diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..50361afbf6 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +docs/changelog.txt merge=union diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 0000000000..2367db6786 --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,6 @@ +Thank you for your interest in contributing to DFHack! If you're reading this +document, you're probably viewing it on GitHub. The DFHack docs are hosted +on [ReadTheDocs](https://dfhack.readthedocs.io/) - in particular, contributing +guidelines are [here](https://docs.dfhack.org/en/latest/docs/Contributing.html). +Double-checking the style guidelines before submitting a pull request is +always appreciated. diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000000..e68a754c63 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1 @@ +If this PR makes an externally-visible change in behavior or API, please add an appropriate line to `docs/changelog.txt`. diff --git a/.github/release_template.md b/.github/release_template.md new file mode 100644 index 0000000000..2bfc7a3c04 --- /dev/null +++ b/.github/release_template.md @@ -0,0 +1,64 @@ +#### Q: How do I download DFHack? +**A:** Either add to your Steam library from our [Steam page](https://store.steampowered.com/app/2346660/DFHack) or scroll to the latest release on our [GitHub releases page](https://github.com/DFHack/dfhack/releases), expand the "Assets" list, and download the file for your platform (e.g. `dfhack-XX.XX-rX-Windows-64bit.zip`. If you are on Windows and are manually installing from the zip file, please remember to right click on the file after downloading, open the file properties, and select the "Unblock" checkbox. This will prevent issues with Windows antivirus programs. + +------------- + +This release is compatible with all distributions of Dwarf Fortress: [Steam](https://store.steampowered.com/app/975370/Dwarf_Fortress/), [Itch](https://kitfoxgames.itch.io/dwarf-fortress), and [Classic](https://www.bay12games.com/dwarves/). + +- [Install DFHack from Steam](https://store.steampowered.com/app/2346660/DFHack) +- [Manual install](https://docs.dfhack.org/en/stable/docs/Installing.html#installing) +- [Quickstart guide (for players)](https://docs.dfhack.org/en/stable/docs/Quickstart.html#quickstart) +- [Modding guide (for modders)](https://docs.dfhack.org/en/stable/docs/guides/modding-guide.html) + +Please report any issues (or feature requests) on the DFHack [GitHub issue tracker](https://github.com/DFHack/dfhack/issues). When reporting issues, please upload a zip file of your savegame and a zip file of your `mods` directory to the cloud and add links to the GitHub issue. Make sure your files are downloadable by "everyone with the link". We need your savegame to reproduce the problem and test the fix, and we need your active mods so we can load your savegame. Issues with savegames and mods attached get fixed first! + +Highlights +---------------------------------- + +
+Highlight 1, Highlight 2 + +### Highlight 1 + +Demo screenshot/vidcap + +Text + +### Highlight 2 + +Demo screenshot/vidcap + +Text + +
+ +Announcements +---------------------------------- + +
+Annc 1, PSAs + +### Annc 1 + +Text + +### PSAs + +As always, remember that, just like the vanilla DF game, DFHack tools can also have bugs. It is a good idea to **save often and keep backups** of the forts that you care about. + +Some DFHack tools that worked in previous (pre-Steam) versions of DF have not been updated yet and are marked with the "unavailable" tag in their docs. If you try to run them, they will show a warning and exit immediately. You can run the command again to override the warning (though of course the tools may not work). We make no guarantees of reliability for the tools that are marked as "unavailable". + +The in-game interface for running DFHack commands (`gui/launcher`) will not show "unavailable" tools by default. You can still run them if you know their names, or you can turn on dev mode by hitting Ctrl-D while in `gui/launcher` and they will be added to the autocomplete list. Some tools listed as "unavailable" in the docs do not compile yet and are not accessible at all, even when in dev mode. + +If you see a tool complaining about the lack of a cursor, know that it's referring to the **keyboard** cursor (which used to be the only real option in Dwarf Fortress). You can enable the keyboard cursor by entering mining mode or selecting the dump/forbid tool and hitting Alt-K (the DFHack keybinding for `toggle-kbd-cursor`). We're working on making DFHack tools more mouse-aware and accessible so this step isn't necessary in the future. + +
+ +Changelog +==================== + +
+New tools, fixes, and improvements + +%RELEASE_NOTES% +
diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml new file mode 100644 index 0000000000..c2d946e300 --- /dev/null +++ b/.github/workflows/build-linux.yml @@ -0,0 +1,205 @@ +name: Build linux64 + +on: + workflow_call: + inputs: + dfhack_repo: + type: string + default: DFHack/dfhack + dfhack_ref: + type: string + scripts_repo: + type: string + default: DFHack/scripts + scripts_ref: + type: string + structures_repo: + type: string + default: DFHack/df-structures + structures_ref: + type: string + stonesense_repo: + type: string + default: DFHack/stonesense + stonesense_ref: + type: string + artifact-name: + type: string + append-date-and-hash: + type: boolean + default: false + cache-id: + type: string + default: '' + cache-readonly: + type: boolean + default: false + platform-files: + type: boolean + default: true + plugins: + type: boolean + default: true + common-files: + type: boolean + default: true + docs: + type: boolean + default: false + html: + type: boolean + default: true + stonesense: + type: boolean + default: false + launchdf: + type: boolean + default: false + extras: + type: boolean + default: false + tests: + type: boolean + default: false + xml-dump-type-sizes: + type: boolean + default: false + gcc-ver: + type: string + default: "11" + +jobs: + build-linux64: + name: Build linux64 + runs-on: ubuntu-22.04 + steps: + - name: Install basic build dependencies + run: | + sudo apt-get update + sudo apt-get install ninja-build + - name: Install binary build dependencies + if: inputs.platform-files || inputs.xml-dump-type-sizes + run: | + sudo apt-get install \ + ccache \ + gcc-${{ inputs.gcc-ver }} \ + g++-${{ inputs.gcc-ver }} \ + libxml-libxslt-perl + - name: Install stonesense dependencies + if: inputs.stonesense + run: sudo apt-get install libgl-dev + - name: Install doc dependencies + if: inputs.docs + run: pip install 'sphinx' + - name: Clone DFHack + uses: actions/checkout@v4 + with: + repository: ${{ inputs.dfhack_repo }} + ref: ${{ inputs.dfhack_ref }} + submodules: true + fetch-depth: ${{ !inputs.platform-files && 1 || 0 }} + - name: Clone scripts + if: inputs.scripts_ref + uses: actions/checkout@v4 + with: + repository: ${{ inputs.scripts_repo }} + ref: ${{ inputs.scripts_ref }} + path: scripts + - name: Clone structures + if: inputs.structures_ref + uses: actions/checkout@v4 + with: + repository: ${{ inputs.structures_repo }} + ref: ${{ inputs.structures_ref }} + path: library/xml + - name: Clone stonesense + if: inputs.stonesense_ref + uses: actions/checkout@v4 + with: + repository: ${{ inputs.stonesense_repo }} + ref: ${{ inputs.stonesense_ref }} + path: plugins/stonesense + - name: Get 3rd party SDKs + if: inputs.launchdf + uses: actions/checkout@v4 + with: + repository: DFHack/3rdparty + ref: main + ssh-key: ${{ secrets.DFHACK_3RDPARTY_TOKEN }} + path: depends/steam + - name: Fetch ccache + if: inputs.platform-files + uses: actions/cache/restore@v4 + with: + path: ~/.cache/ccache + key: linux-gcc-${{ inputs.gcc-ver }}-${{ inputs.cache-id }}-${{ github.sha }} + restore-keys: | + linux-gcc-${{ inputs.gcc-ver }}-${{ inputs.cache-id }} + linux-gcc-${{ inputs.gcc-ver }} + - name: Configure DFHack + env: + CC: gcc-${{ inputs.gcc-ver }} + CXX: g++-${{ inputs.gcc-ver }} + run: | + cmake \ + -S . \ + -B build \ + -G Ninja \ + -DCMAKE_INSTALL_PREFIX=build/image \ + -DCMAKE_BUILD_TYPE=Release \ + -DDFHACK_RUN_URL='https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}' \ + ${{ inputs.platform-files && '-DCMAKE_C_COMPILER_LAUNCHER=ccache' || '' }} \ + ${{ inputs.platform-files && '-DCMAKE_CXX_COMPILER_LAUNCHER=ccache' || '' }} \ + -DBUILD_LIBRARY:BOOL=${{ inputs.platform-files }} \ + -DBUILD_PLUGINS:BOOL=${{ inputs.platform-files && inputs.plugins }} \ + -DBUILD_STONESENSE:BOOL=${{ inputs.stonesense }} \ + -DBUILD_DFLAUNCH:BOOL=${{ inputs.launchdf }} \ + -DBUILD_DEV_PLUGINS:BOOL=${{ inputs.extras }} \ + -DBUILD_SIZECHECK:BOOL=${{ inputs.extras }} \ + -DBUILD_SKELETON:BOOL=${{ inputs.extras }} \ + -DBUILD_DOCS:BOOL=${{ inputs.docs }} \ + -DBUILD_DOCS_NO_HTML:BOOL=${{ !inputs.html }} \ + -DBUILD_TESTS:BOOL=${{ inputs.tests }} \ + -DBUILD_XMLDUMP:BOOL=${{ inputs.xml-dump-type-sizes }} \ + ${{ inputs.xml-dump-type-sizes && '-DINSTALL_XMLDUMP:BOOL=1' || ''}} \ + -DINSTALL_DATA_FILES:BOOL=${{ inputs.common-files }} \ + -DINSTALL_SCRIPTS:BOOL=${{ inputs.common-files }} + - name: Build DFHack + run: ninja -C build install + - name: Run cpp tests + if: inputs.platform-files + run: ninja -C build test + - name: Finalize ccache + if: inputs.platform-files + run: | + ccache --show-stats --verbose + ccache --max-size 40M + ccache --cleanup + ccache --max-size 500M + ccache --zero-stats + - name: Save ccache + if: inputs.platform-files && !inputs.cache-readonly + uses: actions/cache/save@v4 + with: + path: ~/.cache/ccache + key: linux-gcc-${{ inputs.gcc-ver }}-${{ inputs.cache-id }}-${{ github.sha }} + - name: Format artifact name + if: inputs.artifact-name + id: artifactname + run: | + if test "false" = "${{ inputs.append-date-and-hash }}"; then + echo name=${{ inputs.artifact-name }} >> $GITHUB_OUTPUT + else + echo name=${{ inputs.artifact-name }}-$(date +%Y%m%d)-$(git rev-parse --short HEAD) >> $GITHUB_OUTPUT + fi + - name: Prep artifact + if: inputs.artifact-name + run: | + cd build/image + tar cjf ../../${{ steps.artifactname.outputs.name }}.tar.bz2 . + - name: Upload artifact + if: inputs.artifact-name + uses: actions/upload-artifact@v4 + with: + name: ${{ steps.artifactname.outputs.name }} + path: ${{ steps.artifactname.outputs.name }}.tar.bz2 diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml new file mode 100644 index 0000000000..1dec211117 --- /dev/null +++ b/.github/workflows/build-windows.yml @@ -0,0 +1,206 @@ +name: Build win64 + +on: + workflow_call: + inputs: + dfhack_repo: + type: string + default: DFHack/dfhack + dfhack_ref: + type: string + scripts_repo: + type: string + default: DFHack/scripts + scripts_ref: + type: string + structures_repo: + type: string + default: DFHack/df-structures + structures_ref: + type: string + stonesense_repo: + type: string + default: DFHack/stonesense + stonesense_ref: + type: string + artifact-name: + type: string + append-date-and-hash: + type: boolean + default: false + cache-id: + type: string + default: '' + cache-readonly: + type: boolean + default: false + platform-files: + type: boolean + default: true + plugins: + type: boolean + default: true + common-files: + type: boolean + default: true + docs: + type: boolean + default: false + html: + type: boolean + default: true + stonesense: + type: boolean + default: false + tests: + type: boolean + default: false + xml-dump-type-sizes: + type: boolean + default: false + launchdf: + type: boolean + default: false + + +jobs: + build-win64: + name: Build win64 + runs-on: windows-2022 + steps: + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: '3.x' + - name: Install build dependencies + run: | + choco install sccache + pip install Jinja2 + - name: Install doc dependencies + if: inputs.docs + run: | + pip install sphinx + - name: Clone DFHack + uses: actions/checkout@v4 + with: + repository: ${{ inputs.dfhack_repo }} + ref: ${{ inputs.dfhack_ref }} + submodules: true + fetch-depth: 0 + - name: Clone scripts + if: inputs.scripts_ref + uses: actions/checkout@v4 + with: + repository: ${{ inputs.scripts_repo }} + ref: ${{ inputs.scripts_ref }} + path: scripts + - name: Clone structures + if: inputs.structures_ref + uses: actions/checkout@v4 + with: + repository: ${{ inputs.structures_repo }} + ref: ${{ inputs.structures_ref }} + path: library/xml + - name: Clone stonesense + if: inputs.stonesense_ref + uses: actions/checkout@v4 + with: + repository: ${{ inputs.stonesense_repo }} + ref: ${{ inputs.stonesense_ref }} + path: plugins/stonesense + - name: Get 3rd party SDKs + if: inputs.launchdf + uses: actions/checkout@v4 + with: + repository: DFHack/3rdparty + ref: main + ssh-key: ${{ secrets.DFHACK_3RDPARTY_TOKEN }} + path: depends/steam + - name: Prepare output directories + run: | + mkdir output + mkdir pdb + - name: Get sccache path + run: echo ("SCCACHE_DIR=" + $env:LOCALAPPDATA + "\Mozilla\sccache\cache") >> $env:GITHUB_ENV + - name: Fetch ccache + if: inputs.platform-files + uses: actions/cache/restore@v4 + with: + path: ${{ env.SCCACHE_DIR }} + key: win-msvc-${{ inputs.cache-id }}-${{ github.sha }} + restore-keys: | + win-msvc-${{ inputs.cache-id }} + win-msvc + - uses: ilammy/msvc-dev-cmd@v1 + - name: Configure DFHack + run: | + cmake ` + -S . ` + -B build ` + -GNinja ` + -DDFHACK_BUILD_ARCH=64 ` + -DCMAKE_BUILD_TYPE=Release ` + -DCMAKE_INSTALL_PREFIX=output ` + -DCMAKE_C_COMPILER_LAUNCHER=sccache ` + -DCMAKE_CXX_COMPILER_LAUNCHER=sccache ` + -DBUILD_PDBS:BOOL=${{ inputs.cache-id == 'release' }} ` + -DDFHACK_RUN_URL='https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}' ` + -DBUILD_LIBRARY=${{ inputs.platform-files }} ` + -DBUILD_PLUGINS:BOOL=${{ inputs.platform-files && inputs.plugins }} ` + -DBUILD_STONESENSE:BOOL=${{ inputs.stonesense }} ` + -DBUILD_DOCS:BOOL=${{ inputs.docs }} ` + -DBUILD_DOCS_NO_HTML:BOOL=${{ !inputs.html }} ` + -DINSTALL_DATA_FILES:BOOL=${{ inputs.common-files }} ` + -DBUILD_DFLAUNCH:BOOL=${{ inputs.launchdf }} ` + -DBUILD_TESTS:BOOL=${{ inputs.tests }} ` + -DBUILD_XMLDUMP:BOOL=${{ inputs.xml-dump-type-sizes }} ` + ${{ inputs.xml-dump-type-sizes && '-DINSTALL_XMLDUMP:BOOL=1' || '' }} + - name: Build DFHack + env: + SCCACHE_CACHE_SIZE: 500M + run: | + ninja install -C build + - name: Finalize cache + run: | + cd build + sccache --show-stats + sccache --zero-stats + - name: Save ccache + if: inputs.platform-files && !inputs.cache-readonly + uses: actions/cache/save@v4 + with: + path: ${{ env.SCCACHE_DIR }} + key: win-msvc-${{ inputs.cache-id }}-${{ github.sha }} + - name: Format artifact name + if: inputs.artifact-name + id: artifactname + run: | + if ("${{ inputs.append-date-and-hash }}" -eq "false") { + "name=${{ inputs.artifact-name }}" | Out-File -Append $env:GITHUB_OUTPUT + } else { + $date = Get-Date -Format "yyyMMdd" + $hash = git rev-parse --short HEAD + "name=${{ inputs.artifact-name}}-$date-$hash" | Out-File -Append $env:GITHUB_OUTPUT + } + - name: Prep pdbs + if: inputs.artifact-name && inputs.cache-id == 'release' + run: | + Get-ChildItem -Recurse -File -Path "build" -Filter *.pdb | + Copy-Item -Destination "pdb" + - name: Prep artifact + run: | + cd output + 7z a -ttar -so -an . | + 7z a -si -tbzip2 ../${{ steps.artifactname.outputs.name }}.tar.bz2 + - name: Upload artifact + if: inputs.artifact-name + uses: actions/upload-artifact@v4 + with: + name: ${{ steps.artifactname.outputs.name }} + path: ${{ steps.artifactname.outputs.name }}.tar.bz2 + - name: Upload PDBs + if: inputs.artifact-name && inputs.cache-id == 'release' + uses: actions/upload-artifact@v4 + with: + name: ${{ steps.artifactname.outputs.name }}_pdb + path: pdb diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000000..3767b42ba5 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,46 @@ +name: Build + +on: [push, pull_request] + +jobs: + test: + uses: ./.github/workflows/test.yml + with: + dfhack_repo: ${{ github.repository }} + dfhack_ref: ${{ github.ref }} + secrets: inherit + + package: + uses: ./.github/workflows/package.yml + with: + dfhack_repo: ${{ github.repository }} + dfhack_ref: ${{ github.ref }} + secrets: inherit + + docs: + uses: ./.github/workflows/build-linux.yml + with: + dfhack_repo: ${{ github.repository }} + dfhack_ref: ${{ github.ref }} + platform-files: false + common-files: false + docs: true + secrets: inherit + + lint: + uses: ./.github/workflows/lint.yml + with: + dfhack_repo: ${{ github.repository }} + dfhack_ref: ${{ github.ref }} + secrets: inherit + + check-pr: + runs-on: ubuntu-latest + if: github.event_name == 'pull_request' + steps: + - name: Check that PR is based on develop branch + env: + BASE_BRANCH: ${{ github.base_ref }} + run: | + echo "PR base branch: $BASE_BRANCH" + test "$BASE_BRANCH" = develop diff --git a/.github/workflows/clean-cache.yml b/.github/workflows/clean-cache.yml new file mode 100644 index 0000000000..91d5675ad8 --- /dev/null +++ b/.github/workflows/clean-cache.yml @@ -0,0 +1,32 @@ +name: Clean up PR caches + +on: + workflow_call: + pull_request_target: + types: + - closed + +jobs: + cleanup: + runs-on: ubuntu-latest + steps: + - name: Check out code + uses: actions/checkout@v4 + - name: Cleanup + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh extension install actions/gh-actions-cache + + REPO=${{ github.repository }} + BRANCH="refs/pull/${{ github.event.pull_request.number }}/merge" + + echo "Fetching list of cache keys" + cacheKeysForPR=$(gh actions-cache list -R $REPO -B $BRANCH -L 100 | cut -f 1) + + set +e + echo "Deleting caches..." + for cacheKey in $cacheKeysForPR; do + gh actions-cache delete $cacheKey -R $REPO -B $BRANCH --confirm + done + echo "Done" diff --git a/.github/workflows/generate-symbols.yml b/.github/workflows/generate-symbols.yml new file mode 100644 index 0000000000..f78da19e74 --- /dev/null +++ b/.github/workflows/generate-symbols.yml @@ -0,0 +1,421 @@ +name: Generate symbols + +on: + workflow_dispatch: + inputs: + structures_ref: + description: Structures branch to build from and update + required: true + default: master + version: + description: DF version (can be "auto" if channel is steam) + required: true + platform: + description: Target OS platform + type: choice + required: true + default: all + options: + - all + - windows + - linux + channel: + description: DF distribution channel + type: choice + required: true + default: all + options: + - all + - steam + - itch + - classic + df_steam_branch: + description: DF Steam branch to read from (if processing Steam distribution channel) + required: true + type: choice + default: default + options: + - default + - experimental + - testing + - adventure_test + - beta + steam_branch: + description: DFHack Steam branch to deploy to (leave blank to skip deploy) + type: string + +jobs: + package-linux: + uses: ./.github/workflows/build-linux.yml + if: inputs.platform == 'all' || inputs.platform == 'linux' + with: + dfhack_ref: ${{ github.ref }} + structures_ref: ${{ inputs.structures_ref }} + artifact-name: dfhack-symbols-linux64-build + append-date-and-hash: false + cache-id: test + cache-readonly: true + plugins: false + secrets: inherit + + package-win64: + uses: ./.github/workflows/build-windows.yml + if: (inputs.platform == 'all' || inputs.platform == 'windows') && inputs.version == 'auto' + with: + dfhack_ref: ${{ github.ref }} + structures_ref: ${{ inputs.structures_ref }} + artifact-name: dfhack-symbols-windows64-build + append-date-and-hash: false + cache-id: test + cache-readonly: true + plugins: false + secrets: inherit + + generate-linux: + name: Generate linux64 symbols + runs-on: ubuntu-latest + if: inputs.platform == 'all' || inputs.platform == 'linux' + needs: + - package-linux + steps: + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install \ + ansifilter \ + libsdl2-2.0-0 \ + libsdl2-image-2.0-0 + - name: Clone structures + uses: actions/checkout@v4 + with: + repository: DFHack/df-structures + ref: ${{ inputs.structures_ref }} + token: ${{ secrets.DFHACK_GITHUB_TOKEN }} + path: xml + - name: Download DFHack + uses: actions/download-artifact@v4 + with: + name: dfhack-symbols-linux64-build + - name: Start X server + run: Xvfb :0 -screen 0 1600x1200x24 & + + # Steam + - name: Setup steamcmd + if: inputs.channel == 'all' || inputs.channel == 'steam' + id: steamcmd + uses: CyberAndrii/setup-steamcmd@v1 + - name: Generate Steam symbols + if: inputs.channel == 'all' || inputs.channel == 'steam' + env: + DISPLAY: :0 + STEAM_USERNAME: ${{ secrets.STEAM_USERNAME }} + STEAM_CONFIG_VDF: ${{ secrets.STEAM_CONFIG_VDF }} + STEAM_DF_TESTING: ${{ secrets.STEAM_DF_TESTING }} + STEAM_DF_ADVENTURE_TEST: ${{ secrets.STEAM_DF_ADVENTURE_TEST }} + run: | + mkdir DF_steam + mkdir -p $HOME/Steam/config + echo "$STEAM_CONFIG_VDF" | base64 -d >$HOME/Steam/config/config.vdf + echo "DF steam branch: ${{ inputs.df_steam_branch }}" + if [ "${{ inputs.df_steam_branch }}" = "default" ]; then + BETA_PARAMS="" + elif [ "${{ inputs.df_steam_branch }}" = "testing" ]; then + BETA_PARAMS="-beta testing -betapassword $STEAM_DF_TESTING" + elif [ "${{ inputs.df_steam_branch }}" = "adventure_test" ]; then + BETA_PARAMS="-beta adventure_test -betapassword $STEAM_DF_ADVENTURE_TEST" + else + BETA_PARAMS="-beta ${{ inputs.df_steam_branch }}" + fi + ${{ steps.steamcmd.outputs.executable }} \ + +@ShutdownOnFailedCommand 1 \ + +force_install_dir $PWD/DF_steam \ + +login $STEAM_USERNAME \ + "+app_update 975370 $BETA_PARAMS validate" \ + +quit + tar xjf dfhack-symbols-linux64-build.tar.bz2 -C DF_steam + xml/symbols_gen_linux.sh ${{ inputs.version == 'auto' && '50.0' || inputs.version }} STEAM DF_steam + if [ "${{ inputs.version }}" == "auto" ]; then + while pgrep dwarfort; do + echo "waiting for DF to exit" + sleep 0.5 + done + cp xml/symbols.xml DF_steam/hack + cd DF_steam + DFHACK_DISABLE_CONSOLE=1 ./dfhack & + while ! ./dfhack-run lua 'print(scr)' | fgrep 'viewscreen_titlest' 2>/dev/null; do + echo "waiting for DF to start" + sleep 0.5 + done + df_ver=`./dfhack-run lua 'print(dfhack.gui.getDFViewscreen(true).str_version)' | ansifilter` + echo "Found version string: '$df_ver'" + echo "DETECTED_DF_VER=$df_ver" >>$GITHUB_ENV + sed -i "s/v0.50.0 linux64 STEAM/v0.$df_ver linux64 STEAM/" ../xml/symbols.xml + ./dfhack-run die || true + fi + + # Itch + - name: Generate Itch symbols + if: (inputs.channel == 'all' || inputs.channel == 'itch') && inputs.version != 'auto' + env: + DISPLAY: :0 + ITCH_API_KEY: ${{ secrets.ITCH_API_KEY }} + run: | + mkdir DF_itch + pip install itch-dl + minor=$(echo "${{ inputs.version }}" | cut -d. -f1) + patch=$(echo "${{ inputs.version }}" | cut -d. -f2) + fname="dwarf_fortress_${minor}_${patch}_linux.tar.bz2" + itch-dl https://kitfoxgames.itch.io/dwarf-fortress --download-to . --api-key $ITCH_API_KEY --filter-files-glob "${fname}" + tar xjf "kitfoxgames/dwarf-fortress/files/${fname}" -C DF_itch + tar xjf dfhack-symbols-linux64-build.tar.bz2 -C DF_itch + xml/symbols_gen_linux.sh ${{ inputs.version }} ITCH DF_itch + + # Classic + - name: Generate Classic symbols + if: (inputs.channel == 'all' || inputs.channel == 'classic') && inputs.version != 'auto' + env: + DISPLAY: :0 + run: | + mkdir DF_classic + minor=$(echo "${{ inputs.version }}" | cut -d. -f1) + patch=$(echo "${{ inputs.version }}" | cut -d. -f2) + fname="df_${minor}_${patch}_linux.tar.bz2" + wget "https://www.bay12games.com/dwarves/${fname}" + tar xjf "${fname}" -C DF_classic + tar xjf dfhack-symbols-linux64-build.tar.bz2 -C DF_classic + xml/symbols_gen_linux.sh ${{ inputs.version }} CLASSIC DF_classic + + # Finalize + - name: Merge updates + run: | + cd xml + if ! git diff --exit-code; then + git stash + git pull + git stash pop + fi + - name: Commit symbol updates + uses: stefanzweifel/git-auto-commit-action@v5 + with: + commit_message: Auto-update symbols for Linux DF version ${{ env.DETECTED_DF_VER || inputs.version }} + repository: xml + commit_user_name: DFHack-Urist via GitHub Actions + commit_user_email: 63161697+DFHack-Urist@users.noreply.github.com + + generate-windows: + name: Generate win64 symbols + runs-on: ubuntu-latest + if: inputs.platform == 'all' || inputs.platform == 'windows' + steps: + - name: Install dependencies + run: pip install pefile + - name: Clone structures + uses: actions/checkout@v4 + with: + repository: DFHack/df-structures + ref: ${{ inputs.structures_ref }} + token: ${{ secrets.DFHACK_GITHUB_TOKEN }} + path: xml + - name: Clone df_misc + uses: actions/checkout@v4 + with: + repository: DFHack/df_misc + path: df_misc + - name: Clone metasm + uses: actions/checkout@v4 + with: + repository: jjyg/metasm + path: metasm + + # Steam + - name: Setup steamcmd + if: inputs.channel == 'all' || inputs.channel == 'steam' + id: steamcmd + uses: CyberAndrii/setup-steamcmd@v1 + - name: Generate Steam symbols + if: inputs.channel == 'all' || inputs.channel == 'steam' + env: + STEAM_USERNAME: ${{ secrets.STEAM_USERNAME }} + STEAM_CONFIG_VDF: ${{ secrets.STEAM_CONFIG_VDF }} + STEAM_DF_TESTING: ${{ secrets.STEAM_DF_TESTING }} + STEAM_DF_ADVENTURE_TEST: ${{ secrets.STEAM_DF_ADVENTURE_TEST }} + run: | + mkdir DF_steam + mkdir -p $HOME/Steam/config + echo "$STEAM_CONFIG_VDF" | base64 -d >$HOME/Steam/config/config.vdf + echo "DF steam branch: ${{ inputs.df_steam_branch }}" + if [ "${{ inputs.df_steam_branch }}" = "default" ]; then + BETA_PARAMS="" + elif [ "${{ inputs.df_steam_branch }}" = "testing" ]; then + BETA_PARAMS="-beta testing -betapassword $STEAM_DF_TESTING" + elif [ "${{ inputs.df_steam_branch }}" = "adventure_test" ]; then + BETA_PARAMS="-beta adventure_test -betapassword $STEAM_DF_ADVENTURE_TEST" + else + BETA_PARAMS="-beta ${{ inputs.df_steam_branch }}" + fi + ${{ steps.steamcmd.outputs.executable }} \ + +@ShutdownOnFailedCommand 1 \ + +@sSteamCmdForcePlatformType windows \ + +force_install_dir $PWD/DF_steam \ + +login $STEAM_USERNAME \ + "+app_update 975370 $BETA_PARAMS validate" \ + +quit + xml/symbols_gen_windows.sh ${{ inputs.version == 'auto' && '50.0' || inputs.version }} STEAM DF_steam + + # Itch + - name: Generate Itch symbols + if: (inputs.channel == 'all' || inputs.channel == 'itch') && inputs.version != 'auto' + env: + ITCH_API_KEY: ${{ secrets.ITCH_API_KEY }} + run: | + mkdir DF_itch + pip install itch-dl + minor=$(echo "${{ inputs.version }}" | cut -d. -f1) + patch=$(echo "${{ inputs.version }}" | cut -d. -f2) + fname="dwarf_fortress_${minor}_${patch}_windows.zip" + itch-dl https://kitfoxgames.itch.io/dwarf-fortress --download-to . --api-key $ITCH_API_KEY --filter-files-glob "${fname}" + unzip -d DF_itch "kitfoxgames/dwarf-fortress/files/${fname}" + xml/symbols_gen_windows.sh ${{ inputs.version }} ITCH DF_itch + + # Classic + - name: Generate Classic symbols + if: (inputs.channel == 'all' || inputs.channel == 'classic') && inputs.version != 'auto' + run: | + mkdir DF_classic + minor=$(echo "${{ inputs.version }}" | cut -d. -f1) + patch=$(echo "${{ inputs.version }}" | cut -d. -f2) + fname="df_${minor}_${patch}_win.zip" + wget "https://www.bay12games.com/dwarves/${fname}" + unzip -d DF_classic "${fname}" + xml/symbols_gen_windows.sh ${{ inputs.version }} CLASSIC DF_classic + + # Finalize + - name: Merge updates + run: | + cd xml + if ! git diff --exit-code; then + git stash + git pull + git stash pop + fi + - name: Commit symbol updates + uses: stefanzweifel/git-auto-commit-action@v5 + with: + commit_message: Auto-update symbols for Windows DF version ${{ inputs.version }} + repository: xml + commit_user_name: DFHack-Urist via GitHub Actions + commit_user_email: 63161697+DFHack-Urist@users.noreply.github.com + + auto-ver-windows: + name: Autodetect DF version string (Windows) + if: (inputs.platform == 'all' || inputs.platform == 'windows') && (inputs.channel == 'all' || inputs.channel == 'steam') && inputs.version == 'auto' + needs: + - package-win64 + - generate-windows + runs-on: windows-latest + steps: + - name: Clone structures + uses: actions/checkout@v4 + with: + repository: DFHack/df-structures + ref: ${{ inputs.structures_ref }} + token: ${{ secrets.DFHACK_GITHUB_TOKEN }} + path: xml + - name: Download DFHack + uses: actions/download-artifact@v4 + with: + name: dfhack-symbols-windows64-build + - name: Setup steamcmd + id: steamcmd + uses: CyberAndrii/setup-steamcmd@v1 + - name: Update DF version string + env: + STEAM_USERNAME: ${{ secrets.STEAM_USERNAME }} + STEAM_CONFIG_VDF: ${{ secrets.STEAM_CONFIG_VDF }} + STEAM_DF_TESTING: ${{ secrets.STEAM_DF_TESTING }} + STEAM_DF_ADVENTURE_TEST: ${{ secrets.STEAM_DF_ADVENTURE_TEST }} + shell: bash + run: | + mkdir DF_steam + echo "$STEAM_CONFIG_VDF" | base64 -d >${{ steps.steamcmd.outputs.directory }}/config/config.vdf + echo "DF steam branch: ${{ inputs.df_steam_branch }}" + if [ "${{ inputs.df_steam_branch }}" = "default" ]; then + BETA_PARAMS="" + elif [ "${{ inputs.df_steam_branch }}" = "testing" ]; then + BETA_PARAMS="-beta testing -betapassword $STEAM_DF_TESTING" + elif [ "${{ inputs.df_steam_branch }}" = "adventure_test" ]; then + BETA_PARAMS="-beta adventure_test -betapassword $STEAM_DF_ADVENTURE_TEST" + else + BETA_PARAMS="-beta ${{ inputs.df_steam_branch }}" + fi + ${{ steps.steamcmd.outputs.executable }} \ + +@ShutdownOnFailedCommand 1 \ + +@sSteamCmdForcePlatformType windows \ + +force_install_dir $PWD/DF_steam \ + +login $STEAM_USERNAME \ + "+app_update 975370 $BETA_PARAMS validate" \ + +quit + tar xjf dfhack-symbols-windows64-build.tar.bz2 -C DF_steam + cp xml/symbols.xml DF_steam/hack + cd DF_steam + "./Dwarf Fortress.exe" & + while ! ./dfhack-run.exe lua 'print(scr)' | fgrep 'viewscreen_titlest' 2>/dev/null; do + echo "waiting for DF to start" + sleep 0.5 + done + df_ver=`./dfhack-run.exe lua 'print(dfhack.gui.getDFViewscreen(true).str_version)'` + echo "Found version string: '$df_ver'" + echo "DETECTED_DF_VER=$df_ver" >>$GITHUB_ENV + sed -i "s/v0.50.0 win64 STEAM/v0.$df_ver win64 STEAM/" ../xml/symbols.xml + ./dfhack-run.exe die || true + - name: Merge updates + shell: bash + run: | + cd xml + if ! git diff --exit-code; then + git stash + git pull + git stash pop + fi + - name: Commit symbol updates + uses: stefanzweifel/git-auto-commit-action@v5 + with: + commit_message: Auto-update Windows DF version to ${{ env.DETECTED_DF_VER }} in symbols + repository: xml + commit_user_name: DFHack-Urist via GitHub Actions + commit_user_email: 63161697+DFHack-Urist@users.noreply.github.com + + update-ref: + name: Update structures ref + runs-on: ubuntu-latest + needs: + - generate-linux + - auto-ver-windows + if: ${{ ! failure() }} + steps: + - name: Clone DFHack + uses: actions/checkout@v4 + with: + token: ${{ secrets.DFHACK_GITHUB_TOKEN }} + - name: Update ref + shell: bash + run: | + git submodule update --init --no-single-branch library/xml + cd library/xml + git checkout ${{ inputs.structures_ref }} + git pull + df_ver=`grep -E 'symbol-table.*STEAM' symbols.xml | head -n1 | sed -r "s/.*name='v0.([^ ]+) .*/\1/"` + echo "using DF version: $df_ver" + echo "DETECTED_DF_VER=$df_ver" >>$GITHUB_ENV + - name: Commit ref update + uses: stefanzweifel/git-auto-commit-action@v5 + with: + commit_message: Auto-update structures ref for ${{ env.DETECTED_DF_VER }} + commit_user_name: DFHack-Urist via GitHub Actions + commit_user_email: 63161697+DFHack-Urist@users.noreply.github.com + - name: Launch steam-deploy + if: inputs.steam_branch + shell: bash + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: gh workflow run steam-deploy.yml -R DFHack/dfhack -r ${{ github.ref }} -f version=${{ env.DETECTED_DF_VER }} -f steam_branch=${{ inputs.steam_branch }} diff --git a/.github/workflows/github-release.yml b/.github/workflows/github-release.yml new file mode 100644 index 0000000000..16a4602141 --- /dev/null +++ b/.github/workflows/github-release.yml @@ -0,0 +1,81 @@ +name: Deploy to GitHub + +on: + push: + tags: + - '*-r*' + + workflow_dispatch: + inputs: + ref: + description: Tag + required: true + +jobs: + package: + uses: ./.github/workflows/package.yml + with: + dfhack_ref: ${{ github.event.inputs && github.event.inputs.ref || github.event.ref }} + append-date-and-hash: false + cache-readonly: true + launchdf: true + secrets: inherit + + create-update-release: + name: Draft GitHub release + needs: package + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Install doc dependencies + run: pip install 'sphinx' + - name: Clone DFHack + uses: actions/checkout@v4 + with: + ref: ${{ github.event.inputs && github.event.inputs.ref || github.event.ref }} + submodules: true + - name: Get tag + id: gettag + run: | + TAG=$(git describe --tags --abbrev=0 --exact-match) + echo name="$TAG" >> $GITHUB_OUTPUT + echo type=$(echo "$TAG" | egrep 'r[0-9]+$' && echo "release" || echo "prerelease") >> $GITHUB_OUTPUT + - name: Generate release text + run: | + python docs/gen_changelog.py -a + CHANGELOG_FILE=docs/changelogs/${{ steps.gettag.outputs.name }}-github.txt + if ! test -f $CHANGELOG_FILE; then CHANGELOG_FILE=docs/changelogs/future-github.txt; fi + TOKEN_LINE=$(grep -Fhne '%RELEASE_NOTES%' .github/release_template.md | sed 's/:.*//') + head -n $((TOKEN_LINE - 1)) .github/release_template.md > release_body.md + CHANGELOG_LINES=$(wc -l <$CHANGELOG_FILE) + tail -n $((CHANGELOG_LINES - 3)) $CHANGELOG_FILE >> release_body.md + tail -n 1 .github/release_template.md >> release_body.md + cat release_body.md + - name: Stage release + uses: actions/download-artifact@v4 + - name: Prep artifacts + run: | + mkdir artifacts + cd dfhack-windows64-build + tar xjf dfhack-windows64-build.tar.bz2 + rm dfhack-windows64-build.tar.bz2 + zip -qr ../artifacts/dfhack-${{ steps.gettag.outputs.name }}-Windows-64bit.zip . + cd ../dfhack-linux64-build + mv dfhack-linux64-build.tar.bz2 ../artifacts/dfhack-${{ steps.gettag.outputs.name }}-Linux-64bit.tar.bz2 + - name: Create or update GitHub release + uses: ncipollo/release-action@v1 + with: + artifacts: "artifacts/dfhack-*" + bodyFile: "release_body.md" + allowUpdates: true + artifactErrorsFailBuild: true + draft: true + name: "DFHack ${{ steps.gettag.outputs.name }}" + omitBodyDuringUpdate: true + omitDraftDuringUpdate: true + omitNameDuringUpdate: true + omitPrereleaseDuringUpdate: true + prerelease: ${{ steps.gettag.outputs.type == 'prerelease' }} + replacesArtifacts: true + tag: ${{ steps.gettag.outputs.name }} diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000000..0b44747c01 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,50 @@ +name: Lint + +on: + workflow_call: + inputs: + dfhack_repo: + type: string + default: DFHack/dfhack + dfhack_ref: + type: string + scripts_repo: + type: string + default: DFHack/scripts + scripts_ref: + type: string + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - name: Install Lua + run: | + sudo apt-get update + sudo apt-get install lua5.3 + - name: Clone DFHack + uses: actions/checkout@v4 + with: + repository: ${{ inputs.dfhack_repo }} + ref: ${{ inputs.dfhack_ref }} + - name: Get scripts submodule ref + if: '!inputs.scripts_ref' + id: scriptssubmoduleref + run: echo ref=$(git submodule | fgrep scripts | cut -c2-41) >> $GITHUB_OUTPUT + - name: Clone scripts + uses: actions/checkout@v4 + with: + repository: ${{ inputs.scripts_repo }} + ref: ${{ inputs.scripts_ref || steps.scriptssubmoduleref.outputs.ref }} + path: scripts + - name: Check whitespace + run: python ci/lint.py --git-only --github-actions + - name: Check Authors.rst + if: always() + run: python ci/authors-rst.py + - name: Check for missing documentation + if: always() + run: python ci/script-docs.py + - name: Check Lua syntax + if: always() + run: python ci/script-syntax.py --ext=lua --cmd="luac5.3 -p" --github-actions diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml new file mode 100644 index 0000000000..41e72ea636 --- /dev/null +++ b/.github/workflows/package.yml @@ -0,0 +1,76 @@ +name: Package + +on: + workflow_call: + inputs: + dfhack_repo: + type: string + dfhack_ref: + type: string + scripts_repo: + type: string + scripts_ref: + type: string + structures_repo: + type: string + structures_ref: + type: string + append-date-and-hash: + type: boolean + default: true + cache-readonly: + type: boolean + default: false + launchdf: + type: boolean + default: false + include_windows: + type: boolean + default: true + include_linux: + type: boolean + default: true + + +jobs: + package-win64: + name: Windows + uses: ./.github/workflows/build-windows.yml + if: inputs.include_windows + with: + dfhack_repo: ${{ inputs.dfhack_repo }} + dfhack_ref: ${{ inputs.dfhack_ref }} + scripts_repo: ${{ inputs.scripts_repo }} + scripts_ref: ${{ inputs.scripts_ref }} + structures_repo: ${{ inputs.structures_repo }} + structures_ref: ${{ inputs.structures_ref }} + artifact-name: dfhack-windows64-build + append-date-and-hash: ${{ inputs.append-date-and-hash }} + cache-id: release + cache-readonly: ${{ inputs.cache-readonly }} + stonesense: true + docs: true + html: false + launchdf: ${{ inputs.launchdf }} + secrets: inherit + + package-linux: + name: Linux + uses: ./.github/workflows/build-linux.yml + if: inputs.include_linux + with: + dfhack_repo: ${{ inputs.dfhack_repo }} + dfhack_ref: ${{ inputs.dfhack_ref }} + scripts_repo: ${{ inputs.scripts_repo }} + scripts_ref: ${{ inputs.scripts_ref }} + structures_repo: ${{ inputs.structures_repo }} + structures_ref: ${{ inputs.structures_ref }} + artifact-name: dfhack-linux64-build + append-date-and-hash: ${{ inputs.append-date-and-hash }} + cache-id: release + cache-readonly: ${{ inputs.cache-readonly }} + stonesense: true + docs: true + html: false + launchdf: ${{ inputs.launchdf }} + secrets: inherit diff --git a/.github/workflows/steam-deploy.yml b/.github/workflows/steam-deploy.yml new file mode 100644 index 0000000000..2fbe6849e1 --- /dev/null +++ b/.github/workflows/steam-deploy.yml @@ -0,0 +1,96 @@ +name: Deploy to Steam + +on: + push: + tags: + - '*-r*' + workflow_dispatch: + inputs: + version: + description: Version or build description + type: string + required: true + steam_branch: + description: Steam release branch + type: string + required: true + default: staging + +jobs: + depot-common: + name: Common depot files + uses: ./.github/workflows/build-linux.yml + with: + artifact-name: common-depot + dfhack_ref: ${{ github.ref }} + platform-files: false + docs: true + html: false + stonesense: true + secrets: inherit + + depot-win64: + name: Windows depot files + uses: ./.github/workflows/build-windows.yml + with: + artifact-name: win64-depot + dfhack_ref: ${{ github.ref }} + cache-id: release + cache-readonly: true + common-files: false + stonesense: true + launchdf: true + secrets: inherit + + depot-linux64: + name: Linux depot files + uses: ./.github/workflows/build-linux.yml + with: + artifact-name: linux64-depot + dfhack_ref: ${{ github.ref }} + cache-id: release + cache-readonly: true + common-files: false + stonesense: true + launchdf: true + secrets: inherit + + deploy-to-steam: + name: Deploy to Steam + needs: + - depot-common + - depot-win64 + - depot-linux64 + runs-on: ubuntu-latest + concurrency: steamdeploy + steps: + - name: Download depot files + uses: actions/download-artifact@v4 + - name: Stage depot files + run: | + for name in common win64 linux64; do + cd ${name}-depot + tar xjf ${name}-depot.tar.bz2 + rm ${name}-depot.tar.bz2 + cd .. + done + - name: Get short SHA of commit + run: echo "SHORT_SHA=`echo ${{ github.sha }} | cut -c1-8`" >>$GITHUB_ENV + - name: steamcmd cache + uses: actions/cache@v4 + with: + path: /home/runner/work/_temp/_github_home + key: steamcmd-${{ github.sha }} + restore-keys: steamcmd + - name: Steam deploy + uses: game-ci/steam-deploy@v3 + with: + username: ${{ secrets.STEAM_USERNAME }} + configVdf: ${{ secrets.STEAM_CONFIG_VDF}} + appId: 2346660 + buildDescription: ${{ github.event.inputs && github.event.inputs.version || github.ref_name }} (${{ env.SHORT_SHA }}) + rootPath: . + depot1Path: common-depot + depot2Path: win64-depot + depot3Path: linux64-depot + releaseBranch: ${{ github.event.inputs && github.event.inputs.steam_branch || 'staging' }} diff --git a/.github/workflows/test-suite.yml b/.github/workflows/test-suite.yml new file mode 100644 index 0000000000..3fbf683b63 --- /dev/null +++ b/.github/workflows/test-suite.yml @@ -0,0 +1,93 @@ +name: Test suite + +on: + workflow_call: + inputs: + dfhack_repo: + type: string + dfhack_ref: + type: string + os: + type: string + compiler: + type: string + plugins: + type: string + config: + type: string + +jobs: + run-tests: + name: Test (${{ inputs.os }}, ${{ inputs.compiler }}, ${{ inputs.plugins }} plugins, ${{ inputs.config }} config) + runs-on: ${{ inputs.os }}-latest + steps: + - name: Set env + shell: bash + run: echo "DF_FOLDER=DF" >>$GITHUB_ENV + - name: Install dependencies + if: inputs.os == 'ubuntu' + run: | + sudo apt-get update + sudo apt-get install \ + libsdl2-2.0-0 \ + libsdl2-image-2.0-0 + - name: Clone DFHack + uses: actions/checkout@v4 + with: + repository: ${{ inputs.dfhack_repo }} + ref: ${{ inputs.dfhack_ref }} + - name: Detect DF version + shell: bash + run: echo DF_VERSION="$(sh ci/get-df-version.sh)" >>$GITHUB_ENV + - name: Fetch DF cache + id: restore-df + uses: actions/cache/restore@v4 + with: + path: ${{ env.DF_FOLDER }} + key: df-${{ inputs.os }}-${{ env.DF_VERSION }}-${{ hashFiles('ci/download-df.sh') }} + - name: Download DF + if: steps.restore-df.outputs.cache-hit != 'true' + run: sh ci/download-df.sh ${{ env.DF_FOLDER }} ${{ inputs.os }} ${{ env.DF_VERSION }} + - name: Save DF cache + if: steps.restore-df.outputs.cache-hit != 'true' + uses: actions/cache/save@v4 + with: + path: ${{ env.DF_FOLDER }} + key: df-${{ inputs.os }}-${{ env.DF_VERSION }}-${{ hashFiles('ci/download-df.sh') }} + - name: Install blank DFHack init scripts + if: inputs.config == 'empty' + shell: bash + run: | + mkdir -p ${{ env.DF_FOLDER }}/dfhack-config/init + cd data/dfhack-config/init + for fname in *.init; do touch ../../../${{ env.DF_FOLDER }}/dfhack-config/init/$fname; done + - name: Download DFHack + uses: actions/download-artifact@v4 + with: + name: test-${{ inputs.compiler }} + - name: Install DFHack + shell: bash + run: tar xjf test-${{ inputs.compiler }}.tar.bz2 -C ${{ env.DF_FOLDER }} + - name: Start X server + if: inputs.os == 'ubuntu' + run: Xvfb :0 -screen 0 1600x1200x24 & + - name: Run lua tests + uses: nick-fields/retry@v3 + env: + DISPLAY: :0 + TERM: xterm-256color + with: + timeout_minutes: 1 + command: python ci/run-tests.py --keep-status "${{ env.DF_FOLDER }}" + - name: Check RPC interface + run: python ci/check-rpc.py "${{ env.DF_FOLDER }}/dfhack-rpc.txt" + - name: Upload test artifacts + uses: actions/upload-artifact@v4 + if: always() + continue-on-error: true + with: + name: test-output-${{ inputs.compiler }}-${{ inputs.plugins }}_plugins-${{ inputs.config }}_config + path: | + ${{ env.DF_FOLDER }}/dfhack-rpc.txt + ${{ env.DF_FOLDER }}/test*.json + ${{ env.DF_FOLDER }}/*.log diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000000..175a1adf48 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,113 @@ +name: Test + +on: + workflow_call: + inputs: + dfhack_repo: + type: string + default: DFHack/dfhack + dfhack_ref: + type: string + scripts_repo: + type: string + default: DFHack/scripts + scripts_ref: + type: string + structures_repo: + type: string + default: DFHack/df-structures + structures_ref: + type: string + +jobs: + build-windows: + name: Windows MSVC + uses: ./.github/workflows/build-windows.yml + with: + dfhack_repo: ${{ inputs.dfhack_repo }} + dfhack_ref: ${{ inputs.dfhack_ref }} + scripts_repo: ${{ inputs.scripts_repo }} + scripts_ref: ${{ inputs.scripts_ref }} + structures_repo: ${{ inputs.structures_repo }} + structures_ref: ${{ inputs.structures_ref }} + artifact-name: test-msvc + cache-id: test + docs: true + html: false + tests: true + + build-linux: + name: Linux gcc-${{ matrix.gcc }} + uses: ./.github/workflows/build-linux.yml + with: + dfhack_repo: ${{ inputs.dfhack_repo }} + dfhack_ref: ${{ inputs.dfhack_ref }} + scripts_repo: ${{ inputs.scripts_repo }} + scripts_ref: ${{ inputs.scripts_ref }} + structures_repo: ${{ inputs.structures_repo }} + structures_ref: ${{ inputs.structures_ref }} + artifact-name: test-gcc-${{ matrix.gcc }} + cache-id: test + stonesense: ${{ matrix.plugins == 'all' }} + extras: ${{ matrix.plugins == 'all' }} + docs: true + html: false + tests: true + gcc-ver: ${{ matrix.gcc }} + secrets: inherit + strategy: + fail-fast: false + matrix: + include: + - gcc: 11 # baseline compatibility with ubuntu LTS 22.04 + plugins: "default" + - gcc: 12 # highest available in ubuntu 22.04 + plugins: "all" + + test-windows: + name: Run Windows test suite + needs: build-windows + uses: ./.github/workflows/test-suite.yml + with: + dfhack_repo: ${{ inputs.dfhack_repo }} + dfhack_ref: ${{ inputs.dfhack_ref }} + os: windows + compiler: msvc + plugins: default + config: default + + test-windows-empty: + name: Run Windows test suite (empty config) + needs: build-windows + uses: ./.github/workflows/test-suite.yml + with: + dfhack_repo: ${{ inputs.dfhack_repo }} + dfhack_ref: ${{ inputs.dfhack_ref }} + os: windows + compiler: msvc + plugins: default + config: empty + + test-linux: + name: Run Linux test suite + needs: build-linux + uses: ./.github/workflows/test-suite.yml + with: + dfhack_repo: ${{ inputs.dfhack_repo }} + dfhack_ref: ${{ inputs.dfhack_ref }} + os: ubuntu + compiler: gcc-11 + plugins: default + config: default + + test-linux-gcc-12-all-plugins: + name: Run Linux test suite (gcc-12, all plugins) + needs: build-linux + uses: ./.github/workflows/test-suite.yml + with: + dfhack_repo: ${{ inputs.dfhack_repo }} + dfhack_ref: ${{ inputs.dfhack_ref }} + os: ubuntu + compiler: gcc-12 + plugins: all + config: default diff --git a/.github/workflows/update-submodules.yml b/.github/workflows/update-submodules.yml new file mode 100644 index 0000000000..c634e94d0a --- /dev/null +++ b/.github/workflows/update-submodules.yml @@ -0,0 +1,29 @@ +name: Update submodules + +on: + schedule: + - cron: '0 7 * * *' + workflow_dispatch: + +jobs: + run: + if: ${{ github.event_name == 'workflow_dispatch' || github.repository_owner == 'DFHack' }} + runs-on: ubuntu-latest + steps: + - name: Clone DFHack + uses: actions/checkout@v4 + with: + fetch-depth: 0 + ref: ${{ github.ref }} + submodules: true + token: ${{ secrets.DFHACK_GITHUB_TOKEN }} + - name: Update submodules + run: | + git config user.name "DFHack-Urist via GitHub Actions" + git config user.email "63161697+DFHack-Urist@users.noreply.github.com" + if bash -x ci/update-submodules.bash; then + git push --recurse-submodules=check + elif ! git diff --exit-code HEAD; then + echo "update-submodules.bash failed to commit changes" + exit 1 + fi diff --git a/.github/workflows/watch-df-release.yml b/.github/workflows/watch-df-release.yml new file mode 100644 index 0000000000..50950140d1 --- /dev/null +++ b/.github/workflows/watch-df-release.yml @@ -0,0 +1,159 @@ +name: Watch DF Releases + +on: + schedule: + - cron: '8/10 * * * *' + workflow_dispatch: + +jobs: + check-steam: + if: github.repository == 'DFHack/dfhack' + name: Check Steam (${{ matrix.df_steam_branch }}) for new DF releases + runs-on: ubuntu-latest + concurrency: watch-release-steam-${{ matrix.df_steam_branch }} + strategy: + fail-fast: false + matrix: + # df_steam_branch: which DF Steam branch to watch + # platform: for symbols generation; leave blank to default to all + # structures_ref: leave blank to default to master + # dfhack_ref: leave blank if no structures update is desired + # steam_branch: leave blank if no DFHack steam push is desired + include: + - df_steam_branch: public +# - df_steam_branch: beta +# - df_steam_branch: experimental +# structures_ref: experimental +# dfhack_ref: experimental +# steam_branch: experimental + steps: + - name: Fetch state + uses: actions/cache/restore@v4 + with: + path: state + key: watch-release-steam-${{ matrix.df_steam_branch }} + - name: Compare branch metadata + uses: nick-fields/retry@v3 + with: + timeout_minutes: 5 + retry_wait_seconds: 60 + command: | + blob=$(wget 'https://api.steamcmd.net/v1/info/975370?pretty=1' -O- | \ + awk '/^ *"branches"/,0' | \ + awk '/^ *"${{ matrix.df_steam_branch }}"/,0') + buildid=$(echo "$blob" | \ + fgrep buildid | \ + head -n1 | \ + cut -d'"' -f4) + timestamp=$(echo "$blob" | \ + fgrep timeupdated | \ + head -n1 | \ + cut -d'"' -f4) + test -z "$buildid" && echo "no buildid result" && exit 1 + test -z "$timestamp" && echo "no timestamp result" && exit 1 + test "$buildid" -gt 0 || exit 1 + test "$timestamp" -gt 0 || exit 1 + echo "buildid and timestamp of last branch update: $buildid, $timestamp" + mkdir -p state + touch state/buildid state/timestamp + last_buildid=$(cat state/buildid) + last_timestamp=$(cat state/timestamp) + if [ -z "$last_timestamp" ]; then + echo "no stored timestamp" + last_buildid=0 + last_timestamp=0 + else + echo "stored buildid and timestamp of last branch update: $last_buildid, $last_timestamp" + fi + if [ "$buildid" -ne "$last_buildid" -a "$timestamp" -gt "$last_timestamp" ]; then + echo "branch updated" + echo "$buildid" >state/buildid + echo "$timestamp" >state/timestamp + echo BUILDID=$buildid >> $GITHUB_ENV + fi + - name: Discord Webhook Action + uses: tsickert/discord-webhook@v5.3.0 + if: env.BUILDID + with: + webhook-url: ${{ secrets.DISCORD_TEAM_PRIVATE_WEBHOOK_URL }} + content: "<@&${{ secrets.DISCORD_TEAM_ROLE_ID }}> Steam ${{ matrix.df_steam_branch }} branch updated (build id: ${{ env.BUILDID }})" + - name: Launch symbol generation workflow + if: env.BUILDID && matrix.dfhack_ref + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh workflow run generate-symbols.yml \ + -R DFHack/dfhack \ + -r ${{ matrix.dfhack_ref }} \ + -f structures_ref=${{ matrix.structures_ref }} \ + -f version=auto \ + -f platform=${{ matrix.platform }} \ + -f channel=steam \ + -f df_steam_branch=${{ matrix.df_steam_branch }} \ + -f steam_branch=${{ matrix.steam_branch }} + - name: Save state + uses: actions/cache/save@v4 + if: env.BUILDID + with: + path: state + key: watch-release-steam-${{ matrix.df_steam_branch }}-${{ env.BUILDID }} + + check-non-steam: + if: github.repository == 'DFHack/dfhack' + name: Check ${{ matrix.channel }} for new DF releases + runs-on: ubuntu-latest + concurrency: watch-release-${{ matrix.channel }} + strategy: + fail-fast: false + matrix: + include: + - channel: itch + url: 'https://kitfoxgames.itch.io/dwarf-fortress' + prefix: 'dwarf_fortress' + - channel: classic + url: 'https://www.bay12games.com/dwarves/' + prefix: 'df' + steps: + - name: Fetch state + uses: actions/cache/restore@v4 + with: + path: state + key: watch-release-${{ matrix.channel }} + - name: Compare versions + uses: nick-fields/retry@v3 + with: + timeout_minutes: 5 + retry_wait_seconds: 60 + command: | + version=$(wget "${{ matrix.url }}" -qO- | tr '"' '\n' | fgrep 'tar.bz2' | head -n1 | sed -r 's/${{ matrix.prefix }}_([0-9]{2})_([0-9]{2})_linux.tar.bz2/\1.\2/') + echo "latest ${{ matrix.channel }} version: $version" + if ! grep -qE '^[0-9]+\.[0-9]+$' <<<"$version"; then + echo "invalid version" + exit 1 + fi + mkdir -p state + touch state/last_version + last_version=$(cat state/last_version) + if [ -z "$last_version" ]; then + echo "no stored version" + last_version=0 + else + echo "stored ${{ matrix.channel }} version: $last_version" + fi + if [ "$(tr -d '.' <<<"$version")" -gt "$(tr -d '.' <<<"$last_version")" ]; then + echo "${{ matrix.channel }} has been updated" + echo "$version" >state/last_version + echo NEW_VERSION=$version >> $GITHUB_ENV + fi + - name: Discord Webhook Action + uses: tsickert/discord-webhook@v5.3.0 + if: env.NEW_VERSION + with: + webhook-url: ${{ secrets.DISCORD_TEAM_PRIVATE_WEBHOOK_URL }} + content: "<@&${{ secrets.DISCORD_TEAM_ROLE_ID }}> ${{ matrix.channel }} updated to ${{ env.NEW_VERSION }}" + - name: Save state + uses: actions/cache/save@v4 + if: env.NEW_VERSION + with: + path: state + key: watch-release-${{ matrix.channel }}-${{ env.NEW_VERSION }} diff --git a/.gitignore b/.gitignore index 5bcab6110e..eda2b226d5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,43 +1,89 @@ # linux backup files *~ -# compiled binaries -output/* - -# this one is important, track it -!output/Memory.xml - -# a file generated by cmake -dfhack/include/config.h -library/private/config.h +# Kdevelop project files +*.kdev4 +.kdev4 # any build folders build*/ +nix +buntu #except for the real one !build/ +# Sphinx generated documentation +docs/changelogs/ +docs/html/ +docs/pdf/ +docs/pseudoxml/ +docs/tags/ +docs/text/ +docs/tools/ +docs/xml/ + # in-place build build/Makefile build/CMakeCache.txt build/cmake_install.cmake build/CMakeFiles -build/doc +build/CTestTestfile.cmake +build/DartConfiguration.tcl +build/data +build/docs +build/lua build/bin +build/lib +build/depends build/library -build/tools - -#ignore Kdevelop stuff -.kdev4 - -#fake curses header -examples/fake-curses.h +build/package +build/plugins +build/scripts +build/install_manifest.txt +build/_CPack_Packages +build/dfhack-*.zip +build/dfhack-*.bz2 +build/*ninja* +build/compile_commands.json +build/dfhack_setarch.txt +build/ImportExecutables.cmake +build/Testing +build/_deps # Python binding binaries *.pyc -dfhack/python/pydfhack/_pydfhack.so -dfhack/python/PyDFHack.egg-info -dfhack/python/build -dfhack/python/dist + +# CPack stuff +build/CPack*Config.cmake /cmakeall.bat + +# vim files +*.swp +.vimrc + +# VSCode files +.vscode +*.code-workspace + +# ctags file +tags + +# Mac OS X .DS_Store files +.DS_Store + +# VS is annoying about this one. +/build/win64/DF_PATH.txt +/build/win32/DF_PATH.txt +/.vs + +# CLion +.idea + +# external plugins +/plugins/CMakeLists.custom.txt + +# 3rd party downloads +depends/steam +depends/SDL2 diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000..596bafc98f --- /dev/null +++ b/.gitmodules @@ -0,0 +1,33 @@ +[submodule "plugins/stonesense"] + path = plugins/stonesense + url = ../../DFHack/stonesense.git +[submodule "library/xml"] + path = library/xml + url = ../../DFHack/df-structures.git +[submodule "depends/clsocket"] + path = depends/clsocket + url = ../../DFHack/clsocket.git +[submodule "scripts2"] + path = scripts + url = ../../DFHack/scripts.git +[submodule "depends/jsoncpp"] + path = depends/jsoncpp-sub + url = ../../DFHack/jsoncpp.git +[submodule "depends/xlsxio"] + path = depends/xlsxio + url = ../../DFHack/xlsxio.git +[submodule "depends/libzip"] + path = depends/libzip + url = ../../DFHack/libzip.git +[submodule "depends/libexpat"] + path = depends/libexpat + url = ../../DFHack/libexpat.git +[submodule "depends/luacov"] + path = depends/luacov + url = ../../DFHack/luacov.git +[submodule "depends/googletest"] + path = depends/googletest + url = ../../google/googletest.git +[submodule "depends/dfhooks"] + path = depends/dfhooks + url = ../../DFHack/dfhooks diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000000..47251d8ed3 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,44 @@ +ci: + autofix_prs: false + autoupdate_schedule: monthly +repos: +# shared across repos: +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v6.0.0 + hooks: + - id: check-added-large-files + - id: check-case-conflict + - id: check-executables-have-shebangs + - id: check-merge-conflict + - id: check-shebang-scripts-are-executable + - id: check-symlinks + - id: check-xml + - id: check-yaml + - id: destroyed-symlinks + - id: end-of-file-fixer + - id: mixed-line-ending + args: ['--fix=lf'] + - id: trailing-whitespace +- repo: https://github.com/python-jsonschema/check-jsonschema + rev: 0.37.4 + hooks: + - id: check-github-workflows +- repo: https://github.com/Lucas-C/pre-commit-hooks + rev: v1.5.6 + hooks: + - id: forbid-tabs + exclude_types: + - json + - id: remove-tabs + exclude_types: + - json +# specific to dfhack: +- repo: local + hooks: + - id: authors-rst + name: Check Authors.rst + language: python + entry: python3 ci/authors-rst.py + files: docs/about/Authors\.rst + pass_filenames: false +exclude: '^(depends/|data/.*\.json$|.*\.diff$|.*\.dfstock$)' diff --git a/dfhack-python/CMakeLists.txt b/.readthedocs.requirements.txt similarity index 100% rename from dfhack-python/CMakeLists.txt rename to .readthedocs.requirements.txt diff --git a/.readthedocs.yml b/.readthedocs.yml new file mode 100644 index 0000000000..bf71c46b78 --- /dev/null +++ b/.readthedocs.yml @@ -0,0 +1,22 @@ +# .readthedocs.yaml +# Read the Docs configuration file +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +version: 2 + +build: + os: ubuntu-22.04 + tools: + python: "3" + +submodules: + include: all + +sphinx: + configuration: conf.py + +formats: all + +python: + install: + - requirements: .readthedocs.requirements.txt diff --git a/.ycm_extra_conf.py b/.ycm_extra_conf.py new file mode 100644 index 0000000000..31a336b2b6 --- /dev/null +++ b/.ycm_extra_conf.py @@ -0,0 +1,164 @@ +'''This file provides editor completions while working on DFHack using ycmd: +https://github.com/Valloric/ycmd +''' + +# pylint: disable=import-error,invalid-name,missing-docstring,unused-argument + +import os,platform +import ycm_core + +def DirectoryOfThisScript(): + return os.path.dirname(os.path.abspath(__file__)) + +default_flags = [ + '-I','library/include', + '-I','library/proto', + '-I','plugins/proto', + '-I','depends/protobuf', + '-I','depends/lua/include', + '-I','depends/md5', + '-I','depends/jsoncpp/include', + '-I','depends/tinyxml', + '-I','depends/clsocket/src', + '-x','c++', + '-D','PROTOBUF_USE_DLLS', + '-D','LUA_BUILD_AS_DLL', + '-Wall','-Wextra', +] + +if os.name == 'posix': + default_flags.extend([ + '-D','LINUX_BUILD', + '-D','_GLIBCXX_USE_C99', + ]) + if platform.system() == 'Darwin': + default_flags.extend(['-D','_DARWIN']) + else: + default_flags.extend(['-D','_LINUX']) +else: + default_flags.extend(['-D','WIN32']) + +# We need to tell YouCompleteMe how to compile this project. We do this using +# clang's "Compilation Database" system, which essentially just dumps a big +# json file into the build folder. +# More details: http://clang.llvm.org/docs/JSONCompilationDatabase.html +# +# We don't use clang, but luckily CMake supports generating a database on its +# own, using: +# set( CMAKE_EXPORT_COMPILE_COMMANDS 1 ) + +for potential_build_folder in ['build', 'build-osx']: + if os.path.exists(DirectoryOfThisScript() + os.path.sep + potential_build_folder + + os.path.sep + 'compile_commands.json'): + database = ycm_core.CompilationDatabase(potential_build_folder) + break +else: + raise RuntimeError("Can't find dfhack build folder: not one of build, build-osx") + + +def MakeRelativePathsInFlagsAbsolute(flags, working_directory): + if not working_directory: + return list(flags) + new_flags = [] + make_next_absolute = False + path_flags = ['-isystem', '-I', '-iquote', '--sysroot='] + for flag in flags: + new_flag = flag + + if make_next_absolute: + make_next_absolute = False + if not flag.startswith('/'): + new_flag = os.path.join(working_directory, flag) + + for path_flag in path_flags: + if flag == path_flag: + make_next_absolute = True + break + + if flag.startswith(path_flag): + path = flag[len(path_flag):] + new_flag = path_flag + os.path.join(working_directory, path) + break + + if new_flag: + new_flags.append(new_flag) + return new_flags + + +def IsHeaderFile(filename): + extension = os.path.splitext(filename)[1] + return extension in ['.h', '.hxx', '.hpp', '.hh'] + + +SOURCE_EXTENSIONS = ['.cpp', '.cxx', '.cc', '.c', '.m', '.mm'] + +def PotentialAlternatives(header): + dirname, filename = os.path.split(header) + basename, _ = os.path.splitext(filename) + + source_dirs = [dirname] + + if dirname.endswith(os.path.sep + 'include'): + # if we're in a folder 'include', also look in its parent + parent = os.path.abspath(os.path.join(dirname, os.path.pardir)) + source_dirs.append(parent) + # and ../src (used by lua dependency) + source_dirs.append(os.path.join(parent, 'src')) + + include_idx = dirname.rfind(os.path.sep + 'include' + os.path.sep) + if include_idx != -1: + # we're in a subfolder of a parent '/include/' + # .../include/subdir/path + # look in .../subdir/path + source_dirs.append( + dirname[:include_idx] + + os.path.sep + + dirname[include_idx + len('include') + 2*len(os.path.sep):] + ) + + for source_dir in source_dirs: + for ext in SOURCE_EXTENSIONS: + yield source_dir + os.path.sep + basename + ext + + +def GetCompilationInfoForFile(filename): + # The compilation_commands.json file generated by CMake does not have entries + # for header files. So we do our best by asking the db for flags for a + # corresponding source file, if any. If one exists, the flags for that file + # should be good enough. + if IsHeaderFile(filename): + for alternative in PotentialAlternatives(filename): + if os.path.exists(alternative): + compilation_info = database.GetCompilationInfoForFile( + alternative + ) + + if compilation_info.compiler_flags_: + return compilation_info + return None + else: + return database.GetCompilationInfoForFile(filename) + + +def FlagsForFile(filename, **kwargs): + # Bear in mind that compilation_info.compiler_flags_ does NOT return a + # python list, but a "list-like" StringVec object + compilation_info = GetCompilationInfoForFile(filename) + if not compilation_info: + return { + 'flags':MakeRelativePathsInFlagsAbsolute(default_flags,DirectoryOfThisScript()), + 'do_cache': True, + } + + final_flags = MakeRelativePathsInFlagsAbsolute( + compilation_info.compiler_flags_, + compilation_info.compiler_working_dir_ + ) + + # Make sure ycm reports more suspicuous code lines + final_flags.append('-Wextra') + + return { + 'flags': final_flags, + 'do_cache': True + } diff --git a/CMake/DownloadFile.cmake b/CMake/DownloadFile.cmake new file mode 100644 index 0000000000..d0165b11a3 --- /dev/null +++ b/CMake/DownloadFile.cmake @@ -0,0 +1,71 @@ +# Helper to download files as needed + +function(file_md5_if_exists FILE VAR) + if(EXISTS "${FILE}") + file(MD5 "${FILE}" "${VAR}") + set(${VAR} "${${VAR}}" PARENT_SCOPE) + else() + set(${VAR} "" PARENT_SCOPE) + endif() +endfunction() + +function(search_downloads FILE_MD5 VAR) + set(${VAR} "" PARENT_SCOPE) + file(GLOB FILES ${dfhack_SOURCE_DIR}/CMake/downloads/*) + foreach(FILE ${FILES}) + file(MD5 "${FILE}" CUR_MD5) + if("${CUR_MD5}" STREQUAL "${FILE_MD5}") + set(${VAR} ${FILE} PARENT_SCOPE) + return() + endif() + endforeach() +endfunction() + +function(download_file URL DEST EXPECTED_MD5) + get_filename_component(FILENAME "${URL}" NAME) + file_md5_if_exists("${DEST}" CUR_MD5) + + if(NOT "${EXPECTED_MD5}" STREQUAL "${CUR_MD5}") + search_downloads(${EXPECTED_MD5} DLPATH) + if(NOT("${DLPATH}" STREQUAL "")) + message("* Copying ${FILENAME} from ${DLPATH}") + execute_process(COMMAND "${CMAKE_COMMAND}" -E copy + "${DLPATH}" + "${DEST}") + return() + endif() + + message("* Downloading ${FILENAME}") + file(DOWNLOAD "${URL}" "${DEST}" EXPECTED_MD5 "${EXPECTED_MD5}" SHOW_PROGRESS) + endif() +endfunction() + +# Download a file and uncompress it +function(download_file_unzip URL ZIP_TYPE ZIP_DEST ZIP_MD5 UNZIP_DEST UNZIP_MD5) + get_filename_component(FILENAME "${URL}" NAME) + file_md5_if_exists("${UNZIP_DEST}" CUR_UNZIP_MD5) + + # Redownload if the MD5 of the uncompressed file doesn't match + if(NOT "${UNZIP_MD5}" STREQUAL "${CUR_UNZIP_MD5}") + download_file("${URL}" "${ZIP_DEST}" "${ZIP_MD5}") + + if(EXISTS "${ZIP_DEST}") + message("* Decompressing ${FILENAME}") + if("${ZIP_TYPE}" STREQUAL "gz") + execute_process(COMMAND + "${PERL_EXECUTABLE}" "${dfhack_SOURCE_DIR}/depends/gunzip.pl" + "${ZIP_DEST}" --force) + else() + message(SEND_ERROR "Unknown ZIP_TYPE: ${ZIP_TYPE}") + endif() + if(NOT EXISTS "${UNZIP_DEST}") + message(SEND_ERROR "File failed to unzip to ${UNZIP_DEST}") + else() + file(MD5 "${UNZIP_DEST}" CUR_UNZIP_MD5) + if(NOT "${UNZIP_MD5}" STREQUAL "${CUR_UNZIP_MD5}") + message(SEND_ERROR "MD5 mismatch: ${UNZIP_DEST}: expected ${UNZIP_MD5}, got ${CUR_UNZIP_MD5}") + endif() + endif() + endif() + endif() +endfunction() diff --git a/CMake/Modules/CMakeVS10FindMake.cmake b/CMake/Modules/CMakeVS10FindMake.cmake deleted file mode 100644 index 460de25e5d..0000000000 --- a/CMake/Modules/CMakeVS10FindMake.cmake +++ /dev/null @@ -1,28 +0,0 @@ - -#============================================================================= -# Copyright 2009 Kitware, Inc. -# -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. -#============================================================================= -# (To distributed this file outside of CMake, substitute the full -# License text for the above reference.) - -# We use MSBuild as the build tool for VS 10 -FIND_PROGRAM(CMAKE_MAKE_PROGRAM - NAMES MSBuild - HINTS - [HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\10.0\\Setup\\VS;ProductDir] - "$ENV{SYSTEMROOT}/Microsoft.NET/Framework/[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\10.0;CLR Version]/" - "c:/WINDOWS/Microsoft.NET/Framework/[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\10.0;CLR Version]/" - "$ENV{SYSTEMROOT}/Microsoft.NET/Framework/[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\10.0;CLR Version]/" - ) - -MARK_AS_ADVANCED(CMAKE_MAKE_PROGRAM) -SET(MSVC10 1) -SET(MSVC_VERSION 1600) - diff --git a/CMake/Modules/FindCurses.cmake b/CMake/Modules/FindCurses.cmake deleted file mode 100644 index 98adf9815f..0000000000 --- a/CMake/Modules/FindCurses.cmake +++ /dev/null @@ -1,23 +0,0 @@ -IF(Curses_FOUND) - SET(Curses_FIND_QUIETLY TRUE) -ENDIF() - -FIND_PATH(Curses_INCLUDE_PATH - NAMES ncurses.h curses.h - PATH_SUFFIXES ncurses - PATHS /usr/include/ncursesw /usr/include /usr/local/include /usr/pkg/include -) - -FIND_LIBRARY(Curses_LIBRARY - NAMES ncursesw - PATHS /lib /usr/lib /usr/local/lib /usr/pkg/lib -) - -IF (Curses_INCLUDE_PATH AND Curses_LIBRARY) - SET(Curses_FOUND TRUE) -ENDIF() - -MARK_AS_ADVANCED( - Curses_INCLUDE_PATH - Curses_LIBRARY -) diff --git a/CMake/Modules/FindDoxygen.cmake b/CMake/Modules/FindDoxygen.cmake deleted file mode 100644 index 94d20a9ffd..0000000000 --- a/CMake/Modules/FindDoxygen.cmake +++ /dev/null @@ -1,185 +0,0 @@ -# - This module looks for Doxygen and the path to Graphviz's dot -# Doxygen is a documentation generation tool. Please see -# http://www.doxygen.org -# -# This module accepts the following optional variables: -# -# DOXYGEN_SKIP_DOT = If true this module will skip trying to find Dot -# (an optional component often used by Doxygen) -# -# This modules defines the following variables: -# -# DOXYGEN_EXECUTABLE = The path to the doxygen command. -# DOXYGEN_FOUND = Was Doxygen found or not? -# -# DOXYGEN_DOT_EXECUTABLE = The path to the dot program used by doxygen. -# DOXYGEN_DOT_FOUND = Was Dot found or not? -# DOXYGEN_DOT_PATH = The path to dot not including the executable -# -# - -#Copyright 2000-2009 Kitware, Inc., Insight Software Consortium -#All rights reserved. -# -#Redistribution and use in source and binary forms, with or without -#modification, are permitted provided that the following conditions -#are met: -# -#* Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# -#* Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -#* Neither the names of Kitware, Inc., the Insight Software Consortium, -# nor the names of their contributors may be used to endorse or promote -# products derived from this software without specific prior written -# permission. -# -#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -#"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -#LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -#A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -#HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -#SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -#LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -#DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -#THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -#(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -#OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -#----------------------------------------------------------------------------- -# -#The above copyright and license notice applies to distributions of -#CMake in source and binary form. Some source files contain additional -#notices of original copyright by their contributors; see each source -#for details. Third-party software packages supplied with CMake under -#compatible licenses provide their own copyright notices documented in -#corresponding subdirectories. -# -#----------------------------------------------------------------------------- -# -#CMake was initially developed by Kitware with the following sponsorship: -# -# * National Library of Medicine at the National Institutes of Health -# as part of the Insight Segmentation and Registration Toolkit (ITK). -# -# * US National Labs (Los Alamos, Livermore, Sandia) ASC Parallel -# Visualization Initiative. -# -# * National Alliance for Medical Image Computing (NAMIC) is funded by the -# National Institutes of Health through the NIH Roadmap for Medical Research, -# Grant U54 EB005149. -# -# * Kitware, Inc. - - -# For backwards compatibility support -IF(Doxygen_FIND_QUIETLY) - SET(DOXYGEN_FIND_QUIETLY TRUE) -ENDIF(Doxygen_FIND_QUIETLY) - -# ===== Rationale for OS X AppBundle mods below ===== -# With the OS X GUI version, Doxygen likes to be installed to /Applications and -# it contains the doxygen executable in the bundle. In the versions I've -# seen, it is located in Resources, but in general, more often binaries are -# located in MacOS. -# -# NOTE: The official Doxygen.app that is distributed for OS X uses non-standard -# conventions. Instead of the command-line "doxygen" tool being placed in -# Doxygen.app/Contents/MacOS, "Doxywizard" is placed there instead and -# "doxygen" is placed in Contents/Resources. This is most likely done -# so that something happens when people double-click on the Doxygen.app -# package. Unfortunately, CMake gets confused by this as when it sees the -# bundle it uses "Doxywizard" as the executable to use instead of -# "doxygen". Therefore to work-around this issue we temporarily disable -# the app-bundle feature, just for this CMake module: -if(APPLE) - # Save the old setting - SET(TEMP_DOXYGEN_SAVE_CMAKE_FIND_APPBUNDLE ${CMAKE_FIND_APPBUNDLE}) - # Disable the App-bundle detection feature - SET(CMAKE_FIND_APPBUNDLE "NEVER") -endif() -# FYI: -# In the older versions of OS X Doxygen, dot was included with the -# Doxygen bundle. But the new versions require you to download -# Graphviz.app which contains "dot" in it's bundle. -# ============== End OSX stuff ================ - -# -# Find Doxygen... -# - -FIND_PROGRAM(DOXYGEN_EXECUTABLE - NAMES doxygen - PATHS - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\doxygen_is1;Inno Setup: App Path]/bin" - /Applications/Doxygen.app/Contents/Resources - /Applications/Doxygen.app/Contents/MacOS - DOC "Doxygen documentation generation tool (http://www.doxygen.org)" -) - -include(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(Doxygen DEFAULT_MSG DOXYGEN_EXECUTABLE) - -# -# Find Dot... -# - -IF(NOT DOXYGEN_SKIP_DOT) - FIND_PROGRAM(DOXYGEN_DOT_EXECUTABLE - NAMES dot - PATHS - "$ENV{ProgramFiles}/Graphviz2.26.3/bin" - "C:/Program Files/Graphviz2.26.3/bin" - "$ENV{ProgramFiles}/Graphviz 2.21/bin" - "C:/Program Files/Graphviz 2.21/bin" - "$ENV{ProgramFiles}/ATT/Graphviz/bin" - "C:/Program Files/ATT/Graphviz/bin" - [HKEY_LOCAL_MACHINE\\SOFTWARE\\ATT\\Graphviz;InstallPath]/bin - /Applications/Graphviz.app/Contents/MacOS - /Applications/Doxygen.app/Contents/Resources - /Applications/Doxygen.app/Contents/MacOS - DOC "Graphviz Dot tool for using Doxygen" - ) - - if(DOXYGEN_DOT_EXECUTABLE) - set(DOXYGEN_DOT_FOUND TRUE) - # The Doxyfile wants the path to Dot, not the entire path and executable - get_filename_component(DOXYGEN_DOT_PATH "${DOXYGEN_DOT_EXECUTABLE}" PATH CACHE) - endif() - -endif(NOT DOXYGEN_SKIP_DOT) - -# -# Backwards compatibility... -# - -if(APPLE) - # Restore the old app-bundle setting setting - SET(CMAKE_FIND_APPBUNDLE ${TEMP_DOXYGEN_SAVE_CMAKE_FIND_APPBUNDLE}) -endif() - -# Maintain the _FOUND variables as "YES" or "NO" for backwards compatibility -# (allows people to stuff them directly into Doxyfile with configure_file()) -if(DOXYGEN_FOUND) - set(DOXYGEN_FOUND "YES") -else() - set(DOXYGEN_FOUND "NO") -endif() -if(DOXYGEN_DOT_FOUND) - set(DOXYGEN_DOT_FOUND "YES") -else() - set(DOXYGEN_DOT_FOUND "NO") -endif() - -# For backwards compatibility support -SET (DOXYGEN ${DOXYGEN_EXECUTABLE} ) -SET (DOT ${DOXYGEN_DOT_EXECUTABLE} ) - -MARK_AS_ADVANCED( - DOXYGEN_EXECUTABLE - DOXYGEN_DOT_EXECUTABLE - DOXYGEN_DOT_PATH - ) diff --git a/CMake/Modules/FindSphinx.cmake b/CMake/Modules/FindSphinx.cmake new file mode 100644 index 0000000000..6b78a555ff --- /dev/null +++ b/CMake/Modules/FindSphinx.cmake @@ -0,0 +1,15 @@ +# build the documentation with Sphinx +find_program(SPHINX_EXECUTABLE NAMES sphinx-build + HINTS + $ENV{SPHINX_DIR} + PATH_SUFFIXES bin + DOC "Sphinx Documentation Generator" +) + +include(FindPackageHandleStandardArgs) + +find_package_handle_standard_args(Sphinx DEFAULT_MSG + SPHINX_EXECUTABLE +) + +mark_as_advanced(SPHINX_EXECUTABLE) diff --git a/CMake/Modules/FindTinyXML.cmake b/CMake/Modules/FindTinyXML.cmake new file mode 100644 index 0000000000..4d6d69f7bb --- /dev/null +++ b/CMake/Modules/FindTinyXML.cmake @@ -0,0 +1,107 @@ +# Sourced from: +# https://raw.githubusercontent.com/ros/cmake_modules/0.4-devel/cmake/Modules/FindTinyXML.cmake +# under the following license: https://github.com/ros/cmake_modules/blob/0.4-devel/LICENSE, +# reproduced here: + +# Copyright (c) 2013, Open Source Robotics Foundation +# All rights reserved. + +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: + +# Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. + +# Redistributions in binary form must reproduce the above copyright notice, this +# list of conditions and the following disclaimer in the documentation and/or +# other materials provided with the distribution. + +# Neither the name of the {organization} nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. + +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +################################################################################################## +# +# CMake script for finding TinyXML. +# +# Input variables: +# +# - TinyXML_ROOT_DIR (optional): When specified, header files and libraries will be searched for in +# ${TinyXML_ROOT_DIR}/include +# ${TinyXML_ROOT_DIR}/libs +# respectively, and the default CMake search order will be ignored. When unspecified, the default +# CMake search order is used. +# This variable can be specified either as a CMake or environment variable. If both are set, +# preference is given to the CMake variable. +# Use this variable for finding packages installed in a nonstandard location, or for enforcing +# that one of multiple package installations is picked up. +# +# +# Cache variables (not intended to be used in CMakeLists.txt files) +# +# - TinyXML_INCLUDE_DIR: Absolute path to package headers. +# - TinyXML_LIBRARY: Absolute path to library. +# +# +# Output variables: +# +# - TinyXML_FOUND: Boolean that indicates if the package was found +# - TinyXML_INCLUDE_DIRS: Paths to the necessary header files +# - TinyXML_LIBRARIES: Package libraries +# +# +# Example usage: +# +# find_package(TinyXML) +# if(NOT TinyXML_FOUND) +# # Error handling +# endif() +# ... +# include_directories(${TinyXML_INCLUDE_DIRS} ...) +# ... +# target_link_libraries(my_target ${TinyXML_LIBRARIES}) +# +################################################################################################## + +# Get package location hint from environment variable (if any) +if(NOT TinyXML_ROOT_DIR AND DEFINED ENV{TinyXML_ROOT_DIR}) + set(TinyXML_ROOT_DIR "$ENV{TinyXML_ROOT_DIR}" CACHE PATH + "TinyXML base directory location (optional, used for nonstandard installation paths)") +endif() + +# Search path for nonstandard package locations +if(TinyXML_ROOT_DIR) + set(TinyXML_INCLUDE_PATH PATHS "${TinyXML_ROOT_DIR}/include" NO_DEFAULT_PATH) + set(TinyXML_LIBRARY_PATH PATHS "${TinyXML_ROOT_DIR}/lib" NO_DEFAULT_PATH) +endif() + +# Find headers and libraries +find_path(TinyXML_INCLUDE_DIR NAMES tinyxml.h PATH_SUFFIXES "tinyxml" ${TinyXML_INCLUDE_PATH}) +find_library(TinyXML_LIBRARY NAMES tinyxml PATH_SUFFIXES "tinyxml" ${TinyXML_LIBRARY_PATH}) + +mark_as_advanced(TinyXML_INCLUDE_DIR + TinyXML_LIBRARY) + +# Output variables generation +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(TinyXML DEFAULT_MSG TinyXML_LIBRARY + TinyXML_INCLUDE_DIR) + +set(TinyXML_FOUND ${TINYXML_FOUND}) # Enforce case-correctness: Set appropriately cased variable... +unset(TINYXML_FOUND) # ...and unset uppercase variable generated by find_package_handle_standard_args + +if(TinyXML_FOUND) + set(TinyXML_INCLUDE_DIRS ${TinyXML_INCLUDE_DIR}) + set(TinyXML_LIBRARIES ${TinyXML_LIBRARY}) +endif() diff --git a/CMake/downloads/.gitignore b/CMake/downloads/.gitignore new file mode 100644 index 0000000000..ff7b252fea --- /dev/null +++ b/CMake/downloads/.gitignore @@ -0,0 +1,3 @@ +* +!README.txt +!.gitignore diff --git a/CMake/downloads/README.txt b/CMake/downloads/README.txt new file mode 100644 index 0000000000..40b5047257 --- /dev/null +++ b/CMake/downloads/README.txt @@ -0,0 +1,3 @@ +This folder exists as an alternate location for downloaded files. Files will +ordinarily not be downloaded here, but CMake will look for them here anyway to +facilitate offline builds. diff --git a/CMakeLists.txt b/CMakeLists.txt index 173ea571d7..61bddcc0b4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,286 +1,646 @@ # main project file. use it from a build sub-folder, see COMPILE for details ## some generic CMake magic -cmake_minimum_required(VERSION 2.8.0 FATAL_ERROR) -PROJECT (dfhack) +cmake_minimum_required(VERSION 3.18 FATAL_ERROR) +cmake_policy(SET CMP0048 NEW) +cmake_policy(SET CMP0074 NEW) +set(CMAKE_INSTALL_MESSAGE "LAZY") + +# set up versioning. +set(DF_VERSION "53.15") +set(DFHACK_RELEASE "r2") +set(DFHACK_PRERELEASE FALSE) + +set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") +set(DFHACK_ABI_VERSION 2) +set(DFHACK_BUILD_ID "" CACHE STRING "Build ID (should be specified on command line)") + +# set up ccache +find_program(CCACHE_EXECUTABLE "ccache" HINTS /usr/local/bin /opt/local/bin) +if(CCACHE_EXECUTABLE) + message(STATUS "using ccache") + set(CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE_EXECUTABLE}" CACHE PATH "ccache" FORCE) + set(CMAKE_C_COMPILER_LAUNCHER "${CCACHE_EXECUTABLE}" CACHE PATH "ccache" FORCE) +endif() + +# project must be declared *after* ccache setup +project(dfhack) + +# Set up build types +if(CMAKE_CONFIGURATION_TYPES) + set(CMAKE_CONFIGURATION_TYPES "Release;RelWithDebInfo" CACHE STRING "List of supported configuration types" FORCE) +else(CMAKE_CONFIGURATION_TYPES) + set(DFHACK_TYPE_HELP "Choose the type of build, options are: Release and RelWithDebInfo") + # Prevent cmake C module attempts to overwrite our help string + if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE "Release" CACHE STRING "${DFHACK_TYPE_HELP}") + else(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE "${CMAKE_BUILD_TYPE}" CACHE STRING "${DFHACK_TYPE_HELP}") + endif(NOT CMAKE_BUILD_TYPE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Release;RelWithDebInfo") +endif(CMAKE_CONFIGURATION_TYPES) + +option(BUILD_DOCS "Choose whether to build the documentation (requires python and Sphinx)." OFF) +option(BUILD_DOCS_NO_HTML "Don't build the HTML docs, only the in-game docs." OFF) +option(REMOVE_SYMBOLS_FROM_DF_STUBS "Remove debug symbols from DF stubs. (Reduces libdfhack size to about half but removes a few useful symbols)" ON) + +macro(CHECK_GCC compiler_path) + execute_process(COMMAND ${compiler_path} -dumpversion OUTPUT_VARIABLE GCC_VERSION_OUT) + string(STRIP "${GCC_VERSION_OUT}" GCC_VERSION_OUT) + if(${GCC_VERSION_OUT} VERSION_LESS "11") + message(SEND_ERROR "${compiler_path} version ${GCC_VERSION_OUT} cannot be used - use GCC 11 or later") + endif() +endmacro() + +if(UNIX) + if(CMAKE_COMPILER_IS_GNUCC) + check_gcc(${CMAKE_C_COMPILER}) + else() + message(SEND_ERROR "C compiler is not GCC") + endif() + if(CMAKE_COMPILER_IS_GNUCXX) + check_gcc(${CMAKE_CXX_COMPILER}) + else() + message(SEND_ERROR "C++ compiler is not GCC") + endif() +endif() + +if(WIN32) + set(MSVC_MIN_VER 1930) + set(MSVC_MAX_VER 1944) + if(NOT MSVC) + message(SEND_ERROR "No MSVC found! MSVC 2022 version ${MSVC_MIN_VER} to ${MSVC_MAX_VER} is required.") + elseif((MSVC_VERSION LESS MSVC_MIN_VER) OR (MSVC_VERSION GREATER MSVC_MAX_VER)) + message(SEND_ERROR "MSVC 2022 version ${MSVC_MIN_VER} to ${MSVC_MAX_VER} is required, Version Found: ${MSVC_VERSION}") + endif() +endif() + +# Ask for C++-20 standard from compilers +set(CMAKE_CXX_STANDARD 20) +# Require the standard support from compilers. +set(CMAKE_CXX_STANDARD_REQUIRED ON) +# Use only standard c++ to keep code portable +set(CMAKE_CXX_EXTENSIONS OFF) + +if(MSVC) + # increase warning level and treat warnings as errors + add_compile_options("/WX") + add_compile_options("/W3") + + # disable C4819 code-page warning + add_compile_options("/wd4819") + + # disable use of POSIX name warnings + add_definitions("/D_CRT_NONSTDC_NO_WARNINGS /D_CRT_SECURE_NO_WARNINGS") + + # supress C4503 - VC++ dislikes if a name is too long. If you get + # weird and mysterious linking errors, you can disable this, but you'll have to + # deal with a LOT of compiler noise over it + # see https://msdn.microsoft.com/en-us/library/074af4b6.aspx + add_compile_options("/wd4503") + + # suppress C4267 - VC++ considers a narrowing conversion from size_t to a smaller + # integer type a warning. this is technically correct but there are so many instances + # of this that we don't want to fix, so.... + add_compile_options("/wd4267") + + # suppress C4251 - VC++ will warn when exporting an entire class which contains members + # referencing unexported compound types as this is potentially unsafe. because we don't + # guarantee a stable ABI for exports, we don't really care about this, and so we choose to + # be lazy and continue to export entire classes instead of exporting on a method-by-method basis + add_compile_options("/wd4251") + + # suppress C4068 - VC++ will warn for unknown pragmas by default. this is equivalent to gcc + # -Wno-unknown-pragmas (which is enabled for gcc below). + # we could work around this with sufficiently complex macros + add_compile_options("/wd4068") + + # suppress C4244 - VC++ warns by default (with /W3) about narrowing conversions that may lose data + # (such as double -> int or int32_t -> int16_t). dfhack has many of these, mostly related to Lua + # this is equivalent to gcc -Wno_conversions which is the default as gcc -Wall doesn't enable -Wconversions + add_compile_options("/wd4244") + + # Enable C5038 - This is equivalent to gcc's -Werror=reorder, which is enabled by default by gcc -Wall + add_compile_options("/w15038") + + # Enable C4062 - Warns about missing enum case in switch statement, equivalent to gcc -Wswitch + add_compile_options("/w14062") + + # MSVC panics if an object file contains more than 65,279 sections. this + # happens quite frequently with code that uses templates, such as vectors. + add_compile_options("/bigobj") +endif() + +# Automatically detect architecture based on Visual Studio generator +if(MSVC AND NOT DEFINED DFHACK_BUILD_ARCH) + if ((${CMAKE_GENERATOR} MATCHES "Win32") OR (${CMAKE_GENERATOR} MATCHES "x86")) + message(SEND_ERROR "DF v50 does not support 32-bit") + else() + set(DFHACK_BUILD_ARCH "64") + endif() +else() + set(DFHACK_BUILD_ARCH "64" CACHE STRING "Architecture to build ('32' or '64')") +endif() + +if("${DFHACK_BUILD_ARCH}" STREQUAL "32") + set(DFHACK_BUILD_32 1) + set(DFHACK_BUILD_64 0) + set(DFHACK_SETARCH "i386") +elseif("${DFHACK_BUILD_ARCH}" STREQUAL "64") + set(DFHACK_BUILD_32 0) + set(DFHACK_BUILD_64 1) + set(DFHACK_SETARCH "x86_64") + add_definitions(-DDFHACK64) +else() + message(SEND_ERROR "Invalid build architecture (should be 32 or 64): ${DFHACK_BUILD_ARCH}") +endif() + +if(CMAKE_CROSSCOMPILING) + set(DFHACK_NATIVE_BUILD_DIR "DFHACK_NATIVE_BUILD_DIR-NOTFOUND" CACHE FILEPATH "Path to a native build directory") + include("${DFHACK_NATIVE_BUILD_DIR}/ImportExecutables.cmake") +endif() + +find_package(Perl REQUIRED) + +# set up folder structures for IDE solutions +# checking for msvc express is meaningless now, all available editions of msvc support folder groupings +option(CMAKE_USE_FOLDERS "Enable folder grouping of projects in IDEs." ON) + +if(CMAKE_USE_FOLDERS) + set_property(GLOBAL PROPERTY USE_FOLDERS ON) +else() + set_property(GLOBAL PROPERTY USE_FOLDERS OFF) +endif() -SET(CMAKE_MODULE_PATH -${dfhack_SOURCE_DIR}/CMake/Modules -${CMAKE_MODULE_PATH} +# macro for setting up IDE folders without nasty if()s everywhere +macro(IDE_FOLDER target folder) + if(CMAKE_USE_FOLDERS) + set_property(TARGET ${target} PROPERTY FOLDER ${folder}) + endif() +endmacro() + +set(CMAKE_MODULE_PATH + ${dfhack_SOURCE_DIR}/CMake/Modules + ${CMAKE_MODULE_PATH} ) -if("${dfhack_SOURCE_DIR}" STREQUAL "${dfhack_BINARY_DIR}") - message(FATAL_ERROR "In-source builds are not allowed.") +# generates compile_commands.json, used for autocompletion by some editors +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +include(CheckCXXSourceCompiles) +check_cxx_source_compiles(" +#include +#include +int main(void) { + char32_t in = 0; + char out[MB_CUR_MAX]; + std::mbstate_t state{}; + std::c32rtomb(out, in, &state); + return 0; +}" HAVE_CUCHAR2) +if(HAVE_CUCHAR2) + add_definitions("-DHAVE_CUCHAR") +endif() + +# mixing the build system with the source code is ugly and stupid. enforce the opposite :) +if("${dfhack_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}") + message(FATAL_ERROR "In-source builds are not allowed.") +endif() + +# make sure all the necessary submodules have been set up +if(NOT EXISTS ${dfhack_SOURCE_DIR}/library/xml/codegen.pl + OR NOT EXISTS ${dfhack_SOURCE_DIR}/scripts/CMakeLists.txt + OR NOT EXISTS ${dfhack_SOURCE_DIR}/depends/dfhooks/CMakeLists.txt + OR NOT EXISTS ${dfhack_SOURCE_DIR}/depends/clsocket/CMakeLists.txt + OR NOT EXISTS ${dfhack_SOURCE_DIR}/depends/jsoncpp-sub/CMakeLists.txt + OR NOT EXISTS ${dfhack_SOURCE_DIR}/depends/libexpat/expat/CMakeLists.txt + OR NOT EXISTS ${dfhack_SOURCE_DIR}/depends/libzip/CMakeLists.txt + OR NOT EXISTS ${dfhack_SOURCE_DIR}/depends/xlsxio/CMakeLists.txt + OR NOT EXISTS ${dfhack_SOURCE_DIR}/depends/googletest/CMakeLists.txt + OR NOT EXISTS ${dfhack_SOURCE_DIR}/depends/luacov/src +) + message(SEND_ERROR "One or more required submodules could not be found! Run 'git submodule update --init' from the root DFHack directory. (See the section 'Getting the Code' in docs/dev/compile/Compile.rst)") +endif() + +# dfhack data goes here: +set(DFHACK_DATA_DESTINATION hack) + +## where to install things (after the build is done, classic 'make install' or package structure) +# the dfhack libraries will be installed here: + +# put the lib into DF/hack +# windows will find it because dfhooks will `AddDllDirectory` the hack folder at runtime +set(DFHACK_LIBRARY_DESTINATION ${DFHACK_DATA_DESTINATION}) + +# external tools will be installed here: +set(DFHACK_BINARY_DESTINATION .) +# plugin libs go here: +set(DFHACK_PLUGIN_DESTINATION ${DFHACK_DATA_DESTINATION}/plugins) +# dfhack lua files go here: +set(DFHACK_LUA_DESTINATION ${DFHACK_DATA_DESTINATION}/lua) + +# user documentation goes here: +set(DFHACK_USERDOC_DESTINATION ${DFHACK_DATA_DESTINATION}) + +# some options for the user/developer to play with +option(BUILD_LIBRARY "Build the DFHack library." ON) +option(BUILD_PLUGINS "Build the DFHack plugins." ON) +option(INSTALL_SCRIPTS "Install DFHack scripts." ON) +option(INSTALL_DATA_FILES "Install DFHack platform independent files." ON) + +set(CMAKE_POSITION_INDEPENDENT_CODE TRUE) +if(UNIX) + ## flags for GCC + # default to hidden symbols + # ensure compatibility with older CPUs + add_definitions(-DLINUX_BUILD) + set(GCC_COMMON_FLAGS "-fvisibility=hidden -mtune=generic -Wall -Werror -Wl,--disable-new-dtags -Wno-unknown-pragmas") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GCC_COMMON_FLAGS}") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${GCC_COMMON_FLAGS}") + if(DFHACK_BUILD_64) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m64 -mno-avx") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m64 -mno-avx") + else() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32 -march=i686") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32 -march=i686") + endif() + string(REPLACE "-DNDEBUG" "" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") + set(CMAKE_INSTALL_RPATH "$ORIGIN") +elseif(MSVC) + # for msvc, tell it to always use 8-byte pointers to member functions to avoid confusion + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /vmg /vmm /MP") + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Od") + string(REPLACE "/O2" "" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") + string(REPLACE "/DNDEBUG" "" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") + + option(BUILD_PDBS "Build PDB debug symbol files." OFF) + if(BUILD_PDBS) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Z7") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /DEBUG") + set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} /DEBUG") + endif() +endif() + +# use shared libraries for protobuf +add_definitions(-DPROTOBUF_USE_DLLS) +add_definitions(-DLUA_BUILD_AS_DLL) + +if(APPLE) + add_definitions(-D_DARWIN) + set(CMAKE_MACOSX_RPATH 1) +elseif(UNIX) + add_definitions(-D_LINUX) +elseif(WIN32) + add_definitions(-DWIN32) endif() -SET(DFHACK_CONSISTENCY 1) - -set(CPACK_PACKAGE_VERSION_MAJOR "0") -set(CPACK_PACKAGE_VERSION_MINOR "5") -set(CPACK_PACKAGE_VERSION_PATCH "15") -set(DFHACK_REVISION "1") - -set(DFHACK_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}") -set(CPACK_PACKAGE_VERSION ${DFHACK_VERSION}) - -set(CPACK_PACKAGE_NAME "dfhack") -SET(CPACK_PACKAGE_VENDOR "dethware.org") -SET(CPACK_PACKAGE_CONTACT "peterix@dethware.org") -SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Memory hacks for Dwarf Fortress") -SET(CPACK_PACKAGE_DESCRIPTION -"DFHack is a Dwarf Fortress memory access library and a set of basic -tools using this library. The library is a work in progress, so things -might change as more tools are written for it. -. -It is an attempt to unite the various ways tools access DF memory and -allow for easier development of new tools.") - - -## setting the build type -IF(NOT DEFINED CMAKE_BUILD_TYPE OR CMAKE_BUILD_TYPE STREQUAL "") - SET(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel.") -ENDIF() - -## put everything in one big ugly directory to make MSVC and KDevelop debuggers happy -SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${dfhack_BINARY_DIR}/bin") -SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${dfhack_BINARY_DIR}/bin") -SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${dfhack_BINARY_DIR}/bin") - -IF(WIN32) - set (DFHACK_INST_DEFAULT "portable") -ELSE() - set (DFHACK_INST_DEFAULT "linux") -ENDIF() - -SET( DFHACK_INSTALL ${DFHACK_INST_DEFAULT} CACHE STRING -"Choose the install type: -'portable' for a portable zip or tar.gz package (windows default) -'linux' for generic packaging and system installs on linux (linux default) -'ubuntu-10.10' for ubuntu maverick package.") - -SET( MEMXML_DATA_PATH . CACHE PATH -"Path to a valid Memory.xml file. -This is baked into the library, so when you package DFHack for linux, set it to the right path.") - -IF(${DFHACK_INSTALL} STREQUAL "portable") - # the dfhack libraries will be installed here: - SET(DFHACK_LIBRARY_DESTINATION .) - # the dfhack tools will be installed here: - SET(DFHACK_BINARY_DESTINATION .) - # Memory.xml goes here: - SET(DFHACK_DATA_DESTINATION .) - # Includes go here: - SET(DFHACK_INCLUDES_DESTINATION dev/include) - # the Windows .lib files go here: - IF(WIN32) - SET(DFHACK_DEVLIB_DESTINATION dev) - SET(CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION .) - ENDIF() - IF(UNIX) - SET(CMAKE_INSTALL_RPATH "$ORIGIN") - ENDIF() - # documentation goes here: - SET(DFHACK_USERDOC_DESTINATION .) - SET(DFHACK_DEVDOC_DESTINATION dev) - SET(DFHACK_DOXYGEN_DESTINATION dev/doxygen) -ENDIF() - -# generic linux package in a .tar.gz -IF(${DFHACK_INSTALL} STREQUAL "linux") - if(WIN32) - MESSAGE(FATAL_ERROR "WTF are you doing?") +#### dependencies #### + +# fix for pyenv: default to `python3` before `python3.x` +set(Python_FIND_UNVERSIONED_NAMES FIRST) + +include(CMake/DownloadFile.cmake) + +if(WIN32) + set(ZLIB_FILE zlib.lib) + set(ZLIB_PATH ${dfhack_SOURCE_DIR}/depends/zlib/) + set(ZLIB_MD5 a3b2fc6b68efafa89b0882e354fc8418) + download_file("https://github.com/DFHack/dfhack-bin/releases/download/0.44.09/win64-${ZLIB_FILE}" + ${ZLIB_PATH}lib/${ZLIB_FILE} + ${ZLIB_MD5}) + set(ZLIB_ROOT ${ZLIB_PATH}) +else() + # Rescan for pthread and zlib if the build arch changed + if(NOT "${DFHACK_BUILD_ARCH}" STREQUAL "${DFHACK_BUILD_ARCH_PREV}") + unset(ZLIB_LIBRARY CACHE) + unset(CMAKE_HAVE_PTHREAD_H CACHE) endif() - # set RPATH to always point at the dfhack lib using relative path. - SET(CMAKE_INSTALL_RPATH "$ORIGIN/../lib/") - # the dfhack libraries will be installed here: - SET(DFHACK_LIBRARY_DESTINATION lib) - # the dfhack tools will be installed here: - SET(DFHACK_BINARY_DESTINATION bin) - # Memory.xml goes here: - SET(DFHACK_DATA_DESTINATION share/dfhack) - # Includes go here: - SET(DFHACK_INCLUDES_DESTINATION include) - # documentation goes here: - SET(DFHACK_USERDOC_DESTINATION share/dfhack/doc) - SET(DFHACK_DEVDOC_DESTINATION share/dfhack/doc) - SET(DFHACK_DOXYGEN_DESTINATION share/dfhack/doc/doxygen) -ENDIF() - -IF(${DFHACK_INSTALL} STREQUAL "ubuntu-10.10" OR ${DFHACK_INSTALL} STREQUAL "debian") - if(WIN32) - MESSAGE(FATAL_ERROR "WTF are you doing?") + + if(NOT APPLE AND DFHACK_BUILD_32) + set(ZLIB_ROOT /usr/lib/i386-linux-gnu) endif() - # set RPATH to always point at the dfhack lib using relative path. - SET(CMAKE_INSTALL_RPATH "$ORIGIN/../lib/") - # the dfhack libraries will be installed here: - SET(DFHACK_LIBRARY_DESTINATION usr/lib) - # the dfhack tools will be installed here: - SET(DFHACK_BINARY_DESTINATION usr/bin) - # Memory.xml goes here: - SET(DFHACK_DATA_DESTINATION usr/share/dfhack) - # Includes go here: - SET(DFHACK_INCLUDES_DESTINATION usr/include) - # documentation goes here: - SET(DFHACK_USERDOC_DESTINATION usr/share/dfhack/doc) - SET(DFHACK_DEVDOC_DESTINATION usr/share/dfhack/doc) - SET(DFHACK_DOXYGEN_DESTINATION usr/share/dfhack/doc/doxygen) - INSTALL(FILES - "${CMAKE_CURRENT_SOURCE_DIR}/package/${DFHACK_INSTALL}/99-dfhack.conf" - DESTINATION etc/sysctl.d) -ENDIF() - - - -## some options for the user/developer to play with -OPTION(BUILD_DFHACK_LIBRARY "Build the library. Needed for all the tools." ON) -OPTION(BUILD_DFHACK_C_BINDINGS "Build the C portion of the library." ON) -OPTION(BUILD_DFHACK_PYTHON_BINDINGS "Build/install the python wrapper." ON) -IF(WIN32) - OPTION(BUILD_DFHACK_DEVEL "Build the developer stuff." OFF) -ENDIF() -IF(UNIX) - OPTION(BUILD_DFHACK_DEVEL "Build the developer stuff." ON) -ENDIF() -OPTION(BUILD_DFHACK_DOXYGEN "Create doxygen documentation for developers" ON) -OPTION(BUILD_DFHACK_SUPPORTED "Build the supported tools." ON) -OPTION(BUILD_DFHACK_EXAMPLES "Build example tools" OFF) -OPTION(BUILD_DFHACK_PLAYGROUND "Build tools from the playground folder" OFF) - -include_directories (${dfhack_SOURCE_DIR}/library/include/) -include_directories (${dfhack_SOURCE_DIR}/library/shm/) -include_directories (${dfhack_SOURCE_DIR}/library/depends/argstream/) -include_directories (${dfhack_SOURCE_DIR}/library/depends/xgetopt/) - -# handle curses library bull**** on multiple platforms. -IF(UNIX) - find_package(Curses QUIET) - if(Curses_FOUND) - add_library(curses SHARED IMPORTED) - set_property(TARGET curses PROPERTY IMPORTED_LOCATION ${Curses_LIBRARY}) - include_directories (${Curses_INCLUDE_PATH}) +endif() +find_package(ZLIB REQUIRED) + +set(USE_SYSTEM_SDL2 OFF CACHE BOOL "Set to ON to use the system SDL2 headers.") + +if(BUILD_LIBRARY) + if(USE_SYSTEM_SDL2) + find_package(SDL2 REQUIRED CONFIG REQUIRED COMPONENTS SDL2) + else() + # Download SDL release and extract into depends in the build dir + # all we need are the header files (including generated headers), so the same release package + # will work for all platforms + # (the above statement is untested for OSX) + set(SDL_VERSION 2.26.2) + set(SDL_ZIP_MD5 574daf26d48de753d0b1e19823c9d8bb) + set(SDL_ZIP_FILE SDL2-devel-${SDL_VERSION}-VC.zip) + set(SDL_ZIP_PATH ${dfhack_SOURCE_DIR}/depends/SDL2/) + download_file("https://github.com/libsdl-org/SDL/releases/download/release-${SDL_VERSION}/${SDL_ZIP_FILE}" + ${SDL_ZIP_PATH}${SDL_ZIP_FILE} + ${SDL_ZIP_MD5}) + file(ARCHIVE_EXTRACT INPUT ${SDL_ZIP_PATH}${SDL_ZIP_FILE} + DESTINATION ${SDL_ZIP_PATH}) + set(SDL2_INCLUDE_DIRS ${SDL_ZIP_PATH}/SDL2-${SDL_VERSION}/include) endif() -ELSE() - add_library(curses SHARED IMPORTED) - set_property(TARGET curses PROPERTY IMPORTED_LOCATION ${dfhack_SOURCE_DIR}/pdcurses/pdcurses.dll) - set_property(TARGET curses PROPERTY IMPORTED_IMPLIB ${dfhack_SOURCE_DIR}/pdcurses/pdcurses.lib) - include_directories (${dfhack_SOURCE_DIR}/pdcurses) - add_custom_target( curses-copy - COMMAND "${CMAKE_COMMAND}" -E make_directory ${dfhack_BINARY_DIR}/bin/${CMAKE_CFG_INTDIR}/ - COMMAND "${CMAKE_COMMAND}" -E copy "${dfhack_SOURCE_DIR}/pdcurses/pdcurses.dll" ${dfhack_BINARY_DIR}/bin/${CMAKE_CFG_INTDIR}/ - DEPENDS "${dfhack_SOURCE_DIR}/pdcurses/pdcurses.dll") - SET(Curses_FOUND TRUE) - INSTALL(FILES "${dfhack_SOURCE_DIR}/pdcurses/pdcurses.dll" DESTINATION ${DFHACK_BINARY_DESTINATION}) -ENDIF() - -# macro to save on typing in the tool subdirs -# builds a tool, links it to the dfhack lib and makes sure the dependency -# LOCAL_DEPNAME is built first, in case there is one -MACRO(DFHACK_TOOL TOOL_NAME TOOL_SOURCES) - ADD_EXECUTABLE(${TOOL_NAME} ${TOOL_SOURCES}) - TARGET_LINK_LIBRARIES(${TOOL_NAME} dfhack) - if(DEFINED LOCAL_DEPNAME) - ADD_DEPENDENCIES(${TOOL_NAME} ${LOCAL_DEPNAME}) +endif() + +# this can be made conditional once we get to better platform support for std::format +INCLUDE(FetchContent) +FetchContent_Declare( + fmt + GIT_REPOSITORY https://github.com/fmtlib/fmt.git + GIT_TAG 790b9389ae99c4ddebdd2736a8602eca1fec684e # 12.1.0 + bugfix for MSVC warning + build time improvements +) +FetchContent_MakeAvailable(fmt) +set(FMTLIB fmt) +add_definitions("-DUSE_FMTLIB") + +if(APPLE) + # libstdc++ (GCC 4.8.5 for OS X 10.6) + # fixes crash-on-unwind bug in DF's libstdc++ + set(LIBSTDCXX_DOWNLOAD_DIR ${dfhack_SOURCE_DIR}/package/darwin/osx${DFHACK_BUILD_ARCH}) + + if(${GCC_VERSION_OUT} VERSION_LESS "4.9") + set(LIBSTDCXX_GCC_VER "48") + else() + set(LIBSTDCXX_GCC_VER "7") + set(LIBSTDCXX_DOWNLOAD_DIR "${LIBSTDCXX_DOWNLOAD_DIR}-gcc7") endif() - install(TARGETS - ${TOOL_NAME} - RUNTIME DESTINATION ${DFHACK_BINARY_DESTINATION}) -ENDMACRO() - -# same as above builds a curses tool instead of plain terminal one. -MACRO(DFHACK_CURSES_TOOL TOOL_NAME TOOL_SOURCES) - IF(Curses_FOUND) - ADD_EXECUTABLE(${TOOL_NAME} ${TOOL_SOURCES}) - TARGET_LINK_LIBRARIES(${TOOL_NAME} dfhack curses) - if(DEFINED LOCAL_DEPNAME) - ADD_DEPENDENCIES(${TOOL_NAME} ${LOCAL_DEPNAME}) + + if(${DFHACK_BUILD_ARCH} STREQUAL "64") + if(${LIBSTDCXX_GCC_VER} STREQUAL "48") + download_file_unzip("https://github.com/DFHack/dfhack-bin/releases/download/0.44.09/osx64-gcc48-libstdcxx.6.dylib.gz" + "gz" + ${LIBSTDCXX_DOWNLOAD_DIR}/libstdc++.6.dylib.gz + "cf26ed588be8e83c8e3a49919793b416" + ${LIBSTDCXX_DOWNLOAD_DIR}/libstdc++.6.dylib + "16dc6dbd4ecde7f9b95bb6dc91f07404") + else() + # GCC 7 + download_file_unzip("https://github.com/DFHack/dfhack-bin/releases/download/0.44.09/osx64-gcc7-libstdcxx.6.dylib.gz" + "gz" + ${LIBSTDCXX_DOWNLOAD_DIR}/libstdc++.6.dylib.gz + "81314b7846f9e8806409bef2160c76e6" + ${LIBSTDCXX_DOWNLOAD_DIR}/libstdc++.6.dylib + "93b6cf4b01e9a9084a508fd6a4a88992") endif() - if(WIN32) - ADD_DEPENDENCIES(${TOOL_NAME} curses-copy) - ENDIF() - install(TARGETS - ${TOOL_NAME} - RUNTIME DESTINATION ${DFHACK_BINARY_DESTINATION}) - ELSE() - MESSAGE(STATUS "Wide-character ncurses library not found - " ${TOOL_NAME} "can't be built") - ENDIF() -ENDMACRO() - - -IF(BUILD_DFHACK_LIBRARY) - - add_subdirectory (library) - - IF(BUILD_DFHACK_PYTHON_BINDINGS) - MESSAGE("TODO: write CMakeLists.txt for the python things.") - ENDIF() - IF(BUILD_DFHACK_SUPPORTED) - add_subdirectory (tools/supported) - ENDIF() - - IF(BUILD_DFHACK_EXAMPLES) - add_subdirectory (tools/examples) - ENDIF() - - IF(BUILD_DFHACK_PLAYGROUND) - add_subdirectory (tools/playground) - ENDIF() - - ## install the default documentation files - install(FILES LICENSE Readme.html DESTINATION ${DFHACK_USERDOC_DESTINATION}) + + else() # 32-bit + + if(${LIBSTDCXX_GCC_VER} STREQUAL "48") + download_file_unzip("https://github.com/DFHack/dfhack-bin/releases/download/0.44.09/osx32-gcc48-libstdcxx.6.dylib.gz" + "gz" + ${LIBSTDCXX_DOWNLOAD_DIR}/libstdc++.6.dylib.gz + "40f3d83871b114f0279240626311621b" + ${LIBSTDCXX_DOWNLOAD_DIR}/libstdc++.6.dylib + "c3f5678b8204917e03870834902c3e8b") + else() + # GCC 7 + download_file_unzip("https://github.com/DFHack/dfhack-bin/releases/download/0.44.09/osx32-gcc7-libstdcxx.6.dylib.gz" + "gz" + ${LIBSTDCXX_DOWNLOAD_DIR}/libstdc++.6.dylib.gz + "dbd213171f66edb90d204d525f10c969" + ${LIBSTDCXX_DOWNLOAD_DIR}/libstdc++.6.dylib + "b14c857e7e485a097c70a9ccd3132da7") + endif() + endif() + + if(NOT EXTERNAL_LIBSTDCXX) + install(PROGRAMS ${LIBSTDCXX_DOWNLOAD_DIR}/libstdc++.6.dylib + DESTINATION ./hack/) + endif() +endif() + +#### expose depends #### + +# Support linking against external tinyxml +# If we find an external tinyxml, set the DFHACK_TINYXML variable to "tinyxml" +# Otherwise, set it to "dfhack-tinyxml" +option(EXTERNAL_TINYXML "Choose to link against external TinyXML" OFF) +if(EXTERNAL_TINYXML) + find_package(TinyXML REQUIRED) + if(NOT TinyXML_FOUND) + message(SEND_ERROR "Could not find an external TinyXML, consider setting EXTERNAL_TINYXML to OFF.") + endif() + set(DFHACK_TINYXML "tinyxml") +else() + set(DFHACK_TINYXML "dfhack-tinyxml") +endif() + +if(BUILD_LIBRARY) + add_subdirectory(depends) +endif() + +# Testing with CTest +macro(dfhack_test name files) +if(BUILD_LIBRARY AND UNIX AND NOT APPLE) # remove this once our MSVC build env has been updated + add_executable(${name} ${files}) + target_include_directories(${name} PUBLIC depends/googletest/googletest/include) + target_link_libraries(${name} dfhack ${FMTLIB} gtest) + add_test(NAME ${name} COMMAND ${name}) +endif() +endmacro() +include(CTest) + +find_package(Git REQUIRED) +if(NOT GIT_FOUND) + message(SEND_ERROR "could not find git") +endif() + +# build the lib itself +add_subdirectory(library) +if(BUILD_LIBRARY) + file(WRITE ${CMAKE_BINARY_DIR}/dfhack_setarch.txt ${DFHACK_SETARCH}) + install(FILES ${CMAKE_BINARY_DIR}/dfhack_setarch.txt DESTINATION ${DFHACK_DATA_DESTINATION}) +endif() + +# build the plugins +add_subdirectory(plugins) + +if(INSTALL_DATA_FILES) + add_subdirectory(data) + install(FILES LICENSE.rst DESTINATION ${DFHACK_USERDOC_DESTINATION}) + install(FILES docs/changelog-placeholder.txt DESTINATION ${DFHACK_USERDOC_DESTINATION} RENAME changelog.txt) + install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/depends/luacov/src/luacov/ DESTINATION ${DFHACK_DATA_DESTINATION}/lua/luacov) +endif() + +if(INSTALL_SCRIPTS) + add_subdirectory(scripts) +endif() + +if(BUILD_DOCS) + find_package(Python3) + find_package(Sphinx) + + if(NOT SPHINX_FOUND) + message(SEND_ERROR "Sphinx not found but BUILD_DOCS enabled") + endif() + + file(GLOB SPHINX_GLOB_DEPS + LIST_DIRECTORIES false + "${CMAKE_CURRENT_SOURCE_DIR}/docs/images/*.png" + "${CMAKE_CURRENT_SOURCE_DIR}/docs/styles/*" + "${CMAKE_CURRENT_SOURCE_DIR}/data/init/*init" + ) + file(GLOB_RECURSE SPHINX_GLOB_RECURSE_DEPS + "${CMAKE_CURRENT_SOURCE_DIR}/*.rst" + "${CMAKE_CURRENT_SOURCE_DIR}/changelog.txt" + "${CMAKE_CURRENT_SOURCE_DIR}/docs/*py" + ) + list(FILTER SPHINX_GLOB_RECURSE_DEPS + EXCLUDE REGEX "docs/changelogs" + ) + list(FILTER SPHINX_GLOB_RECURSE_DEPS + EXCLUDE REGEX "docs/html" + ) + list(FILTER SPHINX_GLOB_RECURSE_DEPS + EXCLUDE REGEX "docs/tags" + ) + list(FILTER SPHINX_GLOB_RECURSE_DEPS + EXCLUDE REGEX "docs/text" + ) + list(FILTER SPHINX_GLOB_RECURSE_DEPS + EXCLUDE REGEX "docs/tools" + ) + set(SPHINX_DEPS ${SPHINX_GLOB_DEPS} ${SPHINX_GLOB_RECURSE_DEPS} ${SPHINX_SCRIPT_DEPS} + "${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt" + "${CMAKE_CURRENT_SOURCE_DIR}/conf.py" + ) + + if(BUILD_DOCS_NO_HTML) + set(SPHINX_OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/docs/text/index.txt") + set(SPHINX_BUILD_TARGETS text) + else() + set(SPHINX_OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/docs/html/.buildinfo") + set(SPHINX_BUILD_TARGETS html text) + endif() + + set_property( + DIRECTORY PROPERTY ADDITIONAL_CLEAN_FILES TRUE + "${CMAKE_CURRENT_SOURCE_DIR}/docs/changelogs" + "${CMAKE_CURRENT_SOURCE_DIR}/docs/html" + "${CMAKE_CURRENT_SOURCE_DIR}/docs/pdf" + "${CMAKE_CURRENT_SOURCE_DIR}/docs/pseudoxml" + "${CMAKE_CURRENT_SOURCE_DIR}/docs/tags" + "${CMAKE_CURRENT_SOURCE_DIR}/docs/text" + "${CMAKE_CURRENT_SOURCE_DIR}/docs/tools" + "${CMAKE_CURRENT_SOURCE_DIR}/docs/xml" + "${CMAKE_BINARY_DIR}/docs/html" + "${CMAKE_BINARY_DIR}/docs/pdf" + "${CMAKE_BINARY_DIR}/docs/pseudoxml" + "${CMAKE_BINARY_DIR}/docs/text" + "${CMAKE_BINARY_DIR}/docs/xml" + ) + + add_custom_command(OUTPUT ${SPHINX_OUTPUT} + COMMAND "${Python3_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/docs/build.py" + ${SPHINX_BUILD_TARGETS} --sphinx="${SPHINX_EXECUTABLE}" --quiet -- -W + DEPENDS ${SPHINX_DEPS} + COMMENT "Building documentation with Sphinx" + ) + + add_custom_target(dfhack_docs ALL + DEPENDS ${SPHINX_OUTPUT} + ) + # Sphinx doesn't touch this file if it didn't make changes, + # which makes CMake think it didn't complete + add_custom_command(TARGET dfhack_docs POST_BUILD + COMMAND ${CMAKE_COMMAND} -E touch ${SPHINX_OUTPUT}) + + if(NOT BUILD_DOCS_NO_HTML) + install(DIRECTORY ${dfhack_SOURCE_DIR}/docs/html/ + DESTINATION ${DFHACK_USERDOC_DESTINATION}/docs + FILES_MATCHING PATTERN "*" + PATTERN html/_sources EXCLUDE) + endif() + install(DIRECTORY ${dfhack_SOURCE_DIR}/docs/text/ + DESTINATION ${DFHACK_USERDOC_DESTINATION}/docs) + install(FILES docs/changelogs/news.rst docs/changelogs/news-dev.rst DESTINATION ${DFHACK_USERDOC_DESTINATION}) + install(FILES "README.html" DESTINATION "${DFHACK_DATA_DESTINATION}") +endif() + +option(BUILD_TESTS "Include tests (currently just installs Lua tests into the scripts folder)" OFF) +if(BUILD_TESTS) + if(EXISTS "${dfhack_SOURCE_DIR}/test/scripts") + message(SEND_ERROR "test/scripts must not exist in the dfhack repo since it would conflict with the tests installed from the scripts repo.") + endif() + install(DIRECTORY ${dfhack_SOURCE_DIR}/test + DESTINATION ${DFHACK_DATA_DESTINATION}/scripts) + install(FILES ci/test.lua DESTINATION ${DFHACK_DATA_DESTINATION}/scripts) +endif() + +# Packaging with CPack! +set(DFHACK_PACKAGE_SUFFIX "") +if(UNIX) + execute_process(COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION) + string(STRIP ${GCC_VERSION} GCC_VERSION) + set(DFHACK_PACKAGE_SUFFIX "-gcc-${GCC_VERSION}") + set(CPACK_GENERATOR "TBZ2") +elseif(WIN32) + set(CPACK_GENERATOR "ZIP") +endif() +set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY 0) +if(APPLE) + set(DFHACK_PACKAGE_PLATFORM_NAME OSX) +else() + set(DFHACK_PACKAGE_PLATFORM_NAME ${CMAKE_SYSTEM_NAME}) +endif() +# set on command line +if(DFHACK_BUILD_ID STREQUAL "") + set(DFHACK_BUILD_ID_PACKAGE "") +else() + set(DFHACK_BUILD_ID_PACKAGE "${DFHACK_BUILD_ID}-") +endif() +set(CPACK_PACKAGE_FILE_NAME "dfhack-${DFHACK_VERSION}-${DFHACK_BUILD_ID_PACKAGE}${DFHACK_PACKAGE_PLATFORM_NAME}-${DFHACK_BUILD_ARCH}bit${DFHACK_PACKAGE_SUFFIX}") +include(CPack) + +option(DFHACK_INCLUDE_CORE "Download and include Dwarf Fortress core files in DFHack. Useful for local testing, but should not be used in releases." OFF) +if(DFHACK_INCLUDE_CORE) + string(REPLACE "." "_" DF_CORE_FILENAME "${DF_VERSION}") + string(REGEX REPLACE "^0_" "df_" DF_CORE_FILENAME "${DF_CORE_FILENAME}") + if(UNIX) + if(APPLE) + string(APPEND DF_CORE_FILENAME "_osx") + else() + string(APPEND DF_CORE_FILENAME "_linux") + endif() + if(DFHACK_BUILD_32) + string(APPEND DF_CORE_FILENAME "32") + endif() + string(APPEND DF_CORE_FILENAME ".tar.bz2") + else() + string(APPEND DF_CORE_FILENAME "_win") + if(DFHACK_BUILD_32) + string(APPEND DF_CORE_FILENAME "32") + endif() + string(APPEND DF_CORE_FILENAME ".zip") + endif() + set(DF_CORE_URL "http://bay12games.com/dwarves/${DF_CORE_FILENAME}") + if(NOT EXISTS "${CMAKE_BINARY_DIR}/${DF_CORE_FILENAME}") + file(DOWNLOAD "${DF_CORE_URL}" "${CMAKE_BINARY_DIR}/${DF_CORE_FILENAME}" SHOW_PROGRESS) + endif() + file(REMOVE_RECURSE "${CMAKE_BINARY_DIR}/df-core") + file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/df-core") + if(UNIX) + execute_process(COMMAND ${CMAKE_COMMAND} -E tar xjf "../${DF_CORE_FILENAME}" --strip-components=1 + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/df-core") + else() + execute_process(COMMAND ${CMAKE_COMMAND} -E tar xf "../${DF_CORE_FILENAME}" --format=zip + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/df-core") + file(REMOVE "${CMAKE_BINARY_DIR}/df-core/SDL.dll") + endif() + install(DIRECTORY "${CMAKE_BINARY_DIR}/df-core/" + DESTINATION .) +endif() + +# Store old build arch +set(DFHACK_BUILD_ARCH_PREV "${DFHACK_BUILD_ARCH}" CACHE STRING "Previous build architecture" FORCE) + +option(BUILD_SIZECHECK "Build the sizecheck library, for research" OFF) +if(BUILD_LIBRARY AND BUILD_SIZECHECK) + add_subdirectory(depends/sizecheck) + add_dependencies(dfhack sizecheck) endif() -IF(BUILD_DFHACK_DOXYGEN AND BUILD_DFHACK_DEVEL) - add_subdirectory (doc) -ENDIF() - -IF(${DFHACK_INSTALL} STREQUAL "portable") - IF(UNIX) - SET(CPACK_GENERATOR "TGZ") - ENDIF() - IF(WIN32) - SET(CPACK_GENERATOR "ZIP") - # this includes the MSVC C++ DLLs in the package. Doesn't work with Express versions in general. - INCLUDE(InstallRequiredSystemLibraries) - ENDIF() - set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${DFHACK_VERSION}-${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}") - INCLUDE(CPack) -ENDIF() - -#------------------------------------------------------------------------------- -# Figure out debian architecture -#------------------------------------------------------------------------------- - -FUNCTION(GET_DEBIAN_ARCHITECTURE arch) - SET(dpkgarch) - - FIND_PROGRAM(DPKG_CMD dpkg) - IF(NOT DPKG_CMD) - MESSAGE(STATUS "Can not find dpkg in your path, default to i386.") - SET(${arch} i386 PARENT_SCOPE) - ENDIF() - EXECUTE_PROCESS(COMMAND "${DPKG_CMD}" --print-architecture - OUTPUT_VARIABLE dpkgarch - OUTPUT_STRIP_TRAILING_WHITESPACE ) - SET(${arch} ${dpkgarch} PARENT_SCOPE) -ENDFUNCTION() - -IF(${DFHACK_INSTALL} STREQUAL "ubuntu-10.10" OR ${DFHACK_INSTALL} STREQUAL "debian") - SET(CPACK_GENERATOR "DEB") - - #wtf, wtf, wtf. force them to be empty - set(CMAKE_INSTALL_PREFIX "" FORCE) - set(CPACK_INSTALL_PREFIX "") - SET(CPACK_PACKAGING_INSTALL_PREFIX "") - set(CPACK_SET_DESTDIR true) - - SET(CPACK_DEBIAN_PACKAGE_SECTION "Games") # yep. magma. - SET(CPACK_DEBIAN_PACKAGE_PRIORITY "optional") # very. - SET(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON) # find deps automatically! hopefully... maybe... - SET(INSTSCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/package/${DFHACK_INSTALL}") - SET(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${INSTSCRIPT}/postinst;${INSTSCRIPT}/preinst;${INSTSCRIPT}/postrm") - - GET_DEBIAN_ARCHITECTURE(PKG_ARCHITECTURE) - - set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}_${DFHACK_VERSION}-${DFHACK_REVISION}_${DFHACK_INSTALL}-${PKG_ARCHITECTURE}") - INCLUDE(CPack) -ENDIF() +add_subdirectory(package) diff --git a/CMakeSettings.json b/CMakeSettings.json new file mode 100644 index 0000000000..d1511716f7 --- /dev/null +++ b/CMakeSettings.json @@ -0,0 +1,284 @@ +{ + "configurations": [ + { + "name": "MSVC 64 Debug", + "generator": "Ninja", + "configurationType": "RelWithDebInfo", + "inheritEnvironments": [ "msvc_x64_x64" ], + "variables": [ + { + "name": "DFHACK_BUILD_ARCH", + "value": "64" + }, + { + "name": "BUILD_STONESENSE", + "value": "1" + }, + { + "name": "REMOVE_SYMBOLS_FROM_DF_STUBS", + "value": "0" + }, + { + "name": "DFHACK_INCLUDE_CORE", + "value": "1" + } + ] + }, + { + "name": "MSVC 64 Release", + "generator": "Ninja", + "configurationType": "Release", + "inheritEnvironments": [ "msvc_x64_x64" ], + "variables": [ + { + "name": "DFHACK_BUILD_ARCH", + "value": "64" + }, + { + "name": "BUILD_STONESENSE", + "value": "1" + } + ] + }, + { + "name": "GCC 32 Debug", + "remoteMachineName": "${defaultRemoteMachineName}", + "remoteCMakeListsRoot": "/tmp/dfhack-${workspaceHash}/src", + "remoteBuildRoot": "/tmp/dfhack-${workspaceHash}/debug-32", + "rsyncCommandArgs": "--exclude=build --include=.git", + "remoteCopySources": true, + "cmakeExecutable": "$(which cmake)/..", + "generator": "Ninja", + "configurationType": "RelWithDebInfo", + "intelliSenseMode": "linux-gcc-x86", + "variables": [ + { + "name": "DFHACK_BUILD_ARCH", + "value": "32" + }, + { + "name": "BUILD_STONESENSE", + "value": "1" + }, + { + "name": "REMOVE_SYMBOLS_FROM_DF_STUBS", + "value": "0" + }, + { + "name": "DFHACK_INCLUDE_CORE", + "value": "1" + } + ] + }, + { + "name": "GCC 32 Release", + "remoteMachineName": "${defaultRemoteMachineName}", + "remoteCMakeListsRoot": "/tmp/dfhack-${workspaceHash}/src", + "remoteBuildRoot": "/tmp/dfhack-${workspaceHash}/release-32", + "rsyncCommandArgs": "--exclude=build --include=.git", + "remoteCopySources": true, + "cmakeExecutable": "$(which cmake)/..", + "generator": "Ninja", + "configurationType": "Release", + "intelliSenseMode": "linux-gcc-x86", + "variables": [ + { + "name": "DFHACK_BUILD_ARCH", + "value": "32" + }, + { + "name": "BUILD_STONESENSE", + "value": "1" + } + ] + }, + { + "name": "GCC 64 Debug", + "remoteMachineName": "${defaultRemoteMachineName}", + "remoteCMakeListsRoot": "/tmp/dfhack-${workspaceHash}/src", + "remoteBuildRoot": "/tmp/dfhack-${workspaceHash}/debug-64", + "rsyncCommandArgs": "--exclude=build --include=.git", + "remoteCopySources": true, + "cmakeExecutable": "$(which cmake)/..", + "generator": "Ninja", + "configurationType": "RelWithDebInfo", + "intelliSenseMode": "linux-gcc-x64", + "variables": [ + { + "name": "DFHACK_BUILD_ARCH", + "value": "64" + }, + { + "name": "BUILD_STONESENSE", + "value": "1" + }, + { + "name": "REMOVE_SYMBOLS_FROM_DF_STUBS", + "value": "0" + }, + { + "name": "DFHACK_INCLUDE_CORE", + "value": "1" + } + ] + }, + { + "name": "GCC 64 Release", + "remoteMachineName": "${defaultRemoteMachineName}", + "remoteCMakeListsRoot": "/tmp/dfhack-${workspaceHash}/src", + "remoteBuildRoot": "/tmp/dfhack-${workspaceHash}/release-64", + "rsyncCommandArgs": "--exclude=build --include=.git", + "remoteCopySources": true, + "cmakeExecutable": "$(which cmake)/..", + "generator": "Ninja", + "configurationType": "Release", + "intelliSenseMode": "linux-gcc-x64", + "variables": [ + { + "name": "DFHACK_BUILD_ARCH", + "value": "64" + }, + { + "name": "BUILD_STONESENSE", + "value": "1" + } + ] + }, + { + "name": "GCC 4.8 32 Debug", + "remoteMachineName": "${defaultRemoteMachineName}", + "remoteCMakeListsRoot": "/tmp/dfhack-${workspaceHash}/src", + "remoteBuildRoot": "/tmp/dfhack-${workspaceHash}/debug-32-48", + "rsyncCommandArgs": "--exclude=build --include=.git", + "remoteCopySources": true, + "cmakeExecutable": "$(which cmake)/..", + "generator": "Ninja", + "configurationType": "RelWithDebInfo", + "intelliSenseMode": "linux-gcc-x86", + "variables": [ + { + "name": "CMAKE_C_COMPILER", + "value": "gcc-4.8" + }, + { + "name": "CMAKE_CXX_COMPILER", + "value": "g++-4.8" + }, + { + "name": "DFHACK_BUILD_ARCH", + "value": "32" + }, + { + "name": "BUILD_STONESENSE", + "value": "1" + }, + { + "name": "REMOVE_SYMBOLS_FROM_DF_STUBS", + "value": "0" + }, + { + "name": "DFHACK_INCLUDE_CORE", + "value": "1" + } + ] + }, + { + "name": "GCC 4.8 32 Release", + "remoteMachineName": "${defaultRemoteMachineName}", + "remoteCMakeListsRoot": "/tmp/dfhack-${workspaceHash}/src", + "remoteBuildRoot": "/tmp/dfhack-${workspaceHash}/release-32-48", + "rsyncCommandArgs": "--exclude=build --include=.git", + "remoteCopySources": true, + "cmakeExecutable": "$(which cmake)/..", + "generator": "Ninja", + "configurationType": "Release", + "intelliSenseMode": "linux-gcc-x86", + "variables": [ + { + "name": "CMAKE_C_COMPILER", + "value": "gcc-4.8" + }, + { + "name": "CMAKE_CXX_COMPILER", + "value": "g++-4.8" + }, + { + "name": "DFHACK_BUILD_ARCH", + "value": "32" + }, + { + "name": "BUILD_STONESENSE", + "value": "1" + } + ] + }, + { + "name": "GCC 4.8 64 Debug", + "remoteMachineName": "${defaultRemoteMachineName}", + "remoteCMakeListsRoot": "/tmp/dfhack-${workspaceHash}/src", + "remoteBuildRoot": "/tmp/dfhack-${workspaceHash}/debug-64-48", + "rsyncCommandArgs": "--exclude=build --include=.git", + "remoteCopySources": true, + "cmakeExecutable": "$(which cmake)/..", + "generator": "Ninja", + "configurationType": "RelWithDebInfo", + "intelliSenseMode": "linux-gcc-x64", + "variables": [ + { + "name": "CMAKE_C_COMPILER", + "value": "gcc-4.8" + }, + { + "name": "CMAKE_CXX_COMPILER", + "value": "g++-4.8" + }, + { + "name": "DFHACK_BUILD_ARCH", + "value": "64" + }, + { + "name": "BUILD_STONESENSE", + "value": "1" + }, + { + "name": "REMOVE_SYMBOLS_FROM_DF_STUBS", + "value": "0" + }, + { + "name": "DFHACK_INCLUDE_CORE", + "value": "1" + } + ] + }, + { + "name": "GCC 4.8 64 Release", + "remoteMachineName": "${defaultRemoteMachineName}", + "remoteCMakeListsRoot": "/tmp/dfhack-${workspaceHash}/src", + "remoteBuildRoot": "/tmp/dfhack-${workspaceHash}/release-64-48", + "rsyncCommandArgs": "--exclude=build --include=.git", + "remoteCopySources": true, + "cmakeExecutable": "$(which cmake)/..", + "generator": "Ninja", + "configurationType": "Release", + "intelliSenseMode": "linux-gcc-x64", + "variables": [ + { + "name": "CMAKE_C_COMPILER", + "value": "gcc-4.8" + }, + { + "name": "CMAKE_CXX_COMPILER", + "value": "g++-4.8" + }, + { + "name": "DFHACK_BUILD_ARCH", + "value": "64" + }, + { + "name": "BUILD_STONESENSE", + "value": "1" + } + ] + } + ] +} diff --git a/COMPILE.rst b/COMPILE.rst deleted file mode 100644 index 951c0a369c..0000000000 --- a/COMPILE.rst +++ /dev/null @@ -1,266 +0,0 @@ -################ -Compiling DFHACK -################ - -============================ -Here's how you build dfhack! -============================ - -.. contents:: - - -Dependencies -============ -* ``cmake`` -* A compiler for building the main lib and the various tools. -* (Linux only) Veinlook requires the wide-character ncurses library (libncursesw) -* (Linux only) You'll need X11 dev libraries. - -Building on Linux -================= -To run in the output folder (without installing) building the library -is simple. Enter the build folder, run the tools. Like this:: - - cd build - cmake .. -DCMAKE_BUILD_TYPE:string=Release - make - -This will build the library and its tools and place them in a sub-directory ``bin`` inside your build directory. - -Alternatively, you can use ccmake instead of cmake: - - cd build - ccmake .. - make - -This will show a curses-based interface that lets you set all of the -extra options. - -You can also use a cmake-friendly IDE like KDevelop 4 or the cmake-gui -program. - -To be installed into the system or packaged:: - - cd build - cmake -DCMAKE_BUILD_TYPE:string=Release \ - -DCMAKE_INSTALL_PREFIX=/usr \ - -DMEMXML_DATA_PATH:path=/usr/share/dfhack .. - make - make install - -With this dfhack installs: - -* library to ``$CMAKE_INSTALL_PREFIX/lib`` -* executables to ``$CMAKE_INSTALL_PREFIX/bin`` -* The ``Memory.xml`` file to ``/usr/share/dfhack`` - -Building on Windows -=================== -You need ``cmake``. Get the win32 installer version from the official -site: http://www.cmake.org/cmake/resources/software.html - -It has the usual installer wizard thing. - ------------ -Using mingw ------------ -You also need a compiler. I build dfhack using mingw. You can get it -from the mingw site: http://www.mingw.org/ - -Get the automated installer, it will download newest version of mingw -and set things up nicely. - -You'll have to add ``C:\MinGW\`` to your PATH variable. - -Building --------- -open up cmd and navigate to the ``dfhack\build`` folder, run ``cmake`` -and the mingw version of make:: - - cd build - cmake .. -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE:string=Release - mingw32-make - ----------- -Using MSVC ----------- -open up ``cmd`` and navigate to the ``dfhack\build`` folder, run -``cmake``:: - - cd build - cmake .. - -This will generate MSVC solution and project files. - -.. note:: - - You are working in the ``/build`` folder. Files added to - projects from within MSVC will end up there! (and that's - wrong). Any changes to the build system should be done - by changing the CMakeLists.txt files and running ``cmake``! - -------------------------- -Using some other compiler -------------------------- -I'm afraid you are on your own. dfhack wasn't tested with any other -compiler. - -Try using a different cmake generator that's intended for your tools. - -Build targets -============= -dfhack has a few build targets: - -* If you're only after the library run ``make dfhack``. -* ``make`` will build everything. -* ``make expbench`` will build the expbench testing program and the - library. -* Some of the utilities and the doxygen documentation won't be - normally built. You can enable them by specifying some extra - CMake variables:: - - BUILD_DFHACK_DOCUMENTATION - generate the documentation (really bad) - BUILD_DFHACK_EXAMPLES - build tools from tools/examples - BUILD_DFHACK_PLAYGROUND - build tools from tools/playground - - Example:: - - cmake .. -DBUILD_DFHACK_EXAMPLES=ON - -Build types -=========== -``cmake`` allows you to pick a build type by changing this -variable: ``CMAKE_BUILD_TYPE`` - -:: - - cmake .. -DCMAKE_BUILD_TYPE:string=BUILD_TYPE - -Without specifying a build type or 'None', cmake uses the -``CMAKE_CXX_FLAGS`` variable for building. - -Valid an useful build types include 'Release', 'Debug' and -'RelWithDebInfo'. There are others, but they aren't really that useful. - -Have fun. - -================================ -Using the library as a developer -================================ -DFHack is using the zlib/libpng license. This makes it easy to link to -it, use it in-source or add your own extensions. Contributing back to -the dfhack repository is welcome and the right thing to do :) - -Rudimentary API documentation can be built using doxygen. - -Contributing to DFHack -====================== - -Several things should be kept in mind when contributing to DFHack. - ------------- -Coding style ------------- -DFhack uses ANSI formatting and four spaces as indentation. Line -endings are UNIX. The files use UTF-8 encoding. Code not following this -won't make me happy, because I'll have to fix it. There's a good chance -I'll make *you* fix it ;) - -------------------------------- -How to get new code into DFHack -------------------------------- -You can send patches or make a clone of the github repo and ask me on -the IRC channel to pull your code in. I'll review it and see if there -are any problems. I'll fix them if they are minor. - -Fixes are higher in priority. If you want to work on something, but -don't know what, check out http://github.com/peterix/dfhack/issues -- -this is also a good place to dump new ideas and/or bugs that need -fixing. - ----------------- -Layout for tools ----------------- -Tools live in the tools/ folder. There, they are split into three -categories. - -distributed - these tools get distributed with binary releases and are installed - by doing 'make install' on linux. They are supposed to be stable - and supported. Experimental, useless, buggy or untested stuff - doesn't belong here. -examples - examples are tools that aren't very useful, but show how DF and - DFHack work. They should use only DFHack API functions. No actual - hacking or 'magic offsets' are allowed. -playground - This is a catch-all folder for tools that aren't ready to be - examples or be distributed in binary releases. All new tools should - start here. They can contain actual hacking, magic values and other - nasty business. - ------------------------- -Modules - what are they? ------------------------- -DFHack uses modules to partition sets of features into manageable -chunks. A module can have both client and server side. - -Client side is the part that goes into the main library and is -generally written in C++. It is exposed to the users of DFHack. - -Server side is used inside DF and serves to accelerate the client -modules. This is written mostly in C style. - -There's a Core module that shouldn't be changed, because it defines the -basic commands like reading and writing raw data. The client parts for -the Core module are the various implementations of the Process -interface. - -A good example of a module is Maps. Named the same in both client and -server, it allows accelerating the reading of map blocks. - -Communication between modules happens by using shared memory. This is -pretty fast, but needs quite a bit of care to not break. - ------------- -Dependencies ------------- -Internal - either part of the codebase or statically linked. -External - linked as dynamic loaded libraries (.dll, .so, etc.) - -If you want to add dependencies, think twice about it. All internal -dependencies for core dfhack should be either public domain or require -attribution at most. External dependencies for tools can be either -that, or any Free Software licenses. - -Current internal dependencies ------------------------------ -tinyxml - used by core dfhack to read offset definitions from Memory.xml -md5 - an implementation of the MD5 hash algorithm. Used for identifying - DF binaries on Linux. -argstream - Allows reading terminal application arguments. GPL! - -Current external dependencies ------------------------------ -wide-character ncurses - used for the veinlook tool on Linux. -x11 libraries - used for sending key events on linux - -Build-time dependencies ------------------------ -cmake - you need cmake to generate the build system and some configuration - headers - -========================= -Memory offset definitions -========================= -The files with memory offset definitions used by dfhack can be found in the -data folder. - diff --git a/Compile.html b/Compile.html deleted file mode 100644 index 8f271a6552..0000000000 --- a/Compile.html +++ /dev/null @@ -1,602 +0,0 @@ - - - - - - -Compiling DFHACK - - - -
-

Compiling DFHACK

- -
-

Here's how you build dfhack!

- -
-

Dependencies

-
    -
  • cmake
  • -
  • A compiler for building the main lib and the various tools.
  • -
  • (Linux only) Veinlook requires the wide-character ncurses library (libncursesw)
  • -
  • (Linux only) You'll need X11 dev libraries.
  • -
-
-
-

Building on Linux

-

To run in the output folder (without installing) building the library -is simple. Enter the build folder, run the tools. Like this:

-
-cd build
-cmake .. -DCMAKE_BUILD_TYPE:string=Release
-make
-
-

This will build the library and its tools and place them in a sub-directory bin inside your build directory.

-

Alternatively, you can use ccmake instead of cmake:

-
-cd build -ccmake .. -make
-

This will show a curses-based interface that lets you set all of the -extra options.

-

You can also use a cmake-friendly IDE like KDevelop 4 or the cmake-gui -program.

-

To be installed into the system or packaged:

-
-cd build
-cmake -DCMAKE_BUILD_TYPE:string=Release \
-    -DCMAKE_INSTALL_PREFIX=/usr \
-    -DMEMXML_DATA_PATH:path=/usr/share/dfhack ..
-make
-make install
-
-

With this dfhack installs:

-
    -
  • library to $CMAKE_INSTALL_PREFIX/lib
  • -
  • executables to $CMAKE_INSTALL_PREFIX/bin
  • -
  • The Memory.xml file to /usr/share/dfhack
  • -
-
-
-

Building on Windows

-

You need cmake. Get the win32 installer version from the official -site: http://www.cmake.org/cmake/resources/software.html

-

It has the usual installer wizard thing.

-
-

Using mingw

-

You also need a compiler. I build dfhack using mingw. You can get it -from the mingw site: http://www.mingw.org/

-

Get the automated installer, it will download newest version of mingw -and set things up nicely.

-

You'll have to add C:\MinGW\ to your PATH variable.

-
-

Building

-

open up cmd and navigate to the dfhack\build folder, run cmake -and the mingw version of make:

-
-cd build
-cmake .. -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE:string=Release
-mingw32-make
-
-
-
-
-

Using MSVC

-

open up cmd and navigate to the dfhack\build folder, run -cmake:

-
-cd build
-cmake ..
-
-

This will generate MSVC solution and project files.

-
-

Note

-

You are working in the /build folder. Files added to -projects from within MSVC will end up there! (and that's -wrong). Any changes to the build system should be done -by changing the CMakeLists.txt files and running cmake!

-
-
-
-

Using some other compiler

-

I'm afraid you are on your own. dfhack wasn't tested with any other -compiler.

-

Try using a different cmake generator that's intended for your tools.

-
-
-
-

Build targets

-

dfhack has a few build targets:

-
    -
  • If you're only after the library run make dfhack.

    -
  • -
  • make will build everything.

    -
  • -
  • make expbench will build the expbench testing program and the -library.

    -
  • -
  • Some of the utilities and the doxygen documentation won't be -normally built. You can enable them by specifying some extra -CMake variables:

    -
    -BUILD_DFHACK_DOCUMENTATION - generate the documentation (really bad)
    -BUILD_DFHACK_EXAMPLES      - build tools from tools/examples
    -BUILD_DFHACK_PLAYGROUND    - build tools from tools/playground
    -
    -

    Example:

    -
    -cmake .. -DBUILD_DFHACK_EXAMPLES=ON
    -
    -
  • -
-
-
-

Build types

-

cmake allows you to pick a build type by changing this -variable: CMAKE_BUILD_TYPE

-
-cmake .. -DCMAKE_BUILD_TYPE:string=BUILD_TYPE
-
-

Without specifying a build type or 'None', cmake uses the -CMAKE_CXX_FLAGS variable for building.

-

Valid an useful build types include 'Release', 'Debug' and -'RelWithDebInfo'. There are others, but they aren't really that useful.

-

Have fun.

-
-
-
-

Using the library as a developer

-

DFHack is using the zlib/libpng license. This makes it easy to link to -it, use it in-source or add your own extensions. Contributing back to -the dfhack repository is welcome and the right thing to do :)

-

Rudimentary API documentation can be built using doxygen.

-
-

Contributing to DFHack

-

Several things should be kept in mind when contributing to DFHack.

-
-

Coding style

-

DFhack uses ANSI formatting and four spaces as indentation. Line -endings are UNIX. The files use UTF-8 encoding. Code not following this -won't make me happy, because I'll have to fix it. There's a good chance -I'll make you fix it ;)

-
-
-

How to get new code into DFHack

-

You can send patches or make a clone of the github repo and ask me on -the IRC channel to pull your code in. I'll review it and see if there -are any problems. I'll fix them if they are minor.

-

Fixes are higher in priority. If you want to work on something, but -don't know what, check out http://github.com/peterix/dfhack/issues -- -this is also a good place to dump new ideas and/or bugs that need -fixing.

-
-
-

Layout for tools

-

Tools live in the tools/ folder. There, they are split into three -categories.

-
-
distributed
-
these tools get distributed with binary releases and are installed -by doing 'make install' on linux. They are supposed to be stable -and supported. Experimental, useless, buggy or untested stuff -doesn't belong here.
-
examples
-
examples are tools that aren't very useful, but show how DF and -DFHack work. They should use only DFHack API functions. No actual -hacking or 'magic offsets' are allowed.
-
playground
-
This is a catch-all folder for tools that aren't ready to be -examples or be distributed in binary releases. All new tools should -start here. They can contain actual hacking, magic values and other -nasty business.
-
-
-
-

Modules - what are they?

-

DFHack uses modules to partition sets of features into manageable -chunks. A module can have both client and server side.

-

Client side is the part that goes into the main library and is -generally written in C++. It is exposed to the users of DFHack.

-

Server side is used inside DF and serves to accelerate the client -modules. This is written mostly in C style.

-

There's a Core module that shouldn't be changed, because it defines the -basic commands like reading and writing raw data. The client parts for -the Core module are the various implementations of the Process -interface.

-

A good example of a module is Maps. Named the same in both client and -server, it allows accelerating the reading of map blocks.

-

Communication between modules happens by using shared memory. This is -pretty fast, but needs quite a bit of care to not break.

-
-
-

Dependencies

-
-
Internal
-
either part of the codebase or statically linked.
-
External
-
linked as dynamic loaded libraries (.dll, .so, etc.)
-
-

If you want to add dependencies, think twice about it. All internal -dependencies for core dfhack should be either public domain or require -attribution at most. External dependencies for tools can be either -that, or any Free Software licenses.

-
-

Current internal dependencies

-
-
tinyxml
-
used by core dfhack to read offset definitions from Memory.xml
-
md5
-
an implementation of the MD5 hash algorithm. Used for identifying -DF binaries on Linux.
-
argstream
-
Allows reading terminal application arguments. GPL!
-
-
-
-

Current external dependencies

-
-
wide-character ncurses
-
used for the veinlook tool on Linux.
-
x11 libraries
-
used for sending key events on linux
-
-
-
-

Build-time dependencies

-
-
cmake
-
you need cmake to generate the build system and some configuration -headers
-
-
-
-
-
-
-

Memory offset definitions

-

The files with memory offset definitions used by dfhack can be found in the -data folder.

-
-
- - diff --git a/LICENSE b/LICENSE deleted file mode 100644 index d9943bf5a6..0000000000 --- a/LICENSE +++ /dev/null @@ -1,173 +0,0 @@ ----------------------------------------------------------------------- -License of dfhack -github.com/peterix/dfhack -Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf - -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 acknowledgment 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. - ----------------------------------------------------------------------- -License of library/include/dfhack/DFstdint_win.h - -ISO C9x compliant stdint.h for Microsoft Visual Studio -Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 - - Copyright (c) 2006-2008 Alexander Chemeris - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - 3. The name of the author may be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED -WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO -EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------------- -License of argstream (used by some utilities for parsing command line params) - -Copyright (C) 2004 Xavier Decoret - -argsteam is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -Foobar is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Foobar; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -This library is used by: -tools/playground/catsplosion.cpp -tools/playground/digger.cpp -tools/supported/vdig.cpp - ----------------------------------------------------------------------------- -License of "RSA Data Security, Inc. MD5 Message-Digest Algorithm" -Used to identify DF binaries. - -Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All -rights reserved. - -License to copy and use this software is granted provided that it -is identified as the "RSA Data Security, Inc. MD5 Message-Digest -Algorithm" in all material mentioning or referencing this software -or this function. - -License is also granted to make and use derivative works provided -that such works are identified as "derived from the RSA Data -Security, Inc. MD5 Message-Digest Algorithm" in all material -mentioning or referencing the derived work. - -RSA Data Security, Inc. makes no representations concerning either -the merchantability of this software or the suitability of this -software for any particular purpose. It is provided "as is" -without express or implied warranty of any kind. - -These notices must be retained in any copies of any part of this -documentation and/or software. ------------------------------------------------------------------ -License of the "RSA Data Security, Inc. MD5 Message-Digest Algorithm" C++ wrapper: - -This is my wrapper-class to create -a MD5 Hash from a string and a file. - -This code is completly free, you -can copy it, modify it, or do -what ever you want with it. - -Feb. 2005 -Benjamin Grüdelbach ------------------------------------------------------------------- -License of the used XML reader library - -www.sourceforge.net/projects/tinyxml -Original code (2.0 and earlier )copyright (c) 2000-2006 Lee Thomason (www.grinninglizard.com) - -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 acknowledgment 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. ------------------------------------------------------------------- -Free Getopt -Copyright (c)2002-2003 Mark K. Kim -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - * Neither the original author of this software nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED -AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. diff --git a/LICENSE.rst b/LICENSE.rst new file mode 100644 index 0000000000..1ab6a682ee --- /dev/null +++ b/LICENSE.rst @@ -0,0 +1,160 @@ +.. _license: + +######## +Licenses +######## + +DFHack is distributed under the Zlib license, with some MIT- and BSD-licensed +components. These licenses protect your right to use DFHack for any purpose, +distribute copies, and so on. + +The core, plugins, scripts, and other DFHack code all use the ZLib license +unless noted otherwise. By contributing to DFHack, authors release the +contributed work under this license. + +Some graphic assets are derived from vanilla DF assets and used with permission +from Bay12. + +DFHack also draws on several external packages. Their licenses are summarised +here and reproduced below. + +=============== ============= ================================================= +Component License Copyright +=============== ============= ================================================= +DFHack_ Zlib \(c\) 2009-2012, Petr Mrázek +clsocket_ BSD 3-clause \(c\) 2007-2009, CarrierLabs, LLC. +dirent_ MIT \(c\) 2006, Toni Ronkko +JSON.lua_ CC-BY-SA_ \(c\) 2010-2014, Jeffrey Friedl +jsoncpp_ MIT \(c\) 2007-2010, Baptiste Lepilleur +libexpat_ MIT \(c\) 1998-2000 Thai Open Source Software Center Ltd and Clark Cooper \(c\) 2001-2019 Expat maintainers +libzip_ BSD 3-clause \(c\) 1999-2020 Dieter Baron and Thomas Klausner +linenoise_ BSD 2-clause \(c\) 2010, Salvatore Sanfilippo & Pieter Noordhuis +lua_ MIT \(c\) 1994-2008, Lua.org, PUC-Rio. +luacov_ MIT \(c\) 2007 - 2018 Hisham Muhammad +luafilesystem_ MIT \(c\) 2003-2014, Kepler Project +lua-profiler_ MIT \(c\) 2002,2003,2004 Pepperfish +protobuf_ BSD 3-clause \(c\) 2008, Google Inc. +tinyxml_ Zlib \(c\) 2000-2006, Lee Thomason +UTF-8-decoder_ MIT \(c\) 2008-2010, Bjoern Hoehrmann +xlsxio_ MIT \(c\) 2016-2020, Brecht Sanders +alt-getopt_ MIT \(c\) 2009 Aleksey Cheusov +googletest_ BSD 3-Clause \(c\) 2008, Google Inc. +=============== ============= ================================================= + +.. _DFHack: https://github.com/DFHack/dfhack +.. _clsocket: https://github.com/DFHack/clsocket +.. _dirent: https://github.com/tronkko/dirent +.. _JSON.lua: http://regex.info/blog/lua/json +.. _jsoncpp: https://github.com/open-source-parsers/jsoncpp +.. _libexpat: https://github.com/libexpat/libexpat +.. _libzip: https://github.com/nih-at/libzip +.. _linenoise: http://github.com/antirez/linenoise +.. _lua: http://www.lua.org +.. _luacov: https://github.com/keplerproject/luacov +.. _luafilesystem: https://github.com/keplerproject/luafilesystem +.. _lua-profiler: http://lua-users.org/wiki/PepperfishProfiler +.. _protobuf: https://github.com/google/protobuf +.. _tinyxml: http://www.sourceforge.net/projects/tinyxml +.. _UTF-8-decoder: http://bjoern.hoehrmann.de/utf-8/decoder/dfa +.. _xlsxio: https://github.com/brechtsanders/xlsxio +.. _alt-getopt: https://github.com/LuaDist/alt-getopt +.. _googletest: https://github.com/google/googletest + +.. _CC-BY-SA: http://creativecommons.org/licenses/by/3.0/deed.en_US + + +Zlib License +============ +See https://en.wikipedia.org/wiki/Zlib_License +:: + + 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 acknowledgment 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. + +MIT License +=========== +See https://en.wikipedia.org/wiki/MIT_License +:: + + 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. + +BSD Licenses +============ +See https://en.wikipedia.org/wiki/BSD_licenses +:: + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +``linenoise`` adds no further clauses. + +``protobuf`` adds the following clause:: + + 3. Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +``clsocket`` adds the following clauses:: + + 3. The name of the author may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + 4. The name "CarrierLabs" must not be used to endorse or promote + products derived from this software without prior written + permission. For written permission, please contact + mark@carrierlabs.com diff --git a/Memory-40d.xml b/Memory-40d.xml deleted file mode 100644 index b6d5ce1f5a..0000000000 --- a/Memory-40d.xml +++ /dev/null @@ -1,2129 +0,0 @@ - - - - - - - - 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 - 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 - 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 - 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 - 0 - 66 - 11 - 10 - 13 - 12 - 14 - 15 - 16 - 20 - 38 - 19 - 41 - 39 - 43 - 42 - 40 - 44 - 45 - 48 - 27 - 49 - 21 - 47 - 26 - 46 - 50 - 23 - 18 - 30 - 32 - 71 - 33 - 34 - 70 - 31 - 28 - 69 - 25 - 22 - 29 - 72 - 35 - 36 - 37 - 67 - 73 - 64 - 65 - 17 - 8 - 2 - 6 - 4 - 1 - 5 - 7 - 9 - 3 - 24 - 51 - 52 - 53 - 54 - 55 - 57 - -1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .,:rsr, - :2;,;r2A@@5 - @2::s5A#@@@ @r. . - sd;:riXA#@@ :@@@Gir;;AS9 - Bs::sS3A#@2 @@#AhXirsS#; - iHrLr5d#@@@ .@#95sr;;rie - i*' `*@3 @@A2sr;:;r#5 - :..:rll: @@A5sr::r3@ - @Hr;iZ#@@@@ `:rr;;;;: - S@r.;i2#@@@ @s. .. - @2::ri2A@@# B@G2ir:...5i - :@r,r3X##@@ @G5sr:..,:A - .@Ar;;rSB@@# H#2sr;,..,is - .' `* ,@ASs;:..,:B - ;rr;:,..,:. - `''' - W I N D O W S - and - W I N E - - - 0x47b6fac2 - 48c831b6f3950913b8e1aeada563d2db - 0x0 - 0x4 -
0x014639f4
-
0x01463288
-
0x01463388
-
0x00c7bc00
-
0x01287d14
-
0x00941288
-
0x01287a9c
-
0x01463358
-
0x014a6994
-
0x014a4eac
-
0x014a6834
-
0xffffffff
-
0x8b010127
-
0x014a4edc
-
0x014a4ee0
-
0x014a4ee4
-
0x014a6680
-
0x014a671c
-
0x014a69b4
-
0x01467b78
-
0x01295d58
-
0x01284184
-
0x00941288
-
0x00c2358c
-
0x00c68350
-
0x014a64dc
-
0x014a4ec4
-
0x014a4ec8
-
0x014a4ecc
- - 0x08 - - 0x08 - 0x2C - 0x0062 - 0x0264 - 0x0664 - 0x1D64 - - 0x0 - 0x1C - 0x38 - 0x1C - - 0x00 - 0x6c - 0x88 - 0x8C - 0x94 - 0xE4 - 0xE8 - 0xF2 - 0xF4 - 0x158 - 0x1F8 - 0x1FC - 0x228 - 0x2F8 - 0x2AC - 0x328 - 0x32C - 0x330 - 0x3CC - 0x438 - 0x43C - 0x440 - 0x444 - 0x454 - 0x474 - 0x520 - 0x5D0 - - 0x70 - - 0x84 - 0x86 - 0x684 - 0x6B4 - - 0x5C - 0x58 - - 0x4 - - 0x10 - - 0x84 - 0x60 - 0x08 - 0x2C - 0x0062 - 0x0264 - 0x0664 - 0x1D64 - 0x3C - 0x2 - 0x4 - 0x8 - 0x24 - 0x1C - 0x20 - 0x00 - 0x7a - 0xD8 - 0x68 - 0x24 - 0x1C - 0x28 - 0x24 - 0x24 - 0x24 - 0x5C - 0x94 - 0xB0 -
- - 0x47c12f36 - 8bd90fb6db8388f129fde224a35459de -
0x01463bec
-
0x01463480
-
0x01463580
-
0x00c7bc04
-
0x01287d14
-
0x0094128c
-
0x01287a9c
-
0x01463550
-
0x014a6c60
-
0x014a50a4
-
0x014a6b00
-
0xffffffff
-
0x8b010127
-
0x014a50d4
-
0x014a50d8
-
0x014a50dc
-
0x014a694c
-
0x014a69e8
-
0x014a6c80
-
0x01467d70
-
0x01295d58
-
0x01284184
-
0x00c3fb40
-
0x00c23594
-
0x00c68354
-
0x014a66d4
-
0x014a50bc
-
0x014a50c0
-
0x014a50c4
-
- - 0x47c29583 - 9147b5e922a30873fd1a742b1dea1724 -
0xffffffff
-
0x8b010127
-
- - 0x487b4e8b - 4b3857a05590b9d9488900e575079e9d -
0x01512b70
-
0x014feb80
-
0x01512504
-
0x00d16c20
-
0x01322d58
-
0x009d6284
-
0x01322adc
-
0x014fec50
-
0x01555f88
-
0x01554028
-
0x01555e28
-
0xffffffff
-
0x8b010131
-
0x01554058
-
0x0155405c
-
0x01554060
-
0x01555ce8
-
0x01555c6c
-
0x01555fa8
-
0x01516cf4
-
0x01330d98
-
0x0131f1b4
-
0x00cd5398
-
0x00cb8dec
-
0x00d03370
-
0x01555658
-
0x01554040
-
0x01554044
-
0x01554048
-
- - 0x487c9338 - 52155dea390c2080fc16e4bbeb077164 -
0xffffffff
-
0x8b010131
-
- - 0x487f2f30 - 8f8cf06b1cd5ea102881a7cced767d4f -
0x01513b90
-
0x014ffba0
-
0x01513524
-
0x00d17c44
-
0x01323d78
-
0x009d7284
-
0xffffffff
- -
0x014ffc70
-
0x01556fa8
-
0x01555048
-
0x01556e48
-
0xffffffff
- -
0x8b010131
-
0x01555078
-
0x0155507c
-
0x01555080
-
0x01556d08
-
0x01556c8c
-
0x01556fc8
-
0x01517d14
-
0x01331db8
-
0x013201d4
-
0x00cd63bc
-
0x00cb9dec
-
0x00d04394
-
0x01556678
-
0x01555060
-
0x01555064
-
0x01555068
-
- - 0x48873bc3 - 8614a01593baef6e4a341e2f1a92ba06 -
0x0151ffb8
-
0x0150bfc8
-
0x0151f94c
-
0x00d23c4c
-
0x0132fdb0
-
0x009e3284
-
0x0132fb34
-
0x0150c098
-
0x015635cc
-
0x01561470
-
0x0156346c
-
0x0132faac
-
0x8b010131
-
0x015614a0
-
0x015614a4
-
0x015614a8
-
0x01563154
-
0x015630d8
-
0x015635ec
-
0x0152413c
-
0x0133ddf0
-
0x0132c1dc
-
0x00ce23c4
-
0x00cc5df4
-
0x00d1039c
-
0x01562aa0
-
0x01561488
-
0x0156148c
-
0x01561490
-
- - 0x4888672c - 32f68422f5b4d938549eed0565bcfb92 - - - 0x489d8c7f - 33db0401081058fb54252210bf371344 -
0x01576468
-
0x01562478
-
0x01575dfc
-
0x00d7a0fc
-
0x01386260
-
0x009ef294
-
0x01385fe4
-
0x01562548
-
0x015b9a7c
-
0x015b7920
-
0x015b991c
-
0x01385f5c
-
0x5f010137
-
0x015b7950
-
0x015b7954
-
0x015b7958
-
0x015b9604
-
0x015b9588
-
0x015b9a9c
-
0x0157a5ec
-
0x013942a0
-
0x0138268c
-
0x00d387fc
-
0x00d66870
-
0x00d6684c
-
0x015b8f50
-
0x015b7938
-
0x015b793c
-
0x015b7940
-
- - 0x48a9727f - 441c76f45cfffc6abc6548e41c7e2218 -
0x015828a8
-
0x0156e8b8
-
0x0158223c
-
0x00d860fc
-
0x01392268
-
0x009fb294
-
0x01391fc0
-
0x0156e988
-
0x015c5ecc
-
0x015c3d60
-
0x015c5d6c
-
0x01391f64
-
0x5f010138
-
0x015c3d90
-
0x015c3d94
-
0x015c3d98
-
0x015c5a54
-
0x015c59c8
-
0x015c5eec
-
0x01586a2c
-
0x013a02a8
-
0x0138e694
-
0x00d447fc
-
0x00d72870
-
0x00d7284c
-
0x015c5390
-
0x015c3d78
-
0x015c3d7c
-
0x015c3d80
-
- - 0x48ad547a - 65b4fa339d4081e934c1297d2a22234a - - - 0x48ad802b - 15e95727019e76aa653538618c7e0cfd - - - 0x48c330df - 2c686c26307dcccd7c36cc79737ebe4f -
0x015838a0
-
0x0156f8b0
-
0x01583234
-
0x00D870F4
-
0x01393260
-
0x009fc294
-
0x1583234
-
0x01392fb8
-
0x0156f980
-
0x015c6ed0
-
0x015c4d58
-
0x015c6d70
-
0x01392f5c
-
0x0138147f
-
0x015c4d88
-
0x015c4d8c
-
0x015c4d90
-
0x015c6a58
-
0x015c69cc
-
0x015c6ef0
-
0x01587a24
-
0x013a12a0
-
0x0138f68c
-
0x00d457f4
-
0x00d73868
-
0x00d73844
-
0x015c6388
-
0x015c4d70
-
0x015c4d74
-
0x015c4d78
-
- - - 0x4953556c - b1a8ca1f91734eb492b7f54f6823cddb - -0x8 - 0x4 -
0x014d1db0
-
0x014bda18
-
0x014D141C
-
0x00cd4c3c
-
0x0165b5a8
-
0x0094b27c
-
0x165b410
-
0x012e101c
-
0x014d14f8
-
0x01517678
-
0x015152f8
-
0x01517468
-
0x012e0fe4
-
0x012cefbf
-
0x01515330
-
0x01515334
-
0x01515338
-
0x015170f8
-
0x0151702c
-
0x015176a8
-
0x014d7f84
-
0x012ef340
-
0x0165a34c
-
0x00c9333c
-
0x00cc13b0
-
0x00cc138c
-
0x01516930
-
0x01515318
-
0x0151531c
-
0x01515320
- 0x54 - - 0x0 - 0x1C - 0x38 - 0x1C - - - 0xFC - 0x100 - 0x10A - 0x10C - 0x198 - 0x238 - 0x23C - 0x268 - 0x2F8 - 0x314 - 0x3C0 - 0x3C4 - 0x3C8 - 0x484 - 0x4F0 - 0x4F4 - 0x4F8 - 0x504 - 0x51C - 0x544 - 0x610 - 0x700 - - 0x70 - - 0x10 - 0x2C - 0x0082 - 0x0284 - 0x0684 - 0x1D84 - 0x84 - 0x86 - 0x75C - 0x79C - - 0x64 - 0x60 - - 0xC - 0x2 - 0x4 - 0x8 - 0x24 - 0x1C - 0x20 - 0x2C - 0x0 - 0x7a - 0x100 - 0x68 - 0x24 - - 0x18 - 0x1C - 0x28 - 0x24 - 0x24 - 0x24 - 0x5C - 0x94 - 0xB0 - - - - - - - -
- - 0x4957716f - 9b6da355562a4cdd345ea3046290499b -
0x00cd6c3c
-
0x0094d27c
-
0x012d0fbf
-
0x00c9533c
-
0x00cc33b0
-
0x00cc338c
-
- - 0x4957a0a2 - b77759db7a6dd787bf98953fc5749d81 - - - 0x495991c3 - a0792b81e5b8ec1dbdd627643e93b40d -
0xcd8c34
-
0x0094f27c
-
0x012d2fbb
-
0x00c97334
-
0x00cc53a8
-
0x00cc5384
-
- - 0x495cafd2 - d09e88a32fe57de5973f78ef213271b6 -
0xcefc68
-
0x009662a4
-
0x012e9fef
-
0x00cae368
-
0x00cdc3dc
-
0x00cdc3b8
-
- - 0x495fcfef - 8e8e2a83d421e356a8047dc8830a7426 -
0xcefc68
-
0x009662a4
-
0x012e9fef
-
0x00cae368
-
0x00cdc3dc
-
0x00cdc3b8
-
- - 0x4963c928 - 32253bee114dd25ebbaa50d90b5c0a2a - - - 0x4967c2e0 - aea5a207b8b1cda942502f97a429f6c3 - - - 0x49c59b94 - 193193d8624f2f3f6d9d556fab09b122 -
0x0151bd00
-
0x01507968
-
0x0151b36c
-
0x00d20ed8
-
0x016a54f8
-
0x009652a4
-
0x16a5360
-
0x0132e574
-
0x0151b448
-
0x015615c8
-
0x0155f248
-
0x015613b8
-
0x0132e53c
-
0x0131b25f
-
0x0155f280
-
0x0155f284
-
0x0155f288
-
0x01561048
-
0x01560f7c
-
0x015615f8
-
0x01521ed4
-
0x0133c898
-
0x016a429c
-
0x00cdf5a0
-
0x00d0d64c
-
0x00d0d628
-
0x01560880
-
0x0155f268
-
0x0155f26c
-
0x0155f270
-
- - 0x49c82d3f - 6f81231b845e9c9dc29aaf57705ccc7c - - - 0x4a3ccb7f - 6ea1de36af8e1666bd6478736e298c4c -
0x015b7750
-
0x015a33b8
-
0x015b6dbc
-
0x00ddaed8
-
0x0095f410
-
0x0095f2b4
-
0x1740e60
-
0x013e8574
-
0x015b6e98
-
0x015fd04c
-
0x015faccc
-
0x015fce3c
-
0x013e853c
-
0x013d525f
-
0x015fad04
-
0x015fad08
-
0x015fad0c
-
0x015fcacc
-
0x015fca00
-
0x015fd07c
-
0x015bd924
-
0x015b6dc4
-
0x0173fde0
-
0x00d995a0
-
0x00dc764c
-
0x00dc7628
-
0x015fc304
-
0x015facec
-
0x015facf0
-
0x015facf4
-
- - 0x4a51c26e - 04a8d8ce311d8ac75e4241bef68d3147 -
0x00ddff38
-
0x00964430
-
0x009642b4
-
0x013da2bf
-
0x00d9e600
-
0x00dcc6ac
-
0x00dcc688
-
- - 0x4a8623d2 - 781a2e51be4056a7320108f8f0df8a13 -
0x00de1f44
-
0x00966430
-
0x009662b4
-
0x013dc2c7
-
0x00da060c
-
0x00dce6b8
-
0x00dce694
-
- - 0x4a9a6090 - 12cc4a3dbb6e6dfd7bc7aee458b9471a -
0x015be808
-
0x015aa470
-
0x015bde74
-
0x00de1f54
-
0x00966430
-
0x009662b4
-
0x1747f20
-
0x013ef62c
-
0x015bdf50
-
0x01604104
-
0x01601d84
-
0x01603ef4
-
0x013ef5f4
-
0x013dc2eb
-
0x01601dbc
-
0x01601dc0
-
0x01601dc4
-
0x01603b84
-
0x01603ab8
-
0x01604134
-
0x015c49dc
-
0x015bde7c
-
0x01746e98
-
0x00da061c
-
0x00dce6c8
-
0x00dce6a4
-
0x016033bc
-
0x01601da4
-
0x01601da8
-
0x01601dac
-
- - 0x4a9b1a72 - 59ab29021aca9f3c66b1ab102fb3ceea - - - 0x4b6b7879 - de66405f54d98297303d439b3b7aa30e -
0x015f3260
-
0x015deec8
-
0x015f28cc
-
0x00e16924
-
0x0099ae08
-
0x0099ac88
-
0x177c978
-
0x014240dc
-
0x015f29a8
-
0x01638b5c
-
0x016367dc
-
0x0163894c
-
0x014240a4
-
0x01410cc1
-
0x01636814
-
0x01636818
-
0x0163681c
-
0x016385dc
-
0x01638510
-
0x01638b8c
-
0x015f9434
-
0x014243c4
-
0x0177b8f0
-
0x00dd4fec
-
0x00e03098
-
0x00e03074
-
0x01637e14
-
0x016367fc
-
0x01636800
-
0x01636804
-
0x0177c978
-
- - - - 0x4b81b00d - 5cdc6f4804809f4d5cacdb66785e8cda - -
0x00df2ebc
-
0x00977438
-
0x009772b8
-
0x014ad278
-
0x00db1584
-
0x00ddf630
-
0x00ddf60c
-
- - 0x4b90268a - 13640a273d90af39425b798ae9823757 -
0x01512898
-
0x014fe500
-
0x01511f04
-
0x00d35b68
-
0x016ac1a0
-
0x0097a2b8
-
0x169bfb0
-
0x01343714
-
0x01511fe0
-
0x01558194
-
0x01555e14
-
0x01557f84
-
0x013436dc
-
0x0132ff1e
-
0x01555e4c
-
0x01555e50
-
0x01555e54
-
0x01557c14
-
0x01557b48
-
0x015581c4
-
0x01518a6c
-
0x013439fc
-
0x0169af28
-
0x00cf4230
-
0x00d222dc
-
0x00d222b8
-
0x0155744c
-
0x01555e34
-
0x01555e38
-
0x01555e3c
-
- - 0x4B918BB9 - af29004e1763bb3460faa11907c3ac90 - - .-"""-. - ' \ - |,. ,-. | - |()L( ()| | - |,' `".| | - |.___.',| ` - .j `--"' ` `. - / ' ' \ - / / ` `. - / / ` . - / / l | - . , L I N U X | | - ,"`. .| | - _.' ``. | `..-'l - | `.`, | `. - | `. __.j ) - |__ |--""___| ,-' - `"--...,+"""" `._,.-' - - - - 7a0859795e972574e80fa3cebc9fcf85 - 0x0 - 0x0 -
0x093154e0
-
0x093016b8
-
0x09355940
-
0x09314ffc
-
0x09301560
-
0x08859fc0
-
0x08cfa060
-
0x0930140c
-
0x09356fd0
-
0x09314ffc
-
0x09355964
-
0x09357808
-
0x093013e4
-
0x092f0580
-
0x0935596c
-
0x09355970
-
0x09355974
-
0x0935754c
-
0x093574e0
-
0x09357928
-
0x09318630
-
0x08b36c80
-
0x09355968
-
0x08b36c84
-
0x08cfa978
-
0x08cfa97c
-
0x09356f6c
-
0x09355954
-
0x09355958
-
0x0935595c
- 0x1C - - 0x0 - 0x4 - 0x8 - 0x4 - - 0x08 - - 0x00 - 0x4C - 0x44 - 0x90 - 0x94 - 0x003c - 0x0040 - 0x009E - 0x00A0 - 0x00F0 - 0x160 - 0x164 - 0x190 - 0x02F8 - 0x0200 - 0x264 - 0x268 - 0x26C - 0x02F8 - 0x0334 - 0x0338 - 0x033C - 0x0340 - 0x034C - 0x0364 - 0x0400 - 0x0490 - - 0x40 - - 0x08 - 0x2C - 0x0052 - 0x0254 - 0x0654 - 0x1D54 - - 0x54 - 0x56 - 0x5A4 - 0x5C8 - - 0x58 - 0x54 - - 0x4 - - 0xC - 0x24 - 0x18 - 0x2 - 0x4 - 0x8 - 0xC - 0x4 - 0x8 - 0x14 - 0x00 - 0x4a - 0x94 - 0x50 - 0x0C - - 0x20 - - 0xC - 0x4 - 0x10 - 0xC - 0xC - 0xC - 0x14 - 0x1C - 0x20 - - - - - - -
- - 51c73ff46b2688aafaee0204efe91a94 -
0x09315f00
-
0x093020d8
-
0x09356360
-
0x09315a1c
-
0x09301f80
-
0x0885a9e4
-
0x08cfaa80
-
0x09301e2c
-
0x093579f0
-
0x09315a1c
-
0x09356384
-
0x09358228
-
0x09301e04
-
0x092f0fa0
-
0x0935638c
-
0x09356390
-
0x09356394
-
0x09357f6c
-
0x09357f00
-
0x09358348
-
0x09319050
-
0x08b376a0
-
0x09356388
-
0x08b376a4
-
0x08cfb398
-
0x08cfb39c
-
0x0935798c
-
0x09356374
-
0x09356378
-
0x0935637c
-
- - c1eb408868c80fd1c726d2a917cd1b9a -
0x0885ad54
-
- - 59d497bfc3a523f0f40f34283ad59796 -
0x0885bbf0
-
- - f756194db073f05b98fc6ce872c8757d -
0x09333e00
-
0x0931ffd8
-
0x09374260
-
0x0933391c
-
0x0931fe80
-
0x088788e4
-
0x08d18980
-
0x0931fd2c
-
0x093758f0
-
0x0933391c
-
0x09374284
-
0x09376128
-
0x0931fd04
-
0x0930eea0
-
0x0937428c
-
0x09374290
-
0x09374294
-
0x09375e6c
-
0x09375e00
-
0x09376248
-
0x09336f50
-
0x08b555a0
-
0x09374288
-
0x08b555a4
-
0x08d19298
-
0x08d1929c
-
0x0937588c
-
0x09374274
-
0x09374278
-
0x0937427c
-
- - b004b3876193633875956af752663f26 - - - c8616fc74d79b3c8c40bbc1182fbd61c -
0x088786a0
-
- - 992afd73855e787860277f53d18afcbb -
0x08877630
-
- - cba6354000ec54865a161627605c3837 -
0x092bf340
-
0x092ab518
-
0x092bee5c
-
0x0929a3c8
-
0x092ab3c0
-
0x088073d4
-
0x08ca3eb8
-
0x092ab26c
-
0x092beecc
-
0x09301770
-
0x092ff7a0
-
0x09301668
-
0x092ab244
-
0x0929a3e0
-
0x092ff7cc
-
0x092ff7d0
-
0x092ff7d4
-
0x093013ac
-
0x09301340
-
0x09301788
-
0x092c2490
-
0x08ae40a0
-
0x09510050
-
0x08ca47d4
-
0x08ca47d8
-
0x08ca47dc
-
0x09300dcc
-
0x092ff7b4
-
0x092ff7b8
-
0x092ff7bc
-
- - fb8ecac8a12af5d0d7b1707078985d0d - - - 4367c59934cbcf14f43fd3af6444c455 -
0x08f55740
-
0x08f41918
-
0x08f5525c
-
0x08f307c8
-
0x08f417c0
-
0x0877b33c
-
0x0893a2ac
-
0x08f4166c
-
0x08f552cc
-
0x08f97b8c
-
0x08f95bbc
-
0x08f97a84
-
0x08f41644
-
0x08f307e0
-
0x08f95be8
-
0x08f95bec
-
0x08f95bf0
-
0x08f977c8
-
0x08f9775c
-
0x08f97ba4
-
0x08f58890
-
0x0877f8e0
-
0x091a647c
-
0x0893abd4
-
0x0893abd8
-
0x0893abdc
-
0x08f971e8
-
0x08f95bd0
-
0x08f95bd4
-
0x08f95bd8
-
- - 2f3cb9d720e9fe8844c02c72a2b20bbd -
0x08780344
-
0x0893f2d0
-
- - dab3ce6bc074529706a1e5fe1273108c -
0x08f5a760
-
0x08f46938
-
0x08f5a27c
-
0x08f357e8
-
0x08f467e0
-
0x08780354
-
0x0893f2d0
-
0x08f4668c
-
0x08f5a2ec
-
0x08f9cbac
-
0x08f9abdc
-
0x08f9caa4
-
0x08f46664
-
0x08f35800
-
0x08f9ac08
-
0x08f9ac0c
-
0x08f9ac10
-
0x08f9c7e8
-
0x08f9c77c
-
0x08f9cbc4
-
0x08f5d8b0
-
0x08784900
-
0x091ab49c
-
0x0893fbf4
-
0x0893fbf8
-
0x0893fbfc
-
0x08f9c208
-
0x08f9abf0
-
0x08f9abf4
-
0x08f9abf8
-
- - 4f55a1dcc326786271f221de23c425b5 - - - 022b933926e08da49c6df8649295f2b7 - - - 8f55a6250f2550e28535b79db43d5f1a -
0x08f628c0
-
0x08f4ea98
-
0x08f623dc
-
0x08f3d948
-
0x08f4e940
-
0x0878c340
-
0x08947438
-
0x08f4e7ec
-
0x08f6244c
-
0x08fa4d0c
-
0x08fa2d3c
-
0x08fa4c04
-
0x08f4e7c4
-
0x660008f3
-
0x08fa2d68
-
0x08fa2d6c
-
0x08fa2d70
-
0x08fa4948
-
0x08fa48dc
-
0x08fa4d24
-
0x08f65a10
-
0x0878caa0
-
0x091b35fc
-
0x08947d54
-
0x08947d58
-
0x08947d5c
-
0x08fa4368
-
0x08fa2d50
-
0x08fa2d54
-
0x08fa2d58
-
- - 777e7d674d8908042307994cb75250ff -
0x09009860
-
0x08ff5a38
-
0x0900937C
-
0x08fe48e8
-
0x08ff58e0
-
0x08833324
-
0x089ee3d8
-
0x08FF578C
-
0x090093ec
-
0x0904bcac
-
0x09049cdc
-
0x0904bba4
-
0x08ff5764
-
0x08fe4900
-
0x09049d08
-
0x09049d0c
-
0x09049d10
-
0x0904b8e8
-
0x0904b87c
-
0x0904bcc4
-
0x0900c9b0
-
0x08833a40
-
0x0925a59c
-
0x089eecf4
-
0x089eecf8
-
0x089eecfc
-
0x0904b308
-
0x09049cf0
-
0x09049cf4
-
0x09049cf8
-
- - 04c3ad13c657f59ba6fc135e156d721d -
0x09008880
-
0x08ff4a58
-
0x0900839C
-
0x08fe3908
-
0x08ff4900
-
0x08832328
-
0x089ed3f8
-
0x08ff47ac
-
0x0900840c
-
0x0904accc
-
0x09048cfc
-
0x0904abc4
-
0x08ff4784
-
0xc60008fe
-
0x09048d28
-
0x09048d2c
-
0x09048d30
-
0x0904a908
-
0x0904a89c
-
0x0904ace4
-
0x0900b9d0
-
0x08832a60
-
0x091995fc
-
0x089edd14
-
0x089edd18
-
0x089edd1c
-
0x0904a328
-
0x09048d10
-
0x09048d14
-
0x09048d18
-
- - - 851c1190b6a7b42f2463967623d18575 - 0x4BB45F99 - - - 0x18 - 0x0 - 0xC - 0x1C - - -
0xe32798
-
0xe60838
-
0xe60814
-
0xae82cc
- -
0x17f5ab8
- Found addresses: (next to each other!) - 0x17f5ab8 - 0x17f5ac0 - 0x17f5ac8 - 0x17f5ad0 - -
0x146e45f
- Found addresses: - 0x146e45f - 0x185b677 - - Bogus:
0xae82cc
- -
0x017f6f38
- - Bogus:
0xae82cc
- - - -
0x016ad738
-
0x016ad73C
-
0x016ad740
- -
0x016ad744
-
0x016ad748
-
0x016ad74C
- -
0x016ad750
-
0x016ad754
-
0x016ad758
- -
0x016AD718
- 0x10 - 0x0092 - 0x029C - - - 0x0 - 0x1C - 0x38 - - - 0x0 - 0x90 - 0xF8 - 0xFC - 0x110 - 0x114 - 0x6D0 - 0x770 - - - - -
-
-
diff --git a/Memory.xml b/Memory.xml deleted file mode 100644 index c61576bcfc..0000000000 --- a/Memory.xml +++ /dev/null @@ -1,3095 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - -
-
-
-
-
-
-
- - -
-
-
-
- - -
-
-
-
-
-
-
-
-
-
-
-
- - -
- - - - - - - - - - - - - - - - - - -
- - - - - - -
- - - - - - -
-
- - - - - - - vector - vector - - - -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - -
- - -
- - - -
- - - -
- - - -
- - -
-
- - - -
- - - -
- -
- - - - -
- - - - - - -
- - List of offsets in the VTable : - - - - - - - - - - - - -
-
-
-
-
- - - - -
- - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - .,:rsr, - :2;,;r2A@@5 - @2::s5A#@@@ @r. . - sd;:riXA#@@ :@@@Gir;;AS9 - Bs::sS3A#@2 @@#AhXirsS#; - iHrLr5d#@@@ .@#95sr;;rie - i*' `*@3 @@A2sr;:;r#5 - :..:rll: @@A5sr::r3@ - @Hr;iZ#@@@@ `:rr;;;;: - S@r.;i2#@@@ @s. .. - @2::ri2A@@# B@G2ir:...5i - :@r,r3X##@@ @G5sr:..,:A - .@Ar;;rSB@@# H#2sr;,..,is - .' `* ,@ASs;:..,:B - ;rr;:,..,:. - `''' - W I N D O W S - and - W I N E - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - -
-
-
-
-
- - -
-
-
-
- - -
-
-
-
-
-
-
-
-
-
-
-
- - - - - - - - - - - - - - - - -
- - - - - -
- - - - - -
-
- - - - - vector - vector - - - -
-
-
- - - - - - - - - - - - - - - - - - - - - the skill that will be increased at the end of the mood (or not) - - seems to be indexes in the list of possible colors defined in the raws for each group - - - - - - - - - - - - - - - - - Incrementaly assigned - seems to be just like the old occupations - - - like mood materials, 0=bars, 4=stone, 5=wood, 57=cloth, 54=leather ... - subsubtype ? - subtype ? - index of material (for example, 2 is for silver) - set only for shell / bone mood requirements ? - - - - -
-
-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
-
- - - -
- - - -
- -
- - - - -
- - - - - - - - - - - - - - - - WORLD: 0x0165c1d0 ? - -
Was 0x17f5ab8 - - -
-
-
-
-
-
-
-
-
-
-
-
- - -
- - -
- - - -
-
- - - -
- - - - - - - - - - - -
-
-
-
-
-
- -
- - -
- - - -
- - - -
- - -
-
- - -
- - - -
-
- - -
- List of offsets in the VTable : - - - - - ... seriously, WHAT? - - - - - -
-
- - - - - - - - -
- - -
- -
-
-
-
-
- -
-
-
- - - -
-
- - -
-
- - -
-
-
-
-
-
-
-
-
-
-
-
- - -
- - -
- - - -
-
- - - -
- - -
- - -
- - -
- - -
-
-
-
-
- - - - - - - - -
-
BOGUS! - - -
-
-
-
- - -
-
- - - - - - - -
- - - - - - - -
- - - - - - - - -
- - - - - - - - -
- - -
- - - - - - - - - - - - - - - - - - - - - - - - -
-
-
-
- - - - - - - - -
- - -
MAYBE -
- - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - -
-
-
-
-
-
- - -
- - -
- - -
- - -
-
-
-
-
-
-
-
- -
- -
- -
-
- - - - - - - - - - - - - - - -
- - - - - -
- - - - - -
-
- - - vector - vector - - - YES -
-
-
-
-
-
NO! - - YES - YES - YES - YES - - YES - MAYBE - YES - - YES - - - - - YES - - - - - - - - - this is crap it seems - - -
- - - -
- - - -
- - - -
-
- - - -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - is it a vector? - - - - - - - - - - - -
- - - -
Second possible: 0x0169fb7C - - - - - - - - - - -
- - -
- - - -
-
- - - -
-
- - -
-
-
-
-
- - -
-
- - - -
Second possible: 0x016a0b88 - - - - - - - - - - - - -
0x16445F0 + 0x5DC0C see code at 0x9CFB01 - - -
-
- - -
- AS BOGUS AS IT GETS -
-
-
-
- - -
- - -
MAYBE -
-
- - -
- - - - - - - - - - - - - -
- -
-
- - - -
-
-
-
-
- - -
- - - - -
- - -
- - - -
-
- - - - 0x016a12c0 vector - - -
MAYBE... THE DETAILS WILL BE DIFFERENT -
- WTF IS THIS, I DON'T EVEN... -
-
-
- - -
- - -
-
- - - -
-
-
- - - - - - - - - - - -
-
-
-
-
- - -
maybe -
-
- - - - - - - - - THIS IS TOTAL BS - DT: 0x3C4, I don't believe that's OK' - DT calls it 'states' it seems - maybe - - - - - - - - - - - - -
-
-
-
-
-
-
-
-
-
TODO: it's signed! -
-
- - -
- - -
- - - LOOKS FINE? -
-
- - - - -
-
-
-
-
-
- - maybe: 0x2064 before:0x1a08 - - looks kinda funny, same as in .16 - OK - OK - - - -
-
- - - -
- - -
- - -
- - -
- One of those really. Which one is the right one? - 0x16dad78 - 0x16dad88 -
- - -
maybe -
-
-
-
- - fortress = 0, adventure = 1, arena = 0, menu and legends = 3 0xb4a814 - Game mode: 0xb4a818 . fortress = 0, adventure = 1, arena = 4 - 0xe2e2a2 seems to be a copy of the first one - - - -
-
- - - - - - - - -
-
-
-
-
-
- -
-
- - I'M NOT SURE ABOUT THESE - - - LOOKS LIKE CRAP, but seems to work anyway - - - - - - 0x530 - 71389344 + 0x5ac - - "region1" = 0x18639d8 - some features vector = 0x18639f8 ? - -
0x16cca38 + 0x56d20 -
-
- - - - -
- - - -
- - - - - - -
-
- - - -
-
- - -
- - -
- - - - - - - - - - Vegetation vector might be bad / not contain willow trees! - - - mode - -
-
-
-
-
- - - - - - - - - - - - - - - - - -
- - -
-
-
-
-
- - -
- - -
0x16B0A78 in 31.25 - - -
- - - - - - Vegetation vector might be bad / not contain willow trees! - - - - - Vegetation vector might be bad / not contain willow trees! - - - - - - - - - - - - -
- - - - - 0x194 TEST - - - - cmake - item vector: - - -- those two seem to have identical length - 0x16c4540 -- maybe - 0x16c4550 -- maybe - - 0x16c4d20 -- too small/bogus? - 0x16c4660 -- too small again - 0x185c104 -- no. - - .-"""-. - ' \ - |,. ,-. | _________________________ - |()L( ()| | \ \ - |,' `".| | /_ Argh !!! \ - |.___.',| ` \________________________\ - .j `--"' ` `. - / ' ' \ - / / ` `. - / / ` . - / / l | - . , L I N U X | | - ,"`. .| | - _.' ``. | `..-'l - | `.`, | `. - | `. __.j ) - |__ |--""___| ,-' - `"--...,+"""" `._,.-' - - - - - - - -
- - - - - - - - - - - - - - - - - -
-
-
-
-
- - -
- - -
-
-
-
-
-
-
-
-
-
-
-
- - - - - - - - - - - - - - - -
- - - - - -
- - - - - -
-
- - - - - vector - vector - - - -
-
-
- - - - - - - - - - - - - - CHMOD - It's good - - - chmod - - - - - - - - - - - - - - -
-
-
-
-
- VERIFY - - - - - - - - - - -
- - - -
- - - -
-
- - - -
-
- - - - - - - - -
VERIFIED - - Creatures - ========= - WORLD + 0x139E0 - 0x92d79d4 - 0x92d79e0 = real one? seems like it - 0x92d7a10 - - - - - - - - - - - - - - - VERIFY - - - - - - - - - - - CHMOD - - - - - - - - - -
- -
- - - - - - - - - - - - - - - - -
VERIFIED -
VERIFIED -
VERIFIED -
VERIFIED - - - - - - - - -
- - -
- - -
- - - -
- - -
- - - -
- - - - - - - -
- - -
- - -
-
-
- - -
-
-
-
-
-
-
-
-
-
-
-
- - -
- - -
- - - -
-
- - - -
-
-
-
-
-
- - -
- - -
- - -
-
-
- - - - - - - -
-
-
-
-
-
-
-
-
-
-
-
- - -
- - - -
- - -
-
-
-
-
-
- - -
- - - - - - - -
- - -
- - - - - - - -
-
- - -
- - -
-
-
possibly bullshit! - - -
- - - - -
- - -
- - - -
-
- - - -
-
-
-
-
- -
-
- - - -
-
-
-
- - -
-
- - -
-
- - - - - - - -
-
- - -
- - -
-
-
0x93f886c = orig, possibly bullshit! VERIFY!!! - - -
- - -
-
- - -
- - -
- - - -
-
- - - -
-
-
-
-
- -
-
- - - -
-
-
-
- - -
-
- - -
-
- - - - - - - - -
- - -
-
-
-
-
- -
-
- - - -
-
-
- - -
-
- - - - - - - -
- - -
-
- - - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - MAYBE, DT SAYS SO - - - - - - - - -
- - -
-
-
-
-
- - -
-
-
-
-
- - -
- there are some possibly related vectors right next to it. - - -
-
-
- - - - - - - - - - - - - - - -
- - - -
- - - - -
-
- - - - - -
- - - - - FIXME: this is 0xa40 really, the struct is wrong - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - -
-
- - - - - - - WORLD: 0x93f77a0 - - Maybe, possibly. -
-
- Address name="vector" value="0x0940b174" - - - - - -
- - -
-
-
- - -
- - - - - - 0x194 TEST - - - - - - - -
- - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - -
- - - - - - diff --git a/README.html b/README.html new file mode 100644 index 0000000000..4d1b0fd13c --- /dev/null +++ b/README.html @@ -0,0 +1,16 @@ + + + + + + + + + Page Redirection + + + Follow this link to the documentation. + + diff --git a/README.md b/README.md new file mode 100644 index 0000000000..3a2db02fc5 --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ +# DFHack Readme + +[![Build Status](https://github.com/DFHack/dfhack/workflows/Build/badge.svg?event=push)](https://github.com/DFHack/dfhack/actions?query=workflow%3ABuild) +[![Documentation Status](https://readthedocs.org/projects/dfhack/badge)](https://dfhack.readthedocs.org) +[![License](https://img.shields.io/badge/license-ZLib-blue.svg)](https://en.wikipedia.org/wiki/Zlib_License) +[![Discord](https://img.shields.io/discord/793331351645323264)](https://dfhack.org/discord) + +DFHack is a Dwarf Fortress memory access library, distributed with scripts +and plugins implementing a wide variety of useful functions and tools. + +The full documentation [is available online here](https://dfhack.readthedocs.org). +If you have DFHack installed, it is also accessible as raw text in the `hack/docs` folder. +If you're an end-user, modder, or interested in contributing to DFHack -- go read those docs. + +If the docs are unclear or you need more help, please check out our [support page](https://docs.dfhack.org/en/latest/docs/Support.html) for ways to contact the DFHack developers. diff --git a/README.rst b/README.rst deleted file mode 100644 index b6dfdcd901..0000000000 --- a/README.rst +++ /dev/null @@ -1,238 +0,0 @@ -============ -Introduction -============ - -DFHack is a Dwarf Fortress memory access library and a set of basic -tools using this library. The library is a work in progress, so things -might change as more tools are written for it. - -It is an attempt to unite the various ways tools access DF memory and -allow for easier development of new tools. - -.. contents:: - -============== -Getting DFHack -============== -The project is currently hosted on github_, for both source and -binaries at http://github.com/peterix/dfhack - -.. _github: http://www.github.com/ - -============= -Compatibility -============= -DFHack works on Windows XP, Vista, 7 or any modern Linux distribution. -OSX is not supported due to lack of developers with a Mac. - -In general, the older DF release you use, the less features will work. -DFHack development is always focused on the latest DF version. Go too -far into the past, and only the most basic tools will work. - -Windows -======= -.. note:: - - Windows 2000 is currently *not supported* due to missing OS - functionality. If you know how to easily suspend processes, you can - fix it :) - -0.31.01 - 0.31.03 legacy - -0.31.04 - 0.31.25 SDL - -Linux -===== -Native linux DF ---------------- -0.31.05 - 0.31.24: spotty support (some things might not work) - -0.31.25: full support - -Windows DF under wine ---------------------- -0.31.01 - 0.31.03 legacy - -0.31.04 - 0.31.25 SDL - -===== -Tools -===== -All the DFHack tools are terminal programs. This might seem strange to Windows -users, but these are meant mostly as examples for developers. Still, they can -be useful and are cross-platform just like the library itself. - -dfattachtest -============ -Test of the process attach/detach mechanism. - -dfautodump -========== -Automated item dumping tool. All loose items on the floor marked -for dumping are insta-dumped to the position of the in-game cursor. - -Cursor must be placed on a floor tile. Instadumped items may not -show up in the cursor description list until you save/reload. - -Options: --------- --d Destroy instead of dumping. Doesn't require a cursor. - -dfcleanmap -========== -Cleans all the splatter that get scattered all over the map. -Only exception is mud. It leaves mud alone. - -dfcleanowned -============ -Removes the ownership flag from items. -By default, owned food on the floor and rotten items are confistacted and dumped. - -Options: --------- --a confiscate all owned items --l confiscated and dump all items scattered on the floor --x confiscate/dump items with wear level 'x' and more --X confiscate/dump items with wear level 'X' and more --d a dry run. combine with other options to see what will happen without it actually happening. - -On Windows: - * dfremovelitter.bat runs the tool with -lx - * dfconfiscate.bat runs the tool with -a - -dfcleartask -=========== -Items marked for a job can get stuck during a abandon/reclaim. This tool aims to fix that. -Best used immediately after a reclaim. Not thoroughly tested, use at your own risk. - -dfderamp (by zilpin) -==================== -Removes all ramps designated for removal from the map. This is useful for replicating the old channel digging designation. -It also removes any and all 'down ramps' that can remain after a cave-in (you don't have to designate anything for that to happen). - -dfdoffsets -========== -Dumps the offsets for the currently running DF version into the terminal. - -dfexpbench -========== -Just a simple benchmark of the data export speed. - -dfflows -======= -A tool for checking how many liquid tiles are actively checked for flows. - -dfincremental -============= -A simple memory search tool for DF. Requires arcane knowledge ;) - -dfgrow -====== -Makes all saplings present on the map grow into trees (almost) instantly. - -dfimmolate -========== -A tool for getting rid of trees and shrubs. By default, it only kills a tree/shrub under the cursor. - -Options: --------- --s affect all shrubs on the map --t affect all trees on the map --i instead of just instaburning plants to ashes, produce fire. WILL KILL FPS! - -The windows binary releases contain many .bat files that can run the tool with different parameters. - -dfstatus (by enjia2000) -======================= -Runs next to DF and shows some vital statistics of the fort, including food and booze. - -dflair -====== -Marks all of the map as a lair, preventing item scatter on abandon/reclaim. - -dfliquids -========= -A command prompt for liquid creation and manipulation (the Moses -effect included!) Also allows painting obsidian walls directly. - -.. note:: - - Spawning and deleting liquids can F up pathing data and - temperatures (creating heat traps). You've been warned. - -dfmode -====== -This tool lets you change the game mode directly. Not all combinations are good for every situation and most of them will produce undesirable results. -There are a few good ones though. - -.. admonition:: Example - - You are in fort game mode (0 game mode), managing your fortress (0 control mode) and paused. - You switch to the arena game mode, *assume control of a creature* and the switch to adventure game mode(1). - You just lost a fortress and gained an adventurer. - -I take no responsibility of anything that happens as a result of using this tool :P - -dfpause -======= -Forces DF to pause. This is useful when your FPS drops below 1 and you lose control of the game. - -dfposition -========== -Prints the game mode, current DF window properties and cursor position in both local and world coordinates. - -dfprobe -======= -Can be used to determine tile properties like temperature. - -dfprospector -============ -Lists all available minerals on the map and how much of them there is. - -Options: --------- --a processes all tiles, even hidden ones. - -On windows, it's possible to run dfprospector-all.bat to process all the tiles without messing with terminal windows. -Also on Windos, dfprospector-text.bat will print the output into a file and then show it in a notepad program (whatever opens .txt by default). - -dfreveal -======== -Reveals the whole map, waits for input and hides it again. If you close -the tool while it waits, the map remains revealed. - -dfunreveal -========== -Hides everything and then only reveals the part of the map accessible from the position of DF's cursor. Place the cursor in open space that you want to keep revealed - this should include the surface world. -Can be used to fix maps stuck revealed or hide parts of the fortress blocked off by walls. - -dfsuspend -========= -Test of the process suspend/resume mechanism. If this doesn't work as expected, it's not safe to use DFHack. - -dftubefill -========== -Fills all the 'candy stores' with 'delicious candy'. No need to fear the clowns. Don't use if you haven't seen the hidden fun stuff -yet ;) - -dfunstuck -========= -Use if you prematurely close any of the tools and DF appears to be stuck. Mostly only needed on Windows. - -dfvdig -====== -Designates a whole vein for digging. Point the cursor at a vein and run this thing :) -Running 'dfXvdig' on Windows or using the '-x' parameter will dig stairs between z-levels to follow the veins. - -dfveinlook -========== -Simplistic map viewer. Mostly a debug/development thing. Now supported on Windows too! - -dfweather -=========== -Lets you change the current weather to 'clear sky', 'rainy' or 'snowing'. Fill those ponds without mucking around with dfliquids -:D Rain can also stop brush fires. - -Your tool here -============== -Write one ;) diff --git a/Readme.html b/Readme.html deleted file mode 100644 index f218df35f1..0000000000 --- a/Readme.html +++ /dev/null @@ -1,648 +0,0 @@ - - - - - - - - - - -
- - -
-

Introduction

-

DFHack is a Dwarf Fortress memory access library and a set of basic -tools using this library. The library is a work in progress, so things -might change as more tools are written for it.

-

It is an attempt to unite the various ways tools access DF memory and -allow for easier development of new tools.

- -
-
-

Getting DFHack

-

The project is currently hosted on github, for both source and -binaries at http://github.com/peterix/dfhack

-
-
-

Compatibility

-

DFHack works on Windows XP, Vista, 7 or any modern Linux distribution. -OSX is not supported due to lack of developers with a Mac.

-

In general, the older DF release you use, the less features will work. -DFHack development is always focused on the latest DF version. Go too -far into the past, and only the most basic tools will work.

-
-

Windows

-
-

Note

-

Windows 2000 is currently not supported due to missing OS -functionality. If you know how to easily suspend processes, you can -fix it :)

-
-

0.31.01 - 0.31.03 legacy

-

0.31.04 - 0.31.25 SDL

-
-
-

Linux

-
-

Native linux DF

-

0.31.05 - 0.31.24: spotty support (some things might not work)

-

0.31.25: full support

-
-
-

Windows DF under wine

-

0.31.01 - 0.31.03 legacy

-

0.31.04 - 0.31.25 SDL

-
-
-
-
-

Tools

-

All the DFHack tools are terminal programs. This might seem strange to Windows -users, but these are meant mostly as examples for developers. Still, they can -be useful and are cross-platform just like the library itself.

-
-

dfattachtest

-

Test of the process attach/detach mechanism.

-
-
-

dfautodump

-

Automated item dumping tool. All loose items on the floor marked -for dumping are insta-dumped to the position of the in-game cursor.

-

Cursor must be placed on a floor tile. Instadumped items may not -show up in the cursor description list until you save/reload.

-
-

Options:

- --- - - - -
--dDestroy instead of dumping. Doesn't require a cursor.
-
-
-
-

dfcleanmap

-

Cleans all the splatter that get scattered all over the map. -Only exception is mud. It leaves mud alone.

-
-
-

dfcleanowned

-

Removes the ownership flag from items. -By default, owned food on the floor and rotten items are confistacted and dumped.

-
-

Options:

- --- - - - - - - - - - - - -
--aconfiscate all owned items
--lconfiscated and dump all items scattered on the floor
--xconfiscate/dump items with wear level 'x' and more
--Xconfiscate/dump items with wear level 'X' and more
--da dry run. combine with other options to see what will happen without it actually happening.
-
-
On Windows:
-
    -
  • dfremovelitter.bat runs the tool with -lx
  • -
  • dfconfiscate.bat runs the tool with -a
  • -
-
-
-
-
-
-

dfcleartask

-

Items marked for a job can get stuck during a abandon/reclaim. This tool aims to fix that. -Best used immediately after a reclaim. Not thoroughly tested, use at your own risk.

-
-
-

dfderamp (by zilpin)

-

Removes all ramps designated for removal from the map. This is useful for replicating the old channel digging designation. -It also removes any and all 'down ramps' that can remain after a cave-in (you don't have to designate anything for that to happen).

-
-
-

dfdoffsets

-

Dumps the offsets for the currently running DF version into the terminal.

-
-
-

dfexpbench

-

Just a simple benchmark of the data export speed.

-
-
-

dfflows

-

A tool for checking how many liquid tiles are actively checked for flows.

-
-
-

dfincremental

-

A simple memory search tool for DF. Requires arcane knowledge ;)

-
-
-

dfgrow

-

Makes all saplings present on the map grow into trees (almost) instantly.

-
-
-

dfimmolate

-

A tool for getting rid of trees and shrubs. By default, it only kills a tree/shrub under the cursor.

-
-

Options:

- --- - - - - - - - -
--saffect all shrubs on the map
--taffect all trees on the map
--iinstead of just instaburning plants to ashes, produce fire. WILL KILL FPS!
-

The windows binary releases contain many .bat files that can run the tool with different parameters.

-
-
-
-

dfstatus (by enjia2000)

-

Runs next to DF and shows some vital statistics of the fort, including food and booze.

-
-
-

dflair

-

Marks all of the map as a lair, preventing item scatter on abandon/reclaim.

-
-
-

dfliquids

-

A command prompt for liquid creation and manipulation (the Moses -effect included!) Also allows painting obsidian walls directly.

-
-

Note

-

Spawning and deleting liquids can F up pathing data and -temperatures (creating heat traps). You've been warned.

-
-
-
-

dfmode

-

This tool lets you change the game mode directly. Not all combinations are good for every situation and most of them will produce undesirable results. -There are a few good ones though.

-
-

Example

-

You are in fort game mode (0 game mode), managing your fortress (0 control mode) and paused. -You switch to the arena game mode, assume control of a creature and the switch to adventure game mode(1). -You just lost a fortress and gained an adventurer.

-
-

I take no responsibility of anything that happens as a result of using this tool :P

-
-
-

dfpause

-

Forces DF to pause. This is useful when your FPS drops below 1 and you lose control of the game.

-
-
-

dfposition

-

Prints the game mode, current DF window properties and cursor position in both local and world coordinates.

-
-
-

dfprobe

-

Can be used to determine tile properties like temperature.

-
-
-

dfprospector

-

Lists all available minerals on the map and how much of them there is.

-
-

Options:

- --- - - - -
--aprocesses all tiles, even hidden ones.
-

On windows, it's possible to run dfprospector-all.bat to process all the tiles without messing with terminal windows. -Also on Windos, dfprospector-text.bat will print the output into a file and then show it in a notepad program (whatever opens .txt by default).

-
-
-
-

dfreveal

-

Reveals the whole map, waits for input and hides it again. If you close -the tool while it waits, the map remains revealed.

-
-
-

dfunreveal

-

Hides everything and then only reveals the part of the map accessible from the position of DF's cursor. Place the cursor in open space that you want to keep revealed - this should include the surface world. -Can be used to fix maps stuck revealed or hide parts of the fortress blocked off by walls.

-
-
-

dfsuspend

-

Test of the process suspend/resume mechanism. If this doesn't work as expected, it's not safe to use DFHack.

-
-
-

dftubefill

-

Fills all the 'candy stores' with 'delicious candy'. No need to fear the clowns. Don't use if you haven't seen the hidden fun stuff -yet ;)

-
-
-

dfunstuck

-

Use if you prematurely close any of the tools and DF appears to be stuck. Mostly only needed on Windows.

-
-
-

dfvdig

-

Designates a whole vein for digging. Point the cursor at a vein and run this thing :) -Running 'dfXvdig' on Windows or using the '-x' parameter will dig stairs between z-levels to follow the veins.

-
-
-

dfveinlook

-

Simplistic map viewer. Mostly a debug/development thing. Now supported on Windows too!

-
-
-

dfweather

-

Lets you change the current weather to 'clear sky', 'rainy' or 'snowing'. Fill those ponds without mucking around with dfliquids -:D Rain can also stop brush fires.

-
-
-

Your tool here

-

Write one ;)

-
-
-
- - diff --git a/ReleaseText.txt b/ReleaseText.txt deleted file mode 100644 index 83b538a635..0000000000 --- a/ReleaseText.txt +++ /dev/null @@ -1 +0,0 @@ -DFHack tools for DF 31.21 \ No newline at end of file diff --git a/build/.gitignore b/build/.gitignore index 474fe987c3..0675a165cf 100644 --- a/build/.gitignore +++ b/build/.gitignore @@ -1 +1,11 @@ -build-real \ No newline at end of file +VC2010 +VC2015 +VC2015_32 +VC2022 +DF_PATH.txt +_CPack_Packages +*.tar.* +.cmake +win64-cross +dest +DF diff --git a/build/build-MinGW32-debug.bat b/build/build-MinGW32-debug.bat deleted file mode 100644 index a20cb905c3..0000000000 --- a/build/build-MinGW32-debug.bat +++ /dev/null @@ -1,6 +0,0 @@ -mkdir MINGW32-debug -cd MINGW32-debug -cmake ..\.. -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE:string=Debug -cmake-gui . -mingw32-make 2> ..\mingw-build-log.txt -pause \ No newline at end of file diff --git a/build/build-MinGW32-release.bat b/build/build-MinGW32-release.bat deleted file mode 100644 index af1dd060bf..0000000000 --- a/build/build-MinGW32-release.bat +++ /dev/null @@ -1,7 +0,0 @@ -mkdir MINGW32-release -cd MINGW32-release -cmake ..\.. -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE:string=Release - -cmake-gui . -mingw32-make 2> ..\mingw-build-log.txt -pause \ No newline at end of file diff --git a/build/build-osx.sh b/build/build-osx.sh new file mode 100755 index 0000000000..e6be0f3085 --- /dev/null +++ b/build/build-osx.sh @@ -0,0 +1,123 @@ +#!/bin/bash + +# This implements steps 7 and 8 of the OSX compilation procedure described in Compile.rst +# If build-osx does not exist in the parent directory, it will be created. + +LUA_PATCH=1 +ME=$PWD/`basename $0` + +usage() { + echo "Usage: $0 [options] {DF_OSX_PATH}" + echo -e "\told\t- use on pre-Snow Leopard OSX installations" + echo -e "\tbrew\t- if GCC 4.5 was installed with homebrew" + echo -e "\tport\t- if GCC 4.5 was insalled with macports" + echo -e "\tclean\t- delete ../build-osx before compiling" + echo "Example:" + echo -e "\t$0 old brew ../../../personal/df_osx" + echo -e "\t$0 port clean /Users/dfplayer/df_osx" + exit $1 +} + +options() { + case $1 in + brew) + echo "Using homebrew gcc." + export CC=/usr/local/bin/gcc-4.5 + export CXX=/usr/local/bin/g++-4.5 + targetted=1 + ;; + port) + echo "Using macports gcc." + export CC=/opt/local/bin/gcc-mp-4.5 + export CXX=/opt/local/bin/g++-mp-4.5 + targetted=1 + ;; + old) + LUA_PATCH=0 + ;; + clean) + echo "Deleting ../build-osx" + rm -rf ../build-osx + ;; + *) + ;; + esac +} + +# sanity checks +if [[ $# -lt 1 ]] +then + echo "Not enough arguments." + usage 0 +fi +if [[ $# -gt 4 ]] +then + echo "Too many arguments." + usage 1 +fi + +# run through the arguments +for last +do + options $last +done +# last keeps the last argument + +if [[ $targetted -eq 0 ]] +then + echo "You did not specify whether you intalled GCC 4.5 from brew or ports." + echo "If you continue, your default compiler will be used." + read -p "Are you sure you want to continue? [y/N] " -n 1 -r + echo # (optional) move to a new line + if [[ ! $REPLY =~ ^[Yy]$ ]] + then + exit 0 + fi +fi + +# check for build folder and start working there +if [[ ! -d ../build-osx ]] +then + mkdir ../build-osx +fi +cd ../build-osx + +# patch if necessary +if [[ $LUA_PATCH -ne 0 ]] +then + cd .. + echo "$PWD" + sed -e '1,/'"PATCH""CODE"'/d' "$ME" | patch -p0 + cd - +fi + +echo "Generate" +cmake .. -DCMAKE_BUILD_TYPE:string=Release -DCMAKE_INSTALL_PREFIX="$last" +echo "Build" +make +echo "Install" +make install + +# unpatch if /libarary/luaTypes.cpp was patched +if [[ $LUA_PATCH -ne 0 ]] +then + cd .. + echo -n "un" + sed -e '1,/'"PATCH""CODE"'/d' "$ME" | patch -p0 -R + cd - +fi + +exit 0 + +# PATCHCODE - everything below this line is fed into patch +--- library/LuaTypes.cpp 2014-08-20 00:13:17.000000000 -0700 ++++ library/LuaTypes.cpp 2014-08-31 23:31:00.000000000 -0700 +@@ -464,7 +464,7 @@ + { + case struct_field_info::STATIC_STRING: + { +- int len = strnlen((char*)ptr, field->count); ++ int len = strlen((char*)ptr); + lua_pushlstring(state, (char*)ptr, len); + return; + } diff --git a/build/build-win64-from-linux.sh b/build/build-win64-from-linux.sh new file mode 100755 index 0000000000..529893412f --- /dev/null +++ b/build/build-win64-from-linux.sh @@ -0,0 +1,60 @@ +#!/bin/bash + +set -e +# Number of jobs == core count +jobs=$(grep -c ^processor /proc/cpuinfo) + +# Calculate absolute paths for docker to do mounts +srcdir=$(realpath "$(dirname "$(readlink -f "$0")")"/..) + +cd "$srcdir"/build + +builder_uid=$(id -u) + +mkdir -p win64-cross +mkdir -p win64-cross/output +mkdir -p win64-cross/pdb +mkdir -p win64-cross/ccache + +# Check for sudo; we want to use the real user +if [[ $(id -u) -eq 0 ]]; then + if [[ -z "$SUDO_UID" || "$SUDO_UID" -eq 0 ]]; then + echo "Please don't run this script directly as root, use sudo instead:" + echo + echo " sudo $0" + # This is because we can't change the buildmaster UID in the container to 0 -- + # that's already taken by root. + exit 1 + fi + + # If this was run using sudo, let's make sure the directories are owned by the + # real user (and set the BUILDER_UID to it) + builder_uid=$SUDO_UID + chown -R $builder_uid win64-cross +fi + +# Pulls the MSVC build env container from the GitHub registry +# +# NOTE: win64-cross is mounted in /src/build due to the hardcoded `cmake ..` in +# the Dockerfile +if ! docker run --rm -i -v "$srcdir":/src -v "$srcdir/build/win64-cross/":/src/build \ + -e BUILDER_UID=$builder_uid \ + -e CCACHE_DIR=/src/build/ccache \ + -e steam_username \ + -e steam_password \ + --name dfhack-win \ + ghcr.io/dfhack/build-env:master \ + bash -c "cd /src/build && dfhack-configure windows 64 Release -DCMAKE_INSTALL_PREFIX=/src/build/output -DBUILD_DOCS=1 $CMAKE_EXTRA_ARGS && dfhack-make -j$jobs install && find . \! -path './pdb/*' -name '*.pdb' -type f -exec cp '{}' pdb/ \;" \ + ; then + echo + echo "Build failed" + exit 1 +else + echo + echo "Windows artifacts are at win64-cross/output. Copy or symlink them to" + echo "your steam DF directory to install dfhack (and optionally delete the" + echo "hack/ directory already present)" + echo + echo "Typically this can be done like this:" + echo " cp -r win64-cross/output/* ~/.local/share/Steam/steamapps/common/\"Dwarf Fortress\"" +fi diff --git a/build/generate-MSVC-2005.bat b/build/generate-MSVC-2005.bat deleted file mode 100644 index 40aca9e015..0000000000 --- a/build/generate-MSVC-2005.bat +++ /dev/null @@ -1,5 +0,0 @@ -mkdir VC2005 -cd VC2005 -echo Pre-generating a build folder -cmake ..\.. -G"Visual Studio 8 2005" -cmake-gui . \ No newline at end of file diff --git a/build/generate-MSVC-2008.bat b/build/generate-MSVC-2008.bat deleted file mode 100644 index f8b0fd0401..0000000000 --- a/build/generate-MSVC-2008.bat +++ /dev/null @@ -1,5 +0,0 @@ -mkdir VC2008 -cd VC2008 -echo Pre-generating a build folder -cmake ..\.. -G"Visual Studio 9 2008" -cmake-gui . \ No newline at end of file diff --git a/build/generate-MSVC-2010.bat b/build/generate-MSVC-2010.bat deleted file mode 100644 index 00c990083e..0000000000 --- a/build/generate-MSVC-2010.bat +++ /dev/null @@ -1,5 +0,0 @@ -mkdir VC2010 -cd VC2010 -echo Pre-generating a build folder -cmake ..\.. -G"Visual Studio 10" -cmake-gui . \ No newline at end of file diff --git a/build/linux-remote.expect b/build/linux-remote.expect deleted file mode 100644 index 18fcdc8b90..0000000000 --- a/build/linux-remote.expect +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/expect -# procedure to attempt connecting; result 0 if OK, 1 otherwise -proc connect {} { - expect "login:" - send "kitteh\r" - expect "password:" - send "a\r" -expect { - kitteh {return 0} - failed return 1 - "invalid password" return 1 - timeout return 1 - connected -} - # timed out - return 1 -} - -# procedure to do build stuff; result 0 if OK, 1 otherwise -proc dobuild {} { - set timeout -1 - send "pkg-win32.bat\r\n" - puts "\nBuilding...\n" -expect { - "BUILD OK" {return 0} - "MSVC ERROR" {return 1} - "CMAKE ERROR" {return 1} - "ENV ERROR" {return 1} -} -} - -spawn telnet win7 - -set rez [connect] -if { $rez == 1 } { -puts "\nError connecting to server!\n" -exit 1 -} - -send "net use X: \\\\vboxsvr\\projects\r\n" -expect "The command completed successfully." -send "X:\r\n" -expect "X:" -send "cd X:\\dfhack\\build\r\n" -expect "build" - -set buildrez [dobuild] -if { $buildrez == 1 } { - puts "\nThere was an error during build.\n" -} else { - puts "\nAll OK.\n" -} -send "exit\r" -expect eof -exit $buildrez diff --git a/build/pkg-debian.sh b/build/pkg-debian.sh deleted file mode 100644 index 6d3bce5da8..0000000000 --- a/build/pkg-debian.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh -rm -r debian -mkdir debian -cd debian -cmake ../.. -DCMAKE_BUILD_TYPE="Release" -DDFHACK_INSTALL="debian" -DMEMXML_DATA_PATH="/usr/share/dfhack" -DBUILD_DFHACK_C_BINDINGS=ON -DBUILD_DFHACK_DEVEL=ON -DBUILD_DFHACK_DOXYGEN=OFF -DBUILD_DFHACK_EXAMPLES=OFF -DBUILD_DFHACK_PLAYGROUND=OFF -DBUILD_DFHACK_PYTHON_BINDINGS=ON -make package -mv *.deb ../ \ No newline at end of file diff --git a/build/pkg-ubuntu-10.10-x64.sh b/build/pkg-ubuntu-10.10-x64.sh deleted file mode 100644 index 5f4e17b3f4..0000000000 --- a/build/pkg-ubuntu-10.10-x64.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh -rm -r ubuntu64 -mkdir ubuntu64 -cd ubuntu64 -cmake ../.. -DCMAKE_BUILD_TYPE="Release" -DDFHACK_INSTALL="ubuntu-10.10" -DMEMXML_DATA_PATH="/usr/share/dfhack" -DDFHACK_PACKAGE_DIR=".." -DBUILD_DFHACK_C_BINDINGS=ON -DBUILD_DFHACK_DEVEL=ON -DBUILD_DFHACK_DOXYGEN=OFF -DBUILD_DFHACK_EXAMPLES=OFF -DBUILD_DFHACK_PLAYGROUND=OFF -DBUILD_DFHACK_PYTHON_BINDINGS=ON -make package -mv *.deb ../ \ No newline at end of file diff --git a/build/pkg-ubuntu-10.10.sh b/build/pkg-ubuntu-10.10.sh deleted file mode 100644 index 01baab90ee..0000000000 --- a/build/pkg-ubuntu-10.10.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh -rm -r ubuntu -mkdir ubuntu -cd ubuntu -cmake ../.. -DCMAKE_BUILD_TYPE="Release" -DDFHACK_INSTALL="ubuntu-10.10" -DMEMXML_DATA_PATH="/usr/share/dfhack" -DDFHACK_PACKAGE_DIR=".." -DBUILD_DFHACK_C_BINDINGS=ON -DBUILD_DFHACK_DEVEL=ON -DBUILD_DFHACK_DOXYGEN=OFF -DBUILD_DFHACK_EXAMPLES=OFF -DBUILD_DFHACK_PLAYGROUND=OFF -DBUILD_DFHACK_PYTHON_BINDINGS=ON -make package -mv *.deb ../ diff --git a/build/pkg-win32.bat b/build/pkg-win32.bat deleted file mode 100644 index ff71e97449..0000000000 --- a/build/pkg-win32.bat +++ /dev/null @@ -1,37 +0,0 @@ -@ECHO OFF -rd /S /Q MSVC10 -mkdir MSVC10 -cd MSVC10 -echo CLEANUP DONE - -cmake ..\.. -G"Visual Studio 10" -DDFHACK_INSTALL="portable" -DMEMXML_DATA_PATH="." -DBUILD_DFHACK_C_BINDINGS=OFF -DBUILD_DFHACK_DEVEL=OFF -DBUILD_DFHACK_DOXYGEN=OFF -DBUILD_DFHACK_EXAMPLES=OFF -DBUILD_DFHACK_PLAYGROUND=OFF -DBUILD_DFHACK_PYTHON_BINDINGS=OFF > ..\pkg-win32-cmake.log -if errorlevel 1 goto cmakeerror -echo CMAKE OK - -call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" > ..\pkg-win32-env.log -if errorlevel 1 goto enverror -echo ENV OK - -msbuild PACKAGE.vcxproj /p:Configuration=Release /l:FileLogger,Microsoft.Build.Engine;logfile=..\pkg-win32-msbuild.log;encoding=utf-8 -noconsolelogger > NUL -if errorlevel 1 goto msvcerror -move /Y *.zip .. -echo BUILD OK -set errorlevel=0 -goto end - -:cmakeerror -echo CMAKE ERROR -set errorlevel=1 -goto end - -:enverror -echo ENV ERROR -set errorlevel=1 -goto end - -:msvcerror -echo MSVC ERROR -set errorlevel=1 -goto end - -:end \ No newline at end of file diff --git a/build/pkg-win32.sh b/build/pkg-win32.sh deleted file mode 100755 index 6e81264f23..0000000000 --- a/build/pkg-win32.sh +++ /dev/null @@ -1,14 +0,0 @@ -#/bin/sh -# Remote into a virtualbox VM to build with MSVC. -# Very specific to my own local setup. ~px - -# VARS. TODO: parametrize -export DFHACK_VER=0.5.7 -export PKG=dfhack-bin-$DFHACK_VER -export TARGET=Release - -# let's build it all -VBoxManage startvm "7 Prof" -sleep 20 -expect linux-remote.expect $TARGET - diff --git a/build/sublime/dfhack.sublime-project b/build/sublime/dfhack.sublime-project new file mode 100644 index 0000000000..cc147764f3 --- /dev/null +++ b/build/sublime/dfhack.sublime-project @@ -0,0 +1,34 @@ +{ + "folders": + [ + { + "path": "." + } + ], + "build_systems": + [ + { + "name": "DFHack make", + "working_dir": "$project_path", + "cmd": ["python", "$project_path/build/sublime/make.py", "$file"], + "variants": [ + { + "name": "Build all", + "cmd": ["python", "$project_path/build/sublime/make.py", "-a"] + }, + { + "name": "Build+install all", + "cmd": ["python", "$project_path/build/sublime/make.py", "-ai"] + }, + { + "name": "Build plugin", + "cmd": ["python", "$project_path/build/sublime/make.py", "-ap", "$file"] + }, + { + "name": "Build+install plugin", + "cmd": ["python", "$project_path/build/sublime/make.py", "-aip", "$file"] + } + ] + } + ] +} diff --git a/build/sublime/make.py b/build/sublime/make.py new file mode 100644 index 0000000000..526810a40c --- /dev/null +++ b/build/sublime/make.py @@ -0,0 +1,63 @@ +from __future__ import print_function +import argparse +import os +import re +import sys +import subprocess + +class BuildError(Exception): pass + +parser = argparse.ArgumentParser() +parser.add_argument('file', nargs='?', default='', help='current filename') +parser.add_argument('-a', '--all', action='store_true', help='Build all targets') +parser.add_argument('-i', '--install', action='store_true', help='Install') +parser.add_argument('-p', '--plugin', action='store_true', help='Build specified plugin') + +def find_build_folder(): + # search for the one with the most recently modified Makefile + folder = None + mtime = 0 + for f in os.listdir('.'): + if f.startswith('build'): + makefile = os.path.join(f, 'Makefile') + if os.path.isfile(makefile) and os.path.getmtime(makefile) > mtime: + folder = f + mtime = os.path.getmtime(makefile) + if not folder: + raise BuildError('No valid build folder found') + return folder + +def get_plugin_name(filename): + filename = filename.replace('/devel', '') + match = re.search(r'plugins/(.+?)[/\.]', filename) + if match: + return match.group(1) + +def run_command(cmd): + print('$ ' + ' '.join(cmd)) + sys.stdout.flush() + if subprocess.call(cmd) != 0: + raise BuildError('command execution failed: ' + ' '.join(cmd)) + +def main(args): + os.chdir(find_build_folder()) + print('Build folder:', os.getcwd()) + cmd = ['make', '-j3'] + + if args.plugin: + plugin = get_plugin_name(args.file) + if not plugin: + raise BuildError('Cannot determine current plugin name from %r' % args.file) + cmd += [plugin + '/fast'] + + run_command(cmd) + + if args.install: + run_command(['make', 'install/fast']) + +if __name__ == '__main__': + try: + main(parser.parse_args()) + except BuildError as e: + print('** Error: ' + str(e)) + sys.exit(1) diff --git a/build/win64/build-debug.bat b/build/win64/build-debug.bat new file mode 100644 index 0000000000..2db9df402c --- /dev/null +++ b/build/win64/build-debug.bat @@ -0,0 +1 @@ +cmake --build VC2022 -t ALL_BUILD -- /m /p:Platform=x64 /p:Configuration=RelWithDebInfo diff --git a/build/win64/build-release.bat b/build/win64/build-release.bat new file mode 100644 index 0000000000..f719d64bcf --- /dev/null +++ b/build/win64/build-release.bat @@ -0,0 +1 @@ +cmake --build VC2022 -t ALL_BUILD -- /m /p:Platform=x64 /p:Configuration=Release diff --git a/build/win64/generate-MSVC-all.bat b/build/win64/generate-MSVC-all.bat new file mode 100644 index 0000000000..29240da7fd --- /dev/null +++ b/build/win64/generate-MSVC-all.bat @@ -0,0 +1,4 @@ +IF EXIST DF_PATH.txt SET /P _DF_PATH= 0 Then + Set ObjF = fso.GetFolder(args.Item(0)) +else + Set objDlg = WScript.CreateObject("Shell.Application") + Set objF = objDlg.BrowseForFolder (&H0,"Select your DF folder", BIF_returnonlyfsdirs) + if IsValue(objF) Then + set ObjF = objF.self + end if +end if + +If fso.FileExists("DF_PATH.txt") Then + fso.DeleteFile "DF_PATH.txt", True +End If + +If IsValue(objF) Then + If InStr(1, TypeName(objF), "Folder") > 0 Then + Set spoFile = fso.CreateTextFile("DF_PATH.txt", True) + spoFile.WriteLine(objF.Path) + End If +End If + +Function IsValue(obj) + ' Check whether the value has been returned. + Dim tmp + On Error Resume Next + tmp = " " & obj + If Err <> 0 Then + IsValue = False + Else + IsValue = True + End If + On Error GoTo 0 +End Function diff --git a/ci/authors-rst.py b/ci/authors-rst.py new file mode 100755 index 0000000000..6f37172761 --- /dev/null +++ b/ci/authors-rst.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python3 +""" Overly-complicated script to check formatting/sorting in Authors.rst """ + +import os, re, sys + +def main(): + success = [True] + def error(line, msg, **kwargs): + info = '' + for k in kwargs: + info += ' %s %s:' % (k, kwargs[k]) + print('line %i:%s %s' % (line, info, msg)) + if os.environ.get('GITHUB_ACTIONS'): + print('::error file=docs/about/Authors.rst,line=%i::%s %s' % (line, info.lstrip(), msg)) + success[0] = False + with open('docs/about/Authors.rst', 'rb') as f: + lines = list(map(lambda line: line.decode('utf8').replace('\n', ''), f.readlines())) + + if lines[1].startswith('='): + if len(lines[0]) != len(lines[1]): + error(2, 'Length of header does not match underline') + if lines[1].replace('=', ''): + error(2, 'Invalid header') + + first_div_index = list(filter(lambda pair: pair[1].startswith('==='), enumerate(lines[2:])))[0][0] + 2 + first_div = lines[first_div_index] + div_indices = [] + for i, line in enumerate(lines[first_div_index:]): + line_number = i + first_div_index + 1 + if '\t' in line: + error(line_number, 'contains tabs') + if line.startswith('==='): + div_indices.append(i + first_div_index) + if not re.match(r'^=+( =+)+$', line): + error(line_number, 'bad table divider') + if line != lines[first_div_index]: + error(line_number, 'malformed table divider') + if line == lines[first_div_index + i - 1]: + error(line_number, 'duplicate of previous line') + if len(div_indices) < 3: + error(len(lines), 'missing table divider(s)') + for i in div_indices[3:]: + error(i + 1, 'extra table divider') + + col_ranges = [] + i = 0 + while True: + j = first_div.find(' ', i) + col_ranges.append(slice(i, j if j > 0 else None)) + if j == -1: + break + i = j + 1 + + for i, line in enumerate(lines[div_indices[1] + 1:div_indices[2]]): + line_number = i + div_indices[1] + 2 + for c, col in enumerate(col_ranges): + cell = line[col] + if cell.startswith(' '): + error(line_number, 'text does not start in correct location', column=c+1) + # check for text extending into next column if this isn't the last column + if col.stop is not None and col.stop < len(line) and line[col.stop] != ' ': + error(line_number, 'text extends into next column', column=c+1) + if i > 0: + prev_line = lines[div_indices[1] + i] + if line.lower()[col_ranges[0]] < prev_line.lower()[col_ranges[0]]: + error(line_number, 'not sorted: should come before line %i ("%s" before "%s")' % + (line_number - 1, line[col_ranges[0]].rstrip(' '), prev_line[col_ranges[0]].rstrip(' '))) + + return success[0] + +if __name__ == '__main__': + sys.exit(int(not main())) diff --git a/ci/build-lua.sh b/ci/build-lua.sh new file mode 100755 index 0000000000..e29d7ce879 --- /dev/null +++ b/ci/build-lua.sh @@ -0,0 +1,54 @@ +#!/bin/sh + +set -e + +LUA_ROOT="$HOME/lua53" +LUA_URL="http://www.lua.org/ftp/lua-5.3.3.tar.gz" +LUA_TAR=$(basename "$LUA_URL") +LUA_DIR="$LUA_ROOT/${LUA_TAR%.tar.*}" +LUA_SHA1="a0341bc3d1415b814cc738b2ec01ae56045d64ef" + +echo LUA_ROOT $LUA_ROOT +echo LUA_TAR $LUA_TAR +echo LUA_DIR $LUA_DIR + +sha1() { + python -c 'import hashlib, sys; print(hashlib.sha1(open(sys.argv[1],"rb").read()).hexdigest())' "$1" +} + +download() { + echo "Downloading $LUA_URL" + wget -O "$LUA_ROOT/$LUA_TAR" "$LUA_URL" + tar xvf "$LUA_ROOT/$LUA_TAR" +} + +build() { + cd "$LUA_DIR/src" + make generic +} + +main() { + mkdir -p "$LUA_ROOT" + cd "$LUA_ROOT" + mkdir -p bin + + if [ "$(sha1 "$LUA_ROOT/$LUA_TAR" 2>/dev/null)" != "$LUA_SHA1" ]; then + download + build + else + echo "Already downloaded" + + if [ -x "$LUA_DIR/src/luac" ]; then + echo "Already built" + else + build + fi + fi + + echo "Linking" + ln -sf "$LUA_DIR/src/lua" "$LUA_ROOT/bin/lua5.3" + ln -sf "$LUA_DIR/src/luac" "$LUA_ROOT/bin/luac5.3" + echo "Done" +} + +main diff --git a/ci/check-rpc.py b/ci/check-rpc.py new file mode 100755 index 0000000000..5527e1b58c --- /dev/null +++ b/ci/check-rpc.py @@ -0,0 +1,122 @@ +#!/usr/bin/env python3 +import glob +import itertools +import os +import sys + +actual = {'': {}} +SEP = ('=' * 80) + +with open(sys.argv[1]) as f: + plugin_name = '' + for line in f: + line = line.rstrip() + if line.startswith('// Plugin: '): + plugin_name = line.split(' ')[2] + if plugin_name not in actual: + actual[plugin_name] = {} + elif line.startswith('// RPC '): + parts = line.split(' ') + actual[plugin_name][parts[2]] = (parts[4], parts[6]) + +expected = {'': {}} + +for p in glob.iglob('library/proto/*.proto'): + with open(p) as f: + for line in f: + line = line.rstrip() + if line.startswith('// RPC '): + parts = line.split(' ') + expected[''][parts[2]] = (parts[4], parts[6]) + +for p in itertools.chain(glob.iglob('plugins/proto/*.proto'), glob.iglob('plugins/*/proto/*.proto')): + if 'plugins/' + os.path.join('proto', 'example.proto') in p: + continue + print('Checking ' + p) + + plugin_name = '' + with open(p) as f: + for line in f: + line = line.rstrip() + if line.startswith('// Plugin: '): + plugin_name = line.split(' ')[2] + if plugin_name not in expected: + expected[plugin_name] = {} + break + + if plugin_name == '': + continue + + with open(p) as f: + for line in f: + line = line.rstrip() + if line.startswith('// RPC '): + parts = line.split(' ') + expected[plugin_name][parts[2]] = (parts[4], parts[6]) + +error_count = 0 + +for plugin_name in actual: + methods = actual[plugin_name] + + if plugin_name not in expected: + print(SEP) + print('Missing documentation for plugin proto files: ' + plugin_name) + print('Add the following lines:') + print('// Plugin: ' + plugin_name) + error_count += 1 + for m in methods: + io = methods[m] + print('// RPC ' + m + ' : ' + io[0] + ' -> ' + io[1]) + error_count += 1 + else: + missing = [] + wrong = [] + for m in methods: + io = methods[m] + if m in expected[plugin_name]: + if expected[plugin_name][m] != io: + wrong.append('// RPC ' + m + ' : ' + io[0] + ' -> ' + io[1]) + else: + missing.append('// RPC ' + m + ' : ' + io[0] + ' -> ' + io[1]) + + if len(missing) > 0: + print(SEP) + print('Incomplete documentation for ' + ('core' if plugin_name == '' else 'plugin "' + plugin_name + '"') + ' proto files. Add the following lines:') + for m in missing: + print(m) + error_count += 1 + + if len(wrong) > 0: + print(SEP) + print('Incorrect documentation for ' + ('core' if plugin_name == '' else 'plugin "' + plugin_name + '"') + ' proto files. Replace the following comments:') + for m in wrong: + print(m) + error_count += 1 + +for plugin_name in expected: + methods = expected[plugin_name] + + if plugin_name not in actual: + print(SEP) + print('Incorrect documentation for plugin proto files: ' + plugin_name) + print('The following methods are documented, but the plugin does not provide any RPC methods:') + for m in methods: + io = methods[m] + print('// RPC ' + m + ' : ' + io[0] + ' -> ' + io[1]) + error_count += 1 + else: + missing = [] + for m in methods: + io = methods[m] + if m not in actual[plugin_name]: + missing.append('// RPC ' + m + ' : ' + io[0] + ' -> ' + io[1]) + + if len(missing) > 0: + print(SEP) + print('Incorrect documentation for ' + ('core' if plugin_name == '' else 'plugin "' + plugin_name + '"') + ' proto files. Remove the following lines:') + for m in missing: + print(m) + error_count += 1 + +sys.exit(min(100, error_count)) diff --git a/ci/download-df.sh b/ci/download-df.sh new file mode 100755 index 0000000000..ed8b373a25 --- /dev/null +++ b/ci/download-df.sh @@ -0,0 +1,56 @@ +#!/bin/sh + +DF_FOLDER=$1 +OS_TARGET=$2 +DF_VERSION=$3 + +set -e + +minor=$(echo "$DF_VERSION" | cut -d. -f1) +patch=$(echo "$DF_VERSION" | cut -d. -f2) +if [ "$DF_VERSION" = "51.03" -o "$DF_VERSION" = "51.04" ]; then + patch=02 +fi +df_url="https://www.bay12games.com/dwarves/df_${minor}_${patch}" +if test "$OS_TARGET" = "windows"; then + WGET="C:/msys64/usr/bin/wget.exe" + df_url="${df_url}_win_s.zip" + df_archive_name="df.zip" + df_extract_cmd="unzip -d ${DF_FOLDER}" +elif test "$OS_TARGET" = "ubuntu"; then + WGET=wget + df_url="${df_url}_linux.tar.bz2" + df_archive_name="df.tar.bz2" + df_extract_cmd="tar -x -j -C ${DF_FOLDER} -f" +else + echo "Unhandled OS target: ${OS_TARGET}" + exit 1 +fi + +if ! $WGET -v "$df_url" -O "$df_archive_name"; then + echo "Failed to download DF from $df_url" + exit 1 +fi + +md5sum "$df_archive_name" + +save_url="https://dffd.bay12games.com/download.php?id=15434&f=dreamfort.7z" +save_archive_name="test_save.7z" +save_extract_cmd="7z x -o${DF_FOLDER}/save" + +if ! $WGET -v "$save_url" -O "$save_archive_name"; then + echo "Failed to download test save from $save_url" + exit 1 +fi + +md5sum "$save_archive_name" + +echo Extracting +mkdir -p ${DF_FOLDER} +$df_extract_cmd "$df_archive_name" +$save_extract_cmd "$save_archive_name" +mv ${DF_FOLDER}/save/* ${DF_FOLDER}/save/region1 + +echo Done + +ls -l diff --git a/ci/get-df-version.sh b/ci/get-df-version.sh new file mode 100755 index 0000000000..24386252d9 --- /dev/null +++ b/ci/get-df-version.sh @@ -0,0 +1,4 @@ +#!/bin/sh +cd "$(dirname "$0")" +cd .. +grep -i 'set(DF_VERSION' CMakeLists.txt | perl -ne 'print "$&\n" if /[\d\.]+/' diff --git a/ci/lint-check.txt b/ci/lint-check.txt new file mode 100644 index 0000000000..bdfa74365f --- /dev/null +++ b/ci/lint-check.txt @@ -0,0 +1,32 @@ +# Files that lint.py should check + +*.bash +*.bat +*.c +*.cc +*.cmake +*.cpp +*.css +*.gitignore +*.h +*.hh +*.hpp +*.in +*.inc +*.init +*.init-example +*.js +*.lua +*.manifest +*.md +*.mm +*.pl +*.proto +*.py +*.rb +*.rst +*.sh +*.txt +*.vbs +*.yaml +*.yml diff --git a/ci/lint-ignore.txt b/ci/lint-ignore.txt new file mode 100644 index 0000000000..6e9d32cf01 --- /dev/null +++ b/ci/lint-ignore.txt @@ -0,0 +1,24 @@ +# Files that lint.py should ignore + +.git/* + +# Old files exempt from checks for now +plugins/raw/*.txt +plugins/stonesense/*.txt + +# Generated files +*.pb.h +build*/* +docs/changelogs/* +docs/html/* +docs/pdf/* +docs/pseudoxml/* +docs/tags/* +docs/text/* +docs/tools/* +docs/xml/* +library/include/df/* + +# Dependencies that we don't control +depends/* +plugins/stonesense/allegro/* diff --git a/ci/lint.py b/ci/lint.py new file mode 100755 index 0000000000..f2c01cd9c5 --- /dev/null +++ b/ci/lint.py @@ -0,0 +1,197 @@ +#!/usr/bin/env python3 +import argparse +import fnmatch +import re +import os +import subprocess +import sys + +DFHACK_ROOT = os.path.normpath(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + +def load_pattern_files(paths): + patterns = [] + for p in paths: + with open(p) as f: + for line in f.readlines(): + line = line.strip() + if line and not line.startswith('#'): + patterns.append(line) + return patterns + +def valid_file(rel_path, check_patterns, ignore_patterns): + return ( + any(fnmatch.fnmatch(rel_path, pattern) for pattern in check_patterns) + and not any(fnmatch.fnmatch(rel_path, pattern) for pattern in ignore_patterns) + ) + +success = True +def error(msg=None): + global success + success = False + if msg: + sys.stderr.write(msg + '\n') + +def format_lines(lines, total): + if len(lines) == total - 1: + return 'entire file' + if not len(lines): + # should never happen + return 'nowhere' + if len(lines) == 1: + return 'line %i' % lines[0] + s = 'lines ' + range_start = range_end = lines[0] + for i, line in enumerate(lines): + if line > range_end + 1: + if range_start == range_end: + s += ('%i, ' % range_end) + else: + s += ('%i-%i, ' % (range_start, range_end)) + range_start = range_end = line + if i == len(lines) - 1: + s += ('%i' % line) + else: + range_end = line + if i == len(lines) - 1: + s += ('%i-%i, ' % (range_start, range_end)) + return s.rstrip(' ').rstrip(',') + +class LinterError(Exception): + def __init__(self, message, lines, total_lines): + self.message = message + self.lines = lines + self.total_lines = total_lines + + def __str__(self): + return '%s: %s' % (self.message, format_lines(self.lines, self.total_lines)) + + def github_actions_workflow_command(self, filename): + first_line = self.lines[0] if self.lines else 1 + return '::error file=%s,line=%i::%s' % (filename, first_line, self) + +class Linter(object): + ignore = False + def check(self, lines): + failures = [] + for i, line in enumerate(lines): + if not self.check_line(line): + failures.append(i + 1) + if len(failures): + raise LinterError(self.msg, failures, len(lines)) + + def fix(self, lines): + for i in range(len(lines)): + lines[i] = self.fix_line(lines[i]) + + +class NewlineLinter(Linter): + msg = 'Contains DOS-style newlines' + # git supports newline conversion. Catch in CI, ignore on Windows. + ignore = os.linesep != '\n' and not os.environ.get('CI') + def check_line(self, line): + return '\r' not in line + def fix_line(self, line): + return line.replace('\r', '') + +class TrailingWhitespaceLinter(Linter): + msg = 'Contains trailing whitespace' + def check_line(self, line): + line = line.replace('\r', '').replace('\n', '') + return line == line.rstrip('\t ') + def fix_line(self, line): + return line.rstrip('\t ') + +class TabLinter(Linter): + msg = 'Contains tabs' + def check_line(self, line): + return '\t' not in line + def fix_line(self, line): + return line.replace('\t', ' ') + +linters = [cls() for cls in Linter.__subclasses__() if not cls.ignore] + +def walk_all(root_path): + for cur, dirnames, filenames in os.walk(root_path): + for filename in filenames: + full_path = os.path.join(cur, filename) + yield full_path + +def walk_git_files(root_path): + p = subprocess.Popen(['git', '-C', root_path, 'ls-files', root_path], stdout=subprocess.PIPE) + for line in p.stdout.readlines(): + path = line.decode('utf-8').strip() + full_path = os.path.join(root_path, path) + yield full_path + if p.wait() != 0: + raise RuntimeError('git exited with %r' % p.returncode) + +def main(args): + root_path = os.path.abspath(args.path) + if not os.path.exists(args.path): + print('Nonexistent path: %s' % root_path) + sys.exit(2) + + check_patterns = load_pattern_files(args.check_patterns) + ignore_patterns = load_pattern_files(args.ignore_patterns) + + walk_iter = walk_all + if args.git_only: + walk_iter = walk_git_files + + for full_path in walk_iter(root_path): + rel_path = full_path.replace(root_path, '').replace('\\', '/').lstrip('/') + if not valid_file(rel_path, check_patterns, ignore_patterns): + continue + if args.verbose: + print('Checking:', rel_path) + lines = [] + with open(full_path, 'rb') as f: + lines = f.read().split(b'\n') + for i, line in enumerate(lines): + try: + lines[i] = line.decode('utf-8') + except UnicodeDecodeError: + msg_params = (rel_path, i + 1, 'Invalid UTF-8 (other errors will be ignored)') + error('%s:%i: %s' % msg_params) + if args.github_actions: + print('::error file=%s,line=%i::%s' % msg_params) + lines[i] = '' + for linter in linters: + try: + linter.check(lines) + except LinterError as e: + error('%s: %s' % (rel_path, e)) + if args.github_actions: + print(e.github_actions_workflow_command(rel_path)) + if args.fix: + linter.fix(lines) + contents = '\n'.join(lines) + with open(full_path, 'wb') as f: + f.write(contents.encode('utf-8')) + + if success: + print('All linters completed successfully') + sys.exit(0) + else: + sys.exit(1) + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('path', nargs='?', default='.', + help='Path to scan (default: current directory)') + parser.add_argument('--fix', action='store_true', + help='Attempt to modify files in-place to fix identified issues') + parser.add_argument('--git-only', action='store_true', + help='Only check files tracked by git') + parser.add_argument('--github-actions', action='store_true', + help='Enable GitHub Actions workflow command output') + parser.add_argument('-v', '--verbose', action='store_true', + help='Log files as they are checked') + parser.add_argument('--check-patterns', action='append', + default=[os.path.join(DFHACK_ROOT, 'ci', 'lint-check.txt')], + help='File(s) containing filename patterns to check') + parser.add_argument('--ignore-patterns', action='append', + default=[os.path.join(DFHACK_ROOT, 'ci', 'lint-ignore.txt')], + help='File(s) containing filename patterns to ignore') + args = parser.parse_args() + main(args) diff --git a/ci/run-tests.py b/ci/run-tests.py new file mode 100755 index 0000000000..13eeb099c8 --- /dev/null +++ b/ci/run-tests.py @@ -0,0 +1,138 @@ +#!/usr/bin/env python3 +import argparse +import enum +import json +import os +import re +import shutil +import subprocess +import sys + +parser = argparse.ArgumentParser() +parser.add_argument('df_folder', help='DF base folder') +parser.add_argument('--headless', action='store_true', + help='Run without opening DF window (requires non-Windows)') +parser.add_argument('--keep-status', action='store_true', + help='Do not delete final status file') +parser.add_argument('--no-quit', action='store_true', + help='Do not quit DF when done') +parser.add_argument('--test-dir', '--test-folder', + help='Base test folder (default: df_folder/test)') +parser.add_argument('-t', '--test', dest='tests', nargs='+', + help='Test(s) to run (Lua patterns accepted)') +args = parser.parse_args() + +if (not sys.stdin.isatty() or not sys.stdout.isatty() or not sys.stderr.isatty()) and not args.headless: + print('WARN: no TTY detected, enabling headless mode') + args.headless = True + +if args.test_dir is not None: + args.test_dir = os.path.normpath(os.path.join(os.getcwd(), args.test_dir)) + if not os.path.isdir(args.test_dir): + print('ERROR: invalid test folder: %r' % args.test_dir) + +MAX_TRIES = 5 + +dfhack = 'Dwarf Fortress.exe' if sys.platform == 'win32' else './dfhack' +test_status_file = 'test_status.json' + +class TestStatus(enum.Enum): + PENDING = 'pending' + PASSED = 'passed' + FAILED = 'failed' + +def get_test_status(): + if os.path.isfile(test_status_file): + with open(test_status_file) as f: + return {k: TestStatus(v) for k, v in json.load(f).items()} + +def change_setting(content, setting, value): + return '[' + setting + ':' + value + ']\n' + re.sub( + r'\[' + setting + r':.+?\]', '(overridden)', content, flags=re.IGNORECASE) + +os.chdir(args.df_folder) +if os.path.exists(test_status_file): + os.remove(test_status_file) + +print('Backing up init.txt to init.txt.orig') +default_init_txt_path = 'data/init/init_default.txt' +prefs_path = 'prefs' +init_txt_path = 'prefs/init.txt' +if not os.path.exists(init_txt_path): + os.makedirs(prefs_path, exist_ok=True) + shutil.copyfile(default_init_txt_path, init_txt_path) + +shutil.copyfile(init_txt_path, init_txt_path + '.orig') +with open(init_txt_path) as f: + init_contents = f.read() +init_contents = change_setting(init_contents, 'SOUND', 'NO') +init_contents = change_setting(init_contents, 'WINDOWED', 'YES') +init_contents = change_setting(init_contents, 'WINDOWEDX', '1200') +init_contents = change_setting(init_contents, 'WINDOWEDY', '800') +#if args.headless: +# init_contents = change_setting(init_contents, 'PRINT_MODE', 'TEXT') + +init_path = 'dfhack-config/init' +if not os.path.isdir('hack/init'): + # we're on an old branch that still reads init files from the root dir + init_path = '.' +os.makedirs(init_path, exist_ok=True) +test_init_file = os.path.join(init_path, 'dfhackzzz_test.init') # Core sorts these alphabetically +with open(test_init_file, 'w') as f: + f.write(''' + devel/dump-rpc dfhack-rpc.txt + test --resume -- lua scr.breakdown_level=df.interface_breakdown_types.%s + ''' % ('NONE' if args.no_quit else 'QUIT')) + +test_config_file = 'test_config.json' +with open(test_config_file, 'w') as f: + json.dump({ + 'test_dir': args.test_dir, + 'tests': args.tests, + }, f) + +try: + with open(init_txt_path, 'w') as f: + f.write(init_contents) + + tries = 0 + while True: + status = get_test_status() + if status is not None: + if all(s != TestStatus.PENDING for s in status.values()): + print('Done!') + sys.exit(int(any(s != TestStatus.PASSED for s in status.values()))) + elif tries > 0: + print('ERROR: Could not read status file') + sys.exit(2) + + tries += 1 + print('Starting DF: #%i' % (tries)) + if tries > MAX_TRIES: + print('ERROR: Too many tries - aborting') + sys.exit(1) + + if args.headless: + os.environ['DFHACK_HEADLESS'] = '1' + os.environ['DFHACK_DISABLE_CONSOLE'] = '1' + + process = subprocess.Popen([dfhack], + stdin=subprocess.PIPE if args.headless else sys.stdin, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + out, err = process.communicate() + if err: + print('WARN: DF produced stderr: ' + repr(err[:5000])) + with open('df-raw-stderr.log', 'wb') as f: + f.write(err) + if process.returncode != 0: + print('ERROR: DF exited with ' + repr(process.returncode)) + print('DF stdout: ' + repr(out[:5000])) +finally: + print('\nRestoring original init.txt') + shutil.copyfile(init_txt_path + '.orig', init_txt_path) + if os.path.isfile(test_init_file): + os.remove(test_init_file) + if not args.keep_status and os.path.isfile(test_status_file): + os.remove(test_status_file) + print('Cleanup done') diff --git a/ci/script-docs.py b/ci/script-docs.py new file mode 100755 index 0000000000..0106a8f706 --- /dev/null +++ b/ci/script-docs.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python3 +import os +from os.path import basename, dirname, exists, join, splitext +import sys + +SCRIPT_PATH = sys.argv[1] if len(sys.argv) > 1 else 'scripts' +DOCS_PATH = join(SCRIPT_PATH, 'docs') +IS_GITHUB_ACTIONS = bool(os.environ.get('GITHUB_ACTIONS')) + +def get_cmd(path): + """Get the command from the name of a script.""" + dname, fname = basename(dirname(path)), splitext(basename(path))[0] + if dname in ('devel', 'fix', 'gui', 'modtools'): + return dname + '/' + fname + return fname + + +def print_error(message, filename, line=None): + if not isinstance(line, int): + line = 1 + print('Error: %s:%i: %s' % (filename, line, message)) + if IS_GITHUB_ACTIONS: + print('::error file=%s,line=%i::%s' % (filename, line, message)) + + +def check_ls(docfile, lines): + """Check length & existence of first sentence for "ls" builtin command.""" + # TODO + return 0 + + +def check_file(fname): + errors, doc_start_line = 0, None + docfile = join(DOCS_PATH, get_cmd(fname)+'.rst') + if not exists(docfile): + print_error('missing documentation file: {!r}'.format(docfile), fname) + return 1 + with open(docfile, errors='ignore') as f: + lines = f.readlines() + if not lines: + print_error('empty documentation file', docfile) + return 1 + for i, l in enumerate(lines): + l = l.strip() + if l and not doc_start_line and doc_start_line != 0: + doc_start_line = i + doc_end_line = i + lines[i] = l + + errors += check_ls(docfile, lines) + title, underline = lines[doc_start_line:doc_start_line+2] + expected_underline = '=' * len(title) + if underline != expected_underline: + print_error('title/underline mismatch: expected {!r}, got {!r}'.format( + expected_underline, underline), + docfile, doc_start_line+1) + errors += 1 + if title != get_cmd(fname): + print_error('expected script title {!r}, got {!r}'.format( + get_cmd(fname), title), + docfile, doc_start_line) + errors += 1 + return errors + + +def main(): + """Check that all DFHack scripts include documentation""" + err = 0 + exclude = {'.git', 'internal', 'test'} + for root, dirs, files in os.walk(SCRIPT_PATH, topdown=True): + dirs[:] = [d for d in dirs if d not in exclude] + for f in files: + if f.split('.')[-1] in {'rb', 'lua'}: + err += check_file(join(root, f)) + return err + + +if __name__ == '__main__': + sys.exit(min(100, main())) diff --git a/ci/script-syntax.py b/ci/script-syntax.py new file mode 100755 index 0000000000..593a25a241 --- /dev/null +++ b/ci/script-syntax.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 +import argparse +import os +import subprocess +import sys + + +def print_stderr(stderr, args): + if not args.github_actions: + sys.stderr.write(stderr + '\n') + return + + for line in stderr.split('\n'): + print(line) + parts = list(map(str.strip, line.split(':'))) + # e.g. luac prints "luac:" in front of messages, so find the first part + # containing the actual filename + for i in range(len(parts) - 1): + if parts[i].endswith('.' + args.ext) and parts[i + 1].isdigit(): + print('::error file=%s,line=%s::%s' % (parts[i], parts[i + 1], ':'.join(parts[i + 2:]))) + break + + +def main(args): + root_path = os.path.abspath(args.path) + cmd = args.cmd.split(' ') + if not os.path.exists(root_path): + print('Nonexistent path: %s' % root_path) + sys.exit(2) + err = False + for cur, dirnames, filenames in os.walk(root_path): + parts = cur.replace('\\', '/').split('/') + if '.git' in parts or 'depends' in parts: + continue + for filename in filenames: + if not filename.endswith('.' + args.ext): + continue + full_path = os.path.join(cur, filename) + try: + p = subprocess.Popen(cmd + [full_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + _, stderr = p.communicate() + stderr = stderr.decode('utf-8', errors='ignore') + if stderr: + print_stderr(stderr, args) + if p.returncode != 0: + err = True + except subprocess.CalledProcessError: + err = True + except IOError: + if not err: + print('Warning: cannot check %s script syntax' % args.ext) + err = True + sys.exit(int(err)) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--path', default='.', help='Root directory') + parser.add_argument('--ext', help='Script extension', required=True) + parser.add_argument('--cmd', help='Command', required=True) + parser.add_argument('--github-actions', action='store_true', + help='Enable GitHub Actions workflow command output') + args = parser.parse_args() + main(args) diff --git a/ci/test.lua b/ci/test.lua new file mode 100644 index 0000000000..a4846520ec --- /dev/null +++ b/ci/test.lua @@ -0,0 +1,752 @@ +-- DFHack developer test harness +--@ module = true + +local expect = require('test_util.expect') +local gui = require('gui') +local helpdb = require('helpdb') +local json = require('json') +local mock = require('test_util.mock') +local overlay = require('plugins.overlay') +local script = require('gui.script') +local utils = require('utils') + +local help_text = +[====[ + +test +==== + +Tags: dev + +Command: "test" + + Run DFHack regression tests. + +Discover DFHack functionality that has broken due to recent changes in DF or DFHack. + +Usage +----- + + test [] [] + +If a done_command is specified, it will be run after the tests complete. + +Options +------- + +-d, --test_dir specifies which directory to look in for tests. defaults to + the "hack/scripts/test" folder in your DF installation. +-m, --modes only run tests in the given comma separated list of modes. + see the next section for a list of valid modes. if not + specified, the tests are not filtered by modes. +-r, --resume skip tests that have already been run. remove the + test_status.json file to reset the record. +-s, --save_dir the save folder to load for "fortress" mode tests. this + save is only loaded if a fort is not already loaded when + a "fortress" mode test is run. if not specified, defaults to + 'region1'. +-t, --tests only run tests that match one of the comma separated list of + patterns. if not specified, no tests are filtered and all tessts + are run. + +Modes +----- + +none the test can be run on any screen +title the test must be run on the DF title screen. note that if the game + has a map loaded, "title" mode tests cannot be run +fortress the test must be run while a map is loaded. if the game is + currently on the title screen, the save specified by the save_dir + parameter will be loaded. + +Examples +-------- + +test runs all tests +test -r runs all tests that haven't been run before +test -m none runs tests that don't need the game to be in a + specific mode +test -t quickfort runs quickfort tests +test -d /path/to/dfhack-scripts/repo/test + runs tests in your dev scripts repo + +Default values for the options may be set in a file named test_config.json in +your DF folder. Options with comma-separated values should be written as json +arrays. For example: + + { + "test_dir": "/home/myk/src/dfhack-scripts/test", + "modes": [ "none" ], + "tests": [ "quickfort", "devel" ], + "done_command": "devel/luacov -c" + } + +]====] + +local CONFIG_FILE = 'test_config.json' +local STATUS_FILE = 'test_status.json' +local DF_STATE_FILE = 'test_df_state.json' +local TestStatus = { + PENDING = 'pending', + PASSED = 'passed', + FAILED = 'failed', +} + +local function delay(frames) + frames = frames or 1 + script.sleep(frames, 'frames') +end + +-- Will call the predicate_fn every frame until it returns true. If it fails to +-- return true before timeout_frames have elapsed, throws an error. If +-- timeout_frames is not specified, defaults to 100. +local function delay_until(predicate_fn, timeout_frames) + timeout_frames = tonumber(timeout_frames) or 100 + repeat + delay() + if predicate_fn() then return end + timeout_frames = timeout_frames - 1 + until timeout_frames < 0 + error('timed out while waiting for predicate to return true') +end + +local function clean_require(module) + -- wrapper around require() - forces a clean load of every module to ensure + -- that modules checking for dfhack.internal.IN_TEST at load time behave + -- properly + if package.loaded[module] then + reload(module) + end + return require(module) +end + +-- clean_run_script and clean_reqscript force a clean load of scripts directly +-- or indirectly included from the test file. we use our own scripts table +-- instead of the one in dfhack.internal so we don't affect the state scripts +-- that are used outside the test harness. +local test_scripts = {} +local test_envvars = {} + +-- clean_run_script is accessed via the dfhack table, not directly from the env. +-- therefore we use this function in wrap_test() below and not in test_envvars. +local function clean_run_script(name, ...) + return dfhack.run_script_with_env( + test_envvars, + name, + {scripts=test_scripts}, + ...) +end + +local function clean_reqscript(name) + local path = dfhack.findScript(name) + if test_scripts[path] then return test_scripts[path].env end + local _, env = dfhack.run_script_with_env( + test_envvars, + name, + { + scripts=test_scripts, + module=true, + module_strict=true + }) + return env +end +test_envvars.require = clean_require +test_envvars.reqscript = clean_reqscript + +local function is_title_screen() + return dfhack.gui.matchFocusString('title/Default') +end + +local function wait_for(ms, desc, predicate) + local start_ms = dfhack.getTickCount() + local prev_ms = start_ms + while not predicate() do + delay(10) + local now_ms = dfhack.getTickCount() + if now_ms - start_ms > ms then + qerror(('%s took too long (timed out at %s)'):format( + desc, dfhack.gui.getCurFocus(true)[1])) + end + if now_ms - prev_ms > 1000 then + print(('Waiting for %s...'):format(desc)) + prev_ms = now_ms + end + end +end + +-- This only handles pre-fortress-load screens. It will time out if the player +-- has already loaded a fortress or is in any screen that can't get to the title +-- screen by sending ESC keys. +local function ensure_title_screen() + if df.viewscreen_dwarfmodest:is_instance(dfhack.gui.getDFViewscreen(true)) then + qerror('Cannot reach title screen from loaded fort') + end + for i = 1, 100 do + local scr = dfhack.gui.getCurViewscreen() + if is_title_screen() then + print('Found title screen') + return + end + scr:feed_key(df.interface_key.LEAVESCREEN) + delay(10) + if i % 10 == 0 then print('Looking for title screen...') end + end + qerror(string.format('Could not find title screen (timed out at %s)', + dfhack.gui.getCurFocus(true)[1])) +end + +local function is_fortress() + return dfhack.gui.matchFocusString('dwarfmode/Default') +end + +-- error out if we're not running in a CI environment +-- the tests may corrupt saves, and we don't want to unexpectedly ruin a real player save +-- this heuristic is not perfect, but it should be able to detect most cases +local function ensure_ci_save(scr) + if #scr.savegame_header ~= 1 + or #scr.savegame_header_world ~= 1 + or not string.find(scr.savegame_header[0].fort_name, 'Dream') + then + qerror('Unexpected test save in slot 0; please manually load a fort for ' .. + 'running fortress mode tests. note that tests may alter or corrupt the ' .. + 'fort! Do not save after running tests.') + end +end + +local function click_top_title_button(scr) + local sw, sh = dfhack.screen.getWindowSize() + df.global.gps.mouse_x = sw // 2 + df.global.gps.precise_mouse_x = df.global.gps.mouse_x * df.global.gps.tile_pixel_x + if sh < 60 then + df.global.gps.mouse_y = 25 + else + df.global.gps.mouse_y = (sh // 2) + 3 + end + df.global.gps.precise_mouse_y = df.global.gps.mouse_y * df.global.gps.tile_pixel_y + gui.simulateInput(scr, '_MOUSE_L') +end + +local function load_first_save(scr) + if #scr.savegame_header == 0 then + qerror('no savegames available to load') + end + + click_top_title_button(scr) + wait_for(1000, 'world list', function() + return scr.mode == 2 + end) + click_top_title_button(scr) + wait_for(1000, 'savegame list', function() + return scr.mode == 3 + end) + click_top_title_button(scr) + wait_for(1000, 'loadgame progress bar', function() + return dfhack.gui.matchFocusString('loadgame') + end) +end + +-- Requires that a fortress game is already loaded or is ready to be loaded via +-- the "Continue active game" option in the title screen. Otherwise the function +-- will time out and/or exit with error. +local function ensure_fortress(config) + for screen_timeout = 1,10 do + if is_fortress() then + print('Fortress map is loaded') + -- pause the game (if it's not already paused) + dfhack.gui.resetDwarfmodeView(true) + return + end + local scr = dfhack.gui.getCurViewscreen() + if dfhack.gui.matchFocusString('title/Default', scr) then + print('Attempting to load the test fortress') + -- TODO: reinstate loading of a specified save dir; for now + -- just load the first possible save, which will at least let us + -- run fortress tests in CI + -- qerror()'s on falure + -- dfhack.run_script('load-save', config.save_dir) + ensure_ci_save(scr) + load_first_save(scr) + elseif not dfhack.gui.matchFocusString('loadgame', scr) then + -- if we're not actively loading a game, hope we're in + -- a screen where hitting ESC will get us to the game map + -- or the title screen + scr:feed_key(df.interface_key.LEAVESCREEN) + end + -- wait for current screen to change + local prev_focus_string = dfhack.gui.getCurFocus()[1] + wait_for(60000, 'screen change', function() + return dfhack.gui.getCurFocus()[1] ~= prev_focus_string + end) + end + qerror(string.format('Could not load fortress (timed out at %s)', + table.concat(dfhack.gui.getCurFocus(), ' '))) +end + +local MODES = { + none = {order=1, detect=function() return true end}, + title = {order=2, detect=is_title_screen, navigate=ensure_title_screen}, + fortress = {order=3, detect=is_fortress, navigate=ensure_fortress}, +} + +local function load_test_config(config_file) + local config = {} + print ("loading test config from " .. config_file) + if dfhack.filesystem.isfile(config_file) then + config = json.decode_file(config_file) + end + + if not config.test_dir then + config.test_dir = dfhack.getHackPath() .. '/scripts/test' + end + + if not config.save_dir then + config.save_dir = 'region1' + end + + return config +end + +local function TestTable() + local inner = utils.OrderedTable() + local meta = copyall(getmetatable(inner)) + + function meta:__newindex(k, v) + if inner[k] then + error('Attempt to overwrite existing test: ' .. k) + elseif type(v) ~= 'function' then + error('Attempt to define test as non-function: ' .. k .. ' = ' .. tostring(v)) + else + inner[k] = v + end + end + + local self = {} + setmetatable(self, meta) + return self +end + +-- we have to save and use the original dfhack.printerr here so our test harness +-- output doesn't trigger its own dfhack.printerr usage detection (see +-- detect_printerr below) +local orig_printerr = dfhack.printerr +local function wrap_expect(func, private, path) + return function(...) + private.checks = private.checks + 1 + local ret = {func(...)} + local ok = table.remove(ret, 1) + if ok then + private.checks_ok = private.checks_ok + 1 + return + end + local msg = '' + for _, part in pairs(ret) do + if part then + msg = msg .. ': ' .. tostring(part) + end + end + msg = msg:sub(3) -- strip leading ': ' + orig_printerr('Check failed! ' .. (msg or '(no message)')) + -- Generate a stack trace with all function calls in the same file as the caller to expect.*() + -- (this produces better stack traces when using helpers in tests) + local frame = 2 + local caller_src + while true do + info = debug.getinfo(frame) + if not info then break end + if not caller_src then + caller_src = info.short_src + end + -- Skip any frames corresponding to C calls, or Lua functions defined in another file + -- these could include pcall(), with_finalize(), etc. + if info.what == 'Lua' and (info.short_src == caller_src or info.short_src == path) then + orig_printerr((' at %s:%d'):format(info.short_src, info.currentline)) + end + frame = frame + 1 + end + print('') + end +end + +local function build_test_env(path) + local env = { + test = TestTable(), + -- config values can be overridden in the test file to define + -- requirements for the tests in that file + config = { + -- override with the required game mode + mode = 'none', + -- override with a test wrapper function with common setup and + -- teardown for every test, if needed. for example: + -- local function test_wrapper(test_fn) + -- mock.patch(dfhack.filesystem, + -- 'listdir_recursive', + -- mock.func({}), + -- test_fn) + -- end + -- config.wrapper = test_wrapper + wrapper = nil, + }, + expect = {}, + mock = mock, + delay = delay, + delay_until = delay_until, + require = clean_require, + reqscript = clean_reqscript, + } + local private = { + checks = 0, + checks_ok = 0, + } + for name, func in pairs(expect) do + env.expect[name] = wrap_expect(func, private, path) + end + setmetatable(env, {__index = _G}) + return env, private +end + +local function get_test_files(test_dir) + local files = {} + print('Loading tests from ' .. test_dir) + for _, entry in ipairs(dfhack.filesystem.listdir_recursive(test_dir)) do + if not entry.isdir then + table.insert(files, entry.path) + end + end + table.sort(files) + return files +end + +local function load_test_status() + if dfhack.filesystem.isfile(STATUS_FILE) then + return json.decode_file(STATUS_FILE) + end +end + +local function save_test_status(status) + json.encode_file(status, STATUS_FILE) +end + +local function finish_tests(done_command) + dfhack.internal.IN_TEST = false + overlay.rescan() + if done_command and #done_command > 0 then + dfhack.run_command(done_command) + end +end + +local function load_tests(file, tests) + local short_filename = file:sub((file:find('test') or -4) + 5, -1) + print('Loading file: ' .. short_filename) + local env, env_private = build_test_env(file) + local code, err = loadfile(file, 't', env) + if not code then + dfhack.printerr('Failed to load file: ' .. tostring(err)) + return false + end + dfhack.internal.IN_TEST = true + local ok, err = dfhack.pcall(code) + dfhack.internal.IN_TEST = false + if not ok then + dfhack.printerr('Error when running file: ' .. tostring(err)) + return false + end + if not MODES[env.config.mode] then + dfhack.printerr('Invalid config.mode: ' .. tostring(env.config.mode)) + return false + end + if not env.config.target then + dfhack.printerr('Skipping tests for unspecified target in ' .. file) + return true -- TODO: change to false once existing tests have targets specified + end + local targets = type(env.config.target) == 'table' and env.config.target or {env.config.target} + for _,target in ipairs(targets) do + if target == 'core' then goto continue end + if type(target) ~= 'string' or helpdb.has_tag(target, 'unavailable') then + dfhack.printerr('Skipping tests for unavailable target: ' .. target) + return true + end + ::continue:: + end + for name, test_func in pairs(env.test) do + if env.config.wrapper then + local fn = test_func + test_func = function() env.config.wrapper(fn) end + end + local test_data = { + full_name = short_filename .. ':' .. name, + func = test_func, + private = env_private, + config = env.config, + } + test_data.name = test_data.full_name:gsub('test/', ''):gsub('.lua', '') + table.insert(tests, test_data) + end + return true +end + +local function sort_tests(tests) + -- to make sort stable + local test_index = utils.invert(tests) + table.sort(tests, function(a, b) + if a.config.mode ~= b.config.mode then + return MODES[a.config.mode].order < MODES[b.config.mode].order + end + return test_index[a] < test_index[b] + end) +end + +local function wrap_test(func) + local saved_printerr = dfhack.printerr + local printerr_called = false + local printerr_wrapper = function(msg) + if msg == nil then return end + saved_printerr(msg) + printerr_called = true + end + + return mock.patch( + { + {dfhack, 'printerr', printerr_wrapper}, + {dfhack, 'run_script', clean_run_script}, + {dfhack, 'reqscript', clean_reqscript}, + }, + function() + local ok, err = dfhack.pcall(func) + if printerr_called then + return false, + "dfhack.printerr was called outside of" .. + " expect.printerr_match(). please wrap your test" .. + " with expect.printerr_match()." + end + return ok, err + end + ) +end + +local function get_elapsed_str(elapsed) + return elapsed < 1 and "<1" or tostring(elapsed) +end + +local function run_test(test, status, counts) + test.private.checks = 0 + test.private.checks_ok = 0 + counts.tests = counts.tests + 1 + dfhack.internal.IN_TEST = true + local start_ms = dfhack.getTickCount() + local ok, err = wrap_test(test.func) + local elapsed_ms = dfhack.getTickCount() - start_ms + dfhack.internal.IN_TEST = false + local passed = false + if not ok then + dfhack.printerr('error: ' .. tostring(err) .. '\n') + dfhack.printerr('test errored: ' .. test.name) + elseif test.private.checks ~= test.private.checks_ok then + dfhack.printerr('test failed: ' .. test.name) + else + local elapsed_str = get_elapsed_str(elapsed_ms) + print(('test passed in %s ms: %s'):format(elapsed_str, test.name)) + passed = true + counts.tests_ok = counts.tests_ok + 1 + end + counts.checks = counts.checks + (tonumber(test.private.checks) or 0) + counts.checks_ok = counts.checks_ok + (tonumber(test.private.checks_ok) or 0) + return passed +end + +local function get_tests(test_files, counts) + local tests = {} + for _, file in ipairs(test_files) do + if not load_tests(file, tests) then + counts.file_errors = counts.file_errors + 1 + end + end + return tests +end + +local function filter_tests(tests, config) + if config.tests or config.modes then + for _,filter in ipairs({{'tests', 'name pattern'},{'modes', 'mode'}}) do + if config[filter[1]] and #config[filter[1]] > 0 then + print(string.format('Filtering tests by %s:', filter[2])) + for _,v in ipairs(config[filter[1]]) do + print(string.format(' %s', v)) + end + end + end + local orig_length = #tests + for i = #tests, 1, -1 do + local remove = false + if config.modes then + remove = true + -- allow test if it matches any of the given modes + for _, mode in pairs(config.modes) do + if tests[i].config.mode == mode then + remove = false + break + end + end + end + if config.tests and not remove then + remove = true + -- allow test if it matches any of the given patterns + for _, pattern in pairs(config.tests) do + if tests[i].name:match(pattern) then + remove = false + break + end + end + end + if remove then table.remove(tests, i) end + end + print('Selected tests: ' .. #tests .. '/' .. orig_length) + end + + local status = {} + if config.resume then + status = load_test_status() or status + for i = #tests, 1, -1 do + local test = tests[i] + if not status[test.full_name] then + status[test.full_name] = TestStatus.PENDING + elseif status[test.full_name] ~= TestStatus.PENDING then + print(('skipping test: %s: state = %s'):format( + test.name, status[test.full_name])) + table.remove(tests, i) + end + end + end + + sort_tests(tests) + return status +end + +local function run_tests(tests, status, counts, config) + wait_for(60000, 'game load', function() + local scr = dfhack.gui.getDFViewscreen() + return not df.viewscreen_initial_prepst:is_instance(scr) + end) + print(('Running %d tests'):format(#tests)) + local start_ms = dfhack.getTickCount() + local num_skipped = 0 + for _, test in pairs(tests) do + if MODES[test.config.mode].failed then + num_skipped = num_skipped + 1 + goto skip + end + if not MODES[test.config.mode].detect() then + print(('Switching to %s mode for test: %s'):format(test.config.mode, test.name)) + local ok, err = pcall(MODES[test.config.mode].navigate, config) + if not ok then + MODES[test.config.mode].failed = true + dfhack.printerr(tostring(err)) + num_skipped = num_skipped + 1 + goto skip + end + end + -- pre-emptively mark the test as failed in case we induce a crash + status[test.full_name] = TestStatus.FAILED + save_test_status(status) + if run_test(test, status, counts) then + status[test.full_name] = TestStatus.PASSED + save_test_status(status) + end + ::skip:: + end + local elapsed_ms = dfhack.getTickCount() - start_ms + + local function print_summary_line(ok, message) + local print_fn = print + if not ok then + status['*'] = TestStatus.FAILED + print_fn = dfhack.printerr + end + print_fn(' ' .. message) + end + + status['*'] = status['*'] or TestStatus.PASSED + print(('\nTests completed in %s ms:'):format(get_elapsed_str(elapsed_ms))) + print_summary_line(counts.tests_ok == counts.tests, + ('%d/%d tests passed'):format(counts.tests_ok, counts.tests)) + print_summary_line(counts.checks_ok == counts.checks, + ('%d/%d checks passed'):format(counts.checks_ok, counts.checks)) + print_summary_line(counts.file_errors == 0, + ('%d test files failed to load'):format(counts.file_errors)) + print_summary_line(num_skipped == 0, + ('%d tests in unreachable modes'):format(num_skipped)) + + save_test_status(status) +end + +local function dump_df_state() + local state = { + enabler = { + fps = df.global.enabler.fps, + gfps = df.global.enabler.gfps, + fullscreen_state = df.global.enabler.fullscreen_state.whole, + }, + gps = { + dimx = df.global.gps.dimx, + dimy = df.global.gps.dimy, + display_frames = df.global.gps.display_frames, + }, + } + json.encode_file(state, DF_STATE_FILE) + print('DF global state: ' .. json.encode(state, {pretty = false})) +end + +local function main(args) + local help, resume, test_dir, mode_filter, save_dir, test_filter = + false, false, nil, {}, nil, {} + local other_args = utils.processArgsGetopt(args, { + {'h', 'help', handler=function() help = true end}, + {'d', 'test_dir', hasArg=true, + handler=function(arg) test_dir = arg end}, + {'m', 'modes', hasArg=true, + handler=function(arg) mode_filter = utils.split_string(arg, ',') end}, + {'r', 'resume', handler=function() resume = true end}, + {'s', 'save_dir', hasArg=true, + handler=function(arg) save_dir = arg end}, + {'t', 'tests', hasArg=true, + handler=function(arg) test_filter = utils.split_string(arg, ',') end}, + }) + + if help then print(help_text) return end + + local done_command = table.concat(other_args, ' ') + local config = load_test_config(CONFIG_FILE) + + -- override config with any params specified on the commandline + if test_dir then config.test_dir = test_dir end + if resume then config.resume = true end + if save_dir then config.save_dir = save_dir end + if #mode_filter > 0 then config.modes = mode_filter end + if #test_filter > 0 then config.tests = test_filter end + if #done_command > 0 then config.done_command = done_command end + + if not dfhack.filesystem.isdir(config.test_dir) then + qerror(('Invalid test folder: "%s"'):format(config.test_dir)) + end + + local counts = { + tests = 0, + tests_ok = 0, + checks = 0, + checks_ok = 0, + file_errors = 0, + } + + dump_df_state() + local test_files = get_test_files(config.test_dir) + local tests = get_tests(test_files, counts) + local status = filter_tests(tests, config) + + script.start(function() + dfhack.call_with_finalizer(1, true, + finish_tests, config.done_command, + run_tests, tests, status, counts, config) + end) +end + +if not dfhack_flags.module then + main({...}) +end diff --git a/ci/update-submodules.bash b/ci/update-submodules.bash new file mode 100755 index 0000000000..3cea29961c --- /dev/null +++ b/ci/update-submodules.bash @@ -0,0 +1,40 @@ +#!/bin/bash + +set -e + +message_file=.git/COMMIT_EDITMSG + +get_git_root() { + git rev-parse --show-toplevel +} + +write_msg() { + echo "$@" >> "${message_file}" +} + +git_root="$(get_git_root)" +cd "${git_root}" +rm -f "${message_file}" +write_msg "Auto-update submodules" +write_msg "" + +cat ci/update-submodules.manifest | while read path branch; do + cd "${git_root}/${path}" + test "${git_root}" != "$(get_git_root)" + git fetch origin "${branch}:${branch}" + git checkout "${branch}" + git branch --set-upstream-to="origin/${branch}" "${branch}" + git pull --ff-only + cd "${git_root}" + if ! git diff --quiet --ignore-submodules=dirty -- "${path}"; then + git add "${path}" + write_msg "${path}: ${branch}" + fi +done + +if ! git diff --exit-code --cached; then + git commit --file "${message_file}" --no-edit + exit 0 +else + exit 1 +fi diff --git a/ci/update-submodules.manifest b/ci/update-submodules.manifest new file mode 100644 index 0000000000..7d2c1412cf --- /dev/null +++ b/ci/update-submodules.manifest @@ -0,0 +1,10 @@ +library/xml master +scripts master +plugins/stonesense master +depends/clsocket master +depends/libzip dfhack +depends/libexpat dfhack +depends/xlsxio dfhack +depends/luacov dfhack +depends/jsoncpp-sub dfhack +depends/dfhooks main diff --git a/conf.py b/conf.py new file mode 100644 index 0000000000..f5dd4451a1 --- /dev/null +++ b/conf.py @@ -0,0 +1,309 @@ +# -*- coding: utf-8 -*- +""" +DFHack documentation build configuration file + +This file is execfile()d with the current directory set to its +containing dir. + +Note that not all possible configuration values are present in this +autogenerated file. + +All configuration values have a default; values that are commented out +serve to show the default. +""" + +# pylint:disable=redefined-builtin + +import datetime +import os +import re +import shlex # pylint:disable=unused-import +import sphinx +import sys + +sys.path.append(os.path.join(os.path.abspath(os.path.dirname(__file__)), 'docs', 'sphinx_extensions')) +from dfhack.util import write_file_if_changed + +if os.environ.get('DFHACK_DOCS_BUILD_OFFLINE'): + # block attempted image downloads, particularly for the PDF builder + def request_disabled(*args, **kwargs): + raise RuntimeError('Offline build - network request blocked') + + import urllib3.util + urllib3.util.create_connection = request_disabled + + import urllib3.connection + urllib3.connection.HTTPConnection.connect = request_disabled + + import requests + requests.request = request_disabled + requests.get = request_disabled + + +# -- Autodoc for DFhack plugins and scripts ------------------------------- + +def doc_dir(dirname, files, prefix): + """Yield (name, includepath) for each file in the directory.""" + sdir = os.path.relpath(dirname, '.').replace('\\', '/').replace('../', '') + if prefix == '.': + prefix = '' + else: + prefix += '/' + for f in files: + if f[-4:] != '.rst': + continue + yield prefix + f[:-4], sdir + '/' + f + + +def doc_all_dirs(): + """Collect the commands and paths to include in our docs.""" + tools = [] + for root, _, files in os.walk('docs/builtins'): + tools.extend(doc_dir(root, files, os.path.relpath(root, 'docs/builtins'))) + for root, _, files in os.walk('docs/plugins'): + tools.extend(doc_dir(root, files, os.path.relpath(root, 'docs/plugins'))) + for root, _, files in os.walk('scripts/docs'): + tools.extend(doc_dir(root, files, os.path.relpath(root, 'scripts/docs'))) + return tuple(tools) + + +def write_tool_docs(): + """ + Creates a file for each tool with the ".. include::" directives to pull in + the original documentation. + """ + for k in doc_all_dirs(): + label = ('.. _{name}:\n\n').format(name=k[0]) + include = ('.. include:: /{path}\n\n').format(path=k[1]) + os.makedirs(os.path.join('docs/tools', os.path.dirname(k[0])), + mode=0o755, exist_ok=True) + with write_file_if_changed('docs/tools/{}.rst'.format(k[0])) as outfile: + outfile.write(label) + outfile.write(include) + + +write_tool_docs() + + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +needs_sphinx = '3.4.3' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.extlinks', + 'dfhack.changelog', + 'dfhack.lexer', + 'dfhack.tool_docs', +] + +sphinx_major_version = sphinx.version_info[0] + +def get_caption_str(prefix=''): + return prefix + (sphinx_major_version >= 5 and '%s' or '') + +# This config value must be a dictionary of external sites, mapping unique +# short alias names to a base URL and a prefix. +# See http://sphinx-doc.org/ext/extlinks.html +extlinks = { + 'wiki': ('https://dwarffortresswiki.org/%s', get_caption_str()), + 'forums': ('http://www.bay12forums.com/smf/index.php?topic=%s', + get_caption_str('Bay12 forums thread ')), + 'dffd': ('https://dffd.bay12games.com/file.php?id=%s', + get_caption_str('DFFD file ')), + 'bug': ('https://dwarffortressbugtracker.com/view.php?id=%s', + get_caption_str('Bug ')), + 'source': ('https://github.com/DFHack/dfhack/tree/develop/%s', + get_caption_str()), + 'source-scripts': ('https://github.com/DFHack/scripts/tree/master/%s', + get_caption_str()), + 'issue': ('https://github.com/DFHack/dfhack/issues/%s', + get_caption_str('Issue ')), + 'commit': ('https://github.com/DFHack/dfhack/commit/%s', + get_caption_str('Commit ')), +} + +# Add any paths that contain templates here, relative to this directory. +templates_path = ["docs/templates"] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +source_suffix = ['.rst'] + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = 'DFHack' +copyright = '2015-%d, The DFHack Team' % datetime.datetime.now().year +author = 'The DFHack Team' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. + +def get_version(): + """Return the DFHack version string, from CMakeLists.txt""" + version = release = '' #pylint:disable=redefined-outer-name + pattern = re.compile(r'set\((df_version|dfhack_release)\s+"(.+?)"\)') + try: + with open('CMakeLists.txt') as f: + for s in f.readlines(): + for match in pattern.findall(s.lower()): + if match[0] == 'df_version': + version = match[1] + elif match[0] == 'dfhack_release': + release = match[1] + return (version + '-' + release).replace('")\n', '') + except IOError: + return 'unknown' + +# The short X.Y version. +# The full version, including alpha/beta/rc tags. +version = release = get_version() + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = 'en' + +# strftime format for |today| and 'Last updated on:' timestamp at page bottom +today_fmt = html_last_updated_fmt = '%Y-%m-%d' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = [ + 'README.md', + '.git/*', + 'build*', + 'depends/*', + 'docs/html/*', + 'docs/tags/*', + 'docs/text/*', + 'docs/builtins/*', + 'docs/pdf/*', + 'docs/plugins/*', + 'docs/pseudoxml/*', + 'docs/xml/*', + 'scripts/docs/*', + 'plugins/*', + ] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +default_role = 'ref' + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# The default language to highlight source code in. +highlight_language = 'dfhack' + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = False + +rst_prolog = """ +.. |sphinx_min_version| replace:: {sphinx_min_version} +.. |dfhack_version| replace:: {dfhack_version} +""".format( + sphinx_min_version=needs_sphinx, + dfhack_version=version, +) + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'alabaster' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +html_theme_options = { + 'logo': 'dfhack-logo.png', + 'github_user': 'DFHack', + 'github_repo': 'dfhack', + 'github_button': False, + 'travis_button': False, + 'fixed_sidebar': True, +} + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +html_short_title = 'DFHack Docs' + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +html_favicon = 'docs/styles/dfhack-icon.ico' + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['docs/styles'] + +# A list of paths that contain extra files not directly related to the +# documentation. +html_extra_path = ['robots.txt'] + +# Custom sidebar templates, maps document names to template names. +html_sidebars = { + '**': [ + 'about.html', + 'relations.html', + 'searchbox.html', + 'localtoc.html', + ] +} + +# generate domain indices but not the (unused) genindex +html_use_index = False +html_domain_indices = True + +# don't link to rst sources in the generated pages +html_show_sourcelink = False + +html_css_files = [ + 'dfhack.css', +] + +if sphinx_major_version >= 5: + html_css_files.append('sphinx5.css') + +# -- Options for LaTeX output --------------------------------------------- + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'DFHack.tex', 'DFHack Documentation', + 'The DFHack Team', 'manual'), +] + +latex_toplevel_sectioning = 'part' + +# -- Options for text output --------------------------------------------- + +from sphinx.writers import text + +# this value is arbitrary. it just needs to be bigger than the number of +# characters in the longest paragraph in the DFHack docs +text.MAXWIDTH = 1000000000 + +# this is the order that section headers will use the characters for underlines +# they are in the order of (subjective) text-mode readability +text_sectionchars = '=-~`+"*' diff --git a/data/CMakeLists.txt b/data/CMakeLists.txt new file mode 100644 index 0000000000..75146071b8 --- /dev/null +++ b/data/CMakeLists.txt @@ -0,0 +1,34 @@ +install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/dfhack-config/ + DESTINATION "${DFHACK_DATA_DESTINATION}/data/dfhack-config-defaults") + +install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/init/ + DESTINATION "${DFHACK_DATA_DESTINATION}/init") + +install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/base_command_counts.json + DESTINATION "${DFHACK_DATA_DESTINATION}/data") + +install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/orders/ + DESTINATION "${DFHACK_DATA_DESTINATION}/data/orders") + +install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/stockpiles/ + DESTINATION "${DFHACK_DATA_DESTINATION}/data/stockpiles") + +install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/art/ + DESTINATION "${DFHACK_DATA_DESTINATION}/data/art") + +install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/professions/ + DESTINATION "${DFHACK_DATA_DESTINATION}/data/professions") + +install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/blueprints/ + DESTINATION "${DFHACK_DATA_DESTINATION}/data/blueprints" + FILES_MATCHING PATTERN "*" + PATTERN blueprints/test EXCLUDE) + +install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/patches/ + DESTINATION ${DFHACK_DATA_DESTINATION}/patches +) + +if(BUILD_TESTS) + install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/blueprints/test/ + DESTINATION "${DFHACK_DATA_DESTINATION}/data/blueprints/test") +endif() diff --git a/data/art/border-bold.png b/data/art/border-bold.png new file mode 100644 index 0000000000..16423a3a74 Binary files /dev/null and b/data/art/border-bold.png differ diff --git a/data/art/border-medium.png b/data/art/border-medium.png new file mode 100644 index 0000000000..529a60ee43 Binary files /dev/null and b/data/art/border-medium.png differ diff --git a/data/art/border-panel.png b/data/art/border-panel.png new file mode 100644 index 0000000000..52b24b9199 Binary files /dev/null and b/data/art/border-panel.png differ diff --git a/data/art/border-thin.png b/data/art/border-thin.png new file mode 100644 index 0000000000..71fa59a3ea Binary files /dev/null and b/data/art/border-thin.png differ diff --git a/data/art/border-window.png b/data/art/border-window.png new file mode 100644 index 0000000000..34747d69b7 Binary files /dev/null and b/data/art/border-window.png differ diff --git a/data/art/control-panel.png b/data/art/control-panel.png new file mode 100644 index 0000000000..2f5e9468af Binary files /dev/null and b/data/art/control-panel.png differ diff --git a/data/art/curses-small-letters_top-left.png b/data/art/curses-small-letters_top-left.png new file mode 100644 index 0000000000..2bf2e5aff2 Binary files /dev/null and b/data/art/curses-small-letters_top-left.png differ diff --git a/data/art/damp_dig_map.png b/data/art/damp_dig_map.png new file mode 100644 index 0000000000..db82f1a1b0 Binary files /dev/null and b/data/art/damp_dig_map.png differ diff --git a/data/art/damp_dig_toolbar.png b/data/art/damp_dig_toolbar.png new file mode 100644 index 0000000000..4c2c1939e6 Binary files /dev/null and b/data/art/damp_dig_toolbar.png differ diff --git a/data/art/design.png b/data/art/design.png new file mode 100644 index 0000000000..38fed7e088 Binary files /dev/null and b/data/art/design.png differ diff --git a/data/art/design_toolbar.png b/data/art/design_toolbar.png new file mode 100644 index 0000000000..935a332f00 Binary files /dev/null and b/data/art/design_toolbar.png differ diff --git a/data/art/green-pin.png b/data/art/green-pin.png new file mode 100644 index 0000000000..25d0e696ff Binary files /dev/null and b/data/art/green-pin.png differ diff --git a/data/art/icons.png b/data/art/icons.png new file mode 100644 index 0000000000..141d9f79f4 Binary files /dev/null and b/data/art/icons.png differ diff --git a/data/art/logo.png b/data/art/logo.png new file mode 100644 index 0000000000..c34407b372 Binary files /dev/null and b/data/art/logo.png differ diff --git a/data/art/mass_remove_toolbar.png b/data/art/mass_remove_toolbar.png new file mode 100644 index 0000000000..d1b09ac93b Binary files /dev/null and b/data/art/mass_remove_toolbar.png differ diff --git a/data/art/note_green_pin_map.png b/data/art/note_green_pin_map.png new file mode 100644 index 0000000000..b692263f90 Binary files /dev/null and b/data/art/note_green_pin_map.png differ diff --git a/data/art/on-off.png b/data/art/on-off.png new file mode 100644 index 0000000000..2b731e1c6b Binary files /dev/null and b/data/art/on-off.png differ diff --git a/data/art/on-off_top-left.png b/data/art/on-off_top-left.png new file mode 100644 index 0000000000..7303ff10d4 Binary files /dev/null and b/data/art/on-off_top-left.png differ diff --git a/data/art/pathable.png b/data/art/pathable.png new file mode 100644 index 0000000000..00f7f831d1 Binary files /dev/null and b/data/art/pathable.png differ diff --git a/data/art/red-pin.png b/data/art/red-pin.png new file mode 100644 index 0000000000..763b83e97e Binary files /dev/null and b/data/art/red-pin.png differ diff --git a/data/art/sitemap_toolbar.png b/data/art/sitemap_toolbar.png new file mode 100644 index 0000000000..a29fa9b900 Binary files /dev/null and b/data/art/sitemap_toolbar.png differ diff --git a/data/art/tiletypes.png b/data/art/tiletypes.png new file mode 100644 index 0000000000..9411c7c91d Binary files /dev/null and b/data/art/tiletypes.png differ diff --git a/data/art/unsuspend.png b/data/art/unsuspend.png new file mode 100644 index 0000000000..f1d1d33da6 Binary files /dev/null and b/data/art/unsuspend.png differ diff --git a/data/base_command_counts.json b/data/base_command_counts.json new file mode 100644 index 0000000000..a05d50c1ed --- /dev/null +++ b/data/base_command_counts.json @@ -0,0 +1,145 @@ +{ + "manipulator": 75, + "autolabor": 59, + "reveal": 51, + "help": 50, + "ls": 50, + "die": 50, + "tags": 50, + "embark-assistant": 42, + "prospect": 37, + "autodump": 36, + "clean": 35, + "gui/workflow": 28, + "workflow": 28, + "exportlegends": 26, + "gui/autobutcher": 25, + "autobutcher": 25, + "digv": 24, + "fastdwarf": 22, + "autonestbox": 20, + "showmood": 19, + "gui/liquids": 18, + "liquids": 18, + "search": 18, + "gui/quickfort": 15, + "quickfort": 15, + "createitem": 14, + "stocks": 14, + "autofarm": 12, + "autochop": 12, + "tiletypes": 12, + "exterminate": 12, + "buildingplan": 12, + "quicksave": 11, + "gui/gm-editor": 11, + "cleanowned": 10, + "gui/autogems": 9, + "autogems": 9, + "stonesense": 9, + "gui/stockpiles": 8, + "stockpiles": 8, + "changevein": 8, + "gui/teleport": 7, + "teleport": 7, + "seedwatch": 6, + "automelt": 6, + "embark-tools": 6, + "cursecheck": 5, + "open-legends": 5, + "ban-cooking": 5, + "burial": 5, + "automaterial": 5, + "remove-stress": 5, + "gui/blueprint": 5, + "blueprint": 5, + "tailor": 4, + "startdwarf": 4, + "3dveins": 4, + "digcircle": 4, + "nestboxes": 3, + "deathcause": 3, + "list-agreements": 3, + "gui/room-list": 3, + "points": 3, + "region-pops": 3, + "gui/advfort": 3, + "unsuspend": 3, + "locate-ore": 3, + "changelayer": 3, + "source": 3, + "gui/gm-unit": 3, + "combine-drinks": 3, + "combine-plants": 3, + "deteriorate": 3, + "warn-starving": 3, + "gaydar": 2, + "gui/dfstatus": 2, + "gui/rename": 2, + "rename": 2, + "fix-ster": 2, + "job-material": 2, + "stockflow": 2, + "drain-aquifer": 2, + "full-heal": 2, + "spawnunit": 2, + "flashstep": 2, + "gui/family-affairs": 2, + "caravan": 2, + "mousequery": 2, + "tweak": 2, + "confirm": 2, + "autoclothing": 1, + "autounsuspend": 1, + "prioritize": 1, + "dwarfmonitor": 1, + "show-unit-syndromes": 1, + "troubleshoot-item": 1, + "gui/mechanisms": 1, + "gui/pathable": 1, + "hotkeys": 1, + "infinite-sky": 1, + "force": 1, + "hermit": 1, + "strangemood": 1, + "weather": 1, + "add-recipe": 1, + "autotrade": 1, + "zone": 1, + "autonick": 1, + "stripcaged": 1, + "unforbid": 1, + "workorder": 1, + "gui/mod-manager": 1, + "spotclean": 1, + "plant": 1, + "regrass": 1, + "dig-now": 1, + "build-now": 1, + "clear-webs": 1, + "gui/siege-engine": 1, + "assign-skills": 1, + "brainwash": 1, + "elevate-mental": 1, + "elevate-physical": 1, + "launch": 1, + "linger": 1, + "make-legendary": 1, + "rejuvenate": 1, + "resurrect-adv": 1, + "questport": 1, + "getplants": 1, + "gui/stamper": 1, + "tweak": 1, + "fixveins": 1, + "deramp": 1, + "fix/dead-units": 1, + "fix/fat-dwarves": 1, + "fix/loyaltycascade": 1, + "fix/retrieve-units": 1, + "tweak": 1, + "sort-items": 1, + "gui/color-schemes": 1, + "color-schemes": 1, + "season-palette": 1 +} diff --git a/data/blueprints/aquifer_tap.csv b/data/blueprints/aquifer_tap.csv new file mode 100644 index 0000000000..dc79e523d4 --- /dev/null +++ b/data/blueprints/aquifer_tap.csv @@ -0,0 +1,73 @@ +#notes label(help) +"This blueprint will help you get a safe, everlasting source of fresh water from a light aquifer. See https://youtu.be/hF3_fjLc_EU for a video tutorial." +"" +Here's the procedure: +"" +"1) Locate an area with a light aquifer. DFHack gives light aquifer tiles a two-drop icon that appears when you are in mining mode. If you dug through it on the way down, take note of the elevations where it's likely to be (but be aware that there is regional variation and there's no guarantee that it exists on the map where you want it to be). If you are having trouble finding the boundaries of your aquifer, you can run prospect all --show features to discover the general elevations or gui/reveal -o to see the actual tiles." +"" +2) Dig a one-tile-wide tunnel from where you want the water to end up (e.g. your well cistern) to an area on the same z-level directly below the target light aquifer. Dig a one-tile-wide diagonal segment in this tunnel near the cistern side so water that will eventually flow through the tunnel is depressurized. +"" +"3) Pause the game. From the end of that tunnel, go down one z-level then designate for digging a staircase straight up so that the top is in the lowest aquifer level (a tile with a two-drop icon). Your original tunnel should connect to the staircase one z-level above the bottom of the staircase." +"" +"4) Apply this blueprint (gui/quickfort aquifer_tap /dig) to the z-level at the top of the staircase. The tiles will be designated in ""damp dig"" mode so your miners can dig it out without the damp tiles canceling the digging designations. This blueprint also changes the staircase tile below the tap to a vanilla ""blueprint"" tile (shaded in blue) so your miners don't dig the tap before your drainage tunnel is ready." +"" +"5) You can now unpause the game. From the bottom of the staircase (the z-level below where the water will flow to your cisterns), dig a straight, one-tile wide tunnel to the closest edge of the map. This is your emergency drainage tunnel. Smooth the map edge tile and carve a fortification. The water can flow through the fortification and off the map, allowing the dwarves to dig out the aquifer tap without drowning." +"" +6) Place a lever-controlled floodgate in the drainage tunnel and open the floodgate. Place the lever somewhere else in your fort so that it will remain dry and accessible. +"" +"7) If you want, haul away any boulders in the tunnels and/or smooth the tiles (e.g. mark them for dumping -- hotkey i-p -- and wait for them to be dumped). Enable prioritize in gui/control-panel to focus dwarves on dumping tasks and make it go faster. You won't be able to access any of this area once it fills up with water!" +"" +"8) Convert the ""blueprint"" stairway tile to a regular up/down stair dig designation to allow your miners to dig out the tap. You can haul away any boulders if you like. There is no rush. The water will safely flow down the staircase, through the open floodgate, down the drainage tunnel, and off the map as long as the floodgate is open." +"8b) Sometimes, DF gets into a bad state with mining designations and miners will refuse to dig the stairway tile. If this happens to you, enter mining mode, enable the keyboard cursor if it's not already enabled (hotkey: Alt-k), highlight the undug stair designation, and run dig-now here in gui/launcher. You might also have to do this for the down stair designation in the center of the aquifer tap. Your miners should be able to handle the rest without assistance." + +"9) Once everything is dug out and all dwarves are out of the waterways, close the floodgate. Your cisterns will fill with water. Since the waterway to your cisterns is depressurized (due to the diagonal tunnel you dug), the cisterns will stay forever full, but will not flood." +"" +A diagram might be useful. Here is a vertical view through the z-levels. This blueprint goes at the top: +"" +"j <- down stairs, center of this blueprint" +"i <- up/down stairs, initially in ""blueprint mode"" to prevent digging before drainage is ready" +"... <- up/down stairs, make this as tall as you need" +i +i <- cistern outlet level with diagonal tunnel to depressurize +"u <- up stairs, drainage level" +"" +"Good luck! If done right, this method is the safest way to supply your fort with clean water." +#dig label(dig) start(10 10 center of tap) light aquifer water collector +,,,,,,,,,,,,,,,,,, +,,,,,,,,mdd3,mdd3,mdd3,,,,,,,, +,,,,,,mdd3,mdd3,mdd3,,mdd3,mdd3,mdd3,,,,,, +,,,,mdd3,,mdd3,mdd3,mdd3,,mdd3,mdd3,mdd3,,mdd3,,,, +,,,mdd3,mdd3,mdd3,mdd3,,mdd3,mdd3,mdd3,,mdd3,mdd3,mdd3,mdd3,,, +,,mdd3,,,mdd3,mdd3,,mdd3,mdd3,mdd3,,mdd3,mdd3,,,mdd3,, +,,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,, +,,,mdd3,mdd3,,,mdd3,mdd3,,mdd3,mdd3,,,mdd3,mdd3,,, +,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3, +,mdd3,mdd3,,,mdd3,mdd3,,,mdj3,,,mdd3,mdd3,,,mdd3,mdd3, +,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3, +,,,mdd3,mdd3,,,mdd3,mdd3,,mdd3,mdd3,,,mdd3,mdd3,,, +,,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,, +,,mdd3,,,mdd3,mdd3,,mdd3,mdd3,mdd3,,mdd3,mdd3,,,mdd3,, +,,,mdd3,mdd3,mdd3,mdd3,,mdd3,mdd3,mdd3,,mdd3,mdd3,mdd3,mdd3,,, +,,,,mdd3,,mdd3,mdd3,mdd3,,mdd3,mdd3,mdd3,,mdd3,,,, +,,,,,,mdd3,mdd3,mdd3,,mdd3,mdd3,mdd3,,,,,, +,,,,,,,,mdd3,mdd3,mdd3,,,,,,,, +,,,,,,,,,,,,,,,,,, +#>,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,, +,,,,,,,,`,`,`,,,,,,,, +,,,,,,`,`,`,,`,`,`,,,,,, +,,,,`,,`,`,`,,`,`,`,,`,,,, +,,,`,`,`,`,,`,`,`,,`,`,`,`,,, +,,`,,,`,`,,`,`,`,,`,`,,,`,, +,,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,, +,,,`,`,,,`,`,,`,`,,,`,`,,, +,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`, +,`,`,,,`,`,,,mbmdi3,,,`,`,,,`,`, +,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`, +,,,`,`,,,`,`,,`,`,,,`,`,,, +,,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,, +,,`,,,`,`,,`,`,`,,`,`,,,`,, +,,,`,`,`,`,,`,`,`,,`,`,`,`,,, +,,,,`,,`,`,`,,`,`,`,,`,,,, +,,,,,,`,`,`,,`,`,`,,,,,, +,,,,,,,,`,`,`,,,,,,,, diff --git a/data/blueprints/bedrooms/28-3-Modified_Windmill_Villas.csv b/data/blueprints/bedrooms/28-3-Modified_Windmill_Villas.csv new file mode 100644 index 0000000000..af15f0cc4f --- /dev/null +++ b/data/blueprints/bedrooms/28-3-Modified_Windmill_Villas.csv @@ -0,0 +1,74 @@ +"#dig label(dig) start(12; 12) 28 bedrooms, 3 tiles each" + +,,,,,,,d,,,,,,d +,,,,,,,d,,,,,,d +,,,,,d,,d,,d,,d,,d,,d +,,,,,d,,d,,d,,d,,d,,d +,,,,,d,d,d,d,d,,d,d,d,,d,,d,d,d +,,,,,,,d,,,,,,d,d,,,d +,,,d,d,d,,d,,d,d,d,,d,d,d,d,d,d,d,d,d +,,,,,,d,d,,,,d,,d,,,,d +,d,d,d,d,d,d,d,d,d,d,d,d,d,,d,,d,d,d +,,,,,d,,,,d,~,~,~,d,,d +,,,d,d,d,,d,d,d,~,~,~,d,d,d,,d,d,d +,,,,,,,d,,d,~,~,~,d,,,,d +,,,d,d,d,,d,,d,d,d,d,d,d,d,d,d,d,d,d,d +,,,,,d,,,,d,,d,,,,d,d +,d,d,d,d,d,d,d,d,d,,d,d,d,,d,,d,d,d +,,,,,d,,,d,d,,,,,,d +,,,d,d,d,,d,,d,d,d,,d,d,d,d,d +,,,,,,,d,,d,,d,,d,,d,,d +,,,,,,,d,,d,,d,,d,,d,,d +,,,,,,,,,d,,,,,,d +,,,,,,,,,d,,,,,,d + +#meta label(rooms) +zone/zone +build/build +#zone label(zone) start(12; 12) hidden() +,,,,,,b(3x5),,,,,,b(3x5) +,,,,,,,`,,,,,,` +,,,,b(3x5),,,`,b(3x5),,b(3x5),,,`,b(3x5) +,,,,,`,,`,,`,,`,,`,,` +,,,,,`,,`,,`,,`,,`,,`,b(5x3) +,,,,,`,`,`,`,`,,`,`,`,,`,,`,`,` +,,b(5x3),,,,,`,b(5x3),,,,,`,`,,,`,b(5x3) +,,,`,`,`,,`,,`,`,`,,`,`,`,`,`,`,`,`,` +b(5x3),,,,,,`,`,,,,`,,`,b(3x5),,b(5x3),` +,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,` +,,b(5x3),,,`,b(3x5),,,`,`,`,`,`,,`,b(5x3) +,,,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,` +,,b(5x3),,,,,`,,`,`,`,`,`,,,,`,b(5x3) +,,,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,` +b(5x3),,,,,`,,,,`,b(5x3),`,,,,`,b(5x3) +,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,` +,,b(5x3),,,`,b(3x5),,`,`,b(3x5),,b(3x5),,,`,b(3x5) +,,,`,`,`,,`,,`,`,`,,`,`,`,`,` +,,,,,,,`,b(3x5),`,,`,,`,b(3x5),`,,` +,,,,,,,`,,`,,`,,`,,`,,` +,,,,,,,,,`,,,,,,` +,,,,,,,,,`,,,,,,` + +#build label(build) start(12; 12) hidden() + +,,,,,,,f,,,,,,f +,,,,,,,h,,,,,,h +,,,,,f,,b,,f,,f,,b,,f +,,,,,h,,d,,h,,h,,d,,h +,,,,,b,d,`,d,b,,b,d,`,,b,,b,h,f +,,,,,,,`,,,,,,`,d,,,d +,,,f,h,b,,`,,f,h,b,,`,`,`,`,`,d,b,h,f +,,,,,,d,`,,,,d,,`,,,,d +,f,h,b,d,`,`,`,`,`,`,`,`,`,,f,,b,h,f +,,,,,d,,,,`,`,`,`,`,,h +,,,f,h,b,,b,d,`,`,`,`,`,d,b,,b,h,f +,,,,,,,h,,`,`,`,`,`,,,,d +,,,f,h,b,,f,,`,`,`,`,`,`,`,`,`,d,b,h,f +,,,,,d,,,,`,,d,,,,`,d +,f,h,b,d,`,`,`,`,`,,b,h,f,,`,,b,h,f +,,,,,d,,,d,`,,,,,,` +,,,f,h,b,,b,,`,d,b,,b,d,`,d,b +,,,,,,,h,,d,,h,,h,,d,,h +,,,,,,,f,,b,,f,,f,,b,,f +,,,,,,,,,h,,,,,,h +,,,,,,,,,f,,,,,,f diff --git a/data/blueprints/bedrooms/48-4-Raynard_Whirlpool_Housing.csv b/data/blueprints/bedrooms/48-4-Raynard_Whirlpool_Housing.csv new file mode 100644 index 0000000000..ae7d83f6ec --- /dev/null +++ b/data/blueprints/bedrooms/48-4-Raynard_Whirlpool_Housing.csv @@ -0,0 +1,209 @@ +"#dig label(dig) start(17; 17) 48 rooms, 4 tiles each" + +,,,,,,,,,,,,,,d,,,,d +,,,,,d,,,,d,,,,d,d,d,d,d,d,d,,,,d,,,,d +,,,,d,d,d,d,d,d,d,,,,d,,d,,d,,,,d,d,d,d,d,d,d +,,d,,,d,,d,,d,,,d,,,,d,,,,d,,,d,,d,,d,,,d +,d,d,d,,,,d,,,,d,d,d,,d,d,d,,d,d,d,,,,d,,,,d,d,d +,,d,,,d,d,d,d,d,,,d,,,d,d,d,,,d,,,d,d,d,d,d,,,d +,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,d,,,d,d,d,d,d,,,d,,,d,d,d,,,d,,,d,d,d,d,d,,,d +,d,d,d,,,,d,,,,d,d,d,,d,d,d,,d,d,d,,,,d,,,,d,d,d +,,d,,,d,,d,,d,,,d,,,,d,,,,d,,,d,,d,,d,,,d +,,,,d,d,d,d,d,d,d,,,,d,,d,,d,,,,d,d,d,d,d,d,d +,,,,,d,,d,,d,,,,d,d,d,d,d,d,d,,,,d,,d,,d +,,,d,,,,d,,,,d,,,d,,d,,d,,,d,,,,d,,,,d +,,d,d,d,,d,d,d,,d,d,d,,,,d,,,,d,d,d,,d,d,d,,d,d,d +,,,d,,,d,d,d,,,d,,,d,~,~,~,d,,,d,,,d,d,d,,,d +,,,d,d,d,d,d,d,d,d,d,d,d,d,~,~,~,d,d,d,d,d,d,d,d,d,d,d,d +,,,d,,,d,d,d,,,d,,,d,~,~,~,d,,,d,,,d,d,d,,,d +,,d,d,d,,d,d,d,,d,d,d,,,,d,,,,d,d,d,,d,d,d,,d,d,d +,,,d,,,,d,,,,d,,,d,,d,,d,,,d,,,,d,,,,d +,,,,,d,,d,,d,,,,d,d,d,d,d,d,d,,,,d,,d,,d +,,,,d,d,d,d,d,d,d,,,,d,,d,,d,,,,d,d,d,d,d,d,d +,,d,,,d,,d,,d,,,d,,,,d,,,,d,,,d,,d,,d,,,d +,d,d,d,,,,d,,,,d,d,d,,d,d,d,,d,d,d,,,,d,,,,d,d,d +,,d,,,d,d,d,d,d,,,d,,,d,d,d,,,d,,,d,d,d,d,d,,,d +,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,d,,,d,d,d,d,d,,,d,,,d,d,d,,,d,,,d,d,d,d,d,,,d +,d,d,d,,,,d,,,,d,d,d,,d,d,d,,d,d,d,,,,d,,,,d,d,d +,,d,,,d,,d,,d,,,d,,,,d,,,,d,,,d,,d,,d,,,d +,,,,d,d,d,d,d,d,d,,,,d,,d,,d,,,,d,d,d,d,d,d,d +,,,,,d,,,,d,,,,d,d,d,d,d,d,d,,,,d,,,,d +,,,,,,,,,,,,,,d,,,,d + +#meta label(rooms) +zone1/zone1 +zone2/zone2 +zone3/zone3 +zone4/zone4 +build/build +#zone label(zone1) start(17; 17) hidden() + +,,,,,,,,,,,,,,`,,,,` +,,,,,`,,,,`,,,,`,,`,,`,,`,,,,`,,,,` +,b,b,b,`,,`,,`,,`,b,b,b,`,,,,`,b,b,b,`,,`,,`,,`,b,b,b +b,b,b,b,b,`,,,,`,b,b,b,b,b,,,,b,b,b,b,b,`,,,,`,b,b,b,b,b +b,b,b,b,b,,,,,,b,b,b,b,b,,,,b,b,b,b,b,,,,,,b,b,b,b,b +b,b,b,b,b,,,,,,b,b,b,b,b,,,,b,b,b,b,b,,,,,,b,b,b,b,b +,,,,,,,`,,,,,,,,,`,,,,,,,,,` +,,`,,,,,,,,,,`,,,,,,,,`,,,,,,,,,,` +,`,,`,,,,,,,,`,,`,,,,,,`,,`,,,,,,,,`,,` +,,`,,,`,,,,`,,,`,,,,,,,,`,,,`,,,,`,,,` +,,,,`,,`,,`,,`,,,,`,,,,`,,,,`,,`,,`,,` +,,b,b,b,`,,,,`,b,b,b,`,,`,,`,,`,b,b,b,`,,,,`,b,b,b +,b,b,b,b,b,,,,b,b,b,b,b,`,,,,`,b,b,b,b,b,,,,b,b,b,b,b +,b,b,b,b,b,,,,b,b,b,b,b,,,,,,b,b,b,b,b,,,,b,b,b,b,b +,b,b,b,b,b,,,,b,b,b,b,b,,,,,,b,b,b,b,b,,,,b,b,b,b,b +,,,,,,,`,,,,,,,,,,,,,,,,,,` +,,,`,,,,,,,,`,,,,,,,,,,`,,,,,,,,` +,,`,,`,,,,,,`,,`,,,,,,,,`,,`,,,,,,`,,` +,,,`,,,,,,,,`,,,`,,,,`,,,`,,,,,,,,` +,,,,,`,,,,`,,,,`,,`,,`,,`,,,,`,,,,` +,b,b,b,`,,`,,`,,`,b,b,b,`,,,,`,b,b,b,`,,`,,`,,`,b,b,b +b,b,b,b,b,`,,,,`,b,b,b,b,b,,,,b,b,b,b,b,`,,,,`,b,b,b,b,b +b,b,b,b,b,,,,,,b,b,b,b,b,,,,b,b,b,b,b,,,,,,b,b,b,b,b +b,b,b,b,b,,,,,,b,b,b,b,b,,,,b,b,b,b,b,,,,,,b,b,b,b,b +,,,,,,,`,,,,,,,,,`,,,,,,,,,` +,,`,,,,,,,,,,`,,,,,,,,`,,,,,,,,,,` +,`,,`,,,,,,,,`,,`,,,,,,`,,`,,,,,,,,`,,` +,,`,,,`,,,,`,,,`,,,,,,,,`,,,`,,,,`,,,` +,,,,`,,`,,`,,`,,,,`,,,,`,,,,`,,`,,`,,` +,,,,,`,,,,`,,,,`,,`,,`,,`,,,,`,,,,` +,,,,,,,,,,,,,,`,,,,` + +#zone label(zone2) start(17; 17) hidden() +,,,,,,,,,,,,,b,b,b +,,,,b,b,b,,,,,,b,b,b,b,,,`,,,,b,b,b +,,,b,b,b,b,,,`,,,b,b,b,b,,`,,`,,b,b,b,b,,,` +,~,~,b,b,b,b,,`,,`,~,b,b,b,b,,,`,~,~,b,b,b,b,,`,,`,~,~,~ +~,~,~,b,b,b,b,,,`,~,~,~,b,b,b,,,~,~,~,b,b,b,b,,,`,~,~,~,~,~ +~,~,~,~,b,b,b,,,,~,~,~,~,~,,,,~,~,~,~,b,b,b,,,,~,~,~,~,~ +~,~,~,~,~,,,,,,~,~,~,~,~,,,,~,~,~,~,~,,,,,,~,~,~,~,~ +,~,~,~,,,,`,,,,~,~,~,,,`,,,~,~,~,,,,`,,,,~,~,~ +,,`,,,,,,,,,,`,,,,,,,,`,,,,,,,,,,` +,`,,`,b,b,b,,,,,`,,`,,,,,,`,,`,b,b,b,,,,,`,,` +,,`,b,b,b,b,,,`,,,`,b,b,b,,,,,`,b,b,b,b,,,`,,,` +,,,b,b,b,b,,`,,`,,b,b,b,b,,,`,,,b,b,b,b,,`,,` +,,~,b,b,b,b,,,`,~,~,b,b,b,b,,`,,`,~,b,b,b,b,,,`,~,~,~ +,~,~,~,b,b,b,,,~,~,~,b,b,b,b,,,`,~,~,~,b,b,b,,,~,~,~,~,~ +,~,~,~,~,~,,,,~,~,~,~,b,b,b,,,,~,~,~,~,~,,,,~,~,~,~,~ +,~,~,~,~,~,,,,~,~,~,~,~,,,,,,~,~,~,~,~,,,,~,~,~,~,~ +,,~,~,~,,,`,,,~,~,~,,,,,,,,~,~,~,,,`,,,~,~,~ +,,,`,,,,,,,,`,,,,,,,,,,`,,,,,,,,` +,,`,,`,,,,,,`,,`,b,b,b,,,,,`,,`,,,,,,`,,` +,,,`,b,b,b,,,,,`,b,b,b,b,,,`,,,`,b,b,b,,,,,` +,,,b,b,b,b,,,`,,,b,b,b,b,,`,,`,,b,b,b,b,,,` +,~,~,b,b,b,b,,`,,`,~,b,b,b,b,,,`,~,~,b,b,b,b,,`,,`,~,~,~ +~,~,~,b,b,b,b,,,`,~,~,~,b,b,b,,,~,~,~,b,b,b,b,,,`,~,~,~,~,~ +~,~,~,~,b,b,b,,,,~,~,~,~,~,,,,~,~,~,~,b,b,b,,,,~,~,~,~,~ +~,~,~,~,~,,,,,,~,~,~,~,~,,,,~,~,~,~,~,,,,,,~,~,~,~,~ +,~,~,~,,,,`,,,,~,~,~,,,`,,,~,~,~,,,,`,,,,~,~,~ +,,`,,,,,,,,,,`,,,,,,,,`,,,,,,,,,,` +,`,,`,b,b,b,,,,,`,,`,,,,,,`,,`,b,b,b,,,,,`,,` +,,`,b,b,b,b,,,`,,,`,b,b,b,,,,,`,b,b,b,b,,,`,,,` +,,,b,b,b,b,,`,,`,,b,b,b,b,,,`,,,b,b,b,b,,`,,` +,,,b,b,b,b,,,`,,,b,b,b,b,,`,,`,,b,b,b,b,,,` +,,,,b,b,b,,,,,,b,b,b,b,,,`,,,,b,b,b +,,,,,,,,,,,,,b,b,b +#zone label(zone3) start(17; 17) hidden() +,,,,,,,,,,,,,~,~,~ +,,,,~,~,~,,,,,,~,~,~,~,~,,`,,,,~,~,~ +,,,~,~,~,~,~,,`,,,~,~,~,~,~,`,,`,,~,~,~,~,~,,` +,~,~,~,~,~,~,~,`,,`,~,~,~,~,~,~,,`,~,~,~,~,~,~,~,`,,`,~,~,~ +~,~,~,~,~,~,~,~,,`,~,~,~,~,~,~,,,~,~,~,~,~,~,~,~,,`,~,~,~,~,~ +~,~,~,~,~,~,~,,,,~,~,~,~,~,,,,~,~,~,~,~,~,~,,,,~,~,~,~,~ +~,~,~,~,~,,,,,,~,~,~,~,~,,,,~,~,~,~,~,,,,,,~,~,~,~,~ +,,,,,,,`,,,,,,,,,`,,,,,,,,,` +b,b,b,b,b,,,,,,b,b,b,b,b,,,,b,b,b,b,b,,,,,,b,b,b,b,b +b,b,b,b,b,~,~,,,,b,b,b,b,b,,,,b,b,b,b,b,~,~,,,,b,b,b,b,b +b,b,b,b,b,~,~,~,,`,b,b,b,b,b,~,,,b,b,b,b,b,~,~,~,,`,b,b,b,b,b +,b,b,b,~,~,~,~,`,,`,b,b,b,~,~,~,,`,b,b,b,~,~,~,~,`,,`,b,b,b +,,~,~,~,~,~,~,,`,~,~,~,~,~,~,~,`,,`,~,~,~,~,~,~,,`,~,~,~ +,~,~,~,~,~,~,,,~,~,~,~,~,~,~,~,,`,~,~,~,~,~,~,,,~,~,~,~,~ +,~,~,~,~,~,,,,~,~,~,~,~,~,~,,,,~,~,~,~,~,,,,~,~,~,~,~ +,~,~,~,~,~,,,,~,~,~,~,~,,,,,,~,~,~,~,~,,,,~,~,~,~,~ +,,,,,,,`,,,,,,,,,,,,,,,,,,` +,b,b,b,b,b,,,,b,b,b,b,b,,,,,,b,b,b,b,b,,,,b,b,b,b,b +,b,b,b,b,b,,,,b,b,b,b,b,~,~,,,,b,b,b,b,b,,,,b,b,b,b,b +,b,b,b,b,b,~,,,b,b,b,b,b,~,~,~,,`,b,b,b,b,b,~,,,b,b,b,b,b +,,b,b,b,~,~,~,,`,b,b,b,~,~,~,~,`,,`,b,b,b,~,~,~,,`,b,b,b +,~,~,~,~,~,~,~,`,,`,~,~,~,~,~,~,,`,~,~,~,~,~,~,~,`,,`,~,~,~ +~,~,~,~,~,~,~,~,,`,~,~,~,~,~,~,,,~,~,~,~,~,~,~,~,,`,~,~,~,~,~ +~,~,~,~,~,~,~,,,,~,~,~,~,~,,,,~,~,~,~,~,~,~,,,,~,~,~,~,~ +~,~,~,~,~,,,,,,~,~,~,~,~,,,,~,~,~,~,~,,,,,,~,~,~,~,~ +,,,,,,,`,,,,,,,,,`,,,,,,,,,` +b,b,b,b,b,,,,,,b,b,b,b,b,,,,b,b,b,b,b,,,,,,b,b,b,b,b +b,b,b,b,b,~,~,,,,b,b,b,b,b,,,,b,b,b,b,b,~,~,,,,b,b,b,b,b +b,b,b,b,b,~,~,~,,`,b,b,b,b,b,~,,,b,b,b,b,b,~,~,~,,`,b,b,b,b,b +,b,b,b,~,~,~,~,`,,`,b,b,b,~,~,~,,`,b,b,b,~,~,~,~,`,,`,b,b,b +,,,~,~,~,~,~,,`,,,~,~,~,~,~,`,,`,,~,~,~,~,~,,` +,,,,~,~,~,,,,,,~,~,~,~,~,,`,,,,~,~,~ +,,,,,,,,,,,,,~,~,~ +#zone label(zone4) start(17; 17) hidden() +,,,,,,,,,,,,,~,~,~,,b,b,b +,,,,~,~,~,,b,b,b,,~,~,~,~,,b,b,b,b,,~,~,~,,b,b,b +,,,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,b +,~,~,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,b,~,~ +~,~,~,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,~,~,~,~,~,,b,b,b,b,~,~,~ +~,~,~,~,~,~,~,,b,b,b,~,~,~,~,,,,~,~,~,~,~,~,~,,b,b,b,~,~,~,~ +~,~,~,~,~,,,,,,~,~,~,~,~,,,,~,~,~,~,~,,,,,,~,~,~,~,~ +,~,~,~,,,,`,,,,~,~,~,,,`,,,~,~,~,,,,`,,,,~,~,~ +~,~,~,~,~,,,,,,~,~,~,~,~,,,,~,~,~,~,~,,,,,,~,~,~,~,~ +~,~,~,~,~,~,~,,b,b,b,~,~,~,~,,,,~,~,~,~,~,~,~,,b,b,b,~,~,~,~ +~,~,~,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,~,~,~,~,~,,b,b,b,b,~,~,~ +,~,~,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,b,~,~ +,,~,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,b,~ +,~,~,~,~,~,~,,b,b,b,~,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,~,~,~ +,~,~,~,~,~,,,,~,~,~,~,~,~,~,,b,b,b,~,~,~,~,,,,~,~,~,~,~ +,~,~,~,~,~,,,,~,~,~,~,~,,,,,,~,~,~,~,~,,,,~,~,~,~,~ +,,~,~,~,,,`,,,~,~,~,,,,,,,,~,~,~,,,`,,,~,~,~ +,~,~,~,~,~,,,,~,~,~,~,~,,,,,,~,~,~,~,~,,,,~,~,~,~,~ +,~,~,~,~,~,,,,~,~,~,~,~,~,~,,b,b,b,~,~,~,~,,,,~,~,~,~,~ +,~,~,~,~,~,~,,b,b,b,~,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,~,~,~ +,,~,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,b,~ +,~,~,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,b,~,~ +~,~,~,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,~,~,~,~,~,,b,b,b,b,~,~,~ +~,~,~,~,~,~,~,,b,b,b,~,~,~,~,,,,~,~,~,~,~,~,~,,b,b,b,~,~,~,~ +~,~,~,~,~,,,,,,~,~,~,~,~,,,,~,~,~,~,~,,,,,,~,~,~,~,~ +,~,~,~,,,,`,,,,~,~,~,,,`,,,~,~,~,,,,`,,,,~,~,~ +~,~,~,~,~,,,,,,~,~,~,~,~,,,,~,~,~,~,~,,,,,,~,~,~,~,~ +~,~,~,~,~,~,~,,b,b,b,~,~,~,~,,,,~,~,~,~,~,~,~,,b,b,b,~,~,~,~ +~,~,~,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,~,~,~,~,~,,b,b,b,b,~,~,~ +,~,~,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,b,~,~ +,,,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,b +,,,,~,~,~,,b,b,b,,~,~,~,~,,b,b,b,b,,~,~,~,,b,b,b +,,,,,,,,,,,,,~,~,~,,b,b,b +#build label(build) start(17; 17) hidden() + +,,,,,,,,,,,,,,f,,,,f +,,,,,h,,,,h,,,,b,,d,,d,,b,,,,h,,,,h +,,,,b,,d,,d,,b,,,,h,,,,h,,,,b,,d,,d,,b +,,b,,,f,,,,f,,,b,,,,,,,,b,,,f,,,,f,,,b +,f,,h,,,,,,,,h,,f,,,,,,f,,h,,,,,,,,h,,f +,,d,,,,,,,,,,d,,,,,,,,d,,,,,,,,,,d +,,,,,,,s,,,,,,,,,s,,,,,,,,,s +,,d,,,,,,,,,,d,,,,,,,,d,,,,,,,,,,d +,f,,h,,,,,,,,h,,f,,,,,,f,,h,,,,,,,,h,,f +,,b,,,f,,,,f,,,b,,,,,,,,b,,,f,,,,f,,,b +,,,,b,,d,,d,,b,,,,h,,,,h,,,,b,,d,,d,,b +,,,,,h,,,,h,,,,b,,d,,d,,b,,,,h,,,,h +,,,b,,,,,,,,b,,,f,,,,f,,,b,,,,,,,,b +,,h,,f,,,,,,f,,h,,,,,,,,h,,f,,,,,,f,,h +,,,d,,,,,,,,d,,,,,,,,,,d,,,,,,,,d +,,,,,,,s,,,,,,,,,,,,,,,,,,s +,,,d,,,,,,,,d,,,,,,,,,,d,,,,,,,,d +,,h,,f,,,,,,f,,h,,,,,,,,h,,f,,,,,,f,,h +,,,b,,,,,,,,b,,,f,,,,f,,,b,,,,,,,,b +,,,,,h,,,,h,,,,b,,d,,d,,b,,,,h,,,,h +,,,,b,,d,,d,,b,,,,h,,,,h,,,,b,,d,,d,,b +,,b,,,f,,,,f,,,b,,,,,,,,b,,,f,,,,f,,,b +,f,,h,,,,,,,,h,,f,,,,,,f,,h,,,,,,,,h,,f +,,d,,,,,,,,,,d,,,,,,,,d,,,,,,,,,,d +,,,,,,,s,,,,,,,,,s,,,,,,,,,s +,,d,,,,,,,,,,d,,,,,,,,d,,,,,,,,,,d +,f,,h,,,,,,,,h,,f,,,,,,f,,h,,,,,,,,h,,f +,,b,,,f,,,,f,,,b,,,,,,,,b,,,f,,,,f,,,b +,,,,b,,d,,d,,b,,,,h,,,,h,,,,b,,d,,d,,b +,,,,,h,,,,h,,,,b,,d,,d,,b,,,,h,,,,h +,,,,,,,,,,,,,,f,,,,f diff --git a/data/blueprints/bedrooms/95-9-Hactar1_3_Branch_Tree.csv b/data/blueprints/bedrooms/95-9-Hactar1_3_Branch_Tree.csv new file mode 100644 index 0000000000..78543b1e04 --- /dev/null +++ b/data/blueprints/bedrooms/95-9-Hactar1_3_Branch_Tree.csv @@ -0,0 +1,228 @@ +"#dig label(dig) start(36;73) 95 bedrooms (including 14 suites), 190 tombs" + +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,d +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d,d,d,d,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,d +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,,d,,,d,,,d,,,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,,d,,,d,,,d,,,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,,,,,,d,,,,,,,d,,,,,,,d +,,,,,,,,,,,,,,,,,,,,d,d,d,,d,d,d,,d,,d,d,d,d,,d,,d,d,d,d,,d,,d,d,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,d,d,d,,d,d,d,d,d,d,d,d,d,d,,d,,d,d,d,d,d,d,d,d,d,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,d,d,d,,d,d,d,,d,,d,d,d,d,,d,,d,d,d,d,,d,,d,d,d,,d,d,d +,,,,,,,,,,,,,,,,d,d,d,,,d,,,,,,,d,,,,,,,d,,,,,,,d,,,,,,,d,,,d,d,d +,,,,,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,,,,,,,,,,,,,,,d,d,d,,,d,,,,,,,d,,,,,,d,d,d,,,,,,d,,,,,,,d,,,d,d,d +,,,,,,,,,,,,,,,,,,,,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,d,d,d,,d,d,d,d,d,d,d,d,d,,d,d,d,,d,d,d,d,d,d,d,d,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,,,,,,d,,,,,,d,d,d,,,,,,d +,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,d,d,d,,d,d,,d,d,d,,d,d,,d,d,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,d,d,d,,d,d,d,d,d,d,d,d,d,,d,d,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,d,d,d,,d,d,,d,d,d,,d,d,,d,d,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,,d,,,,,,,d,,,d,d,d,,,d,,,,,,,d +,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,d,d,d,d,d,d +,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d,,,d,,,d,d,d,,,d,,,d,d,d,,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,,d,,,,,,d,d,d,,d,d,d,,d,d,d,,,,,,d +,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d,,,,,,d,d,d,,,,,,d,d,d,,d,,d,d,d +,,,,,,,,,,,,d,d,d,,d,d,d,,,d,,,d,,,d,,,d,d,d,,d,d,d,,d,d,d,,,d,,,d,,,d,,,d,d,d,,d,d,d +,,,,,,,,,,,,d,d,d,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,d +,,,,,,,,,,,,d,d,d,,d,d,d,,,d,,,d,,,d,,,d,d,d,,d,d,d,,d,d,d,,,d,,,d,,,d,,,d,d,d,,d,d,d +,,,,,,,,,,,,,d,,,,,,,d,d,d,,d,,d,d,d,,,,,,d,d,d,,,,,,d,d,d,,d,,d,d,d,,,,,,,d +,,,,,d,d,d,,d,d,d,,d,,d,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d,d,,d,,d,d,d,,d,d,d +,,,,,d,d,d,,d,d,d,d,d,d,d,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d,d,d,d,d,d,d,d,,d,d,d +,,,,,d,d,d,,d,d,d,,d,,d,d,d,d,,d,d,d,,d,,,,,,,d,,,d,d,d,,,d,,,,,,,d,,d,d,d,,d,d,d,d,,d,,d,d,d,,d,d,d +,d,d,d,,,d,,,,,,,d,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,,,,,,,,,,,d,,,,,,,d,,,d,d,d +,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,d,d,d,,,d,,,,,,,d,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,,,,,,,,,,,d,,,,,,,d,,,d,d,d +,,,,,d,d,d,,d,d,d,,d,,d,d,d,d,,d,d,d,,d,,,,,,,d,,,d,d,d,,,d,,,,,,,d,,d,d,d,,d,d,d,d,,d,,d,d,d,,d,d,d +,,,,,d,d,d,,d,d,d,d,d,d,d,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d,d,d,d,d,d,d,d,,d,d,d +,,,,,d,d,d,,d,d,d,,d,,d,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d,d,,d,,d,d,d,,d,d,d +,,,,,,,,,,,,,d,,,,,,,d,d,d,,d,,d,d,d,,,,,,d,d,d,,,,,,d,d,d,,d,,d,d,d,,,,,,,d +,,,,,,,,,,,,d,d,d,,d,d,d,,,d,,,d,,,d,,,d,d,d,,d,d,d,,d,d,d,,,d,,,d,,,d,,,d,d,d,,d,d,d +,,,,,,,,,,,,d,d,d,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,d +,,,,,,,,,,,,d,d,d,,d,d,d,,,d,,,d,,,d,,,d,d,d,,d,d,d,,d,d,d,,,d,,,d,,,d,,,d,d,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d,,,,,,d,d,d,,,,,,d,d,d,,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,,d,,,,,,d,d,d,d,d,d,d,d,d,d,d,,,,,,d +,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,,,d,,,d,d,d,,,d,,,d,d,d,d,d,d,d,d,d +,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,,d,,,,,,,d,d,,d,d,d,,d,d,,,,,,,d +,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,d,d,d,,d,d,,d,d,d,,d,d,,d,d,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,d,d,d,d,d,d,,d,d,d,,d,d,d,d,d,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,d,d,d,,d,d,,d,d,d,,d,d,,d,d,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d +,,,,,,,,,,,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,,,,,,,,,,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d,~,~,~,d,d,d,d,d,d,d,d,d,d,d,d +,,,,,,,,,,,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d,~,~,~,d,d,d,d,d,d,d,d,d,d,d,d +,,,,,,,,,,,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d,~,~,~,d,d,d,d,d,d,d,d,d,d,d,d +#meta label(rooms) +zone/zone +build/build +#zone label(zone) start(36;73) hidden() +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,b(5x5) +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,` +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,` +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,T{pets=true}(1x1),`,T{pets=true}(1x1) +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,b(5x5),,,,,`,b(5x5) +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,` +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,` +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,b(5x5),,,,,`,b(5x5) +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,`,,`,,`,`,` +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,`,,`,,`,`,` +,,,,,,,,,,,,,,,,,,,,,,,,,,b(5x5),,,,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),b(5x5) +,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,T{pets=true}(1x1),,,`,,,`,,,`,,,T{pets=true}(1x1),`,` +,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,T{pets=true}(1x1),b(5x6),,`,,,`,b(5x6),,`,,,T{pets=true}(1x1),`,` +,,,,,,,,,,,,,,,,,,,,,,,,,,b(5x5),,,,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),b(5x5) +,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,`,,`,`,`,,`,,`,`,`,,`,`,` +,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,`,,`,`,`,,`,,`,`,`,,`,`,` +,,,,,,,,,,,,,,,,,,,,,,,,,,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,`,,`,,`,`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1) +,,,,,,,,,,,,,,,,,,,b(5x5),,,,b(5x5),,,,,`,b(6x5),,,,,,`,b(6x5),,,,,,`,b(5x5),,,,b(5x5) +,,,,,,,,,,,,,,,,,,,,`,`,`,,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,`,,`,,`,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,,`,`,` +,,,,,,,,,,,,,,,,,,,,`,`,`,,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,,`,`,` +,,,,,,,,,,,,,,,b(5x5),,,,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,`,,`,,`,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),b(5x5) +,,,,,,,,,,,,,,,,`,`,T{pets=true}(1x1),,,`,,,,,,,`,,,,,,,`,,,,,,,`,,,,,,,`,,,T{pets=true}(1x1),`,` +,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,,,,,,`,`,T{pets=true}(1x1),b(5x5),,`,,b(5x5),,,,,`,b(5x5),,,,,`,`,`,b(5x5),,,,,`,b(5x5),,,,b(5x5),,`,,,T{pets=true}(1x1),`,` +,,,,,,,,,,,,,,,,,,,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,,`,`,`,,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1) +,,,,,,,,,,,,,,,,,,,,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,` +,,,,,,,,,,,,,,,,,,,,`,`,`,,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,,`,`,`,,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,,`,`,` +,,,,,,,,,,,,,,,,,,,,,,b(5x5),,,,b(5x5),,`,,b(4x5),,,,`,`,`,b(4x5),,,b(5x5),,`,,b(5x5) +,,,,,,,,,,,,,,,,,,,,,,,`,`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,T{pets=true}(1x1),,`,`,`,,T{pets=true}(1x1),`,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,` +,,,,,,,,,,,,,,,,,,,,,,,`,`,`,,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,,`,`,` +,,,,,,,,,,,,,,,,,,,,,,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,`,,`,T{pets=true}(1x1),,`,`,`,,T{pets=true}(1x1),`,,`,`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1) +,,,,,,,,,,,,,,,,,,,b(5x5),,,,,`,b(5x5),,,,b(5x4),,`,,,`,`,`,b(5x4),,`,,b(5x5),,,,,`,b(5x5) +,,,,,,,,,,,,,,,,,,,,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,` +,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,,,,,,,,,,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,b(5x5),,`,,,`,`,`,b(5x5),,`,,,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,` +,,,,,,,,,,,,,,,,,,,b(5x5),,,,,`,b(5x5),,,,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),b(5x5),,,,,`,b(5x5) +,,,,,,,,,,,,,,,,,,,,`,`,`,,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,,`,`,` +,,,,,,,,,,,,,,,,,,,,`,`,`,,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,,`,`,` +,,,,,,,,,,,b(5x5),,,,b(5x5),,,,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),b(5x5),,,,,`,`,`,b(5x5),,,,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),b(5x5),,,,b(5x5) +,,,,,,,,,,,,`,`,`,,`,`,T{pets=true}(1x1),,,`,,,`,,,`,,,T{pets=true}(1x1),`,`,,`,`,`,,`,`,T{pets=true}(1x1),,,`,,,`,,,`,,,T{pets=true}(1x1),`,`,,`,`,` +,,,,,,,,,,,,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,` +,,,,,,,,,,,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,T{pets=true}(1x1),b(5x6),,`,,,`,b(5x5),,`,,,T{pets=true}(1x1),`,`,,`,`,`,,`,`,T{pets=true}(1x1),b(5x5),,`,,,`,b(5x6),,`,,,T{pets=true}(1x1),`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1) +,,,,b(5x5),,,,b(5x5),,,,,`,b(6x5),,,,,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),b(5x4),,,,,`,`,`,b(5x4),,,,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),b(6x5),,,,,,`,b(5x5),,,,b(5x5) +,,,,,`,`,`,,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,`,,`,`,`,,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,,`,`,`,,`,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,,`,`,` +,,,,,`,`,`,,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,`,,`,,`,`,`,,`,`,`,`,`,`,`,`,`,`,,`,`,` +b(5x5),,,,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,`,,`,`,`,,`,,,,,,,`,,,`,`,`,,,`,,,,,,,`,,`,`,`,,`,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),b(5x5) +,`,`,T{pets=true}(1x1),,,`,,,,,,,`,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,`,,,,,,,`,,,T{pets=true}(1x1),`,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,T{pets=true}(1x1),b(5x5),,`,,b(5x5),,,,,`,b(6x5),,,,,b(5x6),,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,b(5x6),,,,b(6x5),,,,,,`,b(5x5),,,,b(5x5),,`,,,T{pets=true}(1x1),`,` +,,,,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,`,,`,`,`,,`,b(5x5),,,,b(5x4),,`,,,`,`,`,b(5x4),,`,,b(5x5),,,,,`,,`,`,`,,`,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1) +,,,,,`,`,`,,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,`,,`,,`,`,`,,`,`,`,`,`,`,`,`,`,`,,`,`,` +,,,,,`,`,`,,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,`,,`,`,`,,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,,`,`,`,,`,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,,`,`,` +,,,,,,,,,,,b(5x5),,`,,b(5x5),,,,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),b(5x5),,,,,`,`,`,b(5x5),,,,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),b(5x5),,,,b(5x5),,` +,,,,,,,,,,,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,T{pets=true}(1x1),,,`,,,`,,,`,,,T{pets=true}(1x1),`,`,,`,`,`,,`,`,T{pets=true}(1x1),,,`,,,`,,,`,,,T{pets=true}(1x1),`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1) +,,,,,,,,,,,,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,` +,,,,,,,,,,,,`,`,`,,`,`,T{pets=true}(1x1),b(5x5),,`,,,`,b(5x5),,`,,,T{pets=true}(1x1),`,`,,`,`,`,,`,`,T{pets=true}(1x1),b(5x5),,`,,,`,b(5x5),,`,,,T{pets=true}(1x1),`,`,,`,`,` +,,,,,,,,,,,,,,,,,,,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),b(5x6),,,,,`,`,`,b(5x6),,,,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,T{pets=true}(1x1) +,,,,,,,,,,,,,,,,,,,,`,`,`,,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,,`,`,` +,,,,,,,,,,,,,,,,,,,,`,`,`,,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,,`,`,` +,,,,,,,,,,,,,,,,,,,b(5x5),,,,,`,b(5x5),,,,,`,`,`,`,`,`,`,`,`,`,`,b(5x5),,,,,`,b(5x5) +,,,,,,,,,,,,,,,,,,,,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,` +,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,,,`,,,`,`,`,,,`,,,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,,,,,,,,,,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,` +,,,,,,,,,,,,,,,,,,,,,,b(5x5),,`,,b(5x5),,,,,`,`,,`,`,`,,`,`,b(5x5),,,,b(5x5),,` +,,,,,,,,,,,,,,,,,,,,,,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,T{pets=true}(1x1),,`,`,,`,`,`,,`,`,,T{pets=true}(1x1),`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1) +,,,,,,,,,,,,,,,,,,,,,,,`,`,`,,`,`,`,`,`,`,,`,`,`,,`,`,`,`,`,`,,`,`,` +,,,,,,,,,,,,,,,,,,,,,,,`,`,`,,`,`,T{pets=true}(1x1),,`,`,,`,`,`,,`,`,,T{pets=true}(1x1),`,`,,`,`,` +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,` +,,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,`,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,`,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,`,`,`,`,`,`,`,`,`,`,`,` +#build label(build) start(36;73) hidden() + +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,h,`,f +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,`,b,` +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,n,`,n +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,d +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,f,`,n,,`,,n,`,f +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,`,b,`,d,`,d,`,b,` +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,h,`,n,,`,,n,`,h +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,h,`,f,,`,,h,`,f +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,`,b,`,,`,,`,b,` +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,n,`,n,,`,,n,`,n +,,,,,,,,,,,,,,,,,,,,,,,,,,,f,`,n,,,d,,,`,,,d,,,n,`,f +,,,,,,,,,,,,,,,,,,,,,,,,,,,`,b,`,d,`,`,`,`,`,`,`,`,`,d,`,b,` +,,,,,,,,,,,,,,,,,,,,,,,,,,,h,`,n,,,d,,,`,,,d,,,n,`,h +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,n,`,n,,`,,n,`,n +,,,,,,,,,,,,,,,,,,,,,,,,,,,h,`,f,,r,b,t,,`,,r,b,t,,h,`,f +,,,,,,,,,,,,,,,,,,,,,,,,,,,`,b,`,,a,`,c,,`,,a,`,c,,`,b,` +,,,,,,,,,,,,,,,,,,,,,,,,,,,n,`,n,,h,s,f,,`,,h,s,f,,n,`,n +,,,,,,,,,,,,,,,,,,,,,,,,,,,,d,,,,,,,`,,,,,,,d +,,,,,,,,,,,,,,,,,,,,h,`,f,,f,`,n,,`,,n,r,a,h,,`,,h,a,r,n,,`,,n,`,f,,h,`,f +,,,,,,,,,,,,,,,,,,,,`,b,`,,`,b,`,d,`,d,`,b,`,s,,`,,s,`,b,`,d,`,d,`,b,`,,`,b,` +,,,,,,,,,,,,,,,,,,,,n,`,n,,h,`,n,,`,,n,t,c,f,,`,,f,c,t,n,,`,,n,`,h,,n,`,n +,,,,,,,,,,,,,,,,f,`,n,,,d,,,,,,,`,,,,,,,`,,,,,,,`,,,,,,,d,,,n,`,f +,,,,,,,,,,,,,,,,`,b,`,d,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,d,`,b,` +,,,,,,,,,,,,,,,,h,`,n,,,d,,,,,,,`,,,,,,`,`,`,,,,,,`,,,,,,,d,,,n,`,h +,,,,,,,,,,,,,,,,,,,,n,`,n,,f,`,n,,`,,n,`,f,,`,`,`,,f,`,n,,`,,n,`,f,,n,`,n +,,,,,,,,,,,,,,,,,,,,`,b,`,,`,b,`,d,`,d,`,b,`,,`,`,`,,`,b,`,d,`,d,`,b,`,,`,b,` +,,,,,,,,,,,,,,,,,,,,h,`,f,,h,`,n,,`,,n,`,h,,`,`,`,,h,`,n,,`,,n,`,h,,h,`,f +,,,,,,,,,,,,,,,,,,,,,,,,,,,,d,,,,,,`,`,`,,,,,,d +,,,,,,,,,,,,,,,,,,,,,,,h,`,f,,n,`,n,,f,n,,`,`,`,,n,f,,n,`,n,,h,`,f +,,,,,,,,,,,,,,,,,,,,,,,`,b,`,,`,b,`,,b,`,d,`,`,`,d,`,b,,`,b,`,,`,b,` +,,,,,,,,,,,,,,,,,,,,,,,n,`,n,,h,`,f,,h,n,,`,`,`,,n,h,,h,`,f,,n,`,n +,,,,,,,,,,,,,,,,,,,,,,,,d,,,,,,,d,,,`,`,`,,,d,,,,,,,d +,,,,,,,,,,,,,,,,,,,,f,`,n,,`,,n,`,f,,n,`,n,,`,`,`,,n,`,n,,f,`,n,,`,,n,`,f +,,,,,,,,,,,,,,,,,,,,`,b,`,d,`,d,`,b,`,,h,b,f,,`,`,`,,h,b,f,,`,b,`,d,`,d,`,b,` +,,,,,,,,,,,,,,,,,,,,h,`,n,,`,,n,`,h,,,d,,,`,`,`,,,d,,,h,`,n,,`,,n,`,h +,,,,,,,,,,,,,,,,,,,,,,,,`,,,,,,n,`,n,,`,`,`,,n,`,n,,,,,,` +,,,,,,,,,,,,,,,,,,,,h,`,f,,`,,h,`,f,,`,b,`,,`,`,`,,`,b,`,,h,`,f,,`,,h,`,f +,,,,,,,,,,,,,,,,,,,,`,b,`,,`,,`,b,`,,h,`,f,,`,`,`,,h,`,f,,`,b,`,,`,,`,b,` +,,,,,,,,,,,,,,,,,,,,n,`,n,,`,,n,`,n,,,,,,`,`,`,,,,,,n,`,n,,`,,n,`,n +,,,,,,,,,,,,h,`,f,,f,`,n,,,d,,,`,,,d,,,n,`,f,,`,`,`,,f,`,n,,,d,,,`,,,d,,,n,`,f,,h,`,f +,,,,,,,,,,,,`,b,`,,`,b,`,d,`,`,`,`,`,`,`,`,`,d,`,b,`,,`,`,`,,`,b,`,d,`,`,`,`,`,`,`,`,`,d,`,b,`,,`,b,` +,,,,,,,,,,,,n,`,n,,h,`,n,,,d,,,`,,,d,,,n,`,h,,`,`,`,,h,`,n,,,d,,,`,,,d,,,n,`,h,,n,`,n +,,,,,,,,,,,,,d,,,,,,,n,`,n,,`,,n,`,n,,,,,,`,`,`,,,,,,n,`,n,,`,,n,`,n,,,,,,,d +,,,,,h,`,f,,f,`,n,,`,,n,r,a,h,,r,b,t,,`,,`,b,`,,h,b,f,,`,`,`,,h,b,f,,`,b,`,,`,,r,b,t,,h,a,r,n,,`,,n,`,f,,h,`,f +,,,,,`,b,`,,`,b,`,d,`,d,`,b,`,s,,a,`,c,,`,,h,`,f,,n,`,n,,`,`,`,,n,`,n,,h,`,f,,`,,a,`,c,,s,`,b,`,d,`,d,`,b,`,,`,b,` +,,,,,n,`,n,,h,`,n,,`,,n,t,c,f,,h,s,f,,`,,,,,,,d,,,`,`,`,,,d,,,,,,,`,,h,s,f,,f,c,t,n,,`,,n,`,h,,n,`,n +,f,`,n,,,d,,,,,,,`,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,`,,,,,,,d,,,n,`,f +,`,b,`,d,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,d,`,b,` +,h,`,n,,,d,,,,,,,`,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,`,,,,,,,d,,,n,`,h +,,,,,n,`,n,,f,`,n,,`,,n,r,a,h,,h,s,f,,`,,,,,,,d,,,`,`,`,,,d,,,,,,,`,,h,s,f,,h,a,r,n,,`,,n,`,f,,n,`,n +,,,,,`,b,`,,`,b,`,d,`,d,`,b,`,s,,a,`,c,,`,,h,`,f,,n,`,n,,`,`,`,,n,`,n,,h,`,f,,`,,a,`,c,,s,`,b,`,d,`,d,`,b,`,,`,b,` +,,,,,h,`,f,,h,`,n,,`,,n,t,c,f,,r,b,t,,`,,`,b,`,,h,b,f,,`,`,`,,h,b,f,,`,b,`,,`,,r,b,t,,f,c,t,n,,`,,n,`,h,,h,`,f +,,,,,,,,,,,,,d,,,,,,,n,`,n,,`,,n,`,n,,,,,,`,`,`,,,,,,n,`,n,,`,,n,`,n,,,,,,,d +,,,,,,,,,,,,n,`,n,,f,`,n,,,d,,,`,,,d,,,n,`,f,,`,`,`,,f,`,n,,,d,,,`,,,d,,,n,`,f,,n,`,n +,,,,,,,,,,,,`,b,`,,`,b,`,d,`,`,`,`,`,`,`,`,`,d,`,b,`,,`,`,`,,`,b,`,d,`,`,`,`,`,`,`,`,`,d,`,b,`,,`,b,` +,,,,,,,,,,,,h,`,f,,h,`,n,,,d,,,`,,,d,,,n,`,h,,`,`,`,,h,`,n,,,d,,,`,,,d,,,n,`,h,,h,`,f +,,,,,,,,,,,,,,,,,,,,n,`,n,,`,,n,`,n,,,,,,`,`,`,,,,,,n,`,n,,`,,n,`,n +,,,,,,,,,,,,,,,,,,,,`,b,`,,`,,`,b,`,,h,s,f,,`,`,`,,h,s,f,,`,b,`,,`,,`,b,` +,,,,,,,,,,,,,,,,,,,,h,`,f,,`,,h,`,f,,a,`,c,,`,`,`,,a,`,c,,h,`,f,,`,,h,`,f +,,,,,,,,,,,,,,,,,,,,,,,,`,,,,,,r,b,t,d,`,`,`,d,r,b,t,,,,,,` +,,,,,,,,,,,,,,,,,,,,f,`,n,,`,,n,`,f,,n,`,n,,`,`,`,,n,`,n,,f,`,n,,`,,n,`,f +,,,,,,,,,,,,,,,,,,,,`,b,`,d,`,d,`,b,`,,,d,,,`,`,`,,,d,,,`,b,`,d,`,d,`,b,` +,,,,,,,,,,,,,,,,,,,,h,`,n,,`,,n,`,h,,`,`,`,,`,`,`,,`,`,`,,h,`,n,,`,,n,`,h +,,,,,,,,,,,,,,,,,,,,,,,,d,,,,,,,`,`,,`,`,`,,`,`,,,,,,,d +,,,,,,,,,,,,,,,,,,,,,,,n,`,n,,f,`,n,,`,`,,`,`,`,,`,`,,n,`,f,,n,`,n +,,,,,,,,,,,,,,,,,,,,,,,`,b,`,,`,b,`,d,`,`,,`,`,`,,`,`,d,`,b,`,,`,b,` +,,,,,,,,,,,,,,,,,,,,,,,h,`,f,,h,`,n,,`,`,,`,`,`,,`,`,,n,`,h,,h,`,f +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,` +,,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,`,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,`,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,`,`,`,`,`,`,`,`,`,`,`,` diff --git a/data/blueprints/dreamfort.csv b/data/blueprints/dreamfort.csv new file mode 100644 index 0000000000..c1266edb6e --- /dev/null +++ b/data/blueprints/dreamfort.csv @@ -0,0 +1,3238 @@ +#notes label(help) run me for the dreamfort walkthrough +"Welcome to Dreamfort! These blueprints will help you build a functional, secure, fully self-sustaining fortress that you can use as-is or extend to build the fortress of your dreams!" +"" +"It can be difficult to apply a set of blueprints that you did not write yourself. This walkthrough will guide you through the high-level steps of building Dreamfort. Run ""gui/quickfort dreamfort /checklist"" (or, if you're looking at the online version, switch to the ""checklist"" sheet) for a compact list of the blueprints you'll be applying. Each level also has its own mini-walkthrough with more details." +"" +"The final fort will have a walled-in area on the surface for livestock, trading, aboveground farming, and military training. One z-level down is the farming level, with related workshops and vents up to the surface for miasma prevention. The farming level also has a miniature dining hall and dormitory for use until you get the services and housing levels set up." +"" +"Beyond those two, the other layers can be built in any order, at any z-level, according to your preference and the layout peculiarities of your embark site:" +"- The industry level has a compact, but complete set of workshops and stockpiles (minus what is already provided on the farming level)." +"- The services level has dining, hospital, marksman barracks, and justice services. It has a well system and is 4 z-levels deep." +"- The guildhall level has large rooms for building libraries, temples, and guildhalls, with optional furniture layouts." +- The suites level has fancy rooms for your nobles with the furniture that they require. +- The apartments levels have small but well-furnished bedrooms for your other dwarves. +- The crypt level houses your dead. +"" +"Run each level's ""help"" blueprint (e.g. ""gui/quickfort dreamfort /surface_help"") for more details." +"" +"Dreamfort has a central stairs-based design. For all Dreamfort levels, place the cursor on the center (undug) tile of the 3x3 stairs area when you apply the blueprints for that level. The first surface blueprint will designate a column of stairs that you can use as a guide. If you need to extend the stairs down further to lower levels, run ""gui/quickfort dreamfort /central_stairs"" and set the repeat option to go down however many levels you need (each repetition is 2 levels). Apply it with the cursor on the z-level below the lowest current stairs." +"" +"Dreamfort blueprints take care of everything to get the fort up and running. You don't need to clear any extra trees or create any extra buildings or stockpiles (though of course you are free to do so). Blueprints that do require manual steps, like 'assign minecart to hauling route', will leave a message telling you so when you run them. Note that blueprints will designate buildings to build even if you don't have the materials needed to build them. You can use the ""o"" hotkey to automatically create the manager orders for all the needed items when you have a blueprint loaded in gui/quickfort. Make sure your manager is available to validate all the incoming work orders!" +"" +"There are some tasks common to all forts that Dreamfort doesn't specifically handle for you. For example, Dreamfort sets up a barracks, but managing squads is up to you. Here are some other common tasks that may need to be done manually (or with some other tool):" +- Exploratory mining for specific resources like iron (see gui/design for help with this) +"- Filling the well system with water (if you have a light aquifer, see library/aquifer_tap.csv for help with this)" +- Bringing magma up to the industry level to power magma forges/furnaces (see library/pump_stack.csv for help with this) +- Manufacturing trade goods +"- Custom stockpile setups to assist with, for example, encrusting only high-quality items" +"" +"Dreamfort works best at an embark site that is relatively flat and has at least one soil layer. New players should avoid embarks with aquifers if they are not prepared to deal with them. Bring picks for mining, an axe for woodcutting, and an anvil for a forge. Bring a few blocks to speed up initial workshop construction as well. That's all you really need, but see the example embark profile in the online spreadsheets for a more complete setup." +"" +"Other DFHack tools also work very well with Dreamfort, such as autofarm. See the /setup_help blueprint for a suggested list to turn on in the DFHack gui/control-panel." +"" +"Once you have your starting surface workshops up and running, you might want to configure buildingplan to only use blocks for constructions so it won't use your precious wood, boulders, and bars to build floors and walls. If you bring at least 7 blocks with you on embark, you can set this to be your default in the Automation -> Autostart tab of gui/control-panel." +"" +"Directly after embark, run ""gui/quickfort dreamfort /setup_help"" to get some advice on initial settings, and get started building your fort with ""gui/quickfort dreamfort /surface1"" on the surface (see /surface_help for how to select a good spot). Read the walkthroughs for each level to understand what's going on and follow the checklist to keep track of where you are in the building process. Good luck, and have fun building an awesome Dreamfort-based fort!" +"" +"The dreamfort.csv file distributed with DFHack is generated from online spreadsheet files. If you want to look at how these blueprints are put together, it is easier to look at the online spreadsheets than the giant .csv. You can view them at: https://drive.google.com/drive/folders/1dsmvnzbOKsyFS3DCj0F8ibSnMhVHEjdV" +You are welcome to copy the Dreamfort spreadsheets and make your own modifications! +"" +"If you like, you can download a fully built Dreamfort-based fort from https://dffd.bay12games.com/file.php?id=15434 and explore it +interactively." +"# The dreamfort.csv distributed with DFHack is generated from the online spreadsheets with the following command: + for fname in dreamfort*.xlsx; do xlsx2csv -a -p '' ""$fname""; done | sed 's/,*$//'" +#notes label(checklist) command checklist +"Here is the recommended order for Dreamfort commands. Each line is a blueprint that you run with gui/quickfort (default keybinding: Ctrl-Shift-Q), except where we use other tools as noted. If you set ""dreamfort"" as the filter when you open gui/quickfort, you'll conveniently only see Dreamfort blueprints to choose from. See the walkthroughs (the ""help"" blueprints) for context and details. You can also copy text from this spreadsheet when viewing it online and paste it into gui/launcher with Ctrl-V." +"If the checklist indicates that you should generate orders, that means to hit the ""o"" hotkey when the blueprint is loaded in gui/quickfort. You'll get a popup saying which orders were generated. Also remember to read the messages the blueprints display after you run them so you don't miss any important manual steps!" +"" +-- Preparation (before you embark!) -- +Optionally copy the premade Dreamfort embark profile from the online spreadsheets to the prefs/embark_profiles.txt file. +Run gui/control-panel and enable settings on the Autostart tabs. See the /setup_help notes for details. +"" +-- Set settings and preload initial orders -- +DFHack command,Blueprint,Generate orders,Notes +gui/quickfort,/setup_help,,For advice on how to do initial setup for success. +"quickfort orders library/dreamfort.csv -n ""/surface2, /farming2, /surface3, /industry2, /surface4, /industry3""",,,"Queue up orders required to get the fort minimally functional and secure. You can remove the order for the anvil (you brought one with you, right?)." +"" +-- Find a good starting spot on the surface -- +DFHack command,Blueprint,Generate orders,Notes +gui/quickfort,/perimeter,,Run at embark. Don't actually apply the blueprint -- it's way too early to dedicate resources to building walls. Just use the preview shadow to find a good spot on the surface. See the surface level help for how to find a good spot. +"" +-- Dig -- +DFHack command,Blueprint,Generate orders,Notes +gui/quickfort,/surface1,,Clear some trees and dig central staircase. Run when you find your center tile. Deconstruct your wagon if it is in the way. +gui/quickfort,/dig_all,,"Run when you find a suitable (non-aquifer) rock layer for the industry level. It designates digging for industry, services, guildhall, suites, apartments, and the crypt all in one go. This list does not include the farming level, which we'll designate in the uppermost soil layer once the surface miasma channels are dug. Note that it is more efficient for your miners if you designate the digging for a level before they dig the central stairs past that level. The stairs down on each level are designated at priority 5 instead of the regular priority 4. This lets the miners focus on one z-level at a time and not run up and down the stairs attempting to dig out two blueprints simultaneously. If you need to designate your levels individually due to caverns interrupting the sequence or just because it is your preference, run the level-specific dig blueprints (i.e. /industry1, /services1, /guildhall1, /suites1, 3 levels of /apartments1, and /crypt1) instead of running /dig_all." +"" +-- Core fort (should finish at about the third migration wave) -- +DFHack command,Blueprint,Generate orders,Notes +gui/quickfort,/surface2,,"Build starter workshops/stockpiles and dig miasma vents. Run after initial trees are cleared. If you are deconstructing the wagon, do it before running this blueprint so the jobs that depend on scattered wagon contents (e.g. blocks) don't get canceled later." +gui/quickfort,/farming1,,Dig out the farming level. Run when channels on the surface are dug and the additional designated trees are cleared. +gui/quickfort,/farming2,,Build farming level. Run as soon as the farming level has been completely dug out. +gui/quickfort,/surface3,,Cover the miasma vents and start protecting the central staircase from early invasions. Run when /farming2 is mostly complete. +gui/quickfort,/industry2,,"Build industry level. Run as soon as the industry level has been completely dug out. As industry workshops are built, you can remove the temporary workshops and stockpiles on the surface. Be sure that there are no items attached to jobs left in the surface workshops before deconstructing them, otherwise you'll get canceled jobs!" +gui/quickfort,/surface4,,Finish protecting the staircase and lay flooring for future buildings. Run after the walls and floors around the staircase are built and you have moved production from the surface to the industry level. +gui/quickfort,/industry3,,Build the rest of the industry level. Run once /surface4 is mostly complete. +orders import library/basic,,,"Run after the first migration wave, so you have dwarves to do all the basic tasks. Note that this is the ""orders"" plugin, not the ""quickfort orders"" command." +gui/quickfort,/services2,Yes,"Build simple hospital and dining room, including a well. Run once the 4 services levels have been dug out and you have built up some stone in your industry stone stockpiles. Feel free to remove the orders for the ropes if you brought some with you. If you are filling your wells from an aquifer or stream, now is also a good time to start digging the plumbing." +gui/quickfort,/surface5,Yes,"Build surface buildings, drawbridges, and furniture. Run when all marked trees on the surface are chopped down and previously-designated walls and floors have been constructed. Be sure to check that the little ""wing"" of roof section over the future barracks is constructed so we can place the barracks beds." +gui/quickfort,/surface6,Yes,Build security perimeter. Run once you have linked all levers to their respective bridges. +gui/quickfort,/surface7,Yes,Build roof. Run after the surface walls are completed and any marked trees are chopped down. Be sure to give your haulers some time to fill the stonecutter's stockpile with some stone first so your stonecutters won't be hauling it up from the depths by hand. +"" +-- Plumbing -- +"If you haven't done it already, this is a good time to fill your well cisterns, either with a bucket brigade or by routing water from a freshwater stream or an aquifer (see the aquifer_tap library blueprint for help with this)." +Also consider bringing magma up to your services level so you can replace the forge and furnaces on your industry level with more powerful magma versions. This is especially important if your embark has insufficient trees to convert into charcoal. Keep in mind that moving magma is a tricky process and can take a long time. Don't forget to continue making progress on the rest of the fort! +"" +-- Mature fort (fourth migration wave onward) -- +"The order of steps in this section is not important. Feel free to reorder as per the needs of your fort. Once you have about 50 dwarves, you can queue up as much as you want and your haulers will be able to keep your stonecutters supplied. You can even build another two Stonecutter's workshops to speed things along. You might need to dig a quarry on an unused level to get enough stone, though." +DFHack command,Blueprint,Generate orders,Notes +orders import library/furnace,,,Automated production of basic furnace-related items. Don't forget to create a sand collection zone (or remove the sand- and glass-related orders if you have no sand). +gui/quickfort,/guildhall2_default,Yes,"Build library and non-denominational temple, and prepare space for future temples and guildhalls. Run when the guildhall level has been dug out." +gui/quickfort,/services3,Yes,"Extend the dining room and hospital, and start the jail. Run when your population grows to about 20." +gui/quickfort,/apartments2,Yes,Build and zone bedrooms. Run when the first apartment level has been dug out and you have outgrown your starter dormintory. +gui/quickfort,/suites2_default,Yes,Build rooms that you can zone for your nobles. Run when the suites level has been dug out and you are approaching a population of 50. +gui/quickfort,/crypt2,Yes,Build a small group of tombs. Run when the crypt level has been dug out and you have outgrown your starter tomb on the farming level. +gui/quickfort,/surface8,Yes,"Build extended trap corridors. If you have a strong military, you might not need this." +gui/quickfort,/farming3,Yes,Add in all the doors we couldn't afford to build earlier. +orders import library/military,,,Automated production of military equipment. Turn on automelt in the meltables piles on the industry level to automatically upgrade all metal military equipment to masterwork quality. These orders are optional if you are not using a military. +orders import library/smelting,,,Automated production of all types of metal bars. +gui/quickfort,/services4,Yes,Build full dining room and jail. +orders import library/rockstock,,,Maintains a small stock of all types of rock furniture. Useful for filling out future guildhalls. +orders import library/glassstock,,,Maintains a small stock of all types of glass furniture and parts (only import if you have sand). +gui/quickfort,/apartments2,Yes,Repeat as needed as your fort grows. +gui/quickfort,/crypt3,Yes,Run when the crypt is starting to run out of free tombs. +"" +See this checklist online at https://docs.google.com/spreadsheets/d/13PVZ2h3Mm3x_G1OXQvwKd7oIR2lK4A1Ahf6Om1kFigw/edit#gid=1459509569 +#notes label(setup_help) pre- and post-embark tasks +These are Dreamfort's suggestions for adjustments to settings and initial setup. +"" +You can save some time by setting up your settings in gui/control-panel before you embark. +"Beyond the bugfix tools that are enabled by default, we recommend enabling the following DFHack tools in gui/control-panel (but they are not required if you prefer to do these things manually):" +"" +"On the gui/control-panel ""Autostart"" tabs, enable:" +"""Automation"":" +- autobutcher +- autobutcher target 10 10 14 2 BIRD_GOOSE +- autochop +- autocheese +- autofarm +- autofarm threshold 150 grass_tail_pig +- autofish +- automilk +- autonestbox +- autoshear +- autoslab +- ban-cooking all +- buildingplan set boulders false +- buildingplan set logs false +- cleanowned +- logistics enable autoretrain +- nestboxes +- orders-sort +- prioritize +- seedwatch +- suspendmanager +- tailor +"""Gameplay"" subtab:" +- combine +- dwarfvet +- immortal-cravings +- timestream +- work-now +"Note that if you've already started your fort and have missed the ""new fort"" trigger, you can enable these tools on the ""Enabled"" tabs instead. You can run the one-time commands (like ban-cooking all) manually from gui/launcher." +"" +"Now, after you've arrived at your embark site, open the nobles screen and:" +"- Assign dwarves to at least manager, chief medical dwarf, broker, and bookkeeper noble roles (they can all be the same dwarf)" +"" +On the work details screen (Labor -> Work details) + - Specialize your miners (click the hammer-lock button so it turns red) and make your miners also engravers (they'll need something to do once the mining is done) + - Deselect fishing from all dwarves -- you have enough food to get started and you'll need their time for hauling +"" +In standing orders (Labor -> Standing orders): +" - Change ""Automatically weave all thread"" to ""No automatic weaving"" so the hospital always has thread -- we'll be managing cloth production with automated orders" +"- On the ""Other"" tab, change ""Everybody harvests"" to ""Only farmers harvest"". This will prevent unilts that don't have the Planting labor enabled from harvesting plants, allowing planting skill gains to be concentrated into your designated planters and improving your overall crop yield." +"" +"Once you have your standing orders set the way you like, you can export them and instruct DFHack to autoload your saved settings on new embarks. The controls for getting this set up are available by default in a panel at the bottom of the Standing orders -> Automated workshops tab." +"#meta label(dig_all) start(central stairs on industry level) message(You can repeat the /central_stairs blueprint down more levels if you need more stairs.) dig industry, services, guildhall, suites, apartments, and crypt levels. does not include farming." +# Note that this blueprint will only work for the unified dreamfort.csv. It won't work if you have downloaded the individual .xlsx files since #meta blueprints can't cross file boundaries. +"" +/industry1 +#> +/services1 +#>4 +/guildhall1 +#> +/suites1 +#> +/apartments1 repeat(down 3) +#>3 +/crypt1 +#ignore +"Here are the most important skills for getting Dreamfort up and running, along with suggestions for how to distribute them." +"" +Hauler / Manager / Bookkeeper / Broker,Miner,Miner,Stoneworker,Craftsdwarf,Outdoorsdwarf,Farmer +Noble role skills,Miner,Miner,Stonecutter,Stonecrafting,Carpenter,Planter +,,,Stone Carver,Mechanic,Wood Cutter,Stonecutter +"" +"The most time-consuming tasks in early Dreamfort are: mining, chopping down trees, and making blocks. Starting with at least two miners, two woodcutters (assuming your embark has trees), and two stonecutters helps keep the fort from stalling." +"" +We suggest bringing at least: +2 picks,for the two miners +2 battleaxes,for one woodcutters and either a second woodcutter or an emergency weapon +1 anvil,for the forge +food and seeds,as per usual +3 ropes,"for the hospital well and traction benches. you could make the ropes out of raw materials, but dwarves are usually too busy to do textile work at the start of the game." +20 blocks,"for starting workshops, the temporary trade depot, and a few spares in case you need to shore up a light aquifer in a soil layer. necessary if you have buildingplan configured for blocks only." +many boulders,for quickly turning into more blocks while your miners are digging in dirt or dealing with aquifers. blocks are the limiting factor in the early stages. +dogs and cats,for protection and vermin control +geese,for bones and leather. bring at least 1 male and 2 females for the 2 early nestboxes. +"" +Also bring logs for beds if embarking in an area without many trees. +"" +See ldog's Dreamfort embark profile for a more advanced approach: +https://drive.google.com/file/d/1Et42JTzeYK23iI5wrPMsFJ7lUXwVBQob/view?usp=sharing +"#ignore Add these lines to the bottom of your ""prefs/embark_profiles.txt"" file to make the ""Dreamfort"" profile available in-game. Also see ldog's dreamfort embark profile for a more advanced, dwarfy approach." +[PROFILE] +[TITLE:Dreamfort] +[SKILL:1:JUDGING_INTENT:1] +[SKILL:1:APPRAISAL:2] +[SKILL:1:ORGANIZATION:1] +[SKILL:1:RECORD_KEEPING:1] +[SKILL:1:MILITARY_TACTICS:5] +[SKILL:2:MINING:5] +[SKILL:2:ENGRAVE_STONE:4] +[SKILL:2:SWIMMING:1] +[SKILL:3:MINING:5] +[SKILL:3:ENGRAVE_STONE:4] +[SKILL:3:SWIMMING:1] +[SKILL:4:CUT_STONE:5] +[SKILL:4:CARVE_STONE:5] +[SKILL:5:STONECRAFT:5] +[SKILL:5:MECHANICS:5] +[SKILL:6:WOODCUTTING:5] +[SKILL:6:CARPENTRY:5] +[SKILL:7:PLANT:5] +[SKILL:7:CUT_STONE:5] +[ITEM:10:CLOTH:NONE:CREATURE_MAT:SPIDER_CAVE:SILK] +[ITEM:100:WOOD:NONE:PLANT_MAT:WILLOW:WOOD] +[ITEM:30:BLOCKS:NONE:INORGANIC:QUARTZITE] +[ITEM:21:SEEDS:NONE:PLANT_MAT:MUSHROOM_HELMET_PLUMP:SEED] +[ITEM:21:SEEDS:NONE:PLANT_MAT:GRASS_TAIL_PIG:SEED] +[ITEM:21:SEEDS:NONE:PLANT_MAT:GRASS_WHEAT_CAVE:SEED] +[ITEM:21:SEEDS:NONE:PLANT_MAT:POD_SWEET:SEED] +[ITEM:21:SEEDS:NONE:PLANT_MAT:BUSH_QUARRY:SEED] +[ITEM:21:SEEDS:NONE:PLANT_MAT:MUSHROOM_CUP_DIMPLE:SEED] +[ITEM:1:ANVIL:NONE:INORGANIC:IRON] +[ITEM:2:WEAPON:ITEM_WEAPON_AXE_BATTLE:INORGANIC:COPPER] +[ITEM:2:WEAPON:ITEM_WEAPON_PICK:INORGANIC:COPPER] +[ITEM:21:DRINK:NONE:PLANT_MAT:GRASS_TAIL_PIG:DRINK] +[ITEM:20:DRINK:NONE:PLANT_MAT:MUSHROOM_HELMET_PLUMP:DRINK] +[ITEM:20:DRINK:NONE:PLANT_MAT:POD_SWEET:DRINK] +[ITEM:20:DRINK:NONE:PLANT_MAT:GRASS_WHEAT_CAVE:DRINK] +[ITEM:30:PLANT:NONE:PLANT_MAT:MUSHROOM_HELMET_PLUMP:STRUCTURAL] +[ITEM:45:BOULDER:NONE:INORGANIC:QUARTZITE] +[ITEM:21:THREAD:NONE:CREATURE_MAT:SPIDER_CAVE:SILK] +[ITEM:3:CHAIN:NONE:CREATURE_MAT:SPIDER_CAVE:SILK] +[PET:2:DOG:FEMALE:STANDARD] +[PET:1:DOG:MALE:STANDARD] +[PET:2:CAT:FEMALE:STANDARD] +[PET:1:CAT:MALE:STANDARD] +[PET:2:BIRD_GOOSE:FEMALE:STANDARD] +[PET:2:BIRD_GOOSE:MALE:STANDARD] +#notes label(surface_help) surface level walkthrough +Sets up a protected entrance to your fort in a flat area on the surface. +Screenshot: https://drive.google.com/file/d/1dlu3nmwQszav-ZaTx-ac28wrcaYBQc_t +"" +Features: +- A starting set of workshops and stockpiles (which you can later remove once you establish your permanent workshops and storage) +"- Livestock grazing area, nestbox zones, and beehives" +"- Walls, roof, and lever-controlled gates for security" +- Barracks (with prisoner processing quantum dump) +- Trap-filled hallways for invaders +- Optional extended trap hallways (to handle larger sieges with a smaller/no military) +"- Protected trade depot, with separate trade goods stockpiles for organics and inorganics (for safe elven trading)" +- A grid of small farm plots for lucrative surface farming +"- A burrow named ""Inside+"" that grows with your fort as you dig it out. It is pre-registered as a civilian alert burrow so you can use it to get your civilians to safety during sieges." +"- A burrow named ""Clearcutting area"" that is automatically registered with autochop (if you have it enabled) to keep the area around your fort clear of trees. This prevents invaders from jumping over your walls. Moreover, it prevents trees from growing large near your exterior walls. If those trees are chopped down so they fall on the fort, they can collapse the roof." +"" +Manual steps you have to take: +"- Assign grazing livestock to the large pasture, dogs to the pasture over the central stairs, and male birds to the zone between the rows of nestboxes (DFHack's autonestbox will auto-assign the female egg-laying birds to the nestbox zones)" +- Connect levers to the drawbridges that match the names of the levers +- Assign minecarts to the trade goods and prisoner processing quantum stockpile hauling routes with assign-minecarts all +"" +Be sure to choose an embark site that has a flat area on the surface large enough to use these blueprints! +"" +Surface Walkthrough: +"1) Choose a tile for your central fortress stairs. The terrain around that tile should be perfectly flat. Trees are ok, but no slopes, rivers, or ponds. To be sure that the tile you've chosen is in a good spot, run ""gui/quickfort dreamfort /perimeter"". This will show you the eventual boundaries of the fort. Some wall segments might be missing due to existing trees, but that's ok. Make sure the area within the exterior wall is flat. Cancel out of the preview. You don't actually need to apply this blueprint. You may want to double-check your selected area with gui/biomes to make sure your surface farm plots (to the left of the central tile) will be in a biome that you want to grow in (e.g. you cannot grow surface plants in mountain biomes). Also, the biome to the north of the central tile will hold the underground farm plots, so be sure it has soil." +"" +"2) With the cursor on the chosen tile, run /surface1 to clear surrounding trees and set up your pastures. Deconstruct your wagon to get it out of the way of our upcoming walls and floors. Remember to assign your dogs to the pasture around the staircase, your grazing animals to the large pasture, and your male birds to the zone between the nestboxes. Your female egg-layers will automatically get assigned to nestbox zones once the nestboxes are built, so you don't need to worry about them. You can let your cats roam free to chase vermin." +"" +"3) Once the marked trees have been cleared, run /surface2 to setup starting workshops/stockpiles, channel out the miasma vents for the farming level, and start clearing trees from a larger area. If you haven't done it already, now is a good time to configure buildingplan to only build buildings with blocks, not logs or raw boulders. Generate manager orders for /surface2 if you haven't already preordered with the checklist command." +"" +"4) Once the channels are dug out and the trees are cleared, start digging the farming level one z-level down. Once you have run /farming2, come back to the surface and run /surface3 to cover the vents and build an enclosure around your central stairs. Although the vents will be covered with flooring (or solid walls), they will still work to prevent miasma on the farming level. Generate manager orders for /surface3 if you haven't already preordered with the checklist command." +"" +"5) Once all walls and floors have been constructed around the stairwell, run /surface4 to build floors and walls to support upcoming buildings and furniture. Generate manager orders for /surface4 if you haven't already preordered with the checklist command." +"" +"6) Once walls and floors have been constructed (including the small roof segment one z-level up over the barracks), run /surface5 to build furniture and the drawbridge gates. This blueprint also clearcuts the trees from around the exterior walls. The blueprint may appear to extend off the map or into a nearby hill, but that is ok. Generate manager orders for /surface5." +"" +"7) Once all marked trees are cleared, run /surface6 to build the security perimeter and remaining flooring. Generate manager orders for /surface6." +"" +"8) Once you have enough dwarves to do a lot of building without starving other important tasks, run /surface7 to build the roof. This blueprint also sets up the autochop-integrated clearcutting area, so it may extend off the map or into nearby hills. It is not a problem if that happens. Generate manager orders for /surface7." +"" +"9) For extra security, you can run /surface8 any time after /surface7 to extend the trap corridors. Generate manager orders for /surface8." +"" +"10) Once your industry and farming levels are set up and running, you can disassemble the surface workshops and remove the surface stockpiles. Disassembling a workshop scatters the items stored within it and cancels any pending jobs that happen to use those items. In order to avoid job cancellations, first set the surface workshops to not accept general work orders (click on the building, select the ""Work orders"" tab, and set the ""General work orders allowed"" to 0). Then check to see if any items in a workshop are marked as being part of an active job. Once no items in the workshop have that marker, you are free to disassemble that workshop." +"" +Sieges and Prisoner Processing: +Here are some tips and procedures for handling seiges -- including how to clean up afterwards! +"" +"- Your ""Inside+"" burrow will automatically grow with your fort and should include only safe areas. In particular, it does not include the ""atrium"" area (where the ""siege bait"" pasture is) or the trapped hallways." +"" +"- When a siege begins, set your civilian alert (attach the alert to your ""Inside+"" burrow if it isn't already) to ensure all your civilians stay out of danger. Immediately pull the lever to close the outer main gate. It is also wise to close the trade depot and inner main gate as well. That way, if enemies get past the traps, they'll have to go through the soldiers in your barracks (assuming you have a military)." +"" +"- During a siege, you can use the levers to control how attackers path through the trapped corridors. If there are more enemies than cage traps, time your lever pulling so that the inner gates snap closed before your last cage trap is sprung. Then the remaining attackers will have to backtrack and go through the other trap-filled hallway. You can also choose *not* to use the trap hallways and instead meet the siege head-on with your military. It's up to you!" +"" +"- If your cage traps fill up, ensure your hallways are free of uncaged attackers, then close the trap hallway outer gates and open the inner gates. Clear the civilian alert and allow your dwarves to reset all the traps -- make some extra cages in preparation for this! Then re-enable the civilian alert and open the trap hallway outer gates." +"" +"- Once the last attacker is caged, open all the gates and unset the civilian alert. Life is normal again!" +"" +"After a siege, you can use the caged prisoners to safely train your military. Here's how:" +"" +"- Once the prisoners are hauled to the ""prisoner quantum"" stockpile in the barracks, run ""stripcaged all"" in DFHack's gui/launcher." +"" +"- After all the prisoners' items have been confiscated, bring your military dwarves to the barracks (if they aren't already there)." +"" +- Assign a group of prisoners to the pasture that overlaps the prisoner quantum stockpile +"" +"- Hauler dwarves will come and release prisoners one by one. Your military dwarves will immediately pounce on the released prisoners and chop them to bits, saving the hauler dwarves from being attacked. Repeat until all prisoners have been ""processed"". Some prisoners are not directly hostile (like cavern-caught gorlaks) and you may need to be target them explicitly to get your soldiers to attack them." +#dig label(central_stairs_odd) start(2;2) hidden() carved spiral stairs odd levels +`,j6,` +u,`,u +`,j6,` +#meta label(central_stairs_even) hidden() carved spiral stairs even levels +/central_stairs_odd transform(cw) +#meta label(central_stairs) two levels of carved spiral stairs (repeat down as needed) +/central_stairs_odd +#> +/central_stairs_even +#build label(central_stairs_odd_constructed) start(2;2) hidden() constructed spiral stairs odd levels +`,Cd,` +Cu,`,Cu +`,Cd,` +#meta label(central_stairs_even_constructed) hidden() constructed spiral stairs even levels +/central_stairs_odd_constructed transform(cw) +#meta label(central_stairs_constructed) two levels of constructed spiral stairs (repeat down as needed) +/central_stairs_odd_constructed +#> +/central_stairs_even_constructed +"#meta label(perimeter) start(central stairs) message(If you accidentally applied this blueprint to the map, run quickfort undo on this blueprint to clean up.) show the eventual perimeter of the surface fort; useful for location scouting. DO NOT APPLY." +walls/surface_walls +corridor_gates/surface_corridor_gates +corridor/surface_corridor +corridor_traps/surface_corridor_traps +"" +"#meta label(surface1) start(central stairs) +message(Once the central stairs are mined out deeply enough, you should start digging the industry level in a non-aquifer rock layer. You'll need the boulders from the digging to make blocks. +If your wagon is within the fort perimeter, deconstruct it to get it out of the way. +Once the marked trees are all chopped down (if any), continue with /surface2.) clear trees and set up pastures" +clear_small/surface_clear_small +burrow_start/surface_burrow_start +zones/surface_zones +#> +central_stairs/central_stairs repeat(down 10) +"" +"#meta label(surface2) start(central stairs) message(If you preordered items on the checklist, good. If not, don't forget to generate orders for this blueprint now. +Once the channels are dug out and the marked trees are cleared, continue with /surface3.) set up starting workshops/stockpiles, channel miasma vents, and clear more trees" +place_start/surface_place_start +build_start/surface_build_start +channel/surface_channel +clear/surface_clear +"" +"#meta label(surface3) start(central stairs) message(If you preordered items on the checklist, good. If not, don't forget to generate orders for this blueprint now. +Once the walls and floors around the staircase have been constructed, continue with /surface4.) Cover vents and protect the central stairs." +cover_vents/surface_cover_vents +cover_stairs/surface_cover_stairs +"" +"#meta label(surface4) start(central stairs) message(If you preordered items on the checklist, good. If not, don't forget to generate orders for this blueprint now. +Once the bits of flooring have been constructed, continue with /surface5. Be sure to check one z-level above the surface to ensure the roof segment above the future barracks has been finished.) build walls and flooring to support upcoming buildings and furniture" +stairs_doors/surface_stairs_doors +pre_building/surface_pre_building +"" +"#meta label(surface5) start(central stairs) message(Remember to enqueue manager orders for this blueprint. +Once the marked trees are cleared, continue with /surface6.) build gates, furniture, and trade stockpile/depot" +traffic/surface_traffic +place/surface_place +build/surface_build +clear_large/surface_clear_large +"" +"#meta label(surface6) start(central stairs) message(Remember to enqueue manager orders for this blueprint. +Continue with /surface7 sometime after the walls are completed and any marked trees are chopped down, whenever you have enough dwarves to build the roof without starving other important construction tasks.) build traps and remaining walls/floors" +walls/surface_walls +floors/surface_floors +traps/surface_traps +clear_large/surface_clear_large +"" +"#meta label(surface7) start(central stairs (on ground level)) message(Remember to enqueue manager orders for this blueprint. +For extra security, you can run /surface8 at any time to extend the trap corridors.) expand Inside+ burrow to safe surface areas and build roof" +burrows/surface_burrows +#< +roof/surface_roof +roof2/surface_roof2 +roof3/surface_roof3 +roof4/surface_roof4 +"" +#meta label(surface8) start(central stairs) message(Remember to enqueue manager orders for this blueprint.) build extended trap corridors +corridor_gates/surface_corridor_gates +corridor/surface_corridor +corridor_traps/surface_corridor_traps +#dig label(surface_clear_small) start(19; 19) hidden() clear trees for starting workshops and stockpiles + + + +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,t1(25x11),,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,t1,`,`,`,`,`,`,,`,,`,`,`,`,`,t1,`,`,`,t1,`,`,,` +,,,`,,`,,`,t1,t1,,,,,,`,t1,t1,t1,t1,t1,`,,,,t1(5x5),,,,,,`,,` +,,,`,,`,,`,,,,,,,,,t1,t1,t1,t1,t1,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,`,t1,j,t1,j,t1,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,t1,t1,t1,t1,t1,,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,`,t1,t1,t1,t1,t1,`,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,t1,,,,,,t1,`,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,t1,t1,,,,,,t1,t1,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,t1,t1,,t1,t1,t1,,t1,t1,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,t1,t1,t1,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,t1,,,t1,t1,t1,,,t1,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,,,,,,,,,,,,,,t1,,,,,,,,,,,,,,,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` + + + +#burrow label(surface_burrow_start) start(19; 19) hidden() create safety burrow that will grow with your fort + + + +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,`,`,,`,`,,` +,,,`,,`,,`,,,,,,,,`,a{name=Inside+ create=true civalert=true}(5x5),,,,,,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,`,,~,,~,,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` + + + +"#zone label(surface_zones) start(19; 19) hidden() message(Remember to assign your dogs to the pasture surrounding the central stairs, your grazing animals to the large pasture, and your male birds to the zone between the rows of nestboxes. If your wagon is far away, you can let your animals wander closer to the fort before pasturing them to save hauling time.) pastures and training areas" + + + +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,"n{name=""Main pasture""}(25x11)",,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,"t{name=""Pet training area""}(9x5)",,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,`,"n{name=""Nestbox 1""}(1x1)","n{name=""Nestbox 2""}(1x1)","n{name=""Nestbox 3""}(1x1)","n{name=""Nestbox 4""}(1x1)","n{name=""Nestbox 5""}(1x1)","n{name=""Nestbox 6""}(1x1)","n{name=""Nestbox 7""}(1x1)",`,,,,,,`,,,,,,,,,,`,,` +,,,`,,`,,`,"n{name=""Male birds""}(7x3)",,,,,,,,"n/guarddogs{name=""Guard dogs""}(5x1)",~,~,~,~,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,`,,`,~,`,,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,n/guarddogs(5x1),~,~,~,~,,,,,,,,,,,`,,` +,,,`,,`,,`,"n{name=""Nestbox 8""}(1x1)","n{name=""Nestbox 9""}(1x1)","n{name=""Nestbox 10""}(1x1)","n{name=""Nestbox 11""}(1x1)","n{name=""Nestbox 12""}(1x1)","n{name=""Nestbox 13""}(1x1)","n{name=""Nestbox 14""}(1x1)",`,,,,,,`,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,m/welcome(7x1),,,,,,,`,,` +,,,`,,`,"B{name=""Surface barracks""}",B,B,B,B,B,B,B,`,,,,,,,,`,"m/welcome{name=""Welcome area/wagon parking lot""}(8x5)",,,,,,,,`,,` +,,,`,,`,B,B,B,B,B,B,B,B,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,B,B,B,B,B,B,B,B,,,,,"n{name=""Siege bait pasture""}",,,,,,,,,,,,,`,,` +,,,`,,`,B,B,B,B,B,B,B,B,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,B,B,B,B,B,B,"n{name=""Prisoner processing pen""}(1x2)",B,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` + + + +#place label(surface_place_start) start(19; 19) hidden() starting stockpiles + + + +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,"hlr{name=""Starting cloth/trash"" containers=0}(15x2)",,,,,,,,,,,,,,,,"gunzSpd{name=""Starting misc"" containers=0}(9x4)",,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,"w{name=""Starting wood""}(4x4)",,,,~,~,~,,"s2{name=""Starting stone""}:=otherstone(7x3)",,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,~,~,~,,,,,,,,,,"f{name=""Starting food""}(9x2)",,,,,,,,,`,,` +,,,`,,`,,,,,~,~,~,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,~,~,~,~,~,~,~,~,~,`,,` +,,,`,,`,,,,,~,~,~,,~,~,~,,~,~,~,,~,~,~,~,~,~,~,~,~,`,,` +,,,`,,`,~,~,~,,~,~,~,,~,~,~,,~,~,~,,~,~,~,~,~,~,~,~,~,`,,` +,,,`,,`,~,~,~,,~,~,~,,~,~,~,,~,~,~,,~,~,~,~,~,~,~,~,~,`,,` +,,,`,,`,~,~,~,,,,,,,,,,,,,,~,~,~,~,~,~,~,~,~,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,`,,`,~,`,,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` + + + +#build label(surface_build_start) start(19; 19) hidden() starting workshops + + + +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,~,~,~,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,~,"wt{name=""Starter mechanic's"" do_now=true}",~,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,~,~,~,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,~,~,~,,~,~,~,,~,~,~,,,,,,,,,,,`,,` +,,,`,,`,,,,,~,"wc{name=""Starter carpenter"" do_now=true}",~,,~,"wr{name=""Starter craftsdwarf's"" do_now=true}",~,,~,"wm{name=""Starter stoneworker's"" do_now=true max_general_orders=2}",~,,,,,,,,,,,`,,` +,,,`,,`,,,,,~,~,~,,~,~,~,,~,~,~,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,`,N{do_now=true},N{do_now=true},,,,,,`,,,,,,`,,,,~,~,~,~,~,,`,,` +,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,~,~,~,~,~,,`,,` +,,,`,,`,,,,,,,,,,`,,`,~,`,,`,,,,~,~,D{do_now=true},~,~,,`,,` +,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,~,~,~,~,~,,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,~,~,~,~,~,,`,,` +,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` + + + +#dig label(surface_channel) start(19; 19) hidden() channel miasma vents + + + +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,h1,`,`,`,`,`,`,,`,,`,`,`,`,`,h1,`,`,`,h1,`,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,`,,`,~,`,,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,h1,,,,,,h1,`,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,h1,h1,,,,,,h1,h1,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,h1,h1,,h1,h1,h1,,h1,h1,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,h1,h1,h1,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,h1,,,h1,h1,h1,,,h1,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,,,,,,,,,,,,,,h1,,,,,,,,,,,,,,,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` + + + +#dig label(surface_clear) start(19; 19) hidden() clear trees so the farming level can be dug without fear of generating surface holes + + +,,,t1(31x29) +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,`,`,,`,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,`,,`,~,`,,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` + +,,,,,,,,,,,,,,,t1,t1,t1,t1,t1,t1,t1 + +#build label(surface_cover_vents) start(19; 19) hidden() cover the miasma vents + + + +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,Cw,`,`,`,`,`,`,,`,,`,`,`,`,`,Cw,`,`,`,Cw,`,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,`,,`,~,`,,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,Cf,,,,,,Cf,`,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,Cf,Cf,,,,,,Cf,Cf,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,Cf,Cf,,Cf,Cf,Cf,,Cf,Cf,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,Cf,Cf,Cf,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,Cw,,,Cf,Cf,Cf,,,Cw,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,,,,,,,,,,,,,,Cf,,,,,,,,,,,,,,,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` + + + +#build label(surface_cover_stairs) start(19; 19) hidden() protect the central stairs + + + +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,Cw,Cw,Cf,Cw,Cf,Cw,Cw,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,`,,,,,,,,Cw,,,,,,Cw,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,Cf,,`,`,`,,Cf,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,Cw,,H,~,H,,Cw,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,Cf,,`,`,`,,Cf,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,Cw,,,,,,Cw,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,,`,`,Cw,Cw,Cf,Cw,Cf,Cw,Cw,`,`,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` + + + +#build label(surface_stairs_doors) start(19; 19) hidden() + + + +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,Cr{do_now=true},,,,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,d,`,d,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,d,,`,`,`,,d,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,`,,`,`,`,,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,d,,`,`,`,,d,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,,`,`,`,`,d,`,d,`,`,`,`,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` + + + +#< + + + +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,Cf{do_now=true},`,Cf,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,`,,,,,,,,`,Cf,Cf{do_now=true},Cf,Cf,Cf,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,Cf{do_now=true},Cf{do_now=true},Cf{do_now=true},Cf,Cf,Cf,Cf,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,`,Cf,Cf,Cf,Cf,Cf,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,Cf{do_now=true},Cf,Cf,Cf,Cf,Cf,Cf,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,`,Cf,Cf,Cf,Cf,Cf,`,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,,`,`,`,`,Cf,`,Cf,`,`,`,`,,`,`,`,`,`,`,`,,` +,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` + + + +#build label(surface_pre_building) start(19; 19) hidden() flooring and anchoring walls for future buildings/doors +#< + + + +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,~,,,,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,~,`,~,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,`,,,,,,,,`,~,~,~,~,~,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,~,~,~,~,~,~,~,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,`,~,~,~,~,~,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,Cf{do_now=true},Cf{do_now=true},Cf{do_now=true},~,~,~,~,~,~,~,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,Cf{do_now=true},,,`,~,~,~,~,~,`,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,Cf{do_now=true},`,`,`,`,~,`,~,`,`,`,`,,,,,,,,`,,` +,,,`,,`,Cf{do_now=true},Cf{do_now=true},Cf{do_now=true},Cf{do_now=true},Cf{do_now=true},Cf{do_now=true},Cf{do_now=true},,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,,,,,,,Cf{do_now=true},,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,Cf{do_now=true},,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,Cf{do_now=true},,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,Cf{do_now=true},Cf{do_now=true},Cf{do_now=true},Cf{do_now=true},Cf{do_now=true},Cf{do_now=true},Cf{do_now=true},,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` + + + +#> + + + +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,`,~,~,N,N,N,N,N,`,Cf,,Cf,,Cf,`,Cf,Cf,,~,~,~,~,~,,`,,` +,,,`,,`,,Cw,,,,,,,,,,`,`,`,,,Cf,Cf,,~,~,~,~,~,,`,,` +,,,`,,`,,Cf,,,,,,,,`,,`,`,`,,`,Cf,Cf,,~,~,~,~,~,,`,,` +,,,`,,`,,Cw,,,,,,,,,,`,`,`,,,Cf,Cf,,~,~,~,~,~,,`,,` +,,,`,,`,,`,,,,,,,,`,Cf,Cf,Cf,Cf,Cf,`,Cf,Cf,,~,~,~,~,~,,`,,` +,,,`,,`,`,`,`,`,`,Cw,Cf,Cw,`,`,`,,`,,`,`,`,`,,,,,,,,`,,` +,,,`,,`,Cf,Cf,Cf,Cf,Cf,,,,`,~,Cf,Cf,Cf,Cf,Cf,~,`,,,,,,,,,`,,` +,,,`,,`,Cf,Cf,Cf,Cf,Cf,,,,~,~,Cf,Cf,Cf,Cf,Cf,~,~,,,,,,,,,`,,` +,,,`,,`,Cf,Cf,,,,,,,~,~,,~,~,~,,~,~,,,,,,,,,`,,` +,,,`,,`,Cf,Cf,Cf,Cf,Cf,,Cf,,Cf,Cf,,~,~,~,,Cf,Cf,,,,,,,,,`,,` +,,,`,,`,Cf,Cf,Cf,Cf,Cf,,Cf,,`,,,~,~,~,,,`,Cf,,Cf,,,Cf,,Cf,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` +,,,`,Cf,Cf,,,,,,,,Cf,Cf,,,,~,,,,Cf,Cf,,,,,,,,Cf,Cf,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,`,`,`,`,`,`,`,`,`,`,` + + + +#dig label(surface_traffic) start(19; 19) hidden() set traffic designations + + + +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,`,,`,`,`,,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,or,`,`,`,`,,`,,`,`,`,`,,,,,,,,`,,` +,,,`,,`,,,,,,,,or,`,or,or,ol,ol,ol,ol,,`,,,,,,,,,`,,` +,,,`,,`,,,,,,,,or,ol,ol,or,ol,ol,ol,ol,ol,ol,,,,,,,,,`,,` +,,,`,,`,,,,,,,,or,ol,ol,or,,,,,ol,ol,,,,,,,,,`,,` +,,,`,,`,,,,,,,,or,ol,ol,or,,,,,ol,ol,,,,,,,,,`,,` +,,,`,,`,,,,,,,,or,`,or,or,,,,,,`,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,ol,ol,ol,ol,ol,ol,ol,`,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,,,,,ol,ol,ol,ol,ol,ol,ol +,,,,,,,,,,,,,,,ol,ol,ol,ol,ol,ol,ol + +"#place label(surface_place) start(19; 19) hidden() message(Remember to assign minecarts to the trade goods and prisoner processing quantum stockpiles (run ""assign-minecarts all""). +Feel free to adjust the configuration of the ""trade goods"" feeder stockpile so it accepts the item types you want to trade away. If those items types are also accepted by other stockpiles, configure those stockpiles to give to the ""trade goods"" stockpile. +The inorganic trade goods stockpile is set to autotrade, but you can toggle that according to your preference.) remaining surface stockpiles" + + + +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,"a10{name=""Pets/Prisoner feeder"" autotrain=true}(9x5)",,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,"c{name=""Organic trade goods quantum"" quantum=true}:+all",,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,,`,`,`,,,"g{name=""Trade goods"" containers=0}:-cat_finished_goods/type/,core/artifact+crafts(2x3)",,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,`,,`,`,`,,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,"c{name=""Inorganic trade goods quantum"" autotrade=true quantum=true}:+all-organic",,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,"a{name=""Prisoner/cage quantum"" autotrain=true quantum=true}",,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` + + + +"#build label(surface_build) start(19; 19) hidden() message(Use autofarm to manage farm crop selection. +Remember to connect the levers to the gates once they are built.) gates, barracks, farm area, and trade area" + + + +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,~,~,~,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,~,"ww{name=""Milking/shearing station"" labor=""Milking, Shearing""}",~,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,~,~,~,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,~h{do_install=true do_gather=true}(1x1),`,~,~,~,~,~,~,~,`,"Tl{name=""Barracks gate"" do_now=true}",,"Tl{name=""Inner main gate"" do_now=true}",,"Tl{name=""Trade depot gate"" do_now=true}",`,"trackstopE{name=""Organic trade goods dumper"" take_from=""Trade goods"" route=""Organic trade goods quantum""}",,,~,~,~,~,~,,`,,` +,,,`,,`,~h{do_install=true do_gather=true}(1x1),`,p(1x1),p(1x1),p(1x1),p(1x1),p(1x1),p(1x1),p(1x1),,,`,`,`,,,,,,~,~,~,~,~,,`,,` +,,,`,,`,"~h{name=""reserved for splitting"" do_install=true}(1x1)",d,p(1x1),p(1x1),p(1x1),p(1x1),p(1x1),p(1x1),p(1x1),`,,`,`,`,,`,,,,~,~,~,~,~,,`,,` +,,,`,,`,~h{do_install=true do_gather=true}(1x1),`,p(1x1),p(1x1),p(1x1),p(1x1),p(1x1),p(1x1),p(1x1),,,`,`,`,,,,,,~,~,~,~,~,,`,,` +,,,`,,`,~h{do_install=true do_gather=true}(1x1),`,N,N,N,N,N,N,N,`,"Tl{name=""Left outer gate"" do_now=true}(1x1)","Tl{name=""Left inner gate"" do_now=true}(1x1)","Tl{name=""Outer main gate"" do_now=true}(1x1)","Tl{name=""Right inner gate"" do_now=true}(1x1)","Tl{name=""Right outer gate"" do_now=true}(1x1)",`,"trackstopE{name=""Inorganic trade goods dumper"" take_from=""Trade goods,Organic trade goods quantum"" route=""Inorganic trade goods quantum""}:-organic",,,~,~,~,~,~,,`,,` +,,,`,,`,`,`,`,`,`,`,d,`,`,`,`,,`,,`,`,`,`,,,,,,,,`,,` +,,,`,,`,b,b,b,b,b,,,,`,,"gw{name=""Inner main gate"" do_now=true}",gw,gw,gw,gw,,`,,,,,,,,,`,,` +,,,`,,`,h,h,h,h,h,,,,"ga{name=""Barracks gate"" do_now=true}",ga,gw,gw,gw,gw,gw,"gd{name=""Trade depot gate"" do_now=true}",gd,,,,,,,,,`,,` +,,,`,,`,a,r,,,,,,,ga,ga,,,,,,gd,gd,,,,,,,,,`,,` +,,,`,,`,h,h,h,h,h,,"trackstopS{name=""Prisoner/cage dumper"" take_from=""Pets/Prisoner feeder"" route=""Prisoner/cage quantum""}:-cat_animals/tameable",,ga,ga,,,,,,gd,gd,,,,,,,,,`,,` +,,,`,,`,b,b,b,b,b,,,,`,,,,,,,,`,s,,s,,,s,,s,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` +,,,`,"gd{name=""Left outer gate"" do_now=true}",gd,,,,,,,,"gd{name=""Left inner gate"" do_now=true}",gd,,,,,,,,"ga{name=""Right inner gate"" do_now=true}",ga,,,,,,,,"ga{name=""Right outer gate"" do_now=true}",ga,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,"gw{name=""Outer main gate"" do_now=true}",gw,gw,gw,gw,gw,gw,`,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,,,,,gw,gw,gw,gw,gw,gw,gw +,,,,,,,,,,,,,,,gw,gw,gw,gw,gw,gw,gw + +#dig label(surface_clear_large) start(19; 19) hidden() clear wider area of trees +t1(37x33) + + +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,`,,`,~,`,,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` + + + +#build label(surface_walls) start(19; 19) hidden() build remaining walls + + + +,,,`,,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,,` +,,,`,,Cw,,,,,,,,,,,,,,,,,,,,,,,,,,Cw,,` +,,,`,,Cw,,,,,,,,,,,,,,,,,,,,,,,,,,Cw,,` +,,,`,,Cw,,,,,,,,,,,,,,,,,,,,,,,,,,Cw,,` +,,,`,,Cw,,,,,,,,,,,,,,,,,,,,,,,,,,Cw,,` +,,,`,,Cw,,,,,,,,,,,,,,,,,,,,,,,,,,Cw,,` +,,,`,,Cw,,,,,,,,,,,,,,,,,,,,,,,,,,Cw,,` +,,,`,,Cw,,,,,,,,,,,,,,,,,,,,,,,,,,Cw,,` +,,,`,,Cw,,,,,,,,,,,,,,,,,,,,,,,,,,Cw,,` +,,,`,,Cw,,,,,,,,,,,,,,,,,,,,,,,,,,Cw,,` +,,,`,,Cw,,,,,,,,,,,,,,,,,,,,,,,,,,Cw,,` +,,,`,,Cw,,,,,,,,,,,,,,,,,,,,,,,,,,Cw,,` +,,,`,,Cw,Cw,Cw,Cw,Cw,~,Cw,Cw,Cw,Cw,~,~,,~,,~,~,Cw,Cw,Cw,~,Cw,Cw,Cw,~,Cw,Cw,,` +,,,`,,Cw,,Cw,,,,,,,,~,,,,,,~,,,,,,,,,,Cw,,` +,,,`,,Cw,,~,,,,,,,,,,`,`,`,,,,,,,,,,,,Cw,,` +,,,`,,Cw,,,,,,,,,,~,,`,`,`,,~,,,,,,,,,,Cw,,` +,,,`,,Cw,,~,,,,,,,,,,`,`,`,,,,,,,,,,,,Cw,,` +,,,`,,Cw,,Cw,,,,,,,,~,,,,,,~,,,,,,,,,,Cw,,` +,,,`,,Cw,Cw,Cw,Cw,Cw,Cw,~,,~,Cw,~,~,,~,,~,~,Cw,Cw,,,,,,,,Cw,,` +,,,`,,Cw,,,,,,,,,Cw,,,,,,,,Cw,,,,,,,,,Cw,,` +,,,`,,Cw,,,,,,,,,,,,,,,,,,,,,,,,,,Cw,,` +,,,`,,Cw,,,,,,,,,,,,,,,,,,,,,,,,,,Cw,,` +,,,`,,Cw,,,,,,,,,,,,,,,,,,,,,,,,,,Cw,,` +,,,`,,Cw,,,,,,,,,~,,,,,,,,~,,,,,,,,,Cw,,` +,,,`,,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,,,,,,,,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,,` +,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,`,`,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,,,,,,,,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,`,` + + + +#build label(surface_floors) start(19; 19) hidden() build remaining flooring + + + +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,~,`,~,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,`,,,,,,,,`,~,Cf,~,Cf,~,`,~,~,Cf,~,~,~,~,~,Cf,`,,` +,,,`,,`,,`,,,,,,,,~,Cf,Cf,Cf,Cf,Cf,~,~,~,Cf,~,~,~,~,~,Cf,`,,` +,,,`,,`,,~,,,,,,,,`,Cf,`,Cf,`,Cf,`,~,~,Cf,~,~,~,~,~,Cf,`,,` +,,,`,,`,,`,,,,,,,,~,Cf,Cf,Cf,Cf,Cf,~,~,~,Cf,~,~,~,~,~,Cf,`,,` +,,,`,,`,,`,,,,,,,,`,~,~,~,~,~,`,~,~,Cf,~,~,~,~,~,Cf,`,,` +,,,`,,`,`,`,`,`,`,`,~,`,`,`,`,~,`,~,`,`,`,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` +,,,`,,`,~,~,~,~,~,Cf,Cf,Cf,`,~,~,~,~,~,~,~,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` +,,,`,,`,~,~,~,~,~,Cf,Cf,Cf,~,~,~,~,~,~,~,~,~,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` +,,,`,,`,~,~,Cf,Cf,Cf,Cf,Cf,Cf,~,~,Cf,~,~,~,Cf,~,~,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` +,,,`,,`,~,~,~,~,~,Cf,~,Cf,~,~,Cf,~,~,~,Cf,~,~,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` +,,,`,,`,~,~,~,~,~,Cf,~,Cf,`,Cf,Cf,~,~,~,Cf,Cf,`,~,Cf,~,Cf,Cf,~,Cf,~,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,`,`,`,`,`,`,`,`,`,,` +,,,`,~,,,,,,,,,,,Cf,Cf,Cf,~,Cf,Cf,Cf,,,,,,,,,,,~,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` + + + +#build label(surface_traps) start(19; 19) hidden() + +,,,,,Tc,,,,,,,,,,,,,,,,,,,,,,,,,,Tc +,,,,,Tc,,,,,,,,,,,,,,,,,,,,,,,,,,Tc +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,`,,`,`,`,,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,,Tc,Tc,Tc,Tc,Tc,Tc,Tc,,,,,,,,,,,,Tc,Tc,Tc,Tc,Tc,Tc,Tc,,,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,,,Tc,Tc,,,,,,,,Tc,Tc +,,,,,,,,,,,,,Tc,Tc,,,,,,,,Tc,Tc + +#burrow label(surface_burrows) start(19; 19) hidden() extend safety burrow to newly safe surface areas and set up surrounding clearcutting area + + +,,,,"a{name=""Clearcutting area"" create=true autochop_clear=true}(-12x-10)","a{name=""Clearcutting area"" create=true autochop_clear=true}(28x-10)",,,,,,,,,,,,,,,,,,,,,,,,,,,"a{name=""Clearcutting area"" create=true autochop_clear=true}(12x-10)" +,,,`,"a{name=""Clearcutting area"" create=true autochop_clear=true}(-12x27)",`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,"a{name=""Clearcutting area"" create=true autochop_clear=true}(12x27)",` +,,,`,,`,a{name=Inside+}(25x17),,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,`,`,,`,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,`,,~,,~,,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` +,,,`,,a{name=Inside+}(8x7),`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,a{name=Inside+}(8x7),,,,,,,`,,` +,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,,,"a{name=""Clearcutting area"" create=true autochop_clear=true}(-12x10)","a{name=""Clearcutting area"" create=true autochop_clear=true}(28x10)",,,,,,,,,,,,,,,,,,,,,,,,,,,"a{name=""Clearcutting area"" create=true autochop_clear=true}(12x10)" + + +#build label(surface_roof) start(19; 19) hidden() roof hatch and adjacent tiles + + + +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,Cf,,Cf,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,Cf,"H{name=""Roof access""}",Cf,,,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,~,`,~,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,Cf,`,,,,,,,,`,~,~,~,~,~,`,,,,,,,,,,`,,` +,,,`,,`,Cf,`,,,,,,,,~,~,~,~,~,~,~,,,,,,,,,,`,,` +,,,`,,`,Cf,Cf,,,,,,,,`,~,~,~,~,~,`,,,,,,,,,,`,,` +,,,`,,`,Cf,`,,,,,~,~,~,~,~,~,~,~,~,~,,,,,,,,,,`,,` +,,,`,,`,Cf,`,,,,,~,,,`,~,~,~,~,~,`,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,~,`,`,`,`,~,`,~,`,`,`,`,,,,,,,,`,,` +,,,`,,`,~,~,~,~,~,~,~,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,,,,,,,~,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,~,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,~,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,~,~,~,~,~,~,~,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` + + + +#build label(surface_roof2) start(19; 19) hidden() lower half of the roof + + + +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,~,,~,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,~,~,~,,,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,~,`,~,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,~,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,~,~,~,~,~,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` +,,,`,,`,~,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,~,~,~,~,~,~,~,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` +,,,`,,`,~,~,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,~,~,~,~,~,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` +,,,`,,`,~,`,Cf,Cf,Cf,Cf,~,~,~,~,~,~,~,~,~,~,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` +,,,`,,`,~,`,Cf,Cf,Cf,Cf,~,Cf,Cf,`,~,~,~,~,~,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` +,,,`,,`,`,`,`,`,`,`,~,`,`,`,`,~,`,~,`,`,`,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` +,,,`,,`,~,~,~,~,~,~,~,Cf,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` +,,,`,,`,Cf,Cf,Cf,Cf,Cf,Cf,~,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` +,,,`,,`,Cf,Cf,Cf,Cf,Cf,Cf,~,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` +,,,`,,`,Cf,Cf,Cf,Cf,Cf,Cf,~,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` +,,,`,,`,~,~,~,~,~,~,~,Cf,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,`,`,`,`,`,`,`,`,`,`,` + + + +#build label(surface_roof3) start(19; 19) hidden() upper half center of the roof + + + +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,,`,,` +,,,`,,`,,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,,`,,` +,,,`,,`,,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,,`,,` +,,,`,,`,,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,,`,,` +,,,`,,`,,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,,`,,` +,,,`,,`,,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,,`,,` +,,,`,,`,,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,,`,,` +,,,`,,`,,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,,`,,` +,,,`,,`,,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,~,Cf,~,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,,`,,` +,,,`,,`,,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,~,~,~,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,~,`,~,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,~,`,~,~,~,~,~,~,~,`,~,~,~,~,~,`,~,~,~,~,~,~,~,~,~,`,,` +,,,`,,`,~,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,,` +,,,`,,`,~,~,~,~,~,~,~,~,~,`,~,~,~,~,~,`,~,~,~,~,~,~,~,~,~,`,,` +,,,`,,`,~,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,,` +,,,`,,`,~,`,~,~,~,~,~,~,~,`,~,~,~,~,~,`,~,~,~,~,~,~,~,~,~,`,,` +,,,`,,`,`,`,`,`,`,`,~,`,`,`,`,~,`,~,`,`,`,`,~,~,~,~,~,~,~,`,,` +,,,`,,`,~,~,~,~,~,~,~,~,`,~,~,~,~,~,~,~,`,~,~,~,~,~,~,~,~,`,,` +,,,`,,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,,` +,,,`,,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,,` +,,,`,,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,,` +,,,`,,`,~,~,~,~,~,~,~,~,`,~,~,~,~,~,~,~,`,~,~,~,~,~,~,~,~,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,~,~,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,`,` + + + +#build label(surface_roof4) start(19; 19) hidden() upper half remainder of the roof + + + +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` +,,,`,,`,Cf,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,Cf,`,,` +,,,`,,`,Cf,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,Cf,`,,` +,,,`,,`,Cf,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,Cf,`,,` +,,,`,,`,Cf,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,Cf,`,,` +,,,`,,`,Cf,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,Cf,`,,` +,,,`,,`,Cf,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,Cf,`,,` +,,,`,,`,Cf,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,Cf,`,,` +,,,`,,`,Cf,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,Cf,`,,` +,,,`,,`,Cf,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,Cf,`,,` +,,,`,,`,Cf,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,Cf,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,~,`,~,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,~,`,~,~,~,~,~,~,~,`,~,~,~,~,~,`,~,~,~,~,~,~,~,~,~,`,,` +,,,`,,`,~,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,,` +,,,`,,`,~,~,~,~,~,~,~,~,~,`,~,~,~,~,~,`,~,~,~,~,~,~,~,~,~,`,,` +,,,`,,`,~,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,,` +,,,`,,`,~,`,~,~,~,~,~,~,~,`,~,~,~,~,~,`,~,~,~,~,~,~,~,~,~,`,,` +,,,`,,`,`,`,`,`,`,`,~,`,`,`,`,~,`,~,`,`,`,`,~,~,~,~,~,~,~,`,,` +,,,`,,`,~,~,~,~,~,~,~,~,`,~,~,~,~,~,~,~,`,~,~,~,~,~,~,~,~,`,,` +,,,`,,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,,` +,,,`,,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,,` +,,,`,,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,,` +,,,`,,`,~,~,~,~,~,~,~,~,`,~,~,~,~,~,~,~,`,~,~,~,~,~,~,~,~,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,~,~,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,`,` + + + +#build label(surface_corridor_gates) start(19; 19) hidden() message(Remember to connect the levers to the new external trap gates.) gates for the longer trap hallways + + +,,,,"gx{name=""Left trap gate"" do_now=true}",,,,,,,,,,,,,,,,,,,,,,,,,,,,"gx{name=""Right trap gate"" do_now=true}" +,,,`,gx,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,gx,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,`,"Tl{name=""Left trap gate"" do_now=true}",`,`,`,"Tl{name=""Right trap gate"" do_now=true}",`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` + + + +#build label(surface_corridor) start(19; 19) hidden() longer trap hallway walls + + +,,,,~,,,,,,,,,,,,,,,,,,,,,,,,,,,,~ +,,,Cw,~,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,~,Cw +,,,Cw,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,Cw +,,,Cw,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,Cw +,,,Cw,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,Cw +,,,Cw,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,Cw +,,,Cw,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,Cw +,,,Cw,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,Cw +,,,Cw,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,Cw +,,,Cw,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,Cw +,,,Cw,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,Cw +,,,Cw,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,Cw +,,,Cw,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,Cw +,,,Cw,,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,Cw +,,,Cw,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,Cw +,,,Cw,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,Cw +,,,Cw,,`,,,,,,,,,,`,~,`,`,`,~,`,,,,,,,,,,`,,Cw +,,,Cw,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,Cw +,,,Cw,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,Cw +,,,Cw,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,,,,,,,`,,Cw +,,,Cw,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,Cw +,,,Cw,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,Cw +,,,Cw,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,Cw +,,,Cw,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,Cw +,,,Cw,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,Cw +,,,Cw,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,Cw +,,,Cw,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cw +,,,Cw,Cw,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,Cw,Cw + + + +#< + + + +,,,`,Cf,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,Cf,` +,,,`,Cf,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,Cf,` +,,,`,Cf,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,Cf,` +,,,`,Cf,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,Cf,` +,,,`,Cf,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,Cf,` +,,,`,Cf,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,Cf,` +,,,`,Cf,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,Cf,` +,,,`,Cf,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,Cf,` +,,,`,Cf,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,Cf,` +,,,`,Cf,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,Cf,` +,,,`,Cf,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,Cf,` +,,,`,Cf,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,Cf,` +,,,`,Cf,`,`,`,`,`,`,`,`,`,`,`,`,~,`,~,`,`,`,`,`,`,`,`,`,`,`,`,Cf,` +,,,`,Cf,`,~,`,~,~,~,~,~,~,~,`,~,~,~,~,~,`,~,~,~,~,~,~,~,~,~,`,Cf,` +,,,`,Cf,`,~,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,Cf,` +,,,`,Cf,`,~,~,~,~,~,~,~,~,~,`,~,~,~,~,~,`,~,~,~,~,~,~,~,~,~,`,Cf,` +,,,`,Cf,`,~,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,Cf,` +,,,`,Cf,`,~,`,~,~,~,~,~,~,~,`,~,~,~,~,~,`,~,~,~,~,~,~,~,~,~,`,Cf,` +,,,`,Cf,`,`,`,`,`,`,`,~,`,`,`,`,~,`,~,`,`,`,`,~,~,~,~,~,~,~,`,Cf,` +,,,`,Cf,`,~,~,~,~,~,~,~,~,`,~,~,~,~,~,~,~,`,~,~,~,~,~,~,~,~,`,Cf,` +,,,`,Cf,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,Cf,` +,,,`,Cf,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,Cf,` +,,,`,Cf,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,Cf,` +,,,`,Cf,`,~,~,~,~,~,~,~,~,`,~,~,~,~,~,~,~,`,~,~,~,~,~,~,~,~,`,Cf,` +,,,`,Cf,`,`,`,`,`,`,`,`,`,`,~,~,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,Cf,` +,,,`,Cf,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,Cf,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,`,` + + + +#build label(surface_corridor_traps) start(19; 19) hidden() traps for the longer trap hallways + + +,,Tc,Tc,~,,,,,,,,,,,,,,,,,,,,,,,,,,,,~,Tc,Tc +,,Tc,`,~,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,~,`,Tc +,,,`,Tc,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,Tc,` +,,,`,Tc,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,Tc,` +,,,`,Tc,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,Tc,` +,,,`,Tc,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,Tc,` +,,,`,Tc,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,Tc,` +,,,`,Tc,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,Tc,` +,,,`,Tc,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,Tc,` +,,,`,Tc,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,Tc,` +,,,`,Tc,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,Tc,` +,,,`,Tc,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,Tc,` +,,,`,Tc,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,Tc,` +,,,`,Tc,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,Tc,` +,,,`,Tc,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,Tc,` +,,,`,Tc,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,Tc,` +,,,`,Tc,`,,,,,,,,,,`,~,`,`,`,~,`,,,,,,,,,,`,Tc,` +,,,`,Tc,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,Tc,` +,,,`,Tc,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,Tc,` +,,,`,Tc,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,,,,,,,`,Tc,` +,,,`,Tc,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,Tc,` +,,,`,Tc,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,Tc,` +,,,`,Tc,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,Tc,` +,,,`,Tc,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,Tc,` +,,,`,Tc,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,Tc,` +,,,`,Tc,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,Tc,` +,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,Tc,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,Tc +,,Tc,Tc,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Tc,Tc + + +#notes label(farming_help) farming level walkthrough +"Sets up farming, food storage, and related industries. Also provides post-embark necessities that can later be disassembled." +Screenshot: https://drive.google.com/file/d/1vDaedLcgoexUdKREUz75ZXQi0ZSdwWwj +"" +Features: +- Pairs with the surface blueprints for vents that prevent miasma +- Farm plots (can be managed by DFHack autofarm) +- Plentiful food storage +- Refuse/corpse quantum stockpile +"- Starter dormitory, dining room, and tomb for use until more permanent versions are ready" +- Offices for your manager and bookkeeper +"" +Workshops: +- Kitchen +- Brewery +- Butcher +- Fishery +- Tannery +- Farmer's Workshop +- Quern +- Screw Press +"" +Manual steps you have to take: +"- Assign a minecart to your refuse quantum stockpile hauling route (you can run ""assign-minecarts all"" to do this)" +"" +Farming Walkthrough: +"1) Wait until you have channeled the miasma vents and cleared trees on the surface before digging out the farming level on the z-level below the surface, otherwise you will end up with extra ramps on the farming level and unprotected holes through the surface when you later chop down trees growing above empty space." +"" +2) Start digging with /farming1 and get started on manufacturing furniture by generating manager orders for /farming2 (if you haven't already preordered with the checklist command). +"" +"3) Once the level is dug out, run /farming2 to designate zones, build workshops and stockpiles, and place furniture. Remember to assign a minecart to the newly-designated quantum refuse dump with assign-minecarts all." +"" +"4) Once your fort has enough free time to build the remaining doors, run /farming3. Generate manager orders for /farming3." +"" +"5) You can disassemble the dining room and dormitory once the services and apartments levels are up and running, if you like. Also, you can turn on seasonal fertilization for the farm plots if you need to boost your crop yields." +"#dig label(farming1) start(16; 18; central stairs) message(Once the area is dug out, continue with /farming2.)" +# this level is dug at priority 3 since it is dug in soil. it's worth the miner's time to +# stop digging the industry level and quickly dig out this one. +,,,,,,,,,3,3,3,,3,3,3,3,3,,3,3,3,3 +,,,,,,,,,3,3,3,,3,3,3,3,3,,3,3,3,3 +,,,,,,,,,3,3,3,,3,3,3,3,3,,3,3,3,3 +,,,,,,,,,,,3,,3,3,3,3,3,,3,3,3,3 +,,,,,,,3,3,3,,3,,3,3,3,3,3,,3,3,3,3 +,,,,,,,3,3,3,3,3,,3,3,3,3,3,,3,3,3,3 +,,,,,,,3,3,3,,3,,3,3,3,3,3,,3 +,,,,,,,,,,,3,,3,3,3,3,3,,3,,3,3,3 +,,,,,,3,3,3,3,,3,,3,3,3,3,3,,3,3,3,3,3 +,,,,,,3,3,3,3,,3,,3,3,3,3,3,,3,,3,3,3 +,,,3,3,,3,3,3,3,,3,,3,3,3,3,3,,3 +,,3,3,3,,3,3,3,3,,3,,3,3,3,3,3,,3,,3,3,3,,3,3,3 +,,3,3,3,3,3,z3,2,2,2,2,,,3,,3,,,2,2,2,z3,2,2,2,z3,3 +,,,3,3,,3,3,3,3,,2,2,2,2,2,2,2,2,2,,3,3,3,,3,3,3 +,,,,3,,,3,,,,,,2,`,`,`,2,,,,,3,,,,3 +,,3,3,3,3,3,3,3,3,3,3,,2,`,~,`,2,,3,3,3,3,3,3,3,3,3,3 +,,3,3,3,3,3,3,3,3,3,3,3,2,`,`,`,2,3,3,3,3,3,3,3,3,3,3,3 +,,3,3,3,3,3,3,3,3,3,3,,2,2,2,2,2,,3,3,3,3,3,3,3,3,3,3 +,,3,3,3,3,3,3,3,3,3,,,,2,,2,,,,3,3,3,3,3,3,3,3,3 +,,3,3,3,3,3,3,3,3,,,z3,2,2,2,2,2,z3,,,3,3,3,3,3,3,3,3 +,,3,3,3,3,3,3,3,3,,z3,z3,,,2,,,z3,z3,,3,3,3,3,3,3,3,3 +,,3,3,3,3,3,3,3,,,z3,z3,,z3,z3,z3,,z3,z3,,,3,3,3,3,3,3,3 +,,3,3,3,3,3,3,3,,3,2,3,,z3,z3,z3,,3,2,3,,3,3,3,3,3,3,3 +,,3,3,3,3,3,3,3,,3,z3,3,,z3,z3,z3,,3,z3,3,,3,3,3,3,3,3,3 +,,3,3,3,3,3,3,3,,3,3,3,,,2,,,3,3,3,,3,3,3,3,3,3,3 +,,,,,,,,,,,,,,,z3 + + +"#meta label(farming2) start(central stairs) message(If you preordered items on the checklist, good. If not, don't forget to generate orders for this blueprint now. +Once furniture has been placed, continue with /farming3.) workshops, stockpiles, and important furniture" +zone/farming_zone +place/farming_place +build/farming_build +traffic/farming_traffic +burrow/farming_burrow +"" +#meta label(farming3) start(central stairs) message(Remember to enqueue manager orders for this blueprint.) build remaining doors +doors/farming_doors +#zone label(farming_zone) start(16; 18) hidden() rooms + + +,,,,,,,,,T{pets=true}(1x1),`,`,,`,`,`,`,`,,"h{name=""Starter dining hall""}(4x6)",,,` +,,,,,,,,,T{pets=true}(1x1),`,`,,`,`,`,`,`,,`,`,`,` +,,,,,,,,,T{pets=true}(1x1),`,`,,`,`,`,`,`,,`,`,`,` +,,,,,,,,,,,`,,`,`,`,`,`,,`,`,`,` +,,,,,,,"o{name=""Manager's office"" assigned_unit=manager}(3x1)",,`,,`,,`,`,`,`,`,,`,`,`,` +,,,,,,,`,`,`,`,`,,`,`,`,`,`,,`,`,`,` +,,,,,,,"o{name=""Bookkeeper's office"" assigned_unit=bookkeeper}(3x1)",,`,,`,,`,`,`,`,`,,` +,,,,,,,,,,,`,,`,`,`,`,`,,`,,"D{name=""Starter dormitory""}(3x3)",,` +,,,,,,`,`,`,`,,`,,`,`,`,`,`,,`,`,`,`,` +,,,,,,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,` +,,,`,`,,`,`,`,`,,`,,`,`,`,`,`,,` +,,`,`,`,,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,,`,`,` +,,`,`,`,`,`,`,`,`,`,`,,,`,,`,,,`,`,`,`,`,`,`,`,` +,,,`,`,,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,,`,`,` +,,,,`,,,`,,,,,,`,`,`,`,`,,,,,`,,,,` +,,`,`,`,`,`,`,`,`,`,`,,`,`,~,`,`,,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,,,,`,,`,,,,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,,`,`,,,`,,,`,`,,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,,`,`,`,,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,`,`,,,`,,,`,`,`,,`,`,`,`,`,`,` +,,,,,,,,,,,,,,,` + + +"#place label(farming_place) start(16; 18) hidden() message(remember to assign a minecart to the refuse quantum stockpile (run ""assign-minecarts all"")" + + +,,,,,,,,,`,`,`,,`,`,`,"c{name=""Seeds"" barrels=10 links_only=true take_from=""Starting food""}:+seeds(1x9)","c{name=""Potash""}:+potash(1x12)",,"c{name=""Booze"" barrels=-1 take_from=""Starting food""}:+booze(4x2)",,,` +,,,,,,,,,`,`,`,,`,`,`,`,`,,`,`,`,` +,,,,,,,,,`,`,`,,`,`,`,`,`,,`,`,`,` +,,,,,,,,,,,`,,`,`,`,`,`,,`,`,`,` +,,,,,,,`,`,`,,`,,`,`,`,`,`,,`,"c{name=""Prepared food"" take_from=""Starting food""}:+preparedmeals(3x2)",,` +,,,,,,,`,`,`,`,`,,`,`,`,`,`,,`,`,`,` +,,,,,,,`,`,`,,`,,`,`,`,`,`,,` +,,,,,,,,,,,`,,`,`,`,`,`,,`,,`,`,` +,,,,,,`,`,`,"u{name=""Pots"" take_from=""Starting misc""}:-cat_furniture/type+pots(1x4)",,`,,`,`,`,`,`,,`,`,`,`,` +,,,,,,`,`,`,~,,`,,"c{name=""Seeds feeder"" give_to=""Seeds"" take_from=""Starting food""}:+seeds(4x3)",,,,`,,`,,`,`,` +,,,"u{name=""Bags"" take_from=""Starting misc""}:-cat_furniture/type+bags(2x2)",~,,`,`,`,~,,`,,`,`,`,`,`,,` +,,`,~,~,,`,`,`,~,,`,,`,`,`,`,`,,`,,`,`,`,,`,`,` +,,`,"c{name=""Jugs"" take_from=""Starting misc"" give_to=""Cookable food""}:+cat_finished_goods/core,total+woodtools(2x2)",~,`,`,`,`,"u{name=""Barrels"" take_from=""Starting misc,Starting food""}:-cat_furniture/type+barrels(1x2)",`,`,,,`,,`,,,`,`,`,`,`,`,`,`,` +,,,~,~,,`,`,`,~,,`,`,`,`,`,`,`,`,`,,`,`,`,,`,`,` +,,,,`,,,`,,,,,,`,`,`,`,`,,,,,`,,,,` +,,"c{name=""Plants"" barrels=-1 take_from=""Starting food""}:+plants",c,c,c,c,c,c,c,c,c,,`,`,~,`,`,,"c{name=""Cookable food"" barrels=-1 take_from=""Starting food""}:+cat_food/meat/,fish/prepared/,egg/,cheese/,leaves/,powder/,glob/,liquid/plant/,paste/,pressed/,milk,royal_jelly-dye-cat_food/tallow,thread,liquid/misc/",c,c,c,c,c,c,c,c,c +,,c,c,c,c,c,c,c,c,c,c,`,`,`,`,`,`,`,c,c,c,c,c,c,c,c,c,c +,,c,c,c,c,c,c,c,c,c,c,,`,`,`,`,`,,c,c,c,c,c,c,c,c,c,c +,,c,c,c,c,c,c,c,c,c,,,,`,,`,,,,c,c,c,c,c,c,c,c,c +,,c,c,c,c,c,c,c,c,,,c,`,`,`,`,`,c,,,c,c,c,c,c,c,c,c +,,c,c,c,c,c,c,c,c,,"c{name=""Unprepared fish"" take_from=""Starting food""}:+unpreparedfish",c,,,`,,,"c{name=""Rawhides"" take_from=""Starting cloth/trash""}:+rawhides",c,,c,c,c,c,c,c,c,c +,,c,c,c,c,c,c,c,,,c,c,,"c{name=""Refuse feeder"" give_to=""Rawhides"" take_from=""Starting cloth/trash""}:+cat_refuse/type(1x3)","y2{name=""Corpse feeder"" take_from=""Starting cloth/trash""}:+cat_refuse/corpses,bodyparts(2x3)",~,,c,c,,,c,c,c,c,c,c,c +,,c,c,c,c,c,c,c,,`,`,`,,~,~,~,,`,`,`,,c,c,c,c,c,c,c +,,c,c,c,c,c,c,c,,`,`,`,,~,~,~,,`,`,`,,c,c,c,c,c,c,c +,,c,c,c,c,c,c,c,,`,`,`,,,`,,,`,`,`,,c,c,c,c,c,c,c +,,,,,,,,,,,,,,,"ry{name=""Refuse/corpse quantum"" give_to=""Rawhides"" quantum=true}" + + +#build label(farming_build) start(16; 18) hidden() workshops and important furniture + + +,,,,,,,,,n,`,`,,p(3x1),,,`,`,,`,`,`,` +,,,,,,,,,n,`,`,,p(3x1),,,`,`,,`,`,`,` +,,,,,,,,,n,`,`,,p(3x1),,,`,`,,c,t,t,c +,,,,,,,,,,,`,,p(3x1),,,`,`,,c,t,t,c +,,,,,,,t,c,`,,`,,p(3x1),,,`,`,,`,`,`,` +,,,,,,,`,`,`,`,`,,p(3x1),,,`,`,,`,`,`,` +,,,,,,,t,c,`,,`,,p(3x1),,,`,`,,` +,,,,,,,,,,,`,,p(3x1),,,`,`,,`,,b{do_now=true},b{do_now=true},b +,,,,,,`,`,`,`,,`,,p(3x1),,,`,`,,`,`,`,`,h +,,,,,,`,wl,`,`,,`,,`,`,`,`,`,,`,,b,b,b +,,,`,`,,`,`,`,`,,`,,`,`,`,`,`,,` +,,wq,`,`,,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,,`,`,` +,,wp,`,`,`,`,"ww{labor_mask=""Milking, Shearing""}",`,`,`,`,,,`,,`,,,`,`,`,wu,`,`,`,wz,` +,,,`,`,,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,,`,`,` +,,,,`,,,`,,,,,,`,`,`,`,`,,,,,`,,,,` +,,`,`,`,`,`,`,`,`,`,`,,`,`,~,`,`,,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,,,,`,,`,,,,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,,,`,d,`,`,`,d,`,,,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,,`,`,,,d,,,`,`,,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,,`,`,`,,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,wh,`,,`,`,`,,`,wn,`,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,`,`,,,"trackstopS{name=""Refuse/corpse dumper"" take_from=""Refuse feeder,Corpse feeder"" route=""Refuse/corpse quantum""}",,,`,`,`,,`,`,`,`,`,`,` +,,,,,,,,,,,,,,,` + + +#dig label(farming_traffic) start(16; 18) hidden() keep hungry dwarves away from the crops and food stores so they prefer the prepared meals + + +,,,,,,,,,ol,ol,ol,,or,or,or,or,or,,ol,ol,ol,ol +,,,,,,,,,ol,ol,ol,,or,or,or,or,or,,ol,ol,ol,ol +,,,,,,,,,ol,ol,ol,,or,or,or,or,or,,ol,ol,ol,ol +,,,,,,,,,,,ol,,or,or,or,or,or,,ol,ol,ol,ol +,,,,,,,ol,ol,ol,,ol,,or,or,or,or,or,,ol,ol,ol,ol +,,,,,,,ol,ol,ol,ol,ol,,or,or,or,or,or,,ol,ol,ol,ol +,,,,,,,ol,ol,ol,,ol,,or,or,or,or,or,,ol +,,,,,,,,,,,ol,,or,or,or,or,or,,ol,,ol,ol,ol +,,,,,,ol,ol,ol,ol,,ol,,or,or,or,or,or,,ol,ol,ol,ol,ol +,,,,,,ol,ol,ol,ol,,ol,,or,or,or,or,or,,ol,,ol,ol,ol +,,,ol,ol,,ol,ol,ol,ol,,ol,,or,or,or,or,or,,ol +,,ol,ol,ol,,ol,ol,ol,ol,,ol,,or,or,or,or,or,,ol,,or,or,or,,or,or,or +,,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,,,or,,or,,,ol,or,or,or,or,ol,or,or,or +,,,ol,ol,,ol,ol,ol,ol,,ol,ol,ol,ol,ol,ol,ol,ol,ol,,or,or,or,,or,or,or +,,,,or,,,or,,,,,,ol,`,`,`,ol,,,,,or,,,,or +,,or,or,or,or,or,or,or,or,or,or,,ol,`,~,`,ol,,or,or,or,or,or,or,or,or,or,or +,,or,or,or,or,or,or,or,or,or,or,or,ol,`,`,`,ol,or,or,or,or,or,or,or,or,or,or,or +,,or,or,or,or,or,or,or,or,or,or,,ol,ol,ol,ol,ol,,or,or,or,or,or,or,or,or,or,or +,,or,or,or,or,or,or,or,or,or,,,,or,,or,,,,or,or,or,or,or,or,or,or,or +,,or,or,or,or,or,or,or,or,,,or,or,or,or,or,or,or,,,or,or,or,or,or,or,or,or +,,or,or,or,or,or,or,or,or,,or,or,,,or,,,or,or,,or,or,or,or,or,or,or,or +,,or,or,or,or,or,or,or,,,or,or,,or,or,or,,or,or,,,or,or,or,or,or,or,or +,,or,or,or,or,or,or,or,,or,or,or,,or,or,or,,or,or,or,,or,or,or,or,or,or,or +,,or,or,or,or,or,or,or,,or,or,or,,or,or,or,,or,or,or,,or,or,or,or,or,or,or +,,or,or,or,or,or,or,or,,or,or,or,,,or,,,or,or,or,,or,or,or,or,or,or,or +,,,,,,,,,,,,,,,or + + +#burrow label(farming_burrow) start(16; 18) hidden() fix up safety burrow after channel incursions + +,,,,,,,,a{name=Inside+}(16x4) +,,,,,,,,,`,`,`,,`,`,`,`,`,,`,`,`,` +,,,,,,,,,`,`,`,,`,`,`,`,`,,`,`,`,` +,,,,,,,,,`,`,`,,`,`,`,`,`,,`,`,`,` +,,,,,,a{name=Inside+}(18x3),,,,,`,,`,`,`,`,`,,`,`,`,` +,,,,,,,`,`,`,,`,,`,`,`,`,`,,`,`,`,` +,,,,,,,`,`,`,`,`,,`,`,`,`,`,,`,`,`,` +,,,,,,a{name=Inside+}(19x1),`,`,`,,`,,`,`,`,`,`,,` +,,,,,a{name=Inside+}(20x2),,,,,,`,,`,`,`,`,`,,`,,`,`,` +,,,,,,`,`,`,`,,`,,`,`,`,`,`,,`,`,`,`,` +,,a{name=Inside+}(23x1),,,,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,` +,a{name=Inside+}(28x4),,`,`,,`,`,`,`,,`,,`,`,`,`,`,,` +,,`,`,`,,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,,`,`,` +,,`,`,`,`,`,`,`,`,`,`,,,`,,`,,,`,`,`,`,`,`,`,`,` +,,,`,`,,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,,`,`,` +,a{name=Inside+}(29x12),,,`,,,`,,,,,,`,`,`,`,`,,,,,`,,,,` +,,`,`,`,`,`,`,`,`,`,`,,`,`,~,`,`,,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,,,,`,,`,,,,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,,`,`,,,`,,,`,`,,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,,`,`,`,,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,`,`,,,`,,,`,`,`,,`,`,`,`,`,`,` +,,,,,,,,,,,,,,,` +,,,,,,,,,,,,,,a{name=Inside+}(3x1) + +#build label(farming_doors) start(16; 18) hidden() remaining doors + + +,,,,,,,,,`,`,`,,`,`,`,`,`,,`,`,`,` +,,,,,,,,,`,`,`,,`,`,`,`,`,,`,`,`,` +,,,,,,,,,`,`,`,,`,`,`,`,`,,~,~,~,~ +,,,,,,,,,,,d,,`,`,`,`,`,,~,~,~,~ +,,,,,,,`,`,`,,`,,`,`,`,`,`,,`,`,`,` +,,,,,,,`,`,`,d,`,,`,`,`,`,`,,`,`,`,` +,,,,,,,`,`,`,,`,,`,`,`,`,`,,d +,,,,,,,,,,,`,,`,`,`,`,`,,`,,~,~,~ +,,,,,,`,`,`,`,,`,,`,`,`,`,`,,`,d,`,`,~ +,,,,,,`,`,`,`,,`,,`,`,`,`,`,,`,,~,~,~ +,,,`,`,,`,`,`,`,,`,,`,`,`,`,`,,` +,,`,`,`,,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,,`,`,` +,,`,`,`,d,`,`,`,`,d,`,,,d{name=Farming},,d{name=Farming},,,`,d,`,`,`,d,`,`,` +,,,`,`,,`,`,`,`,,`,d{name=Farming},`,`,`,`,`,d{name=Farming},`,,`,`,`,,`,`,` +,,,,d,,,d,,,,,,`,`,`,`,`,,,,,d,,,,d +,,`,`,`,`,`,`,`,`,`,`,,`,`,~,`,`,,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,d{name=Farming},`,`,`,`,`,d{name=Farming},`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,,,,d{name=Farming},,d{name=Farming},,,,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,,,`,~,`,`,`,~,`,,,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,,`,`,,,~,,,`,`,,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,,`,`,`,,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,`,`,,,`,,,`,`,`,,`,`,`,`,`,`,` +,,,,,,,,,,,,,,,` + + +#notes label(industry_help) industry level walkthrough +Sets up workshops for all non-farming industries +Screenshot: https://drive.google.com/file/d/1c8YTHxTgJY5tUII-BOWdLhmDFAHwIOEs +"" +Features: +- Compact layout that covers all workshops +- Manager orders that automate basic fortress maintenance +"- Space available underneath the forge and smelters for magma, allowing the starting forge and smelters to be eventually replaced by magma versions." +- Quantum stockpiles for compact storage (see the wiki for more info on QSPs) +with separate stockpiles for: +- A reserve of uncut gems for strange moods that the jeweler's workshop cannot take from +"- Wood, iron bars, steel bars, flux, and coal so you can see at a glance if you're low on stock" +"- Items that cannot be quantum stockpiled (e.g. lye, dye, and sand bags)" +- Meltable weapons and armor +"" +Workshops: +- 2x Stoneworker +- 4x Craftsdwarf (labor restrictions set to specialize for materials in adjacent stockpiles) +- 1x Jeweler +- 1x Mechanic +- 4x Smelter +- 1x Forge +- 1x Glassmaker +- 1x Kiln +- 4x Wood furnace +- 1x Ashery +- 1x Soap maker +- 1x Carpenter +- 1x Siege workshop +- 1x Bowyer +- 1x Dyer +- 1x Loom +- 1x Clothier +"" +Manual steps you have to take: +- Assign minecarts to your quantum stockpile hauling routes. The assign-minecarts all command will do it for you. +"" +Optional manual steps you can take: +"- If desired, set one or both stockpiles in the bottom left to auto-melt. This results in melting all weapons and armor that are inferior to masterwork. This is great for upgrading your military, but it takes a *lot* of fuel unless you have first replaced the forge and smelters with magma versions. If you enable automelt and you don't have magma forges and magma smelters, be sure to be in a forested area, set up autochop, and keep your coal stocks high!" +"" +Industry Walkthrough: +"1) Start digging out /industry1 as soon as you find a non-aquifer stone layer at least two layers beneath the surface so the boulders can be used by your starting workshops. The services level is intended to be dug beneath this one, and there is space on that level to route magma underneath your furnaces so you can replace the furnaces on this level with magma-powered equivalents." +"" +"2) Generate manager orders for /industry2 if you haven't already preordered with the checklist command. You brought an anvil with you (right??), so you can remove the unneeded anvil work order from the manager orders screen. Note that stockpiles that accept containers may claim the barrels you need to build the Dyer's Workshop and Ashery. If you see those two buildings not being constructed, build a few extra barrels or run combine all to free up some existing ones." +"" +"3) Once the area is dug out, run /industry2 to build replacements for your starter workshops up on the surface. Remember to assign minecarts to to your quantum stockpile hauling routes with assign-minecarts all." +"" +"4) After the initial workshops are constructed, run /industry3 to build the remaining workshops. Generate manager orders if you haven't already preordered with the checklist command." +"" +"5) Once you have enough dwarves to do maintenance tasks (that is, after the first or second migration wave), run ""orders import library/basic"" to use the provided manager orders to take care of your fort's basic needs, such as food, booze, and raw material processing." +"" +"6) If you want to automatically melt goblinite and other non-masterwork weapons and armor, mark the south-west stockpiles for auto-melt. If you don't have an abundance of fuel, though, be sure to route magma to the level beneath this one and replace the forge and furnaces with magma equivalents." +"" +"7) Once you have magma furnaces (or abundant fuel) and more dwarves, run ""orders import library/furnace"", ""orders import library/military"", and ""orders import library/smelting"" (in that order) to import the remaining fort automation orders. The military orders are optional if you are not planning to have a military, of course." +"" +"8) At any time, feel free to build extra workshops or designate custom stockpiles in the remaining open space. The space is there for you to use! Note the area in the bottom right can be used for additional magma-powered furnaces and workshops since there is space reserved for magma in those spots in the services level beneath." +"#dig label(industry1) start(18; 18; central stairs) message(Once the area is dug out, continue with /industry2.)" + + +,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d,d +,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d,d +,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,d,d,d,d,d,,,d,,d,,,d,d,d,d,d,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,d,d,,d,d,d,d,d,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,`,`,`,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,d,d,d,d,d,,d,`,`,`,d,,d,d,d,d,d,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,`,`,`,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,d,d,,d,d,d,d,d,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,d,d,d,d,d,,,d,,d,,,d,d,d,d,d,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d,d +,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d,d + + +"#meta label(industry2) start(central stairs) message(If you preordered items on the checklist, good. If not, don't forget to generate orders for this blueprint now.) stockpiles and high-priority workshops" +traffic/industry_traffic +place/industry_place +build/industry_build +"#meta label(industry3) start(central stairs) message(If you preordered items on the checklist, good. If not, don't forget to generate orders for this blueprint now.) remaining workshops" +build2/industry_build2 +#dig label(industry_traffic) start(18; 18; central stairs) hidden() traffic patterns + + +,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,oh,ol,ol,ol,oh,ol,ol,ol,oh,ol,ol,ol,oh +,,,,oh,oh,oh,oh,oh,oh,oh,oh,ol,ol,ol,oh,ol,ol,ol,oh,ol,ol,ol,oh,oh,oh,oh,oh,oh,oh,oh +,,,,oh,ol,ol,ol,ol,ol,ol,oh,ol,ol,ol,oh,ol,ol,ol,oh,ol,ol,ol,oh,ol,ol,ol,ol,ol,ol,oh +,,,,oh,ol,ol,ol,ol,ol,ol,oh,ol,ol,ol,oh,oh,oh,oh,oh,ol,ol,ol,oh,ol,ol,ol,ol,ol,ol,oh +,,,,oh,ol,ol,ol,ol,ol,ol,oh,ol,ol,ol,oh,oh,`,oh,oh,ol,ol,ol,oh,ol,ol,ol,ol,ol,ol,oh +,,,,oh,ol,ol,ol,ol,ol,ol,oh,ol,ol,ol,oh,oh,`,oh,oh,ol,ol,ol,oh,ol,ol,ol,ol,ol,ol,oh +,,,,oh,ol,ol,ol,ol,ol,ol,oh,ol,ol,ol,`,`,`,`,`,ol,ol,ol,oh,ol,ol,ol,ol,ol,ol,oh +,,,,oh,ol,ol,ol,ol,ol,ol,oh,ol,ol,ol,`,`,`,`,`,ol,ol,ol,oh,ol,ol,ol,ol,ol,ol,oh +,,`,oh,oh,oh,oh,oh,oh,oh,oh,oh,ol,ol,ol,`,`,`,`,`,ol,ol,ol,oh,oh,oh,oh,oh,oh,oh,oh,oh,` +,,`,ol,ol,ol,ol,ol,ol,ol,ol,ol,oh,oh,oh,`,`,`,`,`,oh,oh,oh,ol,ol,ol,ol,ol,ol,ol,ol,ol,` +,,`,ol,ol,ol,ol,ol,ol,ol,ol,ol,oh,oh,oh,`,`,`,`,`,oh,oh,oh,ol,ol,ol,ol,ol,ol,ol,ol,ol,` +,,`,ol,ol,ol,ol,ol,ol,ol,ol,ol,oh,oh,,,`,,`,,,oh,oh,ol,ol,ol,ol,ol,ol,ol,ol,ol,` +,,`,oh,oh,oh,oh,oh,oh,`,`,`,`,`,,`,`,`,`,`,,`,`,`,`,`,oh,oh,oh,oh,oh,oh,` +,,`,ol,ol,ol,oh,oh,oh,`,`,`,`,`,`,`,,,,`,`,`,`,`,`,`,oh,oh,oh,ol,ol,ol,` +,,`,ol,ol,ol,oh,`,`,`,`,`,`,`,,`,,`,,`,,`,`,`,`,`,`,`,oh,ol,ol,ol,` +,,`,ol,ol,ol,oh,oh,oh,`,`,`,`,`,`,`,,,,`,`,`,`,`,`,`,oh,oh,oh,ol,ol,ol,` +,,`,oh,oh,oh,oh,oh,oh,`,`,`,`,`,,`,`,`,`,`,,`,`,`,`,`,oh,oh,oh,oh,oh,oh,` +,,`,ol,ol,ol,ol,ol,ol,ol,ol,ol,oh,oh,,,`,,`,,,oh,oh,ol,ol,ol,ol,ol,ol,ol,ol,ol,` +,,`,ol,ol,ol,ol,ol,ol,ol,ol,ol,oh,oh,oh,`,`,`,`,`,oh,oh,oh,ol,ol,ol,ol,ol,ol,ol,ol,ol,` +,,`,ol,ol,ol,ol,ol,ol,ol,ol,ol,oh,oh,oh,`,`,`,`,`,oh,oh,oh,ol,ol,ol,ol,ol,ol,ol,ol,ol,` +,,`,oh,oh,oh,oh,oh,oh,oh,oh,oh,ol,ol,ol,`,`,`,`,`,ol,ol,ol,oh,oh,oh,oh,oh,oh,oh,oh,oh,` +,,,,`,`,`,`,`,`,`,oh,ol,ol,ol,`,`,`,`,`,ol,ol,ol,oh,ol,ol,ol,ol,ol,ol,oh +,,,,`,`,`,`,`,`,`,oh,ol,ol,ol,`,`,`,`,`,ol,ol,ol,oh,ol,ol,ol,ol,ol,ol,oh +,,,,`,`,`,`,`,`,`,oh,ol,ol,ol,oh,oh,`,oh,oh,ol,ol,ol,oh,ol,ol,ol,ol,ol,ol,oh +,,,,oh,oh,oh,oh,oh,oh,oh,oh,ol,ol,ol,`,oh,`,oh,`,ol,ol,ol,oh,ol,ol,ol,ol,ol,ol,oh +,,,,`,`,`,`,`,`,`,oh,ol,ol,ol,`,`,`,`,`,ol,ol,ol,oh,ol,ol,ol,ol,ol,ol,oh +,,,,`,`,`,`,`,`,`,oh,ol,ol,ol,`,ol,ol,ol,`,ol,ol,ol,oh,ol,ol,ol,ol,ol,ol,oh +,,,,`,`,`,`,`,`,`,oh,ol,ol,ol,`,ol,ol,ol,`,ol,ol,ol,oh,oh,oh,oh,oh,oh,oh,oh +,,,,,,,,,,,oh,ol,ol,ol,oh,ol,ol,ol,oh,ol,ol,ol,oh +,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` + + +"#place label(industry_place) start(18; 18) hidden() message(remember to: +- assign minecarts to to your quantum stockpile hauling routes (use ""assign-minecarts all"") +- if you want to automatically melt goblinite and other low-quality weapons and armor, mark the south-east stockpiles for auto-melt +- once you have enough dwarves, run ""orders import library/basic"" to automate your fort's basic needs (see /industry_help for more info on this file)) industry stockpiles" + + +,,,,,,,,,,,"e{name=""Rough gems for moods"" containers=0 take_from=""Stoneworker quantum,Gem feeder""}:=roughgems",e,e,e,e,e,e,e,e,e,e,e,e +,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,"se{name=""Stoneworker quantum"" quantum=true}",`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,"s10{name=""Stone feeder""}:=otherstone(5x4)",,,~,~,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,` +,,"w{name=""Wood"" take_from=""Goods/wood quantum,Wood feeder""}",`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`,"c{name=""Dye"" barrels=-1 }:+dye" +,,w,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`,c +,,w,`,`,`,`,`,`,`,`,`,`,`,`,"e{name=""Gem feeder"" containers=0}(5x1)",,,~,~,`,`,`,`,`,`,`,`,`,`,`,`,c +,,w,`,`,`,`,`,`,`,`,`,`,`,,,`,,`,,,`,`,`,`,`,`,`,`,`,`,`,c +,,w,`,`,`,`,`,`,"w{name=""Wood feeder""}(2x5)",,"g{name=""Goods feeder"" containers=0}:+cat_food/tallow+wax-crafts-goblets(3x3)",,`,,`,`,`,`,`,,"hlS{name=""Cloth/bones feeder"" containers=0}:+cat_refuse/skulls/,bones/,hair/,shells/,teeth/,horns/-adamantinethread(5x5)",,,~,~,`,`,`,`,`,`,c +,,w,`,`,`,`,`,`,~,~,~,~,~,`,`,,,,`,`,~,~,~,~,~,`,`,`,`,`,`,c +,,`,`,`,`,`,"c{name=""Goods/wood quantum"" quantum=true give_to=""Pots,Barrels,Jugs,Bags,Seeds feeder""}:+all-cat_animals",`,~,~,~,~,~,,`,,`,,`,,~,~,~,~,~,`,"r{name=""Cloth/bones quantum"" quantum=true}:+all",`,`,`,`,c +,,"c{name=""Lye"" barrels=0}:+miscliquid",`,`,`,`,`,`,~,~,"u2{name=""Furniture feeder""}:-sand(3x2)",~,~,`,`,,,,`,`,~,~,~,~,~,`,`,`,`,`,`,c +,,c,`,`,`,`,`,`,~,~,~,~,~,,`,`,`,`,`,,~,~,~,~,~,`,`,`,`,`,`,c +,,c,`,`,`,`,`,`,`,`,`,`,`,,,`,,`,,,`,`,`,`,`,`,`,`,`,`,`,c +,,c,`,`,`,`,`,`,`,`,`,`,`,`,"bnpdz{name=""Bar/military feeder"" containers=0}:-potash+adamantinethread(5x3)",,,,~,`,`,`,`,`,`,`,`,`,`,`,`,c +,,c,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`,c +,,c,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`,c +,,,,"pd{name=""Meltable steel/bronze"" take_from=""Metalworker quantum,Bar/military feeder"" containers=0}:-cat_weapons/mats/,other/-cat_armor/mats/,other/+bronzeweapons+bronzearmor+steelweapons+steelarmor-masterworks-artifacts(7x3)",,,~,~,~,~,`,`,`,`,"s5{name=""Ore/clay feeder""}:-otherstone(5x2)",,,~,~,`,`,`,`,`,`,`,`,`,`,` +,,,,~,~,~,~,~,~,~,`,`,`,`,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,` +,,,,~,~,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,"c{name=""Coal"" containers=0 take_from=""Metalworker quantum,Bar/military feeder""}:+coal",`,"c{name=""Metalworker quantum"" quantum=true}:+all",`,"c{name=""Iron"" containers=0 take_from=""Metalworker quantum,Bar/military feeder""}:+ironbars",`,`,`,`,`,`,`,`,`,`,` +,,,,"pd{name=""Other meltables"" take_from=""Metalworker quantum,Bar/military feeder"" containers=0}:-cat_weapons/other/-cat_armor/other/-bronzeweapons-bronzearmor-steelweapons-steelarmor-masterworks-artifacts(7x3)",,,~,~,~,~,`,`,`,`,c,"c{name=Flux take_from=""Metalworker quantum,Ore/clay feeder"" links_only=true}:+flux(3x1)",,,c,`,`,`,`,`,`,`,`,`,`,` +,,,,~,~,~,~,~,~,~,`,`,`,`,c,`,`,`,c,`,`,`,`,`,`,`,`,`,`,` +,,,,~,~,~,~,~,~,~,`,`,`,`,c,`,`,`,c,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,"u{name=""Sand bags""}:-cat_furniture/type+sand",u,u,u,u,u,`,"c{name=""Steel"" containers=0 take_from=""Metalworker quantum,Bar/military feeder""}:+steelbars",c,c,c,c,c + + +#build label(industry_build) start(18; 18) hidden() workshops to build first + + +,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,"wj{name=""Encruster"" do_now=true take_from=""Goods/wood quantum,Stoneworker quantum,Gem feeder""}",`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,"wr{name=""Stone craftsdwarf"" do_now=true labor=Stonecrafting}",`,`,`,`,`,`,`,wt{do_now=true},`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,"trackstopN{name=""Stone/gem dumper"" do_now=true take_from=""Stone feeder,Gem feeder"" route=""Stone/gem quantum""}",`,`,`,`,`,`,`,`,~,`,`,`,` +,,,,`,`,~,`,`,~,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,wm{max_general_orders=2 do_now=true},`,`,`,`,`,`,`,wm{max_general_orders=10 do_now=true},`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,~,`,`,~,`,`,~,`,`,`,`,`,`,`,`,`,`,`,`,`,~,`,`,~,`,`,~,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,,,~,,~,,,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,~,`,,,,`,~,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,wc{max_general_orders=9 do_now=true},`,`,`,"trackstopW{name=""Goods/wood dumper"" do_now=true take_from=""Wood feeder,Goods feeder,Furniture feeder"" route=""Goods/wood quantum""}",`,`,`,`,`,,`,,`,,`,,`,`,`,`,`,"trackstopE{name=""Cloth/bones dumper"" do_now=true take_from=""Cloth/bones feeder"" route=""Cloth/bones quantum""}",`,`,`,~,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,~,`,,,,`,~,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,,,~,,~,,,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,~,`,`,~,`,`,~,`,`,`,`,`,`,`,`,`,`,`,`,`,~,`,`,~,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,~,`,`,`,`,`,`,`,~,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,"trackstopS{name=""Metalworker dumper"" do_now=true take_from=""Bar/military feeder,Ore/clay feeder"" route=""Metalworker quantum""}",`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,~,`,`,`,`,`,`,`,~,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,~,`,`,`,~,`,`,`,~,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` + + +#build label(industry_build2) start(18; 18) hidden() remaining workshops + + +,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,~,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,~,`,`,`,`,`,`,`,~,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,~,`,`,`,`,`,`,`,`,ws,`,`,`,` +,,,,`,`,wS,`,`,wb,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,~,`,`,`,`,`,`,`,~,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,wy,`,`,ew,`,`,ew,`,`,`,`,`,`,`,`,`,`,`,`,`,wk,`,`,wo,`,`,"wd{take_from=""Cloth/bones feeder,Cloth/bones quantum,Dye""}",`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,,,d{name=Industry},,d{name=Industry},,,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,d{name=Industry},`,,,,`,d{name=Industry},`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,~,`,`,`,~,`,`,`,`,`,,`,,`,,`,,`,`,`,`,`,~,`,`,`,we,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,d{name=Industry},`,,,,`,d{name=Industry},`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,,,d{name=Industry},,d{name=Industry},,,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,"wr{name=""Wood craftsdwarf"" labor=Woodcrafting}",`,`,ew,`,`,ew,`,`,`,`,`,`,`,`,`,`,`,`,`,"wr{name=""Misc craftsdwarf"" labor_mask=""Stonecrafting,Woodcrafting,Bone Carving""}",`,`,"wr{name=""Bone craftsdwarf"" labor=""Bone Carving""}",`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,es,`,`,`,`,`,`,`,es,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,~,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,es,`,`,`,`,`,`,`,es,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,eg,`,`,`,wf{max_general_orders=9},`,`,`,ek,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` + + +#notes label(services_help) services level walkthrough +"Sets up public services (dining, hospital, etc.)" +Screenshot: https://drive.google.com/file/d/1RQMy_zYQWM5GN7-zjn6LoLWmnrJjkxPM +"" +Features: +- Spacious dining room/tavern (tavern is restricted to citizens and residents only by default) +- Large prepared food and drink stockpiles +- Well cistern system (route or carry your own water) +- Hospital (also restricted to residents by default) with a well and soap for washing +- Well-appointed jail cells for happy prisoners +- Bolt-recycling archery range for your marksdwarves +- Interrogation room (office) for your Captain of the Guard +- Garbage dump +- Empty space for magma to power forges and smelters in the industry level above +"" +Manual steps you have to take: +"- If you want to tavern to attract visitors, change the restriction in the location configuration screen." +"- Fill the cisterns with water, either with a bucket brigade or by plumbing flowing water (e.g. with the aquifer_tap library blueprint). Fill so that there are two z-levels of 7-depth water to prevent muddiness. If you want to fill with buckets, you can use the pre-designated pond zones on the level below the main floor. If you feel adventurous and are experienced with water pressure, you can instead route (depressurized!) water to the second-to-bottom level (the one above the up staircases). See the aquifer_tap blueprint for help with getting water from a light aquifer." +"- If you are filling the wells with a bucket brigade and at least one well is already constructed, you'll run into issues with the dwarves stealing water from one well to fill another. Temporarily deconstruct the wells or temporarily build grates beneath the wells to block the buckets to avoid this issue. Remember to rebuild the wells or remove the grates afterwards, though!" +"" +Services Walkthrough: +1) Start this level when your fort grows to about 30 dwarves so everyone has a place to eat. +"" +2) Start digging with /services1. Note that this digs out the main level and three levels below for the well cisterns. +"" +"3) Once the area is dug out, start populating the rooms with /services2. Generate manager orders for /services2." +"" +"4) Fill the wells with either bucket brigades or by carefully routing flowing water (you can use the ""blueprinted"" plumbing template or erase it and plan your own). If you are using a bucket brigade, you have to activate the ""Cistern"" pond zones (which you can search for in the Places screen)." +"" +"5) When your fort has grown some more, or you start needing a jail, run /services3 to extend the rooms a bit more. Generate manager orders for /services3." +"" +"6) When your fort is more mature and you need to expand the rooms, run /services4 to finish everything up. If you didn't have a Sheriff/Captain of the Guard to automatically assign to the interrogation room when you ran /services2, you can manually assign the office now. Generate manager orders for /services4." +"#dig label(services1) start(18; 18; central stairs) message(Once the area is dug out, continue with /services2.)" + +,d,d,d,,d,d,d,,d,d,d,,d,h,d,,d,h,d,,d,h,d,,d,h,d,,d,h,d +,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d +,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d +,,d,,,,d,,,,d,,,,d,,,,d,,,,d,,,,d,,,,d +,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,d,d,d,d,d,d,d,d,d,d,d,,,,,,,,,,,,,,d +,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d,d,d,d,,d,,d,d,d,d,d +,d,d,d,d,d,d,d,d,d,d,d,,h5,h5,h5,h5,h5,h5,h5,h5,h5,h5,d,,d,,d,d,d,d,d +,d,d,d,d,d,d,d,d,d,d,d,,h,h,h,h,h,h,h,h,h,h,d,,d,,d,d,d,d,d +,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d,d,d,d,,j,,d,d,d,d,d +,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d,d +,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d,d,,d,,d,,d,,d,,d +,d,d,d,d,d,d,d,d,d,d,d,,,,,d,,d,,,,,d,,d,,d,,d,,d +,d,d,d,d,d,d,d,d,d,d,d,,,,d,d,d,d,d,,,,d,,d,,d,,d,,d +,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,`,`,`,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,d,d,d,d,d,d,d,d,d,d,d,,d,,d,`,`,`,d,,d,,d,d,d,d,d,d,d,d,d,h +,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,`,`,`,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,d,d,d,d,d,d,d,d,d,d,d,,,,d,d,d,d,d,,,,d,,d,,d,,d,,d +,d,d,d,d,d,d,d,d,d,d,d,,,,,,d,,,,,,d,,d,,d,,d,,d +,d,d,d,d,d,d,d,d,d,d,d,,,,,,,,,,,,d,,d,,d,,d,,d +,d,d,d,d,d,d,d,d,d,d,d +,d,d,d,d,d,d,d,d,d,d,d +,d,d,d,d,d,d,d,d,d,d,d +,d,d,d,d,d,d,d,d,d,d,d +,d,d,d,d,d,d,d,d,d,d,d +,d,d,d,d,d,d,d,d,d,d,d +,,,,d,d,,d,d +,d,d,d,d,d,,d,d,d,d,d +,d,d,d,d,d,,d,d,d,d,d +,d,d,d,d,d,,d,d,d,d,d +,d,d,d,d,d,,d,d,d,d,d +,d,d,d,d,d,,d,d,d,d,d + +#> + +,,,,,,,,,,,,,j5,h5,j,,j5,h5,j,,j5,h5,j,,j5,h5,j,,j5,h5,j +,,,,,,,,,,,,,5,5,5,,5,5,5,,5,5,5,,5,5,5,,5,5,5 +,,,,,,,,,,,,,,d,,,,d,,,,d,,,,d,,,,d +,,,,,,,,,,,,,,d,,,,d,,,,d,,,,d,,,,d +,,,,,,,,,,,,,,d,,,,d,,,,d,,,,d,,,,d +,,,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,,,,d +,,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,,,,d +,,,,,,,,,,,,,,,,,,,,,,,,,,d +,,,,,,,,,,,,,,,,,,,,,,,,,,d +,,,,,,,,,,,,,,,,,,,,,,,,,u,d +,,,,,,,,,,,,,,,,,,,,,,,,,,d +,,,,,,,,,,,,,,,,,,,,,,,,,,d +,,,,,,,,,,,,,,,,,,,,,,,,,,d +,,,,,,,,,,,,,,,d,d,d,d,d,,,,,,,d +,,,,,,,,,,,,,,,d,`,`,`,d,,,,,,,d,,,,,5,j5 +,,,,,,,,,,,,,,,d,`,`,`,d,,,,,,,d,d,d,d,d,5,h5 +,,,,,,,,,,,,,,,d,`,`,`,d,,,,,,,,,,,,5,j +,,,,,,,,,,,,,,,d,d,d,d,d + +#> + +,,,,,,,,,,,,,u5,h5,i,,u5,h5,i,,u5,h5,i,,u5,h5,i,,u5,h5,i +,,,,,,,,mbd,,,,,,mbd,,,,mbd,,,,mbd,,,,mbd,,,,mbd +,,,,,,,mbd,,mbd,mbd,mbd,mbd,mbd,mbd,mbd,mbd,mbd,mbd,mbd,mbd,mbd,mbd,mbd,mbd,mbd,mbd,mbd,mbd,mbd,mbd +,,,,,,,,mbd,,,,,,,,,,,,,,,,,,,,,,mbd +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,mbd +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,mbd +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,mbd +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,mbd +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,mbd +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,mbd +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,mbd +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,mbd +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,mbd +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,mbd +,,,,,,,,,,,,,,,d,d,d,d,d,,,,,,,,,,,mbd +,,,,,,,,,,,,,,,d,`,`,`,d,,,,,,,,,,,mbd,,u5 +,,,,,,,,,,,,,,,d,`,`,`,d,,,,,,,,,,,mbd,mbd,h5 +,,,,,,,,,,,,,,,d,`,`,`,d,,,,,,,,,,,,,i +,,,,,,,,,,,,,,,d,d,d,d,d + +#> + +,,,,,,,,,,,,,,d,u,,,d,u,,,d,u,,,d,u,,,d,u + + + + + + + + + + + + + +,,,,,,,,,,,,,,,d,d,d,d,d +,,,,,,,,,,,,,,,d,`,`,`,d +,,,,,,,,,,,,,,,d,`,`,`,d,,,,,,,,,,,,,d +,,,,,,,,,,,,,,,d,`,`,`,d,,,,,,,,,,,,,u +,,,,,,,,,,,,,,,d,d,d,d,d + +"#meta label(services2) start(central stairs) message(Once furniture has been built, continue with /services3.) zones and minimally functional hospital and dining hall" +traffic/services_traffic +zones/services_zones +place/services_place +build/services_build +smooth/services_smooth +"" +"#meta label(services3) start(central stairs) message(Once furniture has been built, continue with /services4.) expand furnishings" +place2/services_place2 +build2/services_build2 +smooth2/services_smooth2 +"" +#meta label(services4) start(central stairs) complete furnishings +place3/services_place3 +build3/services_build3 +#dig label(services_traffic) start(18; 18) hidden() keep lollygaggers out of the cisterns and justice areas + +,`,`,`,,`,`,`,,`,`,`,,or,or,or,,or,or,or,,or,or,or,,or,or,or,,or,or,or +,`,`,`,,`,`,`,,`,`,`,,or,or,or,,or,or,or,,or,or,or,,or,or,or,,or,or,or +,`,`,`,,`,`,`,,`,`,`,,or,or,or,,or,or,or,,or,or,or,,or,or,or,,or,or,or +,,`,,,,`,,,,`,,,,or,,,,or,,,,or,,,,or,,,,or +,`,`,`,`,`,`,`,`,`,`,`,,or,or,or,or,or,or,or,or,or,or,or,or,or,or,or,or,or,or,or +,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,,,or +,`,`,`,`,`,`,`,`,`,`,`,,or,or,or,or,or,or,or,or,or,or,or,,or,,or,or,or,or,or +,`,`,`,`,`,`,`,`,`,`,`,,or,or,or,or,or,or,or,or,or,or,or,,or,,or,or,or,or,or +,`,`,`,`,`,`,`,`,`,`,`,,or,or,or,or,or,or,or,or,or,or,or,,or,,or,or,or,or,or +,`,`,`,`,`,`,`,`,`,`,`,,or,or,or,or,or,or,or,or,or,or,or,or,or,or,or,or,or,or,or +,`,`,`,`,`,`,`,`,`,`,`,,or,or,or,or,or,or,or,or,or,or,or,,or,,or,or,or,or,or +,`,`,`,`,`,`,`,`,`,`,`,,or,or,or,or,or,or,or,or,or +,`,`,`,`,`,`,`,`,`,`,`,,or,or,or,or,or,or,or,or,or,,or,,or,,or,,or,,or +,`,`,`,`,`,`,`,`,`,`,`,,,,,or,,or,,,,,or,,or,,or,,or,,or +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,or,,or,,or,,or,,or +,`,ol,ol,ol,oh,oh,oh,ol,ol,ol,`,`,`,`,`,`,`,`,`,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh +,`,or,or,ol,oh,or,oh,ol,or,or,`,,`,,`,`,`,`,`,,`,,oh,oh,oh,oh,oh,oh,oh,oh,oh,or +,`,or,or,ol,oh,oh,oh,ol,or,or,`,`,`,`,`,`,`,`,`,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh +,`,or,or,or,ol,oh,ol,or,or,or,`,,,,`,`,`,`,`,,,,or,,or,,or,,or,,or +,`,or,or,or,or,oh,or,or,or,or,`,,,,,,or,,,,,,or,,or,,or,,or,,or +,`,or,or,or,or,oh,or,or,or,or,`,,,,,,,,,,,,or,,or,,or,,or,,or +,`,or,or,or,or,oh,or,or,or,or,` +,`,or,or,or,or,oh,or,or,or,or,` +,`,or,or,or,or,oh,or,or,or,or,` +,`,or,or,or,or,oh,or,or,or,or,` +,`,`,`,oh,oh,oh,oh,oh,`,`,` +,`,`,`,oh,oh,`,oh,oh,`,`,` +,,,,oh,oh,,oh,oh +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` + +#> + +,,,,,,,,,,,,,or,or,or,,or,or,or,,or,or,or,,or,or,or,,or,or,or +,,,,,,,,,,,,,or,or,or,,or,or,or,,or,or,or,,or,or,or,,or,or,or +,,,,,,,,,,,,,,or,,,,or,,,,or,,,,or,,,,or +,,,,,,,,,,,,,,or,,,,or,,,,or,,,,or,,,,or +,,,,,,,,,,,,,,or,,,,or,,,,or,,,,or,,,,or +,,,,,,,,,,,,,,or,or,or,or,or,or,or,or,or,or,or,or,or,or,or,or,or +,,,,,,,,,,,,,,,,,,,,,,,,,,or +,,,,,,,,,,,,,or,or,or,or,or,or,or,or,or,or,,,,or +,,,,,,,,,,,,,or,or,or,or,or,or,or,or,or,or,,,,or +,,,,,,,,,,,,,,,,,,,,,,,,,,or +,,,,,,,,,,,,,,,,,,,,,,,,or,or,or +,,,,,,,,,,,,,,,,,,,,,,,,,,or +,,,,,,,,,,,,,,,,,,,,,,,,,,or +,,,,,,,,,,,,,,,,,,,,,,,,,,or +,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,,or +,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,,or,,,,,or,or +,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,,or,or,or,or,or,or,or +,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,,,,,,,or,or +,,,,,,,,,,,,,,,`,`,`,`,` + +#> + +,,,,,,,,,,,,,or,or,or,,or,or,or,,or,or,or,,or,or,or,,or,or,or + + + + + + + + + + + + + +,,,,,,,,,,,,,,,`,`,`,`,` +,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,,,,,,,,or +,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,,,,,,,,or +,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,,,,,,,,or +,,,,,,,,,,,,,,,`,`,`,`,` + +#> + +,,,,,,,,,,,,,,or,or,,,or,or,,,or,or,,,or,or,,,or,or + + + + + + + + + + + + + +,,,,,,,,,,,,,,,`,`,`,`,` +,,,,,,,,,,,,,,,`,`,`,`,` +,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,,,,,,,,or +,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,,,,,,,,or +,,,,,,,,,,,,,,,`,`,`,`,` + +"#zone label(services_zones) start(18; 18) hidden() message(Don't forget to assign a doctor to the hospital! +If you'd like to fill your wells via bucket brigade instead of routing water (e.g. with the aquifer_tap library blueprint), activate the inactive pond zones one level down from where the wells will be built.) garbage dump, hospital, taverrn, barracks, archery range, and pond zones" +,,,,,,,,,,,,j/jail1,"j/jail1{name=""Jail 1""}(4x5)",j/jail1,j/jail1,j/jail1,"j{name=""Jail 2""}(4x5)",,,,"j{name=""Jail 3""}(4x5)",,,,"j{name=""Jail 4""}(4x5)",,,,"j{name=""Jail 5""}(4x5)" +,"b{location=tavern/bigpub name=""Rented room 1""}(1x3)","b{location=tavern/bigpub name=""Rented room 2""}(1x3)","b{location=tavern/bigpub name=""Rented room 3""}(1x3)",,"b{location=tavern/bigpub name=""Rented room 4""}(1x3)","b{location=tavern/bigpub name=""Rented room 5""}(1x3)","b{location=tavern/bigpub name=""Rented room 6""}(1x3)",,"b{location=tavern/bigpub name=""Rented room 7""}(1x3)","b{location=tavern/bigpub name=""Rented room 8""}(1x3)","b{location=tavern/bigpub name=""Rented room 9""}(1x3)",j/jail1,j/jail1,j/jail1,j/jail1,j/jail1,`,`,`,,`,`,`,,`,`,`,,`,`,` +,`,`,`,,`,`,`,,`,`,`,j/jail1,j/jail1,j/jail1,j/jail1,j/jail1,`,`,`,,`,`,`,,`,`,`,,`,`,` +,`,`,`,,`,`,`,,`,`,`,j/jail1,j/jail1,j/jail1,j/jail1,j/jail1,`,`,`,,`,`,`,,`,`,`,,`,`,` +"h{location=tavern/bigpub allow=residents name=""Grand hall tavern""}(13x31)",,`,,,,`,,,,`,,,j/jail1,j/jail1,j/jail1,j/jail1,,`,,,,`,,,,`,,,,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,,,`,o/interrogation,o/interrogation,o/interrogation,o/interrogation,o/interrogation,o/interrogation,o/interrogation +,`,`,`,`,`,`,`,`,`,`,`,,"B{name=""Marksdwarf barracks""}a{name=""Shooting gallery"" shoot_from=""south""}",Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,,`,o/interrogation,"j{name=""Drunk tank""}",j,j,j,j,o/interrogation +,`,`,`,`,`,`,`,`,`,`,`,,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,,`,o/interrogation,j,"o/interrogation{name=""Interrogation room"" assigned_unit=sheriff}(3x3)",`,`,j,o/interrogation +,`,`,`,`,`,`,`,`,`,`,`,,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,,`,o/interrogation,j,`,`,`,j,o/interrogation +,`,`,`,`,`,`,`,`,`,`,`,,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,`,`,o/interrogation,j,`,`,`,j,o/interrogation +,`,`,`,`,`,`,`,`,`,`,`,,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,,`,o/interrogation,j,j,j,j,j,o/interrogation +,`,`,`,`,`,`,`,`,`,`,`,,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,,,,,o/interrogation,o/interrogation,o/interrogation,o/interrogation,o/interrogation,o/interrogation,o/interrogation +,`,`,`,`,`,`,`,`,`,`,`,,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,,m{location=hospital name=Hospital allow=residents},,m,,m,,m,,m +,`,`,`,`,`,`,`,`,`,`,`,,,,,`,,`,,,,,m,,m,,m,,m,,m +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,m,,m,,m,,m,,m +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,m,m,m,m,m,m,m,m,m,m +,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,,m,m,m,m,m,m,m,m,m,m +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,m,m,m,m,m,m,m,m,m,m +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,m,,m,,m,,m,,m +,`,`,`,`,`,`,`,`,`,`,`,,,,,,"d{name=""Garbage dump""}",,,,,,m,,m,,m,,m,,m +,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,m,,m,,m,,m,,m +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` + +#> + +,,,,,,,,,,,,,`,"p{name=""Jail 1 cistern"" pond=true active=false}",`,,`,"p{name=""Jail 2 cistern"" pond=true active=false}",`,,`,"p{name=""Jail 3 cistern"" pond=true active=false}",`,,`,"p{name=""Jail 4 cistern"" pond=true active=false}",`,,`,"p{name=""Jail 5 cistern"" pond=true active=false}",` +,,,,,,,,,,,,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +,,,,,,,,,,,,,,`,,,,`,,,,`,,,,`,,,,` +,,,,,,,,,,,,,,`,,,,`,,,,`,,,,`,,,,` +,,,,,,,,,,,,,,`,,,,`,,,,`,,,,`,,,,` +,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,,,,` +,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,,,,` +,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,,,,,,,,,,,,,,,,,,,,,,`,`,` +,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,,` +,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,,`,,,,,`,` +,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,,`,`,`,`,`,`,"p{name=""Hospital cistern"" pond=true active=false}" +,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,,,,,,,`,` +,,,,,,,,,,,,,,,`,`,`,`,` + +#place label(services_place) start(18; 18) hidden() + +,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +,,`,,,,`,,,,`,,,,`,,,,`,,,,`,,,,`,,,,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,,,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,"z{name=""Bolts quantum"" quantum=true}",`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,`,,`,,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,"b/soap{name=""Soap"" take_from=""Metalworker quantum""}:=soap" +,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,b/soap +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,"c{name=""Garbage dump"" links_only=true}",,,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,,`,` +,"c{name=""Prepared food"" barrels=-1}:+preparedmeals(5x5)",,,,`,,"c{name=""Booze"" barrels=-1}:+booze(5x5)",,,,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` + +#> + +,,,,,,,,,,,,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +,,,,,,,,,,,,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +,,,,,,,,,,,,,,`,,,,`,,,,`,,,,`,,,,` +,,,,,,,,,,,,,,`,,,,`,,,,`,,,,`,,,,` +,,,,,,,,,,,,,,`,,,,`,,,,`,,,,`,,,,` +,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,,,,,,,,,,,"z{name=""Bolts feeder"" containers=0 take_from=""Metalworker quantum""}:-cat_ammo/type/,other/+bolts(10x1)",,,,,,,,,`,,,,` +,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,,,,` +,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,,,,,,,,,,,,,,,,,,,,,,`,`,` +,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,,` +,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,,`,,,,,`,` +,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,,`,`,`,`,`,`,` +,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,,,,,,,`,` +,,,,,,,,,,,,,,,`,`,`,`,` + +"#build label(services_build) start(18; 18) hidden() message(Remember to enqueue manager orders for this blueprint. +Assign a minecart to the training ammo quantum dump with ""assign-minecarts all"") build basic hospital, dining room, and barracks" + +,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +,,`,,,,`,,,,`,,,,`,,,,`,,,,`,,,,`,,,,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,,,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,A,A,A,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,"trackstopS{name=""Bolts dumper"" take_from=""Bolts feeder"" route=""Bolts quantum""}",`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,h,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,b,`,`,`,`,`,`,`,`,,`,,`,,`,,b,,R +,`,`,`,`,`,`,`,`,`,`,`,,,,,`,,`,,,,,`,,`,,`,,d,,d +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,,h,`,`,`,`,t,`,`,`,l +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,`,,,,,,`,,`,,`,,`,,d +,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,`,,`,,`,,`,,R +,`,`,`,`,`,`,t,c,c,t,` +,`,`,`,`,`,`,t,c,c,t,` +,`,`,`,`,`,`,t,c,c,t,` +,`,`,`,`,`,`,t,c,c,t,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,h,`,`,`,`,` +,,,,`,`,,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` + +#dig label(services_smooth) start(18; 18) hidden() smooth the floor where the pedestal will go + +,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +,,`,,,,`,,,,`,,,,`,,,,`,,,,`,,,,`,,,,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,,,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,`,,`,,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,s1,`,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,`,,,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` + +#place label(services_place2) start(18; 18) hidden() jail food and booze + +,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,"c{name=""Jail booze"" barrels=-1 take_from=""Booze""}:+booze(1x2)",,`,`,`,,`,`,` +,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,"c{name=""Jail food"" barrels=-1 take_from=""Prepared food""}:+preparedmeals(2x1)",,`,,`,`,`,,`,`,` +,,`,,,,`,,,,`,,,,`,,,,`,,,,`,,,,`,,,,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,,,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,~,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,`,,`,,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,~,,,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,,`,` +,~,~,~,~,~,,~,~,~,~,~ +,~,~,~,~,~,,~,~,~,~,~ +,~,~,~,~,~,,~,~,~,~,~ +,~,~,~,~,~,,~,~,~,~,~ +,~,~,~,~,~,,~,~,~,~,~ + +#build label(services_build2) start(18; 18) hidden() message(Remember to enqueue manager orders for this blueprint.) expand each room + +,`,b,`,,`,b,`,,`,b,`,,`,`,`,,`,`,`,,t,l,b,,`,`,`,,`,`,` +,`,h,`,,`,h,`,,`,h,`,,`,`,`,,`,`,`,,c,v,`,,`,`,`,,`,`,` +,`,f,`,,`,f,`,,`,f,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +,,`,,,,`,,,,`,,,,`,,,,`,,,,d,,,,`,,,,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,,,` +,`,`,`,`,`,`,`,`,`,`,`,,A,A,A,~,~,~,A,A,A,A,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,c,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,t,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,~,`,`,`,`,`,`,`,`,`,`,`,c,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,h,b,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,~,`,`,`,`,`,`,`,h +,`,`,`,`,`,`,`,`,`,`,`,,~,`,`,`,`,`,`,`,b,,b,,b,,b,,~,,~ +,`,`,`,`,`,`,`,`,`,`,`,,,,,`,,`,,,,,d,,d,,d,,~,,~ +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,` +,`,`,`,`,`,F,`,`,`,`,`,,`,,`,`,`,`,`,,`,,~,`,`,`,`,~,`,`,`,~ +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,`,,,,,,`,,`,,`,,`,,~ +,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,`,,`,,`,,`,,~ +,`,t,c,c,t,`,~,~,~,~,` +,`,t,c,c,t,`,~,~,~,~,` +,`,t,c,c,t,`,~,~,~,~,` +,`,t,c,c,t,`,~,~,~,~,` +,`,`,`,`,`,`,`,`,`,`,` +,h,`,`,`,`,~,`,`,`,`,h +,,,,`,`,,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` + +#dig label(services_smooth2) start(18; 18) hidden() smooth the floor where the statues will go + +,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +,,`,,,,`,,,,`,,,,`,,,,`,,,,`,,,,`,,,,` +,`,`,`,s1,`,`,`,s1,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,,,` +,s1,`,`,`,`,`,`,`,`,`,s1,,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,s1,`,`,`,`,`,`,`,`,`,s1,,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,s1,`,`,`,`,`,`,`,`,`,s1,,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` +,s1,`,`,`,`,`,`,`,`,`,s1,,`,`,`,`,`,`,`,`,`,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,`,,`,,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,`,,,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,s1,`,`,`,`,`,s1,`,` +,,,,`,`,,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` + +#place label(services_place3) start(18; 18) hidden() remaining jail food and booze + +,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +,`,`,`,,`,`,`,,`,`,`,,`,`,"c{name=""Jail booze"" barrels=-1 take_from=""Booze""}:+booze(1x2)",,`,`,"c{name=""Jail booze"" barrels=-1 take_from=""Booze""}:+booze(1x2)",,`,`,~,,`,`,"c{name=""Jail booze"" barrels=-1 take_from=""Booze""}:+booze(1x2)",,`,`,"c{name=""Jail booze"" barrels=-1 take_from=""Booze""}:+booze(1x2)" +,`,`,`,,`,`,`,,`,`,`,,"c{name=""Jail food"" barrels=-1 take_from=""Prepared food""}:+preparedmeals(2x1)",,`,,"c{name=""Jail food"" barrels=-1 take_from=""Prepared food""}:+preparedmeals(2x1)",,`,,~,`,`,,"c{name=""Jail food"" barrels=-1 take_from=""Prepared food""}:+preparedmeals(2x1)",,`,,"c{name=""Jail food"" barrels=-1 take_from=""Prepared food""}:+preparedmeals(2x1)",,` +,,`,,,,`,,,,`,,,,`,,,,`,,,,`,,,,`,,,,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,,,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,~,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,`,,`,,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,~,,,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,,`,` +,~,~,~,~,~,,~,~,~,~,~ +,~,~,~,~,~,,~,~,~,~,~ +,~,~,~,~,~,,~,~,~,~,~ +,~,~,~,~,~,,~,~,~,~,~ +,~,~,~,~,~,,~,~,~,~,~ + +#build label(services_build3) start(18; 18) hidden() message(Remember to enqueue manager orders for this blueprint.) finalize furniture + +,b,~,b,,b,~,b,,b,~,b,,t,l,b,,t,l,b,,~,~,~,,t,l,b,,t,l,b +,h,~,h,,h,~,h,,h,~,h,,c,v,`,,c,v,`,,~,~,`,,c,v,`,,c,v,` +,f,~,f,,f,~,f,,f,~,f,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +,,d,,,,d,,,,d,,,,d,,,,d,,,,~,,,,d,,,,d +,`,`,`,s,`,`,`,s,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,,,` +,s,`,`,`,`,`,`,`,`,`,s,,~,~,~,~,~,~,~,~,~,~,`,,`,,v,v,v,v,v +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,,`,,v,`,~,`,v +,s,`,`,`,`,`,`,`,`,`,s,,`,`,`,`,`,`,`,`,`,`,`,,`,,v,`,~,`,v +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,~,`,`,`,`,`,`,d,`,d,v,`,~,`,v +,s,`,`,`,`,`,`,`,`,`,s,,`,`,`,`,`,`,`,`,`,~,~,,`,,v,v,v,v,v +,`,`,`,`,`,`,`,`,`,`,`,,~,h,h,h,h,h,h,h,~ +,s,`,`,`,`,`,`,`,`,`,s,,~,b,b,b,b,b,b,b,~,,~,,~,,~,,~,,~ +,`,`,`,`,`,`,`,`,`,`,`,,,,,d{name=Services},,d{name=Services},,,,,~,,~,,~,,~,,~ +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,d,`,d{name=Services},`,`,`,`,`,d{name=Services},`,d,`,`,`,`,`,`,`,`,`,` +,`,t,c,`,`,~,`,`,c,t,`,,s,,`,`,`,`,`,,s,,~,`,`,t,`,~,`,`,`,~ +,`,t,c,`,`,`,`,`,c,t,`,d,`,d{name=Services},`,`,`,`,`,d{name=Services},`,d,`,`,`,`,`,`,`,`,`,` +,`,t,c,c,t,`,t,c,c,t,`,,,,`,`,`,`,`,,,,`,,`,,`,,`,,` +,`,t,c,c,t,`,t,c,c,t,`,,,,,,`,,,,,,d,,d,,d,,d,,` +,`,t,c,c,t,`,t,c,c,t,`,,,,,,,,,,,,b,,b,,b,,b,,` +,`,~,~,~,~,`,~,~,~,~,` +,`,~,~,~,~,`,~,~,~,~,` +,`,~,~,~,~,`,~,~,~,~,` +,`,~,~,~,~,`,~,~,~,~,` +,`,`,`,`,`,`,`,`,`,`,` +,~,`,s,`,`,~,`,`,s,`,~ +,,,,d,d,,d,d +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` + +#notes label(guildhall_help) guildhall level walkthrough +"Eight 7x7 rooms for guildhalls, temples, libraries, etc." +Screenshot: https://drive.google.com/file/d/1mt66QOkfBqFLtw6AJKU6GNYmhB72XSJG +"" +Features: +"- Big rooms, optionally pre-furnished. Double-thick walls to ensure engravings add maximum value. Pre-made meeting zones can be made into locations (e.g. guildhalls) as needed. Optional pre-configured library/temple combo." +"" +"Each 7x7 room will be worth about 3000 when fully engraved (with random quality of engravings). This will get you past the first ""tier"" threshold at standard difficulty settings. Add artifacts to the display cases or other fancy decorations if you need more value. You can also assign multiple 7x7 rooms to the same zone or location and gain more value that way." +"" +Guildhall Walkthrough: +1) Dig out the rooms with /guildhall1. +"" +"2) Once the area is dug out, choose a /guildhall2 variant based on your needs. For your first copy of this level, you probably want /guildhall2_default, which configures the temple and library zones as fully usable locations. For later copies you probably want to create all locations yourself, so you should choose /guildhall2_no_locations if you want the default furnishings or /guildhall2_custom for just the zones and doors, leaving the furnishings up to you. Generate manager orders for your chosen variant." +"" +"Note that the default temple and library are created ""Citizens and Long-Term Residents only"", but you can change this in the location configuration screen if you want them to attract visitors. If you need more rooms, you can dig another /guildhall1 in an unused z-level." +"#dig label(guildhall1) start(15; 15; central stairs) message(Once the area is dug out, continue with /guildhall2.)" + + +,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d +,,,,,,,,,d,,,,d,,d,,,,d +,,,,,,,,,,d,d,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,,d,,,d,,d,,,d,,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,,d,,d,d,d,d,d,,d,,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,d,d,d,d,`,`,`,d,d,d,d,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,,d,,d,`,`,`,d,,d,,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,d,d,d,d,`,`,`,d,d,d,d,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,,d,,d,d,d,d,d,,d,,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,,d,,,d,,d,,,d,,d,d,d,d,d,d,d +,,,,,,,,,,d,d,d,d,d,d,d,d,d +,,,,,,,,,d,,,,d,,d,,,,d +,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d + + +#meta label(guildhall2_default) furnished with default temple and library +locations/guildhall_locations +doors/guildhall_doors +furnish/guildhall_furnish +smooth/guildhall_smooth +"" +#meta label(guildhall2_no_locations) fully furnished and zoned but no locations +zones/guildhall_zones +doors/guildhall_doors +furnish/guildhall_furnish +smooth/guildhall_smooth +"" +#meta label(guildhall2_custom) only zones and doors +zones/guildhall_zones +doors/guildhall_doors +"" +"#zone label(guildhall_locations) start(15; 15; central stairs) hidden() message(The library and temple are restricted to residents only by default. If you'd like them to attract vistors, please go to the location screen and change the restrictions.) declare a library and temple" + +,m(9x9),,,,,,,,,"m{location=temple name=""All-inclusive temple"" allow=residents}(9x9)",,,,,,,,,m(9x9) +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,,,,,,,,~,,,,~,,~,,,,~ +,m(9x9),,,,,,,,,`,`,`,`,`,`,`,`,`,m(9x9) +,,`,`,`,`,`,`,`,,`,,,~,,~,,,`,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,~,`,~,`,,,,`,~,`,~,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,,`,,`,,`,,`,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,~,`,~,`,,,,`,~,`,~,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,,,~,,~,,,`,,`,`,`,`,`,`,` +,,,,,,,,,,`,`,`,`,`,`,`,`,` +,m(9x9),,,,,,,,~,m{location=library name=Library allow=residents}(9x9),,,~,,~,,,,m(9x9) +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` + + +"#zone label(guildhall_zones) start(15; 15; central stairs) hidden() designate zones, ready for custom locations to be assigned" + +,m(9x9),,,,,,,,,m(9x9),,,,,,,,,m(9x9) +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,,,,,,,,~,,,,~,,~,,,,~ +,m(9x9),,,,,,,,,`,`,`,`,`,`,`,`,`,m(9x9) +,,`,`,`,`,`,`,`,,`,,,~,,~,,,`,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,~,`,~,`,,,,`,~,`,~,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,,`,,`,,`,,`,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,~,`,~,`,,,,`,~,`,~,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,,,~,,~,,,`,,`,`,`,`,`,`,` +,,,,,,,,,,`,`,`,`,`,`,`,`,` +,m(9x9),,,,,,,,~,m(9x9),,,~,,~,,,,m(9x9) +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` + + +#build label(guildhall_doors) start(15; 15; central stairs) hidden() message(Remember to enqueue manager orders for this blueprint.) build doors + + +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,,,,,,,,d,,,,d,,d,,,,d +,,,,,,,,,,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,,,d{name=Guidhall},,d{name=Guidhall},,,`,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,d,`,d{name=Guidhall},`,,,,`,d{name=Guidhall},`,d,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,,`,,`,,`,,`,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,d,`,d{name=Guidhall},`,,,,`,d{name=Guidhall},`,d,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,,,d{name=Guidhall},,d{name=Guidhall},,,`,,`,`,`,`,`,`,` +,,,,,,,,,,`,`,`,`,`,`,`,`,` +,,,,,,,,,d,,,,d,,d,,,,d +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` + + +"#build label(guildhall_furnish) start(15; 15; central stairs) hidden() furnish 4 guildhalls, 3 temples, and a library" + + +,,F,`,`,`,s,`,`,,,F,`,`,c,`,`,f,,,`,`,s,`,`,`,F +,,`,`,c,`,`,`,`,,,`,`,`,~a,h,`,s,,,`,`,`,`,c,`,` +,,`,c,t,c,`,`,s,,,`,`,`,`,`,`,`,,,s,`,`,c,t,c,` +,,`,`,c,`,c,`,`,,,`,`,`,`,`,`,`,,,`,`,c,`,c,`,` +,,s,`,`,c,t,c,`,,,`,`,c,c,c,`,`,,,`,c,t,c,`,`,s +,,`,`,`,`,c,`,`,,,`,`,c,c,c,`,`,,,`,`,c,`,`,`,` +,,`,`,s,`,`,`,`,,,t,`,`,`,`,`,t,,,`,`,`,`,s,`,` +,,,,,,,,,~,,,,~,,~,,,,~ +,,,,,,,,,,`,`,`,`,`,`,`,`,` +,,f,s,`,`,`,`,t,,`,,,~,,~,,,`,,t,`,`,`,`,s,f +,,`,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,`,`,`,` +,,`,h,`,`,c,c,`,~,`,~,`,,,,`,~,`,~,`,c,c,`,`,h,` +,,c,~a,`,`,c,c,`,,`,,`,,`,,`,,`,,`,c,c,`,`,~a,c +,,`,`,`,`,c,c,`,~,`,~,`,,,,`,~,`,~,`,c,c,`,`,`,` +,,`,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,`,`,`,` +,,F,`,`,`,`,`,t,,`,,,~,,~,,,`,,t,`,`,`,`,`,F +,,,,,,,,,,`,`,`,`,`,`,`,`,` +,,,,,,,,,~,,,,~,,~,,,,~ +,,`,`,s,`,`,`,`,,,t,`,`,`,`,`,t,,,`,`,`,`,s,`,` +,,`,`,`,`,c,`,`,,,`,`,`,`,`,`,`,,,`,`,c,`,`,`,` +,,s,`,`,c,t,c,`,,,t,c,`,`,`,c,t,,,`,c,t,c,`,`,s +,,`,`,c,`,c,`,`,,,t,c,`,`,`,c,t,,,`,`,c,`,c,`,` +,,`,c,t,c,`,`,s,,,t,c,`,`,`,c,t,,,s,`,`,c,t,c,` +,,`,`,c,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,c,`,` +,,F,`,`,`,s,`,`,,,h,~c,~c,s,~c,~c,h,,,`,`,s,`,`,`,F + + +#dig label(guildhall_smooth) start(15; 15; central stairs) hidden() smooth statue tiles + + +,,s,`,`,`,s,`,`,,,s,`,`,`,`,`,`,,,`,`,s,`,`,`,s +,,`,`,`,`,`,`,`,,,`,`,`,s,`,`,s,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,s,,,`,`,`,`,`,`,`,,,s,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,s,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,s +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,s,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,s,`,` +,,,,,,,,,`,,,,`,,`,,,,` +,,,,,,,,,,`,`,`,`,`,`,`,`,` +,,`,s,`,`,`,`,`,,`,,,`,,`,,,`,,`,`,`,`,`,s,` +,,`,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,`,`,`,`,`,` +,,`,s,`,`,`,`,`,,`,,`,,`,,`,,`,,`,`,`,`,`,s,` +,,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,`,`,`,` +,,s,`,`,`,`,`,`,,`,,,`,,`,,,`,,`,`,`,`,`,`,s +,,,,,,,,,,`,`,`,`,`,`,`,`,` +,,,,,,,,,`,,,,`,,`,,,,` +,,`,`,s,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,s,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,s,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,s +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,s,,,`,`,`,`,`,`,`,,,s,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,s,`,`,`,s,`,`,,,`,s,s,s,s,s,`,,,`,`,s,`,`,`,s + + +#notes label(beds_help) walkthrough for the suites and apartments levels +Suites for nobles and apartments for the teeming masses +Suites screenshot: https://drive.google.com/file/d/16XRb1w5zFoyVq2LBMx_aCwOyjFq7GULc +Apt. screenshot: https://drive.google.com/file/d/16-NXlodLIQjeZUMSmsWRafeytwU2dXQo +"" +Features: +- Well-appointed suites to satisfy nobles or citizens with a need for opulence +"- Suite rooms are multi-functional. Any suite can be zoned as a bedroom, office, dining hall, or tomb. If a noble requires more wealth than what a default room provides, you can smooth, engrave, add furniture, or include multiple rooms in the zone. A default suites level can fully satisfy a monarch if each zone covers four (engraved) rooms." +- Apartments with beds and storage to keep dwarves happy and the fortress clean +"" +Suites Walkthrough: +1) Dig out the suites layer with /suites1. +"" +"2) Once the area is dug out, choose a /suites2 variant based on your needs. For your first copy of this level, you probably want /suites2_default, which defines zones and assigns them to the usual cohort of demanding nobles and administrators. For later copies where your needs are ad hoc, you can choose /suites2_no_zones. Generate manager orders for your chosen variant." +"" +Apartments Walkthrough: +"1) Dig out one layer of apartments with /apartments1, or 3 layers at once (180 bedrooms total) by configuring gui/quickfort to repeat down 3 levels." +"" +"2) Once a layer is dug out, build furniture with /apartments2. Generate manager orders for /apartments2." +"#dig label(suites1) start(18; 18; central stairs) message(Once the area is dug out, run /suites2) noble suites" + +,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,d,,,,d,,,,,,,d,,,,d,d,d,,,,d,,,,,,,d,,,,d +,d,,d,d,d,d,d,,,d,d,d,d,d,,d,,d,,d,d,d,d,d,,,d,d,d,d,d,,d +,d,,d,d,d,d,d,,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,,d,d,d,d,d,,d +,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d +,d,,d,d,d,d,d,,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,,d,d,d,d,d,,d +,d,,d,d,d,d,d,,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,,d,d,d,d,d,,d +,d,,,,,,,,,,,,,,,d,d,d,,,,,,,,,,,,,,,d +,d,,,,,,,,,,,,,,,d,d,d,,,,,,,,,,,,,,,d +,d,,d,d,d,d,d,,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,,d,d,d,d,d,,d +,d,,d,d,d,d,d,,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,,d,d,d,d,d,,d +,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d +,d,,d,d,d,d,d,,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,,d,d,d,d,d,,d +,d,,d,d,d,d,d,,,d,d,d,d,d,,d,,d,,d,d,d,d,d,,,d,d,d,d,d,,d +,d,,,,d,,,,,,,d,,,,d,d,d,,,,d,,,,,,,d,,,,d +,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,`,`,`,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,d,d,,d,d,d,d,d,d,d,d,d,d,,d,`,~,`,d,,d,d,d,d,d,d,d,d,d,d,,d,d +,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,`,`,`,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,d,,,,d,,,,,,,d,,,,d,d,d,,,,d,,,,,,,d,,,,d +,d,,d,d,d,d,d,,,d,d,d,d,d,,d,,d,,d,d,d,d,d,,,d,d,d,d,d,,d +,d,,d,d,d,d,d,,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,,d,d,d,d,d,,d +,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d +,d,,d,d,d,d,d,,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,,d,d,d,d,d,,d +,d,,d,d,d,d,d,,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,,d,d,d,d,d,,d +,d,,,,,,,,,,,,,,,d,d,d,,,,,,,,,,,,,,,d +,d,,,,,,,,,,,,,,,d,d,d,,,,,,,,,,,,,,,d +,d,,d,d,d,d,d,,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,,d,d,d,d,d,,d +,d,,d,d,d,d,d,,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,,d,d,d,d,d,,d +,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d +,d,,d,d,d,d,d,,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,,d,d,d,d,d,,d +,d,,d,d,d,d,d,,,d,d,d,d,d,,d,,d,,d,d,d,d,d,,,d,d,d,d,d,,d +,d,,,,d,,,,,,,d,,,,d,d,d,,,,d,,,,,,,d,,,,d +,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d + +"#meta label(suites2_default) start(central stairs) message(Remember to enqueue manager orders for this blueprint.) build furniture, set traffic patterns, create zones, and assign them to nobles and administrators" +traffic_suites/suites_traffic +build_suites/suites_build +smooth_suites/suites_smooth +zone_suites/suites_zone +"" +"#meta label(suites2_no_zones) start(central stairs) message(Remember to enqueue manager orders for this blueprint. +rooms are left unzoned so you can configure them for specific nobles.) build furniture and set traffic patterns" +traffic_suites/suites_traffic +build_suites/suites_build +smooth_suites/suites_smooth +#dig label(suites_traffic) start(18; 18; central stairs) hidden() don't path through other dwarves' rooms + +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,,,,or,,,,,,,or,,,,`,`,`,,,,or,,,,,,,or,,,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,oh,,oh,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,or,`,`,`,`,`,,,`,`,`,`,`,or,oh,`,oh,or,`,`,`,`,`,,,`,`,`,`,`,or,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,,,,,,,,,,,,,,oh,`,oh,,,,,,,,,,,,,,,` +,`,,,,,,,,,,,,,,,oh,`,oh,,,,,,,,,,,,,,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,or,`,`,`,`,`,,,`,`,`,`,`,or,oh,`,oh,or,`,`,`,`,`,,,`,`,`,`,`,or,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,oh,,oh,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,,,or,,,,,,,or,,,,oh,`,oh,,,,or,,,,,,,or,,,,` +,`,`,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,`,`,`,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,`,` +,`,`,,`,`,`,`,`,`,`,`,`,`,,`,`,~,`,`,,`,`,`,`,`,`,`,`,`,`,,`,` +,`,`,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,`,`,`,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,`,` +,`,,,,or,,,,,,,or,,,,oh,`,oh,,,,or,,,,,,,or,,,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,oh,,oh,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,or,`,`,`,`,`,,,`,`,`,`,`,or,oh,`,oh,or,`,`,`,`,`,,,`,`,`,`,`,or,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,,,,,,,,,,,,,,oh,`,oh,,,,,,,,,,,,,,,` +,`,,,,,,,,,,,,,,,oh,`,oh,,,,,,,,,,,,,,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,or,`,`,`,`,`,,,`,`,`,`,`,or,oh,`,oh,or,`,`,`,`,`,,,`,`,`,`,`,or,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,oh,,oh,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,,,or,,,,,,,or,,,,`,`,`,,,,or,,,,,,,or,,,,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` + +#build label(suites_build) start(18; 18; central stairs) hidden() + +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,,,,d,,,,,,,d,,,,`,`,`,,,,d,,,,,,,d,,,,` +,`,,a,r,`,`,h,,,h,`,`,r,a,,d,,d,,a,r,`,`,h,,,h,`,`,r,a,,` +,`,,`,`,`,`,h,,,h,`,`,`,`,,`,`,`,,`,`,`,`,h,,,h,`,`,`,`,,` +,`,d,`,`,b,`,`,,,`,`,b,`,`,d,`,`,`,d,`,`,b,`,`,,,`,`,b,`,`,d,` +,`,,c,`,`,`,f,,,f,`,`,`,c,,`,`,`,,c,`,`,`,f,,,f,`,`,`,c,,` +,`,,t,`,s,`,n,,,n,`,s,`,t,,`,s,`,,t,`,s,`,n,,,n,`,s,`,t,,` +,`,,,,,,,,,,,,,,,`,`,`,,,,,,,,,,,,,,,` +,`,,,,,,,,,,,,,,,`,`,`,,,,,,,,,,,,,,,` +,`,,t,`,s,`,n,,,n,`,s,`,t,,`,s,`,,t,`,s,`,n,,,n,`,s,`,t,,` +,`,,c,`,`,`,f,,,f,`,`,`,c,,`,`,`,,c,`,`,`,f,,,f,`,`,`,c,,` +,`,d,`,`,b,`,`,,,`,`,b,`,`,d,`,`,`,d,`,`,b,`,`,,,`,`,b,`,`,d,` +,`,,`,`,`,`,h,,,h,`,`,`,`,,`,`,`,,`,`,`,`,h,,,h,`,`,`,`,,` +,`,,a,r,`,`,h,,,h,`,`,r,a,,d{name=Suites},,d{name=Suites},,a,r,`,`,h,,,h,`,`,r,a,,` +,`,,,,d,,,,,,,d,,,,`,`,`,,,,d,,,,,,,d,,,,` +,`,`,d,`,`,`,`,`,`,`,`,`,`,d{name=Suites},`,`,`,`,`,d{name=Suites},`,`,`,`,`,`,`,`,`,`,d,`,` +,`,`,,`,`,`,s,`,`,s,`,`,`,,`,`,~,`,`,,`,`,`,s,`,`,s,`,`,`,,`,` +,`,`,d,`,`,`,`,`,`,`,`,`,`,d{name=Suites},`,`,`,`,`,d{name=Suites},`,`,`,`,`,`,`,`,`,`,d,`,` +,`,,,,d,,,,,,,d,,,,`,`,`,,,,d,,,,,,,d,,,,` +,`,,a,r,`,`,h,,,h,`,`,r,a,,d{name=Suites},,d{name=Suites},,a,r,`,`,h,,,h,`,`,r,a,,` +,`,,`,`,`,`,h,,,h,`,`,`,`,,`,`,`,,`,`,`,`,h,,,h,`,`,`,`,,` +,`,d,`,`,b,`,`,,,`,`,b,`,`,d,`,`,`,d,`,`,b,`,`,,,`,`,b,`,`,d,` +,`,,c,`,`,`,f,,,f,`,`,`,c,,`,`,`,,c,`,`,`,f,,,f,`,`,`,c,,` +,`,,t,`,s,`,n,,,n,`,s,`,t,,`,s,`,,t,`,s,`,n,,,n,`,s,`,t,,` +,`,,,,,,,,,,,,,,,`,`,`,,,,,,,,,,,,,,,` +,`,,,,,,,,,,,,,,,`,`,`,,,,,,,,,,,,,,,` +,`,,t,`,s,`,n,,,n,`,s,`,t,,`,s,`,,t,`,s,`,n,,,n,`,s,`,t,,` +,`,,c,`,`,`,f,,,f,`,`,`,c,,`,`,`,,c,`,`,`,f,,,f,`,`,`,c,,` +,`,d,`,`,b,`,`,,,`,`,b,`,`,d,`,`,`,d,`,`,b,`,`,,,`,`,b,`,`,d,` +,`,,`,`,`,`,h,,,h,`,`,`,`,,`,`,`,,`,`,`,`,h,,,h,`,`,`,`,,` +,`,,a,r,`,`,h,,,h,`,`,r,a,,d,,d,,a,r,`,`,h,,,h,`,`,r,a,,` +,`,,,,d,,,,,,,d,,,,`,`,`,,,,d,,,,,,,d,,,,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` + +#dig label(suites_smooth) start(18; 18; central stairs) hidden() smooth statue tiles + +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,,,,`,,,,,,,`,,,,`,`,`,,,,`,,,,,,,`,,,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,`,,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,`,`,s,`,`,,,`,`,s,`,`,,`,s,`,,`,`,s,`,`,,,`,`,s,`,`,,` +,`,,,,,,,,,,,,,,,`,`,`,,,,,,,,,,,,,,,` +,`,,,,,,,,,,,,,,,`,`,`,,,,,,,,,,,,,,,` +,`,,`,`,s,`,`,,,`,`,s,`,`,,`,s,`,,`,`,s,`,`,,,`,`,s,`,`,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,`,,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,,,`,,,,,,,`,,,,`,`,`,,,,`,,,,,,,`,,,,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,,`,`,`,s,`,`,s,`,`,`,,`,`,~,`,`,,`,`,`,s,`,`,s,`,`,`,,`,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,,,,`,,,,,,,`,,,,`,`,`,,,,`,,,,,,,`,,,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,`,,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,`,`,s,`,`,,,`,`,s,`,`,,`,s,`,,`,`,s,`,`,,,`,`,s,`,`,,` +,`,,,,,,,,,,,,,,,`,`,`,,,,,,,,,,,,,,,` +,`,,,,,,,,,,,,,,,`,`,`,,,,,,,,,,,,,,,` +,`,,`,`,s,`,`,,,`,`,s,`,`,,`,s,`,,`,`,s,`,`,,,`,`,s,`,`,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,`,,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,,,`,,,,,,,`,,,,`,`,`,,,,`,,,,,,,`,,,,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` + +#zone label(suites_zone) start(18; 18; central stairs) hidden() + +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,h{assigned_unit=sheriff},h,h,b{assigned_unit=sheriff},b,b,b,o{assigned_unit=mayor}(7x7),,,`,,,,`,`,`,o{assigned_unit=baron}(7x7),,,`,,,,T{assigned_unit=baron}(7x7),,,`,,,,` +,`,h,h,h,b,b,b,b,,`,`,`,`,`,,`,,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,h,h,h,b,b,b,b,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,h,h,h,b,b,b,b,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,`,h,h,h,h,b,b,b,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,h,h,h,h,b,b,b,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,h,h,h,h,b,b,b,,,,,,,,`,`,`,,,,,,,,,,,,,,,` +,`,h{assigned_unit=mayor}(7x7),,,,,,,b{assigned_unit=mayor}(7x7),,,,,,,`,`,`,b{assigned_unit=baron}(7x7),,,,,,,h{assigned_unit=baron}(7x7),,,,,,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,`,,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,,,`,,,,,,,`,,,,`,`,`,,,,`,,,,,,,`,,,,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,,`,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,h{assigned_unit=outpost_liaison}(7x7),,,`,,,,b{assigned_unit=outpost_liaison}(7x7),,,`,,,,`,`,`,b{assigned_unit=monarch}(7x7),,,`,,,,h{assigned_unit=monarch}(7x7),,,`,,,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,`,,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,,,,,,,,,,,,,,`,`,`,,,,,,,,,,,,,,,` +,`,T{assigned_unit=monarch}(7x7),,,,,,,o{assigned_unit=outpost_liaison}(7x7),,,,,,,`,`,`,o{assigned_unit=monarch}(14x7),,,,,,,,,,,,,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,`,,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,,,`,,,,,,,`,,,,`,`,`,,,,`,,,,,,,`,,,,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` + +"#dig label(apartments1) start(18; 18; central stairs) message(Once the area is dug out, continue with /apartments2.) apartment complex" + +,,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d +,,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d +,,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d +,,,,d,,,d,,,d,,,d,,,d,,d,,,d,,,d,,,d,,,d +,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,d,,,d,,,d,,,d,,,d,,d,d,d,,d,,,d,,,d,,,d,,,d +,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,d,,d,d,,d,d,,d,d,,d,d,,d,d +,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,d,,d,d,,d,d,,d,d,,d,d,,d,d +,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,d,,d,d,,d,d,,d,d,,d,d,,d,d +,,,,,,,,,,,,,,,,d,d,d +,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,d,,d,d,,d,d,,d,d,,d,d,,d,d +,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,d,,d,d,,d,d,,d,d,,d,d,,d,d +,d,d,,d,d,,d,d,,d,d,,d,d,,d,,d,,d,d,,d,d,,d,d,,d,d,,d,d +,d,,,d,,,d,,,d,,,d,,,d,d,d,,,d,,,d,,,d,,,d,,,d +,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,`,`,`,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,d,d,d,d,d,d,d,d,d,d,d,d,d,,d,`,~,`,d,,d,d,d,d,d,d,d,d,d,d,d,d,d +,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,`,`,`,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,d,,,d,,,d,,,d,,,d,,,d,d,d,,,d,,,d,,,d,,,d,,,d +,d,d,,d,d,,d,d,,d,d,,d,d,,d,,d,,d,d,,d,d,,d,d,,d,d,,d,d +,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,d,,d,d,,d,d,,d,d,,d,d,,d,d +,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,d,,d,d,,d,d,,d,d,,d,d,,d,d +,,,,,,,,,,,,,,,,d,d,d +,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,d,,d,d,,d,d,,d,d,,d,d,,d,d +,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,d,,d,d,,d,d,,d,d,,d,d,,d,d +,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,d,,d,d,,d,d,,d,d,,d,d,,d,d +,,d,,,d,,,d,,,d,,,d,,d,d,d,,d,,,d,,,d,,,d,,,d +,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,,,d,,,d,,,d,,,d,,,d,,d,,,d,,,d,,,d,,,d +,,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d +,,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d +,,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d + +#meta label(apartments2) start(central stairs) zone rooms and build furniture +zone_apartments/apartments_rooms +build_apartments/apartments_build +#zone label(apartments_rooms) start(18; 18; central stairs) hidden() zone rooms +,,b(4x5),,,b(4x5),,,b(4x5),,,b(4x5),,,b(4x5),,,b(4x5),,,b(4x5),,,b(4x5),,,b(4x5),,,b(4x5) +,,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,,,,`,,,`,,,`,,,`,,,`,,`,,,`,,,`,,,`,,,` +,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +b(4x5),,`,b(4x5),,`,b(4x5),,`,b(4x5),,`,b(4x5),,`,,`,`,`,b(4x5),`,,b(4x5),`,,b(4x5),`,,b(4x5),`,,b(4x5),` +,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +b(4x5),,,b(4x5),,,b(4x5),,,b(4x5),,,b(4x5),,,,`,`,`,b(4x5),,,b(4x5),,,b(4x5),,,b(4x5),,,b(4x5) +,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,`,`,,`,`,,`,`,,`,`,,`,`,,`,,`,,`,`,,`,`,,`,`,,`,`,,`,` +,`,,,`,,,`,,,`,,,`,,,`,`,`,,,`,,,`,,,`,,,`,,,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,~,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +b(4x5),`,,b(4x5),`,,b(4x5),`,,b(4x5),`,,b(4x5),`,,,`,`,`,b(4x5),,`,b(4x5),,`,b(4x5),,`,b(4x5),,`,b(4x5),,` +,`,`,,`,`,,`,`,,`,`,,`,`,,`,,`,,`,`,,`,`,,`,`,,`,`,,`,` +,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +b(4x5),,,b(4x5),,,b(4x5),,,b(4x5),,,b(4x5),,,,`,`,`,b(4x5),,,b(4x5),,,b(4x5),,,b(4x5),,,b(4x5) +,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,,`,,,`,,,`,,,`,,,`,,`,`,`,,`,,,`,,,`,,,`,,,` +,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,b(4x5),,`,b(4x5),,`,b(4x5),,`,b(4x5),,`,b(4x5),,`,b(4x5),`,,b(4x5),`,,b(4x5),`,,b(4x5),`,,b(4x5),` +,,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,` + +#build label(apartments_build) start(18; 18; central stairs) hidden() message(Remember to enqueue manager orders for this blueprint.) build furniture + +,,,f,h,,f,h,,f,h,,f,h,,f,h,,h,f,,h,f,,h,f,,h,f,,h,f +,,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,,,b,`,,b,`,,b,`,,b,`,,b,`,,`,b,,`,b,,`,b,,`,b,,`,b +,,,,d,,,d,,,d,,,d,,,d,,d,,,d,,,d,,,d,,,d +,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,d,,,d,,,d,,,d,,,d,,`,`,`,,d,,,d,,,d,,,d,,,d +,b,`,,b,`,,b,`,,b,`,,b,`,,`,`,`,,`,b,,`,b,,`,b,,`,b,,`,b +,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,f,h,,f,h,,f,h,,f,h,,f,h,,`,`,`,,h,f,,h,f,,h,f,,h,f,,h,f +,,,,,,,,,,,,,,,,`,`,` +,h,f,,h,f,,h,f,,h,f,,h,f,,`,`,`,,f,h,,f,h,,f,h,,f,h,,f,h +,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,`,b,,`,b,,`,b,,`,b,,`,b,,d{name=Apartments},,d{name=Apartments},,b,`,,b,`,,b,`,,b,`,,b,` +,d,,,d,,,d,,,d,,,d,,,`,`,`,,,d,,,d,,,d,,,d,,,d +,`,`,`,`,`,`,`,`,`,`,`,`,`,d{name=Apartments},`,`,`,`,`,d{name=Apartments},`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,~,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,d{name=Apartments},`,`,`,`,`,d{name=Apartments},`,`,`,`,`,`,`,`,`,`,`,`,` +,d,,,d,,,d,,,d,,,d,,,`,`,`,,,d,,,d,,,d,,,d,,,d +,`,b,,`,b,,`,b,,`,b,,`,b,,d{name=Apartments},,d{name=Apartments},,b,`,,b,`,,b,`,,b,`,,b,` +,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,h,f,,h,f,,h,f,,h,f,,h,f,,`,`,`,,f,h,,f,h,,f,h,,f,h,,f,h +,,,,,,,,,,,,,,,,`,`,` +,f,h,,f,h,,f,h,,f,h,,f,h,,`,`,`,,h,f,,h,f,,h,f,,h,f,,h,f +,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,b,`,,b,`,,b,`,,b,`,,b,`,,`,`,`,,`,b,,`,b,,`,b,,`,b,,`,b +,,d,,,d,,,d,,,d,,,d,,`,`,`,,d,,,d,,,d,,,d,,,d +,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,d,,,d,,,d,,,d,,,d,,d,,,d,,,d,,,d,,,d +,,,b,`,,b,`,,b,`,,b,`,,b,`,,`,b,,`,b,,`,b,,`,b,,`,b +,,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,,,f,h,,f,h,,f,h,,f,h,,f,h,,h,f,,h,f,,h,f,,h,f,,h,f + +#notes label(crypt_help) crypt level walkthrough +Places to rest your dead +Screenshot: https://drive.google.com/file/d/16iT_ho7BIRPD_eofuxdlVQ4FunR1Li23 +"" +Features: +"- Staged crypt expansion that grows with your, um, need" +- 20 tombs in stage 1 +- 192 additional tombs in stage 2 (212 tombs total) +"- Extendable in any direction by reapplying the blueprints to the North, South, East, or West, overlapping by one tile" +"" +Crypt Walkthrough: +1) Dig out the layer with /crypt1. +"" +"2) Once the area is dug out, add initial tombs with /crypt2." +"" +"3) If/when you need additional tombs, apply /crypt3." +"#dig label(crypt1) start(18; 18; central stairs) message(Once the area is dug out, continue with /crypt2.) crypt complex" + +,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d +,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d +,d,d,d,d,d,d,d,d,d,d,d,d,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d +,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d +,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d +,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d +,d,d,d,d,d,d,d,d,d,d,d,d,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d +,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d +,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d +,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d +,d,d,d,d,d,d,d,d,d,d,d,d,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d +,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d +,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d +,,d,,d,,d,,d,,d,,d,,d,,d,d,d,,d,,d,,d,,d,,d,,d,,d +,d,d,d,d,d,d,d,d,d,d,d,d,,,,d,d,d,,,,d,d,d,d,d,d,d,d,d,d,d,d +,,d,,d,,d,,d,,d,,d,d,d,d,,,,d,d,d,d,,d,,d,,d,,d,,d +,,,,,,,,,,,,d,d,d,d,,~,,d,d,d,d +,,d,,d,,d,,d,,d,,d,d,d,d,,,,d,d,d,d,,d,,d,,d,,d,,d +,d,d,d,d,d,d,d,d,d,d,d,d,,,,d,d,d,,,,d,d,d,d,d,d,d,d,d,d,d,d +,,d,,d,,d,,d,,d,,d,,d,,d,d,d,,d,,d,,d,,d,,d,,d,,d +,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d +,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d +,d,d,d,d,d,d,d,d,d,d,d,d,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d +,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d +,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d +,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d +,d,d,d,d,d,d,d,d,d,d,d,d,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d +,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d +,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d +,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d +,d,d,d,d,d,d,d,d,d,d,d,d,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d +,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d +,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d + +#meta label(crypt2) start(central stairs) small crypt that can be extended later +zone/crypt_zone +build/crypt_build +"" +#meta label(crypt3) start(central stairs) crypt extension +zone_extended/crypt_extended_zone +build_extended/crypt_extended_build +#zone label(crypt_zone) start(18; 18; central stairs) hidden() zone tombs + + + + + + + + + +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,` +,,,,,,,,,,,`,`,,,,,,,,,,`,` +,,,,,,,,,,,,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,` +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,,`,,T{pets=true}(1x1),,`,`,`,,T{pets=true}(1x1),,` +,,,,,,,,,,,`,`,,,,`,`,`,,,,`,` +,,,,,,,,,,,,`,`,`,`,,,,`,`,`,` +,,,,,,,,,,,,`,`,`,`,,~,,`,`,`,` +,,,,,,,,,,,,`,`,`,`,,,,`,`,`,` +,,,,,,,,,,,`,`,,,,`,`,`,,,,`,` +,,,,,,,,,,,,`,,T{pets=true}(1x1),,`,`,`,,T{pets=true}(1x1),,` +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,` +,,,,,,,,,,,`,`,,,,,,,,,,`,` +,,,,,,,,,,,,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,` +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` + + + + + + + + + +#build label(crypt_build) start(18; 18; central stairs) hidden() message(Remember to enqueue manager orders for this blueprint.) build urns + + + + + + + + + +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,,`,,n,,n,,n,,n,,` +,,,,,,,,,,,`,`,,,,,,,,,,`,` +,,,,,,,,,,,,`,,n,,n,,n,,n,,` +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,,`,,n,,`,s{name=Crypt},`,,n,,` +,,,,,,,,,,,`,`,,,,`,`,`,,,,`,` +,,,,,,,,,,,,`,`,`,`,,,,`,`,`,` +,,,,,,,,,,,,`,`,s{name=Crypt},`,,~,,`,s{name=Crypt},`,` +,,,,,,,,,,,,`,`,`,`,,,,`,`,`,` +,,,,,,,,,,,`,`,,,,`,`,`,,,,`,` +,,,,,,,,,,,,`,,n,,`,s{name=Crypt},`,,n,,` +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,,`,,n,,n,,n,,n,,` +,,,,,,,,,,,`,`,,,,,,,,,,`,` +,,,,,,,,,,,,`,,n,,n,,n,,n,,` +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` + + + + + + + + + +#zone label(crypt_extended_zone) start(18; 18; central stairs) hidden() zone more tombs + +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1) +,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1) +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1) +,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1) +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,~,,~,,~,,~,,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1) +,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,~,,~,,~,,~,,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1) +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,~,,`,`,`,,~,,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1) +,`,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,`,`,`,,,,`,`,`,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1) +,,,,,,,,,,,,`,`,`,`,,~,,`,`,`,` +,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,`,`,`,,,,`,`,`,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1) +,`,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,~,,`,`,`,,~,,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1) +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,~,,~,,~,,~,,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1) +,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,~,,~,,~,,~,,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1) +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1) +,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1) +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1) +,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1) +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` + +#build label(crypt_extended_build) start(18; 18; central stairs) hidden() message(Remember to enqueue manager orders for this blueprint.) build more urns + +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,n,,n,,n,,n,,n,,`,,n,,n,,n,,n,,`,,n,,n,,n,,n,,n +,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,n,,n,,n,,n,,n,,`,,n,,n,,n,,n,,`,,n,,n,,n,,n,,n +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,n,,n,,n,,n,,n,,`,,n,,n,,n,,n,,`,,n,,n,,n,,n,,n +,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,n,,n,,n,,n,,n,,`,,n,,n,,n,,n,,`,,n,,n,,n,,n,,n +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,n,,n,,n,,n,,n,,`,,~,,~,,~,,~,,`,,n,,n,,n,,n,,n +,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,n,,n,,n,,n,,n,,`,,~,,~,,~,,~,,`,,n,,n,,n,,n,,n +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,n,,n,,n,,n,,n,,`,,~,,`,~,`,,~,,`,,n,,n,,n,,n,,n +,`,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,n,,n,,n,,n,,n,,`,`,`,`,,,,`,`,`,`,,n,,n,,n,,n,,n +,,,,,,,,,,,,`,`,~,`,,~,,`,~,`,` +,,n,,n,,n,,n,,n,,`,`,`,`,,,,`,`,`,`,,n,,n,,n,,n,,n +,`,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,n,,n,,n,,n,,n,,`,,~,,`,~,`,,~,,`,,n,,n,,n,,n,,n +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,n,,n,,n,,n,,n,,`,,~,,~,,~,,~,,`,,n,,n,,n,,n,,n +,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,n,,n,,n,,n,,n,,`,,~,,~,,~,,~,,`,,n,,n,,n,,n,,n +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,n,,n,,n,,n,,n,,`,,n,,n,,n,,n,,`,,n,,n,,n,,n,,n +,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,n,,n,,n,,n,,n,,`,,n,,n,,n,,n,,`,,n,,n,,n,,n,,n +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,n,,n,,n,,n,,n,,`,,n,,n,,n,,n,,`,,n,,n,,n,,n,,n +,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,n,,n,,n,,n,,n,,`,,n,,n,,n,,n,,`,,n,,n,,n,,n,,n +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` diff --git a/data/blueprints/embark.csv b/data/blueprints/embark.csv new file mode 100644 index 0000000000..a92c328398 --- /dev/null +++ b/data/blueprints/embark.csv @@ -0,0 +1,17 @@ +#build label(workshops) start(8;2;center of wagon) basic post embark workshops +`,` ,`,`,` ,`,~,~,~,`,` ,`,`,` ,`,# +`,wc,`,`,wt,`,~,~,~,`,wm,`,`,wr,`,# +`,` ,`,`,` ,`,~,~,~,`,` ,`,`,` ,`,# +#,# ,#,#,# ,#,#,#,#,#,# ,#,#,# ,#,# +#place label(stockpiles) basic post embark stockpiles +w(5x10), , , , ,s(5x1) , , , , ,p(5x1), , , , ,# + , , , , ,g(5x4) , , , , ,d(5x1), , , , ,# + , , , , , , , , , ,f(5x3), , , , ,# + , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , ,# + , , , , ,u(10x5), , , , , , , , , ,# + , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , ,# +# ,#,#,#,#,# ,#,#,#,#,# ,#,#,#,#,# diff --git a/data/blueprints/exploratory-mining/connected-mineshafts.csv b/data/blueprints/exploratory-mining/connected-mineshafts.csv new file mode 100644 index 0000000000..3b4d71de2e --- /dev/null +++ b/data/blueprints/exploratory-mining/connected-mineshafts.csv @@ -0,0 +1,43 @@ +#dig diagonal interconnecting tunnels with stairs at intersections +d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d,# + ,d, , , , , , , ,d, ,d, , , , , , , ,d, ,d, , , , , , , ,d, ,d, , , , , , , ,d, ,# + , ,d, , , , , ,d, , , ,d, , , , , ,d, , , ,d, , , , , ,d, , , ,d, , , , , ,d, , ,# + , , ,d, , , ,d, , , , , ,d, , , ,d, , , , , ,d, , , ,d, , , , , ,d, , , ,d, , , ,# + , , , ,d, ,d, , , , , , , ,d, ,d, , , , , , , ,d, ,d, , , , , , , ,d, ,d, , , , ,# + , , , , ,i, , , , , , , , , ,i, , , , , , , , , ,i, , , , , , , , , ,i, , , , , ,# + , , , ,d, ,d, , , , , , , ,d, ,d, , , , , , , ,d, ,d, , , , , , , ,d, ,d, , , , ,# + , , ,d, , , ,d, , , , , ,d, , , ,d, , , , , ,d, , , ,d, , , , , ,d, , , ,d, , , ,# + , ,d, , , , , ,d, , , ,d, , , , , ,d, , , ,d, , , , , ,d, , , ,d, , , , , ,d, , ,# + ,d, , , , , , , ,d, ,d, , , , , , , ,d, ,d, , , , , , , ,d, ,d, , , , , , , ,d, ,# +d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d,# + ,d, , , , , , , ,d, ,d, , , , , , , ,d, ,d, , , , , , , ,d, ,d, , , , , , , ,d, ,# + , ,d, , , , , ,d, , , ,d, , , , , ,d, , , ,d, , , , , ,d, , , ,d, , , , , ,d, , ,# + , , ,d, , , ,d, , , , , ,d, , , ,d, , , , , ,d, , , ,d, , , , , ,d, , , ,d, , , ,# + , , , ,d, ,d, , , , , , , ,d, ,d, , , , , , , ,d, ,d, , , , , , , ,d, ,d, , , , ,# + , , , , ,i, , , , , , , , , ,i, , , , , , , , , ,i, , , , , , , , , ,i, , , , , ,# + , , , ,d, ,d, , , , , , , ,d, ,d, , , , , , , ,d, ,d, , , , , , , ,d, ,d, , , , ,# + , , ,d, , , ,d, , , , , ,d, , , ,d, , , , , ,d, , , ,d, , , , , ,d, , , ,d, , , ,# + , ,d, , , , , ,d, , , ,d, , , , , ,d, , , ,d, , , , , ,d, , , ,d, , , , , ,d, , ,# + ,d, , , , , , , ,d, ,d, , , , , , , ,d, ,d, , , , , , , ,d, ,d, , , , , , , ,d, ,# +d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d,# + ,d, , , , , , , ,d, ,d, , , , , , , ,d, ,d, , , , , , , ,d, ,d, , , , , , , ,d, ,# + , ,d, , , , , ,d, , , ,d, , , , , ,d, , , ,d, , , , , ,d, , , ,d, , , , , ,d, , ,# + , , ,d, , , ,d, , , , , ,d, , , ,d, , , , , ,d, , , ,d, , , , , ,d, , , ,d, , , ,# + , , , ,d, ,d, , , , , , , ,d, ,d, , , , , , , ,d, ,d, , , , , , , ,d, ,d, , , , ,# + , , , , ,i, , , , , , , , , ,i, , , , , , , , , ,i, , , , , , , , , ,i, , , , , ,# + , , , ,d, ,d, , , , , , , ,d, ,d, , , , , , , ,d, ,d, , , , , , , ,d, ,d, , , , ,# + , , ,d, , , ,d, , , , , ,d, , , ,d, , , , , ,d, , , ,d, , , , , ,d, , , ,d, , , ,# + , ,d, , , , , ,d, , , ,d, , , , , ,d, , , ,d, , , , , ,d, , , ,d, , , , , ,d, , ,# + ,d, , , , , , , ,d, ,d, , , , , , , ,d, ,d, , , , , , , ,d, ,d, , , , , , , ,d, ,# +d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d,# + ,d, , , , , , , ,d, ,d, , , , , , , ,d, ,d, , , , , , , ,d, ,d, , , , , , , ,d, ,# + , ,d, , , , , ,d, , , ,d, , , , , ,d, , , ,d, , , , , ,d, , , ,d, , , , , ,d, , ,# + , , ,d, , , ,d, , , , , ,d, , , ,d, , , , , ,d, , , ,d, , , , , ,d, , , ,d, , , ,# + , , , ,d, ,d, , , , , , , ,d, ,d, , , , , , , ,d, ,d, , , , , , , ,d, ,d, , , , ,# + , , , , ,i, , , , , , , , , ,i, , , , , , , , , ,i, , , , , , , , , ,i, , , , , ,# + , , , ,d, ,d, , , , , , , ,d, ,d, , , , , , , ,d, ,d, , , , , , , ,d, ,d, , , , ,# + , , ,d, , , ,d, , , , , ,d, , , ,d, , , , , ,d, , , ,d, , , , , ,d, , , ,d, , , ,# + , ,d, , , , , ,d, , , ,d, , , , , ,d, , , ,d, , , , , ,d, , , ,d, , , , , ,d, , ,# + ,d, , , , , , , ,d, ,d, , , , , , , ,d, ,d, , , , , , , ,d, ,d, , , , , , , ,d, ,# +d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d,# +#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# diff --git a/data/blueprints/exploratory-mining/tunnels.csv b/data/blueprints/exploratory-mining/tunnels.csv new file mode 100644 index 0000000000..4af994edec --- /dev/null +++ b/data/blueprints/exploratory-mining/tunnels.csv @@ -0,0 +1,52 @@ +#dig paths every 10 units +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d +d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d +d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d +d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d +d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d +d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d +d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d +d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d +d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d +d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d +d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d +d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d +d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d +d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d +d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d +d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d +d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d +d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d +d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d +d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d +d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d +d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d +d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d +d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d +d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d +d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d +d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d +d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d +d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d +d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d +d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d +d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d +d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d +d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d +d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d +d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d +d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d +d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d +d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d +d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d +d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d, , , , , , , , , ,d +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d diff --git a/data/blueprints/exploratory-mining/vertical-mineshafts.csv b/data/blueprints/exploratory-mining/vertical-mineshafts.csv new file mode 100644 index 0000000000..28b4de5631 --- /dev/null +++ b/data/blueprints/exploratory-mining/vertical-mineshafts.csv @@ -0,0 +1,42 @@ +#dig mineshafts as stairs every 3rd tile +i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,# + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# +i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,# + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# +i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,# + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# +i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,# + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# +i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,# + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# +i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,# + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# +i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,# + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# +i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,# + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# +i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,# + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# +i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,# + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# +i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,# + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# +i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,# + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# +i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,# + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# +i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,i, , ,# +#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# diff --git a/data/blueprints/layout-helpers/mark_down_left.csv b/data/blueprints/layout-helpers/mark_down_left.csv new file mode 100644 index 0000000000..84732ccf6c --- /dev/null +++ b/data/blueprints/layout-helpers/mark_down_left.csv @@ -0,0 +1,201 @@ +#dig start(200;1) marks a diagonal line down and left starting at the cursor +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,md +,,,,,,,,,,,,,md +,,,,,,,,,,,,md +,,,,,,,,,,,md +,,,,,,,,,,md +,,,,,,,,,md +,,,,,,,,md +,,,,,,,md +,,,,,,md +,,,,,md +,,,,md +,,,md +,,md +,md +md diff --git a/data/blueprints/layout-helpers/mark_down_right.csv b/data/blueprints/layout-helpers/mark_down_right.csv new file mode 100644 index 0000000000..07f6ae1d08 --- /dev/null +++ b/data/blueprints/layout-helpers/mark_down_right.csv @@ -0,0 +1,201 @@ +#dig start(1;1) marks a diagonal line down and right starting at the cursor +md +,md +,,md +,,,md +,,,,md +,,,,,md +,,,,,,md +,,,,,,,md +,,,,,,,,md +,,,,,,,,,md +,,,,,,,,,,md +,,,,,,,,,,,md +,,,,,,,,,,,,md +,,,,,,,,,,,,,md +,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md diff --git a/data/blueprints/layout-helpers/mark_up_left.csv b/data/blueprints/layout-helpers/mark_up_left.csv new file mode 100644 index 0000000000..a029136cd0 --- /dev/null +++ b/data/blueprints/layout-helpers/mark_up_left.csv @@ -0,0 +1,201 @@ +#dig start(200;200) marks a diagonal line up and left starting at the cursor +md +,md +,,md +,,,md +,,,,md +,,,,,md +,,,,,,md +,,,,,,,md +,,,,,,,,md +,,,,,,,,,md +,,,,,,,,,,md +,,,,,,,,,,,md +,,,,,,,,,,,,md +,,,,,,,,,,,,,md +,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md diff --git a/data/blueprints/layout-helpers/mark_up_right.csv b/data/blueprints/layout-helpers/mark_up_right.csv new file mode 100644 index 0000000000..8f2697d621 --- /dev/null +++ b/data/blueprints/layout-helpers/mark_up_right.csv @@ -0,0 +1,201 @@ +#dig start(1;200) marks a diagonal line up and right starting at the cursor +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,,md +,,,,,,,,,,,,,,md +,,,,,,,,,,,,,md +,,,,,,,,,,,,md +,,,,,,,,,,,md +,,,,,,,,,,md +,,,,,,,,,md +,,,,,,,,md +,,,,,,,md +,,,,,,md +,,,,,md +,,,,md +,,,md +,,md +,md +md diff --git a/data/blueprints/pump_stack.csv b/data/blueprints/pump_stack.csv new file mode 100644 index 0000000000..14ac78a37c --- /dev/null +++ b/data/blueprints/pump_stack.csv @@ -0,0 +1,80 @@ +#notes label(help) +A pump stack is useful for moving water or magma up through the z-levels. +"" +"1) Select the ""/dig"" blueprint and position the blueprint preview on the bottom level of the future pump stack. It should be on the z-level just above the liquid you want to pump." +"" +"2) Enable repetitions with the ""r"" hotkey (ensure you're repeating Up z-levels, not Down) and lock the blueprint in place with the ""L"" hotkey. Move up the z-levels to check that the pump stack has a clear path and doesn't intersect with any open areas (e.g. caverns). Increase the number of repetitions with the ""+"" or ""*"" hotkeys if you need the pump stack to extend further up. Unlock the blueprint and shift it around if you need to, then lock it again to recheck the vertical path." +"" +"3) If you need to flip the pump stack around to make it fit through the rock layers, enable transformations with the ""t"" hotkey and rotate/flip the blueprint as necessary." +"" +"4) Once you have everything lined up, hit Enter to apply. If the height ends up being one too many at the top, manually undesignate the top level." +"" +"5) Since the bottom up/down staircase is a liability, erase the Up/Down staircase designation on the lowest level and replace it with an Up staircase designation. Otherwise you might get water (or magma) critters climbing up through your access stairway!" +"" +"6) After the stack is dug out, haul away (or dump) any stones that are in the way of building the pumps." +"" +"7) Load up the ""/channel"" blueprint and apply it with the same repetition and transformation settings that you used for the ""/dig"" blueprint. Unless you have restarted DF, gui/quickfort will have saved your settings." +"" +"8) Since you do not need to transmit power down below the lowest level, erase the channel designation on the middle tile of the bottom-most pump stack level." +"" +"9) After the channels are dug, prepare for building by setting the buildingplan plugin material filters for screw pumps. If you are planning to move magma, be sure to select magma-safe materials (like green glass) for all three components of the screw pump." +"" +"10) Finally, generate orders for (the ""o"" hotkey) and run the ""/build"" blueprint with the same repetition and transformation settings that you used for the other blueprints. As you manufacture the materials you need to construct the screw pumps, your dwarves will build the pump stack from the bottom up, ensuring each new screw pump is properly supported by the one below." +"" +"If your dwarves end up building the pumps out of order, a section of the stack may spontaneously deconstruct. This will reduce the efficiency of the stack a little, but it's nothing to worry about. Just re-run the ""/build"" blueprint over the entire stack to ""fix up"" any broken pieces. The blueprint will harmlessly skip over any correctly-built screw pumps." +"" +See the wiki for more info on pump stacks: https://dwarffortresswiki.org/index.php/Screw_pump#Pump_stack +#dig label(digSN) start(2;4;on access stairs) hidden() for a pump from south level + +,,,mwmdd +,,,mwmdd +,mwmdi,mwmdd,mwmdd +,,,mwmdd + +#dig label(digNS) start(2;4;on access stairs) hidden() for a pump from north level + +,,,mwmdd +,mwmdd,mwmdd,mwmdd +,mwmdi,,mwmdd +,,,mwmdd + +#meta label(dig) start(at the bottom level on the access stairs) 2 levels of pump stack - bottom level pumps from the south +/digSN +#< +/digNS +#dig label(channelSN) start(2;4;on access stairs) hidden() for a pump from south level + +,,,` +,,,h +,~,`,` +,,,h + +#dig label(channelNS) start(2;4;on access stairs) hidden() for a pump from north level + +,,,h +,`,`,` +,~,,h +,,,` + +#meta label(channel) start(at the bottom level on the access stairs) 2 levels of pump stack - bottom level pumps from the south +/channelSN +#< +/channelNS +#build label(buildSN) start(2;4;on access stairs) hidden() for a pump from south level + +,,,` +,,,~ +,`,`,Msm +,,,` + +#build label(buildNS) start(2;4;on access stairs) hidden() for a pump from north level + +,,,` +,`,`,~ +,`,,Msu +,,,` + +#meta label(build) start(at the bottom level on the access stairs) 2 levels of pump stack - bottom level pumps from the south +/buildSN +#< +/buildNS diff --git a/data/blueprints/test/ecosystem/golden/meta-1-dig.csv b/data/blueprints/test/ecosystem/golden/meta-1-dig.csv new file mode 100644 index 0000000000..456d2ba92e --- /dev/null +++ b/data/blueprints/test/ecosystem/golden/meta-1-dig.csv @@ -0,0 +1,72 @@ +#dig label(dig) start(3;3) +d,d,,,d +d,,j,,d +d,u,d,u,d +d,,j +d,,,d,d +#> +d,d,d,d,d +,,u,,d +,j,d,j +d,,u +d,,d,d,d +#> +d,d,,,d +d,,j,,d +d,u,d,u,d +d,,j +d,,,d,d +#> +d,d,d,d,d +,,u,,d +,j,d,j +d,,u +d,,d,d,d +#> +d,d,,,d +d,,j,,d +d,u,d,u,d +d,,j +d,,,d,d +#> +d,d,d,d,d +,,u,,d +,j,d,j +d,,u +d,,d,d,d +#> +d,d,,,d +d,,j,,d +d,u,d,u,d +d,,j +d,,,d,d +#> +d,d,d,d,d +,,u,,d +,j,d,j +d,,u +d,,d,d,d +#> +d,d,,,d +d,,j,,d +d,u,d,u,d +d,,j +d,,,d,d +#> +d,d,d,d,d +,,u,,d +,j,d,j +d,,u +d,,d,d,d +#> +d,d,,,d +d,,j,,d +d,u,d,u,d +d,,j +d,,,d,d +#> +d,d,d,d,d +,,u,,d +,j,d,j +d,,u +d,,d,d,d diff --git a/data/blueprints/test/ecosystem/golden/tracks-2-carve.csv b/data/blueprints/test/ecosystem/golden/tracks-2-carve.csv new file mode 100644 index 0000000000..c5b4309612 --- /dev/null +++ b/data/blueprints/test/ecosystem/golden/tracks-2-carve.csv @@ -0,0 +1,6 @@ +#dig label(carve) +trackSE,trackEW,trackEW,trackEW,trackSW +trackNE,,,,trackNW +#> + +,trackrampEW,trackEW,trackrampEW diff --git a/data/blueprints/test/ecosystem/golden/transform-1-dig.csv b/data/blueprints/test/ecosystem/golden/transform-1-dig.csv new file mode 100644 index 0000000000..b26339d8a4 --- /dev/null +++ b/data/blueprints/test/ecosystem/golden/transform-1-dig.csv @@ -0,0 +1,28 @@ +#dig label(dig) start(14;14) +,d,d,,d,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d,d,,d,d +d,,d,,d,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d,d,,d,,d +d,d,,,d,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d,d,,,d,d +,,,,,,,,d,d,d,d,d,,d,d,d,d,d +d,d,d,,,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d,,,d,d,d +d,d,d,,d,,d,,d,d,d,d,d,,d,d,d,d,d,,d,,d,,d,d,d +d,d,d,,d,d,,,d,d,d,d,d,,d,d,d,d,d,,,d,d,,d,d,d +,,,,,,,,d,d,d,d,d,,d,d,d,d,d +d,d,d,d,d,d,d,d,,,,,,,,,,,,d,d,d,d,d,d,d,d +d,d,d,d,d,d,d,d,,,d,d,d,,d,d,d,,,d,d,d,d,d,d,d,d +d,d,d,d,d,d,d,d,,d,,d,d,,d,d,,d,,d,d,d,d,d,d,d,d +d,d,d,d,d,d,d,d,,d,d,,d,,d,,d,d,,d,d,d,d,d,d,d,d +d,d,d,d,d,d,d,d,,d,d,d,,,,d,d,d,,d,d,d,d,d,d,d,d + +d,d,d,d,d,d,d,d,,d,d,d,,,,d,d,d,,d,d,d,d,d,d,d,d +d,d,d,d,d,d,d,d,,d,d,,d,,d,,d,d,,d,d,d,d,d,d,d,d +d,d,d,d,d,d,d,d,,d,,d,d,,d,d,,d,,d,d,d,d,d,d,d,d +d,d,d,d,d,d,d,d,,,d,d,d,,d,d,d,,,d,d,d,d,d,d,d,d +d,d,d,d,d,d,d,d,,,,,,,,,,,,d,d,d,d,d,d,d,d +,,,,,,,,d,d,d,d,d,,d,d,d,d,d +d,d,d,,d,d,,,d,d,d,d,d,,d,d,d,d,d,,,d,d,,d,d,d +d,d,d,,d,,d,,d,d,d,d,d,,d,d,d,d,d,,d,,d,,d,d,d +d,d,d,,,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d,,,d,d,d +,,,,,,,,d,d,d,d,d,,d,d,d,d,d +d,d,,,d,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d,d,,,d,d +d,,d,,d,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d,d,,d,,d +,d,d,,d,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d,d,,d,d diff --git a/data/blueprints/test/ecosystem/golden/transform-2-construct.csv b/data/blueprints/test/ecosystem/golden/transform-2-construct.csv new file mode 100644 index 0000000000..9620c96c12 --- /dev/null +++ b/data/blueprints/test/ecosystem/golden/transform-2-construct.csv @@ -0,0 +1,28 @@ +#build label(construct) start(14;14) +,trackNS,trackE,,trackW,trackS,trackN,,,,,,,,,,,,,,trackN,trackS,trackE,,trackW,trackNS +trackEW,,trackSE,,trackSW,trackNE,trackNW,,,,,,,,,,,,,,trackNE,trackNW,trackSE,,trackSW,,trackEW +trackS,trackSE,,,trackNSE,trackNSW,trackEW,,,,,,,,,,,,,,trackEW,trackNSE,trackNSW,,,trackSW,trackS + +trackN,trackNE,trackSEW,,,trackSEW,trackNEW,,,,,,,,,,,,,,trackNEW,trackSEW,,,trackSEW,trackNW,trackN +trackE,trackSW,trackNEW,,trackNSE,,trackNSEW,,,,,,,,,,,,,,trackNSEW,,trackNSW,,trackNEW,trackSE,trackW +trackW,trackNW,trackNS,,trackNSW,trackNSEW,,,,,,,,,,,,,,,,trackNSEW,trackNSE,,trackNS,trackNE,trackE + + +,,,,,,,,,,trackrampNW,trackrampNS,trackrampN,,trackrampN,trackrampNS,trackrampNE +,,,,,,,,,trackrampNW,,trackrampNSE,trackrampNSW,,trackrampNSE,trackrampNSW,,trackrampNE +,,,,,,,,,trackrampEW,trackrampSEW,,trackrampNSEW,,trackrampNSEW,,trackrampSEW,trackrampEW +,,,,,,,,,trackrampW,trackrampNEW,trackrampNSEW,,,,trackrampNSEW,trackrampNEW,trackrampE + +,,,,,,,,,trackrampW,trackrampSEW,trackrampNSEW,,,,trackrampNSEW,trackrampSEW,trackrampE +,,,,,,,,,trackrampEW,trackrampNEW,,trackrampNSEW,,trackrampNSEW,,trackrampNEW,trackrampEW +,,,,,,,,,trackrampSW,,trackrampNSE,trackrampNSW,,trackrampNSE,trackrampNSW,,trackrampSE +,,,,,,,,,,trackrampSW,trackrampNS,trackrampS,,trackrampS,trackrampNS,trackrampSE + + +trackW,trackSW,trackNS,,trackNSW,trackNSEW,,,,,,,,,,,,,,,,trackNSEW,trackNSE,,trackNS,trackSE,trackE +trackE,trackNW,trackSEW,,trackNSE,,trackNSEW,,,,,,,,,,,,,,trackNSEW,,trackNSW,,trackSEW,trackNE,trackW +trackS,trackSE,trackNEW,,,trackNEW,trackSEW,,,,,,,,,,,,,,trackSEW,trackNEW,,,trackNEW,trackSW,trackS + +trackN,trackNE,,,trackNSE,trackNSW,trackEW,,,,,,,,,,,,,,trackEW,trackNSE,trackNSW,,,trackNW,trackN +trackEW,,trackNE,,trackNW,trackSE,trackSW,,,,,,,,,,,,,,trackSE,trackSW,trackNE,,trackNW,,trackEW +,trackNS,trackE,,trackW,trackN,trackS,,,,,,,,,,,,,,trackS,trackN,trackE,,trackW,trackNS diff --git a/data/blueprints/test/ecosystem/golden/transform-3-build.csv b/data/blueprints/test/ecosystem/golden/transform-3-build.csv new file mode 100644 index 0000000000..74434544ab --- /dev/null +++ b/data/blueprints/test/ecosystem/golden/transform-3-build.csv @@ -0,0 +1,28 @@ +#build label(build) start(14;14) +,~,~,,~,~,~,,gs(1x2),ga(2x1),,gx(1x2),gw(1x2),,gw(1x2),gx(1x2),gd(2x1),,gs(1x2),,~,~,~,,~,~ +~,,~,,~,~,~,,,gd(2x1),,,,,,,ga(2x1),,,,~,~,~,,~,,~ +~,~,,,~,~,~,,Mrsssqq(2x1),,,Msh,,,,,Msk,Mrsqq(2x1),,,~,~,~,,,~,~ +,,,,,,,,CSdddaaaa,,Msk,,Mw,,Mw,,,Msh,CSddddaaaa +~,~,~,,,~,~,,CSa,,Mrss(1x2),Mw,,,,Mw,Mrss(1x2),,CSa,,~,~,,,~,~,~ +~,~,~,,~,,~,,,Msm,,,Mhs(1x2),,Mhs(1x2),,,Msm,,,~,,~,,~,~,~ +~,~,~,,~,~,,,Msu,,Mws,,,,,,Mws,,Msu,,,~,~,,~,~,~ +,,,,,,,,,Mws,,Mh(2x1),,,Mh(2x1),,,Mws +gs(2x1),,Mrqq(1x2),CSddaaaa,CSa,,Msh,,,,,,,,,,,,,,,Msk,CSa,CSddaaaa,Mrqq(1x2),gs(2x1) +gw(1x2),gx(1x2),,,,Msk,,Mw,,,~,~,~,,~,~,~,,,Mw,,,Msh,,,gx(1x2),gw(1x2) +,,,Msm,Mrs(2x1),,Mw,,,~,,~,~,,~,~,,~,,,Mw,Mrsss(2x1),,Msm +gd(2x1),,Msu,,Mws,,,Mhs(1x2),,~,~,,~,,~,,~,~,,Mhs(1x2),,,Mws,,Msu,ga(2x1) +ga(2x1),,,Mws,,Mh(2x1),,,,~,~,~,,,,~,~,~,,,Mh(2x1),,,Mws,,gd(2x1) + +ga(2x1),,,Mws,,Mh(2x1),,Mhs(1x2),,~,~,~,,,,~,~,~,,Mhs(1x2),Mh(2x1),,,Mws,,gd(2x1) +gd(2x1),,,,Mws,,,,,~,~,,~,,~,,~,~,,,,,Mws,,,ga(2x1) +gx(1x2),gw(1x2),Msm,,Mrs(2x1),,Mw,,,~,,~,~,,~,~,,~,,,Mw,Mrsss(2x1),,,Msm,gw(1x2),gx(1x2) +,,Mrssqq(1x2),Msu,,Msk,,Mw,,,~,~,~,,~,~,~,,,Mw,,,Msh,Msu,Mrssqq(1x2) +gs(2x1),,,CSdaaaa,CSa,,Msh,,,,,,,,,,,,,,,Msk,CSa,CSdaaaa,,gs(2x1) +,,,,,,,,,Mws,,Mh(2x1),,,Mh(2x1),,,Mws +~,~,~,,~,~,,,,,Mws,,Mhs(1x2),,Mhs(1x2),,Mws,,,,,~,~,,~,~,~ +~,~,~,,~,,~,,Msm,,Mr(1x2),,,,,,Mr(1x2),,Msm,,~,,~,,~,~,~ +~,~,~,,,~,~,,CSa,Msu,,Mw,,,,Mw,,Msu,CSa,,~,~,,,~,~,~ +,,,,,,,,CSdddaaaa,,Msk,,Mw,,Mw,,,Msh,CSddddaaaa +~,~,,,~,~,~,,Mrsssqq(2x1),,,Msh,,,,,Msk,Mrsqq(2x1),,,~,~,~,,,~,~ +~,,~,,~,~,~,,gs(1x2),gd(2x1),,gw(1x2),gx(1x2),,gx(1x2),gw(1x2),ga(2x1),,gs(1x2),,~,~,~,,~,,~ +,~,~,,~,~,~,,,ga(2x1),,,,,,,gd(2x1),,,,~,~,~,,~,~ diff --git a/data/blueprints/test/ecosystem/in/basic-1-dig.csv b/data/blueprints/test/ecosystem/in/basic-1-dig.csv new file mode 100644 index 0000000000..a2019b675a --- /dev/null +++ b/data/blueprints/test/ecosystem/in/basic-1-dig.csv @@ -0,0 +1,6 @@ +#dig label(dig) +,,d +,d,d,d +d,d,d,d,d +,d,d,d +,,d diff --git a/data/blueprints/test/ecosystem/in/basic-2-carve.csv b/data/blueprints/test/ecosystem/in/basic-2-carve.csv new file mode 100644 index 0000000000..250ea23812 --- /dev/null +++ b/data/blueprints/test/ecosystem/in/basic-2-carve.csv @@ -0,0 +1,6 @@ +#dig label(carve) +,,trackS +,,trackNS +trackE,trackEW,trackNSEW,trackEW,trackW +,,trackNS +,,trackN diff --git a/data/blueprints/test/ecosystem/in/basic-3-build.csv b/data/blueprints/test/ecosystem/in/basic-3-build.csv new file mode 100644 index 0000000000..c69caf7133 --- /dev/null +++ b/data/blueprints/test/ecosystem/in/basic-3-build.csv @@ -0,0 +1,5 @@ +#build label(build) + + + +,h,,f diff --git a/data/blueprints/test/ecosystem/in/basic-4-place.csv b/data/blueprints/test/ecosystem/in/basic-4-place.csv new file mode 100644 index 0000000000..754fd30228 --- /dev/null +++ b/data/blueprints/test/ecosystem/in/basic-4-place.csv @@ -0,0 +1,3 @@ +#place label(place) + +,f,,g diff --git a/data/blueprints/test/ecosystem/in/basic-5-zone.csv b/data/blueprints/test/ecosystem/in/basic-5-zone.csv new file mode 100644 index 0000000000..83042e20ec --- /dev/null +++ b/data/blueprints/test/ecosystem/in/basic-5-zone.csv @@ -0,0 +1,4 @@ +#zone label(zone) +,,m +,m,m,m +,pPf(2x2) diff --git a/data/blueprints/test/ecosystem/in/basic-spec.csv b/data/blueprints/test/ecosystem/in/basic-spec.csv new file mode 100644 index 0000000000..828b2ca964 --- /dev/null +++ b/data/blueprints/test/ecosystem/in/basic-spec.csv @@ -0,0 +1,4 @@ +#notes +description=basic test for all phases +width=5 +height=5 diff --git a/data/blueprints/test/ecosystem/in/buildings-1-dig.csv b/data/blueprints/test/ecosystem/in/buildings-1-dig.csv new file mode 100644 index 0000000000..0731112b65 --- /dev/null +++ b/data/blueprints/test/ecosystem/in/buildings-1-dig.csv @@ -0,0 +1,43 @@ +#dig label(dig) +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +h,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +#> + + + + + + + +r diff --git a/data/blueprints/test/ecosystem/in/buildings-2-construct.csv b/data/blueprints/test/ecosystem/in/buildings-2-construct.csv new file mode 100644 index 0000000000..e7e1d12bbc --- /dev/null +++ b/data/blueprints/test/ecosystem/in/buildings-2-construct.csv @@ -0,0 +1,21 @@ +#build label(construct) + + + + + + + + + + + + + +Cw +Cf +Cr +Cu +Cd +Cx +CF diff --git a/data/blueprints/test/ecosystem/in/buildings-3-build.csv b/data/blueprints/test/ecosystem/in/buildings-3-build.csv new file mode 100644 index 0000000000..f48457c0a5 --- /dev/null +++ b/data/blueprints/test/ecosystem/in/buildings-3-build.csv @@ -0,0 +1,33 @@ +#build label(build) +a,Mg,,CS +b,Mh(1x1),S,CSa,,,,,,Mw,,,wm,,,wp +c,Mhs(1x1),m,CSaa,,,,,,,,,,,,,,,,,D +n,Mv,v,CSaaa,,Msu +,Mr(1x1),j,CSaaaa,,,,,,Mws,,,wu,,,ew +d,Mrq(1x1),A,CSd,,,Msk +,Mrqq(1x1),R,CSda +l,Mrqqq(1x1),N,CSdaa,,Msm,,,,we,,,wn,,,es,,,,,k +x,Mrqqqq(1x1),~h,CSdaaa +H,Mrs(1x1),~a,CSdaaaa,,,Msh +W,Mrsq(1x1),~c,CSdd,,,,,,wq,,,wr,,,el +G,Mrsqq(1x1),F,CSdda +B,Mrsqqq(1x1),o(1x1),CSddaa,,,,,,,,,,,,,,,,,ws +~,~b,Mrsqqqq(1x1),CSddaaa,,,,,,wM,,,wt,,,eg +~,f,Mrss(1x1),CSddaaaa +~,h,Mrssq(1x1),CSddd +~,r,Mrssqq(1x1),CSddda,,,,,,wo,,,wl,,,ea,,,,gx(1x2),gx(1x2) +~,s,Mrssqqq(1x1),CSdddaa +~,~s,Mrssqqqq(1x1),CSdddaaa,,,,,,,,,,,,,,gd(2x1),,gs(2x1),,ga(2x1) +~,t,Mrsss(1x1),CSdddaaaa,,,,,,wk,,,ww,,,ek,,gd(2x1),,gs(2x1),,ga(2x1) +gs(1x1),Mrsssq(1x1),,CSdddd,,,,,,,,,,,,,,,,gw(1x2),gw(1x2) +ga(1x1),Mrsssqq(1x1),,CSdddda +gd(1x1),Mrsssqqq(1x1),,CSddddaa,,,,,,wb,,,wz,,,en +gw(1x1),Mrsssqqqq(1x1),,CSddddaaa,,,,,,,,,,,,,,Mh(2x1),,Mh(2x1),,Mhs(1x2),Mhs(1x2) +gx(1x1),,,CSddddaaaa,,,,,,,,,,,,,,Mh(2x1),,Mh(2x1) +,,,Ts,,,,,,wc,,,wh,,,ib,,Mr(1x2),Mr(1x2),Mrs(2x1),,Mhs(1x2),Mhs(1x2) +y,,,Tw,,,,,,,,,,,,,,,,Mrs(2x1) +Y,,,Tl,,,,,,,,,,,,,,Mr(1x2),Mr(1x2),Mrsq(2x1),,Mrsq(2x1) +,,,Tp,,,,,,wf,,,wy,,,ic,,,,Mrsssqqqq(2x1),,Mrsssqqqq(2x1) +,,,Tc +,,,TS +,,,,,,,,,,wv,,,wd,,,wj,,,wS diff --git a/data/blueprints/test/ecosystem/in/buildings-spec.csv b/data/blueprints/test/ecosystem/in/buildings-spec.csv new file mode 100644 index 0000000000..dd74099f3c --- /dev/null +++ b/data/blueprints/test/ecosystem/in/buildings-spec.csv @@ -0,0 +1,8 @@ +#notes +description=underground buildings coverage test +width=24 +height=37 +depth=2 +#ignore +does not include (p) farm plots or (oO) dirt/paved roads, since they are built +on dirt and the ecosystem harness only chooses rock areas. diff --git a/data/blueprints/test/ecosystem/in/fortifications-1-dig.csv b/data/blueprints/test/ecosystem/in/fortifications-1-dig.csv new file mode 100644 index 0000000000..dc40f07b26 --- /dev/null +++ b/data/blueprints/test/ecosystem/in/fortifications-1-dig.csv @@ -0,0 +1,3 @@ +#dig label(dig) + +,d diff --git a/data/blueprints/test/ecosystem/in/fortifications-2-smooth.csv b/data/blueprints/test/ecosystem/in/fortifications-2-smooth.csv new file mode 100644 index 0000000000..bf91a23287 --- /dev/null +++ b/data/blueprints/test/ecosystem/in/fortifications-2-smooth.csv @@ -0,0 +1,4 @@ +#dig label(smooth) +,s +s,,s +,s diff --git a/data/blueprints/test/ecosystem/in/fortifications-3-carve.csv b/data/blueprints/test/ecosystem/in/fortifications-3-carve.csv new file mode 100644 index 0000000000..c174cc918a --- /dev/null +++ b/data/blueprints/test/ecosystem/in/fortifications-3-carve.csv @@ -0,0 +1,4 @@ +#dig label(carve) +,F +F,,F +,F diff --git a/data/blueprints/test/ecosystem/in/fortifications-spec.csv b/data/blueprints/test/ecosystem/in/fortifications-spec.csv new file mode 100644 index 0000000000..462a2e6dbe --- /dev/null +++ b/data/blueprints/test/ecosystem/in/fortifications-spec.csv @@ -0,0 +1,4 @@ +#notes +description=test carving fortifications +width=3 +height=3 diff --git a/data/blueprints/test/ecosystem/in/meta-1-dig.csv b/data/blueprints/test/ecosystem/in/meta-1-dig.csv new file mode 100644 index 0000000000..7467bca2d5 --- /dev/null +++ b/data/blueprints/test/ecosystem/in/meta-1-dig.csv @@ -0,0 +1,41 @@ +#ignore +tests recursive meta composition, z-level manipulation, transformations, and +repeat up/down + +#dig label(border) start(3 3) hidden() +d(2x1),,,,d(1x3) + + + +d(1x-4),,,,d(-2x1) +#dig label(center_tile) start(3 3) hidden() + + +,,d +#dig label(even_up) start(3 3) hidden() + + +,u,,u +#dig label(even_down) start(3 3) hidden() + +,,j + +,,j +#meta label(even) hidden() +/border +/even_up +/even_down +#meta label(odd) hidden() +/even transform(rotcw) +#meta label(twoz) hidden() +/even +#> +/odd +#meta label(fourz) hidden() +/twoz +#>2 +/twoz +#> +/center_tile repeat(up 4) +#meta label(dig) +/fourz repeat(>3) diff --git a/data/blueprints/test/ecosystem/in/meta-spec.csv b/data/blueprints/test/ecosystem/in/meta-spec.csv new file mode 100644 index 0000000000..5b32a29384 --- /dev/null +++ b/data/blueprints/test/ecosystem/in/meta-spec.csv @@ -0,0 +1,6 @@ +#notes +description=meta coverage test +width=5 +height=5 +depth=12 +"start=3,3" diff --git a/data/blueprints/test/ecosystem/in/stockpiles-2-place.csv b/data/blueprints/test/ecosystem/in/stockpiles-2-place.csv new file mode 100644 index 0000000000..f5ac0ce511 --- /dev/null +++ b/data/blueprints/test/ecosystem/in/stockpiles-2-place.csv @@ -0,0 +1,12 @@ +#place label(place) +a(2x2),,f(2x2),,u(2x2),,n(2x2),,y(2x2),,r(2x2) + +s(2x2),,w(2x2),,e(2x2),,b(2x2),,h(2x2),,l(2x2) + +z(2x2),,S(2x2),,g(2x2),,p(2x2),,d(2x2),,afunyrswebhlzSgpd(2x2) + +a,a,g,g,a,,,g,l,w,s,a +a,,,g,a,a,g,g,w,w,s,a +u,u,u,,,,,,s,s,s,a +u,z,u,,,c,,,a,a,a,a +u,u,u diff --git a/data/blueprints/test/ecosystem/in/stockpiles-spec.csv b/data/blueprints/test/ecosystem/in/stockpiles-spec.csv new file mode 100644 index 0000000000..f0fb680be9 --- /dev/null +++ b/data/blueprints/test/ecosystem/in/stockpiles-spec.csv @@ -0,0 +1,4 @@ +#notes +description=stockpile coverage test +width=12 +height=11 diff --git a/data/blueprints/test/ecosystem/in/tracks-1-dig.csv b/data/blueprints/test/ecosystem/in/tracks-1-dig.csv new file mode 100644 index 0000000000..734ecd0b7c --- /dev/null +++ b/data/blueprints/test/ecosystem/in/tracks-1-dig.csv @@ -0,0 +1,6 @@ +#dig label(dig) +d,d,d,d,d +d,h,,h,d +#> + +,r,d,r diff --git a/data/blueprints/test/ecosystem/in/tracks-2-carve.csv b/data/blueprints/test/ecosystem/in/tracks-2-carve.csv new file mode 100644 index 0000000000..0646e5934d --- /dev/null +++ b/data/blueprints/test/ecosystem/in/tracks-2-carve.csv @@ -0,0 +1,6 @@ +#dig label(carve) +T(5x2) +,,,,T(-5x-2) +#> + +T(5x1) diff --git a/data/blueprints/test/ecosystem/in/tracks-3-build.csv b/data/blueprints/test/ecosystem/in/tracks-3-build.csv new file mode 100644 index 0000000000..c750936b44 --- /dev/null +++ b/data/blueprints/test/ecosystem/in/tracks-3-build.csv @@ -0,0 +1,4 @@ +#build label(build) +#> + +,,CS diff --git a/data/blueprints/test/ecosystem/in/tracks-spec.csv b/data/blueprints/test/ecosystem/in/tracks-spec.csv new file mode 100644 index 0000000000..c0dc9526ad --- /dev/null +++ b/data/blueprints/test/ecosystem/in/tracks-spec.csv @@ -0,0 +1,5 @@ +#notes +description=track coverage test +width=5 +height=2 +depth=2 diff --git a/data/blueprints/test/ecosystem/in/transform-1-dig.csv b/data/blueprints/test/ecosystem/in/transform-1-dig.csv new file mode 100644 index 0000000000..92d386e551 --- /dev/null +++ b/data/blueprints/test/ecosystem/in/transform-1-dig.csv @@ -0,0 +1,26 @@ +#dig label(big) hidden() +d(5x8) +#dig label(outer) hidden() +d,d,d,,d,d +d,d,d,,d +d,d,d + +d,d +d +#dig label(inner) hidden() +d,d,d +d,d +d +#meta label(chunk) hidden() +/big shift(1 -13) +/outer shift(7 -13) +/inner shift(1 -4) +#meta label(dig) +/chunk +/chunk transform(cw) +/chunk transform(cw cw) +/chunk transform(ccw) +/chunk transform(fliph) +/chunk transform(flipv) +/chunk transform(cw flipv) +/chunk transform(ccw flipv) diff --git a/data/blueprints/test/ecosystem/in/transform-2-construct.csv b/data/blueprints/test/ecosystem/in/transform-2-construct.csv new file mode 100644 index 0000000000..95717afa85 --- /dev/null +++ b/data/blueprints/test/ecosystem/in/transform-2-construct.csv @@ -0,0 +1,23 @@ +#build label(outer) hidden() +trackN,trackS,trackE,,trackW,trackNS +trackNE,trackNW,trackSE,,trackSW +trackEW,trackNSE,trackNSW + +trackNEW,trackSEW +trackNSEW +#build label(inner) hidden() +trackrampN,trackrampNS,trackrampNE +trackrampNSE,trackrampNSW +trackrampNSEW +#meta label(chunk) hidden() +/outer shift(7 -13) +/inner shift(1 -4) +#meta label(construct) +/chunk +/chunk transform(cw) +/chunk transform(cw cw) +/chunk transform(ccw) +/chunk transform(fliph) +/chunk transform(flipv) +/chunk transform(cw flipv) +/chunk transform(ccw flipv) diff --git a/data/blueprints/test/ecosystem/in/transform-3-build.csv b/data/blueprints/test/ecosystem/in/transform-3-build.csv new file mode 100644 index 0000000000..7907220e7c --- /dev/null +++ b/data/blueprints/test/ecosystem/in/transform-3-build.csv @@ -0,0 +1,20 @@ +#build label(big) hidden() +gw(1x2),gx(1x2),gd(2x1),,gs(1x2) +,,ga(2x1) +,,Msk,Mrsqq(2x1) +Mw,,,Msh,CSddddaaaa +,Mw,Mrss(1x2),,CSa +Mhs(1x2),,,Msm +,,Mws,,Msu +Mh(2x1),,,Mws +#meta label(chunk) hidden() +/big shift(1 -13) +#meta label(build) +/chunk +/chunk transform(cw) +/chunk transform(cw cw) +/chunk transform(ccw) +/chunk transform(fliph) +/chunk transform(flipv) +/chunk transform(cw flipv) +/chunk transform(ccw flipv) diff --git a/data/blueprints/test/ecosystem/in/transform-spec.csv b/data/blueprints/test/ecosystem/in/transform-spec.csv new file mode 100644 index 0000000000..2a3bba25fe --- /dev/null +++ b/data/blueprints/test/ecosystem/in/transform-spec.csv @@ -0,0 +1,5 @@ +#notes +description=transformation coverage test +width=27 +height=27 +"start=14,14" diff --git a/data/blueprints/test/ecosystem/in/zones-2-zone.csv b/data/blueprints/test/ecosystem/in/zones-2-zone.csv new file mode 100644 index 0000000000..b67a1dd5bf --- /dev/null +++ b/data/blueprints/test/ecosystem/in/zones-2-zone.csv @@ -0,0 +1,8 @@ +#zone label(zone) +w(1x1),f(1x1),g(1x1),d(1x1),n(1x1) +p(1x1),s(1x1),c(1x1),m(1x1),h(1x1) +t(1x1),a(1x1) +n(1x1),n(1x1) +wfgGt^dpPf^scmhH{hospital thread=90000 cloth=60000 splints=6 crutches=6 plaster=15000 buckets=3 soap=900}^t(2x2) + +hH{hospital splints=6}(1x1) diff --git a/data/blueprints/test/ecosystem/in/zones-spec.csv b/data/blueprints/test/ecosystem/in/zones-spec.csv new file mode 100644 index 0000000000..37d6dfedcd --- /dev/null +++ b/data/blueprints/test/ecosystem/in/zones-spec.csv @@ -0,0 +1,4 @@ +#notes +description=zone coverage test +width=5 +height=7 diff --git a/data/blueprints/test/quickfort/list/all_modes.csv b/data/blueprints/test/quickfort/list/all_modes.csv new file mode 100644 index 0000000000..c8a042846a --- /dev/null +++ b/data/blueprints/test/quickfort/list/all_modes.csv @@ -0,0 +1,10 @@ +#dig hidden() +#build hidden() +#place hidden() +#zone hidden() +#query hidden() +#config hidden() +#ignore +#aliases +#meta hidden() +#notes hidden() diff --git a/data/blueprints/test/quickfort/list/all_modes_separate_sheets.xlsx b/data/blueprints/test/quickfort/list/all_modes_separate_sheets.xlsx new file mode 100644 index 0000000000..47445283f0 Binary files /dev/null and b/data/blueprints/test/quickfort/list/all_modes_separate_sheets.xlsx differ diff --git a/data/blueprints/test/quickfort/list/all_modes_single_sheet.xlsx b/data/blueprints/test/quickfort/list/all_modes_single_sheet.xlsx new file mode 100644 index 0000000000..51331918c1 Binary files /dev/null and b/data/blueprints/test/quickfort/list/all_modes_single_sheet.xlsx differ diff --git a/data/blueprints/tombs/Mini_Saracen.csv b/data/blueprints/tombs/Mini_Saracen.csv new file mode 100644 index 0000000000..f30fbc55da --- /dev/null +++ b/data/blueprints/tombs/Mini_Saracen.csv @@ -0,0 +1,26 @@ +#dig start(6;6) room for 24 corpses +d, ,d, ,d, ,d, ,d, ,d,# +d,d,d,d,d,d,d,d,d,d,d,# +d, ,d, ,d,d,d, ,d, ,d,# + , , , ,d,d,d, , , , ,# +d, ,d,d,i,i,i,d,d, ,d,# +d,d,d,d,i,i,i,d,d,d,d,# +d, ,d,d,i,i,i,d,d, ,d,# + , , , ,d,d,d, , , , ,# +d, ,d, ,d,d,d, ,d, ,d,# +d,d,d,d,d,d,d,d,d,d,d,# +d, ,d, ,d, ,d, ,d, ,d,# +#,#,#,#,#,#,#,#,#,#,#,# +#build label(urns) start(6;6) message(use burial script to mark urns as usable) 24 urns +n, ,n, ,n, ,n, ,n, ,n,# +`,`,`,`,`,`,`,`,`,`,`,# +n, ,n, ,`,`,`, ,n, ,n,# + , , , ,`,`,`, , , , ,# +n, ,`,`,~,~,~,`,`, ,n,# +`,`,`,`,~,~,~,`,`,`,`,# +n, ,`,`,~,~,~,`,`, ,n,# + , , , ,`,`,`, , , , ,# +n, ,n, ,`,`,`, ,n, ,n,# +`,`,`,`,`,`,`,`,`,`,`,# +n, ,n, ,n, ,n, ,n, ,n,# +#,#,#,#,#,#,#,#,#,#,#,# diff --git a/data/blueprints/tombs/The_Saracen_Crypts.csv b/data/blueprints/tombs/The_Saracen_Crypts.csv new file mode 100644 index 0000000000..a70b77a09a --- /dev/null +++ b/data/blueprints/tombs/The_Saracen_Crypts.csv @@ -0,0 +1,99 @@ +#dig start(24;25) room for 513 corpses +# see an image of this blueprint at https://i.imgur.com/Kcjvx6R.png +d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d,d,d,d,d,d,d,d,d,d,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d,# +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d, , , , , , , , , ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,# +d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d,# + , , , , , , , , , , , , , , , , , ,d,d,d,d,d,d,d,d,d,d,d, , , , , , , , , , , , , , , , , , ,# +d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d,# +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d, , , , , , , , , ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,# +d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d,# + , , , , , , , , , , , , , , , , , ,d,d,d,d,d,d,d,d,d,d,d, , , , , , , , , , , , , , , , , , ,# +d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d,# +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d, , , , , , , , , ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,# +d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d,# + , , , , , , , , , , , , , , , , , ,d,d,d,d,d,d,d,d,d,d,d, , , , , , , , , , , , , , , , , , ,# +d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d,# +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d, , , , , , , , , ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,# +d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d,# + , , , , , , , , , , , , , , , , , ,d,d,d,d,d,d,d,d,d,d,d, , , , , , , , , , , , , , , , , , ,# +d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d,# +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d, , , , , , , , , ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,# +d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d,# + , , , , , , , , , , , , , , , , , ,d,d,d,d,d,d,d,d,d,d,d, , , , , , , , , , , , , , , , , , ,# +d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d,d,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d,# +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d, , , ,d,d,d, , , ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,# +d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d,d,d,d,i,i,i,d,d,d,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d,# + , , , , , , , , , , , , , , , , , ,d,d,d,d,i,i,i,d,d,d,d, , , , , , , , , , , , , , , , , , ,# +d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d,d,d,d,i,i,i,d,d,d,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d,# +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d, , , ,d,d,d, , , ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,# +d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d,d,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d,# + , , , , , , , , , , , , , , , , , ,d,d,d,d,d,d,d,d,d,d,d, , , , , , , , , , , , , , , , , , ,# +d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d,# +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d, , , , , , , , , ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,# +d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d,# + , , , , , , , , , , , , , , , , , ,d,d,d,d,d,d,d,d,d,d,d, , , , , , , , , , , , , , , , , , ,# +d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d,# +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d, , , , , , , , , ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,# +d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d,# + , , , , , , , , , , , , , , , , , ,d,d,d,d,d,d,d,d,d,d,d, , , , , , , , , , , , , , , , , , ,# +d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d,# +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d, , , , , , , , , ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,# +d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d,# + , , , , , , , , , , , , , , , , , ,d,d,d,d,d,d,d,d,d,d,d, , , , , , , , , , , , , , , , , , ,# +d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d,# +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d, , , , , , , , , ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,# +d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d,# + , , , , , , , , , , , , , , , , , ,d,d,d,d,d,d,d,d,d,d,d, , , , , , , , , , , , , , , , , , ,# +d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d,# +d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d, , , , , , , , , ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,# +d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d,d,d,d,d,d,d,d,d,d,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d, ,d,# +#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# +#build label(urns) start(24;24) message(use burial script to mark urns as usable) 513 urns +n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,`,`,`,`,`,`,`,`,`,`,`, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n,# +`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`, , , , , , , , , ,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,# +n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,`, ,n, ,n, ,n, ,n, ,`, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n,# + , , , , , , , , , , , , , , , , , ,`,`,`,`,`,`,`,`,`,`,`, , , , , , , , , , , , , , , , , , ,# +n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,`, ,n, ,n, ,n, ,n, ,`, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n,# +`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`, , , , , , , , , ,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,# +n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,`, ,n, ,n, ,n, ,n, ,`, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n,# + , , , , , , , , , , , , , , , , , ,`,`,`,`,`,`,`,`,`,`,`, , , , , , , , , , , , , , , , , , ,# +n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,`, ,n, ,n, ,n, ,n, ,`, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n,# +`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`, , , , , , , , , ,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,# +n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,`, ,n, ,n, ,n, ,n, ,`, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n,# + , , , , , , , , , , , , , , , , , ,`,`,`,`,`,`,`,`,`,`,`, , , , , , , , , , , , , , , , , , ,# +n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,`, ,n, ,n, ,n, ,n, ,`, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n,# +`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`, , , , , , , , , ,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,# +n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,`, ,n, ,n, ,n, ,n, ,`, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n,# + , , , , , , , , , , , , , , , , , ,`,`,`,`,`,`,`,`,`,`,`, , , , , , , , , , , , , , , , , , ,# +n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,`, ,n, ,n, ,n, ,n, ,`, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n,# +`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`, , , , , , , , , ,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,# +n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,`, ,n, ,n, ,n, ,n, ,`, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n,# + , , , , , , , , , , , , , , , , , ,`,`,`,`,`,`,`,`,`,`,`, , , , , , , , , , , , , , , , , , ,# +n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,`, ,n, ,n,`,n, ,n, ,`, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n,# +`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`, , , ,`,`,`, , , ,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,# +n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,`,`,`,`,~,~,~,`,`,`,`, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n,# + , , , , , , , , , , , , , , , , , ,`,`,`,`,~,~,~,`,`,`,`, , , , , , , , , , , , , , , , , , ,# +n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,`,`,`,`,~,~,~,`,`,`,`, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n,# +`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`, , , ,`,`,`, , , ,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,# +n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,`, ,n, ,n,`,n, ,n, ,`, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n,# + , , , , , , , , , , , , , , , , , ,`,`,`,`,`,`,`,`,`,`,`, , , , , , , , , , , , , , , , , , ,# +n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,`, ,n, ,n, ,n, ,n, ,`, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n,# +`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`, , , , , , , , , ,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,# +n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,`, ,n, ,n, ,n, ,n, ,`, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n,# + , , , , , , , , , , , , , , , , , ,`,`,`,`,`,`,`,`,`,`,`, , , , , , , , , , , , , , , , , , ,# +n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,`, ,n, ,n, ,n, ,n, ,`, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n,# +`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`, , , , , , , , , ,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,# +n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,`, ,n, ,n, ,n, ,n, ,`, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n,# + , , , , , , , , , , , , , , , , , ,`,`,`,`,`,`,`,`,`,`,`, , , , , , , , , , , , , , , , , , ,# +n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,`, ,n, ,n, ,n, ,n, ,`, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n,# +`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`, , , , , , , , , ,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,# +n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,`, ,n, ,n, ,n, ,n, ,`, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n,# + , , , , , , , , , , , , , , , , , ,`,`,`,`,`,`,`,`,`,`,`, , , , , , , , , , , , , , , , , , ,# +n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,`, ,n, ,n, ,n, ,n, ,`, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n,# +`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`, , , , , , , , , ,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,# +n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,`, ,n, ,n, ,n, ,n, ,`, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n,# + , , , , , , , , , , , , , , , , , ,`,`,`,`,`,`,`,`,`,`,`, , , , , , , , , , , , , , , , , , ,# +n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,`, ,n, ,n, ,n, ,n, ,`, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n,# +`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`, , , , , , , , , ,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,# +n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n,`,`,`,`,`,`,`,`,`,`, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n, ,n,# +#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# diff --git a/data/dfhack-config/autonick.txt b/data/dfhack-config/autonick.txt new file mode 100644 index 0000000000..bdd40beed4 --- /dev/null +++ b/data/dfhack-config/autonick.txt @@ -0,0 +1,1283 @@ +# autonick config file +# every line in this file that is not empty and does +# not start with "#" will be used as a nickname by the +# autonick script. + +# nicknames can be multiple words +Toady One +Threetoe + +#Dwarven single names taken from Classic Fantasy works +Balin +Dwalin +Fili +Kili +Gloin +Oin +Bifur +Bofur +Bombur +Ori +Gimli +Thrain +Thror +Fundin +Frerin +Gror +Ibun +Khim +Fimbrethil +Floi +Nali +Thor +Vili +Regin +Fafnir +Brokkr +Sindri +Nordri +Sudri +Austri +Doriath +Thingol +Eol +Mim +Telchar +Narvi +Gundabad +Muhrak +Skorri +Draupnir +Alaric +Grimr +Eitri +Svidurr +Thorgar +Hrungnir +Galar +Skirni +Hreinn +Dori +Hreimr +Hreinir +Hroaldr +Groin +Vestri +Nori +Durin +Dvalin +Eikinskjaldi +Bafur +Snorri +Fimafeng +Vitr +Dvali +Dain +Nain +Nipingr +Hrodvitnir +Sveinn +Ivaldi +Svein +Sveinbjorn +Havardr +Haki +Hakon +Mouri +Motsognir +Eberk +Thromar +Kragar +Borgar +Throk +Orvald +Berric +Rogar +Urgen +Morgrim +Keldar +Ingvar +Frandar +Grimsi +Hrokur +Orik +Rundar +Bjornar +Throki +Dworin +Thranduil +Faldar +Galdor +Thorkel +Dorrin +Borkan +Gundrik +Throkir +Raldor +Helgrim +Throgar +Borin +Ragnir +Orvar +Skalf +Baldir +Fror +Thorgil +Ulfar +Grimbold +Faldur +Varrin +Dornir +Halgrim +Gundin +Ulfgar +Skalfar +Yngvarr +Kaldur +Thrandar +Keldin +Rundin +Skaldur +Borgin +Haldur +Bjornulf +Orkarn +Ragnor +Baldrick +Thorlin +Graldor +Ulfrik +Fornir +Egil +Grimnor +Roldor +Ulfgard +Borgrim +Faldrik +Rognir +Balfor +Volmar +Thormund +Brynhild + +#Dwarven composite names taken from Classic Fantasy works +Gorin Stonehammer +Brundar Ironfoot +Haldrek Battlebeard +Orin Stonefist +Frida Stormaxe +Torvald Rockjaw +Einar Blackforge +Thorgar Granitebeard +Ragnir Hammerhelm +Hilda Ironbrow +Grimnar Deepdelver +Ulfrik Ironmane +Freya Thunderstone +Ragnar Firebeard +Gunnar Ironpeak +Astrid Ironheart +Bjorn Steelbreaker +Hrolf Thunderhammer +Sigrun Stonebreaker +Eirik Rockbeard +Helga Frostbeard +Skaldur Stormguard +Agnar Stonehand +Ingrid Mountainmace +Hjalmar Blackstone +Solveig Steelhelm +Rurik Stonegrip +Freyja Silveraxe +Thordur Goldbeard +Gudrun Ironfoot +Vali Fireforge +Thora Frostbeard +Vargr Stoneborn +Astrid Ironbrow +Einar Blackstone +Hilda Hammerheart +Leif Ironshaper +Thrain Stormbrow +Sigrid Steelheart +Haldor Boulderbreaker +Ragnhild Strongarm +Brynjar Ironmantle +Sigrun Thunderbeard +Valgard Steelbeard +Gunnhild Stonefist +Ingrid Ironrock +Eirik Frostbane +Helga Deepforge +Skaldur Ironshield +Agnar Stonemace +Solveig Stormgrip +Hjalmar Mountainheart +Gudrun Firebeard +Thora Thunderstrike +Vargr Ironhand +Freyja Stoneguard +Thordur Blackstone +Rurik Hammerbeard +Solveig Ironbreaker +Astrid Goldhand +Einar Stormbrew +Hilda Steelbeard +Thrain Ironmane +Sigrid Fireheart +Haldor Thunderstone +Ragnhild Ironfoot +Brynjar Blackhelm +Sigrun Frostbeard +Valgard Stoneshield +Gunnhild Ironheart +Bjorn Deepdelver +Ingrid Ironpeak +Eirik Thunderhammer +Gormund Stoneforge +Eovar Broadshield +Thrunir Hammerstone +Brunhild Steelbraid +Garrik Frostbeard +Haldrek Ironhand +Astrid Rockrider +Dagmar Stonefury +Borgar Thunderhelm +Ingrid Ironstrike +Rurik Blackmane +Fjorn Stoneborn +Siv Ironbreaker +Gudrik Stormbeard +Ulfgar Emberforge +Eilif Silverstone +Hilda Stormwarden +Ormar Ironjaw +Vali Steelshaper +Eira Frostbeard +Torgar Graniteheart +Brunhild Firebrand +Haldrek Ironmantle +Solveig Rockbreaker +Thrain Thunderaxe +Brynjar Stoneclaw +Asa Ironhide +Grimnar Blackmane +Ragnvald Hammerfall +Gudbrand Ironhand +Astrid Flamebeard +Ormur Steelbender +Hjalmar Rockjaw +Inga Thunderheart +Valgard Ironbeard +Eirik Swiftstrike +Sylvi Stoneguard +Helge Hammerfist +Jorunn Fireforge +Solveig Ironroot +Thora Stormbeard +Baldur Stonemane +Freydis Ironshaper +Gunnvald Deepstone +Bjorn Blackstone +Ingrid Frostmane +Agnar Steelhammer +Thordur Ironbeard +Ylva Goldhand +Greta Firestone +Rurik Rockhelm +Gunnhild Ironsong +Vali Steelgrip +Brynhild Stormblade +Astrid Ironmantle +Einar Stoneshield +Hilda Frostbeard +Ormr Ironheart +Inga Steelbreaker +Ulfrik Thunderaxe +Freyja Stonebeard +Sigrun Frostfury +Sylvi Blackmane +Thorvald Ironhelm +Eirik Stormstone +Haldora Deepdelver +Sigrid Steelshaper +Gunnar Thunderheart +Bjorn Ironbrow +Ingrid Goldmantle +Agnar Stormforge +Solveig Ironclaw +Thora Rockguard +Grimur Emberstone +Ragnhild Hammerstrike +Vali Ironfist +Brynjar Blackbraid +Astrid Flameforge +Einar Stonestorm +Hilda Frostbane +Ormur Ironhelm +Inga Steelshaper +Gudbrand Thunderbeard +Freya Stonefist +Gunnvald Stormmane +Bjorn Ironhelm +Ingrid Frostforge +Agnar Steelgrip +Thordur Ironhand +Ylva Flameheart +Greta Stonemane +Rurik Ironroot +Gunnhild Steelbeard +Vali Thunderstrike +Thorin Oakenshield +Dain Ironfoot +Gamil Zirak + + +# animals +Mouse +Otter +Snake +Owl +Bat +Fox +Mole +Cat +Badger +Squirrel +Kit +Wren +Jay +Crow +Raven +Sparrow +Platypus +House Mouse +Pangolin +Funnel Web +Weasel +Meerkats +Rat +Ant +Gopher +Fennec +Groundhog +Aardvark +Rabbit +Olm +Chipmunk +Bilbie +Vole +Nile Croc +Wombat +Worm +Gerbil +Armodillo +Thrinaxodon +Binky +Bandicoot +Bettongs +Potoroos +Antechinus +Jerboas +Numbat + +# colours +Flash +Red +Gray +Blue +Shadow +Indigo +Jade +Silver +Bistre +Black +Black bean +Noir +Charcoal +Ebony +Eerie +Jet +Licorice +Midnight +Night +Onyx +Space +Raisin +Rich +Russ violet +Smoky +Aero +Alice +Argent Lue +Azure +Azul +Baby blue +Berkeley +Bice +Bleu +Bondi +Brandeis Byzant +Cambridge +Carolina +Celestial +Celtic +Cerulean +Chefchaouen +Chrysler +Cobalt +Columbia +Cornflower +Delft +Denim +Dodger +Duke +Federal +Electrindigo +Eclipse +Illini +Klein +Jordy +Lapis Lazuli +Majorelle +Marian +Maya +Slate +Munsell +Navy +Neon blue +Oxford +Palatinate +Penn +Periwinkle +Phthalo +Picton +Poly +Powder +Prussia +Royal +Ruddy +Honolulu +Savoy +Silver Lake +Space cadet +Steel +Tang +Tufts +Ultramarine +Uranian +Vista +Yale +Zaffre +Auburn +Almond +Beaver +Beige +Bole +Bone +Bronze +Sienna +Umber +Camel +Caput mortuum +Caramel +Chamoisee +Chestnut +Chocolate +Citron +Cocoa +Coffee +Copper +Coyote +Desert +Drab +Dun +Earth +Fallow +Fawn +Field +Fulvous +Goldenrod +Harvest +Khaki +Kobicha +Lion +Liver +Mahogany +Maroon +Ochre +Redwood +Rufous +Russet +Rust +Sand +Satin +Sheen +Seal +Sepia +Sinopia +Tan +Tawny +Van Dyke +Walnut +Wenge +Aqua +Aquamarine +Capri +Caribbean +Celeste +Cyprus +Fluorescent +Jungle +Keppel +Ice +Sea +Myrtle +Pacific +Robin +Skobeloff +Teal +Verdigris +Vivid +Zomp +Platinum +Timberwolf +Rose quartz +Cinereous +Cadet +Cool +Davys +Paynes +Glaucous +Gunmetal +Feldgrau +Asparagus +Avocado +Brunswick +Cal Poly +Castleton +Celadon +Chartreuse +Moss +Pastel +Dartmouth +Emerald +Fern +Forest +Harlequin +Honeydew +Hunter +Kelly green +Lawn +Malachite +Mantis +Neon +Olivine +Paris +Pear +Pigment +Pistachio +Reseda +Rifle +Sage +Screamin' +Shamrock +Bud +Amaranth +Baker-Miller +Cerise +Carmine +Magenta +Eggplant +Fandango +Finn +Fuchsia +Haze +Plum +Pizzazz +Quinacridone +Razzle dazzle +Rose +Shocking +Telemagenta +Aerospace +Alloy +Amber +Atomic +Tangerine +Burnt +Butterscotch +Carrot +Champagne +Coral +Flame +Gold +Hunyadi +Melon +Peel +Papaya +Peach +Persimmon +Princeton +Pumpkin +Safety orange +Saffron +Tangelo +Tigers Eye +Titian +Xanthous +Blush +Brilliant +Brink +Carnation +Cherry +Cyclamen +Dogwood +Hollywood +Hot +Lavender +Mimi +Misty +Mountbatten +Orchid +Phlox +Pompadour +Puce +Raspberry +Razzmatazz +Bonbon +Quartz +Taupe +Vale +Rosewood +Rosy +Salmon +Tea +Tickle +Thulian +Ultra +Burgundy +Byzantium +Eminence +Grape +Iris +Mardi Gras +Mauve +Mauveine +Mulberry +Murrey +Pale +Pomp +Power +Purpureus +Tekhelet +Thistle +Tropical +Tyrian +Wisteria +Barn +Bittersweet +Shimmer +Blood +Candy apple +Cantaloupe +Cardinal +Chili +Cosmos +Cinnabar +Claret +Coquelicot +Cordovan +Cornell +Crimson +Falu +Brick +Engine +Folly +Imperial +Jaspar +Poppy +Rojo +Rusty +Scarlet +Syracuse +Tomato +Turkey +Vermilion +Wine +Alabaster +Antique +Cornsilk +Latte +Cream +Eggshell +Flax +Floral +Ghost +Isabelline +Ivory +Lemon +chiffon +Linen +Navajo +Nyanza +Lace +Parchment +Pearl +Seasalt +Seashell +Vanilla +Smoke +Apricot +Arylide +Aureolin +Buff +Canary +Ecru +Gamboge +Icterine +Jonquil +Maize +Mikado +Mindaro +Mustard +Selective +Stil de grain +Straw +Sunglow +Sunset +Wheat + +# planets +Mars +Jupiter +Saturn +Pluto +Neptune +Europa + +# charites +Damia +Auxesia +Cleta +Phaenna +Hegemone +Peitho +Paregoros +Pasithea +Charis +Kale +Antheia +Eudaimonia +Euthymia +Eutychia +Paidia +Pandaisia +Pannychis +Aglaea +Euphrosyne +Thalia + +# nature +Blaze +River +Snow +Bones +Rain +Reed +Lake +Briar +Brook +Sky +Storm +Clay +Ember +Marsh +Star + +# trees +Ash +Oak +Rowan +Aspen +Alder +Apple +Beech +Birch +Box +Cedar +Cypress +Elder +Elm +Larch +Fir +Juniper +Lime +Pine +Poplar +Spruce +Yew + +# seasons +Spring +Summer +Autumn +Winter + +# cardinals +North +South +East +West + +# other +Ink +Echo +Mint +Mel +X +Sam +Tango +Gadget +Brum +Wall +Beam +Ud +Tal +Ren +Aki +Jun +Kei +Lynn +Lex +Cid +Miles +Rotor +Mesa +Verse + +# from the "300 list" +Aiden +Arden +Auden +August +Avery +Avis +Bay +Blake +Erin +Ezra +Kai +Lane +Leah +Noel +Pat +Ray +Remi +Roan +Robyn +Salem +Sean +Tate +Tobin +Tori +True +Val +Wilder +Wisdom +Wyatt +Zephyr + +# Gemstones +Actinolite +Nephrite +Adamite +Aegirine +Afghanite +Agrellite +Algodonite +Alunite +Amblygonite +Analcime +Anatase +Andalusite +Chiastolite +Anglesite +Anhydrite +Annabergite +Anorthite +Antigorite +Bowenite +Apatite +Apophyllite +Aragonite +Asbestos +Astrophyllite +Augelite +Austinite +Ferro +Magnes +Mangan +Tinzenite +Azurmalachite +Azurite +Baryte +Bast +Bayldonite +Benitoite +Beryl +Maxixe +Goshenite +Golden beryl +Heliodor +Morganite +Red beryl +Beryllonite +Beudantite +Bismutot +Biotit +Boracite +Bornite +Brazilianite +Brookite +Brucite +Bustam +Bytown +Calcite +Caledonite +Canasite +Cancrin +Vishnev +Carleton +Carnall +Cassiterite +Cataplei +Cavans +Celestite +Ceruleite +Cerussite +Chalcopyr +Chambers +Charlesite +Charoite +Childrenite +Chiolite +Chrysoberyl +Alexandrite +Cymophane +Chromite +Chrysocolla +Clinochlore +Clinohumite +Clintonite +Cobaltite +Coleman +Cordierite +Iolite +Cornwallite +Corundum +Ruby +Sapphire +Padparadscha +Covell +Creedite +Crocite +Cuprite +Danburite +Datolite +Descloiz +Diamond +Bort +Ballas +Diaspore +Dickinsonite +Diopside +Dioptase +Dolomite +Dumortier +Ekanite +Trapiche +Enstatite +Bronzite +Hypersthene +Eosphorite +Epidote +Piemont +Erythrite +Esperite +Ettring +Eudialyte +Faya +Feldspar +Andesine +Albite +Anorth +Anorthoc +Amazon +Celsian +Microcline +Moonstone +Adularia +Rainbow +Ortho +Kite +Plagioclase +Labradorite +Oligoclase +Sunstone +Oregon Sunstone +Rainbow Lattice +Fergusonite +Ferroaxin +Fluora +Fluorapophyl +Fluorite +Forster +Friedelite +Gadolin +Gahnite +Gahnospinel +Garnet +Pyralspite +Almandine +Spessartine +Ugrand +Demantoid +Melanite +Topazolita +Grossular +Hessonite +Hydrogrossular +Tsavorite +Pyrope +Rhodolite +Mali garnet +Malaia +Umbal +Gaspe +Gayluss +Gibbsite +Glaucophane +Goeth +Goosecreek +Grandidier +Gypsum +Gyro +Halite +Hambergite +Hanksite +Hardystonite +Helenite +Hematite +Herder +Hexagonite +Hibonite +Hidden +Hodgkinsonite +Holtite +Howlite +Huebnerite +Humite +Hurlbut +Ilmenite +Inderite +Jadeite +Jasper +Jeremejevite +Kainite +Kämmerer +Kaolin +Kornerup +Kurnakov +Kyanite +Langbein +Lawsonite +Lazulite +Lazurite +Legrandite +Lepidolite +Leucite +Leucophan +Linarite +Lizardite +Londonite +Ludlamite +Ludwigite +Maria-meionite +Werner +Marcasite +Meliphanite +Mellite +Mesolite +Milar +Millerite +Mime +Monazite +Mordenite +Mottram +Muscovite +Fuchsite +Nambul +Natrolite +Nepheline +Neptunite +Nickeline +Niccolite +Nosean +Nuumm +Opal +Fire opal +Moss opal +Painite +Papagoite +Pargas +Parisite +Pectol +Larimar +Pentland +Periclase +Perthite +Petal +Castor +Pezzottaite +Phena +Phosgen +Phospho +Piemontite +Realgar +Rhodizite +Rhodochros +Rhodon +Richter +Riebeck +Crocidolite +Rosasite +Rutile +Samarskite +Sanidine +Sapphirine +Sarcol +Scapol +Marialite +Meionite +Scheel +Schizol +Scorod +Selenite +Sella +Senarmon +Sepio +Meerschaum +Sérandite +Seraph +Serendibite +Serpentine +Bowen +Stich +Shattuck +Shiga +Shortite +Shung +Siderite +Silliman +Simpsonite +Sinhal +Smalt +Smithsonite +Sodalite +Hackman +Sogdian +Sperry +Spessar +Sphaler +Spinel +Ceylon +Spodumene +Triphane +Spurrite +Stauro +Strontian +Titanate +Sulfur +Bustamite +Sylvite +Taaffeita +Talc +Tantalite +Tektites +Tephroite +Thomsonite +Thaumasite +Topaz +Tourmaline +Achroite +Chrome +Dravite +Elbaite +Indicol +Olenite +Paraiba +Rossman +Rubellite +Tremol +Triphyl +Triplite +Tugtup +Turquoise +Ulex +Ussing +Vanadinite +Variscite +Vesuvianite +Californite +Villiaum +Vivianite +Vlasov +Wardite +Wavell +Welogan +Whewell +Wilkeite +Willemite +Wither +Wollastone +Wulfenite +Wurtzite +Xonot +Yugawara +Zektzer +Zeolites +Chabaz +Steller +Stilbite +Zinc +Zinnwald +Zircon +Jacinth +Zoisite +Tanzan +Thulite +Zultan +Zany +Lapis lazuli +Desert glass +Llanite +Maw sit-sit +Obsidian +Tears +Pallas +Peridot +Soapstone +Tact +Unakite +Bauxite +Concretions +Bloodstone +Heliotrope +Eilat stone +Epidos +Glimmer +Goldstone +Hawks eye +Iddings +Lampro diff --git a/data/dfhack-config/blueprints/README.md b/data/dfhack-config/blueprints/README.md new file mode 100644 index 0000000000..5d0e41a245 --- /dev/null +++ b/data/dfhack-config/blueprints/README.md @@ -0,0 +1,5 @@ +This folder contains blueprints that can be applied by the `quickfort` script. For more information, see: + +* [Quickfort command reference](https://docs.dfhack.org/en/stable/docs/tools/quickfort.html) +* [Quickfort blueprint guide](https://docs.dfhack.org/en/stable/docs/guides/quickfort-user-guide.html) +* [Quickfort library guide](https://docs.dfhack.org/en/stable/docs/guides/quickfort-library-guide.html) diff --git a/data/dfhack-config/buildingplan.json b/data/dfhack-config/buildingplan.json new file mode 100644 index 0000000000..9bb3052b71 --- /dev/null +++ b/data/dfhack-config/buildingplan.json @@ -0,0 +1,5 @@ +{ + "planner": { + "minimized": true + } +} \ No newline at end of file diff --git a/data/dfhack-config/dfstatus.lua b/data/dfhack-config/dfstatus.lua new file mode 100644 index 0000000000..f1e087d2f4 --- /dev/null +++ b/data/dfhack-config/dfstatus.lua @@ -0,0 +1,28 @@ +-- dfstatus config +-- the dfstatus script can be found in hack/scripts/gui/ +--[[ +The following variables can be set to true/false to enable/disable categories (all true by default) +* drink +* wood +* fuel +* prepared_meals +* tanned_hides +* cloth +* metals + +Example: +drink = false +fuel = true + +To add metals: +* metal 'IRON' +* metals "GOLD" 'SILVER' +* metal('COPPER') +* metals("BRONZE", 'HORN_SILVER') +Use '-' for a blank line: +* metal '-' +]] + +metals 'IRON' 'PIG_IRON' 'STEEL' +metals '-' +metals 'GOLD' 'SILVER' 'COPPER' diff --git a/data/dfhack-config/dwarfmonitor.json b/data/dfhack-config/dwarfmonitor.json new file mode 100644 index 0000000000..9bd3b1f769 --- /dev/null +++ b/data/dfhack-config/dwarfmonitor.json @@ -0,0 +1,3 @@ +{ + "date_format": "Y-M-D" +} diff --git a/data/dfhack-config/init/default.dfhack.init b/data/dfhack-config/init/default.dfhack.init new file mode 100644 index 0000000000..aad18dd1c4 --- /dev/null +++ b/data/dfhack-config/init/default.dfhack.init @@ -0,0 +1,7 @@ +# Load DFHack defaults. +# +# If you delete this file, it will reappear when you restart DFHack. +# Instead, please comment out the following line if you do not want DFHack to +# load its default configuration. + +script hack/init/dfhack.default.init diff --git a/data/dfhack-config/init/default.onLoad.init b/data/dfhack-config/init/default.onLoad.init new file mode 100644 index 0000000000..fe87d42097 --- /dev/null +++ b/data/dfhack-config/init/default.onLoad.init @@ -0,0 +1,7 @@ +# Load DFHack defaults. +# +# If you delete this file, it will reappear when you restart DFHack. +# Instead, please comment out the following line if you do not want DFHack to +# load its default configuration. + +script hack/init/onLoad.default.init diff --git a/data/dfhack-config/init/default.onMapLoad.init b/data/dfhack-config/init/default.onMapLoad.init new file mode 100644 index 0000000000..9e781b924a --- /dev/null +++ b/data/dfhack-config/init/default.onMapLoad.init @@ -0,0 +1,7 @@ +# Load DFHack defaults. +# +# If you delete this file, it will reappear when you restart DFHack. +# Instead, please comment out the following line if you do not want DFHack to +# load its default configuration. + +script hack/init/onMapLoad.default.init diff --git a/data/dfhack-config/init/default.onMapUnload.init b/data/dfhack-config/init/default.onMapUnload.init new file mode 100644 index 0000000000..716680fd01 --- /dev/null +++ b/data/dfhack-config/init/default.onMapUnload.init @@ -0,0 +1,7 @@ +# Load DFHack defaults. +# +# If you delete this file, it will reappear when you restart DFHack. +# Instead, please comment out the following line if you do not want DFHack to +# load its default configuration. + +script hack/init/onMapUnload.default.init diff --git a/data/dfhack-config/init/default.onUnload.init b/data/dfhack-config/init/default.onUnload.init new file mode 100644 index 0000000000..712c35098f --- /dev/null +++ b/data/dfhack-config/init/default.onUnload.init @@ -0,0 +1,7 @@ +# Load DFHack defaults. +# +# If you delete this file, it will reappear when you restart DFHack. +# Instead, please comment out the following line if you do not want DFHack to +# load its default configuration. + +script hack/init/onUnload.default.init diff --git a/data/dfhack-config/init/dfhack.init b/data/dfhack-config/init/dfhack.init new file mode 100644 index 0000000000..b05598f988 --- /dev/null +++ b/data/dfhack-config/init/dfhack.init @@ -0,0 +1,5 @@ +# This file runs when DFHack is initialized, when Dwarf Fortress is first +# started, before any world or save data is loaded. +# +# You can extend or override DFHack's default configuration by adding commands +# to this file. diff --git a/data/dfhack-config/init/onLoad.init b/data/dfhack-config/init/onLoad.init new file mode 100644 index 0000000000..ef4fd97afe --- /dev/null +++ b/data/dfhack-config/init/onLoad.init @@ -0,0 +1,6 @@ +# This file runs when a world is loaded. This happens when you open a save file +# in fort, adventure, or legends mode. If a fort is being loaded, this file runs +# before any onMapLoad.init files. +# +# You can extend or override DFHack's default configuration by adding commands +# to this file. diff --git a/data/dfhack-config/init/onMapLoad.init b/data/dfhack-config/init/onMapLoad.init new file mode 100644 index 0000000000..90c6b9e140 --- /dev/null +++ b/data/dfhack-config/init/onMapLoad.init @@ -0,0 +1,5 @@ +# This file runs when a map is loaded in adventure or fort mode, after any +# onLoad.init files (which run earlier, when the world is loaded). +# +# You can extend or override DFHack's default configuration by adding commands +# to this file. diff --git a/data/dfhack-config/init/onMapUnload.init b/data/dfhack-config/init/onMapUnload.init new file mode 100644 index 0000000000..c513d9caea --- /dev/null +++ b/data/dfhack-config/init/onMapUnload.init @@ -0,0 +1,5 @@ +# This file runs when a fortress map is unloaded, before any onUnload.init files +# (which run later, when the world is unloaded). +# +# You can extend or override DFHack's default configuration by adding commands +# to this file. diff --git a/data/dfhack-config/init/onUnload.init b/data/dfhack-config/init/onUnload.init new file mode 100644 index 0000000000..c8ed3ab5b5 --- /dev/null +++ b/data/dfhack-config/init/onUnload.init @@ -0,0 +1,4 @@ +# This file runs when a world is unloaded. +# +# You can extend or override DFHack's default configuration by adding commands +# to this file. diff --git a/data/dfhack-config/script-paths.txt b/data/dfhack-config/script-paths.txt new file mode 100644 index 0000000000..89a7fbd43d --- /dev/null +++ b/data/dfhack-config/script-paths.txt @@ -0,0 +1,4 @@ +# Add additional script search paths here +# Blank lines and lines that start with "#" will be ignored +# Paths preceded by "+" will be searched first +# Paths preceded by "-" will be searched after the default paths diff --git a/data/dfhack-config/scripts/README.md b/data/dfhack-config/scripts/README.md new file mode 100644 index 0000000000..95b67b058d --- /dev/null +++ b/data/dfhack-config/scripts/README.md @@ -0,0 +1,7 @@ +You can put scripts you write or download in this folder and DFHack will find +them. + +If a script in this directory has the same name as a default DFHack script, the + script in this directory will take precedence. + +Everything you add to this folder will be kept safe when you upgrade DFHack. diff --git a/data/dfhack-config/stockpiles/README.md b/data/dfhack-config/stockpiles/README.md new file mode 100644 index 0000000000..593d45fb67 --- /dev/null +++ b/data/dfhack-config/stockpiles/README.md @@ -0,0 +1,5 @@ +This folder contains stockpile settings that can be applied by `stockpiles` and +`quickfort` tools. For more information, see: + +* [stockpiles documentation](https://docs.dfhack.org/en/latest/docs/tools/stockpiles.html) +* [quickfort documentation](https://docs.dfhack.org/en/latest/docs/guides/quickfort-user-guide.html) diff --git a/data/init/dfhack.default.init b/data/init/dfhack.default.init new file mode 100644 index 0000000000..78dc70450a --- /dev/null +++ b/data/init/dfhack.default.init @@ -0,0 +1,8 @@ +# Default DFHack commands to run on program init + +# Please do not edit this file directly. It will be overwritten with new +# defaults when you update DFHack. Instead, add your configuration to +# dfhack-config/init/dfhack.init + +script hack/init/dfhack.keybindings.init +script hack/init/dfhack.tools.init diff --git a/data/init/dfhack.keybindings.init b/data/init/dfhack.keybindings.init new file mode 100644 index 0000000000..018c66ccde --- /dev/null +++ b/data/init/dfhack.keybindings.init @@ -0,0 +1,168 @@ +# Default DFHack keybindings + +# Please do not edit this file directly. It will be overwritten with new +# defaults when you update DFHack. Instead, add your configuration to +# dfhack-config/init/dfhack.init + +################### +# global bindings # +################### + +# the GUI command launcher (two bindings since some keyboards don't have "`") +keybinding add ` gui/launcher +keybinding add Ctrl-Shift-D gui/launcher +keybinding add Ctrl-Shift-P "gui/launcher --minimal" + +# show hotkey popup menu +keybinding add Ctrl-Shift-C hotkeys + +# control panel +keybinding add Ctrl-Shift-E gui/control-panel + +# on-screen keyboard +keybinding add Ctrl-Shift-K gui/cp437-table + +# customizable quick command list +keybinding add Ctrl-Shift-A gui/quickcmd + + +################### +# embark bindings # +################### + +keybinding add Ctrl-A@choose_start_site gui/embark-anywhere + + +################################## +# dwarfmode+dungeonmode bindings # +################################## + +# save the description of a selected unit or item to the `markdown_{YourWorldName}.md` file +# in the game root directory +keybinding add Ctrl-T@dwarfmode/ViewSheets/UNIT|dwarfmode/ViewSheets/ITEM|dungeonmode/ViewSheets/UNIT|dungeonmode/ViewSheets/ITEM markdown + +# gui/sitemap +keybinding add Ctrl-G@dwarfmode/Default|dungeonmode/Default gui/sitemap + +# toggle keyboard cursor +keybinding add Alt-K@dwarfmode|dungeonmode/Default|dungeonmode/Look toggle-kbd-cursor + +# gui/journal +keybinding add Ctrl-J@dwarfmode|dungeonmode gui/journal + + +###################### +# dwarfmode bindings # +###################### + +# quicksave +keybinding add Ctrl-Alt-S@dwarfmode quicksave + +# toggle spectate +keybinding add Ctrl-Shift-S@dwarfmode/Default "spectate toggle" + +# designate the whole vein for digging +keybinding add Ctrl-V@dwarfmode digv +keybinding add Ctrl-Shift-V@dwarfmode "digv x" + +# clean the selected tile of blood etc +keybinding add Ctrl-C@dwarfmode spotclean + +# destroy the selected item +keybinding add Ctrl-K@dwarfmode autodump-destroy-item + +# bring up the autodump UI +keybinding add Ctrl-H@dwarfmode gui/autodump + +# bring up the teleport UI +keybinding add Ctrl-Shift-T@dwarfmode gui/teleport + +# apply blueprints to the map +keybinding add Ctrl-Shift-Q@dwarfmode gui/quickfort + +# Stocks plugin +#keybinding add Ctrl-Shift-Z@dwarfmode/Default "stocks show" + +# open an overview window summarising some stocks (dfstatus) +#keybinding add Ctrl-Shift-I@dwarfmode/Default|dfhack/lua/dfstatus gui/dfstatus + +# set workorder item details (on workorder details screen press D again) +#keybinding add D@workquota_details gui/workorder-details + +# view combat reports for the selected unit/corpse/spatter +#keybinding add Ctrl-Shift-R@dwarfmode|unit|unitlist|joblist|dungeon_monsterstatus|layer_unit_relationship|item|workshop_profile|layer_noblelist|locations|pets|layer_overall_health|textviewer|reportlist|announcelist|layer_military|layer_unit_health|customize_unit|buildinglist|workshop_profile view-unit-reports + +# view extra unit information +#keybinding add Alt-I@dwarfmode/ViewUnits|unitlist gui/unit-info-viewer + +# boost priority of jobs related to the selected entity +#keybinding add Alt-N@dwarfmode|job|joblist|unit|unitlist|joblist|dungeon_monsterstatus|layer_unit_relationship|item|layer_noblelist|locations|pets|layer_overall_health|textviewer|reportlist|announcelist|layer_military|layer_unit_health|customize_unit|buildinglist|textviewer|item|layer_assigntrade|tradegoods|store|assign_display_item|treasurelist do-job-now + +# q->stockpile - copy & paste stockpiles +#keybinding add Alt-P@dwarfmode/QueryBuilding/Some/Stockpile copystock + +# q->stockpile - load and save stockpile settings out of game +#keybinding add Alt-L@dwarfmode/QueryBuilding/Some/Stockpile "gui/stockpiles -load" +#keybinding add Alt-S@dwarfmode/QueryBuilding/Some/Stockpile "gui/stockpiles -save" + +# q->workshop - duplicate the selected job +#keybinding add Ctrl-D job-duplicate + +# materials: q->workshop; b->select items +#keybinding add Shift-A "job-material ALUNITE" +#keybinding add Shift-M "job-material MICROCLINE" +#keybinding add Shift-D "job-material DACITE" +#keybinding add Shift-R "job-material RHYOLITE" +#keybinding add Shift-I "job-material CINNABAR" +#keybinding add Shift-B "job-material COBALTITE" +#keybinding add Shift-O "job-material OBSIDIAN" +#keybinding add Shift-T "job-material ORTHOCLASE" +#keybinding add Shift-G "job-material GLASS_GREEN" + +# browse rooms of same owner +#keybinding add Alt-R@dwarfmode/QueryBuilding/Some gui/room-list + +# machine power sensitive pressure plate construction +#keybinding add Ctrl-Shift-M@dwarfmode/Build/Position/Trap gui/power-meter + +# siege engine control +#keybinding add Alt-A@dwarfmode/QueryBuilding/Some/SiegeEngine gui/siege-engine + +# military weapon auto-select +#keybinding add Ctrl-W@layer_military/Equip/Customize/View gui/choose-weapons + +# military copy uniform +#keybinding add Ctrl-C@layer_military/Uniforms gui/clone-uniform + +# minecart Guide path +#keybinding add Alt-P@dwarfmode/Hauling/DefineStop/Cond/Guide gui/guide-path + +# workshop job details +#keybinding add Alt-A@dwarfmode/QueryBuilding/Some/Workshop/Job gui/workshop-job + +# workflow front-end +#keybinding add Alt-W@dwarfmode/QueryBuilding/Some/Workshop/Job gui/workflow +#keybinding add Alt-W@overallstatus "gui/workflow status" +# equivalent to the one above when gui/extended-status is enabled +#keybinding add Alt-W@dfhack/lua/status_overlay "gui/workflow status" + +# gui/rename script - rename units and buildings +#keybinding add Ctrl-Shift-N@dwarfmode|unit|unitlist|joblist|dungeon_monsterstatus|layer_unit_relationship|item|workshop_profile|layer_noblelist|locations|pets|layer_overall_health|textviewer|reportlist|announcelist|layer_military|layer_unit_health|customize_unit|buildinglist gui/rename +#keybinding add Ctrl-Shift-T@dwarfmode|unit|unitlist|joblist|dungeon_monsterstatus|layer_unit_relationship|item|workshop_profile|layer_noblelist|locations|pets|layer_overall_health|textviewer|reportlist|announcelist|layer_military|layer_unit_health|customize_unit "gui/rename unit-profession" + +# gui/design +keybinding add Ctrl-D@dwarfmode/Default gui/design +keybinding add Ctrl-M@dwarfmode/Default gui/mass-remove + + +######################## +# dungeonmode bindings # +######################## + +keybinding add Ctrl-A@setupadventure unretire-anyone + +#keybinding add Ctrl-B@dungeonmode adv-bodyswap +#keybinding add Ctrl-Shift-B@dungeonmode "adv-bodyswap force" +#keybinding add Shift-O@dungeonmode gui/companion-order +#keybinding add Ctrl-T@dungeonmode gui/advfort +keybinding add Ctrl-T@dungeonmode/Default flashstep diff --git a/data/init/dfhack.tools.init b/data/init/dfhack.tools.init new file mode 100644 index 0000000000..baa26d3ee4 --- /dev/null +++ b/data/init/dfhack.tools.init @@ -0,0 +1,19 @@ +# Default DFHack tool configuration + +# Please do not edit this file directly. It will be overwritten with new +# defaults when you update DFHack. Instead, add your configuration to +# dfhack-config/init/dfhack.init + +# Enable system services +enable buildingplan +enable burrow +enable logistics +enable overlay +enable preserve-rooms + +# aliases +alias add autounsuspend suspendmanager +alias add drain-aquifer aquifer drain --all +alias add gui/dig gui/design +alias add version help +alias add gui/pregnancy gui/family-affairs --pregnancy diff --git a/data/init/onLoad.default.init b/data/init/onLoad.default.init new file mode 100644 index 0000000000..e797f88ee7 --- /dev/null +++ b/data/init/onLoad.default.init @@ -0,0 +1,7 @@ +# Default DFHack commands to run when a world is loaded + +# Please do not edit this file directly. It will be overwritten with new +# defaults when you update DFHack. Instead, add your configuration to +# dfhack-config/init/onLoad.init + +lua require('quickfix').set_entity_race_references() diff --git a/data/init/onMapLoad.default.init b/data/init/onMapLoad.default.init new file mode 100644 index 0000000000..44986a044c --- /dev/null +++ b/data/init/onMapLoad.default.init @@ -0,0 +1,6 @@ +# Default DFHack commands to run when a map is loaded, either in +# adventure or fort mode. + +# Please do not edit this file directly. It will be overwritten with new +# defaults when you update DFHack. Instead, add your configuration to +# dfhack-config/init/onMapLoad.init diff --git a/data/init/onMapUnload.default.init b/data/init/onMapUnload.default.init new file mode 100644 index 0000000000..6441d72ffa --- /dev/null +++ b/data/init/onMapUnload.default.init @@ -0,0 +1,5 @@ +# Default DFHack commands to run when a map is unloaded + +# Please do not edit this file directly. It will be overwritten with new +# defaults when you update DFHack. Instead, add your configuration to +# dfhack-config/init/onMapUnload.init diff --git a/data/init/onUnload.default.init b/data/init/onUnload.default.init new file mode 100644 index 0000000000..9254a257bf --- /dev/null +++ b/data/init/onUnload.default.init @@ -0,0 +1,5 @@ +# Default DFHack commands to run when a world is unloaded + +# Please do not edit this file directly. It will be overwritten with new +# defaults when you update DFHack. Instead, add your configuration to +# dfhack-config/init/onUnload.init diff --git a/data/orders/basic.json b/data/orders/basic.json new file mode 100644 index 0000000000..e1cd5ac8ff --- /dev/null +++ b/data/orders/basic.json @@ -0,0 +1,1407 @@ +[ + { + "amount_left" : 10, + "amount_total" : 10, + "frequency" : "Daily", + "id" : 0, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "unrotten", + "cookable", + "solid" + ], + "value" : 20 + }, + { + "condition" : "AtLeast", + "flags" : + [ + "unrotten", + "cookable" + ], + "value" : 80 + }, + { + "condition" : "AtMost", + "flags" : + [ + "unrotten" + ], + "item_type" : "FOOD", + "value" : 2000 + } + ], + "job" : "PrepareMeal", + "meal_ingredients" : 4 + }, + { + "amount_left" : 2, + "amount_total" : 2, + "frequency" : "Daily", + "id" : 1, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "unrotten" + ], + "item_type" : "PLANT", + "reaction_product" : "DRINK_MAT", + "value" : 15 + }, + { + "condition" : "AtLeast", + "flags" : + [ + "empty", + "food_storage" + ], + "value" : 5 + }, + { + "condition" : "AtMost", + "item_type" : "DRINK", + "value" : 3000 + } + ], + "job" : "CustomReaction", + "reaction" : "BREW_DRINK_FROM_PLANT" + }, + { + "amount_left" : 2, + "amount_total" : 2, + "frequency" : "Daily", + "id" : 2, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "unrotten" + ], + "item_type" : "PLANT_GROWTH", + "reaction_product" : "DRINK_MAT", + "value" : 15 + }, + { + "condition" : "AtLeast", + "flags" : + [ + "empty", + "food_storage" + ], + "value" : 5 + }, + { + "condition" : "AtMost", + "item_type" : "DRINK", + "value" : 3000 + } + ], + "job" : "CustomReaction", + "reaction" : "BREW_DRINK_FROM_PLANT_GROWTH" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 4, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "non_pressed" + ], + "item_subtype" : "ITEM_TOOL_HONEYCOMB", + "item_type" : "TOOL", + "reaction_product" : "HONEYCOMB_PRESS_MAT", + "value" : 2 + }, + { + "condition" : "AtLeast", + "flags" : + [ + "empty", + "non_absorbent" + ], + "item_type" : "TOOL", + "tool" : "LIQUID_CONTAINER", + "value" : 2 + } + ], + "job" : "CustomReaction", + "reaction" : "PRESS_HONEYCOMB" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 5, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "contains" : + [ + "honey" + ], + "reaction_id" : "MAKE_MEAD", + "value" : 2 + }, + { + "condition" : "AtLeast", + "flags" : + [ + "empty", + "food_storage" + ], + "reaction_id" : "MAKE_MEAD", + "value" : 5 + } + ], + "job" : "CustomReaction", + "reaction" : "MAKE_MEAD" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 6, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "millable", + "unrotten" + ], + "item_type" : "PLANT", + "value" : 20 + }, + { + "condition" : "AtLeast", + "flags" : + [ + "empty" + ], + "item_type" : "BAG", + "value" : 5 + } + ], + "job" : "MillPlants" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 7, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "unrotten", + "processable" + ], + "item_type" : "PLANT", + "value" : 20 + } + ], + "job" : "ProcessPlants" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 8, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "unrotten" + ], + "item_type" : "PLANT", + "reaction_product" : "BAG_ITEM", + "value" : 15 + }, + { + "condition" : "AtLeast", + "flags" : + [ + "empty" + ], + "item_type" : "BAG", + "value" : 5 + } + ], + "job" : "CustomReaction", + "reaction" : "PROCESS_PLANT_TO_BAG" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 9, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "unrotten", + "processable_to_barrel" + ], + "item_type" : "PLANT", + "value" : 150 + }, + { + "condition" : "AtLeast", + "flags" : + [ + "empty" + ], + "item_type" : "BARREL", + "value" : 5 + } + ], + "job" : "ProcessPlantsBarrel" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 10, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "unrotten" + ], + "item_type" : "SEEDS", + "reaction_product" : "PRESS_LIQUID_MAT", + "value" : 30 + }, + { + "condition" : "AtMost", + "flags" : + [ + "non_pressed" + ], + "item_type" : "GLOB", + "reaction_product" : "PRESS_LIQUID_MAT", + "value" : 10 + } + ], + "job" : "CustomReaction", + "reaction" : "MILL_SEEDS_NUTS_TO_PASTE" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 11, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "non_pressed" + ], + "item_type" : "GLOB", + "reaction_product" : "PRESS_LIQUID_MAT", + "value" : 2 + }, + { + "condition" : "AtLeast", + "flags" : + [ + "empty", + "non_absorbent" + ], + "item_type" : "TOOL", + "tool" : "LIQUID_CONTAINER", + "value" : 5 + }, + { + "condition" : "AtMost", + "item_type" : "LIQUID_MISC", + "reaction_product" : "SOAP_MAT", + "value" : 10 + } + ], + "job" : "CustomReaction", + "reaction" : "PRESS_OIL" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 12, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "unrotten", + "body_part", + "hair_wool" + ], + "value" : 5 + } + ], + "job" : "SpinThread", + "material_category" : + [ + "strand" + ] + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 13, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "collected", + "silk" + ], + "item_type" : "THREAD", + "value" : 5 + }, + { + "condition" : "AtMost", + "flags" : + [ + "silk" + ], + "item_type" : "CLOTH", + "value" : 100 + } + ], + "job" : "WeaveCloth", + "material_category" : + [ + "silk" + ] + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 14, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "collected", + "plant" + ], + "item_type" : "THREAD", + "value" : 5 + }, + { + "condition" : "AtMost", + "flags" : + [ + "plant" + ], + "item_type" : "CLOTH", + "value" : 100 + } + ], + "job" : "WeaveCloth", + "material_category" : + [ + "plant" + ] + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 15, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "collected", + "yarn" + ], + "item_type" : "THREAD", + "value" : 5 + }, + { + "condition" : "AtMost", + "flags" : + [ + "yarn" + ], + "item_type" : "CLOTH", + "value" : 100 + } + ], + "job" : "WeaveCloth", + "material_category" : + [ + "yarn" + ] + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 16, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "dyeable" + ], + "item_type" : "CLOTH", + "value" : 5 + }, + { + "condition" : "AtLeast", + "flags" : + [ + "unrotten", + "dye" + ], + "value" : 3 + } + ], + "job" : "DyeCloth" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 17, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "non_economic", + "hard" + ], + "item_type" : "BOULDER", + "material" : "INORGANIC", + "value" : 20 + }, + { + "condition" : "AtMost", + "flags" : + [ + "empty" + ], + "item_subtype" : "ITEM_TOOL_LARGE_POT", + "item_type" : "TOOL", + "value" : 25 + } + ], + "item_subtype" : "ITEM_TOOL_LARGE_POT", + "job" : "MakeTool", + "material" : "INORGANIC" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 18, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "WOOD", + "value" : 50 + }, + { + "condition" : "AtMost", + "flags" : + [ + "empty" + ], + "item_type" : "BIN", + "value" : 5 + } + ], + "job" : "ConstructBin", + "material_category" : + [ + "wood" + ] + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 19, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "WOOD", + "value" : 20 + }, + { + "condition" : "AtMost", + "flags" : + [ + "empty" + ], + "item_subtype" : "ITEM_TOOL_JUG", + "item_type" : "TOOL", + "value" : 10 + } + ], + "item_subtype" : "ITEM_TOOL_JUG", + "job" : "MakeTool", + "material_category" : + [ + "wood" + ] + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 20, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "non_economic", + "hard" + ], + "item_type" : "BOULDER", + "material" : "INORGANIC", + "value" : 20 + }, + { + "condition" : "AtMost", + "item_type" : "GOBLET", + "value" : 10 + } + ], + "job" : "MakeGoblet", + "material" : "INORGANIC" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 21, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "WOOD", + "value" : 150 + }, + { + "condition" : "AtMost", + "item_subtype" : "ITEM_TOOL_WHEELBARROW", + "item_type" : "TOOL", + "value" : 2 + } + ], + "item_subtype" : "ITEM_TOOL_WHEELBARROW", + "job" : "MakeTool", + "material_category" : + [ + "wood" + ] + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 22, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "WOOD", + "value" : 150 + }, + { + "condition" : "AtMost", + "flags" : + [ + "empty" + ], + "item_subtype" : "ITEM_TOOL_MINECART", + "item_type" : "TOOL", + "value" : 2 + } + ], + "item_subtype" : "ITEM_TOOL_MINECART", + "job" : "MakeTool", + "material_category" : + [ + "wood" + ] + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 23, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "WOOD", + "value" : 50 + }, + { + "condition" : "AtMost", + "flags" : + [ + "empty" + ], + "item_type" : "BUCKET", + "value" : 10 + } + ], + "job" : "MakeBucket", + "material_category" : + [ + "wood" + ] + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 24, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "WOOD", + "value" : 150 + }, + { + "condition" : "AtMost", + "flags" : + [ + "empty" + ], + "item_type" : "CAGE", + "value" : 30 + } + ], + "job" : "MakeCage", + "material_category" : + [ + "wood" + ] + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 25, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "non_economic", + "hard" + ], + "item_type" : "BOULDER", + "material" : "INORGANIC", + "value" : 50 + }, + { + "condition" : "AtMost", + "item_type" : "TRAPPARTS", + "value" : 20 + } + ], + "job" : "ConstructMechanisms", + "material" : "INORGANIC" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 26, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "SKIN_TANNED", + "value" : 10 + }, + { + "condition" : "AtMost", + "flags" : + [ + "empty" + ], + "item_type" : "BAG", + "value" : 30 + } + ], + "job" : "ConstructBag", + "material_category" : + [ + "leather" + ] + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 27, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "silk" + ], + "item_type" : "CLOTH", + "min_dimension" : 10000, + "value" : 10 + }, + { + "condition" : "AtMost", + "flags" : + [ + "empty" + ], + "item_type" : "BAG", + "value" : 30 + } + ], + "job" : "ConstructBag", + "material_category" : + [ + "silk" + ] + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 28, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "plant" + ], + "item_type" : "CLOTH", + "min_dimension" : 10000, + "value" : 10 + }, + { + "condition" : "AtMost", + "flags" : + [ + "empty" + ], + "item_type" : "BAG", + "value" : 30 + } + ], + "job" : "ConstructBag", + "material_category" : + [ + "cloth" + ] + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 29, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "yarn" + ], + "item_type" : "CLOTH", + "min_dimension" : 10000, + "value" : 10 + }, + { + "condition" : "AtMost", + "flags" : + [ + "empty" + ], + "item_type" : "BAG", + "value" : 30 + } + ], + "job" : "ConstructBag", + "material_category" : + [ + "yarn" + ] + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 30, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "GLOB", + "reaction_class" : "WAX", + "value" : 2 + } + ], + "job" : "CustomReaction", + "reaction" : "MAKE_WAX_CRAFTS" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 31, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "unrotten", + "shell", + "body_part" + ], + "value" : 2 + } + ], + "item_subtype" : "ITEM_PANTS_LEGGINGS", + "job" : "MakePants", + "material_category" : + [ + "shell" + ] + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 32, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "unrotten", + "totemable", + "body_part" + ], + "value" : 5 + } + ], + "job" : "MakeTotem" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 33, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "WOOD", + "value" : 50 + }, + { + "condition" : "AtMost", + "item_type" : "SPLINT", + "value" : 1 + } + ], + "job" : "ConstructSplint", + "material_category" : + [ + "wood" + ] + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 34, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "WOOD", + "value" : 50 + }, + { + "condition" : "AtMost", + "item_type" : "CRUTCH", + "value" : 1 + } + ], + "job" : "ConstructCrutch", + "material_category" : + [ + "wood" + ] + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 35, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "WOOD", + "value" : 150 + }, + { + "condition" : "AtMost", + "item_type" : "BED", + "value" : 2 + } + ], + "job" : "ConstructBed", + "material_category" : + [ + "wood" + ] + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 36, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "ASH", + "value" : 5 + }, + { + "condition" : "AtLeast", + "flags" : + [ + "empty" + ], + "item_type" : "BUCKET", + "value" : 5 + }, + { + "condition" : "AtMost", + "contains" : + [ + "lye" + ], + "reaction_id" : "MAKE_SOAP_FROM_TALLOW", + "value" : 5 + } + ], + "job" : "MakeLye" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 37, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "unrotten" + ], + "item_type" : "GLOB", + "reaction_class" : "TALLOW", + "reaction_product" : "SOAP_MAT", + "value" : 5 + }, + { + "condition" : "AtLeast", + "contains" : + [ + "lye" + ], + "reaction_id" : "MAKE_SOAP_FROM_TALLOW", + "value" : 3 + }, + { + "condition" : "AtMost", + "flags" : + [ + "soap" + ], + "item_type" : "BAR", + "value" : 5 + } + ], + "job" : "CustomReaction", + "reaction" : "MAKE_SOAP_FROM_TALLOW" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 38, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "LIQUID_MISC", + "reaction_product" : "SOAP_MAT", + "value" : 5 + }, + { + "condition" : "AtLeast", + "contains" : + [ + "lye" + ], + "reaction_id" : "MAKE_SOAP_FROM_OIL", + "value" : 3 + }, + { + "condition" : "AtMost", + "flags" : + [ + "soap" + ], + "item_type" : "BAR", + "value" : 5 + } + ], + "job" : "CustomReaction", + "reaction" : "MAKE_SOAP_FROM_OIL" + }, + { + "amount_left" : 4, + "amount_total" : 4, + "frequency" : "Daily", + "id" : 39, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "WOOD", + "value" : 50 + }, + { + "condition" : "AtMost", + "item_type" : "BAR", + "material" : "ASH", + "value" : 10 + } + ], + "job" : "MakeAsh" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 40, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "ASH", + "value" : 5 + }, + { + "condition" : "AtMost", + "item_type" : "BAR", + "material" : "POTASH", + "value" : 20 + } + ], + "job" : "MakePotashFromAsh" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 41, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "unrotten" + ], + "item_type" : "PLANT", + "reaction_id" : "MAKE_SLURRY_FROM_PLANT", + "reaction_product" : "PRESS_PAPER_MAT", + "value" : 50 + }, + { + "condition" : "AtMost", + "flags" : + [ + "non_pressed" + ], + "item_type" : "GLOB", + "reaction_class" : "PAPER_SLURRY", + "value" : 2 + } + ], + "job" : "CustomReaction", + "reaction" : "MAKE_SLURRY_FROM_PLANT" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 42, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "non_pressed" + ], + "item_type" : "GLOB", + "reaction_class" : "PAPER_SLURRY", + "reaction_id" : "PRESS_PLANT_PAPER", + "value" : 2 + }, + { + "condition" : "AtMost", + "item_type" : "SHEET", + "value" : 10 + } + ], + "job" : "CustomReaction", + "reaction" : "PRESS_PLANT_PAPER" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 43, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "unrotten" + ], + "item_type" : "PLANT", + "reaction_class" : "PAPER_PLANT", + "reaction_id" : "MAKE_SHEET_FROM_PLANT", + "value" : 15 + }, + { + "condition" : "AtMost", + "item_type" : "SHEET", + "value" : 10 + } + ], + "job" : "CustomReaction", + "reaction" : "MAKE_SHEET_FROM_PLANT" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 44, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "non_economic", + "hard" + ], + "item_type" : "BOULDER", + "material" : "INORGANIC", + "value" : 50 + }, + { + "condition" : "AtMost", + "item_subtype" : "ITEM_TOOL_SCROLL_ROLLERS", + "item_type" : "TOOL", + "value" : 10 + } + ], + "item_subtype" : "ITEM_TOOL_SCROLL_ROLLERS", + "job" : "MakeTool", + "material" : "INORGANIC" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 45, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "SHEET", + "reaction_id" : "MAKE_SCROLL", + "value" : 2 + }, + { + "condition" : "AtLeast", + "item_subtype" : "ITEM_TOOL_SCROLL_ROLLERS", + "item_type" : "TOOL", + "reaction_id" : "MAKE_SCROLL", + "value" : 2 + }, + { + "condition" : "AtMost", + "item_subtype" : "ITEM_TOOL_SCROLL", + "item_type" : "TOOL", + "value" : 10 + } + ], + "job" : "CustomReaction", + "reaction" : "MAKE_SCROLL" + } +] diff --git a/data/orders/furnace.json b/data/orders/furnace.json new file mode 100644 index 0000000000..62e389ded1 --- /dev/null +++ b/data/orders/furnace.json @@ -0,0 +1,360 @@ +[ + { + "amount_left" : 20, + "amount_total" : 20, + "frequency" : "Daily", + "id" : 0, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "WOOD", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "BAR", + "material" : "COAL", + "value" : 150 + }, + { + "condition" : "AtMost", + "item_type" : "BOULDER", + "material" : "INORGANIC:COAL_BITUMINOUS", + "value" : 10 + }, + { + "condition" : "AtMost", + "item_type" : "BOULDER", + "material" : "INORGANIC:LIGNITE", + "value" : 10 + } + ], + "job" : "MakeCharcoal" + }, + { + "amount_left" : 4, + "amount_total" : 4, + "frequency" : "Daily", + "id" : 1, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "WOOD", + "value" : 10 + }, + { + "condition" : "AtMost", + "item_type" : "BAR", + "material" : "COAL", + "value" : 20 + } + ], + "job" : "MakeCharcoal" + }, + { + "amount_left" : 4, + "amount_total" : 4, + "frequency" : "Daily", + "id" : 2, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BOULDER", + "material" : "INORGANIC:COAL_BITUMINOUS", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 5 + } + ], + "job" : "CustomReaction", + "reaction" : "BITUMINOUS_COAL_TO_COKE" + }, + { + "amount_left" : 4, + "amount_total" : 4, + "frequency" : "Daily", + "id" : 3, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BOULDER", + "material" : "INORGANIC:LIGNITE", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 5 + } + ], + "job" : "CustomReaction", + "reaction" : "LIGNITE_TO_COKE" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 5, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "POTASH", + "reaction_id" : "MAKE_PEARLASH", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "BAR", + "material" : "PEARLASH", + "value" : 10 + } + ], + "job" : "CustomReaction", + "reaction" : "MAKE_PEARLASH" + }, + { + "amount_left" : 4, + "amount_total" : 4, + "frequency" : "Daily", + "id" : 6, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "empty" + ], + "item_type" : "BAG", + "value" : 10 + }, + { + "condition" : "AtMost", + "flags" : + [ + "sand_bearing" + ], + "value" : 30 + } + ], + "job" : "CollectSand" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 7, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "sand_bearing" + ], + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "ROUGH", + "material" : "GLASS_GREEN", + "value" : 10 + } + ], + "job" : "MakeRawGlass", + "material" : "GLASS_GREEN" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 8, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "sand_bearing" + ], + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "PEARLASH", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "ROUGH", + "material" : "GLASS_CLEAR", + "value" : 10 + } + ], + "job" : "MakeRawGlass", + "material" : "GLASS_CLEAR" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 9, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "PEARLASH", + "value" : 5 + }, + { + "condition" : "AtLeast", + "flags" : + [ + "glass_making" + ], + "item_type" : "ROUGH", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "ROUGH", + "material" : "GLASS_CRYSTAL", + "value" : 10 + } + ], + "job" : "MakeRawGlass", + "material" : "GLASS_CRYSTAL" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 10, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BOULDER", + "material" : "INORGANIC:RAW_ADAMANTINE", + "value" : 5 + } + ], + "job" : "ExtractMetalStrands", + "material" : "INORGANIC:RAW_ADAMANTINE" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 11, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "THREAD", + "material" : "INORGANIC:ADAMANTINE", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "BAR", + "material" : "INORGANIC:ADAMANTINE", + "value" : 20 + } + ], + "job" : "CustomReaction", + "reaction" : "ADAMANTINE_WAFERS" + }, + { + "amount_left" : 4, + "amount_total" : 4, + "frequency" : "Daily", + "id" : 12, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "melt_designated", + "allow_melt_dump" + ], + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + } + ], + "job" : "MeltMetalObject" + } +] diff --git a/data/orders/glassstock.json b/data/orders/glassstock.json new file mode 100644 index 0000000000..ec5ad5ec6f --- /dev/null +++ b/data/orders/glassstock.json @@ -0,0 +1,688 @@ +[ + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 0, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "sand_bearing" + ], + "value" : 15 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "ARMORSTAND", + "value" : 2 + } + ], + "job" : "ConstructArmorStand", + "material" : "GLASS_GREEN" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 1, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "sand_bearing" + ], + "value" : 15 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "BLOCKS", + "material" : "GLASS_GREEN", + "value" : 2 + } + ], + "job" : "ConstructBlocks", + "material" : "GLASS_GREEN" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 2, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "sand_bearing" + ], + "value" : 15 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "BOX", + "material" : "GLASS_GREEN", + "value" : 2 + } + ], + "job" : "ConstructChest", + "material" : "GLASS_GREEN" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 3, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "sand_bearing" + ], + "value" : 15 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "CABINET", + "value" : 2 + } + ], + "job" : "ConstructCabinet", + "material" : "GLASS_GREEN" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 4, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "sand_bearing" + ], + "value" : 15 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "COFFIN", + "value" : 2 + } + ], + "job" : "ConstructCoffin", + "material" : "GLASS_GREEN" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 5, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "sand_bearing" + ], + "value" : 15 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "FLOODGATE", + "value" : 2 + } + ], + "job" : "ConstructFloodgate", + "material" : "GLASS_GREEN" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 6, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "sand_bearing" + ], + "value" : 15 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "GRATE", + "value" : 2 + } + ], + "job" : "ConstructGrate", + "material" : "GLASS_GREEN" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 7, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "sand_bearing" + ], + "value" : 15 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "HATCH_COVER", + "value" : 2 + } + ], + "job" : "ConstructHatchCover", + "material" : "GLASS_GREEN" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 8, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "sand_bearing" + ], + "value" : 15 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "DOOR", + "value" : 2 + } + ], + "job" : "ConstructDoor", + "material" : "GLASS_GREEN" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 9, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "sand_bearing" + ], + "value" : 15 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "STATUE", + "value" : 2 + } + ], + "job" : "ConstructStatue", + "material" : "GLASS_GREEN" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 10, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "sand_bearing" + ], + "value" : 15 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "TABLE", + "value" : 2 + } + ], + "job" : "ConstructTable", + "material" : "GLASS_GREEN" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 11, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "sand_bearing" + ], + "value" : 15 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "CHAIR", + "value" : 2 + } + ], + "job" : "ConstructThrone", + "material" : "GLASS_GREEN" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 12, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "sand_bearing" + ], + "value" : 15 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "WEAPONRACK", + "value" : 2 + } + ], + "job" : "ConstructWeaponRack", + "material" : "GLASS_GREEN" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 13, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "sand_bearing" + ], + "value" : 15 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_subtype" : "ITEM_TRAPCOMP_ENORMOUSCORKSCREW", + "item_type" : "TRAPCOMP", + "material" : "GLASS_GREEN", + "value" : 2 + } + ], + "item_subtype" : "ITEM_TRAPCOMP_ENORMOUSCORKSCREW", + "job" : "MakeTrapComponent", + "material" : "GLASS_GREEN" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 14, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "sand_bearing" + ], + "value" : 15 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_subtype" : "ITEM_TOOL_ALTAR", + "item_type" : "TOOL", + "value" : 2 + } + ], + "item_subtype" : "ITEM_TOOL_ALTAR", + "job" : "MakeTool", + "material" : "GLASS_GREEN" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 15, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "sand_bearing" + ], + "value" : 15 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_subtype" : "ITEM_TOOL_BOOKCASE", + "item_type" : "TOOL", + "value" : 2 + } + ], + "item_subtype" : "ITEM_TOOL_BOOKCASE", + "job" : "MakeTool", + "material" : "GLASS_GREEN" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 16, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "sand_bearing" + ], + "value" : 15 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_subtype" : "ITEM_TOOL_PEDESTAL", + "item_type" : "TOOL", + "value" : 2 + } + ], + "item_subtype" : "ITEM_TOOL_PEDESTAL", + "job" : "MakeTool", + "material" : "GLASS_GREEN" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 17, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "sand_bearing" + ], + "value" : 15 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "CAGE", + "value" : 2 + } + ], + "job" : "MakeCage", + "material" : "GLASS_GREEN" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 18, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "sand_bearing" + ], + "value" : 15 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "PIPE_SECTION", + "material" : "GLASS_GREEN", + "value" : 2 + } + ], + "job" : "MakePipeSection", + "material" : "GLASS_GREEN" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 19, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "sand_bearing" + ], + "value" : 15 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "WINDOW", + "material" : "GLASS_GREEN", + "value" : 2 + } + ], + "job" : "MakeWindow", + "material" : "GLASS_GREEN" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 20, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "sand_bearing" + ], + "value" : 15 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "FLASK", + "material" : "GLASS_GREEN", + "value" : 2 + } + ], + "job" : "MakeFlask", + "material" : "GLASS_GREEN" + } +] diff --git a/data/orders/military.json b/data/orders/military.json new file mode 100644 index 0000000000..e461f0d3d7 --- /dev/null +++ b/data/orders/military.json @@ -0,0 +1,4676 @@ +[ + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 0, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "SKIN_TANNED", + "value" : 10 + }, + { + "condition" : "AtMost", + "item_type" : "BACKPACK", + "value" : 10 + } + ], + "job" : "MakeBackpack", + "material_category" : + [ + "leather" + ] + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 1, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "SKIN_TANNED", + "value" : 10 + }, + { + "condition" : "AtMost", + "flags" : + [ + "leather" + ], + "item_type" : "FLASK", + "value" : 10 + } + ], + "job" : "MakeFlask", + "material_category" : + [ + "leather" + ] + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 2, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "SKIN_TANNED", + "value" : 10 + }, + { + "condition" : "AtMost", + "item_type" : "QUIVER", + "value" : 10 + } + ], + "job" : "MakeQuiver", + "material_category" : + [ + "leather" + ] + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 3, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "silk" + ], + "item_type" : "CLOTH", + "min_dimension" : 10000, + "value" : 10 + }, + { + "condition" : "AtMost", + "item_subtype" : "ITEM_ARMOR_CLOAK", + "item_type" : "ARMOR", + "value" : 10 + } + ], + "item_subtype" : "ITEM_ARMOR_CLOAK", + "job" : "MakeArmor", + "material_category" : + [ + "silk" + ] + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 4, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "WOOD", + "value" : 50 + }, + { + "condition" : "AtMost", + "item_subtype" : "ITEM_WEAPON_CROSSBOW", + "item_type" : "WEAPON", + "value" : 10 + } + ], + "item_subtype" : "ITEM_WEAPON_CROSSBOW", + "job" : "MakeWeapon", + "material_category" : + [ + "wood" + ] + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 5, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "WOOD", + "value" : 50 + }, + { + "condition" : "AtMost", + "item_subtype" : "ITEM_SHIELD_SHIELD", + "item_type" : "SHIELD", + "value" : 10 + } + ], + "item_subtype" : "ITEM_SHIELD_SHIELD", + "job" : "MakeShield", + "material_category" : + [ + "wood" + ] + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 6, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "SKIN_TANNED", + "value" : 25 + }, + { + "condition" : "AtMost", + "item_subtype" : "ITEM_ARMOR_LEATHER", + "item_type" : "ARMOR", + "value" : 10 + } + ], + "item_subtype" : "ITEM_ARMOR_LEATHER", + "job" : "MakeArmor", + "material_category" : + [ + "leather" + ] + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 7, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "SKIN_TANNED", + "value" : 25 + }, + { + "condition" : "AtMost", + "flags" : + [ + "leather" + ], + "item_subtype" : "ITEM_HELM_HELM", + "item_type" : "HELM", + "value" : 10 + } + ], + "item_subtype" : "ITEM_HELM_HELM", + "job" : "MakeHelm", + "material_category" : + [ + "leather" + ] + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 8, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "SKIN_TANNED", + "value" : 25 + }, + { + "condition" : "AtMost", + "flags" : + [ + "leather" + ], + "item_subtype" : "ITEM_SHOES_BOOTS", + "item_type" : "SHOES", + "value" : 20 + } + ], + "item_subtype" : "ITEM_SHOES_BOOTS", + "job" : "MakeShoes", + "material_category" : + [ + "leather" + ] + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 9, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "SKIN_TANNED", + "value" : 25 + }, + { + "condition" : "AtMost", + "flags" : + [ + "leather" + ], + "item_subtype" : "ITEM_PANTS_LEGGINGS", + "item_type" : "PANTS", + "value" : 10 + } + ], + "item_subtype" : "ITEM_PANTS_LEGGINGS", + "job" : "MakePants", + "material_category" : + [ + "leather" + ] + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 10, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "SKIN_TANNED", + "value" : 25 + }, + { + "condition" : "AtMost", + "flags" : + [ + "leather" + ], + "item_subtype" : "ITEM_GLOVES_GLOVES", + "item_type" : "GLOVES", + "value" : 20 + } + ], + "item_subtype" : "ITEM_GLOVES_GLOVES", + "job" : "MakeGloves", + "material_category" : + [ + "leather" + ] + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 11, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "unrotten", + "bone", + "body_part" + ], + "value" : 5 + }, + { + "condition" : "AtMost", + "flags" : + [ + "bone" + ], + "item_subtype" : "ITEM_AMMO_BOLTS", + "item_type" : "AMMO", + "value" : 1000 + } + ], + "item_subtype" : "ITEM_AMMO_BOLTS", + "job" : "MakeAmmo", + "material_category" : + [ + "bone" + ] + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 12, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "WOOD", + "value" : 150 + }, + { + "condition" : "AtMost", + "flags" : + [ + "bone" + ], + "item_subtype" : "ITEM_AMMO_BOLTS", + "item_type" : "AMMO", + "value" : 200 + }, + { + "condition" : "AtMost", + "flags" : + [ + "plant" + ], + "item_subtype" : "ITEM_AMMO_BOLTS", + "item_type" : "AMMO", + "value" : 1000 + } + ], + "item_subtype" : "ITEM_AMMO_BOLTS", + "job" : "MakeAmmo", + "material_category" : + [ + "wood" + ] + }, + { + "amount_left" : 4, + "amount_total" : 4, + "frequency" : "Daily", + "id" : 13, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BOULDER", + "material" : "INORGANIC:CASSITERITE", + "value" : 25 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "BAR", + "material" : "INORGANIC:TIN", + "value" : 20 + } + ], + "job" : "SmeltOre", + "material" : "INORGANIC:CASSITERITE" + }, + { + "amount_left" : 4, + "amount_total" : 4, + "frequency" : "Daily", + "id" : 14, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BOULDER", + "material" : "INORGANIC:HEMATITE", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 40 + } + ], + "job" : "SmeltOre", + "material" : "INORGANIC:HEMATITE" + }, + { + "amount_left" : 4, + "amount_total" : 4, + "frequency" : "Daily", + "id" : 15, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BOULDER", + "material" : "INORGANIC:HORN_SILVER", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "BAR", + "material" : "INORGANIC:SILVER", + "value" : 10 + } + ], + "job" : "SmeltOre", + "material" : "INORGANIC:HORN_SILVER" + }, + { + "amount_left" : 4, + "amount_total" : 4, + "frequency" : "Daily", + "id" : 16, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BOULDER", + "material" : "INORGANIC:LIMONITE", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 40 + } + ], + "job" : "SmeltOre", + "material" : "INORGANIC:LIMONITE" + }, + { + "amount_left" : 4, + "amount_total" : 4, + "frequency" : "Daily", + "id" : 17, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BOULDER", + "material" : "INORGANIC:NATIVE_COPPER", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "BAR", + "material" : "INORGANIC:COPPER", + "value" : 40 + } + ], + "job" : "SmeltOre", + "material" : "INORGANIC:NATIVE_COPPER" + }, + { + "amount_left" : 4, + "amount_total" : 4, + "frequency" : "Daily", + "id" : 18, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BOULDER", + "material" : "INORGANIC:NATIVE_SILVER", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "BAR", + "material" : "INORGANIC:SILVER", + "value" : 10 + } + ], + "job" : "SmeltOre", + "material" : "INORGANIC:NATIVE_SILVER" + }, + { + "amount_left" : 4, + "amount_total" : 4, + "frequency" : "Daily", + "id" : 19, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BOULDER", + "material" : "INORGANIC:MAGNETITE", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 40 + } + ], + "job" : "SmeltOre", + "material" : "INORGANIC:MAGNETITE" + }, + { + "amount_left" : 4, + "amount_total" : 4, + "frequency" : "Daily", + "id" : 20, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BOULDER", + "material" : "INORGANIC:MALACHITE", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "BAR", + "material" : "INORGANIC:COPPER", + "value" : 40 + } + ], + "job" : "SmeltOre", + "material" : "INORGANIC:MALACHITE" + }, + { + "amount_left" : 4, + "amount_total" : 4, + "frequency" : "Daily", + "id" : 21, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BOULDER", + "material" : "INORGANIC:TETRAHEDRITE", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "BAR", + "material" : "INORGANIC:COPPER", + "value" : 40 + } + ], + "job" : "SmeltOre", + "material" : "INORGANIC:TETRAHEDRITE" + }, + { + "amount_left" : 4, + "amount_total" : 4, + "frequency" : "Daily", + "id" : 22, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "bearing" : "TIN", + "condition" : "AtLeast", + "item_type" : "BOULDER", + "value" : 25 + }, + { + "bearing" : "COPPER", + "condition" : "AtLeast", + "item_type" : "BOULDER", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "BAR", + "material" : "INORGANIC:BRONZE", + "value" : 40 + } + ], + "job" : "CustomReaction", + "reaction" : "BRONZE_MAKING" + }, + { + "amount_left" : 4, + "amount_total" : 4, + "frequency" : "Daily", + "id" : 23, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:TIN", + "value" : 10 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:COPPER", + "value" : 10 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "BAR", + "material" : "INORGANIC:BRONZE", + "value" : 40 + }, + { + "bearing" : "TIN", + "condition" : "AtMost", + "item_type" : "BOULDER", + "value" : 25 + }, + { + "bearing" : "COPPER", + "condition" : "AtMost", + "item_type" : "BOULDER", + "value" : 5 + } + ], + "job" : "CustomReaction", + "reaction" : "BRONZE_MAKING2" + }, + { + "amount_left" : 4, + "amount_total" : 4, + "frequency" : "Daily", + "id" : 24, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 10 + }, + { + "condition" : "AtLeast", + "item_type" : "BOULDER", + "reaction_class" : "FLUX", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "BAR", + "material" : "INORGANIC:PIG_IRON", + "value" : 10 + } + ], + "job" : "CustomReaction", + "reaction" : "PIG_IRON_MAKING" + }, + { + "amount_left" : 4, + "amount_total" : 4, + "frequency" : "Daily", + "id" : 25, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:PIG_IRON", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BOULDER", + "reaction_class" : "FLUX", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 40 + } + ], + "job" : "CustomReaction", + "reaction" : "STEEL_MAKING" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 26, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:BRONZE", + "value" : 20 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_AMMO_BOLTS", + "item_type" : "AMMO", + "value" : 1000 + } + ], + "item_subtype" : "ITEM_AMMO_BOLTS", + "job" : "MakeAmmo", + "material" : "INORGANIC:BRONZE" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 27, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:BISMUTH_BRONZE", + "min_dimension" : 150, + "value" : 20 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_AMMO_BOLTS", + "item_type" : "AMMO", + "value" : 1000 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:BRONZE", + "value" : 20 + } + ], + "item_subtype" : "ITEM_AMMO_BOLTS", + "job" : "MakeAmmo", + "material" : "INORGANIC:BISMUTH_BRONZE" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 28, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:COPPER", + "value" : 20 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_AMMO_BOLTS", + "item_type" : "AMMO", + "value" : 1000 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:BRONZE", + "value" : 20 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:BISMUTH_BRONZE", + "value" : 20 + } + ], + "item_subtype" : "ITEM_AMMO_BOLTS", + "job" : "MakeAmmo", + "material" : "INORGANIC:COPPER" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 29, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "min_dimension" : 150, + "value" : 20 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_AMMO_BOLTS", + "item_type" : "AMMO", + "value" : 1000 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:BRONZE", + "value" : 20 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:BISMUTH_BRONZE", + "value" : 20 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:COPPER", + "value" : 20 + } + ], + "item_subtype" : "ITEM_AMMO_BOLTS", + "job" : "MakeAmmo", + "material" : "INORGANIC:IRON" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 30, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 20 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_subtype" : "ITEM_SHIELD_SHIELD", + "item_type" : "SHIELD", + "material" : "INORGANIC:STEEL", + "value" : 10 + } + ], + "item_subtype" : "ITEM_SHIELD_SHIELD", + "job" : "MakeShield", + "material" : "INORGANIC:STEEL" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 31, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 20 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_subtype" : "ITEM_ARMOR_MAIL_SHIRT", + "item_type" : "ARMOR", + "material" : "INORGANIC:STEEL", + "value" : 10 + } + ], + "item_subtype" : "ITEM_ARMOR_MAIL_SHIRT", + "job" : "MakeArmor", + "material" : "INORGANIC:STEEL" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 32, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 20 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_subtype" : "ITEM_HELM_HELM", + "item_type" : "HELM", + "material" : "INORGANIC:STEEL", + "value" : 10 + } + ], + "item_subtype" : "ITEM_HELM_HELM", + "job" : "MakeHelm", + "material" : "INORGANIC:STEEL" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 33, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 20 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_subtype" : "ITEM_SHOES_BOOTS", + "item_type" : "SHOES", + "material" : "INORGANIC:STEEL", + "value" : 20 + } + ], + "item_subtype" : "ITEM_SHOES_BOOTS", + "job" : "MakeShoes", + "material" : "INORGANIC:STEEL" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 34, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 20 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_subtype" : "ITEM_GLOVES_GAUNTLETS", + "item_type" : "GLOVES", + "material" : "INORGANIC:STEEL", + "value" : 20 + } + ], + "item_subtype" : "ITEM_GLOVES_GAUNTLETS", + "job" : "MakeGloves", + "material" : "INORGANIC:STEEL" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 35, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 20 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_subtype" : "ITEM_PANTS_GREAVES", + "item_type" : "PANTS", + "material" : "INORGANIC:STEEL", + "value" : 10 + }, + { + "condition" : "AtLeast", + "item_subtype" : "ITEM_ARMOR_MAIL_SHIRT", + "item_type" : "ARMOR", + "material" : "INORGANIC:STEEL", + "value" : 5 + } + ], + "item_subtype" : "ITEM_PANTS_GREAVES", + "job" : "MakePants", + "material" : "INORGANIC:STEEL" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 36, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 20 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_subtype" : "ITEM_ARMOR_BREASTPLATE", + "item_type" : "ARMOR", + "material" : "INORGANIC:STEEL", + "value" : 10 + }, + { + "condition" : "AtLeast", + "item_subtype" : "ITEM_ARMOR_MAIL_SHIRT", + "item_type" : "ARMOR", + "material" : "INORGANIC:STEEL", + "value" : 5 + } + ], + "item_subtype" : "ITEM_ARMOR_BREASTPLATE", + "job" : "MakeArmor", + "material" : "INORGANIC:STEEL" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 37, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 10 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_subtype" : "ITEM_WEAPON_MACE", + "item_type" : "WEAPON", + "material" : "INORGANIC:STEEL", + "value" : 10 + } + ], + "item_subtype" : "ITEM_WEAPON_MACE", + "job" : "MakeWeapon", + "material" : "INORGANIC:STEEL" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 38, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 10 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_subtype" : "ITEM_WEAPON_HAMMER_WAR", + "item_type" : "WEAPON", + "material" : "INORGANIC:STEEL", + "value" : 10 + } + ], + "item_subtype" : "ITEM_WEAPON_HAMMER_WAR", + "job" : "MakeWeapon", + "material" : "INORGANIC:STEEL" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 39, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 10 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_subtype" : "ITEM_WEAPON_SPEAR", + "item_type" : "WEAPON", + "material" : "INORGANIC:STEEL", + "value" : 10 + } + ], + "item_subtype" : "ITEM_WEAPON_SPEAR", + "job" : "MakeWeapon", + "material" : "INORGANIC:STEEL" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 40, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 10 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_subtype" : "ITEM_WEAPON_SWORD_SHORT", + "item_type" : "WEAPON", + "material" : "INORGANIC:STEEL", + "value" : 10 + } + ], + "item_subtype" : "ITEM_WEAPON_SWORD_SHORT", + "job" : "MakeWeapon", + "material" : "INORGANIC:STEEL" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 41, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 10 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_subtype" : "ITEM_WEAPON_AXE_BATTLE", + "item_type" : "WEAPON", + "material" : "INORGANIC:STEEL", + "value" : 10 + } + ], + "item_subtype" : "ITEM_WEAPON_AXE_BATTLE", + "job" : "MakeWeapon", + "material" : "INORGANIC:STEEL" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 42, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 30 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_subtype" : "ITEM_WEAPON_PICK", + "item_type" : "WEAPON", + "material" : "INORGANIC:STEEL", + "value" : 10 + } + ], + "item_subtype" : "ITEM_WEAPON_PICK", + "job" : "MakeWeapon", + "material" : "INORGANIC:STEEL" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 43, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 30 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_subtype" : "ITEM_WEAPON_CROSSBOW", + "item_type" : "WEAPON", + "material" : "INORGANIC:STEEL", + "value" : 10 + } + ], + "item_subtype" : "ITEM_WEAPON_CROSSBOW", + "job" : "MakeWeapon", + "material" : "INORGANIC:STEEL" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 44, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:SILVER", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "LessThan", + "item_type" : "BOULDER", + "reaction_class" : "FLUX", + "value" : 5 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_WEAPON_MACE", + "item_type" : "WEAPON", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 10 + } + ], + "item_subtype" : "ITEM_WEAPON_MACE", + "job" : "MakeWeapon", + "material" : "INORGANIC:SILVER" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 45, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:SILVER", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "LessThan", + "item_type" : "BOULDER", + "reaction_class" : "FLUX", + "value" : 5 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_WEAPON_HAMMER_WAR", + "item_type" : "WEAPON", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 10 + } + ], + "item_subtype" : "ITEM_WEAPON_HAMMER_WAR", + "job" : "MakeWeapon", + "material" : "INORGANIC:SILVER" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 46, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 20 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "LessThan", + "item_type" : "BOULDER", + "reaction_class" : "FLUX", + "value" : 5 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_SHIELD_SHIELD", + "item_type" : "SHIELD", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 20 + } + ], + "item_subtype" : "ITEM_SHIELD_SHIELD", + "job" : "MakeShield", + "material" : "INORGANIC:IRON" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 47, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 20 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "LessThan", + "item_type" : "BOULDER", + "reaction_class" : "FLUX", + "value" : 5 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_ARMOR_MAIL_SHIRT", + "item_type" : "ARMOR", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 20 + } + ], + "item_subtype" : "ITEM_ARMOR_MAIL_SHIRT", + "job" : "MakeArmor", + "material" : "INORGANIC:IRON" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 48, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 20 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "LessThan", + "item_type" : "BOULDER", + "reaction_class" : "FLUX", + "value" : 5 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_HELM_HELM", + "item_type" : "HELM", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 20 + } + ], + "item_subtype" : "ITEM_HELM_HELM", + "job" : "MakeHelm", + "material" : "INORGANIC:IRON" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 49, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 20 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "LessThan", + "item_type" : "BOULDER", + "reaction_class" : "FLUX", + "value" : 5 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_SHOES_BOOTS", + "item_type" : "SHOES", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 20 + } + ], + "item_subtype" : "ITEM_SHOES_BOOTS", + "job" : "MakeShoes", + "material" : "INORGANIC:IRON" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 50, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 20 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "LessThan", + "item_type" : "BOULDER", + "reaction_class" : "FLUX", + "value" : 5 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_GLOVES_GAUNTLETS", + "item_type" : "GLOVES", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 20 + } + ], + "item_subtype" : "ITEM_GLOVES_GAUNTLETS", + "job" : "MakeGloves", + "material" : "INORGANIC:IRON" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 51, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 20 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "LessThan", + "item_type" : "BOULDER", + "reaction_class" : "FLUX", + "value" : 5 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_PANTS_GREAVES", + "item_type" : "PANTS", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 20 + }, + { + "condition" : "AtLeast", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_ARMOR_MAIL_SHIRT", + "item_type" : "ARMOR", + "value" : 5 + } + ], + "item_subtype" : "ITEM_PANTS_GREAVES", + "job" : "MakePants", + "material" : "INORGANIC:IRON" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 52, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 20 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "LessThan", + "item_type" : "BOULDER", + "reaction_class" : "FLUX", + "value" : 5 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_ARMOR_BREASTPLATE", + "item_type" : "ARMOR", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 20 + }, + { + "condition" : "AtLeast", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_ARMOR_MAIL_SHIRT", + "item_type" : "ARMOR", + "value" : 5 + } + ], + "item_subtype" : "ITEM_ARMOR_BREASTPLATE", + "job" : "MakeArmor", + "material" : "INORGANIC:IRON" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 53, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 10 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "LessThan", + "item_type" : "BOULDER", + "reaction_class" : "FLUX", + "value" : 5 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:SILVER", + "value" : 5 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_WEAPON_MACE", + "item_type" : "WEAPON", + "value" : 10 + } + ], + "item_subtype" : "ITEM_WEAPON_MACE", + "job" : "MakeWeapon", + "material" : "INORGANIC:IRON" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 54, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 10 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "LessThan", + "item_type" : "BOULDER", + "reaction_class" : "FLUX", + "value" : 5 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:SILVER", + "value" : 5 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_WEAPON_HAMMER_WAR", + "item_type" : "WEAPON", + "value" : 10 + } + ], + "item_subtype" : "ITEM_WEAPON_HAMMER_WAR", + "job" : "MakeWeapon", + "material" : "INORGANIC:IRON" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 55, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 10 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "LessThan", + "item_type" : "BOULDER", + "reaction_class" : "FLUX", + "value" : 5 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_WEAPON_SPEAR", + "item_type" : "WEAPON", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 10 + } + ], + "item_subtype" : "ITEM_WEAPON_SPEAR", + "job" : "MakeWeapon", + "material" : "INORGANIC:IRON" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 56, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 10 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "LessThan", + "item_type" : "BOULDER", + "reaction_class" : "FLUX", + "value" : 5 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_WEAPON_SWORD_SHORT", + "item_type" : "WEAPON", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 10 + } + ], + "item_subtype" : "ITEM_WEAPON_SWORD_SHORT", + "job" : "MakeWeapon", + "material" : "INORGANIC:IRON" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 57, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 10 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "LessThan", + "item_type" : "BOULDER", + "reaction_class" : "FLUX", + "value" : 5 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_WEAPON_AXE_BATTLE", + "item_type" : "WEAPON", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 10 + } + ], + "item_subtype" : "ITEM_WEAPON_AXE_BATTLE", + "job" : "MakeWeapon", + "material" : "INORGANIC:IRON" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 58, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 30 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "LessThan", + "item_type" : "BOULDER", + "reaction_class" : "FLUX", + "value" : 5 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_WEAPON_PICK", + "item_type" : "WEAPON", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 30 + } + ], + "item_subtype" : "ITEM_WEAPON_PICK", + "job" : "MakeWeapon", + "material" : "INORGANIC:IRON" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 59, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 30 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "LessThan", + "item_type" : "BOULDER", + "reaction_class" : "FLUX", + "value" : 5 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 30 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_WEAPON_CROSSBOW", + "item_type" : "WEAPON", + "value" : 10 + } + ], + "item_subtype" : "ITEM_WEAPON_CROSSBOW", + "job" : "MakeWeapon", + "material" : "INORGANIC:IRON" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 74, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:BISMUTH_BRONZE", + "value" : 20 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_SHIELD_SHIELD", + "item_type" : "SHIELD", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 20 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 20 + } + ], + "item_subtype" : "ITEM_SHIELD_SHIELD", + "job" : "MakeShield", + "material" : "INORGANIC:BISMUTH_BRONZE" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 75, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:BISMUTH_BRONZE", + "value" : 20 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_ARMOR_MAIL_SHIRT", + "item_type" : "ARMOR", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 20 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 20 + } + ], + "item_subtype" : "ITEM_ARMOR_MAIL_SHIRT", + "job" : "MakeArmor", + "material" : "INORGANIC:BISMUTH_BRONZE" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 76, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:BISMUTH_BRONZE", + "value" : 20 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_HELM_HELM", + "item_type" : "HELM", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 20 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 20 + } + ], + "item_subtype" : "ITEM_HELM_HELM", + "job" : "MakeHelm", + "material" : "INORGANIC:BISMUTH_BRONZE" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 77, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:BISMUTH_BRONZE", + "value" : 20 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_SHOES_BOOTS", + "item_type" : "SHOES", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 20 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 20 + } + ], + "item_subtype" : "ITEM_SHOES_BOOTS", + "job" : "MakeShoes", + "material" : "INORGANIC:BISMUTH_BRONZE" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 78, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:BISMUTH_BRONZE", + "value" : 20 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_GLOVES_GAUNTLETS", + "item_type" : "GLOVES", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 20 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 20 + } + ], + "item_subtype" : "ITEM_GLOVES_GAUNTLETS", + "job" : "MakeGloves", + "material" : "INORGANIC:BISMUTH_BRONZE" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 79, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:BISMUTH_BRONZE", + "value" : 20 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_PANTS_GREAVES", + "item_type" : "PANTS", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 20 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 20 + }, + { + "condition" : "AtLeast", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_ARMOR_MAIL_SHIRT", + "item_type" : "ARMOR", + "value" : 5 + } + ], + "item_subtype" : "ITEM_PANTS_GREAVES", + "job" : "MakePants", + "material" : "INORGANIC:BISMUTH_BRONZE" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 80, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:BISMUTH_BRONZE", + "value" : 20 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_ARMOR_BREASTPLATE", + "item_type" : "ARMOR", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 20 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 20 + }, + { + "condition" : "AtLeast", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_ARMOR_MAIL_SHIRT", + "item_type" : "ARMOR", + "value" : 5 + } + ], + "item_subtype" : "ITEM_ARMOR_BREASTPLATE", + "job" : "MakeArmor", + "material" : "INORGANIC:BISMUTH_BRONZE" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 67, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:BISMUTH_BRONZE", + "min_dimension" : 150, + "value" : 10 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_WEAPON_MACE", + "item_type" : "WEAPON", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:SILVER", + "value" : 5 + } + ], + "item_subtype" : "ITEM_WEAPON_MACE", + "job" : "MakeWeapon", + "material" : "INORGANIC:BISMUTH_BRONZE" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 82, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:BISMUTH_BRONZE", + "value" : 10 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:SILVER", + "value" : 5 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_WEAPON_HAMMER_WAR", + "item_type" : "WEAPON", + "value" : 10 + } + ], + "item_subtype" : "ITEM_WEAPON_HAMMER_WAR", + "job" : "MakeWeapon", + "material" : "INORGANIC:BISMUTH_BRONZE" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 83, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:BISMUTH_BRONZE", + "value" : 10 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_WEAPON_SPEAR", + "item_type" : "WEAPON", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 10 + } + ], + "item_subtype" : "ITEM_WEAPON_SPEAR", + "job" : "MakeWeapon", + "material" : "INORGANIC:BISMUTH_BRONZE" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 84, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:BISMUTH_BRONZE", + "value" : 10 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_WEAPON_SWORD_SHORT", + "item_type" : "WEAPON", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 10 + } + ], + "item_subtype" : "ITEM_WEAPON_SWORD_SHORT", + "job" : "MakeWeapon", + "material" : "INORGANIC:BISMUTH_BRONZE" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 85, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:BISMUTH_BRONZE", + "value" : 10 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_WEAPON_AXE_BATTLE", + "item_type" : "WEAPON", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 10 + } + ], + "item_subtype" : "ITEM_WEAPON_AXE_BATTLE", + "job" : "MakeWeapon", + "material" : "INORGANIC:BISMUTH_BRONZE" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 86, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:BISMUTH_BRONZE", + "value" : 30 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_WEAPON_PICK", + "item_type" : "WEAPON", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 30 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 30 + } + ], + "item_subtype" : "ITEM_WEAPON_PICK", + "job" : "MakeWeapon", + "material" : "INORGANIC:BISMUTH_BRONZE" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 87, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:BISMUTH_BRONZE", + "value" : 30 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 30 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 30 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_WEAPON_CROSSBOW", + "item_type" : "WEAPON", + "value" : 10 + } + ], + "item_subtype" : "ITEM_WEAPON_CROSSBOW", + "job" : "MakeWeapon", + "material" : "INORGANIC:BISMUTH_BRONZE" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 74, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:BRONZE", + "value" : 20 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_SHIELD_SHIELD", + "item_type" : "SHIELD", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 20 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 20 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:BISMUTH_BRONZE", + "value" : 20 + } + ], + "item_subtype" : "ITEM_SHIELD_SHIELD", + "job" : "MakeShield", + "material" : "INORGANIC:BRONZE" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 75, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:BRONZE", + "value" : 20 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_ARMOR_MAIL_SHIRT", + "item_type" : "ARMOR", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 20 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 20 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:BISMUTH_BRONZE", + "value" : 20 + } + ], + "item_subtype" : "ITEM_ARMOR_MAIL_SHIRT", + "job" : "MakeArmor", + "material" : "INORGANIC:BRONZE" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 76, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:BRONZE", + "value" : 20 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_HELM_HELM", + "item_type" : "HELM", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 20 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 20 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:BISMUTH_BRONZE", + "value" : 20 + } + ], + "item_subtype" : "ITEM_HELM_HELM", + "job" : "MakeHelm", + "material" : "INORGANIC:BRONZE" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 77, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:BRONZE", + "value" : 20 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_SHOES_BOOTS", + "item_type" : "SHOES", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 20 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 20 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:BISMUTH_BRONZE", + "value" : 20 + } + ], + "item_subtype" : "ITEM_SHOES_BOOTS", + "job" : "MakeShoes", + "material" : "INORGANIC:BRONZE" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 78, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:BRONZE", + "value" : 20 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_GLOVES_GAUNTLETS", + "item_type" : "GLOVES", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 20 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 20 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:BISMUTH_BRONZE", + "value" : 20 + } + ], + "item_subtype" : "ITEM_GLOVES_GAUNTLETS", + "job" : "MakeGloves", + "material" : "INORGANIC:BRONZE" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 79, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:BRONZE", + "value" : 20 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_PANTS_GREAVES", + "item_type" : "PANTS", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 20 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 20 + }, + { + "condition" : "AtLeast", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_ARMOR_MAIL_SHIRT", + "item_type" : "ARMOR", + "value" : 5 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:BISMUTH_BRONZE", + "value" : 20 + } + ], + "item_subtype" : "ITEM_PANTS_GREAVES", + "job" : "MakePants", + "material" : "INORGANIC:BRONZE" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 80, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:BRONZE", + "value" : 20 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_ARMOR_BREASTPLATE", + "item_type" : "ARMOR", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 20 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 20 + }, + { + "condition" : "AtLeast", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_ARMOR_MAIL_SHIRT", + "item_type" : "ARMOR", + "value" : 5 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:BISMUTH_BRONZE", + "value" : 20 + } + ], + "item_subtype" : "ITEM_ARMOR_BREASTPLATE", + "job" : "MakeArmor", + "material" : "INORGANIC:BRONZE" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 81, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:BRONZE", + "value" : 10 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:SILVER", + "value" : 5 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_WEAPON_MACE", + "item_type" : "WEAPON", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:BISMUTH_BRONZE", + "value" : 10 + } + ], + "item_subtype" : "ITEM_WEAPON_MACE", + "job" : "MakeWeapon", + "material" : "INORGANIC:BRONZE" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 82, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:BRONZE", + "value" : 10 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:SILVER", + "value" : 5 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_WEAPON_HAMMER_WAR", + "item_type" : "WEAPON", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:BISMUTH_BRONZE", + "value" : 10 + } + ], + "item_subtype" : "ITEM_WEAPON_HAMMER_WAR", + "job" : "MakeWeapon", + "material" : "INORGANIC:BRONZE" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 83, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:BRONZE", + "value" : 10 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_WEAPON_SPEAR", + "item_type" : "WEAPON", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:BISMUTH_BRONZE", + "value" : 10 + } + ], + "item_subtype" : "ITEM_WEAPON_SPEAR", + "job" : "MakeWeapon", + "material" : "INORGANIC:BRONZE" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 84, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:BRONZE", + "value" : 10 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_WEAPON_SWORD_SHORT", + "item_type" : "WEAPON", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:BISMUTH_BRONZE", + "value" : 10 + } + ], + "item_subtype" : "ITEM_WEAPON_SWORD_SHORT", + "job" : "MakeWeapon", + "material" : "INORGANIC:BRONZE" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 85, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:BRONZE", + "value" : 10 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_WEAPON_AXE_BATTLE", + "item_type" : "WEAPON", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:BISMUTH_BRONZE", + "value" : 10 + } + ], + "item_subtype" : "ITEM_WEAPON_AXE_BATTLE", + "job" : "MakeWeapon", + "material" : "INORGANIC:BRONZE" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 86, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:BRONZE", + "value" : 30 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_WEAPON_PICK", + "item_type" : "WEAPON", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 30 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 30 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:BISMUTH_BRONZE", + "value" : 30 + } + ], + "item_subtype" : "ITEM_WEAPON_PICK", + "job" : "MakeWeapon", + "material" : "INORGANIC:BRONZE" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 87, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:BRONZE", + "value" : 30 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 30 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 30 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_WEAPON_CROSSBOW", + "item_type" : "WEAPON", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:BISMUTH_BRONZE", + "value" : 30 + } + ], + "item_subtype" : "ITEM_WEAPON_CROSSBOW", + "job" : "MakeWeapon", + "material" : "INORGANIC:BRONZE" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 88, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:COPPER", + "value" : 20 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_SHIELD_SHIELD", + "item_type" : "SHIELD", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:BRONZE", + "value" : 20 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 20 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 20 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:BISMUTH_BRONZE", + "value" : 20 + } + ], + "item_subtype" : "ITEM_SHIELD_SHIELD", + "job" : "MakeShield", + "material" : "INORGANIC:COPPER" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 89, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:COPPER", + "value" : 20 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_ARMOR_MAIL_SHIRT", + "item_type" : "ARMOR", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:BRONZE", + "value" : 20 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 20 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 20 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:BISMUTH_BRONZE", + "value" : 20 + } + ], + "item_subtype" : "ITEM_ARMOR_MAIL_SHIRT", + "job" : "MakeArmor", + "material" : "INORGANIC:COPPER" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 90, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:COPPER", + "value" : 20 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_HELM_HELM", + "item_type" : "HELM", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:BRONZE", + "value" : 20 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 20 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 20 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:BISMUTH_BRONZE", + "value" : 20 + } + ], + "item_subtype" : "ITEM_HELM_HELM", + "job" : "MakeHelm", + "material" : "INORGANIC:COPPER" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 91, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:COPPER", + "value" : 20 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_SHOES_BOOTS", + "item_type" : "SHOES", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:BRONZE", + "value" : 20 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 20 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 20 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:BISMUTH_BRONZE", + "value" : 20 + } + ], + "item_subtype" : "ITEM_SHOES_BOOTS", + "job" : "MakeShoes", + "material" : "INORGANIC:COPPER" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 92, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:COPPER", + "value" : 20 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_GLOVES_GAUNTLETS", + "item_type" : "GLOVES", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:BRONZE", + "value" : 20 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 20 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 20 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:BISMUTH_BRONZE", + "value" : 20 + } + ], + "item_subtype" : "ITEM_GLOVES_GAUNTLETS", + "job" : "MakeGloves", + "material" : "INORGANIC:COPPER" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 93, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:COPPER", + "value" : 20 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_PANTS_GREAVES", + "item_type" : "PANTS", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:BRONZE", + "value" : 20 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 20 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 20 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:BISMUTH_BRONZE", + "value" : 20 + }, + { + "condition" : "AtLeast", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_ARMOR_MAIL_SHIRT", + "item_type" : "ARMOR", + "value" : 5 + } + ], + "item_subtype" : "ITEM_PANTS_GREAVES", + "job" : "MakePants", + "material" : "INORGANIC:COPPER" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 94, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:COPPER", + "value" : 20 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_ARMOR_BREASTPLATE", + "item_type" : "ARMOR", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:BRONZE", + "value" : 20 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 20 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 20 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:BISMUTH_BRONZE", + "value" : 20 + }, + { + "condition" : "AtLeast", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_ARMOR_MAIL_SHIRT", + "item_type" : "ARMOR", + "value" : 5 + } + ], + "item_subtype" : "ITEM_ARMOR_BREASTPLATE", + "job" : "MakeArmor", + "material" : "INORGANIC:COPPER" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 95, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:COPPER", + "value" : 10 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:BRONZE", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:SILVER", + "value" : 5 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_WEAPON_MACE", + "item_type" : "WEAPON", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:BISMUTH_BRONZE", + "value" : 10 + } + ], + "item_subtype" : "ITEM_WEAPON_MACE", + "job" : "MakeWeapon", + "material" : "INORGANIC:COPPER" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 96, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:COPPER", + "value" : 10 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:BRONZE", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:SILVER", + "value" : 5 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:BISMUTH_BRONZE", + "value" : 10 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_WEAPON_HAMMER_WAR", + "item_type" : "WEAPON", + "value" : 10 + } + ], + "item_subtype" : "ITEM_WEAPON_HAMMER_WAR", + "job" : "MakeWeapon", + "material" : "INORGANIC:COPPER" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 97, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:COPPER", + "value" : 10 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_WEAPON_SPEAR", + "item_type" : "WEAPON", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:BRONZE", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:BISMUTH_BRONZE", + "value" : 10 + } + ], + "item_subtype" : "ITEM_WEAPON_SPEAR", + "job" : "MakeWeapon", + "material" : "INORGANIC:COPPER" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 98, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:COPPER", + "value" : 10 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_WEAPON_SWORD_SHORT", + "item_type" : "WEAPON", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:BRONZE", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:BISMUTH_BRONZE", + "value" : 10 + } + ], + "item_subtype" : "ITEM_WEAPON_SWORD_SHORT", + "job" : "MakeWeapon", + "material" : "INORGANIC:COPPER" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 99, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:COPPER", + "value" : 10 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_WEAPON_AXE_BATTLE", + "item_type" : "WEAPON", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:BRONZE", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:BISMUTH_BRONZE", + "value" : 10 + } + ], + "item_subtype" : "ITEM_WEAPON_AXE_BATTLE", + "job" : "MakeWeapon", + "material" : "INORGANIC:COPPER" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 100, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:COPPER", + "value" : 10 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_WEAPON_PICK", + "item_type" : "WEAPON", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:BRONZE", + "value" : 30 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 30 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 30 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:BISMUTH_BRONZE", + "value" : 30 + } + ], + "item_subtype" : "ITEM_WEAPON_PICK", + "job" : "MakeWeapon", + "material" : "INORGANIC:COPPER" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 101, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:COPPER", + "value" : 30 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:BRONZE", + "value" : 30 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 30 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 30 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_WEAPON_CROSSBOW", + "item_type" : "WEAPON", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:BISMUTH_BRONZE", + "value" : 30 + } + ], + "item_subtype" : "ITEM_WEAPON_CROSSBOW", + "job" : "MakeWeapon", + "material" : "INORGANIC:COPPER" + } +] diff --git a/data/orders/rockstock.json b/data/orders/rockstock.json new file mode 100644 index 0000000000..db469ba398 --- /dev/null +++ b/data/orders/rockstock.json @@ -0,0 +1,502 @@ +[ + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 0, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "non_economic", + "hard" + ], + "item_type" : "BOULDER", + "material" : "INORGANIC", + "value" : 50 + }, + { + "condition" : "AtMost", + "item_type" : "ARMORSTAND", + "value" : 2 + } + ], + "job" : "ConstructArmorStand", + "material" : "INORGANIC" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 1, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "non_economic", + "hard" + ], + "item_type" : "BOULDER", + "material" : "INORGANIC", + "value" : 50 + }, + { + "condition" : "AtMost", + "item_type" : "BLOCKS", + "value" : 20 + } + ], + "job" : "ConstructBlocks", + "material" : "INORGANIC" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 2, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "non_economic", + "hard" + ], + "item_type" : "BOULDER", + "material" : "INORGANIC", + "value" : 50 + }, + { + "condition" : "AtMost", + "item_type" : "CABINET", + "value" : 2 + } + ], + "job" : "ConstructCabinet", + "material" : "INORGANIC" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 3, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "non_economic", + "hard" + ], + "item_type" : "BOULDER", + "material" : "INORGANIC", + "value" : 50 + }, + { + "condition" : "AtMost", + "item_type" : "BOX", + "material" : "INORGANIC", + "value" : 2 + } + ], + "job" : "ConstructChest", + "material" : "INORGANIC" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 4, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "non_economic", + "hard" + ], + "item_type" : "BOULDER", + "material" : "INORGANIC", + "value" : 50 + }, + { + "condition" : "AtMost", + "item_type" : "COFFIN", + "value" : 2 + } + ], + "job" : "ConstructCoffin", + "material" : "INORGANIC" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 5, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "non_economic", + "hard" + ], + "item_type" : "BOULDER", + "material" : "INORGANIC", + "value" : 50 + }, + { + "condition" : "AtMost", + "item_type" : "DOOR", + "value" : 2 + } + ], + "job" : "ConstructDoor", + "material" : "INORGANIC" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 6, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "non_economic", + "hard" + ], + "item_type" : "BOULDER", + "material" : "INORGANIC", + "value" : 50 + }, + { + "condition" : "AtMost", + "item_type" : "FLOODGATE", + "value" : 2 + } + ], + "job" : "ConstructFloodgate", + "material" : "INORGANIC" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 7, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "non_economic", + "hard" + ], + "item_type" : "BOULDER", + "material" : "INORGANIC", + "value" : 50 + }, + { + "condition" : "AtMost", + "item_type" : "GRATE", + "value" : 2 + } + ], + "job" : "ConstructGrate", + "material" : "INORGANIC" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 8, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "non_economic", + "hard" + ], + "item_type" : "BOULDER", + "material" : "INORGANIC", + "value" : 50 + }, + { + "condition" : "AtMost", + "item_type" : "HATCH_COVER", + "value" : 2 + } + ], + "job" : "ConstructHatchCover", + "material" : "INORGANIC" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 9, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "non_economic", + "hard" + ], + "item_type" : "BOULDER", + "material" : "INORGANIC", + "value" : 50 + }, + { + "condition" : "AtMost", + "item_type" : "SLAB", + "value" : 2 + } + ], + "job" : "ConstructSlab", + "material" : "INORGANIC" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 10, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "non_economic", + "hard" + ], + "item_type" : "BOULDER", + "material" : "INORGANIC", + "value" : 50 + }, + { + "condition" : "AtMost", + "item_type" : "STATUE", + "value" : 2 + } + ], + "job" : "ConstructStatue", + "material" : "INORGANIC" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 11, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "non_economic", + "hard" + ], + "item_type" : "BOULDER", + "material" : "INORGANIC", + "value" : 50 + }, + { + "condition" : "AtMost", + "item_type" : "TABLE", + "value" : 2 + } + ], + "job" : "ConstructTable", + "material" : "INORGANIC" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 12, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "non_economic", + "hard" + ], + "item_type" : "BOULDER", + "material" : "INORGANIC", + "value" : 50 + }, + { + "condition" : "AtMost", + "item_type" : "CHAIR", + "value" : 2 + } + ], + "job" : "ConstructThrone", + "material" : "INORGANIC" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 13, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "non_economic", + "hard" + ], + "item_type" : "BOULDER", + "material" : "INORGANIC", + "value" : 50 + }, + { + "condition" : "AtMost", + "item_type" : "WEAPONRACK", + "value" : 2 + } + ], + "job" : "ConstructWeaponRack", + "material" : "INORGANIC" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 14, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "non_economic", + "hard" + ], + "item_type" : "BOULDER", + "material" : "INORGANIC", + "value" : 50 + }, + { + "condition" : "AtMost", + "item_subtype" : "ITEM_TOOL_ALTAR", + "item_type" : "TOOL", + "value" : 2 + } + ], + "item_subtype" : "ITEM_TOOL_ALTAR", + "job" : "MakeTool", + "material" : "INORGANIC" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 15, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "non_economic", + "hard" + ], + "item_type" : "BOULDER", + "material" : "INORGANIC", + "value" : 50 + }, + { + "condition" : "AtMost", + "item_subtype" : "ITEM_TOOL_BOOKCASE", + "item_type" : "TOOL", + "value" : 2 + } + ], + "item_subtype" : "ITEM_TOOL_BOOKCASE", + "job" : "MakeTool", + "material" : "INORGANIC" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 16, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "flags" : + [ + "non_economic", + "hard" + ], + "item_type" : "BOULDER", + "material" : "INORGANIC", + "value" : 50 + }, + { + "condition" : "AtMost", + "item_subtype" : "ITEM_TOOL_PEDESTAL", + "item_type" : "TOOL", + "value" : 2 + } + ], + "item_subtype" : "ITEM_TOOL_PEDESTAL", + "job" : "MakeTool", + "material" : "INORGANIC" + } +] diff --git a/data/orders/smelting.json b/data/orders/smelting.json new file mode 100644 index 0000000000..781a52100d --- /dev/null +++ b/data/orders/smelting.json @@ -0,0 +1,1095 @@ +[ + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 0, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BOULDER", + "material" : "INORGANIC:BISMUTHINITE", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "BAR", + "material" : "INORGANIC:BISMUTH", + "value" : 10 + } + ], + "job" : "SmeltOre", + "material" : "INORGANIC:BISMUTHINITE" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 1, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BOULDER", + "material" : "INORGANIC:CASSITERITE", + "value" : 25 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "BAR", + "material" : "INORGANIC:TIN", + "value" : 10 + } + ], + "job" : "SmeltOre", + "material" : "INORGANIC:CASSITERITE" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 2, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BOULDER", + "material" : "INORGANIC:GALENA", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "BAR", + "material" : "INORGANIC:LEAD", + "value" : 10 + } + ], + "job" : "SmeltOre", + "material" : "INORGANIC:GALENA" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 3, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BOULDER", + "material" : "INORGANIC:GARNIERITE", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "BAR", + "material" : "INORGANIC:NICKEL", + "value" : 10 + } + ], + "job" : "SmeltOre", + "material" : "INORGANIC:GARNIERITE" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 4, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BOULDER", + "material" : "INORGANIC:HEMATITE", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 10 + } + ], + "job" : "SmeltOre", + "material" : "INORGANIC:HEMATITE" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 5, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BOULDER", + "material" : "INORGANIC:HORN_SILVER", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "BAR", + "material" : "INORGANIC:SILVER", + "value" : 10 + } + ], + "job" : "SmeltOre", + "material" : "INORGANIC:HORN_SILVER" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 6, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BOULDER", + "material" : "INORGANIC:LIMONITE", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 10 + } + ], + "job" : "SmeltOre", + "material" : "INORGANIC:LIMONITE" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 7, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BOULDER", + "material" : "INORGANIC:MAGNETITE", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 10 + } + ], + "job" : "SmeltOre", + "material" : "INORGANIC:MAGNETITE" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 8, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BOULDER", + "material" : "INORGANIC:MALACHITE", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "BAR", + "material" : "INORGANIC:COPPER", + "value" : 10 + } + ], + "job" : "SmeltOre", + "material" : "INORGANIC:MALACHITE" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 9, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BOULDER", + "material" : "INORGANIC:NATIVE_ALUMINUM", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "BAR", + "material" : "INORGANIC:ALUMINUM", + "value" : 10 + } + ], + "job" : "SmeltOre", + "material" : "INORGANIC:NATIVE_ALUMINUM" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 10, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BOULDER", + "material" : "INORGANIC:NATIVE_COPPER", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "BAR", + "material" : "INORGANIC:COPPER", + "value" : 10 + } + ], + "job" : "SmeltOre", + "material" : "INORGANIC:NATIVE_COPPER" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 11, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BOULDER", + "material" : "INORGANIC:NATIVE_GOLD", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "BAR", + "material" : "INORGANIC:GOLD", + "value" : 10 + } + ], + "job" : "SmeltOre", + "material" : "INORGANIC:NATIVE_GOLD" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 12, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BOULDER", + "material" : "INORGANIC:NATIVE_SILVER", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "BAR", + "material" : "INORGANIC:SILVER", + "value" : 10 + } + ], + "job" : "SmeltOre", + "material" : "INORGANIC:NATIVE_SILVER" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 13, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BOULDER", + "material" : "INORGANIC:NATIVE_PLATINUM", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "BAR", + "material" : "INORGANIC:PLATINUM", + "value" : 10 + } + ], + "job" : "SmeltOre", + "material" : "INORGANIC:NATIVE_PLATINUM" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 14, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BOULDER", + "material" : "INORGANIC:SPHALERITE", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "BAR", + "material" : "INORGANIC:ZINC", + "value" : 10 + } + ], + "job" : "SmeltOre", + "material" : "INORGANIC:SPHALERITE" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 15, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BOULDER", + "material" : "INORGANIC:TETRAHEDRITE", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "BAR", + "material" : "INORGANIC:COPPER", + "value" : 10 + } + ], + "job" : "SmeltOre", + "material" : "INORGANIC:TETRAHEDRITE" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 16, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "bearing" : "SILVER", + "condition" : "AtLeast", + "item_type" : "BOULDER", + "value" : 5 + }, + { + "bearing" : "COPPER", + "condition" : "AtLeast", + "item_type" : "BOULDER", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "BAR", + "material" : "INORGANIC:BILLON", + "value" : 10 + } + ], + "job" : "CustomReaction", + "reaction" : "BILLON_MAKING" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 17, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:TIN", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:COPPER", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:BISMUTH", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "BAR", + "material" : "INORGANIC:BISMUTH_BRONZE", + "value" : 10 + } + ], + "job" : "CustomReaction", + "reaction" : "BISMUTH_BRONZE_MAKING" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 18, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:COPPER", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:SILVER", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:GOLD", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "BAR", + "material" : "INORGANIC:BLACK_BRONZE", + "value" : 10 + } + ], + "job" : "CustomReaction", + "reaction" : "BLACK_BRONZE_MAKING" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 19, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "bearing" : "ZINC", + "condition" : "AtLeast", + "item_type" : "BOULDER", + "value" : 5 + }, + { + "bearing" : "COPPER", + "condition" : "AtLeast", + "item_type" : "BOULDER", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "BAR", + "material" : "INORGANIC:BRASS", + "value" : 10 + } + ], + "job" : "CustomReaction", + "reaction" : "BRASS_MAKING" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 20, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "bearing" : "TIN", + "condition" : "AtLeast", + "item_type" : "BOULDER", + "value" : 25 + }, + { + "bearing" : "COPPER", + "condition" : "AtLeast", + "item_type" : "BOULDER", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "BAR", + "material" : "INORGANIC:BRONZE", + "value" : 10 + } + ], + "job" : "CustomReaction", + "reaction" : "BRONZE_MAKING" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 21, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:TIN", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:COPPER", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "BAR", + "material" : "INORGANIC:BRONZE", + "value" : 10 + }, + { + "bearing" : "TIN", + "condition" : "AtMost", + "item_type" : "BOULDER", + "value" : 25 + }, + { + "bearing" : "COPPER", + "condition" : "AtMost", + "item_type" : "BOULDER", + "value" : 5 + } + ], + "job" : "CustomReaction", + "reaction" : "BRONZE_MAKING2" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 22, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "bearing" : "SILVER", + "condition" : "AtLeast", + "item_type" : "BOULDER", + "value" : 5 + }, + { + "bearing" : "GOLD", + "condition" : "AtLeast", + "item_type" : "BOULDER", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "BAR", + "material" : "INORGANIC:ELECTRUM", + "value" : 10 + } + ], + "job" : "CustomReaction", + "reaction" : "ELECTRUM_MAKING" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 23, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "bearing" : "TIN", + "condition" : "AtLeast", + "item_type" : "BOULDER", + "value" : 25 + }, + { + "bearing" : "COPPER", + "condition" : "AtLeast", + "item_type" : "BOULDER", + "value" : 25 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "BAR", + "material" : "INORGANIC:PEWTER_FINE", + "value" : 10 + } + ], + "job" : "CustomReaction", + "reaction" : "PEWTER_FINE_MAKING" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 24, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:TIN", + "value" : 25 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:COPPER", + "value" : 25 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:LEAD", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "BAR", + "material" : "INORGANIC:PEWTER_LAY", + "value" : 10 + } + ], + "job" : "CustomReaction", + "reaction" : "PEWTER_LAY_MAKING" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 25, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:NICKEL", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:COPPER", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:ZINC", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "BAR", + "material" : "INORGANIC:NICKEL_SILVER", + "value" : 10 + } + ], + "job" : "CustomReaction", + "reaction" : "NICKEL_SILVER_MAKING" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 26, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BOULDER", + "reaction_class" : "FLUX", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "BAR", + "material" : "INORGANIC:PIG_IRON", + "value" : 10 + } + ], + "job" : "CustomReaction", + "reaction" : "PIG_IRON_MAKING" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 27, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:GOLD", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:COPPER", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "BAR", + "material" : "INORGANIC:ROSE_GOLD", + "value" : 10 + } + ], + "job" : "CustomReaction", + "reaction" : "ROSE_GOLD_MAKING" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 28, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:IRON", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:PIG_IRON", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BOULDER", + "reaction_class" : "FLUX", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 10 + } + ], + "job" : "CustomReaction", + "reaction" : "STEEL_MAKING" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 29, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:SILVER", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:COPPER", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "BAR", + "material" : "INORGANIC:STERLING_SILVER", + "value" : 10 + } + ], + "job" : "CustomReaction", + "reaction" : "STERLING_SILVER_MAKING" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 30, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "bearing" : "TIN", + "condition" : "AtLeast", + "item_type" : "BOULDER", + "value" : 25 + }, + { + "bearing" : "COPPER", + "condition" : "AtLeast", + "item_type" : "BOULDER", + "value" : 25 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "AtMost", + "item_type" : "BAR", + "material" : "INORGANIC:PEWTER_TRIFLE", + "value" : 10 + } + ], + "job" : "CustomReaction", + "reaction" : "PEWTER_TRIFLE_MAKING" + } +] diff --git a/data/patches/README.md b/data/patches/README.md new file mode 100644 index 0000000000..599bbf47fb --- /dev/null +++ b/data/patches/README.md @@ -0,0 +1,13 @@ +Place IDA-exported `.dif` files for use by `binpatch` in subdirectories of this +directory. Each `.dif` file must be in a subdirectory named after the full +symbol table version string. For example, for DF version 51.05, you would use +these subdirectories: + +- "v0.51.05 linux64 CLASSIC" +- "v0.51.05 linux64 ITCH" +- "v0.51.05 linux64 STEAM" +- "v0.51.05 win64 CLASSIC" +- "v0.51.05 win64 ITCH" +- "v0.51.05 win64 STEAM" + +See https://docs.dfhack.org/en/stable/docs/dev/Binpatches.html for more details. diff --git a/data/professions/Chef b/data/professions/Chef new file mode 100644 index 0000000000..2dd8d8508f --- /dev/null +++ b/data/professions/Chef @@ -0,0 +1,19 @@ +NAME library/Chef +BUTCHER +TANNER +COOK +HAUL_STONE +HAUL_WOOD +HAUL_ITEM +HAUL_BODY +HAUL_FOOD +HAUL_REFUSE +HAUL_FURNITURE +HAUL_ANIMALS +HANDLE_VEHICLES +HAUL_TRADE +HAUL_WATER +CLEAN +PULL_LEVER +BUILD_ROAD +BUILD_CONSTRUCTION diff --git a/data/professions/Craftsdwarf b/data/professions/Craftsdwarf new file mode 100644 index 0000000000..5b9d03ca84 --- /dev/null +++ b/data/professions/Craftsdwarf @@ -0,0 +1,26 @@ +NAME library/Craftsdwarf +WOOD_CRAFT +STONE_CRAFT +BONE_CARVE +GLASSMAKER +EXTRACT_STRAND +POTTERY +GLAZING +WAX_WORKING +PAPERMAKING +BOOKBINDING +HAUL_STONE +HAUL_WOOD +HAUL_ITEM +HAUL_BODY +HAUL_FOOD +HAUL_REFUSE +HAUL_FURNITURE +HAUL_ANIMALS +HANDLE_VEHICLES +HAUL_TRADE +HAUL_WATER +CLEAN +PULL_LEVER +BUILD_ROAD +BUILD_CONSTRUCTION diff --git a/data/professions/Doctor b/data/professions/Doctor new file mode 100644 index 0000000000..b15ff96b22 --- /dev/null +++ b/data/professions/Doctor @@ -0,0 +1,23 @@ +NAME library/Doctor +ANIMALCARE +DIAGNOSE +SURGERY +BONE_SETTING +SUTURING +DRESSING_WOUNDS +FEED_WATER_CIVILIANS +HAUL_STONE +HAUL_WOOD +HAUL_ITEM +HAUL_BODY +HAUL_FOOD +HAUL_REFUSE +HAUL_FURNITURE +HAUL_ANIMALS +HANDLE_VEHICLES +HAUL_TRADE +HAUL_WATER +CLEAN +PULL_LEVER +BUILD_ROAD +BUILD_CONSTRUCTION diff --git a/data/professions/Farmer b/data/professions/Farmer new file mode 100644 index 0000000000..0b2801f4c2 --- /dev/null +++ b/data/professions/Farmer @@ -0,0 +1,13 @@ +NAME library/Farmer +PLANT +MILLER +BREWER +PROCESS_PLANT +MAKE_CHEESE +MILK +SHEARER +SPINNER +PRESSING +GELD +HAUL_FOOD +ALCHEMIST diff --git a/data/professions/Fisherdwarf b/data/professions/Fisherdwarf new file mode 100644 index 0000000000..6c2106e6a2 --- /dev/null +++ b/data/professions/Fisherdwarf @@ -0,0 +1,19 @@ +NAME library/Fisherdwarf +FISH +CLEAN_FISH +DISSECT_FISH +HAUL_STONE +HAUL_WOOD +HAUL_ITEM +HAUL_BODY +HAUL_FOOD +HAUL_REFUSE +HAUL_FURNITURE +HAUL_ANIMALS +HANDLE_VEHICLES +HAUL_TRADE +HAUL_WATER +CLEAN +PULL_LEVER +BUILD_ROAD +BUILD_CONSTRUCTION diff --git a/data/professions/Hauler b/data/professions/Hauler new file mode 100644 index 0000000000..36e7f400ab --- /dev/null +++ b/data/professions/Hauler @@ -0,0 +1,21 @@ +NAME library/Hauler +FEED_WATER_CIVILIANS +SIEGEOPERATE +MECHANIC +OPERATE_PUMP +HAUL_STONE +HAUL_WOOD +HAUL_ITEM +HAUL_BODY +HAUL_FOOD +HAUL_REFUSE +HAUL_FURNITURE +HAUL_ANIMALS +HANDLE_VEHICLES +HAUL_TRADE +HAUL_WATER +ARCHITECT +CLEAN +PULL_LEVER +BUILD_ROAD +BUILD_CONSTRUCTION diff --git a/data/professions/Laborer b/data/professions/Laborer new file mode 100644 index 0000000000..d9b9e7f498 --- /dev/null +++ b/data/professions/Laborer @@ -0,0 +1,21 @@ +NAME library/Laborer +SOAP_MAKER +BURN_WOOD +POTASH_MAKING +LYE_MAKING +SMELT +HAUL_STONE +HAUL_WOOD +HAUL_ITEM +HAUL_BODY +HAUL_FOOD +HAUL_REFUSE +HAUL_FURNITURE +HAUL_ANIMALS +HANDLE_VEHICLES +HAUL_TRADE +HAUL_WATER +CLEAN +PULL_LEVER +BUILD_ROAD +BUILD_CONSTRUCTION diff --git a/data/professions/Marksdwarf b/data/professions/Marksdwarf new file mode 100644 index 0000000000..1c9153f02f --- /dev/null +++ b/data/professions/Marksdwarf @@ -0,0 +1,17 @@ +NAME library/Marksdwarf +MECHANIC +HAUL_STONE +HAUL_WOOD +HAUL_ITEM +HAUL_BODY +HAUL_FOOD +HAUL_REFUSE +HAUL_FURNITURE +HAUL_ANIMALS +HANDLE_VEHICLES +HAUL_TRADE +HAUL_WATER +CLEAN +PULL_LEVER +BUILD_ROAD +BUILD_CONSTRUCTION diff --git a/data/professions/Mason b/data/professions/Mason new file mode 100644 index 0000000000..cd01d9a443 --- /dev/null +++ b/data/professions/Mason @@ -0,0 +1,19 @@ +NAME library/Mason +MASON +CUT_GEM +ENCRUST_GEM +HAUL_STONE +HAUL_WOOD +HAUL_ITEM +HAUL_BODY +HAUL_FOOD +HAUL_REFUSE +HAUL_FURNITURE +HAUL_ANIMALS +HANDLE_VEHICLES +HAUL_TRADE +HAUL_WATER +CLEAN +PULL_LEVER +BUILD_ROAD +BUILD_CONSTRUCTION diff --git a/data/professions/Meleedwarf b/data/professions/Meleedwarf new file mode 100644 index 0000000000..75b2196dfb --- /dev/null +++ b/data/professions/Meleedwarf @@ -0,0 +1,18 @@ +NAME library/Meleedwarf +RECOVER_WOUNDED +MECHANIC +HAUL_STONE +HAUL_WOOD +HAUL_ITEM +HAUL_BODY +HAUL_FOOD +HAUL_REFUSE +HAUL_FURNITURE +HAUL_ANIMALS +HANDLE_VEHICLES +HAUL_TRADE +HAUL_WATER +CLEAN +PULL_LEVER +BUILD_ROAD +BUILD_CONSTRUCTION diff --git a/data/professions/Migrant b/data/professions/Migrant new file mode 100644 index 0000000000..bc59555b96 --- /dev/null +++ b/data/professions/Migrant @@ -0,0 +1,21 @@ +NAME library/Migrant +FEED_WATER_CIVILIANS +SIEGEOPERATE +MECHANIC +OPERATE_PUMP +HAUL_STONE +HAUL_WOOD +HAUL_ITEM +HAUL_BODY +HAUL_FOOD +HAUL_REFUSE +HAUL_FURNITURE +HAUL_ANIMALS +HANDLE_VEHICLES +HAUL_TRADE +HAUL_WATER +ARCHITECT +CLEAN +PULL_LEVER +BUILD_ROAD +BUILD_CONSTRUCTION diff --git a/data/professions/Miner b/data/professions/Miner new file mode 100644 index 0000000000..3170969d94 --- /dev/null +++ b/data/professions/Miner @@ -0,0 +1,5 @@ +NAME library/Miner +MINE +DETAIL +RECOVER_WOUNDED +ALCHEMIST diff --git a/data/professions/Outdoorsdwarf b/data/professions/Outdoorsdwarf new file mode 100644 index 0000000000..2b3006fdef --- /dev/null +++ b/data/professions/Outdoorsdwarf @@ -0,0 +1,27 @@ +NAME library/Outdoorsdwarf +CARPENTER +BOWYER +CUTWOOD +ANIMALTRAIN +TRAPPER +DISSECT_VERMIN +FEED_WATER_CIVILIANS +RECOVER_WOUNDED +HERBALIST +BEEKEEPING +SIEGECRAFT +HAUL_STONE +HAUL_WOOD +HAUL_ITEM +HAUL_BODY +HAUL_FOOD +HAUL_REFUSE +HAUL_FURNITURE +HAUL_ANIMALS +HANDLE_VEHICLES +HAUL_TRADE +HAUL_WATER +CLEAN +PULL_LEVER +BUILD_ROAD +BUILD_CONSTRUCTION diff --git a/data/professions/Smith b/data/professions/Smith new file mode 100644 index 0000000000..26574f80bf --- /dev/null +++ b/data/professions/Smith @@ -0,0 +1,20 @@ +NAME library/Smith +FORGE_WEAPON +FORGE_ARMOR +FORGE_FURNITURE +METAL_CRAFT +HAUL_STONE +HAUL_WOOD +HAUL_ITEM +HAUL_BODY +HAUL_FOOD +HAUL_REFUSE +HAUL_FURNITURE +HAUL_ANIMALS +HANDLE_VEHICLES +HAUL_TRADE +HAUL_WATER +CLEAN +PULL_LEVER +BUILD_ROAD +BUILD_CONSTRUCTION diff --git a/data/professions/StartManager b/data/professions/StartManager new file mode 100644 index 0000000000..36519bce56 --- /dev/null +++ b/data/professions/StartManager @@ -0,0 +1,57 @@ +NAME library/StartManager +CUTWOOD +ANIMALCARE +DIAGNOSE +SURGERY +BONE_SETTING +SUTURING +DRESSING_WOUNDS +FEED_WATER_CIVILIANS +BUTCHER +TANNER +DYER +SOAP_MAKER +BURN_WOOD +POTASH_MAKING +LYE_MAKING +COOK +BEEKEEPING +CLEAN_FISH +DISSECT_FISH +SMELT +FORGE_WEAPON +FORGE_ARMOR +FORGE_FURNITURE +METAL_CRAFT +LEATHER +WOOD_CRAFT +STONE_CRAFT +BONE_CARVE +GLASSMAKER +WEAVER +CLOTHESMAKER +EXTRACT_STRAND +POTTERY +GLAZING +WAX_WORKING +PAPERMAKING +BOOKBINDING +SIEGEOPERATE +MECHANIC +OPERATE_PUMP +HAUL_STONE +HAUL_WOOD +HAUL_ITEM +HAUL_BODY +HAUL_FOOD +HAUL_REFUSE +HAUL_FURNITURE +HAUL_ANIMALS +HANDLE_VEHICLES +HAUL_TRADE +HAUL_WATER +ARCHITECT +CLEAN +PULL_LEVER +BUILD_ROAD +BUILD_CONSTRUCTION diff --git a/data/professions/Tailor b/data/professions/Tailor new file mode 100644 index 0000000000..fc1b04bd4c --- /dev/null +++ b/data/professions/Tailor @@ -0,0 +1,20 @@ +NAME library/Tailor +DYER +LEATHER +WEAVER +CLOTHESMAKER +HAUL_STONE +HAUL_WOOD +HAUL_ITEM +HAUL_BODY +HAUL_FOOD +HAUL_REFUSE +HAUL_FURNITURE +HAUL_ANIMALS +HANDLE_VEHICLES +HAUL_TRADE +HAUL_WATER +CLEAN +PULL_LEVER +BUILD_ROAD +BUILD_CONSTRUCTION diff --git a/data/stockpiles/adamantinecloth.dfstock b/data/stockpiles/adamantinecloth.dfstock new file mode 100644 index 0000000000..38781d3130 --- /dev/null +++ b/data/stockpiles/adamantinecloth.dfstock @@ -0,0 +1 @@ +rBINORGANIC:ADAMANTINE \ No newline at end of file diff --git a/data/stockpiles/adamantinethread.dfstock b/data/stockpiles/adamantinethread.dfstock new file mode 100644 index 0000000000..2231b389f5 --- /dev/null +++ b/data/stockpiles/adamantinethread.dfstock @@ -0,0 +1 @@ +r"INORGANIC:ADAMANTINE \ No newline at end of file diff --git a/data/stockpiles/adamantineweapons.dfstock b/data/stockpiles/adamantineweapons.dfstock new file mode 100644 index 0000000000..6236196f0e Binary files /dev/null and b/data/stockpiles/adamantineweapons.dfstock differ diff --git a/data/stockpiles/all.dfstock b/data/stockpiles/all.dfstock new file mode 100644 index 0000000000..eace9c53dd Binary files /dev/null and b/data/stockpiles/all.dfstock differ diff --git a/data/stockpiles/artifacts.dfstock b/data/stockpiles/artifacts.dfstock new file mode 100644 index 0000000000..1c7315dfe8 Binary files /dev/null and b/data/stockpiles/artifacts.dfstock differ diff --git a/data/stockpiles/ash.dfstock b/data/stockpiles/ash.dfstock new file mode 100644 index 0000000000..d313e0096d --- /dev/null +++ b/data/stockpiles/ash.dfstock @@ -0,0 +1,2 @@ +R +ASH \ No newline at end of file diff --git a/data/stockpiles/bags.dfstock b/data/stockpiles/bags.dfstock new file mode 100644 index 0000000000..3bfa1a1a17 --- /dev/null +++ b/data/stockpiles/bags.dfstock @@ -0,0 +1,2 @@ + +BAG \ No newline at end of file diff --git a/data/stockpiles/barrels.dfstock b/data/stockpiles/barrels.dfstock new file mode 100644 index 0000000000..70a7239035 --- /dev/null +++ b/data/stockpiles/barrels.dfstock @@ -0,0 +1,2 @@ + +BARREL \ No newline at end of file diff --git a/data/stockpiles/bars.dfstock b/data/stockpiles/bars.dfstock new file mode 100644 index 0000000000..c292dcf562 --- /dev/null +++ b/data/stockpiles/bars.dfstock @@ -0,0 +1,6 @@ +R +COAL +POTASH +ASH +PEARLASH +SOAPINORGANIC:IRONINORGANIC:SILVERINORGANIC:COPPERINORGANIC:NICKELINORGANIC:ZINCINORGANIC:BRONZEINORGANIC:BRASSINORGANIC:STEELINORGANIC:PIG_IRONINORGANIC:PLATINUMINORGANIC:ELECTRUM INORGANIC:TININORGANIC:PEWTER_FINEINORGANIC:PEWTER_TRIFLEINORGANIC:PEWTER_LAYINORGANIC:LEADINORGANIC:ALUMINUMINORGANIC:NICKEL_SILVERINORGANIC:BILLONINORGANIC:STERLING_SILVERINORGANIC:BLACK_BRONZEINORGANIC:ROSE_GOLDINORGANIC:BISMUTHINORGANIC:BISMUTH_BRONZEINORGANIC:ADAMANTINEINORGANIC:GOLDINORGANIC:DIVINE_1INORGANIC:DIVINE_3INORGANIC:DIVINE_5INORGANIC:DIVINE_7INORGANIC:DIVINE_9INORGANIC:DIVINE_11INORGANIC:DIVINE_13INORGANIC:DIVINE_15INORGANIC:DIVINE_17INORGANIC:DIVINE_19 \ No newline at end of file diff --git a/data/stockpiles/bauxite.dfstock b/data/stockpiles/bauxite.dfstock new file mode 100644 index 0000000000..83a49cb5b4 --- /dev/null +++ b/data/stockpiles/bauxite.dfstock @@ -0,0 +1,2 @@ +2 +INORGANIC:BAUXITE \ No newline at end of file diff --git a/data/stockpiles/blocks.dfstock b/data/stockpiles/blocks.dfstock new file mode 100644 index 0000000000..cd08d93338 --- /dev/null +++ b/data/stockpiles/blocks.dfstock @@ -0,0 +1 @@ +R GREEN_GLASS CLEAR_GLASS CRYSTAL_GLASSWOOD"INORGANIC:IRON"INORGANIC:SILVER"INORGANIC:COPPER"INORGANIC:NICKEL"INORGANIC:ZINC"INORGANIC:BRONZE"INORGANIC:BRASS"INORGANIC:STEEL"INORGANIC:PIG_IRON"INORGANIC:PLATINUM"INORGANIC:ELECTRUM" INORGANIC:TIN"INORGANIC:PEWTER_FINE"INORGANIC:PEWTER_TRIFLE"INORGANIC:PEWTER_LAY"INORGANIC:LEAD"INORGANIC:ALUMINUM"INORGANIC:NICKEL_SILVER"INORGANIC:BILLON"INORGANIC:STERLING_SILVER"INORGANIC:BLACK_BRONZE"INORGANIC:ROSE_GOLD"INORGANIC:BISMUTH"INORGANIC:BISMUTH_BRONZE"INORGANIC:ADAMANTINE"INORGANIC:PLASTER"INORGANIC:CERAMIC_EARTHENWARE"INORGANIC:CERAMIC_STONEWARE"INORGANIC:CERAMIC_PORCELAIN"INORGANIC:ASH_GLAZE"INORGANIC:TIN_GLAZE"INORGANIC:SANDSTONE"INORGANIC:SILTSTONE"INORGANIC:MUDSTONE"INORGANIC:SHALE"INORGANIC:CLAYSTONE"INORGANIC:ROCK_SALT"INORGANIC:LIMESTONE"INORGANIC:CONGLOMERATE"INORGANIC:DOLOMITE"INORGANIC:CHERT"INORGANIC:CHALK"INORGANIC:GRANITE"INORGANIC:DIORITE"INORGANIC:GABBRO"INORGANIC:RHYOLITE"INORGANIC:BASALT"INORGANIC:ANDESITE"INORGANIC:DACITE"INORGANIC:OBSIDIAN"INORGANIC:QUARTZITE"INORGANIC:SLATE"INORGANIC:PHYLLITE"INORGANIC:SCHIST"INORGANIC:GNEISS"INORGANIC:MARBLE"INORGANIC:HEMATITE"INORGANIC:LIMONITE"INORGANIC:GARNIERITE"INORGANIC:NATIVE_GOLD"INORGANIC:NATIVE_SILVER"INORGANIC:NATIVE_COPPER"INORGANIC:MALACHITE"INORGANIC:GALENA"INORGANIC:SPHALERITE"INORGANIC:CASSITERITE"INORGANIC:COAL_BITUMINOUS"INORGANIC:LIGNITE"INORGANIC:NATIVE_PLATINUM"INORGANIC:CINNABAR"INORGANIC:COBALTITE"INORGANIC:TETRAHEDRITE"INORGANIC:HORN_SILVER"INORGANIC:GYPSUM"INORGANIC:TALC" INORGANIC:JET"INORGANIC:PUDDINGSTONE"INORGANIC:PETRIFIED_WOOD"INORGANIC:GRAPHITE"INORGANIC:BRIMSTONE"INORGANIC:KIMBERLITE"INORGANIC:BISMUTHINITE"INORGANIC:REALGAR"INORGANIC:ORPIMENT"INORGANIC:STIBNITE"INORGANIC:MARCASITE"INORGANIC:SYLVITE"INORGANIC:CRYOLITE"INORGANIC:PERICLASE"INORGANIC:ILMENITE"INORGANIC:RUTILE"INORGANIC:MAGNETITE"INORGANIC:CHROMITE"INORGANIC:PYROLUSITE"INORGANIC:PITCHBLENDE"INORGANIC:BAUXITE"INORGANIC:NATIVE_ALUMINUM"INORGANIC:BORAX"INORGANIC:OLIVINE"INORGANIC:HORNBLENDE"INORGANIC:KAOLINITE"INORGANIC:SERPENTINE"INORGANIC:ORTHOCLASE"INORGANIC:MICROCLINE"INORGANIC:MICA"INORGANIC:CALCITE"INORGANIC:SALTPETER"INORGANIC:ALABASTER"INORGANIC:SELENITE"INORGANIC:SATINSPAR"INORGANIC:ANHYDRITE"INORGANIC:ALUNITE"INORGANIC:RAW_ADAMANTINE"INORGANIC:SLADE" INORGANIC:BROMS_CLEAN_CORPSEDUST"INORGANIC:GOLD"INORGANIC:DIVINE_1"INORGANIC:DIVINE_3"INORGANIC:DIVINE_5"INORGANIC:DIVINE_7"INORGANIC:DIVINE_9"INORGANIC:DIVINE_11"INORGANIC:DIVINE_13"INORGANIC:DIVINE_15"INORGANIC:DIVINE_17"INORGANIC:DIVINE_19 \ No newline at end of file diff --git a/data/stockpiles/bolts.dfstock b/data/stockpiles/bolts.dfstock new file mode 100644 index 0000000000..2e5bd4b4b8 --- /dev/null +++ b/data/stockpiles/bolts.dfstock @@ -0,0 +1,2 @@ +B +AMMO:ITEM_AMMO_BOLTS \ No newline at end of file diff --git a/data/stockpiles/boneammo.dfstock b/data/stockpiles/boneammo.dfstock new file mode 100644 index 0000000000..909c67d1df --- /dev/null +++ b/data/stockpiles/boneammo.dfstock @@ -0,0 +1 @@ +BBONE \ No newline at end of file diff --git a/data/stockpiles/booze.dfstock b/data/stockpiles/booze.dfstock new file mode 100644 index 0000000000..736560f988 Binary files /dev/null and b/data/stockpiles/booze.dfstock differ diff --git a/data/stockpiles/bronzearmor.dfstock b/data/stockpiles/bronzearmor.dfstock new file mode 100644 index 0000000000..22dda4155e Binary files /dev/null and b/data/stockpiles/bronzearmor.dfstock differ diff --git a/data/stockpiles/bronzeweapons.dfstock b/data/stockpiles/bronzeweapons.dfstock new file mode 100644 index 0000000000..54cd87d110 Binary files /dev/null and b/data/stockpiles/bronzeweapons.dfstock differ diff --git a/data/stockpiles/buckets.dfstock b/data/stockpiles/buckets.dfstock new file mode 100644 index 0000000000..cb6b8c4bb5 --- /dev/null +++ b/data/stockpiles/buckets.dfstock @@ -0,0 +1,2 @@ + +BUCKET \ No newline at end of file diff --git a/data/stockpiles/cages.dfstock b/data/stockpiles/cages.dfstock new file mode 100644 index 0000000000..0ca677985c Binary files /dev/null and b/data/stockpiles/cages.dfstock differ diff --git a/data/stockpiles/cat_ammo.dfstock b/data/stockpiles/cat_ammo.dfstock new file mode 100644 index 0000000000..55a20e7e65 --- /dev/null +++ b/data/stockpiles/cat_ammo.dfstock @@ -0,0 +1 @@ +B0 \ No newline at end of file diff --git a/data/stockpiles/cat_animals.dfstock b/data/stockpiles/cat_animals.dfstock new file mode 100644 index 0000000000..9796e4535c --- /dev/null +++ b/data/stockpiles/cat_animals.dfstock @@ -0,0 +1,2 @@ + +  \ No newline at end of file diff --git a/data/stockpiles/cat_armor.dfstock b/data/stockpiles/cat_armor.dfstock new file mode 100644 index 0000000000..54a2d54eee --- /dev/null +++ b/data/stockpiles/cat_armor.dfstock @@ -0,0 +1 @@ +h \ No newline at end of file diff --git a/data/stockpiles/cat_bars_blocks.dfstock b/data/stockpiles/cat_bars_blocks.dfstock new file mode 100644 index 0000000000..b7ae54bb1f --- /dev/null +++ b/data/stockpiles/cat_bars_blocks.dfstock @@ -0,0 +1 @@ +R( \ No newline at end of file diff --git a/data/stockpiles/cat_cloth.dfstock b/data/stockpiles/cat_cloth.dfstock new file mode 100644 index 0000000000..d88106c6b8 --- /dev/null +++ b/data/stockpiles/cat_cloth.dfstock @@ -0,0 +1 @@ +rH \ No newline at end of file diff --git a/data/stockpiles/cat_coins.dfstock b/data/stockpiles/cat_coins.dfstock new file mode 100644 index 0000000000..a48133ac40 --- /dev/null +++ b/data/stockpiles/cat_coins.dfstock @@ -0,0 +1 @@ +J \ No newline at end of file diff --git a/data/stockpiles/cat_corpses.dfstock b/data/stockpiles/cat_corpses.dfstock new file mode 100644 index 0000000000..f4edc7ff85 --- /dev/null +++ b/data/stockpiles/cat_corpses.dfstock @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/data/stockpiles/cat_finished_goods.dfstock b/data/stockpiles/cat_finished_goods.dfstock new file mode 100644 index 0000000000..68a2d90531 --- /dev/null +++ b/data/stockpiles/cat_finished_goods.dfstock @@ -0,0 +1 @@ +b0 \ No newline at end of file diff --git a/data/stockpiles/cat_food.dfstock b/data/stockpiles/cat_food.dfstock new file mode 100644 index 0000000000..32829f6776 --- /dev/null +++ b/data/stockpiles/cat_food.dfstock @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/data/stockpiles/cat_furniture.dfstock b/data/stockpiles/cat_furniture.dfstock new file mode 100644 index 0000000000..fdec022edf --- /dev/null +++ b/data/stockpiles/cat_furniture.dfstock @@ -0,0 +1 @@ +8 \ No newline at end of file diff --git a/data/stockpiles/cat_gems.dfstock b/data/stockpiles/cat_gems.dfstock new file mode 100644 index 0000000000..8a6483e26e --- /dev/null +++ b/data/stockpiles/cat_gems.dfstock @@ -0,0 +1 @@ +Z( \ No newline at end of file diff --git a/data/stockpiles/cat_leather.dfstock b/data/stockpiles/cat_leather.dfstock new file mode 100644 index 0000000000..357287897c --- /dev/null +++ b/data/stockpiles/cat_leather.dfstock @@ -0,0 +1 @@ +j \ No newline at end of file diff --git a/data/stockpiles/cat_refuse.dfstock b/data/stockpiles/cat_refuse.dfstock new file mode 100644 index 0000000000..a6219a81af --- /dev/null +++ b/data/stockpiles/cat_refuse.dfstock @@ -0,0 +1 @@ +*` \ No newline at end of file diff --git a/data/stockpiles/cat_sheets.dfstock b/data/stockpiles/cat_sheets.dfstock new file mode 100644 index 0000000000..0230086d80 --- /dev/null +++ b/data/stockpiles/cat_sheets.dfstock @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/data/stockpiles/cat_stone.dfstock b/data/stockpiles/cat_stone.dfstock new file mode 100644 index 0000000000..29bcd227e4 --- /dev/null +++ b/data/stockpiles/cat_stone.dfstock @@ -0,0 +1 @@ +2 \ No newline at end of file diff --git a/data/stockpiles/cat_weapons.dfstock b/data/stockpiles/cat_weapons.dfstock new file mode 100644 index 0000000000..8f46ee6199 --- /dev/null +++ b/data/stockpiles/cat_weapons.dfstock @@ -0,0 +1 @@ +H \ No newline at end of file diff --git a/data/stockpiles/cat_wood.dfstock b/data/stockpiles/cat_wood.dfstock new file mode 100644 index 0000000000..5613a0f077 --- /dev/null +++ b/data/stockpiles/cat_wood.dfstock @@ -0,0 +1 @@ +z \ No newline at end of file diff --git a/data/stockpiles/clay.dfstock b/data/stockpiles/clay.dfstock new file mode 100644 index 0000000000..e01c7abaf7 --- /dev/null +++ b/data/stockpiles/clay.dfstock @@ -0,0 +1,6 @@ +2f +INORGANIC:CLAY +INORGANIC:SILTY_CLAY +INORGANIC:SANDY_CLAY +INORGANIC:CLAY_LOAM +INORGANIC:FIRE_CLAY \ No newline at end of file diff --git a/data/stockpiles/cloth.dfstock b/data/stockpiles/cloth.dfstock new file mode 100644 index 0000000000..26c4c52f30 --- /dev/null +++ b/data/stockpiles/cloth.dfstock @@ -0,0 +1 @@ +r'*"CREATURE:SPIDER_BROWN_RECLUSE:SILK*&CREATURE:BROWN_RECLUSE_SPIDER_MAN:SILK*(CREATURE:GIANT_BROWN_RECLUSE_SPIDER:SILK*CREATURE:SPIDER_PHANTOM:SILK*CREATURE:SPIDER_CAVE_GIANT:SILK*CREATURE:SPIDER_CAVE:SILK*INORGANIC:DIVINE_2*INORGANIC:DIVINE_4*INORGANIC:DIVINE_6*INORGANIC:DIVINE_8*INORGANIC:DIVINE_10*INORGANIC:DIVINE_12*INORGANIC:DIVINE_14*INORGANIC:DIVINE_16*INORGANIC:DIVINE_18*INORGANIC:DIVINE_20*CREATURE:FORGOTTEN_BEAST_4:SILK* CREATURE:FORGOTTEN_BEAST_22:SILK* CREATURE:FORGOTTEN_BEAST_33:SILK* CREATURE:FORGOTTEN_BEAST_51:SILK* CREATURE:FORGOTTEN_BEAST_56:SILK* CREATURE:FORGOTTEN_BEAST_58:SILK* CREATURE:FORGOTTEN_BEAST_62:SILK* CREATURE:FORGOTTEN_BEAST_74:SILK* CREATURE:FORGOTTEN_BEAST_80:SILK* CREATURE:FORGOTTEN_BEAST_87:SILK* CREATURE:FORGOTTEN_BEAST_90:SILK*!CREATURE:FORGOTTEN_BEAST_106:SILK*!CREATURE:FORGOTTEN_BEAST_109:SILK*!CREATURE:FORGOTTEN_BEAST_127:SILK*!CREATURE:FORGOTTEN_BEAST_131:SILK*!CREATURE:FORGOTTEN_BEAST_143:SILK*!CREATURE:FORGOTTEN_BEAST_145:SILK*!CREATURE:FORGOTTEN_BEAST_163:SILK*!CREATURE:FORGOTTEN_BEAST_177:SILK*!CREATURE:FORGOTTEN_BEAST_189:SILK*!CREATURE:FORGOTTEN_BEAST_194:SILK*!CREATURE:FORGOTTEN_BEAST_197:SILK*!CREATURE:FORGOTTEN_BEAST_200:SILK*!CREATURE:FORGOTTEN_BEAST_201:SILK*!CREATURE:FORGOTTEN_BEAST_202:SILK*!CREATURE:FORGOTTEN_BEAST_217:SILK*!CREATURE:FORGOTTEN_BEAST_224:SILK*!CREATURE:FORGOTTEN_BEAST_234:SILK*!CREATURE:FORGOTTEN_BEAST_242:SILK*!CREATURE:FORGOTTEN_BEAST_246:SILK*!CREATURE:FORGOTTEN_BEAST_250:SILK*!CREATURE:FORGOTTEN_BEAST_270:SILK*!CREATURE:FORGOTTEN_BEAST_271:SILK*!CREATURE:FORGOTTEN_BEAST_286:SILK*!CREATURE:FORGOTTEN_BEAST_291:SILK*!CREATURE:FORGOTTEN_BEAST_296:SILK*!CREATURE:FORGOTTEN_BEAST_329:SILK*!CREATURE:FORGOTTEN_BEAST_350:SILK*!CREATURE:FORGOTTEN_BEAST_351:SILK*!CREATURE:FORGOTTEN_BEAST_359:SILK*!CREATURE:FORGOTTEN_BEAST_365:SILK*!CREATURE:FORGOTTEN_BEAST_375:SILK*!CREATURE:FORGOTTEN_BEAST_376:SILK*!CREATURE:FORGOTTEN_BEAST_377:SILK*!CREATURE:FORGOTTEN_BEAST_383:SILK*!CREATURE:FORGOTTEN_BEAST_387:SILK*!CREATURE:FORGOTTEN_BEAST_398:SILK*!CREATURE:FORGOTTEN_BEAST_400:SILK*!CREATURE:FORGOTTEN_BEAST_406:SILK*!CREATURE:FORGOTTEN_BEAST_410:SILK*!CREATURE:FORGOTTEN_BEAST_417:SILK*!CREATURE:FORGOTTEN_BEAST_428:SILK*!CREATURE:FORGOTTEN_BEAST_429:SILK*!CREATURE:FORGOTTEN_BEAST_432:SILK*!CREATURE:FORGOTTEN_BEAST_442:SILK*!CREATURE:FORGOTTEN_BEAST_448:SILK*!CREATURE:FORGOTTEN_BEAST_452:SILK*!CREATURE:FORGOTTEN_BEAST_457:SILK*!CREATURE:FORGOTTEN_BEAST_468:SILK*!CREATURE:FORGOTTEN_BEAST_472:SILK*!CREATURE:FORGOTTEN_BEAST_479:SILK*!CREATURE:FORGOTTEN_BEAST_482:SILK*!CREATURE:FORGOTTEN_BEAST_492:SILK*!CREATURE:FORGOTTEN_BEAST_504:SILK*!CREATURE:FORGOTTEN_BEAST_512:SILK*!CREATURE:FORGOTTEN_BEAST_519:SILK*!CREATURE:FORGOTTEN_BEAST_537:SILK*!CREATURE:FORGOTTEN_BEAST_550:SILK*!CREATURE:FORGOTTEN_BEAST_556:SILK*!CREATURE:FORGOTTEN_BEAST_557:SILK*!CREATURE:FORGOTTEN_BEAST_563:SILK*!CREATURE:FORGOTTEN_BEAST_573:SILK*!CREATURE:FORGOTTEN_BEAST_583:SILK*!CREATURE:FORGOTTEN_BEAST_588:SILK*!CREATURE:FORGOTTEN_BEAST_599:SILK*!CREATURE:FORGOTTEN_BEAST_602:SILK*!CREATURE:FORGOTTEN_BEAST_605:SILK*!CREATURE:FORGOTTEN_BEAST_607:SILK*!CREATURE:FORGOTTEN_BEAST_611:SILK*!CREATURE:FORGOTTEN_BEAST_618:SILK*!CREATURE:FORGOTTEN_BEAST_621:SILK*!CREATURE:FORGOTTEN_BEAST_627:SILK*!CREATURE:FORGOTTEN_BEAST_638:SILK*!CREATURE:FORGOTTEN_BEAST_639:SILK*!CREATURE:FORGOTTEN_BEAST_651:SILK*!CREATURE:FORGOTTEN_BEAST_659:SILK*!CREATURE:FORGOTTEN_BEAST_670:SILK*!CREATURE:FORGOTTEN_BEAST_686:SILK*!CREATURE:FORGOTTEN_BEAST_692:SILK*!CREATURE:FORGOTTEN_BEAST_695:SILK*!CREATURE:FORGOTTEN_BEAST_697:SILK*!CREATURE:FORGOTTEN_BEAST_699:SILK*!CREATURE:FORGOTTEN_BEAST_707:SILK*!CREATURE:FORGOTTEN_BEAST_713:SILK*!CREATURE:FORGOTTEN_BEAST_723:SILK*!CREATURE:FORGOTTEN_BEAST_733:SILK*!CREATURE:FORGOTTEN_BEAST_740:SILK*!CREATURE:FORGOTTEN_BEAST_741:SILK*!CREATURE:FORGOTTEN_BEAST_747:SILK*!CREATURE:FORGOTTEN_BEAST_758:SILK*!CREATURE:FORGOTTEN_BEAST_766:SILK*!CREATURE:FORGOTTEN_BEAST_769:SILK*!CREATURE:FORGOTTEN_BEAST_771:SILK*!CREATURE:FORGOTTEN_BEAST_790:SILK*!CREATURE:FORGOTTEN_BEAST_794:SILK*!CREATURE:FORGOTTEN_BEAST_826:SILK*!CREATURE:FORGOTTEN_BEAST_827:SILK*!CREATURE:FORGOTTEN_BEAST_837:SILK*!CREATURE:FORGOTTEN_BEAST_839:SILK*!CREATURE:FORGOTTEN_BEAST_846:SILK*!CREATURE:FORGOTTEN_BEAST_847:SILK*!CREATURE:FORGOTTEN_BEAST_849:SILK*!CREATURE:FORGOTTEN_BEAST_850:SILK*!CREATURE:FORGOTTEN_BEAST_855:SILK*CREATURE:TITAN_1:SILK*CREATURE:TITAN_5:SILK*CREATURE:TITAN_18:SILK*CREATURE:TITAN_24:SILK*CREATURE:TITAN_28:SILK*CREATURE:TITAN_29:SILK*CREATURE:TITAN_30:SILK*CREATURE:TITAN_31:SILK*CREATURE:DEMON_13:SILK*CREATURE:DEMON_15:SILK*CREATURE:DEMON_43:SILK*CREATURE:DEMON_46:SILK*CREATURE:DEMON_49:SILK*CREATURE:DEMON_50:SILK*CREATURE:DEMON_52:SILK2PLANT:FLAX:THREAD2PLANT:JUTE:THREAD2PLANT:HEMP:THREAD2PLANT:COTTON:THREAD2PLANT:RAMIE:THREAD2PLANT:KENAF:THREAD2PLANT:GRASS_TAIL_PIG:THREAD2PLANT:REED_ROPE:THREAD:CREATURE:SHEEP:HAIR:CREATURE:LLAMA:HAIR:CREATURE:ALPACA:HAIR:CREATURE:TROLL:HAIR \ No newline at end of file diff --git a/data/stockpiles/coal.dfstock b/data/stockpiles/coal.dfstock new file mode 100644 index 0000000000..8e9ec16e04 --- /dev/null +++ b/data/stockpiles/coal.dfstock @@ -0,0 +1,2 @@ +R +COAL \ No newline at end of file diff --git a/data/stockpiles/coalproducing.dfstock b/data/stockpiles/coalproducing.dfstock new file mode 100644 index 0000000000..30d6f7adf1 --- /dev/null +++ b/data/stockpiles/coalproducing.dfstock @@ -0,0 +1,3 @@ +2. +INORGANIC:COAL_BITUMINOUS +INORGANIC:LIGNITE \ No newline at end of file diff --git a/data/stockpiles/copperarmor.dfstock b/data/stockpiles/copperarmor.dfstock new file mode 100644 index 0000000000..bc7b8ec58e Binary files /dev/null and b/data/stockpiles/copperarmor.dfstock differ diff --git a/data/stockpiles/copperweapons.dfstock b/data/stockpiles/copperweapons.dfstock new file mode 100644 index 0000000000..a30c53107a Binary files /dev/null and b/data/stockpiles/copperweapons.dfstock differ diff --git a/data/stockpiles/crafts.dfstock b/data/stockpiles/crafts.dfstock new file mode 100644 index 0000000000..633dd9f1f2 --- /dev/null +++ b/data/stockpiles/crafts.dfstock @@ -0,0 +1,10 @@ +bG +FIGURINE +AMULET +SCEPTER +CROWN +RING +EARRING +BRACELET +GEM +TOTEM \ No newline at end of file diff --git a/data/stockpiles/cutgems.dfstock b/data/stockpiles/cutgems.dfstock new file mode 100644 index 0000000000..1049acd673 --- /dev/null +++ b/data/stockpiles/cutgems.dfstock @@ -0,0 +1 @@ +Z"INORGANIC:ONYX"INORGANIC:MORION"INORGANIC:SCHORL"INORGANIC:LACE AGATE"INORGANIC:BLUE JADE"INORGANIC:LAPIS LAZULI"INORGANIC:PRASE"INORGANIC:PRASE OPAL"INORGANIC:BLOODSTONE"INORGANIC:MOSS AGATE"INORGANIC:MOSS OPAL"INORGANIC:VARISCITE"INORGANIC:CHRYSOPRASE"INORGANIC:CHRYSOCOLLA"INORGANIC:SARD"INORGANIC:CARNELIAN"INORGANIC:BANDED AGATE"INORGANIC:SARDONYX"INORGANIC:CHERRY OPAL"INORGANIC:LAVENDER JADE"INORGANIC:PINK JADE"INORGANIC:TUBE AGATE"INORGANIC:FIRE AGATE"INORGANIC:PLUME AGATE"INORGANIC:BROWN JASPER"INORGANIC:PICTURE JASPER"INORGANIC:SMOKY QUARTZ"INORGANIC:WAX OPAL"INORGANIC:WOOD OPAL"INORGANIC:AMBER OPAL"INORGANIC:GOLD OPAL"INORGANIC:CITRINE"INORGANIC:YELLOW JASPER"INORGANIC:TIGEREYE"INORGANIC:TIGER IRON"INORGANIC:SUNSTONE"INORGANIC:RESIN OPAL"INORGANIC:PYRITE"INORGANIC:CLEAR TOURMALINE"INORGANIC:GRAY CHALCEDONY"INORGANIC:DENDRITIC AGATE"INORGANIC:SHELL OPAL"INORGANIC:BONE OPAL"INORGANIC:WHITE CHALCEDONY"INORGANIC:FORTIFICATION AGATE"INORGANIC:MILK QUARTZ"INORGANIC:MOONSTONE"INORGANIC:WHITE JADE"INORGANIC:JASPER OPAL"INORGANIC:PINEAPPLE OPAL"INORGANIC:ONYX OPAL"INORGANIC:MILK OPAL"INORGANIC:PIPE OPAL"INORGANIC:AVENTURINE"INORGANIC:TURQUOISE"INORGANIC:QUARTZ_ROSE"INORGANIC:CRYSTAL_ROCK"INORGANIC:BLACK ZIRCON"INORGANIC:BLACK PYROPE"INORGANIC:MELANITE"INORGANIC:INDIGO TOURMALINE"INORGANIC:BLUE GARNET"INORGANIC:TSAVORITE"INORGANIC:GREEN TOURMALINE"INORGANIC:DEMANTOID"INORGANIC:GREEN ZIRCON"INORGANIC:GREEN JADE"INORGANIC:HELIODOR"INORGANIC:PERIDOT"INORGANIC:RED ZIRCON"INORGANIC:RED TOURMALINE"INORGANIC:RED PYROPE"INORGANIC:ALMANDINE"INORGANIC:RED GROSSULAR"INORGANIC:PINK TOURMALINE"INORGANIC:RED BERYL"INORGANIC:FIRE OPAL"INORGANIC:RHODOLITE"INORGANIC:SPINEL_PURPLE"INORGANIC:ALEXANDRITE"INORGANIC:TANZANITE"INORGANIC:MORGANITE"INORGANIC:VIOLET SPESSARTINE"INORGANIC:PINK GARNET"INORGANIC:KUNZITE"INORGANIC:CINNAMON GROSSULAR"INORGANIC:HONEY YELLOW BERYL"INORGANIC:JELLY OPAL"INORGANIC:BROWN ZIRCON"INORGANIC:YELLOW ZIRCON"INORGANIC:GOLDEN BERYL"INORGANIC:YELLOW SPESSARTINE"INORGANIC:TOPAZ"INORGANIC:TOPAZOLITE"INORGANIC:YELLOW GROSSULAR"INORGANIC:RUBICELLE"INORGANIC:CLEAR GARNET"INORGANIC:GOSHENITE"INORGANIC:CAT'S EYE"INORGANIC:CLEAR ZIRCON"INORGANIC:AMETHYST"INORGANIC:AQUAMARINE"INORGANIC:SPINEL_RED"INORGANIC:CHRYSOBERYL"INORGANIC:OPAL_PFIRE"INORGANIC:OPAL_REDFLASH"INORGANIC:OPAL_BLACK"INORGANIC:OPAL_WHITE"INORGANIC:OPAL_CRYSTAL"INORGANIC:OPAL_CLARO"INORGANIC:OPAL_LEVIN"INORGANIC:OPAL_HARLEQUIN"INORGANIC:OPAL_PINFIRE"INORGANIC:OPAL_BANDFIRE"INORGANIC:DIAMOND_LY"INORGANIC:DIAMOND_FY"INORGANIC:EMERALD"INORGANIC:RUBY"INORGANIC:SAPPHIRE"INORGANIC:DIAMOND_CLEAR"INORGANIC:DIAMOND_RED"INORGANIC:DIAMOND_GREEN"INORGANIC:DIAMOND_BLUE"INORGANIC:DIAMOND_YELLOW"INORGANIC:DIAMOND_BLACK"INORGANIC:SAPPHIRE_STAR"INORGANIC:RUBY_STAR \ No newline at end of file diff --git a/data/stockpiles/cutglass.dfstock b/data/stockpiles/cutglass.dfstock new file mode 100644 index 0000000000..6997d42acd --- /dev/null +++ b/data/stockpiles/cutglass.dfstock @@ -0,0 +1 @@ +Z) GLASS_GREEN GLASS_CLEAR GLASS_CRYSTAL \ No newline at end of file diff --git a/data/stockpiles/cutstone.dfstock b/data/stockpiles/cutstone.dfstock new file mode 100644 index 0000000000..5e0f3f881b --- /dev/null +++ b/data/stockpiles/cutstone.dfstock @@ -0,0 +1 @@ +Z"INORGANIC:PLASTER"INORGANIC:CERAMIC_EARTHENWARE"INORGANIC:CERAMIC_STONEWARE"INORGANIC:CERAMIC_PORCELAIN"INORGANIC:ASH_GLAZE"INORGANIC:TIN_GLAZE"INORGANIC:SANDSTONE"INORGANIC:SILTSTONE"INORGANIC:MUDSTONE"INORGANIC:SHALE"INORGANIC:CLAYSTONE"INORGANIC:ROCK_SALT"INORGANIC:LIMESTONE"INORGANIC:CONGLOMERATE"INORGANIC:DOLOMITE"INORGANIC:CHERT"INORGANIC:CHALK"INORGANIC:GRANITE"INORGANIC:DIORITE"INORGANIC:GABBRO"INORGANIC:RHYOLITE"INORGANIC:BASALT"INORGANIC:ANDESITE"INORGANIC:DACITE"INORGANIC:OBSIDIAN"INORGANIC:QUARTZITE"INORGANIC:SLATE"INORGANIC:PHYLLITE"INORGANIC:SCHIST"INORGANIC:GNEISS"INORGANIC:MARBLE"INORGANIC:HEMATITE"INORGANIC:LIMONITE"INORGANIC:GARNIERITE"INORGANIC:NATIVE_GOLD"INORGANIC:NATIVE_SILVER"INORGANIC:NATIVE_COPPER"INORGANIC:MALACHITE"INORGANIC:GALENA"INORGANIC:SPHALERITE"INORGANIC:CASSITERITE"INORGANIC:COAL_BITUMINOUS"INORGANIC:LIGNITE"INORGANIC:NATIVE_PLATINUM"INORGANIC:CINNABAR"INORGANIC:COBALTITE"INORGANIC:TETRAHEDRITE"INORGANIC:HORN_SILVER"INORGANIC:GYPSUM"INORGANIC:TALC" INORGANIC:JET"INORGANIC:PUDDINGSTONE"INORGANIC:PETRIFIED_WOOD"INORGANIC:GRAPHITE"INORGANIC:BRIMSTONE"INORGANIC:KIMBERLITE"INORGANIC:BISMUTHINITE"INORGANIC:REALGAR"INORGANIC:ORPIMENT"INORGANIC:STIBNITE"INORGANIC:MARCASITE"INORGANIC:SYLVITE"INORGANIC:CRYOLITE"INORGANIC:PERICLASE"INORGANIC:ILMENITE"INORGANIC:RUTILE"INORGANIC:MAGNETITE"INORGANIC:CHROMITE"INORGANIC:PYROLUSITE"INORGANIC:PITCHBLENDE"INORGANIC:BAUXITE"INORGANIC:NATIVE_ALUMINUM"INORGANIC:BORAX"INORGANIC:OLIVINE"INORGANIC:HORNBLENDE"INORGANIC:KAOLINITE"INORGANIC:SERPENTINE"INORGANIC:ORTHOCLASE"INORGANIC:MICROCLINE"INORGANIC:MICA"INORGANIC:CALCITE"INORGANIC:SALTPETER"INORGANIC:ALABASTER"INORGANIC:SELENITE"INORGANIC:SATINSPAR"INORGANIC:ANHYDRITE"INORGANIC:ALUNITE"INORGANIC:RAW_ADAMANTINE"INORGANIC:SLADE" INORGANIC:BROMS_CLEAN_CORPSEDUST \ No newline at end of file diff --git a/data/stockpiles/dye.dfstock b/data/stockpiles/dye.dfstock new file mode 100644 index 0000000000..67b785d203 Binary files /dev/null and b/data/stockpiles/dye.dfstock differ diff --git a/data/stockpiles/economic.dfstock b/data/stockpiles/economic.dfstock new file mode 100644 index 0000000000..976f4cc11f --- /dev/null +++ b/data/stockpiles/economic.dfstock @@ -0,0 +1,13 @@ +2 +INORGANIC:LIMESTONE +INORGANIC:DOLOMITE +INORGANIC:CHALK +INORGANIC:MARBLE +INORGANIC:COAL_BITUMINOUS +INORGANIC:LIGNITE +INORGANIC:GYPSUM +INORGANIC:KAOLINITE +INORGANIC:CALCITE +INORGANIC:ALABASTER +INORGANIC:SELENITE +INORGANIC:SATINSPAR \ No newline at end of file diff --git a/data/stockpiles/everything.dfstock b/data/stockpiles/everything.dfstock new file mode 100644 index 0000000000..c0fcb60519 Binary files /dev/null and b/data/stockpiles/everything.dfstock differ diff --git a/data/stockpiles/flux.dfstock b/data/stockpiles/flux.dfstock new file mode 100644 index 0000000000..ec86187db1 --- /dev/null +++ b/data/stockpiles/flux.dfstock @@ -0,0 +1,6 @@ +2_ +INORGANIC:LIMESTONE +INORGANIC:DOLOMITE +INORGANIC:CHALK +INORGANIC:MARBLE +INORGANIC:CALCITE \ No newline at end of file diff --git a/data/stockpiles/goblets.dfstock b/data/stockpiles/goblets.dfstock new file mode 100644 index 0000000000..bff4f8a6d3 --- /dev/null +++ b/data/stockpiles/goblets.dfstock @@ -0,0 +1,2 @@ +b +GOBLET \ No newline at end of file diff --git a/data/stockpiles/ironarmor.dfstock b/data/stockpiles/ironarmor.dfstock new file mode 100644 index 0000000000..9474bd69f3 Binary files /dev/null and b/data/stockpiles/ironarmor.dfstock differ diff --git a/data/stockpiles/ironbars.dfstock b/data/stockpiles/ironbars.dfstock new file mode 100644 index 0000000000..2cb77c0e35 --- /dev/null +++ b/data/stockpiles/ironbars.dfstock @@ -0,0 +1 @@ +RINORGANIC:IRON \ No newline at end of file diff --git a/data/stockpiles/ironore.dfstock b/data/stockpiles/ironore.dfstock new file mode 100644 index 0000000000..2108b60ac3 --- /dev/null +++ b/data/stockpiles/ironore.dfstock @@ -0,0 +1,4 @@ +2= +INORGANIC:HEMATITE +INORGANIC:LIMONITE +INORGANIC:MAGNETITE \ No newline at end of file diff --git a/data/stockpiles/ironweapons.dfstock b/data/stockpiles/ironweapons.dfstock new file mode 100644 index 0000000000..8c0afecd16 Binary files /dev/null and b/data/stockpiles/ironweapons.dfstock differ diff --git a/data/stockpiles/masterworks.dfstock b/data/stockpiles/masterworks.dfstock new file mode 100644 index 0000000000..fa94c86a93 Binary files /dev/null and b/data/stockpiles/masterworks.dfstock differ diff --git a/data/stockpiles/metalammo.dfstock b/data/stockpiles/metalammo.dfstock new file mode 100644 index 0000000000..f1d9cdee9c --- /dev/null +++ b/data/stockpiles/metalammo.dfstock @@ -0,0 +1 @@ +BINORGANIC:IRONINORGANIC:SILVERINORGANIC:COPPERINORGANIC:NICKELINORGANIC:ZINCINORGANIC:BRONZEINORGANIC:BRASSINORGANIC:STEELINORGANIC:PIG_IRONINORGANIC:PLATINUMINORGANIC:ELECTRUM INORGANIC:TININORGANIC:PEWTER_FINEINORGANIC:PEWTER_TRIFLEINORGANIC:PEWTER_LAYINORGANIC:LEADINORGANIC:ALUMINUMINORGANIC:NICKEL_SILVERINORGANIC:BILLONINORGANIC:STERLING_SILVERINORGANIC:BLACK_BRONZEINORGANIC:ROSE_GOLDINORGANIC:BISMUTHINORGANIC:BISMUTH_BRONZEINORGANIC:ADAMANTINEINORGANIC:GOLDINORGANIC:DIVINE_1INORGANIC:DIVINE_3INORGANIC:DIVINE_5INORGANIC:DIVINE_7INORGANIC:DIVINE_9INORGANIC:DIVINE_11INORGANIC:DIVINE_13INORGANIC:DIVINE_15INORGANIC:DIVINE_17INORGANIC:DIVINE_19 \ No newline at end of file diff --git a/data/stockpiles/metalarmor.dfstock b/data/stockpiles/metalarmor.dfstock new file mode 100644 index 0000000000..f3a00646aa Binary files /dev/null and b/data/stockpiles/metalarmor.dfstock differ diff --git a/data/stockpiles/metalbars.dfstock b/data/stockpiles/metalbars.dfstock new file mode 100644 index 0000000000..103619c508 --- /dev/null +++ b/data/stockpiles/metalbars.dfstock @@ -0,0 +1 @@ +RINORGANIC:IRONINORGANIC:SILVERINORGANIC:COPPERINORGANIC:NICKELINORGANIC:ZINCINORGANIC:BRONZEINORGANIC:BRASSINORGANIC:STEELINORGANIC:PIG_IRONINORGANIC:PLATINUMINORGANIC:ELECTRUM INORGANIC:TININORGANIC:PEWTER_FINEINORGANIC:PEWTER_TRIFLEINORGANIC:PEWTER_LAYINORGANIC:LEADINORGANIC:ALUMINUMINORGANIC:NICKEL_SILVERINORGANIC:BILLONINORGANIC:STERLING_SILVERINORGANIC:BLACK_BRONZEINORGANIC:ROSE_GOLDINORGANIC:BISMUTHINORGANIC:BISMUTH_BRONZEINORGANIC:ADAMANTINEINORGANIC:GOLDINORGANIC:DIVINE_1INORGANIC:DIVINE_3INORGANIC:DIVINE_5INORGANIC:DIVINE_7INORGANIC:DIVINE_9INORGANIC:DIVINE_11INORGANIC:DIVINE_13INORGANIC:DIVINE_15INORGANIC:DIVINE_17INORGANIC:DIVINE_19 \ No newline at end of file diff --git a/data/stockpiles/metalore.dfstock b/data/stockpiles/metalore.dfstock new file mode 100644 index 0000000000..8cbb60959e --- /dev/null +++ b/data/stockpiles/metalore.dfstock @@ -0,0 +1,17 @@ +2 +INORGANIC:HEMATITE +INORGANIC:LIMONITE +INORGANIC:GARNIERITE +INORGANIC:NATIVE_GOLD +INORGANIC:NATIVE_SILVER +INORGANIC:NATIVE_COPPER +INORGANIC:MALACHITE +INORGANIC:GALENA +INORGANIC:SPHALERITE +INORGANIC:CASSITERITE +INORGANIC:NATIVE_PLATINUM +INORGANIC:TETRAHEDRITE +INORGANIC:HORN_SILVER +INORGANIC:BISMUTHINITE +INORGANIC:MAGNETITE +INORGANIC:NATIVE_ALUMINUM \ No newline at end of file diff --git a/data/stockpiles/metalweapons.dfstock b/data/stockpiles/metalweapons.dfstock new file mode 100644 index 0000000000..b9cd665117 Binary files /dev/null and b/data/stockpiles/metalweapons.dfstock differ diff --git a/data/stockpiles/miscliquid.dfstock b/data/stockpiles/miscliquid.dfstock new file mode 100644 index 0000000000..dbf75a072e Binary files /dev/null and b/data/stockpiles/miscliquid.dfstock differ diff --git a/data/stockpiles/organic.dfstock b/data/stockpiles/organic.dfstock new file mode 100644 index 0000000000..70f0496ca3 Binary files /dev/null and b/data/stockpiles/organic.dfstock differ diff --git a/data/stockpiles/otherarmor.dfstock b/data/stockpiles/otherarmor.dfstock new file mode 100644 index 0000000000..ec857e0cc3 Binary files /dev/null and b/data/stockpiles/otherarmor.dfstock differ diff --git a/data/stockpiles/otherbars.dfstock b/data/stockpiles/otherbars.dfstock new file mode 100644 index 0000000000..4cbcc1c8f9 --- /dev/null +++ b/data/stockpiles/otherbars.dfstock @@ -0,0 +1,6 @@ +R# +COAL +POTASH +ASH +PEARLASH +SOAP \ No newline at end of file diff --git a/data/stockpiles/otherstone.dfstock b/data/stockpiles/otherstone.dfstock new file mode 100644 index 0000000000..1f9f867edf --- /dev/null +++ b/data/stockpiles/otherstone.dfstock @@ -0,0 +1,56 @@ +2 +INORGANIC:SANDSTONE +INORGANIC:SILTSTONE +INORGANIC:MUDSTONE +INORGANIC:SHALE +INORGANIC:CLAYSTONE +INORGANIC:ROCK_SALT +INORGANIC:CONGLOMERATE +INORGANIC:CHERT +INORGANIC:GRANITE +INORGANIC:DIORITE +INORGANIC:GABBRO +INORGANIC:RHYOLITE +INORGANIC:BASALT +INORGANIC:ANDESITE +INORGANIC:DACITE +INORGANIC:OBSIDIAN +INORGANIC:QUARTZITE +INORGANIC:SLATE +INORGANIC:PHYLLITE +INORGANIC:SCHIST +INORGANIC:GNEISS +INORGANIC:CINNABAR +INORGANIC:COBALTITE +INORGANIC:TALC + INORGANIC:JET +INORGANIC:PUDDINGSTONE +INORGANIC:PETRIFIED_WOOD +INORGANIC:GRAPHITE +INORGANIC:BRIMSTONE +INORGANIC:KIMBERLITE +INORGANIC:REALGAR +INORGANIC:ORPIMENT +INORGANIC:STIBNITE +INORGANIC:MARCASITE +INORGANIC:SYLVITE +INORGANIC:CRYOLITE +INORGANIC:PERICLASE +INORGANIC:ILMENITE +INORGANIC:RUTILE +INORGANIC:CHROMITE +INORGANIC:PYROLUSITE +INORGANIC:PITCHBLENDE +INORGANIC:BAUXITE +INORGANIC:BORAX +INORGANIC:OLIVINE +INORGANIC:HORNBLENDE +INORGANIC:SERPENTINE +INORGANIC:ORTHOCLASE +INORGANIC:MICROCLINE +INORGANIC:MICA +INORGANIC:SALTPETER +INORGANIC:ANHYDRITE +INORGANIC:ALUNITE +INORGANIC:RAW_ADAMANTINE +INORGANIC:SLADE \ No newline at end of file diff --git a/data/stockpiles/otherweapons.dfstock b/data/stockpiles/otherweapons.dfstock new file mode 100644 index 0000000000..f1127a7841 Binary files /dev/null and b/data/stockpiles/otherweapons.dfstock differ diff --git a/data/stockpiles/pearlash.dfstock b/data/stockpiles/pearlash.dfstock new file mode 100644 index 0000000000..3cea5164da --- /dev/null +++ b/data/stockpiles/pearlash.dfstock @@ -0,0 +1,3 @@ +R + +PEARLASH \ No newline at end of file diff --git a/data/stockpiles/pigironbars.dfstock b/data/stockpiles/pigironbars.dfstock new file mode 100644 index 0000000000..f07b1def24 --- /dev/null +++ b/data/stockpiles/pigironbars.dfstock @@ -0,0 +1 @@ +RINORGANIC:PIG_IRON \ No newline at end of file diff --git a/data/stockpiles/plants.dfstock b/data/stockpiles/plants.dfstock new file mode 100644 index 0000000000..ca55f19f98 Binary files /dev/null and b/data/stockpiles/plants.dfstock differ diff --git a/data/stockpiles/plasterproducing.dfstock b/data/stockpiles/plasterproducing.dfstock new file mode 100644 index 0000000000..2764150a3f --- /dev/null +++ b/data/stockpiles/plasterproducing.dfstock @@ -0,0 +1,5 @@ +2P +INORGANIC:GYPSUM +INORGANIC:ALABASTER +INORGANIC:SELENITE +INORGANIC:SATINSPAR \ No newline at end of file diff --git a/data/stockpiles/platinumweapons.dfstock b/data/stockpiles/platinumweapons.dfstock new file mode 100644 index 0000000000..162865512b Binary files /dev/null and b/data/stockpiles/platinumweapons.dfstock differ diff --git a/data/stockpiles/potash.dfstock b/data/stockpiles/potash.dfstock new file mode 100644 index 0000000000..8a09e446fe --- /dev/null +++ b/data/stockpiles/potash.dfstock @@ -0,0 +1,2 @@ +R +POTASH \ No newline at end of file diff --git a/data/stockpiles/pots.dfstock b/data/stockpiles/pots.dfstock new file mode 100644 index 0000000000..2c1fe0e5ca --- /dev/null +++ b/data/stockpiles/pots.dfstock @@ -0,0 +1,2 @@ + + FOOD_STORAGE \ No newline at end of file diff --git a/data/stockpiles/preparedmeals.dfstock b/data/stockpiles/preparedmeals.dfstock new file mode 100644 index 0000000000..657c93f389 --- /dev/null +++ b/data/stockpiles/preparedmeals.dfstock @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/data/stockpiles/rawhides.dfstock b/data/stockpiles/rawhides.dfstock new file mode 100644 index 0000000000..eedc71760d Binary files /dev/null and b/data/stockpiles/rawhides.dfstock differ diff --git a/data/stockpiles/roughgems.dfstock b/data/stockpiles/roughgems.dfstock new file mode 100644 index 0000000000..fdad4be1ad --- /dev/null +++ b/data/stockpiles/roughgems.dfstock @@ -0,0 +1 @@ +ZINORGANIC:ONYXINORGANIC:MORIONINORGANIC:SCHORLINORGANIC:LACE AGATEINORGANIC:BLUE JADEINORGANIC:LAPIS LAZULIINORGANIC:PRASEINORGANIC:PRASE OPALINORGANIC:BLOODSTONEINORGANIC:MOSS AGATEINORGANIC:MOSS OPALINORGANIC:VARISCITEINORGANIC:CHRYSOPRASEINORGANIC:CHRYSOCOLLAINORGANIC:SARDINORGANIC:CARNELIANINORGANIC:BANDED AGATEINORGANIC:SARDONYXINORGANIC:CHERRY OPALINORGANIC:LAVENDER JADEINORGANIC:PINK JADEINORGANIC:TUBE AGATEINORGANIC:FIRE AGATEINORGANIC:PLUME AGATEINORGANIC:BROWN JASPERINORGANIC:PICTURE JASPERINORGANIC:SMOKY QUARTZINORGANIC:WAX OPALINORGANIC:WOOD OPALINORGANIC:AMBER OPALINORGANIC:GOLD OPALINORGANIC:CITRINEINORGANIC:YELLOW JASPERINORGANIC:TIGEREYEINORGANIC:TIGER IRONINORGANIC:SUNSTONEINORGANIC:RESIN OPALINORGANIC:PYRITEINORGANIC:CLEAR TOURMALINEINORGANIC:GRAY CHALCEDONYINORGANIC:DENDRITIC AGATEINORGANIC:SHELL OPALINORGANIC:BONE OPALINORGANIC:WHITE CHALCEDONYINORGANIC:FORTIFICATION AGATEINORGANIC:MILK QUARTZINORGANIC:MOONSTONEINORGANIC:WHITE JADEINORGANIC:JASPER OPALINORGANIC:PINEAPPLE OPALINORGANIC:ONYX OPALINORGANIC:MILK OPALINORGANIC:PIPE OPALINORGANIC:AVENTURINEINORGANIC:TURQUOISEINORGANIC:QUARTZ_ROSEINORGANIC:CRYSTAL_ROCKINORGANIC:BLACK ZIRCONINORGANIC:BLACK PYROPEINORGANIC:MELANITEINORGANIC:INDIGO TOURMALINEINORGANIC:BLUE GARNETINORGANIC:TSAVORITEINORGANIC:GREEN TOURMALINEINORGANIC:DEMANTOIDINORGANIC:GREEN ZIRCONINORGANIC:GREEN JADEINORGANIC:HELIODORINORGANIC:PERIDOTINORGANIC:RED ZIRCONINORGANIC:RED TOURMALINEINORGANIC:RED PYROPEINORGANIC:ALMANDINEINORGANIC:RED GROSSULARINORGANIC:PINK TOURMALINEINORGANIC:RED BERYLINORGANIC:FIRE OPALINORGANIC:RHODOLITEINORGANIC:SPINEL_PURPLEINORGANIC:ALEXANDRITEINORGANIC:TANZANITEINORGANIC:MORGANITEINORGANIC:VIOLET SPESSARTINEINORGANIC:PINK GARNETINORGANIC:KUNZITEINORGANIC:CINNAMON GROSSULARINORGANIC:HONEY YELLOW BERYLINORGANIC:JELLY OPALINORGANIC:BROWN ZIRCONINORGANIC:YELLOW ZIRCONINORGANIC:GOLDEN BERYLINORGANIC:YELLOW SPESSARTINEINORGANIC:TOPAZINORGANIC:TOPAZOLITEINORGANIC:YELLOW GROSSULARINORGANIC:RUBICELLEINORGANIC:CLEAR GARNETINORGANIC:GOSHENITEINORGANIC:CAT'S EYEINORGANIC:CLEAR ZIRCONINORGANIC:AMETHYSTINORGANIC:AQUAMARINEINORGANIC:SPINEL_REDINORGANIC:CHRYSOBERYLINORGANIC:OPAL_PFIREINORGANIC:OPAL_REDFLASHINORGANIC:OPAL_BLACKINORGANIC:OPAL_WHITEINORGANIC:OPAL_CRYSTALINORGANIC:OPAL_CLAROINORGANIC:OPAL_LEVININORGANIC:OPAL_HARLEQUININORGANIC:OPAL_PINFIREINORGANIC:OPAL_BANDFIREINORGANIC:DIAMOND_LYINORGANIC:DIAMOND_FYINORGANIC:EMERALDINORGANIC:RUBYINORGANIC:SAPPHIREINORGANIC:DIAMOND_CLEARINORGANIC:DIAMOND_REDINORGANIC:DIAMOND_GREENINORGANIC:DIAMOND_BLUEINORGANIC:DIAMOND_YELLOWINORGANIC:DIAMOND_BLACKINORGANIC:SAPPHIRE_STARINORGANIC:RUBY_STAR \ No newline at end of file diff --git a/data/stockpiles/roughglass.dfstock b/data/stockpiles/roughglass.dfstock new file mode 100644 index 0000000000..23b95b81ac --- /dev/null +++ b/data/stockpiles/roughglass.dfstock @@ -0,0 +1,4 @@ +Z) + GLASS_GREEN + GLASS_CLEAR + GLASS_CRYSTAL \ No newline at end of file diff --git a/data/stockpiles/sand.dfstock b/data/stockpiles/sand.dfstock new file mode 100644 index 0000000000..b97921e81e --- /dev/null +++ b/data/stockpiles/sand.dfstock @@ -0,0 +1,3 @@ + + +SAND_BAG \ No newline at end of file diff --git a/data/stockpiles/seeds.dfstock b/data/stockpiles/seeds.dfstock new file mode 100644 index 0000000000..ce9d0a4c22 Binary files /dev/null and b/data/stockpiles/seeds.dfstock differ diff --git a/data/stockpiles/silverweapons.dfstock b/data/stockpiles/silverweapons.dfstock new file mode 100644 index 0000000000..de517d0ab6 Binary files /dev/null and b/data/stockpiles/silverweapons.dfstock differ diff --git a/data/stockpiles/soap.dfstock b/data/stockpiles/soap.dfstock new file mode 100644 index 0000000000..0436f1e7a2 --- /dev/null +++ b/data/stockpiles/soap.dfstock @@ -0,0 +1,2 @@ +R +SOAP \ No newline at end of file diff --git a/data/stockpiles/steelarmor.dfstock b/data/stockpiles/steelarmor.dfstock new file mode 100644 index 0000000000..c2ba86fcbb Binary files /dev/null and b/data/stockpiles/steelarmor.dfstock differ diff --git a/data/stockpiles/steelbars.dfstock b/data/stockpiles/steelbars.dfstock new file mode 100644 index 0000000000..888f32e53a --- /dev/null +++ b/data/stockpiles/steelbars.dfstock @@ -0,0 +1 @@ +RINORGANIC:STEEL \ No newline at end of file diff --git a/data/stockpiles/steelweapons.dfstock b/data/stockpiles/steelweapons.dfstock new file mode 100644 index 0000000000..fc52339252 Binary files /dev/null and b/data/stockpiles/steelweapons.dfstock differ diff --git a/data/stockpiles/stonetools.dfstock b/data/stockpiles/stonetools.dfstock new file mode 100644 index 0000000000..dee961a743 --- /dev/null +++ b/data/stockpiles/stonetools.dfstock @@ -0,0 +1,2 @@ +b +TOOLINORGANIC:PLASTERINORGANIC:CERAMIC_EARTHENWAREINORGANIC:CERAMIC_STONEWAREINORGANIC:CERAMIC_PORCELAININORGANIC:ASH_GLAZEINORGANIC:TIN_GLAZEINORGANIC:SANDSTONEINORGANIC:SILTSTONEINORGANIC:MUDSTONEINORGANIC:SHALEINORGANIC:CLAYSTONEINORGANIC:ROCK_SALTINORGANIC:LIMESTONEINORGANIC:CONGLOMERATEINORGANIC:DOLOMITEINORGANIC:CHERTINORGANIC:CHALKINORGANIC:GRANITEINORGANIC:DIORITEINORGANIC:GABBROINORGANIC:RHYOLITEINORGANIC:BASALTINORGANIC:ANDESITEINORGANIC:DACITEINORGANIC:OBSIDIANINORGANIC:QUARTZITEINORGANIC:SLATEINORGANIC:PHYLLITEINORGANIC:SCHISTINORGANIC:GNEISSINORGANIC:MARBLEINORGANIC:HEMATITEINORGANIC:LIMONITEINORGANIC:GARNIERITEINORGANIC:NATIVE_GOLDINORGANIC:NATIVE_SILVERINORGANIC:NATIVE_COPPERINORGANIC:MALACHITEINORGANIC:GALENAINORGANIC:SPHALERITEINORGANIC:CASSITERITEINORGANIC:COAL_BITUMINOUSINORGANIC:LIGNITEINORGANIC:NATIVE_PLATINUMINORGANIC:CINNABARINORGANIC:COBALTITEINORGANIC:TETRAHEDRITEINORGANIC:HORN_SILVERINORGANIC:GYPSUMINORGANIC:TALC INORGANIC:JETINORGANIC:PUDDINGSTONEINORGANIC:PETRIFIED_WOODINORGANIC:GRAPHITEINORGANIC:BRIMSTONEINORGANIC:KIMBERLITEINORGANIC:BISMUTHINITEINORGANIC:REALGARINORGANIC:ORPIMENTINORGANIC:STIBNITEINORGANIC:MARCASITEINORGANIC:SYLVITEINORGANIC:CRYOLITEINORGANIC:PERICLASEINORGANIC:ILMENITEINORGANIC:RUTILEINORGANIC:MAGNETITEINORGANIC:CHROMITEINORGANIC:PYROLUSITEINORGANIC:PITCHBLENDEINORGANIC:BAUXITEINORGANIC:NATIVE_ALUMINUMINORGANIC:BORAXINORGANIC:OLIVINEINORGANIC:HORNBLENDEINORGANIC:KAOLINITEINORGANIC:SERPENTINEINORGANIC:ORTHOCLASEINORGANIC:MICROCLINEINORGANIC:MICAINORGANIC:CALCITEINORGANIC:SALTPETERINORGANIC:ALABASTERINORGANIC:SELENITEINORGANIC:SATINSPARINORGANIC:ANHYDRITEINORGANIC:ALUNITEINORGANIC:RAW_ADAMANTINEINORGANIC:SLADE \ No newline at end of file diff --git a/data/stockpiles/stoneweapons.dfstock b/data/stockpiles/stoneweapons.dfstock new file mode 100644 index 0000000000..acba2374c1 Binary files /dev/null and b/data/stockpiles/stoneweapons.dfstock differ diff --git a/data/stockpiles/tannedhides.dfstock b/data/stockpiles/tannedhides.dfstock new file mode 100644 index 0000000000..9c58d41ce6 Binary files /dev/null and b/data/stockpiles/tannedhides.dfstock differ diff --git a/data/stockpiles/thread.dfstock b/data/stockpiles/thread.dfstock new file mode 100644 index 0000000000..2774f50e8a --- /dev/null +++ b/data/stockpiles/thread.dfstock @@ -0,0 +1,146 @@ +r' +"CREATURE:SPIDER_BROWN_RECLUSE:SILK +&CREATURE:BROWN_RECLUSE_SPIDER_MAN:SILK +(CREATURE:GIANT_BROWN_RECLUSE_SPIDER:SILK +CREATURE:SPIDER_PHANTOM:SILK +CREATURE:SPIDER_CAVE_GIANT:SILK +CREATURE:SPIDER_CAVE:SILK +INORGANIC:DIVINE_2 +INORGANIC:DIVINE_4 +INORGANIC:DIVINE_6 +INORGANIC:DIVINE_8 +INORGANIC:DIVINE_10 +INORGANIC:DIVINE_12 +INORGANIC:DIVINE_14 +INORGANIC:DIVINE_16 +INORGANIC:DIVINE_18 +INORGANIC:DIVINE_20 +CREATURE:FORGOTTEN_BEAST_4:SILK + CREATURE:FORGOTTEN_BEAST_22:SILK + CREATURE:FORGOTTEN_BEAST_33:SILK + CREATURE:FORGOTTEN_BEAST_51:SILK + CREATURE:FORGOTTEN_BEAST_56:SILK + CREATURE:FORGOTTEN_BEAST_58:SILK + CREATURE:FORGOTTEN_BEAST_62:SILK + CREATURE:FORGOTTEN_BEAST_74:SILK + CREATURE:FORGOTTEN_BEAST_80:SILK + CREATURE:FORGOTTEN_BEAST_87:SILK + CREATURE:FORGOTTEN_BEAST_90:SILK +!CREATURE:FORGOTTEN_BEAST_106:SILK +!CREATURE:FORGOTTEN_BEAST_109:SILK +!CREATURE:FORGOTTEN_BEAST_127:SILK +!CREATURE:FORGOTTEN_BEAST_131:SILK +!CREATURE:FORGOTTEN_BEAST_143:SILK +!CREATURE:FORGOTTEN_BEAST_145:SILK +!CREATURE:FORGOTTEN_BEAST_163:SILK +!CREATURE:FORGOTTEN_BEAST_177:SILK +!CREATURE:FORGOTTEN_BEAST_189:SILK +!CREATURE:FORGOTTEN_BEAST_194:SILK +!CREATURE:FORGOTTEN_BEAST_197:SILK +!CREATURE:FORGOTTEN_BEAST_200:SILK +!CREATURE:FORGOTTEN_BEAST_201:SILK +!CREATURE:FORGOTTEN_BEAST_202:SILK +!CREATURE:FORGOTTEN_BEAST_217:SILK +!CREATURE:FORGOTTEN_BEAST_224:SILK +!CREATURE:FORGOTTEN_BEAST_234:SILK +!CREATURE:FORGOTTEN_BEAST_242:SILK +!CREATURE:FORGOTTEN_BEAST_246:SILK +!CREATURE:FORGOTTEN_BEAST_250:SILK +!CREATURE:FORGOTTEN_BEAST_270:SILK +!CREATURE:FORGOTTEN_BEAST_271:SILK +!CREATURE:FORGOTTEN_BEAST_286:SILK +!CREATURE:FORGOTTEN_BEAST_291:SILK +!CREATURE:FORGOTTEN_BEAST_296:SILK +!CREATURE:FORGOTTEN_BEAST_329:SILK +!CREATURE:FORGOTTEN_BEAST_350:SILK +!CREATURE:FORGOTTEN_BEAST_351:SILK +!CREATURE:FORGOTTEN_BEAST_359:SILK +!CREATURE:FORGOTTEN_BEAST_365:SILK +!CREATURE:FORGOTTEN_BEAST_375:SILK +!CREATURE:FORGOTTEN_BEAST_376:SILK +!CREATURE:FORGOTTEN_BEAST_377:SILK +!CREATURE:FORGOTTEN_BEAST_383:SILK +!CREATURE:FORGOTTEN_BEAST_387:SILK +!CREATURE:FORGOTTEN_BEAST_398:SILK +!CREATURE:FORGOTTEN_BEAST_400:SILK +!CREATURE:FORGOTTEN_BEAST_406:SILK +!CREATURE:FORGOTTEN_BEAST_410:SILK +!CREATURE:FORGOTTEN_BEAST_417:SILK +!CREATURE:FORGOTTEN_BEAST_428:SILK +!CREATURE:FORGOTTEN_BEAST_429:SILK +!CREATURE:FORGOTTEN_BEAST_432:SILK +!CREATURE:FORGOTTEN_BEAST_442:SILK +!CREATURE:FORGOTTEN_BEAST_448:SILK +!CREATURE:FORGOTTEN_BEAST_452:SILK +!CREATURE:FORGOTTEN_BEAST_457:SILK +!CREATURE:FORGOTTEN_BEAST_468:SILK +!CREATURE:FORGOTTEN_BEAST_472:SILK +!CREATURE:FORGOTTEN_BEAST_479:SILK +!CREATURE:FORGOTTEN_BEAST_482:SILK +!CREATURE:FORGOTTEN_BEAST_492:SILK +!CREATURE:FORGOTTEN_BEAST_504:SILK +!CREATURE:FORGOTTEN_BEAST_512:SILK +!CREATURE:FORGOTTEN_BEAST_519:SILK +!CREATURE:FORGOTTEN_BEAST_537:SILK +!CREATURE:FORGOTTEN_BEAST_550:SILK +!CREATURE:FORGOTTEN_BEAST_556:SILK +!CREATURE:FORGOTTEN_BEAST_557:SILK +!CREATURE:FORGOTTEN_BEAST_563:SILK +!CREATURE:FORGOTTEN_BEAST_573:SILK +!CREATURE:FORGOTTEN_BEAST_583:SILK +!CREATURE:FORGOTTEN_BEAST_588:SILK +!CREATURE:FORGOTTEN_BEAST_599:SILK +!CREATURE:FORGOTTEN_BEAST_602:SILK +!CREATURE:FORGOTTEN_BEAST_605:SILK +!CREATURE:FORGOTTEN_BEAST_607:SILK +!CREATURE:FORGOTTEN_BEAST_611:SILK +!CREATURE:FORGOTTEN_BEAST_618:SILK +!CREATURE:FORGOTTEN_BEAST_621:SILK +!CREATURE:FORGOTTEN_BEAST_627:SILK +!CREATURE:FORGOTTEN_BEAST_638:SILK +!CREATURE:FORGOTTEN_BEAST_639:SILK +!CREATURE:FORGOTTEN_BEAST_651:SILK +!CREATURE:FORGOTTEN_BEAST_659:SILK +!CREATURE:FORGOTTEN_BEAST_670:SILK +!CREATURE:FORGOTTEN_BEAST_686:SILK +!CREATURE:FORGOTTEN_BEAST_692:SILK +!CREATURE:FORGOTTEN_BEAST_695:SILK +!CREATURE:FORGOTTEN_BEAST_697:SILK +!CREATURE:FORGOTTEN_BEAST_699:SILK +!CREATURE:FORGOTTEN_BEAST_707:SILK +!CREATURE:FORGOTTEN_BEAST_713:SILK +!CREATURE:FORGOTTEN_BEAST_723:SILK +!CREATURE:FORGOTTEN_BEAST_733:SILK +!CREATURE:FORGOTTEN_BEAST_740:SILK +!CREATURE:FORGOTTEN_BEAST_741:SILK +!CREATURE:FORGOTTEN_BEAST_747:SILK +!CREATURE:FORGOTTEN_BEAST_758:SILK +!CREATURE:FORGOTTEN_BEAST_766:SILK +!CREATURE:FORGOTTEN_BEAST_769:SILK +!CREATURE:FORGOTTEN_BEAST_771:SILK +!CREATURE:FORGOTTEN_BEAST_790:SILK +!CREATURE:FORGOTTEN_BEAST_794:SILK +!CREATURE:FORGOTTEN_BEAST_826:SILK +!CREATURE:FORGOTTEN_BEAST_827:SILK +!CREATURE:FORGOTTEN_BEAST_837:SILK +!CREATURE:FORGOTTEN_BEAST_839:SILK +!CREATURE:FORGOTTEN_BEAST_846:SILK +!CREATURE:FORGOTTEN_BEAST_847:SILK +!CREATURE:FORGOTTEN_BEAST_849:SILK +!CREATURE:FORGOTTEN_BEAST_850:SILK +!CREATURE:FORGOTTEN_BEAST_855:SILK +CREATURE:TITAN_1:SILK +CREATURE:TITAN_5:SILK +CREATURE:TITAN_18:SILK +CREATURE:TITAN_24:SILK +CREATURE:TITAN_28:SILK +CREATURE:TITAN_29:SILK +CREATURE:TITAN_30:SILK +CREATURE:TITAN_31:SILK +CREATURE:DEMON_13:SILK +CREATURE:DEMON_15:SILK +CREATURE:DEMON_43:SILK +CREATURE:DEMON_46:SILK +CREATURE:DEMON_49:SILK +CREATURE:DEMON_50:SILK +CREATURE:DEMON_52:SILKPLANT:FLAX:THREADPLANT:JUTE:THREADPLANT:HEMP:THREADPLANT:COTTON:THREADPLANT:RAMIE:THREADPLANT:KENAF:THREADPLANT:GRASS_TAIL_PIG:THREADPLANT:REED_ROPE:THREADCREATURE:SHEEP:HAIRCREATURE:LLAMA:HAIRCREATURE:ALPACA:HAIRCREATURE:TROLL:HAIR \ No newline at end of file diff --git a/data/stockpiles/toys.dfstock b/data/stockpiles/toys.dfstock new file mode 100644 index 0000000000..a90eab591a --- /dev/null +++ b/data/stockpiles/toys.dfstock @@ -0,0 +1,2 @@ +b +TOY \ No newline at end of file diff --git a/data/stockpiles/trapcomponents.dfstock b/data/stockpiles/trapcomponents.dfstock new file mode 100644 index 0000000000..475b530d4c Binary files /dev/null and b/data/stockpiles/trapcomponents.dfstock differ diff --git a/data/stockpiles/traps.dfstock b/data/stockpiles/traps.dfstock new file mode 100644 index 0000000000..ed1ba67763 Binary files /dev/null and b/data/stockpiles/traps.dfstock differ diff --git a/data/stockpiles/unpreparedfish.dfstock b/data/stockpiles/unpreparedfish.dfstock new file mode 100644 index 0000000000..13841da901 Binary files /dev/null and b/data/stockpiles/unpreparedfish.dfstock differ diff --git a/data/stockpiles/unusablearmor.dfstock b/data/stockpiles/unusablearmor.dfstock new file mode 100644 index 0000000000..d5b2e9c649 Binary files /dev/null and b/data/stockpiles/unusablearmor.dfstock differ diff --git a/data/stockpiles/unusableweapons.dfstock b/data/stockpiles/unusableweapons.dfstock new file mode 100644 index 0000000000..6af8d1b5a2 Binary files /dev/null and b/data/stockpiles/unusableweapons.dfstock differ diff --git a/data/stockpiles/usablearmor.dfstock b/data/stockpiles/usablearmor.dfstock new file mode 100644 index 0000000000..58c9296de9 Binary files /dev/null and b/data/stockpiles/usablearmor.dfstock differ diff --git a/data/stockpiles/usablehair.dfstock b/data/stockpiles/usablehair.dfstock new file mode 100644 index 0000000000..2082d7dcf6 Binary files /dev/null and b/data/stockpiles/usablehair.dfstock differ diff --git a/data/stockpiles/usableweapons.dfstock b/data/stockpiles/usableweapons.dfstock new file mode 100644 index 0000000000..248610ae94 Binary files /dev/null and b/data/stockpiles/usableweapons.dfstock differ diff --git a/data/stockpiles/wax.dfstock b/data/stockpiles/wax.dfstock new file mode 100644 index 0000000000..35c69f6ca8 Binary files /dev/null and b/data/stockpiles/wax.dfstock differ diff --git a/data/stockpiles/woodammo.dfstock b/data/stockpiles/woodammo.dfstock new file mode 100644 index 0000000000..6bec8b1e58 --- /dev/null +++ b/data/stockpiles/woodammo.dfstock @@ -0,0 +1 @@ +BWOOD \ No newline at end of file diff --git a/data/stockpiles/woodtools.dfstock b/data/stockpiles/woodtools.dfstock new file mode 100644 index 0000000000..86eb0d0c81 --- /dev/null +++ b/data/stockpiles/woodtools.dfstock @@ -0,0 +1,2 @@ +b +TOOLWOOD \ No newline at end of file diff --git a/depends/CMakeLists.txt b/depends/CMakeLists.txt new file mode 100644 index 0000000000..41996294c6 --- /dev/null +++ b/depends/CMakeLists.txt @@ -0,0 +1,93 @@ +# list depends here. +add_subdirectory(dfhooks) +install(TARGETS dfhooks LIBRARY DESTINATION . RUNTIME DESTINATION .) + +add_subdirectory(lodepng) +add_subdirectory(lua) +add_subdirectory(md5) +add_subdirectory(protobuf) +target_include_directories(protobuf-lite INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/protobuf) + +if(UNIX) + set_target_properties(lua PROPERTIES COMPILE_FLAGS "-Wno-deprecated-declarations -Wno-deprecated-enum-enum-conversion") + set_target_properties(protoc PROPERTIES COMPILE_FLAGS "-Wno-deprecated-declarations -Wno-restrict") + set_target_properties(protoc-bin PROPERTIES COMPILE_FLAGS "-Wno-deprecated-declarations -Wno-restrict") + set_target_properties(protobuf-lite PROPERTIES COMPILE_FLAGS "-Wno-deprecated-declarations -Wno-restrict") + set_target_properties(protobuf PROPERTIES COMPILE_FLAGS "-Wno-deprecated-declarations -Wno-restrict") +endif() + +option(INSTALL_GTEST "Enable installation of googletest. (Projects embedding googletest may want to turn this OFF.)" OFF) +add_subdirectory(googletest) + +# Don't build tinyxml if it's being externally linked against. +if(NOT TinyXML_FOUND) + add_subdirectory(tinyxml) + target_include_directories(dfhack-tinyxml INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/tinyxml) +endif() + +option(JSONCPP_WITH_TESTS "Compile and (for jsoncpp_check) run JsonCpp test executables" OFF) +option(JSONCPP_WITH_POST_BUILD_UNITTEST "Automatically run unit-tests as a post build step" OFF) +option(JSONCPP_BUILD_SHARED_LIBS "Build jsoncpp_lib as a shared library." OFF) +option(JSONCPP_BUILD_OBJECT_LIBS "Build jsoncpp_lib as a object library." OFF) +option(JSONCPP_WITH_CMAKE_PACKAGE "Generate and install cmake package files" OFF) + +add_subdirectory(jsoncpp-sub EXCLUDE_FROM_ALL) +# build clsocket static and only as a dependency. Setting those options here overrides its own default settings. +option(CLSOCKET_SHARED "Build clsocket lib as shared." OFF) +option(CLSOCKET_DEP_ONLY "Build for use inside other CMake projects as dependency." ON) +add_subdirectory(clsocket) +ide_folder(clsocket "Depends") + +# set the default values of libexpat options - the descriptions are left empty +# because later option() calls *do* override those +set(EXPAT_BUILD_EXAMPLES OFF CACHE BOOL "") +set(EXPAT_BUILD_TESTS OFF CACHE BOOL "") +set(EXPAT_BUILD_TOOLS OFF CACHE BOOL "") +set(EXPAT_SHARED_LIBS OFF CACHE BOOL "") +set(EXPAT_BUILD_DOCS OFF CACHE BOOL "") +set(EXPAT_ENABLE_INSTALL OFF CACHE BOOL "") +add_subdirectory(libexpat/expat) +if(UNIX) + set_target_properties(expat PROPERTIES COMPILE_FLAGS "-Wno-maybe-uninitialized") +endif() + +set(CMAKE_REQUIRED_QUIET ON) +set(LIBZIP_BUILD_DOC OFF CACHE BOOL "") +set(LIBZIP_BUILD_EXAMPLES OFF CACHE BOOL "") +set(LIBZIP_BUILD_REGRESS OFF CACHE BOOL "") +set(LIBZIP_BUILD_SHARED_LIBS OFF CACHE BOOL "") +set(LIBZIP_BUILD_OSSFUZZ OFF CACHE BOOL "") +set(LIBZIP_BUILD_TOOLS OFF CACHE BOOL "") +set(LIBZIP_ENABLE_BZIP2 OFF CACHE BOOL "") +set(LIBZIP_ENABLE_COMMONCRYPTO OFF CACHE BOOL "") +set(LIBZIP_ENABLE_GNUTLS OFF CACHE BOOL "") +set(LIBZIP_ENABLE_LZMA OFF CACHE BOOL "") +set(LIBZIP_ENABLE_MBEDTLS OFF CACHE BOOL "") +set(LIBZIP_ENABLE_OPENSSL OFF CACHE BOOL "") +set(LIBZIP_ENABLE_WINDOWS_CRYPTO OFF CACHE BOOL "") +set(LIBZIP_DO_INSTALL OFF CACHE BOOL "") +add_subdirectory(libzip) +if(MSVC) + target_compile_options(zip PRIVATE /wd4244) +elseif(UNIX) + set_target_properties(zip PROPERTIES COMPILE_FLAGS "-Wno-stringop-truncation -Wno-stringop-overflow") +endif() + +set(XLSXIO_USE_DFHACK_LIBS ON CACHE BOOL "") +set(XLSXIO_BUILD_STATIC ON CACHE BOOL "") +set(XLSXIO_BUILD_SHARED OFF CACHE BOOL "") +set(XLSXIO_BUILD_DOCUMENTATION OFF CACHE BOOL "") +set(XLSXIO_BUILD_EXAMPLES OFF CACHE BOOL "") +set(XLSXIO_BUILD_TOOLS OFF CACHE BOOL "") +set(XLSXIO_WITH_LIBZIP ON CACHE BOOL "") +set(XLSXIO_ZLIB_DIR "${ZLIB_DIR}" CACHE PATH "") +set(XLSXIO_LIBZIP_DIR "${CMAKE_CURRENT_BINARY_DIR}/libzip" CACHE PATH "") +set(XLSXIO_EXPAT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libexpat" CACHE PATH "") +set(XLSXIO_ENABLE_INSTALL OFF CACHE BOOL "") +add_subdirectory(xlsxio) +if(MSVC) + target_compile_options(xlsxio_read_STATIC PRIVATE /wd4013 /wd4244) + target_compile_options(xlsxio_write_STATIC PRIVATE /wd4013 /wd4244) +endif() +target_include_directories(xlsxio_read_STATIC INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/xlsxio/include) +target_include_directories(xlsxio_write_STATIC INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/xlsxio/include) diff --git a/depends/clsocket b/depends/clsocket new file mode 160000 index 0000000000..00c3267aac --- /dev/null +++ b/depends/clsocket @@ -0,0 +1 @@ +Subproject commit 00c3267aacc9c10c5864c7fce856df0de52d72a8 diff --git a/depends/copy-if-different.pl b/depends/copy-if-different.pl new file mode 100755 index 0000000000..2ba08a80e1 --- /dev/null +++ b/depends/copy-if-different.pl @@ -0,0 +1,30 @@ +#!/usr/bin/perl + +# A replacement for "cmake -E copy_if_different" that supports multiple files, +# which old cmake versions do not support + +# Usage: copy-if-different.pl src-file [src-file...] dest-dir + +use strict; +use warnings; + +use Digest::SHA; +use File::Basename; +use File::Copy; + +sub sha_file { + my $filename = shift; + my $sha = Digest::SHA->new(256); + $sha->addfile($filename); + return $sha->hexdigest; +} + +my $dest_dir = pop @ARGV or die "no destination dir"; +-d $dest_dir or die "not a directory: $dest_dir"; +my @src_files = @ARGV or die "no source files"; + +foreach my $file (@src_files) { + my $dest = "$dest_dir/" . basename($file); + next if -f $dest && sha_file($file) eq sha_file($dest); + copy($file, $dest); +} diff --git a/depends/dfhooks b/depends/dfhooks new file mode 160000 index 0000000000..5a904e30a8 --- /dev/null +++ b/depends/dfhooks @@ -0,0 +1 @@ +Subproject commit 5a904e30a8bace81c662b44ec7ff076b92edafd1 diff --git a/depends/googletest b/depends/googletest new file mode 160000 index 0000000000..b514bdc898 --- /dev/null +++ b/depends/googletest @@ -0,0 +1 @@ +Subproject commit b514bdc898e2951020cbdca1304b75f5950d1f59 diff --git a/depends/gunzip.pl b/depends/gunzip.pl new file mode 100755 index 0000000000..caabad5a84 --- /dev/null +++ b/depends/gunzip.pl @@ -0,0 +1,21 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +use IO::Uncompress::Gunzip qw(gunzip $GunzipError); + +my %args = map { $_ => 1 } @ARGV; + +my $in_file = $ARGV[0] or die "no input file"; +# remove extension +(my $out_file = $in_file) =~ s{\.[^.]+$}{}; + +if (! -f $in_file) { + die "input file does not exist: \"$in_file\"\n"; +} +if (-f $out_file and !exists($args{'--force'})) { + die "output file exists, not overwriting: \"$out_file\""; +} + +gunzip $in_file => $out_file, BinModeOut => 1 or die "gunzip failed: $GunzipError\n"; diff --git a/depends/jsoncpp-sub b/depends/jsoncpp-sub new file mode 160000 index 0000000000..3a5d4ff058 --- /dev/null +++ b/depends/jsoncpp-sub @@ -0,0 +1 @@ +Subproject commit 3a5d4ff0583ce7dd5abbf92bdf49dca2177459ef diff --git a/depends/libexpat b/depends/libexpat new file mode 160000 index 0000000000..e3ea446907 --- /dev/null +++ b/depends/libexpat @@ -0,0 +1 @@ +Subproject commit e3ea4469079702ddf352bb3333bf85130c5346c2 diff --git a/depends/libzip b/depends/libzip new file mode 160000 index 0000000000..011e45e125 --- /dev/null +++ b/depends/libzip @@ -0,0 +1 @@ +Subproject commit 011e45e125631cff73c0d6a5d19e0232dfc4df6f diff --git a/depends/lodepng/CMakeLists.txt b/depends/lodepng/CMakeLists.txt new file mode 100644 index 0000000000..41cf16864a --- /dev/null +++ b/depends/lodepng/CMakeLists.txt @@ -0,0 +1,3 @@ +project(dfhack-lodepng) +add_library(dfhack-lodepng STATIC EXCLUDE_FROM_ALL lodepng.cpp lodepng.h) +ide_folder(dfhack-lodepng "Depends") diff --git a/depends/lodepng/LICENSE b/depends/lodepng/LICENSE new file mode 100644 index 0000000000..a5fb0603d9 --- /dev/null +++ b/depends/lodepng/LICENSE @@ -0,0 +1,21 @@ +Copyright (c) 2005-2018 Lode Vandevenne + +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 acknowledgment 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. + diff --git a/depends/lodepng/lodepng.cpp b/depends/lodepng/lodepng.cpp new file mode 100644 index 0000000000..51492b887f --- /dev/null +++ b/depends/lodepng/lodepng.cpp @@ -0,0 +1,6464 @@ +/* +LodePNG version 20201017 + +Copyright (c) 2005-2020 Lode Vandevenne + +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 acknowledgment 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. +*/ + +/* +The manual and changelog are in the header file "lodepng.h" +Rename this file to lodepng.cpp to use it for C++, or to lodepng.c to use it for C. +*/ + +#include "lodepng.h" + +#ifdef LODEPNG_COMPILE_DISK +#include /* LONG_MAX */ +#include /* file handling */ +#endif /* LODEPNG_COMPILE_DISK */ + +#ifdef LODEPNG_COMPILE_ALLOCATORS +#include /* allocations */ +#endif /* LODEPNG_COMPILE_ALLOCATORS */ + +#if defined(_MSC_VER) && (_MSC_VER >= 1310) /*Visual Studio: A few warning types are not desired here.*/ +#pragma warning( disable : 4244 ) /*implicit conversions: not warned by gcc -Wall -Wextra and requires too much casts*/ +#pragma warning( disable : 4996 ) /*VS does not like fopen, but fopen_s is not standard C so unusable here*/ +#endif /*_MSC_VER */ + +const char* LODEPNG_VERSION_STRING = "20201017"; + +/* +This source file is built up in the following large parts. The code sections +with the "LODEPNG_COMPILE_" #defines divide this up further in an intermixed way. +-Tools for C and common code for PNG and Zlib +-C Code for Zlib (huffman, deflate, ...) +-C Code for PNG (file format chunks, adam7, PNG filters, color conversions, ...) +-The C++ wrapper around all of the above +*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* // Tools for C, and common code for PNG and Zlib. // */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ + +/*The malloc, realloc and free functions defined here with "lodepng_" in front +of the name, so that you can easily change them to others related to your +platform if needed. Everything else in the code calls these. Pass +-DLODEPNG_NO_COMPILE_ALLOCATORS to the compiler, or comment out +#define LODEPNG_COMPILE_ALLOCATORS in the header, to disable the ones here and +define them in your own project's source files without needing to change +lodepng source code. Don't forget to remove "static" if you copypaste them +from here.*/ + +#ifdef LODEPNG_COMPILE_ALLOCATORS +static void* lodepng_malloc(size_t size) { +#ifdef LODEPNG_MAX_ALLOC + if(size > LODEPNG_MAX_ALLOC) return 0; +#endif + return malloc(size); +} + +/* NOTE: when realloc returns NULL, it leaves the original memory untouched */ +static void* lodepng_realloc(void* ptr, size_t new_size) { +#ifdef LODEPNG_MAX_ALLOC + if(new_size > LODEPNG_MAX_ALLOC) return 0; +#endif + return realloc(ptr, new_size); +} + +static void lodepng_free(void* ptr) { + free(ptr); +} +#else /*LODEPNG_COMPILE_ALLOCATORS*/ +/* TODO: support giving additional void* payload to the custom allocators */ +void* lodepng_malloc(size_t size); +void* lodepng_realloc(void* ptr, size_t new_size); +void lodepng_free(void* ptr); +#endif /*LODEPNG_COMPILE_ALLOCATORS*/ + +/* convince the compiler to inline a function, for use when this measurably improves performance */ +/* inline is not available in C90, but use it when supported by the compiler */ +#if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || (defined(__cplusplus) && (__cplusplus >= 199711L)) +#define LODEPNG_INLINE inline +#else +#define LODEPNG_INLINE /* not available */ +#endif + +/* restrict is not available in C90, but use it when supported by the compiler */ +#if (defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))) ||\ + (defined(_MSC_VER) && (_MSC_VER >= 1400)) || \ + (defined(__WATCOMC__) && (__WATCOMC__ >= 1250) && !defined(__cplusplus)) +#define LODEPNG_RESTRICT __restrict +#else +#define LODEPNG_RESTRICT /* not available */ +#endif + +/* Replacements for C library functions such as memcpy and strlen, to support platforms +where a full C library is not available. The compiler can recognize them and compile +to something as fast. */ + +static void lodepng_memcpy(void* LODEPNG_RESTRICT dst, + const void* LODEPNG_RESTRICT src, size_t size) { + size_t i; + for(i = 0; i < size; i++) ((char*)dst)[i] = ((const char*)src)[i]; +} + +static void lodepng_memset(void* LODEPNG_RESTRICT dst, + int value, size_t num) { + size_t i; + for(i = 0; i < num; i++) ((char*)dst)[i] = (char)value; +} + +/* does not check memory out of bounds, do not use on untrusted data */ +static size_t lodepng_strlen(const char* a) { + const char* orig = a; + /* avoid warning about unused function in case of disabled COMPILE... macros */ + (void)(&lodepng_strlen); + while(*a) a++; + return (size_t)(a - orig); +} + +#define LODEPNG_MAX(a, b) (((a) > (b)) ? (a) : (b)) +#define LODEPNG_MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define LODEPNG_ABS(x) ((x) < 0 ? -(x) : (x)) + +#if defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_DECODER) +/* Safely check if adding two integers will overflow (no undefined +behavior, compiler removing the code, etc...) and output result. */ +static int lodepng_addofl(size_t a, size_t b, size_t* result) { + *result = a + b; /* Unsigned addition is well defined and safe in C90 */ + return *result < a; +} +#endif /*defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_DECODER)*/ + +#ifdef LODEPNG_COMPILE_DECODER +/* Safely check if multiplying two integers will overflow (no undefined +behavior, compiler removing the code, etc...) and output result. */ +static int lodepng_mulofl(size_t a, size_t b, size_t* result) { + *result = a * b; /* Unsigned multiplication is well defined and safe in C90 */ + return (a != 0 && *result / a != b); +} + +#ifdef LODEPNG_COMPILE_ZLIB +/* Safely check if a + b > c, even if overflow could happen. */ +static int lodepng_gtofl(size_t a, size_t b, size_t c) { + size_t d; + if(lodepng_addofl(a, b, &d)) return 1; + return d > c; +} +#endif /*LODEPNG_COMPILE_ZLIB*/ +#endif /*LODEPNG_COMPILE_DECODER*/ + + +/* +Often in case of an error a value is assigned to a variable and then it breaks +out of a loop (to go to the cleanup phase of a function). This macro does that. +It makes the error handling code shorter and more readable. + +Example: if(!uivector_resize(&lz77_encoded, datasize)) ERROR_BREAK(83); +*/ +#define CERROR_BREAK(errorvar, code){\ + errorvar = code;\ + break;\ +} + +/*version of CERROR_BREAK that assumes the common case where the error variable is named "error"*/ +#define ERROR_BREAK(code) CERROR_BREAK(error, code) + +/*Set error var to the error code, and return it.*/ +#define CERROR_RETURN_ERROR(errorvar, code){\ + errorvar = code;\ + return code;\ +} + +/*Try the code, if it returns error, also return the error.*/ +#define CERROR_TRY_RETURN(call){\ + unsigned error = call;\ + if(error) return error;\ +} + +/*Set error var to the error code, and return from the void function.*/ +#define CERROR_RETURN(errorvar, code){\ + errorvar = code;\ + return;\ +} + +/* +About uivector, ucvector and string: +-All of them wrap dynamic arrays or text strings in a similar way. +-LodePNG was originally written in C++. The vectors replace the std::vectors that were used in the C++ version. +-The string tools are made to avoid problems with compilers that declare things like strncat as deprecated. +-They're not used in the interface, only internally in this file as static functions. +-As with many other structs in this file, the init and cleanup functions serve as ctor and dtor. +*/ + +#ifdef LODEPNG_COMPILE_ZLIB +#ifdef LODEPNG_COMPILE_ENCODER +/*dynamic vector of unsigned ints*/ +typedef struct uivector { + unsigned* data; + size_t size; /*size in number of unsigned longs*/ + size_t allocsize; /*allocated size in bytes*/ +} uivector; + +static void uivector_cleanup(void* p) { + ((uivector*)p)->size = ((uivector*)p)->allocsize = 0; + lodepng_free(((uivector*)p)->data); + ((uivector*)p)->data = NULL; +} + +/*returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned uivector_resize(uivector* p, size_t size) { + size_t allocsize = size * sizeof(unsigned); + if(allocsize > p->allocsize) { + size_t newsize = allocsize + (p->allocsize >> 1u); + void* data = lodepng_realloc(p->data, newsize); + if(data) { + p->allocsize = newsize; + p->data = (unsigned*)data; + } + else return 0; /*error: not enough memory*/ + } + p->size = size; + return 1; /*success*/ +} + +static void uivector_init(uivector* p) { + p->data = NULL; + p->size = p->allocsize = 0; +} + +/*returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned uivector_push_back(uivector* p, unsigned c) { + if(!uivector_resize(p, p->size + 1)) return 0; + p->data[p->size - 1] = c; + return 1; +} +#endif /*LODEPNG_COMPILE_ENCODER*/ +#endif /*LODEPNG_COMPILE_ZLIB*/ + +/* /////////////////////////////////////////////////////////////////////////// */ + +/*dynamic vector of unsigned chars*/ +typedef struct ucvector { + unsigned char* data; + size_t size; /*used size*/ + size_t allocsize; /*allocated size*/ +} ucvector; + +/*returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned ucvector_resize(ucvector* p, size_t size) { + if(size > p->allocsize) { + size_t newsize = size + (p->allocsize >> 1u); + void* data = lodepng_realloc(p->data, newsize); + if(data) { + p->allocsize = newsize; + p->data = (unsigned char*)data; + } + else return 0; /*error: not enough memory*/ + } + p->size = size; + return 1; /*success*/ +} + +static ucvector ucvector_init(unsigned char* buffer, size_t size) { + ucvector v; + v.data = buffer; + v.allocsize = v.size = size; + return v; +} + +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_PNG +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + +/*free string pointer and set it to NULL*/ +static void string_cleanup(char** out) { + lodepng_free(*out); + *out = NULL; +} + +/*also appends null termination character*/ +static char* alloc_string_sized(const char* in, size_t insize) { + char* out = (char*)lodepng_malloc(insize + 1); + if(out) { + lodepng_memcpy(out, in, insize); + out[insize] = 0; + } + return out; +} + +/* dynamically allocates a new string with a copy of the null terminated input text */ +static char* alloc_string(const char* in) { + return alloc_string_sized(in, lodepng_strlen(in)); +} +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +#endif /*LODEPNG_COMPILE_PNG*/ + +/* ////////////////////////////////////////////////////////////////////////// */ + +#if defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_PNG) +static unsigned lodepng_read32bitInt(const unsigned char* buffer) { + return (((unsigned)buffer[0] << 24u) | ((unsigned)buffer[1] << 16u) | + ((unsigned)buffer[2] << 8u) | (unsigned)buffer[3]); +} +#endif /*defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_PNG)*/ + +#if defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_ENCODER) +/*buffer must have at least 4 allocated bytes available*/ +static void lodepng_set32bitInt(unsigned char* buffer, unsigned value) { + buffer[0] = (unsigned char)((value >> 24) & 0xff); + buffer[1] = (unsigned char)((value >> 16) & 0xff); + buffer[2] = (unsigned char)((value >> 8) & 0xff); + buffer[3] = (unsigned char)((value ) & 0xff); +} +#endif /*defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_ENCODER)*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / File IO / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_DISK + +/* returns negative value on error. This should be pure C compatible, so no fstat. */ +static long lodepng_filesize(const char* filename) { + FILE* file; + long size; + file = fopen(filename, "rb"); + if(!file) return -1; + + if(fseek(file, 0, SEEK_END) != 0) { + fclose(file); + return -1; + } + + size = ftell(file); + /* It may give LONG_MAX as directory size, this is invalid for us. */ + if(size == LONG_MAX) size = -1; + + fclose(file); + return size; +} + +/* load file into buffer that already has the correct allocated size. Returns error code.*/ +static unsigned lodepng_buffer_file(unsigned char* out, size_t size, const char* filename) { + FILE* file; + size_t readsize; + file = fopen(filename, "rb"); + if(!file) return 78; + + readsize = fread(out, 1, size, file); + fclose(file); + + if(readsize != size) return 78; + return 0; +} + +unsigned lodepng_load_file(unsigned char** out, size_t* outsize, const char* filename) { + long size = lodepng_filesize(filename); + if(size < 0) return 78; + *outsize = (size_t)size; + + *out = (unsigned char*)lodepng_malloc((size_t)size); + if(!(*out) && size > 0) return 83; /*the above malloc failed*/ + + return lodepng_buffer_file(*out, (size_t)size, filename); +} + +/*write given buffer to the file, overwriting the file, it doesn't append to it.*/ +unsigned lodepng_save_file(const unsigned char* buffer, size_t buffersize, const char* filename) { + FILE* file; + file = fopen(filename, "wb" ); + if(!file) return 79; + fwrite(buffer, 1, buffersize, file); + fclose(file); + return 0; +} + +#endif /*LODEPNG_COMPILE_DISK*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* // End of common code and tools. Begin of Zlib related code. // */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_ZLIB +#ifdef LODEPNG_COMPILE_ENCODER + +typedef struct { + ucvector* data; + unsigned char bp; /*ok to overflow, indicates bit pos inside byte*/ +} LodePNGBitWriter; + +static void LodePNGBitWriter_init(LodePNGBitWriter* writer, ucvector* data) { + writer->data = data; + writer->bp = 0; +} + +/*TODO: this ignores potential out of memory errors*/ +#define WRITEBIT(writer, bit){\ + /* append new byte */\ + if(((writer->bp) & 7u) == 0) {\ + if(!ucvector_resize(writer->data, writer->data->size + 1)) return;\ + writer->data->data[writer->data->size - 1] = 0;\ + }\ + (writer->data->data[writer->data->size - 1]) |= (bit << ((writer->bp) & 7u));\ + ++writer->bp;\ +} + +/* LSB of value is written first, and LSB of bytes is used first */ +static void writeBits(LodePNGBitWriter* writer, unsigned value, size_t nbits) { + if(nbits == 1) { /* compiler should statically compile this case if nbits == 1 */ + WRITEBIT(writer, value); + } else { + /* TODO: increase output size only once here rather than in each WRITEBIT */ + size_t i; + for(i = 0; i != nbits; ++i) { + WRITEBIT(writer, (unsigned char)((value >> i) & 1)); + } + } +} + +/* This one is to use for adding huffman symbol, the value bits are written MSB first */ +static void writeBitsReversed(LodePNGBitWriter* writer, unsigned value, size_t nbits) { + size_t i; + for(i = 0; i != nbits; ++i) { + /* TODO: increase output size only once here rather than in each WRITEBIT */ + WRITEBIT(writer, (unsigned char)((value >> (nbits - 1u - i)) & 1u)); + } +} +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#ifdef LODEPNG_COMPILE_DECODER + +typedef struct { + const unsigned char* data; + size_t size; /*size of data in bytes*/ + size_t bitsize; /*size of data in bits, end of valid bp values, should be 8*size*/ + size_t bp; + unsigned buffer; /*buffer for reading bits. NOTE: 'unsigned' must support at least 32 bits*/ +} LodePNGBitReader; + +/* data size argument is in bytes. Returns error if size too large causing overflow */ +static unsigned LodePNGBitReader_init(LodePNGBitReader* reader, const unsigned char* data, size_t size) { + size_t temp; + reader->data = data; + reader->size = size; + /* size in bits, return error if overflow (if size_t is 32 bit this supports up to 500MB) */ + if(lodepng_mulofl(size, 8u, &reader->bitsize)) return 105; + /*ensure incremented bp can be compared to bitsize without overflow even when it would be incremented 32 too much and + trying to ensure 32 more bits*/ + if(lodepng_addofl(reader->bitsize, 64u, &temp)) return 105; + reader->bp = 0; + reader->buffer = 0; + return 0; /*ok*/ +} + +/* +ensureBits functions: +Ensures the reader can at least read nbits bits in one or more readBits calls, +safely even if not enough bits are available. +Returns 1 if there are enough bits available, 0 if not. +*/ + +/*See ensureBits documentation above. This one ensures exactly 1 bit */ +/*static unsigned ensureBits1(LodePNGBitReader* reader) { + if(reader->bp >= reader->bitsize) return 0; + reader->buffer = (unsigned)reader->data[reader->bp >> 3u] >> (reader->bp & 7u); + return 1; +}*/ + +/*See ensureBits documentation above. This one ensures up to 9 bits */ +static unsigned ensureBits9(LodePNGBitReader* reader, size_t nbits) { + size_t start = reader->bp >> 3u; + size_t size = reader->size; + if(start + 1u < size) { + reader->buffer = (unsigned)reader->data[start + 0] | ((unsigned)reader->data[start + 1] << 8u); + reader->buffer >>= (reader->bp & 7u); + return 1; + } else { + reader->buffer = 0; + if(start + 0u < size) reader->buffer |= reader->data[start + 0]; + reader->buffer >>= (reader->bp & 7u); + return reader->bp + nbits <= reader->bitsize; + } +} + +/*See ensureBits documentation above. This one ensures up to 17 bits */ +static unsigned ensureBits17(LodePNGBitReader* reader, size_t nbits) { + size_t start = reader->bp >> 3u; + size_t size = reader->size; + if(start + 2u < size) { + reader->buffer = (unsigned)reader->data[start + 0] | ((unsigned)reader->data[start + 1] << 8u) | + ((unsigned)reader->data[start + 2] << 16u); + reader->buffer >>= (reader->bp & 7u); + return 1; + } else { + reader->buffer = 0; + if(start + 0u < size) reader->buffer |= reader->data[start + 0]; + if(start + 1u < size) reader->buffer |= ((unsigned)reader->data[start + 1] << 8u); + reader->buffer >>= (reader->bp & 7u); + return reader->bp + nbits <= reader->bitsize; + } +} + +/*See ensureBits documentation above. This one ensures up to 25 bits */ +static LODEPNG_INLINE unsigned ensureBits25(LodePNGBitReader* reader, size_t nbits) { + size_t start = reader->bp >> 3u; + size_t size = reader->size; + if(start + 3u < size) { + reader->buffer = (unsigned)reader->data[start + 0] | ((unsigned)reader->data[start + 1] << 8u) | + ((unsigned)reader->data[start + 2] << 16u) | ((unsigned)reader->data[start + 3] << 24u); + reader->buffer >>= (reader->bp & 7u); + return 1; + } else { + reader->buffer = 0; + if(start + 0u < size) reader->buffer |= reader->data[start + 0]; + if(start + 1u < size) reader->buffer |= ((unsigned)reader->data[start + 1] << 8u); + if(start + 2u < size) reader->buffer |= ((unsigned)reader->data[start + 2] << 16u); + reader->buffer >>= (reader->bp & 7u); + return reader->bp + nbits <= reader->bitsize; + } +} + +/*See ensureBits documentation above. This one ensures up to 32 bits */ +static LODEPNG_INLINE unsigned ensureBits32(LodePNGBitReader* reader, size_t nbits) { + size_t start = reader->bp >> 3u; + size_t size = reader->size; + if(start + 4u < size) { + reader->buffer = (unsigned)reader->data[start + 0] | ((unsigned)reader->data[start + 1] << 8u) | + ((unsigned)reader->data[start + 2] << 16u) | ((unsigned)reader->data[start + 3] << 24u); + reader->buffer >>= (reader->bp & 7u); + reader->buffer |= (((unsigned)reader->data[start + 4] << 24u) << (8u - (reader->bp & 7u))); + return 1; + } else { + reader->buffer = 0; + if(start + 0u < size) reader->buffer |= reader->data[start + 0]; + if(start + 1u < size) reader->buffer |= ((unsigned)reader->data[start + 1] << 8u); + if(start + 2u < size) reader->buffer |= ((unsigned)reader->data[start + 2] << 16u); + if(start + 3u < size) reader->buffer |= ((unsigned)reader->data[start + 3] << 24u); + reader->buffer >>= (reader->bp & 7u); + return reader->bp + nbits <= reader->bitsize; + } +} + +/* Get bits without advancing the bit pointer. Must have enough bits available with ensureBits. Max nbits is 31. */ +static unsigned peekBits(LodePNGBitReader* reader, size_t nbits) { + /* The shift allows nbits to be only up to 31. */ + return reader->buffer & ((1u << nbits) - 1u); +} + +/* Must have enough bits available with ensureBits */ +static void advanceBits(LodePNGBitReader* reader, size_t nbits) { + reader->buffer >>= nbits; + reader->bp += nbits; +} + +/* Must have enough bits available with ensureBits */ +static unsigned readBits(LodePNGBitReader* reader, size_t nbits) { + unsigned result = peekBits(reader, nbits); + advanceBits(reader, nbits); + return result; +} + +/* Public for testing only. steps and result must have numsteps values. */ +unsigned lode_png_test_bitreader(const unsigned char* data, size_t size, + size_t numsteps, const size_t* steps, unsigned* result) { + size_t i; + LodePNGBitReader reader; + unsigned error = LodePNGBitReader_init(&reader, data, size); + if(error) return 0; + for(i = 0; i < numsteps; i++) { + size_t step = steps[i]; + unsigned ok; + if(step > 25) ok = ensureBits32(&reader, step); + else if(step > 17) ok = ensureBits25(&reader, step); + else if(step > 9) ok = ensureBits17(&reader, step); + else ok = ensureBits9(&reader, step); + if(!ok) return 0; + result[i] = readBits(&reader, step); + } + return 1; +} +#endif /*LODEPNG_COMPILE_DECODER*/ + +static unsigned reverseBits(unsigned bits, unsigned num) { + /*TODO: implement faster lookup table based version when needed*/ + unsigned i, result = 0; + for(i = 0; i < num; i++) result |= ((bits >> (num - i - 1u)) & 1u) << i; + return result; +} + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Deflate - Huffman / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#define FIRST_LENGTH_CODE_INDEX 257 +#define LAST_LENGTH_CODE_INDEX 285 +/*256 literals, the end code, some length codes, and 2 unused codes*/ +#define NUM_DEFLATE_CODE_SYMBOLS 288 +/*the distance codes have their own symbols, 30 used, 2 unused*/ +#define NUM_DISTANCE_SYMBOLS 32 +/*the code length codes. 0-15: code lengths, 16: copy previous 3-6 times, 17: 3-10 zeros, 18: 11-138 zeros*/ +#define NUM_CODE_LENGTH_CODES 19 + +/*the base lengths represented by codes 257-285*/ +static const unsigned LENGTHBASE[29] + = {3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, + 67, 83, 99, 115, 131, 163, 195, 227, 258}; + +/*the extra bits used by codes 257-285 (added to base length)*/ +static const unsigned LENGTHEXTRA[29] + = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, + 4, 4, 4, 4, 5, 5, 5, 5, 0}; + +/*the base backwards distances (the bits of distance codes appear after length codes and use their own huffman tree)*/ +static const unsigned DISTANCEBASE[30] + = {1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, + 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577}; + +/*the extra bits of backwards distances (added to base)*/ +static const unsigned DISTANCEEXTRA[30] + = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, + 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13}; + +/*the order in which "code length alphabet code lengths" are stored as specified by deflate, out of this the huffman +tree of the dynamic huffman tree lengths is generated*/ +static const unsigned CLCL_ORDER[NUM_CODE_LENGTH_CODES] + = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + +/* ////////////////////////////////////////////////////////////////////////// */ + +/* +Huffman tree struct, containing multiple representations of the tree +*/ +typedef struct HuffmanTree { + unsigned* codes; /*the huffman codes (bit patterns representing the symbols)*/ + unsigned* lengths; /*the lengths of the huffman codes*/ + unsigned maxbitlen; /*maximum number of bits a single code can get*/ + unsigned numcodes; /*number of symbols in the alphabet = number of codes*/ + /* for reading only */ + unsigned char* table_len; /*length of symbol from lookup table, or max length if secondary lookup needed*/ + unsigned short* table_value; /*value of symbol from lookup table, or pointer to secondary table if needed*/ +} HuffmanTree; + +static void HuffmanTree_init(HuffmanTree* tree) { + tree->codes = 0; + tree->lengths = 0; + tree->table_len = 0; + tree->table_value = 0; +} + +static void HuffmanTree_cleanup(HuffmanTree* tree) { + lodepng_free(tree->codes); + lodepng_free(tree->lengths); + lodepng_free(tree->table_len); + lodepng_free(tree->table_value); +} + +/* amount of bits for first huffman table lookup (aka root bits), see HuffmanTree_makeTable and huffmanDecodeSymbol.*/ +/* values 8u and 9u work the fastest */ +#define FIRSTBITS 9u + +/* a symbol value too big to represent any valid symbol, to indicate reading disallowed huffman bits combination, +which is possible in case of only 0 or 1 present symbols. */ +#define INVALIDSYMBOL 65535u + +/* make table for huffman decoding */ +static unsigned HuffmanTree_makeTable(HuffmanTree* tree) { + static const unsigned headsize = 1u << FIRSTBITS; /*size of the first table*/ + static const unsigned mask = (1u << FIRSTBITS) /*headsize*/ - 1u; + size_t i, numpresent, pointer, size; /*total table size*/ + unsigned* maxlens = (unsigned*)lodepng_malloc(headsize * sizeof(unsigned)); + if(!maxlens) return 83; /*alloc fail*/ + + /* compute maxlens: max total bit length of symbols sharing prefix in the first table*/ + lodepng_memset(maxlens, 0, headsize * sizeof(*maxlens)); + for(i = 0; i < tree->numcodes; i++) { + unsigned symbol = tree->codes[i]; + unsigned l = tree->lengths[i]; + unsigned index; + if(l <= FIRSTBITS) continue; /*symbols that fit in first table don't increase secondary table size*/ + /*get the FIRSTBITS MSBs, the MSBs of the symbol are encoded first. See later comment about the reversing*/ + index = reverseBits(symbol >> (l - FIRSTBITS), FIRSTBITS); + maxlens[index] = LODEPNG_MAX(maxlens[index], l); + } + /* compute total table size: size of first table plus all secondary tables for symbols longer than FIRSTBITS */ + size = headsize; + for(i = 0; i < headsize; ++i) { + unsigned l = maxlens[i]; + if(l > FIRSTBITS) size += (1u << (l - FIRSTBITS)); + } + tree->table_len = (unsigned char*)lodepng_malloc(size * sizeof(*tree->table_len)); + tree->table_value = (unsigned short*)lodepng_malloc(size * sizeof(*tree->table_value)); + if(!tree->table_len || !tree->table_value) { + lodepng_free(maxlens); + /* freeing tree->table values is done at a higher scope */ + return 83; /*alloc fail*/ + } + /*initialize with an invalid length to indicate unused entries*/ + for(i = 0; i < size; ++i) tree->table_len[i] = 16; + + /*fill in the first table for long symbols: max prefix size and pointer to secondary tables*/ + pointer = headsize; + for(i = 0; i < headsize; ++i) { + unsigned l = maxlens[i]; + if(l <= FIRSTBITS) continue; + tree->table_len[i] = l; + tree->table_value[i] = pointer; + pointer += (1u << (l - FIRSTBITS)); + } + lodepng_free(maxlens); + + /*fill in the first table for short symbols, or secondary table for long symbols*/ + numpresent = 0; + for(i = 0; i < tree->numcodes; ++i) { + unsigned l = tree->lengths[i]; + unsigned symbol = tree->codes[i]; /*the huffman bit pattern. i itself is the value.*/ + /*reverse bits, because the huffman bits are given in MSB first order but the bit reader reads LSB first*/ + unsigned reverse = reverseBits(symbol, l); + if(l == 0) continue; + numpresent++; + + if(l <= FIRSTBITS) { + /*short symbol, fully in first table, replicated num times if l < FIRSTBITS*/ + unsigned num = 1u << (FIRSTBITS - l); + unsigned j; + for(j = 0; j < num; ++j) { + /*bit reader will read the l bits of symbol first, the remaining FIRSTBITS - l bits go to the MSB's*/ + unsigned index = reverse | (j << l); + if(tree->table_len[index] != 16) return 55; /*invalid tree: long symbol shares prefix with short symbol*/ + tree->table_len[index] = l; + tree->table_value[index] = i; + } + } else { + /*long symbol, shares prefix with other long symbols in first lookup table, needs second lookup*/ + /*the FIRSTBITS MSBs of the symbol are the first table index*/ + unsigned index = reverse & mask; + unsigned maxlen = tree->table_len[index]; + /*log2 of secondary table length, should be >= l - FIRSTBITS*/ + unsigned tablelen = maxlen - FIRSTBITS; + unsigned start = tree->table_value[index]; /*starting index in secondary table*/ + unsigned num = 1u << (tablelen - (l - FIRSTBITS)); /*amount of entries of this symbol in secondary table*/ + unsigned j; + if(maxlen < l) return 55; /*invalid tree: long symbol shares prefix with short symbol*/ + for(j = 0; j < num; ++j) { + unsigned reverse2 = reverse >> FIRSTBITS; /* l - FIRSTBITS bits */ + unsigned index2 = start + (reverse2 | (j << (l - FIRSTBITS))); + tree->table_len[index2] = l; + tree->table_value[index2] = i; + } + } + } + + if(numpresent < 2) { + /* In case of exactly 1 symbol, in theory the huffman symbol needs 0 bits, + but deflate uses 1 bit instead. In case of 0 symbols, no symbols can + appear at all, but such huffman tree could still exist (e.g. if distance + codes are never used). In both cases, not all symbols of the table will be + filled in. Fill them in with an invalid symbol value so returning them from + huffmanDecodeSymbol will cause error. */ + for(i = 0; i < size; ++i) { + if(tree->table_len[i] == 16) { + /* As length, use a value smaller than FIRSTBITS for the head table, + and a value larger than FIRSTBITS for the secondary table, to ensure + valid behavior for advanceBits when reading this symbol. */ + tree->table_len[i] = (i < headsize) ? 1 : (FIRSTBITS + 1); + tree->table_value[i] = INVALIDSYMBOL; + } + } + } else { + /* A good huffman tree has N * 2 - 1 nodes, of which N - 1 are internal nodes. + If that is not the case (due to too long length codes), the table will not + have been fully used, and this is an error (not all bit combinations can be + decoded): an oversubscribed huffman tree, indicated by error 55. */ + for(i = 0; i < size; ++i) { + if(tree->table_len[i] == 16) return 55; + } + } + + return 0; +} + +/* +Second step for the ...makeFromLengths and ...makeFromFrequencies functions. +numcodes, lengths and maxbitlen must already be filled in correctly. return +value is error. +*/ +static unsigned HuffmanTree_makeFromLengths2(HuffmanTree* tree) { + unsigned* blcount; + unsigned* nextcode; + unsigned error = 0; + unsigned bits, n; + + tree->codes = (unsigned*)lodepng_malloc(tree->numcodes * sizeof(unsigned)); + blcount = (unsigned*)lodepng_malloc((tree->maxbitlen + 1) * sizeof(unsigned)); + nextcode = (unsigned*)lodepng_malloc((tree->maxbitlen + 1) * sizeof(unsigned)); + if(!tree->codes || !blcount || !nextcode) error = 83; /*alloc fail*/ + + if(!error) { + for(n = 0; n != tree->maxbitlen + 1; n++) blcount[n] = nextcode[n] = 0; + /*step 1: count number of instances of each code length*/ + for(bits = 0; bits != tree->numcodes; ++bits) ++blcount[tree->lengths[bits]]; + /*step 2: generate the nextcode values*/ + for(bits = 1; bits <= tree->maxbitlen; ++bits) { + nextcode[bits] = (nextcode[bits - 1] + blcount[bits - 1]) << 1u; + } + /*step 3: generate all the codes*/ + for(n = 0; n != tree->numcodes; ++n) { + if(tree->lengths[n] != 0) { + tree->codes[n] = nextcode[tree->lengths[n]]++; + /*remove superfluous bits from the code*/ + tree->codes[n] &= ((1u << tree->lengths[n]) - 1u); + } + } + } + + lodepng_free(blcount); + lodepng_free(nextcode); + + if(!error) error = HuffmanTree_makeTable(tree); + return error; +} + +/* +given the code lengths (as stored in the PNG file), generate the tree as defined +by Deflate. maxbitlen is the maximum bits that a code in the tree can have. +return value is error. +*/ +static unsigned HuffmanTree_makeFromLengths(HuffmanTree* tree, const unsigned* bitlen, + size_t numcodes, unsigned maxbitlen) { + unsigned i; + tree->lengths = (unsigned*)lodepng_malloc(numcodes * sizeof(unsigned)); + if(!tree->lengths) return 83; /*alloc fail*/ + for(i = 0; i != numcodes; ++i) tree->lengths[i] = bitlen[i]; + tree->numcodes = (unsigned)numcodes; /*number of symbols*/ + tree->maxbitlen = maxbitlen; + return HuffmanTree_makeFromLengths2(tree); +} + +#ifdef LODEPNG_COMPILE_ENCODER + +/*BPM: Boundary Package Merge, see "A Fast and Space-Economical Algorithm for Length-Limited Coding", +Jyrki Katajainen, Alistair Moffat, Andrew Turpin, 1995.*/ + +/*chain node for boundary package merge*/ +typedef struct BPMNode { + int weight; /*the sum of all weights in this chain*/ + unsigned index; /*index of this leaf node (called "count" in the paper)*/ + struct BPMNode* tail; /*the next nodes in this chain (null if last)*/ + int in_use; +} BPMNode; + +/*lists of chains*/ +typedef struct BPMLists { + /*memory pool*/ + unsigned memsize; + BPMNode* memory; + unsigned numfree; + unsigned nextfree; + BPMNode** freelist; + /*two heads of lookahead chains per list*/ + unsigned listsize; + BPMNode** chains0; + BPMNode** chains1; +} BPMLists; + +/*creates a new chain node with the given parameters, from the memory in the lists */ +static BPMNode* bpmnode_create(BPMLists* lists, int weight, unsigned index, BPMNode* tail) { + unsigned i; + BPMNode* result; + + /*memory full, so garbage collect*/ + if(lists->nextfree >= lists->numfree) { + /*mark only those that are in use*/ + for(i = 0; i != lists->memsize; ++i) lists->memory[i].in_use = 0; + for(i = 0; i != lists->listsize; ++i) { + BPMNode* node; + for(node = lists->chains0[i]; node != 0; node = node->tail) node->in_use = 1; + for(node = lists->chains1[i]; node != 0; node = node->tail) node->in_use = 1; + } + /*collect those that are free*/ + lists->numfree = 0; + for(i = 0; i != lists->memsize; ++i) { + if(!lists->memory[i].in_use) lists->freelist[lists->numfree++] = &lists->memory[i]; + } + lists->nextfree = 0; + } + + result = lists->freelist[lists->nextfree++]; + result->weight = weight; + result->index = index; + result->tail = tail; + return result; +} + +/*sort the leaves with stable mergesort*/ +static void bpmnode_sort(BPMNode* leaves, size_t num) { + BPMNode* mem = (BPMNode*)lodepng_malloc(sizeof(*leaves) * num); + size_t width, counter = 0; + for(width = 1; width < num; width *= 2) { + BPMNode* a = (counter & 1) ? mem : leaves; + BPMNode* b = (counter & 1) ? leaves : mem; + size_t p; + for(p = 0; p < num; p += 2 * width) { + size_t q = (p + width > num) ? num : (p + width); + size_t r = (p + 2 * width > num) ? num : (p + 2 * width); + size_t i = p, j = q, k; + for(k = p; k < r; k++) { + if(i < q && (j >= r || a[i].weight <= a[j].weight)) b[k] = a[i++]; + else b[k] = a[j++]; + } + } + counter++; + } + if(counter & 1) lodepng_memcpy(leaves, mem, sizeof(*leaves) * num); + lodepng_free(mem); +} + +/*Boundary Package Merge step, numpresent is the amount of leaves, and c is the current chain.*/ +static void boundaryPM(BPMLists* lists, BPMNode* leaves, size_t numpresent, int c, int num) { + unsigned lastindex = lists->chains1[c]->index; + + if(c == 0) { + if(lastindex >= numpresent) return; + lists->chains0[c] = lists->chains1[c]; + lists->chains1[c] = bpmnode_create(lists, leaves[lastindex].weight, lastindex + 1, 0); + } else { + /*sum of the weights of the head nodes of the previous lookahead chains.*/ + int sum = lists->chains0[c - 1]->weight + lists->chains1[c - 1]->weight; + lists->chains0[c] = lists->chains1[c]; + if(lastindex < numpresent && sum > leaves[lastindex].weight) { + lists->chains1[c] = bpmnode_create(lists, leaves[lastindex].weight, lastindex + 1, lists->chains1[c]->tail); + return; + } + lists->chains1[c] = bpmnode_create(lists, sum, lastindex, lists->chains1[c - 1]); + /*in the end we are only interested in the chain of the last list, so no + need to recurse if we're at the last one (this gives measurable speedup)*/ + if(num + 1 < (int)(2 * numpresent - 2)) { + boundaryPM(lists, leaves, numpresent, c - 1, num); + boundaryPM(lists, leaves, numpresent, c - 1, num); + } + } +} + +unsigned lodepng_huffman_code_lengths(unsigned* lengths, const unsigned* frequencies, + size_t numcodes, unsigned maxbitlen) { + unsigned error = 0; + unsigned i; + size_t numpresent = 0; /*number of symbols with non-zero frequency*/ + BPMNode* leaves; /*the symbols, only those with > 0 frequency*/ + + if(numcodes == 0) return 80; /*error: a tree of 0 symbols is not supposed to be made*/ + if((1u << maxbitlen) < (unsigned)numcodes) return 80; /*error: represent all symbols*/ + + leaves = (BPMNode*)lodepng_malloc(numcodes * sizeof(*leaves)); + if(!leaves) return 83; /*alloc fail*/ + + for(i = 0; i != numcodes; ++i) { + if(frequencies[i] > 0) { + leaves[numpresent].weight = (int)frequencies[i]; + leaves[numpresent].index = i; + ++numpresent; + } + } + + lodepng_memset(lengths, 0, numcodes * sizeof(*lengths)); + + /*ensure at least two present symbols. There should be at least one symbol + according to RFC 1951 section 3.2.7. Some decoders incorrectly require two. To + make these work as well ensure there are at least two symbols. The + Package-Merge code below also doesn't work correctly if there's only one + symbol, it'd give it the theoretical 0 bits but in practice zlib wants 1 bit*/ + if(numpresent == 0) { + lengths[0] = lengths[1] = 1; /*note that for RFC 1951 section 3.2.7, only lengths[0] = 1 is needed*/ + } else if(numpresent == 1) { + lengths[leaves[0].index] = 1; + lengths[leaves[0].index == 0 ? 1 : 0] = 1; + } else { + BPMLists lists; + BPMNode* node; + + bpmnode_sort(leaves, numpresent); + + lists.listsize = maxbitlen; + lists.memsize = 2 * maxbitlen * (maxbitlen + 1); + lists.nextfree = 0; + lists.numfree = lists.memsize; + lists.memory = (BPMNode*)lodepng_malloc(lists.memsize * sizeof(*lists.memory)); + lists.freelist = (BPMNode**)lodepng_malloc(lists.memsize * sizeof(BPMNode*)); + lists.chains0 = (BPMNode**)lodepng_malloc(lists.listsize * sizeof(BPMNode*)); + lists.chains1 = (BPMNode**)lodepng_malloc(lists.listsize * sizeof(BPMNode*)); + if(!lists.memory || !lists.freelist || !lists.chains0 || !lists.chains1) error = 83; /*alloc fail*/ + + if(!error) { + for(i = 0; i != lists.memsize; ++i) lists.freelist[i] = &lists.memory[i]; + + bpmnode_create(&lists, leaves[0].weight, 1, 0); + bpmnode_create(&lists, leaves[1].weight, 2, 0); + + for(i = 0; i != lists.listsize; ++i) { + lists.chains0[i] = &lists.memory[0]; + lists.chains1[i] = &lists.memory[1]; + } + + /*each boundaryPM call adds one chain to the last list, and we need 2 * numpresent - 2 chains.*/ + for(i = 2; i != 2 * numpresent - 2; ++i) boundaryPM(&lists, leaves, numpresent, (int)maxbitlen - 1, (int)i); + + for(node = lists.chains1[maxbitlen - 1]; node; node = node->tail) { + for(i = 0; i != node->index; ++i) ++lengths[leaves[i].index]; + } + } + + lodepng_free(lists.memory); + lodepng_free(lists.freelist); + lodepng_free(lists.chains0); + lodepng_free(lists.chains1); + } + + lodepng_free(leaves); + return error; +} + +/*Create the Huffman tree given the symbol frequencies*/ +static unsigned HuffmanTree_makeFromFrequencies(HuffmanTree* tree, const unsigned* frequencies, + size_t mincodes, size_t numcodes, unsigned maxbitlen) { + unsigned error = 0; + while(!frequencies[numcodes - 1] && numcodes > mincodes) --numcodes; /*trim zeroes*/ + tree->lengths = (unsigned*)lodepng_malloc(numcodes * sizeof(unsigned)); + if(!tree->lengths) return 83; /*alloc fail*/ + tree->maxbitlen = maxbitlen; + tree->numcodes = (unsigned)numcodes; /*number of symbols*/ + + error = lodepng_huffman_code_lengths(tree->lengths, frequencies, numcodes, maxbitlen); + if(!error) error = HuffmanTree_makeFromLengths2(tree); + return error; +} +#endif /*LODEPNG_COMPILE_ENCODER*/ + +/*get the literal and length code tree of a deflated block with fixed tree, as per the deflate specification*/ +static unsigned generateFixedLitLenTree(HuffmanTree* tree) { + unsigned i, error = 0; + unsigned* bitlen = (unsigned*)lodepng_malloc(NUM_DEFLATE_CODE_SYMBOLS * sizeof(unsigned)); + if(!bitlen) return 83; /*alloc fail*/ + + /*288 possible codes: 0-255=literals, 256=endcode, 257-285=lengthcodes, 286-287=unused*/ + for(i = 0; i <= 143; ++i) bitlen[i] = 8; + for(i = 144; i <= 255; ++i) bitlen[i] = 9; + for(i = 256; i <= 279; ++i) bitlen[i] = 7; + for(i = 280; i <= 287; ++i) bitlen[i] = 8; + + error = HuffmanTree_makeFromLengths(tree, bitlen, NUM_DEFLATE_CODE_SYMBOLS, 15); + + lodepng_free(bitlen); + return error; +} + +/*get the distance code tree of a deflated block with fixed tree, as specified in the deflate specification*/ +static unsigned generateFixedDistanceTree(HuffmanTree* tree) { + unsigned i, error = 0; + unsigned* bitlen = (unsigned*)lodepng_malloc(NUM_DISTANCE_SYMBOLS * sizeof(unsigned)); + if(!bitlen) return 83; /*alloc fail*/ + + /*there are 32 distance codes, but 30-31 are unused*/ + for(i = 0; i != NUM_DISTANCE_SYMBOLS; ++i) bitlen[i] = 5; + error = HuffmanTree_makeFromLengths(tree, bitlen, NUM_DISTANCE_SYMBOLS, 15); + + lodepng_free(bitlen); + return error; +} + +#ifdef LODEPNG_COMPILE_DECODER + +/* +returns the code. The bit reader must already have been ensured at least 15 bits +*/ +static unsigned huffmanDecodeSymbol(LodePNGBitReader* reader, const HuffmanTree* codetree) { + unsigned short code = peekBits(reader, FIRSTBITS); + unsigned short l = codetree->table_len[code]; + unsigned short value = codetree->table_value[code]; + if(l <= FIRSTBITS) { + advanceBits(reader, l); + return value; + } else { + unsigned index2; + advanceBits(reader, FIRSTBITS); + index2 = value + peekBits(reader, l - FIRSTBITS); + advanceBits(reader, codetree->table_len[index2] - FIRSTBITS); + return codetree->table_value[index2]; + } +} +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_DECODER + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Inflator (Decompressor) / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +/*get the tree of a deflated block with fixed tree, as specified in the deflate specification +Returns error code.*/ +static unsigned getTreeInflateFixed(HuffmanTree* tree_ll, HuffmanTree* tree_d) { + unsigned error = generateFixedLitLenTree(tree_ll); + if(error) return error; + return generateFixedDistanceTree(tree_d); +} + +/*get the tree of a deflated block with dynamic tree, the tree itself is also Huffman compressed with a known tree*/ +static unsigned getTreeInflateDynamic(HuffmanTree* tree_ll, HuffmanTree* tree_d, + LodePNGBitReader* reader) { + /*make sure that length values that aren't filled in will be 0, or a wrong tree will be generated*/ + unsigned error = 0; + unsigned n, HLIT, HDIST, HCLEN, i; + + /*see comments in deflateDynamic for explanation of the context and these variables, it is analogous*/ + unsigned* bitlen_ll = 0; /*lit,len code lengths*/ + unsigned* bitlen_d = 0; /*dist code lengths*/ + /*code length code lengths ("clcl"), the bit lengths of the huffman tree used to compress bitlen_ll and bitlen_d*/ + unsigned* bitlen_cl = 0; + HuffmanTree tree_cl; /*the code tree for code length codes (the huffman tree for compressed huffman trees)*/ + + if(!ensureBits17(reader, 14)) return 49; /*error: the bit pointer is or will go past the memory*/ + + /*number of literal/length codes + 257. Unlike the spec, the value 257 is added to it here already*/ + HLIT = readBits(reader, 5) + 257; + /*number of distance codes. Unlike the spec, the value 1 is added to it here already*/ + HDIST = readBits(reader, 5) + 1; + /*number of code length codes. Unlike the spec, the value 4 is added to it here already*/ + HCLEN = readBits(reader, 4) + 4; + + bitlen_cl = (unsigned*)lodepng_malloc(NUM_CODE_LENGTH_CODES * sizeof(unsigned)); + if(!bitlen_cl) return 83 /*alloc fail*/; + + HuffmanTree_init(&tree_cl); + + while(!error) { + /*read the code length codes out of 3 * (amount of code length codes) bits*/ + if(lodepng_gtofl(reader->bp, HCLEN * 3, reader->bitsize)) { + ERROR_BREAK(50); /*error: the bit pointer is or will go past the memory*/ + } + for(i = 0; i != HCLEN; ++i) { + ensureBits9(reader, 3); /*out of bounds already checked above */ + bitlen_cl[CLCL_ORDER[i]] = readBits(reader, 3); + } + for(i = HCLEN; i != NUM_CODE_LENGTH_CODES; ++i) { + bitlen_cl[CLCL_ORDER[i]] = 0; + } + + error = HuffmanTree_makeFromLengths(&tree_cl, bitlen_cl, NUM_CODE_LENGTH_CODES, 7); + if(error) break; + + /*now we can use this tree to read the lengths for the tree that this function will return*/ + bitlen_ll = (unsigned*)lodepng_malloc(NUM_DEFLATE_CODE_SYMBOLS * sizeof(unsigned)); + bitlen_d = (unsigned*)lodepng_malloc(NUM_DISTANCE_SYMBOLS * sizeof(unsigned)); + if(!bitlen_ll || !bitlen_d) ERROR_BREAK(83 /*alloc fail*/); + lodepng_memset(bitlen_ll, 0, NUM_DEFLATE_CODE_SYMBOLS * sizeof(*bitlen_ll)); + lodepng_memset(bitlen_d, 0, NUM_DISTANCE_SYMBOLS * sizeof(*bitlen_d)); + + /*i is the current symbol we're reading in the part that contains the code lengths of lit/len and dist codes*/ + i = 0; + while(i < HLIT + HDIST) { + unsigned code; + ensureBits25(reader, 22); /* up to 15 bits for huffman code, up to 7 extra bits below*/ + code = huffmanDecodeSymbol(reader, &tree_cl); + if(code <= 15) /*a length code*/ { + if(i < HLIT) bitlen_ll[i] = code; + else bitlen_d[i - HLIT] = code; + ++i; + } else if(code == 16) /*repeat previous*/ { + unsigned replength = 3; /*read in the 2 bits that indicate repeat length (3-6)*/ + unsigned value; /*set value to the previous code*/ + + if(i == 0) ERROR_BREAK(54); /*can't repeat previous if i is 0*/ + + replength += readBits(reader, 2); + + if(i < HLIT + 1) value = bitlen_ll[i - 1]; + else value = bitlen_d[i - HLIT - 1]; + /*repeat this value in the next lengths*/ + for(n = 0; n < replength; ++n) { + if(i >= HLIT + HDIST) ERROR_BREAK(13); /*error: i is larger than the amount of codes*/ + if(i < HLIT) bitlen_ll[i] = value; + else bitlen_d[i - HLIT] = value; + ++i; + } + } else if(code == 17) /*repeat "0" 3-10 times*/ { + unsigned replength = 3; /*read in the bits that indicate repeat length*/ + replength += readBits(reader, 3); + + /*repeat this value in the next lengths*/ + for(n = 0; n < replength; ++n) { + if(i >= HLIT + HDIST) ERROR_BREAK(14); /*error: i is larger than the amount of codes*/ + + if(i < HLIT) bitlen_ll[i] = 0; + else bitlen_d[i - HLIT] = 0; + ++i; + } + } else if(code == 18) /*repeat "0" 11-138 times*/ { + unsigned replength = 11; /*read in the bits that indicate repeat length*/ + replength += readBits(reader, 7); + + /*repeat this value in the next lengths*/ + for(n = 0; n < replength; ++n) { + if(i >= HLIT + HDIST) ERROR_BREAK(15); /*error: i is larger than the amount of codes*/ + + if(i < HLIT) bitlen_ll[i] = 0; + else bitlen_d[i - HLIT] = 0; + ++i; + } + } else /*if(code == INVALIDSYMBOL)*/ { + ERROR_BREAK(16); /*error: tried to read disallowed huffman symbol*/ + } + /*check if any of the ensureBits above went out of bounds*/ + if(reader->bp > reader->bitsize) { + /*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol + (10=no endcode, 11=wrong jump outside of tree)*/ + /* TODO: revise error codes 10,11,50: the above comment is no longer valid */ + ERROR_BREAK(50); /*error, bit pointer jumps past memory*/ + } + } + if(error) break; + + if(bitlen_ll[256] == 0) ERROR_BREAK(64); /*the length of the end code 256 must be larger than 0*/ + + /*now we've finally got HLIT and HDIST, so generate the code trees, and the function is done*/ + error = HuffmanTree_makeFromLengths(tree_ll, bitlen_ll, NUM_DEFLATE_CODE_SYMBOLS, 15); + if(error) break; + error = HuffmanTree_makeFromLengths(tree_d, bitlen_d, NUM_DISTANCE_SYMBOLS, 15); + + break; /*end of error-while*/ + } + + lodepng_free(bitlen_cl); + lodepng_free(bitlen_ll); + lodepng_free(bitlen_d); + HuffmanTree_cleanup(&tree_cl); + + return error; +} + +/*inflate a block with dynamic of fixed Huffman tree. btype must be 1 or 2.*/ +static unsigned inflateHuffmanBlock(ucvector* out, LodePNGBitReader* reader, + unsigned btype, size_t max_output_size) { + unsigned error = 0; + HuffmanTree tree_ll; /*the huffman tree for literal and length codes*/ + HuffmanTree tree_d; /*the huffman tree for distance codes*/ + + HuffmanTree_init(&tree_ll); + HuffmanTree_init(&tree_d); + + if(btype == 1) error = getTreeInflateFixed(&tree_ll, &tree_d); + else /*if(btype == 2)*/ error = getTreeInflateDynamic(&tree_ll, &tree_d, reader); + + while(!error) /*decode all symbols until end reached, breaks at end code*/ { + /*code_ll is literal, length or end code*/ + unsigned code_ll; + ensureBits25(reader, 20); /* up to 15 for the huffman symbol, up to 5 for the length extra bits */ + code_ll = huffmanDecodeSymbol(reader, &tree_ll); + if(code_ll <= 255) /*literal symbol*/ { + if(!ucvector_resize(out, out->size + 1)) ERROR_BREAK(83 /*alloc fail*/); + out->data[out->size - 1] = (unsigned char)code_ll; + } else if(code_ll >= FIRST_LENGTH_CODE_INDEX && code_ll <= LAST_LENGTH_CODE_INDEX) /*length code*/ { + unsigned code_d, distance; + unsigned numextrabits_l, numextrabits_d; /*extra bits for length and distance*/ + size_t start, backward, length; + + /*part 1: get length base*/ + length = LENGTHBASE[code_ll - FIRST_LENGTH_CODE_INDEX]; + + /*part 2: get extra bits and add the value of that to length*/ + numextrabits_l = LENGTHEXTRA[code_ll - FIRST_LENGTH_CODE_INDEX]; + if(numextrabits_l != 0) { + /* bits already ensured above */ + length += readBits(reader, numextrabits_l); + } + + /*part 3: get distance code*/ + ensureBits32(reader, 28); /* up to 15 for the huffman symbol, up to 13 for the extra bits */ + code_d = huffmanDecodeSymbol(reader, &tree_d); + if(code_d > 29) { + if(code_d <= 31) { + ERROR_BREAK(18); /*error: invalid distance code (30-31 are never used)*/ + } else /* if(code_d == INVALIDSYMBOL) */{ + ERROR_BREAK(16); /*error: tried to read disallowed huffman symbol*/ + } + } + distance = DISTANCEBASE[code_d]; + + /*part 4: get extra bits from distance*/ + numextrabits_d = DISTANCEEXTRA[code_d]; + if(numextrabits_d != 0) { + /* bits already ensured above */ + distance += readBits(reader, numextrabits_d); + } + + /*part 5: fill in all the out[n] values based on the length and dist*/ + start = out->size; + if(distance > start) ERROR_BREAK(52); /*too long backward distance*/ + backward = start - distance; + + if(!ucvector_resize(out, out->size + length)) ERROR_BREAK(83 /*alloc fail*/); + if(distance < length) { + size_t forward; + lodepng_memcpy(out->data + start, out->data + backward, distance); + start += distance; + for(forward = distance; forward < length; ++forward) { + out->data[start++] = out->data[backward++]; + } + } else { + lodepng_memcpy(out->data + start, out->data + backward, length); + } + } else if(code_ll == 256) { + break; /*end code, break the loop*/ + } else /*if(code_ll == INVALIDSYMBOL)*/ { + ERROR_BREAK(16); /*error: tried to read disallowed huffman symbol*/ + } + /*check if any of the ensureBits above went out of bounds*/ + if(reader->bp > reader->bitsize) { + /*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol + (10=no endcode, 11=wrong jump outside of tree)*/ + /* TODO: revise error codes 10,11,50: the above comment is no longer valid */ + ERROR_BREAK(51); /*error, bit pointer jumps past memory*/ + } + if(max_output_size && out->size > max_output_size) { + ERROR_BREAK(109); /*error, larger than max size*/ + } + } + + HuffmanTree_cleanup(&tree_ll); + HuffmanTree_cleanup(&tree_d); + + return error; +} + +static unsigned inflateNoCompression(ucvector* out, LodePNGBitReader* reader, + const LodePNGDecompressSettings* settings) { + size_t bytepos; + size_t size = reader->size; + unsigned LEN, NLEN, error = 0; + + /*go to first boundary of byte*/ + bytepos = (reader->bp + 7u) >> 3u; + + /*read LEN (2 bytes) and NLEN (2 bytes)*/ + if(bytepos + 4 >= size) return 52; /*error, bit pointer will jump past memory*/ + LEN = (unsigned)reader->data[bytepos] + ((unsigned)reader->data[bytepos + 1] << 8u); bytepos += 2; + NLEN = (unsigned)reader->data[bytepos] + ((unsigned)reader->data[bytepos + 1] << 8u); bytepos += 2; + + /*check if 16-bit NLEN is really the one's complement of LEN*/ + if(!settings->ignore_nlen && LEN + NLEN != 65535) { + return 21; /*error: NLEN is not one's complement of LEN*/ + } + + if(!ucvector_resize(out, out->size + LEN)) return 83; /*alloc fail*/ + + /*read the literal data: LEN bytes are now stored in the out buffer*/ + if(bytepos + LEN > size) return 23; /*error: reading outside of in buffer*/ + + lodepng_memcpy(out->data + out->size - LEN, reader->data + bytepos, LEN); + bytepos += LEN; + + reader->bp = bytepos << 3u; + + return error; +} + +static unsigned lodepng_inflatev(ucvector* out, + const unsigned char* in, size_t insize, + const LodePNGDecompressSettings* settings) { + unsigned BFINAL = 0; + LodePNGBitReader reader; + unsigned error = LodePNGBitReader_init(&reader, in, insize); + + if(error) return error; + + while(!BFINAL) { + unsigned BTYPE; + if(!ensureBits9(&reader, 3)) return 52; /*error, bit pointer will jump past memory*/ + BFINAL = readBits(&reader, 1); + BTYPE = readBits(&reader, 2); + + if(BTYPE == 3) return 20; /*error: invalid BTYPE*/ + else if(BTYPE == 0) error = inflateNoCompression(out, &reader, settings); /*no compression*/ + else error = inflateHuffmanBlock(out, &reader, BTYPE, settings->max_output_size); /*compression, BTYPE 01 or 10*/ + if(!error && settings->max_output_size && out->size > settings->max_output_size) error = 109; + if(error) break; + } + + return error; +} + +unsigned lodepng_inflate(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGDecompressSettings* settings) { + ucvector v = ucvector_init(*out, *outsize); + unsigned error = lodepng_inflatev(&v, in, insize, settings); + *out = v.data; + *outsize = v.size; + return error; +} + +static unsigned inflatev(ucvector* out, const unsigned char* in, size_t insize, + const LodePNGDecompressSettings* settings) { + if(settings->custom_inflate) { + unsigned error = settings->custom_inflate(&out->data, &out->size, in, insize, settings); + out->allocsize = out->size; + if(error) { + /*the custom inflate is allowed to have its own error codes, however, we translate it to code 110*/ + error = 110; + /*if there's a max output size, and the custom zlib returned error, then indicate that error instead*/ + if(settings->max_output_size && out->size > settings->max_output_size) error = 109; + } + return error; + } else { + return lodepng_inflatev(out, in, insize, settings); + } +} + +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Deflator (Compressor) / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +static const size_t MAX_SUPPORTED_DEFLATE_LENGTH = 258; + +/*search the index in the array, that has the largest value smaller than or equal to the given value, +given array must be sorted (if no value is smaller, it returns the size of the given array)*/ +static size_t searchCodeIndex(const unsigned* array, size_t array_size, size_t value) { + /*binary search (only small gain over linear). TODO: use CPU log2 instruction for getting symbols instead*/ + size_t left = 1; + size_t right = array_size - 1; + + while(left <= right) { + size_t mid = (left + right) >> 1; + if(array[mid] >= value) right = mid - 1; + else left = mid + 1; + } + if(left >= array_size || array[left] > value) left--; + return left; +} + +static void addLengthDistance(uivector* values, size_t length, size_t distance) { + /*values in encoded vector are those used by deflate: + 0-255: literal bytes + 256: end + 257-285: length/distance pair (length code, followed by extra length bits, distance code, extra distance bits) + 286-287: invalid*/ + + unsigned length_code = (unsigned)searchCodeIndex(LENGTHBASE, 29, length); + unsigned extra_length = (unsigned)(length - LENGTHBASE[length_code]); + unsigned dist_code = (unsigned)searchCodeIndex(DISTANCEBASE, 30, distance); + unsigned extra_distance = (unsigned)(distance - DISTANCEBASE[dist_code]); + + size_t pos = values->size; + /*TODO: return error when this fails (out of memory)*/ + unsigned ok = uivector_resize(values, values->size + 4); + if(ok) { + values->data[pos + 0] = length_code + FIRST_LENGTH_CODE_INDEX; + values->data[pos + 1] = extra_length; + values->data[pos + 2] = dist_code; + values->data[pos + 3] = extra_distance; + } +} + +/*3 bytes of data get encoded into two bytes. The hash cannot use more than 3 +bytes as input because 3 is the minimum match length for deflate*/ +static const unsigned HASH_NUM_VALUES = 65536; +static const unsigned HASH_BIT_MASK = 65535; /*HASH_NUM_VALUES - 1, but C90 does not like that as initializer*/ + +typedef struct Hash { + int* head; /*hash value to head circular pos - can be outdated if went around window*/ + /*circular pos to prev circular pos*/ + unsigned short* chain; + int* val; /*circular pos to hash value*/ + + /*TODO: do this not only for zeros but for any repeated byte. However for PNG + it's always going to be the zeros that dominate, so not important for PNG*/ + int* headz; /*similar to head, but for chainz*/ + unsigned short* chainz; /*those with same amount of zeros*/ + unsigned short* zeros; /*length of zeros streak, used as a second hash chain*/ +} Hash; + +static unsigned hash_init(Hash* hash, unsigned windowsize) { + unsigned i; + hash->head = (int*)lodepng_malloc(sizeof(int) * HASH_NUM_VALUES); + hash->val = (int*)lodepng_malloc(sizeof(int) * windowsize); + hash->chain = (unsigned short*)lodepng_malloc(sizeof(unsigned short) * windowsize); + + hash->zeros = (unsigned short*)lodepng_malloc(sizeof(unsigned short) * windowsize); + hash->headz = (int*)lodepng_malloc(sizeof(int) * (MAX_SUPPORTED_DEFLATE_LENGTH + 1)); + hash->chainz = (unsigned short*)lodepng_malloc(sizeof(unsigned short) * windowsize); + + if(!hash->head || !hash->chain || !hash->val || !hash->headz|| !hash->chainz || !hash->zeros) { + return 83; /*alloc fail*/ + } + + /*initialize hash table*/ + for(i = 0; i != HASH_NUM_VALUES; ++i) hash->head[i] = -1; + for(i = 0; i != windowsize; ++i) hash->val[i] = -1; + for(i = 0; i != windowsize; ++i) hash->chain[i] = i; /*same value as index indicates uninitialized*/ + + for(i = 0; i <= MAX_SUPPORTED_DEFLATE_LENGTH; ++i) hash->headz[i] = -1; + for(i = 0; i != windowsize; ++i) hash->chainz[i] = i; /*same value as index indicates uninitialized*/ + + return 0; +} + +static void hash_cleanup(Hash* hash) { + lodepng_free(hash->head); + lodepng_free(hash->val); + lodepng_free(hash->chain); + + lodepng_free(hash->zeros); + lodepng_free(hash->headz); + lodepng_free(hash->chainz); +} + + + +static unsigned getHash(const unsigned char* data, size_t size, size_t pos) { + unsigned result = 0; + if(pos + 2 < size) { + /*A simple shift and xor hash is used. Since the data of PNGs is dominated + by zeroes due to the filters, a better hash does not have a significant + effect on speed in traversing the chain, and causes more time spend on + calculating the hash.*/ + result ^= ((unsigned)data[pos + 0] << 0u); + result ^= ((unsigned)data[pos + 1] << 4u); + result ^= ((unsigned)data[pos + 2] << 8u); + } else { + size_t amount, i; + if(pos >= size) return 0; + amount = size - pos; + for(i = 0; i != amount; ++i) result ^= ((unsigned)data[pos + i] << (i * 8u)); + } + return result & HASH_BIT_MASK; +} + +static unsigned countZeros(const unsigned char* data, size_t size, size_t pos) { + const unsigned char* start = data + pos; + const unsigned char* end = start + MAX_SUPPORTED_DEFLATE_LENGTH; + if(end > data + size) end = data + size; + data = start; + while(data != end && *data == 0) ++data; + /*subtracting two addresses returned as 32-bit number (max value is MAX_SUPPORTED_DEFLATE_LENGTH)*/ + return (unsigned)(data - start); +} + +/*wpos = pos & (windowsize - 1)*/ +static void updateHashChain(Hash* hash, size_t wpos, unsigned hashval, unsigned short numzeros) { + hash->val[wpos] = (int)hashval; + if(hash->head[hashval] != -1) hash->chain[wpos] = hash->head[hashval]; + hash->head[hashval] = (int)wpos; + + hash->zeros[wpos] = numzeros; + if(hash->headz[numzeros] != -1) hash->chainz[wpos] = hash->headz[numzeros]; + hash->headz[numzeros] = (int)wpos; +} + +/* +LZ77-encode the data. Return value is error code. The input are raw bytes, the output +is in the form of unsigned integers with codes representing for example literal bytes, or +length/distance pairs. +It uses a hash table technique to let it encode faster. When doing LZ77 encoding, a +sliding window (of windowsize) is used, and all past bytes in that window can be used as +the "dictionary". A brute force search through all possible distances would be slow, and +this hash technique is one out of several ways to speed this up. +*/ +static unsigned encodeLZ77(uivector* out, Hash* hash, + const unsigned char* in, size_t inpos, size_t insize, unsigned windowsize, + unsigned minmatch, unsigned nicematch, unsigned lazymatching) { + size_t pos; + unsigned i, error = 0; + /*for large window lengths, assume the user wants no compression loss. Otherwise, max hash chain length speedup.*/ + unsigned maxchainlength = windowsize >= 8192 ? windowsize : windowsize / 8u; + unsigned maxlazymatch = windowsize >= 8192 ? MAX_SUPPORTED_DEFLATE_LENGTH : 64; + + unsigned usezeros = 1; /*not sure if setting it to false for windowsize < 8192 is better or worse*/ + unsigned numzeros = 0; + + unsigned offset; /*the offset represents the distance in LZ77 terminology*/ + unsigned length; + unsigned lazy = 0; + unsigned lazylength = 0, lazyoffset = 0; + unsigned hashval; + unsigned current_offset, current_length; + unsigned prev_offset; + const unsigned char *lastptr, *foreptr, *backptr; + unsigned hashpos; + + if(windowsize == 0 || windowsize > 32768) return 60; /*error: windowsize smaller/larger than allowed*/ + if((windowsize & (windowsize - 1)) != 0) return 90; /*error: must be power of two*/ + + if(nicematch > MAX_SUPPORTED_DEFLATE_LENGTH) nicematch = MAX_SUPPORTED_DEFLATE_LENGTH; + + for(pos = inpos; pos < insize; ++pos) { + size_t wpos = pos & (windowsize - 1); /*position for in 'circular' hash buffers*/ + unsigned chainlength = 0; + + hashval = getHash(in, insize, pos); + + if(usezeros && hashval == 0) { + if(numzeros == 0) numzeros = countZeros(in, insize, pos); + else if(pos + numzeros > insize || in[pos + numzeros - 1] != 0) --numzeros; + } else { + numzeros = 0; + } + + updateHashChain(hash, wpos, hashval, numzeros); + + /*the length and offset found for the current position*/ + length = 0; + offset = 0; + + hashpos = hash->chain[wpos]; + + lastptr = &in[insize < pos + MAX_SUPPORTED_DEFLATE_LENGTH ? insize : pos + MAX_SUPPORTED_DEFLATE_LENGTH]; + + /*search for the longest string*/ + prev_offset = 0; + for(;;) { + if(chainlength++ >= maxchainlength) break; + current_offset = (unsigned)(hashpos <= wpos ? wpos - hashpos : wpos - hashpos + windowsize); + + if(current_offset < prev_offset) break; /*stop when went completely around the circular buffer*/ + prev_offset = current_offset; + if(current_offset > 0) { + /*test the next characters*/ + foreptr = &in[pos]; + backptr = &in[pos - current_offset]; + + /*common case in PNGs is lots of zeros. Quickly skip over them as a speedup*/ + if(numzeros >= 3) { + unsigned skip = hash->zeros[hashpos]; + if(skip > numzeros) skip = numzeros; + backptr += skip; + foreptr += skip; + } + + while(foreptr != lastptr && *backptr == *foreptr) /*maximum supported length by deflate is max length*/ { + ++backptr; + ++foreptr; + } + current_length = (unsigned)(foreptr - &in[pos]); + + if(current_length > length) { + length = current_length; /*the longest length*/ + offset = current_offset; /*the offset that is related to this longest length*/ + /*jump out once a length of max length is found (speed gain). This also jumps + out if length is MAX_SUPPORTED_DEFLATE_LENGTH*/ + if(current_length >= nicematch) break; + } + } + + if(hashpos == hash->chain[hashpos]) break; + + if(numzeros >= 3 && length > numzeros) { + hashpos = hash->chainz[hashpos]; + if(hash->zeros[hashpos] != numzeros) break; + } else { + hashpos = hash->chain[hashpos]; + /*outdated hash value, happens if particular value was not encountered in whole last window*/ + if(hash->val[hashpos] != (int)hashval) break; + } + } + + if(lazymatching) { + if(!lazy && length >= 3 && length <= maxlazymatch && length < MAX_SUPPORTED_DEFLATE_LENGTH) { + lazy = 1; + lazylength = length; + lazyoffset = offset; + continue; /*try the next byte*/ + } + if(lazy) { + lazy = 0; + if(pos == 0) ERROR_BREAK(81); + if(length > lazylength + 1) { + /*push the previous character as literal*/ + if(!uivector_push_back(out, in[pos - 1])) ERROR_BREAK(83 /*alloc fail*/); + } else { + length = lazylength; + offset = lazyoffset; + hash->head[hashval] = -1; /*the same hashchain update will be done, this ensures no wrong alteration*/ + hash->headz[numzeros] = -1; /*idem*/ + --pos; + } + } + } + if(length >= 3 && offset > windowsize) ERROR_BREAK(86 /*too big (or overflown negative) offset*/); + + /*encode it as length/distance pair or literal value*/ + if(length < 3) /*only lengths of 3 or higher are supported as length/distance pair*/ { + if(!uivector_push_back(out, in[pos])) ERROR_BREAK(83 /*alloc fail*/); + } else if(length < minmatch || (length == 3 && offset > 4096)) { + /*compensate for the fact that longer offsets have more extra bits, a + length of only 3 may be not worth it then*/ + if(!uivector_push_back(out, in[pos])) ERROR_BREAK(83 /*alloc fail*/); + } else { + addLengthDistance(out, length, offset); + for(i = 1; i < length; ++i) { + ++pos; + wpos = pos & (windowsize - 1); + hashval = getHash(in, insize, pos); + if(usezeros && hashval == 0) { + if(numzeros == 0) numzeros = countZeros(in, insize, pos); + else if(pos + numzeros > insize || in[pos + numzeros - 1] != 0) --numzeros; + } else { + numzeros = 0; + } + updateHashChain(hash, wpos, hashval, numzeros); + } + } + } /*end of the loop through each character of input*/ + + return error; +} + +/* /////////////////////////////////////////////////////////////////////////// */ + +static unsigned deflateNoCompression(ucvector* out, const unsigned char* data, size_t datasize) { + /*non compressed deflate block data: 1 bit BFINAL,2 bits BTYPE,(5 bits): it jumps to start of next byte, + 2 bytes LEN, 2 bytes NLEN, LEN bytes literal DATA*/ + + size_t i, numdeflateblocks = (datasize + 65534u) / 65535u; + unsigned datapos = 0; + for(i = 0; i != numdeflateblocks; ++i) { + unsigned BFINAL, BTYPE, LEN, NLEN; + unsigned char firstbyte; + size_t pos = out->size; + + BFINAL = (i == numdeflateblocks - 1); + BTYPE = 0; + + LEN = 65535; + if(datasize - datapos < 65535u) LEN = (unsigned)datasize - datapos; + NLEN = 65535 - LEN; + + if(!ucvector_resize(out, out->size + LEN + 5)) return 83; /*alloc fail*/ + + firstbyte = (unsigned char)(BFINAL + ((BTYPE & 1u) << 1u) + ((BTYPE & 2u) << 1u)); + out->data[pos + 0] = firstbyte; + out->data[pos + 1] = (unsigned char)(LEN & 255); + out->data[pos + 2] = (unsigned char)(LEN >> 8u); + out->data[pos + 3] = (unsigned char)(NLEN & 255); + out->data[pos + 4] = (unsigned char)(NLEN >> 8u); + lodepng_memcpy(out->data + pos + 5, data + datapos, LEN); + datapos += LEN; + } + + return 0; +} + +/* +write the lz77-encoded data, which has lit, len and dist codes, to compressed stream using huffman trees. +tree_ll: the tree for lit and len codes. +tree_d: the tree for distance codes. +*/ +static void writeLZ77data(LodePNGBitWriter* writer, const uivector* lz77_encoded, + const HuffmanTree* tree_ll, const HuffmanTree* tree_d) { + size_t i = 0; + for(i = 0; i != lz77_encoded->size; ++i) { + unsigned val = lz77_encoded->data[i]; + writeBitsReversed(writer, tree_ll->codes[val], tree_ll->lengths[val]); + if(val > 256) /*for a length code, 3 more things have to be added*/ { + unsigned length_index = val - FIRST_LENGTH_CODE_INDEX; + unsigned n_length_extra_bits = LENGTHEXTRA[length_index]; + unsigned length_extra_bits = lz77_encoded->data[++i]; + + unsigned distance_code = lz77_encoded->data[++i]; + + unsigned distance_index = distance_code; + unsigned n_distance_extra_bits = DISTANCEEXTRA[distance_index]; + unsigned distance_extra_bits = lz77_encoded->data[++i]; + + writeBits(writer, length_extra_bits, n_length_extra_bits); + writeBitsReversed(writer, tree_d->codes[distance_code], tree_d->lengths[distance_code]); + writeBits(writer, distance_extra_bits, n_distance_extra_bits); + } + } +} + +/*Deflate for a block of type "dynamic", that is, with freely, optimally, created huffman trees*/ +static unsigned deflateDynamic(LodePNGBitWriter* writer, Hash* hash, + const unsigned char* data, size_t datapos, size_t dataend, + const LodePNGCompressSettings* settings, unsigned final) { + unsigned error = 0; + + /* + A block is compressed as follows: The PNG data is lz77 encoded, resulting in + literal bytes and length/distance pairs. This is then huffman compressed with + two huffman trees. One huffman tree is used for the lit and len values ("ll"), + another huffman tree is used for the dist values ("d"). These two trees are + stored using their code lengths, and to compress even more these code lengths + are also run-length encoded and huffman compressed. This gives a huffman tree + of code lengths "cl". The code lengths used to describe this third tree are + the code length code lengths ("clcl"). + */ + + /*The lz77 encoded data, represented with integers since there will also be length and distance codes in it*/ + uivector lz77_encoded; + HuffmanTree tree_ll; /*tree for lit,len values*/ + HuffmanTree tree_d; /*tree for distance codes*/ + HuffmanTree tree_cl; /*tree for encoding the code lengths representing tree_ll and tree_d*/ + unsigned* frequencies_ll = 0; /*frequency of lit,len codes*/ + unsigned* frequencies_d = 0; /*frequency of dist codes*/ + unsigned* frequencies_cl = 0; /*frequency of code length codes*/ + unsigned* bitlen_lld = 0; /*lit,len,dist code lengths (int bits), literally (without repeat codes).*/ + unsigned* bitlen_lld_e = 0; /*bitlen_lld encoded with repeat codes (this is a rudimentary run length compression)*/ + size_t datasize = dataend - datapos; + + /* + If we could call "bitlen_cl" the the code length code lengths ("clcl"), that is the bit lengths of codes to represent + tree_cl in CLCL_ORDER, then due to the huffman compression of huffman tree representations ("two levels"), there are + some analogies: + bitlen_lld is to tree_cl what data is to tree_ll and tree_d. + bitlen_lld_e is to bitlen_lld what lz77_encoded is to data. + bitlen_cl is to bitlen_lld_e what bitlen_lld is to lz77_encoded. + */ + + unsigned BFINAL = final; + size_t i; + size_t numcodes_ll, numcodes_d, numcodes_lld, numcodes_lld_e, numcodes_cl; + unsigned HLIT, HDIST, HCLEN; + + uivector_init(&lz77_encoded); + HuffmanTree_init(&tree_ll); + HuffmanTree_init(&tree_d); + HuffmanTree_init(&tree_cl); + /* could fit on stack, but >1KB is on the larger side so allocate instead */ + frequencies_ll = (unsigned*)lodepng_malloc(286 * sizeof(*frequencies_ll)); + frequencies_d = (unsigned*)lodepng_malloc(30 * sizeof(*frequencies_d)); + frequencies_cl = (unsigned*)lodepng_malloc(NUM_CODE_LENGTH_CODES * sizeof(*frequencies_cl)); + + if(!frequencies_ll || !frequencies_d || !frequencies_cl) error = 83; /*alloc fail*/ + + /*This while loop never loops due to a break at the end, it is here to + allow breaking out of it to the cleanup phase on error conditions.*/ + while(!error) { + lodepng_memset(frequencies_ll, 0, 286 * sizeof(*frequencies_ll)); + lodepng_memset(frequencies_d, 0, 30 * sizeof(*frequencies_d)); + lodepng_memset(frequencies_cl, 0, NUM_CODE_LENGTH_CODES * sizeof(*frequencies_cl)); + + if(settings->use_lz77) { + error = encodeLZ77(&lz77_encoded, hash, data, datapos, dataend, settings->windowsize, + settings->minmatch, settings->nicematch, settings->lazymatching); + if(error) break; + } else { + if(!uivector_resize(&lz77_encoded, datasize)) ERROR_BREAK(83 /*alloc fail*/); + for(i = datapos; i < dataend; ++i) lz77_encoded.data[i - datapos] = data[i]; /*no LZ77, but still will be Huffman compressed*/ + } + + /*Count the frequencies of lit, len and dist codes*/ + for(i = 0; i != lz77_encoded.size; ++i) { + unsigned symbol = lz77_encoded.data[i]; + ++frequencies_ll[symbol]; + if(symbol > 256) { + unsigned dist = lz77_encoded.data[i + 2]; + ++frequencies_d[dist]; + i += 3; + } + } + frequencies_ll[256] = 1; /*there will be exactly 1 end code, at the end of the block*/ + + /*Make both huffman trees, one for the lit and len codes, one for the dist codes*/ + error = HuffmanTree_makeFromFrequencies(&tree_ll, frequencies_ll, 257, 286, 15); + if(error) break; + /*2, not 1, is chosen for mincodes: some buggy PNG decoders require at least 2 symbols in the dist tree*/ + error = HuffmanTree_makeFromFrequencies(&tree_d, frequencies_d, 2, 30, 15); + if(error) break; + + numcodes_ll = LODEPNG_MIN(tree_ll.numcodes, 286); + numcodes_d = LODEPNG_MIN(tree_d.numcodes, 30); + /*store the code lengths of both generated trees in bitlen_lld*/ + numcodes_lld = numcodes_ll + numcodes_d; + bitlen_lld = (unsigned*)lodepng_malloc(numcodes_lld * sizeof(*bitlen_lld)); + /*numcodes_lld_e never needs more size than bitlen_lld*/ + bitlen_lld_e = (unsigned*)lodepng_malloc(numcodes_lld * sizeof(*bitlen_lld_e)); + if(!bitlen_lld || !bitlen_lld_e) ERROR_BREAK(83); /*alloc fail*/ + numcodes_lld_e = 0; + + for(i = 0; i != numcodes_ll; ++i) bitlen_lld[i] = tree_ll.lengths[i]; + for(i = 0; i != numcodes_d; ++i) bitlen_lld[numcodes_ll + i] = tree_d.lengths[i]; + + /*run-length compress bitlen_ldd into bitlen_lld_e by using repeat codes 16 (copy length 3-6 times), + 17 (3-10 zeroes), 18 (11-138 zeroes)*/ + for(i = 0; i != numcodes_lld; ++i) { + unsigned j = 0; /*amount of repetitions*/ + while(i + j + 1 < numcodes_lld && bitlen_lld[i + j + 1] == bitlen_lld[i]) ++j; + + if(bitlen_lld[i] == 0 && j >= 2) /*repeat code for zeroes*/ { + ++j; /*include the first zero*/ + if(j <= 10) /*repeat code 17 supports max 10 zeroes*/ { + bitlen_lld_e[numcodes_lld_e++] = 17; + bitlen_lld_e[numcodes_lld_e++] = j - 3; + } else /*repeat code 18 supports max 138 zeroes*/ { + if(j > 138) j = 138; + bitlen_lld_e[numcodes_lld_e++] = 18; + bitlen_lld_e[numcodes_lld_e++] = j - 11; + } + i += (j - 1); + } else if(j >= 3) /*repeat code for value other than zero*/ { + size_t k; + unsigned num = j / 6u, rest = j % 6u; + bitlen_lld_e[numcodes_lld_e++] = bitlen_lld[i]; + for(k = 0; k < num; ++k) { + bitlen_lld_e[numcodes_lld_e++] = 16; + bitlen_lld_e[numcodes_lld_e++] = 6 - 3; + } + if(rest >= 3) { + bitlen_lld_e[numcodes_lld_e++] = 16; + bitlen_lld_e[numcodes_lld_e++] = rest - 3; + } + else j -= rest; + i += j; + } else /*too short to benefit from repeat code*/ { + bitlen_lld_e[numcodes_lld_e++] = bitlen_lld[i]; + } + } + + /*generate tree_cl, the huffmantree of huffmantrees*/ + for(i = 0; i != numcodes_lld_e; ++i) { + ++frequencies_cl[bitlen_lld_e[i]]; + /*after a repeat code come the bits that specify the number of repetitions, + those don't need to be in the frequencies_cl calculation*/ + if(bitlen_lld_e[i] >= 16) ++i; + } + + error = HuffmanTree_makeFromFrequencies(&tree_cl, frequencies_cl, + NUM_CODE_LENGTH_CODES, NUM_CODE_LENGTH_CODES, 7); + if(error) break; + + /*compute amount of code-length-code-lengths to output*/ + numcodes_cl = NUM_CODE_LENGTH_CODES; + /*trim zeros at the end (using CLCL_ORDER), but minimum size must be 4 (see HCLEN below)*/ + while(numcodes_cl > 4u && tree_cl.lengths[CLCL_ORDER[numcodes_cl - 1u]] == 0) { + numcodes_cl--; + } + + /* + Write everything into the output + + After the BFINAL and BTYPE, the dynamic block consists out of the following: + - 5 bits HLIT, 5 bits HDIST, 4 bits HCLEN + - (HCLEN+4)*3 bits code lengths of code length alphabet + - HLIT + 257 code lengths of lit/length alphabet (encoded using the code length + alphabet, + possible repetition codes 16, 17, 18) + - HDIST + 1 code lengths of distance alphabet (encoded using the code length + alphabet, + possible repetition codes 16, 17, 18) + - compressed data + - 256 (end code) + */ + + /*Write block type*/ + writeBits(writer, BFINAL, 1); + writeBits(writer, 0, 1); /*first bit of BTYPE "dynamic"*/ + writeBits(writer, 1, 1); /*second bit of BTYPE "dynamic"*/ + + /*write the HLIT, HDIST and HCLEN values*/ + /*all three sizes take trimmed ending zeroes into account, done either by HuffmanTree_makeFromFrequencies + or in the loop for numcodes_cl above, which saves space. */ + HLIT = (unsigned)(numcodes_ll - 257); + HDIST = (unsigned)(numcodes_d - 1); + HCLEN = (unsigned)(numcodes_cl - 4); + writeBits(writer, HLIT, 5); + writeBits(writer, HDIST, 5); + writeBits(writer, HCLEN, 4); + + /*write the code lengths of the code length alphabet ("bitlen_cl")*/ + for(i = 0; i != numcodes_cl; ++i) writeBits(writer, tree_cl.lengths[CLCL_ORDER[i]], 3); + + /*write the lengths of the lit/len AND the dist alphabet*/ + for(i = 0; i != numcodes_lld_e; ++i) { + writeBitsReversed(writer, tree_cl.codes[bitlen_lld_e[i]], tree_cl.lengths[bitlen_lld_e[i]]); + /*extra bits of repeat codes*/ + if(bitlen_lld_e[i] == 16) writeBits(writer, bitlen_lld_e[++i], 2); + else if(bitlen_lld_e[i] == 17) writeBits(writer, bitlen_lld_e[++i], 3); + else if(bitlen_lld_e[i] == 18) writeBits(writer, bitlen_lld_e[++i], 7); + } + + /*write the compressed data symbols*/ + writeLZ77data(writer, &lz77_encoded, &tree_ll, &tree_d); + /*error: the length of the end code 256 must be larger than 0*/ + if(tree_ll.lengths[256] == 0) ERROR_BREAK(64); + + /*write the end code*/ + writeBitsReversed(writer, tree_ll.codes[256], tree_ll.lengths[256]); + + break; /*end of error-while*/ + } + + /*cleanup*/ + uivector_cleanup(&lz77_encoded); + HuffmanTree_cleanup(&tree_ll); + HuffmanTree_cleanup(&tree_d); + HuffmanTree_cleanup(&tree_cl); + lodepng_free(frequencies_ll); + lodepng_free(frequencies_d); + lodepng_free(frequencies_cl); + lodepng_free(bitlen_lld); + lodepng_free(bitlen_lld_e); + + return error; +} + +static unsigned deflateFixed(LodePNGBitWriter* writer, Hash* hash, + const unsigned char* data, + size_t datapos, size_t dataend, + const LodePNGCompressSettings* settings, unsigned final) { + HuffmanTree tree_ll; /*tree for literal values and length codes*/ + HuffmanTree tree_d; /*tree for distance codes*/ + + unsigned BFINAL = final; + unsigned error = 0; + size_t i; + + HuffmanTree_init(&tree_ll); + HuffmanTree_init(&tree_d); + + error = generateFixedLitLenTree(&tree_ll); + if(!error) error = generateFixedDistanceTree(&tree_d); + + if(!error) { + writeBits(writer, BFINAL, 1); + writeBits(writer, 1, 1); /*first bit of BTYPE*/ + writeBits(writer, 0, 1); /*second bit of BTYPE*/ + + if(settings->use_lz77) /*LZ77 encoded*/ { + uivector lz77_encoded; + uivector_init(&lz77_encoded); + error = encodeLZ77(&lz77_encoded, hash, data, datapos, dataend, settings->windowsize, + settings->minmatch, settings->nicematch, settings->lazymatching); + if(!error) writeLZ77data(writer, &lz77_encoded, &tree_ll, &tree_d); + uivector_cleanup(&lz77_encoded); + } else /*no LZ77, but still will be Huffman compressed*/ { + for(i = datapos; i < dataend; ++i) { + writeBitsReversed(writer, tree_ll.codes[data[i]], tree_ll.lengths[data[i]]); + } + } + /*add END code*/ + if(!error) writeBitsReversed(writer,tree_ll.codes[256], tree_ll.lengths[256]); + } + + /*cleanup*/ + HuffmanTree_cleanup(&tree_ll); + HuffmanTree_cleanup(&tree_d); + + return error; +} + +static unsigned lodepng_deflatev(ucvector* out, const unsigned char* in, size_t insize, + const LodePNGCompressSettings* settings) { + unsigned error = 0; + size_t i, blocksize, numdeflateblocks; + Hash hash; + LodePNGBitWriter writer; + + LodePNGBitWriter_init(&writer, out); + + if(settings->btype > 2) return 61; + else if(settings->btype == 0) return deflateNoCompression(out, in, insize); + else if(settings->btype == 1) blocksize = insize; + else /*if(settings->btype == 2)*/ { + /*on PNGs, deflate blocks of 65-262k seem to give most dense encoding*/ + blocksize = insize / 8u + 8; + if(blocksize < 65536) blocksize = 65536; + if(blocksize > 262144) blocksize = 262144; + } + + numdeflateblocks = (insize + blocksize - 1) / blocksize; + if(numdeflateblocks == 0) numdeflateblocks = 1; + + error = hash_init(&hash, settings->windowsize); + + if(!error) { + for(i = 0; i != numdeflateblocks && !error; ++i) { + unsigned final = (i == numdeflateblocks - 1); + size_t start = i * blocksize; + size_t end = start + blocksize; + if(end > insize) end = insize; + + if(settings->btype == 1) error = deflateFixed(&writer, &hash, in, start, end, settings, final); + else if(settings->btype == 2) error = deflateDynamic(&writer, &hash, in, start, end, settings, final); + } + } + + hash_cleanup(&hash); + + return error; +} + +unsigned lodepng_deflate(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGCompressSettings* settings) { + ucvector v = ucvector_init(*out, *outsize); + unsigned error = lodepng_deflatev(&v, in, insize, settings); + *out = v.data; + *outsize = v.size; + return error; +} + +static unsigned deflate(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGCompressSettings* settings) { + if(settings->custom_deflate) { + unsigned error = settings->custom_deflate(out, outsize, in, insize, settings); + /*the custom deflate is allowed to have its own error codes, however, we translate it to code 111*/ + return error ? 111 : 0; + } else { + return lodepng_deflate(out, outsize, in, insize, settings); + } +} + +#endif /*LODEPNG_COMPILE_DECODER*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Adler32 / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +static unsigned update_adler32(unsigned adler, const unsigned char* data, unsigned len) { + unsigned s1 = adler & 0xffffu; + unsigned s2 = (adler >> 16u) & 0xffffu; + + while(len != 0u) { + unsigned i; + /*at least 5552 sums can be done before the sums overflow, saving a lot of module divisions*/ + unsigned amount = len > 5552u ? 5552u : len; + len -= amount; + for(i = 0; i != amount; ++i) { + s1 += (*data++); + s2 += s1; + } + s1 %= 65521u; + s2 %= 65521u; + } + + return (s2 << 16u) | s1; +} + +/*Return the adler32 of the bytes data[0..len-1]*/ +static unsigned adler32(const unsigned char* data, unsigned len) { + return update_adler32(1u, data, len); +} + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Zlib / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_DECODER + +static unsigned lodepng_zlib_decompressv(ucvector* out, + const unsigned char* in, size_t insize, + const LodePNGDecompressSettings* settings) { + unsigned error = 0; + unsigned CM, CINFO, FDICT; + + if(insize < 2) return 53; /*error, size of zlib data too small*/ + /*read information from zlib header*/ + if((in[0] * 256 + in[1]) % 31 != 0) { + /*error: 256 * in[0] + in[1] must be a multiple of 31, the FCHECK value is supposed to be made that way*/ + return 24; + } + + CM = in[0] & 15; + CINFO = (in[0] >> 4) & 15; + /*FCHECK = in[1] & 31;*/ /*FCHECK is already tested above*/ + FDICT = (in[1] >> 5) & 1; + /*FLEVEL = (in[1] >> 6) & 3;*/ /*FLEVEL is not used here*/ + + if(CM != 8 || CINFO > 7) { + /*error: only compression method 8: inflate with sliding window of 32k is supported by the PNG spec*/ + return 25; + } + if(FDICT != 0) { + /*error: the specification of PNG says about the zlib stream: + "The additional flags shall not specify a preset dictionary."*/ + return 26; + } + + error = inflatev(out, in + 2, insize - 2, settings); + if(error) return error; + + if(!settings->ignore_adler32) { + unsigned ADLER32 = lodepng_read32bitInt(&in[insize - 4]); + unsigned checksum = adler32(out->data, (unsigned)(out->size)); + if(checksum != ADLER32) return 58; /*error, adler checksum not correct, data must be corrupted*/ + } + + return 0; /*no error*/ +} + + +unsigned lodepng_zlib_decompress(unsigned char** out, size_t* outsize, const unsigned char* in, + size_t insize, const LodePNGDecompressSettings* settings) { + ucvector v = ucvector_init(*out, *outsize); + unsigned error = lodepng_zlib_decompressv(&v, in, insize, settings); + *out = v.data; + *outsize = v.size; + return error; +} + +/*expected_size is expected output size, to avoid intermediate allocations. Set to 0 if not known. */ +static unsigned zlib_decompress(unsigned char** out, size_t* outsize, size_t expected_size, + const unsigned char* in, size_t insize, const LodePNGDecompressSettings* settings) { + unsigned error; + if(settings->custom_zlib) { + error = settings->custom_zlib(out, outsize, in, insize, settings); + if(error) { + /*the custom zlib is allowed to have its own error codes, however, we translate it to code 110*/ + error = 110; + /*if there's a max output size, and the custom zlib returned error, then indicate that error instead*/ + if(settings->max_output_size && *outsize > settings->max_output_size) error = 109; + } + } else { + ucvector v = ucvector_init(*out, *outsize); + if(expected_size) { + /*reserve the memory to avoid intermediate reallocations*/ + ucvector_resize(&v, *outsize + expected_size); + v.size = *outsize; + } + error = lodepng_zlib_decompressv(&v, in, insize, settings); + *out = v.data; + *outsize = v.size; + } + return error; +} + +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER + +unsigned lodepng_zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in, + size_t insize, const LodePNGCompressSettings* settings) { + size_t i; + unsigned error; + unsigned char* deflatedata = 0; + size_t deflatesize = 0; + + error = deflate(&deflatedata, &deflatesize, in, insize, settings); + + *out = NULL; + *outsize = 0; + if(!error) { + *outsize = deflatesize + 6; + *out = (unsigned char*)lodepng_malloc(*outsize); + if(!*out) error = 83; /*alloc fail*/ + } + + if(!error) { + unsigned ADLER32 = adler32(in, (unsigned)insize); + /*zlib data: 1 byte CMF (CM+CINFO), 1 byte FLG, deflate data, 4 byte ADLER32 checksum of the Decompressed data*/ + unsigned CMF = 120; /*0b01111000: CM 8, CINFO 7. With CINFO 7, any window size up to 32768 can be used.*/ + unsigned FLEVEL = 0; + unsigned FDICT = 0; + unsigned CMFFLG = 256 * CMF + FDICT * 32 + FLEVEL * 64; + unsigned FCHECK = 31 - CMFFLG % 31; + CMFFLG += FCHECK; + + (*out)[0] = (unsigned char)(CMFFLG >> 8); + (*out)[1] = (unsigned char)(CMFFLG & 255); + for(i = 0; i != deflatesize; ++i) (*out)[i + 2] = deflatedata[i]; + lodepng_set32bitInt(&(*out)[*outsize - 4], ADLER32); + } + + lodepng_free(deflatedata); + return error; +} + +/* compress using the default or custom zlib function */ +static unsigned zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in, + size_t insize, const LodePNGCompressSettings* settings) { + if(settings->custom_zlib) { + unsigned error = settings->custom_zlib(out, outsize, in, insize, settings); + /*the custom zlib is allowed to have its own error codes, however, we translate it to code 111*/ + return error ? 111 : 0; + } else { + return lodepng_zlib_compress(out, outsize, in, insize, settings); + } +} + +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#else /*no LODEPNG_COMPILE_ZLIB*/ + +#ifdef LODEPNG_COMPILE_DECODER +static unsigned zlib_decompress(unsigned char** out, size_t* outsize, size_t expected_size, + const unsigned char* in, size_t insize, const LodePNGDecompressSettings* settings) { + if(!settings->custom_zlib) return 87; /*no custom zlib function provided */ + (void)expected_size; + return settings->custom_zlib(out, outsize, in, insize, settings); +} +#endif /*LODEPNG_COMPILE_DECODER*/ +#ifdef LODEPNG_COMPILE_ENCODER +static unsigned zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in, + size_t insize, const LodePNGCompressSettings* settings) { + if(!settings->custom_zlib) return 87; /*no custom zlib function provided */ + return settings->custom_zlib(out, outsize, in, insize, settings); +} +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#endif /*LODEPNG_COMPILE_ZLIB*/ + +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_ENCODER + +/*this is a good tradeoff between speed and compression ratio*/ +#define DEFAULT_WINDOWSIZE 2048 + +void lodepng_compress_settings_init(LodePNGCompressSettings* settings) { + /*compress with dynamic huffman tree (not in the mathematical sense, just not the predefined one)*/ + settings->btype = 2; + settings->use_lz77 = 1; + settings->windowsize = DEFAULT_WINDOWSIZE; + settings->minmatch = 3; + settings->nicematch = 128; + settings->lazymatching = 1; + + settings->custom_zlib = 0; + settings->custom_deflate = 0; + settings->custom_context = 0; +} + +const LodePNGCompressSettings lodepng_default_compress_settings = {2, 1, DEFAULT_WINDOWSIZE, 3, 128, 1, 0, 0, 0}; + + +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#ifdef LODEPNG_COMPILE_DECODER + +void lodepng_decompress_settings_init(LodePNGDecompressSettings* settings) { + settings->ignore_adler32 = 0; + settings->ignore_nlen = 0; + settings->max_output_size = 0; + + settings->custom_zlib = 0; + settings->custom_inflate = 0; + settings->custom_context = 0; +} + +const LodePNGDecompressSettings lodepng_default_decompress_settings = {0, 0, 0, 0, 0, 0}; + +#endif /*LODEPNG_COMPILE_DECODER*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* // End of Zlib related code. Begin of PNG related code. // */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_PNG + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / CRC32 / */ +/* ////////////////////////////////////////////////////////////////////////// */ + + +#ifndef LODEPNG_NO_COMPILE_CRC +/* CRC polynomial: 0xedb88320 */ +static unsigned lodepng_crc32_table[256] = { + 0u, 1996959894u, 3993919788u, 2567524794u, 124634137u, 1886057615u, 3915621685u, 2657392035u, + 249268274u, 2044508324u, 3772115230u, 2547177864u, 162941995u, 2125561021u, 3887607047u, 2428444049u, + 498536548u, 1789927666u, 4089016648u, 2227061214u, 450548861u, 1843258603u, 4107580753u, 2211677639u, + 325883990u, 1684777152u, 4251122042u, 2321926636u, 335633487u, 1661365465u, 4195302755u, 2366115317u, + 997073096u, 1281953886u, 3579855332u, 2724688242u, 1006888145u, 1258607687u, 3524101629u, 2768942443u, + 901097722u, 1119000684u, 3686517206u, 2898065728u, 853044451u, 1172266101u, 3705015759u, 2882616665u, + 651767980u, 1373503546u, 3369554304u, 3218104598u, 565507253u, 1454621731u, 3485111705u, 3099436303u, + 671266974u, 1594198024u, 3322730930u, 2970347812u, 795835527u, 1483230225u, 3244367275u, 3060149565u, + 1994146192u, 31158534u, 2563907772u, 4023717930u, 1907459465u, 112637215u, 2680153253u, 3904427059u, + 2013776290u, 251722036u, 2517215374u, 3775830040u, 2137656763u, 141376813u, 2439277719u, 3865271297u, + 1802195444u, 476864866u, 2238001368u, 4066508878u, 1812370925u, 453092731u, 2181625025u, 4111451223u, + 1706088902u, 314042704u, 2344532202u, 4240017532u, 1658658271u, 366619977u, 2362670323u, 4224994405u, + 1303535960u, 984961486u, 2747007092u, 3569037538u, 1256170817u, 1037604311u, 2765210733u, 3554079995u, + 1131014506u, 879679996u, 2909243462u, 3663771856u, 1141124467u, 855842277u, 2852801631u, 3708648649u, + 1342533948u, 654459306u, 3188396048u, 3373015174u, 1466479909u, 544179635u, 3110523913u, 3462522015u, + 1591671054u, 702138776u, 2966460450u, 3352799412u, 1504918807u, 783551873u, 3082640443u, 3233442989u, + 3988292384u, 2596254646u, 62317068u, 1957810842u, 3939845945u, 2647816111u, 81470997u, 1943803523u, + 3814918930u, 2489596804u, 225274430u, 2053790376u, 3826175755u, 2466906013u, 167816743u, 2097651377u, + 4027552580u, 2265490386u, 503444072u, 1762050814u, 4150417245u, 2154129355u, 426522225u, 1852507879u, + 4275313526u, 2312317920u, 282753626u, 1742555852u, 4189708143u, 2394877945u, 397917763u, 1622183637u, + 3604390888u, 2714866558u, 953729732u, 1340076626u, 3518719985u, 2797360999u, 1068828381u, 1219638859u, + 3624741850u, 2936675148u, 906185462u, 1090812512u, 3747672003u, 2825379669u, 829329135u, 1181335161u, + 3412177804u, 3160834842u, 628085408u, 1382605366u, 3423369109u, 3138078467u, 570562233u, 1426400815u, + 3317316542u, 2998733608u, 733239954u, 1555261956u, 3268935591u, 3050360625u, 752459403u, 1541320221u, + 2607071920u, 3965973030u, 1969922972u, 40735498u, 2617837225u, 3943577151u, 1913087877u, 83908371u, + 2512341634u, 3803740692u, 2075208622u, 213261112u, 2463272603u, 3855990285u, 2094854071u, 198958881u, + 2262029012u, 4057260610u, 1759359992u, 534414190u, 2176718541u, 4139329115u, 1873836001u, 414664567u, + 2282248934u, 4279200368u, 1711684554u, 285281116u, 2405801727u, 4167216745u, 1634467795u, 376229701u, + 2685067896u, 3608007406u, 1308918612u, 956543938u, 2808555105u, 3495958263u, 1231636301u, 1047427035u, + 2932959818u, 3654703836u, 1088359270u, 936918000u, 2847714899u, 3736837829u, 1202900863u, 817233897u, + 3183342108u, 3401237130u, 1404277552u, 615818150u, 3134207493u, 3453421203u, 1423857449u, 601450431u, + 3009837614u, 3294710456u, 1567103746u, 711928724u, 3020668471u, 3272380065u, 1510334235u, 755167117u +}; + +/*Return the CRC of the bytes buf[0..len-1].*/ +unsigned lodepng_crc32(const unsigned char* data, size_t length) { + unsigned r = 0xffffffffu; + size_t i; + for(i = 0; i < length; ++i) { + r = lodepng_crc32_table[(r ^ data[i]) & 0xffu] ^ (r >> 8u); + } + return r ^ 0xffffffffu; +} +#else /* !LODEPNG_NO_COMPILE_CRC */ +unsigned lodepng_crc32(const unsigned char* data, size_t length); +#endif /* !LODEPNG_NO_COMPILE_CRC */ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Reading and writing PNG color channel bits / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +/* The color channel bits of less-than-8-bit pixels are read with the MSB of bytes first, +so LodePNGBitWriter and LodePNGBitReader can't be used for those. */ + +static unsigned char readBitFromReversedStream(size_t* bitpointer, const unsigned char* bitstream) { + unsigned char result = (unsigned char)((bitstream[(*bitpointer) >> 3] >> (7 - ((*bitpointer) & 0x7))) & 1); + ++(*bitpointer); + return result; +} + +/* TODO: make this faster */ +static unsigned readBitsFromReversedStream(size_t* bitpointer, const unsigned char* bitstream, size_t nbits) { + unsigned result = 0; + size_t i; + for(i = 0 ; i < nbits; ++i) { + result <<= 1u; + result |= (unsigned)readBitFromReversedStream(bitpointer, bitstream); + } + return result; +} + +static void setBitOfReversedStream(size_t* bitpointer, unsigned char* bitstream, unsigned char bit) { + /*the current bit in bitstream may be 0 or 1 for this to work*/ + if(bit == 0) bitstream[(*bitpointer) >> 3u] &= (unsigned char)(~(1u << (7u - ((*bitpointer) & 7u)))); + else bitstream[(*bitpointer) >> 3u] |= (1u << (7u - ((*bitpointer) & 7u))); + ++(*bitpointer); +} + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / PNG chunks / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +unsigned lodepng_chunk_length(const unsigned char* chunk) { + return lodepng_read32bitInt(&chunk[0]); +} + +void lodepng_chunk_type(char type[5], const unsigned char* chunk) { + unsigned i; + for(i = 0; i != 4; ++i) type[i] = (char)chunk[4 + i]; + type[4] = 0; /*null termination char*/ +} + +unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type) { + if(lodepng_strlen(type) != 4) return 0; + return (chunk[4] == type[0] && chunk[5] == type[1] && chunk[6] == type[2] && chunk[7] == type[3]); +} + +unsigned char lodepng_chunk_ancillary(const unsigned char* chunk) { + return((chunk[4] & 32) != 0); +} + +unsigned char lodepng_chunk_private(const unsigned char* chunk) { + return((chunk[6] & 32) != 0); +} + +unsigned char lodepng_chunk_safetocopy(const unsigned char* chunk) { + return((chunk[7] & 32) != 0); +} + +unsigned char* lodepng_chunk_data(unsigned char* chunk) { + return &chunk[8]; +} + +const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk) { + return &chunk[8]; +} + +unsigned lodepng_chunk_check_crc(const unsigned char* chunk) { + unsigned length = lodepng_chunk_length(chunk); + unsigned CRC = lodepng_read32bitInt(&chunk[length + 8]); + /*the CRC is taken of the data and the 4 chunk type letters, not the length*/ + unsigned checksum = lodepng_crc32(&chunk[4], length + 4); + if(CRC != checksum) return 1; + else return 0; +} + +void lodepng_chunk_generate_crc(unsigned char* chunk) { + unsigned length = lodepng_chunk_length(chunk); + unsigned CRC = lodepng_crc32(&chunk[4], length + 4); + lodepng_set32bitInt(chunk + 8 + length, CRC); +} + +unsigned char* lodepng_chunk_next(unsigned char* chunk, unsigned char* end) { + if(chunk >= end || end - chunk < 12) return end; /*too small to contain a chunk*/ + if(chunk[0] == 0x89 && chunk[1] == 0x50 && chunk[2] == 0x4e && chunk[3] == 0x47 + && chunk[4] == 0x0d && chunk[5] == 0x0a && chunk[6] == 0x1a && chunk[7] == 0x0a) { + /* Is PNG magic header at start of PNG file. Jump to first actual chunk. */ + return chunk + 8; + } else { + size_t total_chunk_length; + unsigned char* result; + if(lodepng_addofl(lodepng_chunk_length(chunk), 12, &total_chunk_length)) return end; + result = chunk + total_chunk_length; + if(result < chunk) return end; /*pointer overflow*/ + return result; + } +} + +const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk, const unsigned char* end) { + if(chunk >= end || end - chunk < 12) return end; /*too small to contain a chunk*/ + if(chunk[0] == 0x89 && chunk[1] == 0x50 && chunk[2] == 0x4e && chunk[3] == 0x47 + && chunk[4] == 0x0d && chunk[5] == 0x0a && chunk[6] == 0x1a && chunk[7] == 0x0a) { + /* Is PNG magic header at start of PNG file. Jump to first actual chunk. */ + return chunk + 8; + } else { + size_t total_chunk_length; + const unsigned char* result; + if(lodepng_addofl(lodepng_chunk_length(chunk), 12, &total_chunk_length)) return end; + result = chunk + total_chunk_length; + if(result < chunk) return end; /*pointer overflow*/ + return result; + } +} + +unsigned char* lodepng_chunk_find(unsigned char* chunk, unsigned char* end, const char type[5]) { + for(;;) { + if(chunk >= end || end - chunk < 12) return 0; /* past file end: chunk + 12 > end */ + if(lodepng_chunk_type_equals(chunk, type)) return chunk; + chunk = lodepng_chunk_next(chunk, end); + } +} + +const unsigned char* lodepng_chunk_find_const(const unsigned char* chunk, const unsigned char* end, const char type[5]) { + for(;;) { + if(chunk >= end || end - chunk < 12) return 0; /* past file end: chunk + 12 > end */ + if(lodepng_chunk_type_equals(chunk, type)) return chunk; + chunk = lodepng_chunk_next_const(chunk, end); + } +} + +unsigned lodepng_chunk_append(unsigned char** out, size_t* outsize, const unsigned char* chunk) { + unsigned i; + size_t total_chunk_length, new_length; + unsigned char *chunk_start, *new_buffer; + + if(lodepng_addofl(lodepng_chunk_length(chunk), 12, &total_chunk_length)) return 77; + if(lodepng_addofl(*outsize, total_chunk_length, &new_length)) return 77; + + new_buffer = (unsigned char*)lodepng_realloc(*out, new_length); + if(!new_buffer) return 83; /*alloc fail*/ + (*out) = new_buffer; + (*outsize) = new_length; + chunk_start = &(*out)[new_length - total_chunk_length]; + + for(i = 0; i != total_chunk_length; ++i) chunk_start[i] = chunk[i]; + + return 0; +} + +/*Sets length and name and allocates the space for data and crc but does not +set data or crc yet. Returns the start of the chunk in chunk. The start of +the data is at chunk + 8. To finalize chunk, add the data, then use +lodepng_chunk_generate_crc */ +static unsigned lodepng_chunk_init(unsigned char** chunk, + ucvector* out, + unsigned length, const char* type) { + size_t new_length = out->size; + if(lodepng_addofl(new_length, length, &new_length)) return 77; + if(lodepng_addofl(new_length, 12, &new_length)) return 77; + if(!ucvector_resize(out, new_length)) return 83; /*alloc fail*/ + *chunk = out->data + new_length - length - 12u; + + /*1: length*/ + lodepng_set32bitInt(*chunk, length); + + /*2: chunk name (4 letters)*/ + lodepng_memcpy(*chunk + 4, type, 4); + + return 0; +} + +/* like lodepng_chunk_create but with custom allocsize */ +static unsigned lodepng_chunk_createv(ucvector* out, + unsigned length, const char* type, const unsigned char* data) { + unsigned char* chunk; + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, length, type)); + + /*3: the data*/ + lodepng_memcpy(chunk + 8, data, length); + + /*4: CRC (of the chunkname characters and the data)*/ + lodepng_chunk_generate_crc(chunk); + + return 0; +} + +unsigned lodepng_chunk_create(unsigned char** out, size_t* outsize, + unsigned length, const char* type, const unsigned char* data) { + ucvector v = ucvector_init(*out, *outsize); + unsigned error = lodepng_chunk_createv(&v, length, type, data); + *out = v.data; + *outsize = v.size; + return error; +} + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Color types, channels, bits / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +/*checks if the colortype is valid and the bitdepth bd is allowed for this colortype. +Return value is a LodePNG error code.*/ +static unsigned checkColorValidity(LodePNGColorType colortype, unsigned bd) { + switch(colortype) { + case LCT_GREY: if(!(bd == 1 || bd == 2 || bd == 4 || bd == 8 || bd == 16)) return 37; break; + case LCT_RGB: if(!( bd == 8 || bd == 16)) return 37; break; + case LCT_PALETTE: if(!(bd == 1 || bd == 2 || bd == 4 || bd == 8 )) return 37; break; + case LCT_GREY_ALPHA: if(!( bd == 8 || bd == 16)) return 37; break; + case LCT_RGBA: if(!( bd == 8 || bd == 16)) return 37; break; + case LCT_MAX_OCTET_VALUE: return 31; /* invalid color type */ + default: return 31; /* invalid color type */ + } + return 0; /*allowed color type / bits combination*/ +} + +static unsigned getNumColorChannels(LodePNGColorType colortype) { + switch(colortype) { + case LCT_GREY: return 1; + case LCT_RGB: return 3; + case LCT_PALETTE: return 1; + case LCT_GREY_ALPHA: return 2; + case LCT_RGBA: return 4; + case LCT_MAX_OCTET_VALUE: return 0; /* invalid color type */ + default: return 0; /*invalid color type*/ + } +} + +static unsigned lodepng_get_bpp_lct(LodePNGColorType colortype, unsigned bitdepth) { + /*bits per pixel is amount of channels * bits per channel*/ + return getNumColorChannels(colortype) * bitdepth; +} + +/* ////////////////////////////////////////////////////////////////////////// */ + +void lodepng_color_mode_init(LodePNGColorMode* info) { + info->key_defined = 0; + info->key_r = info->key_g = info->key_b = 0; + info->colortype = LCT_RGBA; + info->bitdepth = 8; + info->palette = 0; + info->palettesize = 0; +} + +/*allocates palette memory if needed, and initializes all colors to black*/ +static void lodepng_color_mode_alloc_palette(LodePNGColorMode* info) { + size_t i; + /*if the palette is already allocated, it will have size 1024 so no reallocation needed in that case*/ + /*the palette must have room for up to 256 colors with 4 bytes each.*/ + if(!info->palette) info->palette = (unsigned char*)lodepng_malloc(1024); + if(!info->palette) return; /*alloc fail*/ + for(i = 0; i != 256; ++i) { + /*Initialize all unused colors with black, the value used for invalid palette indices. + This is an error according to the PNG spec, but common PNG decoders make it black instead. + That makes color conversion slightly faster due to no error handling needed.*/ + info->palette[i * 4 + 0] = 0; + info->palette[i * 4 + 1] = 0; + info->palette[i * 4 + 2] = 0; + info->palette[i * 4 + 3] = 255; + } +} + +void lodepng_color_mode_cleanup(LodePNGColorMode* info) { + lodepng_palette_clear(info); +} + +unsigned lodepng_color_mode_copy(LodePNGColorMode* dest, const LodePNGColorMode* source) { + lodepng_color_mode_cleanup(dest); + lodepng_memcpy(dest, source, sizeof(LodePNGColorMode)); + if(source->palette) { + dest->palette = (unsigned char*)lodepng_malloc(1024); + if(!dest->palette && source->palettesize) return 83; /*alloc fail*/ + lodepng_memcpy(dest->palette, source->palette, source->palettesize * 4); + } + return 0; +} + +LodePNGColorMode lodepng_color_mode_make(LodePNGColorType colortype, unsigned bitdepth) { + LodePNGColorMode result; + lodepng_color_mode_init(&result); + result.colortype = colortype; + result.bitdepth = bitdepth; + return result; +} + +static int lodepng_color_mode_equal(const LodePNGColorMode* a, const LodePNGColorMode* b) { + size_t i; + if(a->colortype != b->colortype) return 0; + if(a->bitdepth != b->bitdepth) return 0; + if(a->key_defined != b->key_defined) return 0; + if(a->key_defined) { + if(a->key_r != b->key_r) return 0; + if(a->key_g != b->key_g) return 0; + if(a->key_b != b->key_b) return 0; + } + if(a->palettesize != b->palettesize) return 0; + for(i = 0; i != a->palettesize * 4; ++i) { + if(a->palette[i] != b->palette[i]) return 0; + } + return 1; +} + +void lodepng_palette_clear(LodePNGColorMode* info) { + if(info->palette) lodepng_free(info->palette); + info->palette = 0; + info->palettesize = 0; +} + +unsigned lodepng_palette_add(LodePNGColorMode* info, + unsigned char r, unsigned char g, unsigned char b, unsigned char a) { + if(!info->palette) /*allocate palette if empty*/ { + lodepng_color_mode_alloc_palette(info); + if(!info->palette) return 83; /*alloc fail*/ + } + if(info->palettesize >= 256) { + return 108; /*too many palette values*/ + } + info->palette[4 * info->palettesize + 0] = r; + info->palette[4 * info->palettesize + 1] = g; + info->palette[4 * info->palettesize + 2] = b; + info->palette[4 * info->palettesize + 3] = a; + ++info->palettesize; + return 0; +} + +/*calculate bits per pixel out of colortype and bitdepth*/ +unsigned lodepng_get_bpp(const LodePNGColorMode* info) { + return lodepng_get_bpp_lct(info->colortype, info->bitdepth); +} + +unsigned lodepng_get_channels(const LodePNGColorMode* info) { + return getNumColorChannels(info->colortype); +} + +unsigned lodepng_is_greyscale_type(const LodePNGColorMode* info) { + return info->colortype == LCT_GREY || info->colortype == LCT_GREY_ALPHA; +} + +unsigned lodepng_is_alpha_type(const LodePNGColorMode* info) { + return (info->colortype & 4) != 0; /*4 or 6*/ +} + +unsigned lodepng_is_palette_type(const LodePNGColorMode* info) { + return info->colortype == LCT_PALETTE; +} + +unsigned lodepng_has_palette_alpha(const LodePNGColorMode* info) { + size_t i; + for(i = 0; i != info->palettesize; ++i) { + if(info->palette[i * 4 + 3] < 255) return 1; + } + return 0; +} + +unsigned lodepng_can_have_alpha(const LodePNGColorMode* info) { + return info->key_defined + || lodepng_is_alpha_type(info) + || lodepng_has_palette_alpha(info); +} + +static size_t lodepng_get_raw_size_lct(unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth) { + size_t bpp = lodepng_get_bpp_lct(colortype, bitdepth); + size_t n = (size_t)w * (size_t)h; + return ((n / 8u) * bpp) + ((n & 7u) * bpp + 7u) / 8u; +} + +size_t lodepng_get_raw_size(unsigned w, unsigned h, const LodePNGColorMode* color) { + return lodepng_get_raw_size_lct(w, h, color->colortype, color->bitdepth); +} + + +#ifdef LODEPNG_COMPILE_PNG + +/*in an idat chunk, each scanline is a multiple of 8 bits, unlike the lodepng output buffer, +and in addition has one extra byte per line: the filter byte. So this gives a larger +result than lodepng_get_raw_size. Set h to 1 to get the size of 1 row including filter byte. */ +static size_t lodepng_get_raw_size_idat(unsigned w, unsigned h, unsigned bpp) { + /* + 1 for the filter byte, and possibly plus padding bits per line. */ + /* Ignoring casts, the expression is equal to (w * bpp + 7) / 8 + 1, but avoids overflow of w * bpp */ + size_t line = ((size_t)(w / 8u) * bpp) + 1u + ((w & 7u) * bpp + 7u) / 8u; + return (size_t)h * line; +} + +#ifdef LODEPNG_COMPILE_DECODER +/*Safely checks whether size_t overflow can be caused due to amount of pixels. +This check is overcautious rather than precise. If this check indicates no overflow, +you can safely compute in a size_t (but not an unsigned): +-(size_t)w * (size_t)h * 8 +-amount of bytes in IDAT (including filter, padding and Adam7 bytes) +-amount of bytes in raw color model +Returns 1 if overflow possible, 0 if not. +*/ +static int lodepng_pixel_overflow(unsigned w, unsigned h, + const LodePNGColorMode* pngcolor, const LodePNGColorMode* rawcolor) { + size_t bpp = LODEPNG_MAX(lodepng_get_bpp(pngcolor), lodepng_get_bpp(rawcolor)); + size_t numpixels, total; + size_t line; /* bytes per line in worst case */ + + if(lodepng_mulofl((size_t)w, (size_t)h, &numpixels)) return 1; + if(lodepng_mulofl(numpixels, 8, &total)) return 1; /* bit pointer with 8-bit color, or 8 bytes per channel color */ + + /* Bytes per scanline with the expression "(w / 8u) * bpp) + ((w & 7u) * bpp + 7u) / 8u" */ + if(lodepng_mulofl((size_t)(w / 8u), bpp, &line)) return 1; + if(lodepng_addofl(line, ((w & 7u) * bpp + 7u) / 8u, &line)) return 1; + + if(lodepng_addofl(line, 5, &line)) return 1; /* 5 bytes overhead per line: 1 filterbyte, 4 for Adam7 worst case */ + if(lodepng_mulofl(line, h, &total)) return 1; /* Total bytes in worst case */ + + return 0; /* no overflow */ +} +#endif /*LODEPNG_COMPILE_DECODER*/ +#endif /*LODEPNG_COMPILE_PNG*/ + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + +static void LodePNGUnknownChunks_init(LodePNGInfo* info) { + unsigned i; + for(i = 0; i != 3; ++i) info->unknown_chunks_data[i] = 0; + for(i = 0; i != 3; ++i) info->unknown_chunks_size[i] = 0; +} + +static void LodePNGUnknownChunks_cleanup(LodePNGInfo* info) { + unsigned i; + for(i = 0; i != 3; ++i) lodepng_free(info->unknown_chunks_data[i]); +} + +static unsigned LodePNGUnknownChunks_copy(LodePNGInfo* dest, const LodePNGInfo* src) { + unsigned i; + + LodePNGUnknownChunks_cleanup(dest); + + for(i = 0; i != 3; ++i) { + size_t j; + dest->unknown_chunks_size[i] = src->unknown_chunks_size[i]; + dest->unknown_chunks_data[i] = (unsigned char*)lodepng_malloc(src->unknown_chunks_size[i]); + if(!dest->unknown_chunks_data[i] && dest->unknown_chunks_size[i]) return 83; /*alloc fail*/ + for(j = 0; j < src->unknown_chunks_size[i]; ++j) { + dest->unknown_chunks_data[i][j] = src->unknown_chunks_data[i][j]; + } + } + + return 0; +} + +/******************************************************************************/ + +static void LodePNGText_init(LodePNGInfo* info) { + info->text_num = 0; + info->text_keys = NULL; + info->text_strings = NULL; +} + +static void LodePNGText_cleanup(LodePNGInfo* info) { + size_t i; + for(i = 0; i != info->text_num; ++i) { + string_cleanup(&info->text_keys[i]); + string_cleanup(&info->text_strings[i]); + } + lodepng_free(info->text_keys); + lodepng_free(info->text_strings); +} + +static unsigned LodePNGText_copy(LodePNGInfo* dest, const LodePNGInfo* source) { + size_t i = 0; + dest->text_keys = NULL; + dest->text_strings = NULL; + dest->text_num = 0; + for(i = 0; i != source->text_num; ++i) { + CERROR_TRY_RETURN(lodepng_add_text(dest, source->text_keys[i], source->text_strings[i])); + } + return 0; +} + +static unsigned lodepng_add_text_sized(LodePNGInfo* info, const char* key, const char* str, size_t size) { + char** new_keys = (char**)(lodepng_realloc(info->text_keys, sizeof(char*) * (info->text_num + 1))); + char** new_strings = (char**)(lodepng_realloc(info->text_strings, sizeof(char*) * (info->text_num + 1))); + + if(new_keys) info->text_keys = new_keys; + if(new_strings) info->text_strings = new_strings; + + if(!new_keys || !new_strings) return 83; /*alloc fail*/ + + ++info->text_num; + info->text_keys[info->text_num - 1] = alloc_string(key); + info->text_strings[info->text_num - 1] = alloc_string_sized(str, size); + if(!info->text_keys[info->text_num - 1] || !info->text_strings[info->text_num - 1]) return 83; /*alloc fail*/ + + return 0; +} + +unsigned lodepng_add_text(LodePNGInfo* info, const char* key, const char* str) { + return lodepng_add_text_sized(info, key, str, lodepng_strlen(str)); +} + +void lodepng_clear_text(LodePNGInfo* info) { + LodePNGText_cleanup(info); +} + +/******************************************************************************/ + +static void LodePNGIText_init(LodePNGInfo* info) { + info->itext_num = 0; + info->itext_keys = NULL; + info->itext_langtags = NULL; + info->itext_transkeys = NULL; + info->itext_strings = NULL; +} + +static void LodePNGIText_cleanup(LodePNGInfo* info) { + size_t i; + for(i = 0; i != info->itext_num; ++i) { + string_cleanup(&info->itext_keys[i]); + string_cleanup(&info->itext_langtags[i]); + string_cleanup(&info->itext_transkeys[i]); + string_cleanup(&info->itext_strings[i]); + } + lodepng_free(info->itext_keys); + lodepng_free(info->itext_langtags); + lodepng_free(info->itext_transkeys); + lodepng_free(info->itext_strings); +} + +static unsigned LodePNGIText_copy(LodePNGInfo* dest, const LodePNGInfo* source) { + size_t i = 0; + dest->itext_keys = NULL; + dest->itext_langtags = NULL; + dest->itext_transkeys = NULL; + dest->itext_strings = NULL; + dest->itext_num = 0; + for(i = 0; i != source->itext_num; ++i) { + CERROR_TRY_RETURN(lodepng_add_itext(dest, source->itext_keys[i], source->itext_langtags[i], + source->itext_transkeys[i], source->itext_strings[i])); + } + return 0; +} + +void lodepng_clear_itext(LodePNGInfo* info) { + LodePNGIText_cleanup(info); +} + +static unsigned lodepng_add_itext_sized(LodePNGInfo* info, const char* key, const char* langtag, + const char* transkey, const char* str, size_t size) { + char** new_keys = (char**)(lodepng_realloc(info->itext_keys, sizeof(char*) * (info->itext_num + 1))); + char** new_langtags = (char**)(lodepng_realloc(info->itext_langtags, sizeof(char*) * (info->itext_num + 1))); + char** new_transkeys = (char**)(lodepng_realloc(info->itext_transkeys, sizeof(char*) * (info->itext_num + 1))); + char** new_strings = (char**)(lodepng_realloc(info->itext_strings, sizeof(char*) * (info->itext_num + 1))); + + if(new_keys) info->itext_keys = new_keys; + if(new_langtags) info->itext_langtags = new_langtags; + if(new_transkeys) info->itext_transkeys = new_transkeys; + if(new_strings) info->itext_strings = new_strings; + + if(!new_keys || !new_langtags || !new_transkeys || !new_strings) return 83; /*alloc fail*/ + + ++info->itext_num; + + info->itext_keys[info->itext_num - 1] = alloc_string(key); + info->itext_langtags[info->itext_num - 1] = alloc_string(langtag); + info->itext_transkeys[info->itext_num - 1] = alloc_string(transkey); + info->itext_strings[info->itext_num - 1] = alloc_string_sized(str, size); + + return 0; +} + +unsigned lodepng_add_itext(LodePNGInfo* info, const char* key, const char* langtag, + const char* transkey, const char* str) { + return lodepng_add_itext_sized(info, key, langtag, transkey, str, lodepng_strlen(str)); +} + +/* same as set but does not delete */ +static unsigned lodepng_assign_icc(LodePNGInfo* info, const char* name, const unsigned char* profile, unsigned profile_size) { + if(profile_size == 0) return 100; /*invalid ICC profile size*/ + + info->iccp_name = alloc_string(name); + info->iccp_profile = (unsigned char*)lodepng_malloc(profile_size); + + if(!info->iccp_name || !info->iccp_profile) return 83; /*alloc fail*/ + + lodepng_memcpy(info->iccp_profile, profile, profile_size); + info->iccp_profile_size = profile_size; + + return 0; /*ok*/ +} + +unsigned lodepng_set_icc(LodePNGInfo* info, const char* name, const unsigned char* profile, unsigned profile_size) { + if(info->iccp_name) lodepng_clear_icc(info); + info->iccp_defined = 1; + + return lodepng_assign_icc(info, name, profile, profile_size); +} + +void lodepng_clear_icc(LodePNGInfo* info) { + string_cleanup(&info->iccp_name); + lodepng_free(info->iccp_profile); + info->iccp_profile = NULL; + info->iccp_profile_size = 0; + info->iccp_defined = 0; +} +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +void lodepng_info_init(LodePNGInfo* info) { + lodepng_color_mode_init(&info->color); + info->interlace_method = 0; + info->compression_method = 0; + info->filter_method = 0; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + info->background_defined = 0; + info->background_r = info->background_g = info->background_b = 0; + + LodePNGText_init(info); + LodePNGIText_init(info); + + info->time_defined = 0; + info->phys_defined = 0; + + info->gama_defined = 0; + info->chrm_defined = 0; + info->srgb_defined = 0; + info->iccp_defined = 0; + info->iccp_name = NULL; + info->iccp_profile = NULL; + + LodePNGUnknownChunks_init(info); +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} + +void lodepng_info_cleanup(LodePNGInfo* info) { + lodepng_color_mode_cleanup(&info->color); +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + LodePNGText_cleanup(info); + LodePNGIText_cleanup(info); + + lodepng_clear_icc(info); + + LodePNGUnknownChunks_cleanup(info); +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} + +unsigned lodepng_info_copy(LodePNGInfo* dest, const LodePNGInfo* source) { + lodepng_info_cleanup(dest); + lodepng_memcpy(dest, source, sizeof(LodePNGInfo)); + lodepng_color_mode_init(&dest->color); + CERROR_TRY_RETURN(lodepng_color_mode_copy(&dest->color, &source->color)); + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + CERROR_TRY_RETURN(LodePNGText_copy(dest, source)); + CERROR_TRY_RETURN(LodePNGIText_copy(dest, source)); + if(source->iccp_defined) { + CERROR_TRY_RETURN(lodepng_assign_icc(dest, source->iccp_name, source->iccp_profile, source->iccp_profile_size)); + } + + LodePNGUnknownChunks_init(dest); + CERROR_TRY_RETURN(LodePNGUnknownChunks_copy(dest, source)); +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + return 0; +} + +/* ////////////////////////////////////////////////////////////////////////// */ + +/*index: bitgroup index, bits: bitgroup size(1, 2 or 4), in: bitgroup value, out: octet array to add bits to*/ +static void addColorBits(unsigned char* out, size_t index, unsigned bits, unsigned in) { + unsigned m = bits == 1 ? 7 : bits == 2 ? 3 : 1; /*8 / bits - 1*/ + /*p = the partial index in the byte, e.g. with 4 palettebits it is 0 for first half or 1 for second half*/ + unsigned p = index & m; + in &= (1u << bits) - 1u; /*filter out any other bits of the input value*/ + in = in << (bits * (m - p)); + if(p == 0) out[index * bits / 8u] = in; + else out[index * bits / 8u] |= in; +} + +typedef struct ColorTree ColorTree; + +/* +One node of a color tree +This is the data structure used to count the number of unique colors and to get a palette +index for a color. It's like an octree, but because the alpha channel is used too, each +node has 16 instead of 8 children. +*/ +struct ColorTree { + ColorTree* children[16]; /*up to 16 pointers to ColorTree of next level*/ + int index; /*the payload. Only has a meaningful value if this is in the last level*/ +}; + +static void color_tree_init(ColorTree* tree) { + lodepng_memset(tree->children, 0, 16 * sizeof(*tree->children)); + tree->index = -1; +} + +static void color_tree_cleanup(ColorTree* tree) { + int i; + for(i = 0; i != 16; ++i) { + if(tree->children[i]) { + color_tree_cleanup(tree->children[i]); + lodepng_free(tree->children[i]); + } + } +} + +/*returns -1 if color not present, its index otherwise*/ +static int color_tree_get(ColorTree* tree, unsigned char r, unsigned char g, unsigned char b, unsigned char a) { + int bit = 0; + for(bit = 0; bit < 8; ++bit) { + int i = 8 * ((r >> bit) & 1) + 4 * ((g >> bit) & 1) + 2 * ((b >> bit) & 1) + 1 * ((a >> bit) & 1); + if(!tree->children[i]) return -1; + else tree = tree->children[i]; + } + return tree ? tree->index : -1; +} + +#ifdef LODEPNG_COMPILE_ENCODER +static int color_tree_has(ColorTree* tree, unsigned char r, unsigned char g, unsigned char b, unsigned char a) { + return color_tree_get(tree, r, g, b, a) >= 0; +} +#endif /*LODEPNG_COMPILE_ENCODER*/ + +/*color is not allowed to already exist. +Index should be >= 0 (it's signed to be compatible with using -1 for "doesn't exist") +Returns error code, or 0 if ok*/ +static unsigned color_tree_add(ColorTree* tree, + unsigned char r, unsigned char g, unsigned char b, unsigned char a, unsigned index) { + int bit; + for(bit = 0; bit < 8; ++bit) { + int i = 8 * ((r >> bit) & 1) + 4 * ((g >> bit) & 1) + 2 * ((b >> bit) & 1) + 1 * ((a >> bit) & 1); + if(!tree->children[i]) { + tree->children[i] = (ColorTree*)lodepng_malloc(sizeof(ColorTree)); + if(!tree->children[i]) return 83; /*alloc fail*/ + color_tree_init(tree->children[i]); + } + tree = tree->children[i]; + } + tree->index = (int)index; + return 0; +} + +/*put a pixel, given its RGBA color, into image of any color type*/ +static unsigned rgba8ToPixel(unsigned char* out, size_t i, + const LodePNGColorMode* mode, ColorTree* tree /*for palette*/, + unsigned char r, unsigned char g, unsigned char b, unsigned char a) { + if(mode->colortype == LCT_GREY) { + unsigned char gray = r; /*((unsigned short)r + g + b) / 3u;*/ + if(mode->bitdepth == 8) out[i] = gray; + else if(mode->bitdepth == 16) out[i * 2 + 0] = out[i * 2 + 1] = gray; + else { + /*take the most significant bits of gray*/ + gray = ((unsigned)gray >> (8u - mode->bitdepth)) & ((1u << mode->bitdepth) - 1u); + addColorBits(out, i, mode->bitdepth, gray); + } + } else if(mode->colortype == LCT_RGB) { + if(mode->bitdepth == 8) { + out[i * 3 + 0] = r; + out[i * 3 + 1] = g; + out[i * 3 + 2] = b; + } else { + out[i * 6 + 0] = out[i * 6 + 1] = r; + out[i * 6 + 2] = out[i * 6 + 3] = g; + out[i * 6 + 4] = out[i * 6 + 5] = b; + } + } else if(mode->colortype == LCT_PALETTE) { + int index = color_tree_get(tree, r, g, b, a); + if(index < 0) return 82; /*color not in palette*/ + if(mode->bitdepth == 8) out[i] = index; + else addColorBits(out, i, mode->bitdepth, (unsigned)index); + } else if(mode->colortype == LCT_GREY_ALPHA) { + unsigned char gray = r; /*((unsigned short)r + g + b) / 3u;*/ + if(mode->bitdepth == 8) { + out[i * 2 + 0] = gray; + out[i * 2 + 1] = a; + } else if(mode->bitdepth == 16) { + out[i * 4 + 0] = out[i * 4 + 1] = gray; + out[i * 4 + 2] = out[i * 4 + 3] = a; + } + } else if(mode->colortype == LCT_RGBA) { + if(mode->bitdepth == 8) { + out[i * 4 + 0] = r; + out[i * 4 + 1] = g; + out[i * 4 + 2] = b; + out[i * 4 + 3] = a; + } else { + out[i * 8 + 0] = out[i * 8 + 1] = r; + out[i * 8 + 2] = out[i * 8 + 3] = g; + out[i * 8 + 4] = out[i * 8 + 5] = b; + out[i * 8 + 6] = out[i * 8 + 7] = a; + } + } + + return 0; /*no error*/ +} + +/*put a pixel, given its RGBA16 color, into image of any color 16-bitdepth type*/ +static void rgba16ToPixel(unsigned char* out, size_t i, + const LodePNGColorMode* mode, + unsigned short r, unsigned short g, unsigned short b, unsigned short a) { + if(mode->colortype == LCT_GREY) { + unsigned short gray = r; /*((unsigned)r + g + b) / 3u;*/ + out[i * 2 + 0] = (gray >> 8) & 255; + out[i * 2 + 1] = gray & 255; + } else if(mode->colortype == LCT_RGB) { + out[i * 6 + 0] = (r >> 8) & 255; + out[i * 6 + 1] = r & 255; + out[i * 6 + 2] = (g >> 8) & 255; + out[i * 6 + 3] = g & 255; + out[i * 6 + 4] = (b >> 8) & 255; + out[i * 6 + 5] = b & 255; + } else if(mode->colortype == LCT_GREY_ALPHA) { + unsigned short gray = r; /*((unsigned)r + g + b) / 3u;*/ + out[i * 4 + 0] = (gray >> 8) & 255; + out[i * 4 + 1] = gray & 255; + out[i * 4 + 2] = (a >> 8) & 255; + out[i * 4 + 3] = a & 255; + } else if(mode->colortype == LCT_RGBA) { + out[i * 8 + 0] = (r >> 8) & 255; + out[i * 8 + 1] = r & 255; + out[i * 8 + 2] = (g >> 8) & 255; + out[i * 8 + 3] = g & 255; + out[i * 8 + 4] = (b >> 8) & 255; + out[i * 8 + 5] = b & 255; + out[i * 8 + 6] = (a >> 8) & 255; + out[i * 8 + 7] = a & 255; + } +} + +/*Get RGBA8 color of pixel with index i (y * width + x) from the raw image with given color type.*/ +static void getPixelColorRGBA8(unsigned char* r, unsigned char* g, + unsigned char* b, unsigned char* a, + const unsigned char* in, size_t i, + const LodePNGColorMode* mode) { + if(mode->colortype == LCT_GREY) { + if(mode->bitdepth == 8) { + *r = *g = *b = in[i]; + if(mode->key_defined && *r == mode->key_r) *a = 0; + else *a = 255; + } else if(mode->bitdepth == 16) { + *r = *g = *b = in[i * 2 + 0]; + if(mode->key_defined && 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r) *a = 0; + else *a = 255; + } else { + unsigned highest = ((1U << mode->bitdepth) - 1U); /*highest possible value for this bit depth*/ + size_t j = i * mode->bitdepth; + unsigned value = readBitsFromReversedStream(&j, in, mode->bitdepth); + *r = *g = *b = (value * 255) / highest; + if(mode->key_defined && value == mode->key_r) *a = 0; + else *a = 255; + } + } else if(mode->colortype == LCT_RGB) { + if(mode->bitdepth == 8) { + *r = in[i * 3 + 0]; *g = in[i * 3 + 1]; *b = in[i * 3 + 2]; + if(mode->key_defined && *r == mode->key_r && *g == mode->key_g && *b == mode->key_b) *a = 0; + else *a = 255; + } else { + *r = in[i * 6 + 0]; + *g = in[i * 6 + 2]; + *b = in[i * 6 + 4]; + if(mode->key_defined && 256U * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r + && 256U * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g + && 256U * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b) *a = 0; + else *a = 255; + } + } else if(mode->colortype == LCT_PALETTE) { + unsigned index; + if(mode->bitdepth == 8) index = in[i]; + else { + size_t j = i * mode->bitdepth; + index = readBitsFromReversedStream(&j, in, mode->bitdepth); + } + /*out of bounds of palette not checked: see lodepng_color_mode_alloc_palette.*/ + *r = mode->palette[index * 4 + 0]; + *g = mode->palette[index * 4 + 1]; + *b = mode->palette[index * 4 + 2]; + *a = mode->palette[index * 4 + 3]; + } else if(mode->colortype == LCT_GREY_ALPHA) { + if(mode->bitdepth == 8) { + *r = *g = *b = in[i * 2 + 0]; + *a = in[i * 2 + 1]; + } else { + *r = *g = *b = in[i * 4 + 0]; + *a = in[i * 4 + 2]; + } + } else if(mode->colortype == LCT_RGBA) { + if(mode->bitdepth == 8) { + *r = in[i * 4 + 0]; + *g = in[i * 4 + 1]; + *b = in[i * 4 + 2]; + *a = in[i * 4 + 3]; + } else { + *r = in[i * 8 + 0]; + *g = in[i * 8 + 2]; + *b = in[i * 8 + 4]; + *a = in[i * 8 + 6]; + } + } +} + +/*Similar to getPixelColorRGBA8, but with all the for loops inside of the color +mode test cases, optimized to convert the colors much faster, when converting +to the common case of RGBA with 8 bit per channel. buffer must be RGBA with +enough memory.*/ +static void getPixelColorsRGBA8(unsigned char* LODEPNG_RESTRICT buffer, size_t numpixels, + const unsigned char* LODEPNG_RESTRICT in, + const LodePNGColorMode* mode) { + unsigned num_channels = 4; + size_t i; + if(mode->colortype == LCT_GREY) { + if(mode->bitdepth == 8) { + for(i = 0; i != numpixels; ++i, buffer += num_channels) { + buffer[0] = buffer[1] = buffer[2] = in[i]; + buffer[3] = 255; + } + if(mode->key_defined) { + buffer -= numpixels * num_channels; + for(i = 0; i != numpixels; ++i, buffer += num_channels) { + if(buffer[0] == mode->key_r) buffer[3] = 0; + } + } + } else if(mode->bitdepth == 16) { + for(i = 0; i != numpixels; ++i, buffer += num_channels) { + buffer[0] = buffer[1] = buffer[2] = in[i * 2]; + buffer[3] = mode->key_defined && 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r ? 0 : 255; + } + } else { + unsigned highest = ((1U << mode->bitdepth) - 1U); /*highest possible value for this bit depth*/ + size_t j = 0; + for(i = 0; i != numpixels; ++i, buffer += num_channels) { + unsigned value = readBitsFromReversedStream(&j, in, mode->bitdepth); + buffer[0] = buffer[1] = buffer[2] = (value * 255) / highest; + buffer[3] = mode->key_defined && value == mode->key_r ? 0 : 255; + } + } + } else if(mode->colortype == LCT_RGB) { + if(mode->bitdepth == 8) { + for(i = 0; i != numpixels; ++i, buffer += num_channels) { + lodepng_memcpy(buffer, &in[i * 3], 3); + buffer[3] = 255; + } + if(mode->key_defined) { + buffer -= numpixels * num_channels; + for(i = 0; i != numpixels; ++i, buffer += num_channels) { + if(buffer[0] == mode->key_r && buffer[1]== mode->key_g && buffer[2] == mode->key_b) buffer[3] = 0; + } + } + } else { + for(i = 0; i != numpixels; ++i, buffer += num_channels) { + buffer[0] = in[i * 6 + 0]; + buffer[1] = in[i * 6 + 2]; + buffer[2] = in[i * 6 + 4]; + buffer[3] = mode->key_defined + && 256U * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r + && 256U * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g + && 256U * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b ? 0 : 255; + } + } + } else if(mode->colortype == LCT_PALETTE) { + if(mode->bitdepth == 8) { + for(i = 0; i != numpixels; ++i, buffer += num_channels) { + unsigned index = in[i]; + /*out of bounds of palette not checked: see lodepng_color_mode_alloc_palette.*/ + lodepng_memcpy(buffer, &mode->palette[index * 4], 4); + } + } else { + size_t j = 0; + for(i = 0; i != numpixels; ++i, buffer += num_channels) { + unsigned index = readBitsFromReversedStream(&j, in, mode->bitdepth); + /*out of bounds of palette not checked: see lodepng_color_mode_alloc_palette.*/ + lodepng_memcpy(buffer, &mode->palette[index * 4], 4); + } + } + } else if(mode->colortype == LCT_GREY_ALPHA) { + if(mode->bitdepth == 8) { + for(i = 0; i != numpixels; ++i, buffer += num_channels) { + buffer[0] = buffer[1] = buffer[2] = in[i * 2 + 0]; + buffer[3] = in[i * 2 + 1]; + } + } else { + for(i = 0; i != numpixels; ++i, buffer += num_channels) { + buffer[0] = buffer[1] = buffer[2] = in[i * 4 + 0]; + buffer[3] = in[i * 4 + 2]; + } + } + } else if(mode->colortype == LCT_RGBA) { + if(mode->bitdepth == 8) { + lodepng_memcpy(buffer, in, numpixels * 4); + } else { + for(i = 0; i != numpixels; ++i, buffer += num_channels) { + buffer[0] = in[i * 8 + 0]; + buffer[1] = in[i * 8 + 2]; + buffer[2] = in[i * 8 + 4]; + buffer[3] = in[i * 8 + 6]; + } + } + } +} + +/*Similar to getPixelColorsRGBA8, but with 3-channel RGB output.*/ +static void getPixelColorsRGB8(unsigned char* LODEPNG_RESTRICT buffer, size_t numpixels, + const unsigned char* LODEPNG_RESTRICT in, + const LodePNGColorMode* mode) { + const unsigned num_channels = 3; + size_t i; + if(mode->colortype == LCT_GREY) { + if(mode->bitdepth == 8) { + for(i = 0; i != numpixels; ++i, buffer += num_channels) { + buffer[0] = buffer[1] = buffer[2] = in[i]; + } + } else if(mode->bitdepth == 16) { + for(i = 0; i != numpixels; ++i, buffer += num_channels) { + buffer[0] = buffer[1] = buffer[2] = in[i * 2]; + } + } else { + unsigned highest = ((1U << mode->bitdepth) - 1U); /*highest possible value for this bit depth*/ + size_t j = 0; + for(i = 0; i != numpixels; ++i, buffer += num_channels) { + unsigned value = readBitsFromReversedStream(&j, in, mode->bitdepth); + buffer[0] = buffer[1] = buffer[2] = (value * 255) / highest; + } + } + } else if(mode->colortype == LCT_RGB) { + if(mode->bitdepth == 8) { + lodepng_memcpy(buffer, in, numpixels * 3); + } else { + for(i = 0; i != numpixels; ++i, buffer += num_channels) { + buffer[0] = in[i * 6 + 0]; + buffer[1] = in[i * 6 + 2]; + buffer[2] = in[i * 6 + 4]; + } + } + } else if(mode->colortype == LCT_PALETTE) { + if(mode->bitdepth == 8) { + for(i = 0; i != numpixels; ++i, buffer += num_channels) { + unsigned index = in[i]; + /*out of bounds of palette not checked: see lodepng_color_mode_alloc_palette.*/ + lodepng_memcpy(buffer, &mode->palette[index * 4], 3); + } + } else { + size_t j = 0; + for(i = 0; i != numpixels; ++i, buffer += num_channels) { + unsigned index = readBitsFromReversedStream(&j, in, mode->bitdepth); + /*out of bounds of palette not checked: see lodepng_color_mode_alloc_palette.*/ + lodepng_memcpy(buffer, &mode->palette[index * 4], 3); + } + } + } else if(mode->colortype == LCT_GREY_ALPHA) { + if(mode->bitdepth == 8) { + for(i = 0; i != numpixels; ++i, buffer += num_channels) { + buffer[0] = buffer[1] = buffer[2] = in[i * 2 + 0]; + } + } else { + for(i = 0; i != numpixels; ++i, buffer += num_channels) { + buffer[0] = buffer[1] = buffer[2] = in[i * 4 + 0]; + } + } + } else if(mode->colortype == LCT_RGBA) { + if(mode->bitdepth == 8) { + for(i = 0; i != numpixels; ++i, buffer += num_channels) { + lodepng_memcpy(buffer, &in[i * 4], 3); + } + } else { + for(i = 0; i != numpixels; ++i, buffer += num_channels) { + buffer[0] = in[i * 8 + 0]; + buffer[1] = in[i * 8 + 2]; + buffer[2] = in[i * 8 + 4]; + } + } + } +} + +/*Get RGBA16 color of pixel with index i (y * width + x) from the raw image with +given color type, but the given color type must be 16-bit itself.*/ +static void getPixelColorRGBA16(unsigned short* r, unsigned short* g, unsigned short* b, unsigned short* a, + const unsigned char* in, size_t i, const LodePNGColorMode* mode) { + if(mode->colortype == LCT_GREY) { + *r = *g = *b = 256 * in[i * 2 + 0] + in[i * 2 + 1]; + if(mode->key_defined && 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r) *a = 0; + else *a = 65535; + } else if(mode->colortype == LCT_RGB) { + *r = 256u * in[i * 6 + 0] + in[i * 6 + 1]; + *g = 256u * in[i * 6 + 2] + in[i * 6 + 3]; + *b = 256u * in[i * 6 + 4] + in[i * 6 + 5]; + if(mode->key_defined + && 256u * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r + && 256u * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g + && 256u * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b) *a = 0; + else *a = 65535; + } else if(mode->colortype == LCT_GREY_ALPHA) { + *r = *g = *b = 256u * in[i * 4 + 0] + in[i * 4 + 1]; + *a = 256u * in[i * 4 + 2] + in[i * 4 + 3]; + } else if(mode->colortype == LCT_RGBA) { + *r = 256u * in[i * 8 + 0] + in[i * 8 + 1]; + *g = 256u * in[i * 8 + 2] + in[i * 8 + 3]; + *b = 256u * in[i * 8 + 4] + in[i * 8 + 5]; + *a = 256u * in[i * 8 + 6] + in[i * 8 + 7]; + } +} + +unsigned lodepng_convert(unsigned char* out, const unsigned char* in, + const LodePNGColorMode* mode_out, const LodePNGColorMode* mode_in, + unsigned w, unsigned h) { + size_t i; + ColorTree tree; + size_t numpixels = (size_t)w * (size_t)h; + unsigned error = 0; + + if(mode_in->colortype == LCT_PALETTE && !mode_in->palette) { + return 107; /* error: must provide palette if input mode is palette */ + } + + if(lodepng_color_mode_equal(mode_out, mode_in)) { + size_t numbytes = lodepng_get_raw_size(w, h, mode_in); + lodepng_memcpy(out, in, numbytes); + return 0; + } + + if(mode_out->colortype == LCT_PALETTE) { + size_t palettesize = mode_out->palettesize; + const unsigned char* palette = mode_out->palette; + size_t palsize = (size_t)1u << mode_out->bitdepth; + /*if the user specified output palette but did not give the values, assume + they want the values of the input color type (assuming that one is palette). + Note that we never create a new palette ourselves.*/ + if(palettesize == 0) { + palettesize = mode_in->palettesize; + palette = mode_in->palette; + /*if the input was also palette with same bitdepth, then the color types are also + equal, so copy literally. This to preserve the exact indices that were in the PNG + even in case there are duplicate colors in the palette.*/ + if(mode_in->colortype == LCT_PALETTE && mode_in->bitdepth == mode_out->bitdepth) { + size_t numbytes = lodepng_get_raw_size(w, h, mode_in); + lodepng_memcpy(out, in, numbytes); + return 0; + } + } + if(palettesize < palsize) palsize = palettesize; + color_tree_init(&tree); + for(i = 0; i != palsize; ++i) { + const unsigned char* p = &palette[i * 4]; + error = color_tree_add(&tree, p[0], p[1], p[2], p[3], (unsigned)i); + if(error) break; + } + } + + if(!error) { + if(mode_in->bitdepth == 16 && mode_out->bitdepth == 16) { + for(i = 0; i != numpixels; ++i) { + unsigned short r = 0, g = 0, b = 0, a = 0; + getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode_in); + rgba16ToPixel(out, i, mode_out, r, g, b, a); + } + } else if(mode_out->bitdepth == 8 && mode_out->colortype == LCT_RGBA) { + getPixelColorsRGBA8(out, numpixels, in, mode_in); + } else if(mode_out->bitdepth == 8 && mode_out->colortype == LCT_RGB) { + getPixelColorsRGB8(out, numpixels, in, mode_in); + } else { + unsigned char r = 0, g = 0, b = 0, a = 0; + for(i = 0; i != numpixels; ++i) { + getPixelColorRGBA8(&r, &g, &b, &a, in, i, mode_in); + error = rgba8ToPixel(out, i, mode_out, &tree, r, g, b, a); + if(error) break; + } + } + } + + if(mode_out->colortype == LCT_PALETTE) { + color_tree_cleanup(&tree); + } + + return error; +} + + +/* Converts a single rgb color without alpha from one type to another, color bits truncated to +their bitdepth. In case of single channel (gray or palette), only the r channel is used. Slow +function, do not use to process all pixels of an image. Alpha channel not supported on purpose: +this is for bKGD, supporting alpha may prevent it from finding a color in the palette, from the +specification it looks like bKGD should ignore the alpha values of the palette since it can use +any palette index but doesn't have an alpha channel. Idem with ignoring color key. */ +unsigned lodepng_convert_rgb( + unsigned* r_out, unsigned* g_out, unsigned* b_out, + unsigned r_in, unsigned g_in, unsigned b_in, + const LodePNGColorMode* mode_out, const LodePNGColorMode* mode_in) { + unsigned r = 0, g = 0, b = 0; + unsigned mul = 65535 / ((1u << mode_in->bitdepth) - 1u); /*65535, 21845, 4369, 257, 1*/ + unsigned shift = 16 - mode_out->bitdepth; + + if(mode_in->colortype == LCT_GREY || mode_in->colortype == LCT_GREY_ALPHA) { + r = g = b = r_in * mul; + } else if(mode_in->colortype == LCT_RGB || mode_in->colortype == LCT_RGBA) { + r = r_in * mul; + g = g_in * mul; + b = b_in * mul; + } else if(mode_in->colortype == LCT_PALETTE) { + if(r_in >= mode_in->palettesize) return 82; + r = mode_in->palette[r_in * 4 + 0] * 257u; + g = mode_in->palette[r_in * 4 + 1] * 257u; + b = mode_in->palette[r_in * 4 + 2] * 257u; + } else { + return 31; + } + + /* now convert to output format */ + if(mode_out->colortype == LCT_GREY || mode_out->colortype == LCT_GREY_ALPHA) { + *r_out = r >> shift ; + } else if(mode_out->colortype == LCT_RGB || mode_out->colortype == LCT_RGBA) { + *r_out = r >> shift ; + *g_out = g >> shift ; + *b_out = b >> shift ; + } else if(mode_out->colortype == LCT_PALETTE) { + unsigned i; + /* a 16-bit color cannot be in the palette */ + if((r >> 8) != (r & 255) || (g >> 8) != (g & 255) || (b >> 8) != (b & 255)) return 82; + for(i = 0; i < mode_out->palettesize; i++) { + unsigned j = i * 4; + if((r >> 8) == mode_out->palette[j + 0] && (g >> 8) == mode_out->palette[j + 1] && + (b >> 8) == mode_out->palette[j + 2]) { + *r_out = i; + return 0; + } + } + return 82; + } else { + return 31; + } + + return 0; +} + +#ifdef LODEPNG_COMPILE_ENCODER + +void lodepng_color_stats_init(LodePNGColorStats* stats) { + /*stats*/ + stats->colored = 0; + stats->key = 0; + stats->key_r = stats->key_g = stats->key_b = 0; + stats->alpha = 0; + stats->numcolors = 0; + stats->bits = 1; + stats->numpixels = 0; + /*settings*/ + stats->allow_palette = 1; + stats->allow_greyscale = 1; +} + +/*function used for debug purposes with C++*/ +/*void printColorStats(LodePNGColorStats* p) { + std::cout << "colored: " << (int)p->colored << ", "; + std::cout << "key: " << (int)p->key << ", "; + std::cout << "key_r: " << (int)p->key_r << ", "; + std::cout << "key_g: " << (int)p->key_g << ", "; + std::cout << "key_b: " << (int)p->key_b << ", "; + std::cout << "alpha: " << (int)p->alpha << ", "; + std::cout << "numcolors: " << (int)p->numcolors << ", "; + std::cout << "bits: " << (int)p->bits << std::endl; +}*/ + +/*Returns how many bits needed to represent given value (max 8 bit)*/ +static unsigned getValueRequiredBits(unsigned char value) { + if(value == 0 || value == 255) return 1; + /*The scaling of 2-bit and 4-bit values uses multiples of 85 and 17*/ + if(value % 17 == 0) return value % 85 == 0 ? 2 : 4; + return 8; +} + +/*stats must already have been inited. */ +unsigned lodepng_compute_color_stats(LodePNGColorStats* stats, + const unsigned char* in, unsigned w, unsigned h, + const LodePNGColorMode* mode_in) { + size_t i; + ColorTree tree; + size_t numpixels = (size_t)w * (size_t)h; + unsigned error = 0; + + /* mark things as done already if it would be impossible to have a more expensive case */ + unsigned colored_done = lodepng_is_greyscale_type(mode_in) ? 1 : 0; + unsigned alpha_done = lodepng_can_have_alpha(mode_in) ? 0 : 1; + unsigned numcolors_done = 0; + unsigned bpp = lodepng_get_bpp(mode_in); + unsigned bits_done = (stats->bits == 1 && bpp == 1) ? 1 : 0; + unsigned sixteen = 0; /* whether the input image is 16 bit */ + unsigned maxnumcolors = 257; + if(bpp <= 8) maxnumcolors = LODEPNG_MIN(257, stats->numcolors + (1u << bpp)); + + stats->numpixels += numpixels; + + /*if palette not allowed, no need to compute numcolors*/ + if(!stats->allow_palette) numcolors_done = 1; + + color_tree_init(&tree); + + /*If the stats was already filled in from previous data, fill its palette in tree + and mark things as done already if we know they are the most expensive case already*/ + if(stats->alpha) alpha_done = 1; + if(stats->colored) colored_done = 1; + if(stats->bits == 16) numcolors_done = 1; + if(stats->bits >= bpp) bits_done = 1; + if(stats->numcolors >= maxnumcolors) numcolors_done = 1; + + if(!numcolors_done) { + for(i = 0; i < stats->numcolors; i++) { + const unsigned char* color = &stats->palette[i * 4]; + error = color_tree_add(&tree, color[0], color[1], color[2], color[3], i); + if(error) goto cleanup; + } + } + + /*Check if the 16-bit input is truly 16-bit*/ + if(mode_in->bitdepth == 16 && !sixteen) { + unsigned short r = 0, g = 0, b = 0, a = 0; + for(i = 0; i != numpixels; ++i) { + getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode_in); + if((r & 255) != ((r >> 8) & 255) || (g & 255) != ((g >> 8) & 255) || + (b & 255) != ((b >> 8) & 255) || (a & 255) != ((a >> 8) & 255)) /*first and second byte differ*/ { + stats->bits = 16; + sixteen = 1; + bits_done = 1; + numcolors_done = 1; /*counting colors no longer useful, palette doesn't support 16-bit*/ + break; + } + } + } + + if(sixteen) { + unsigned short r = 0, g = 0, b = 0, a = 0; + + for(i = 0; i != numpixels; ++i) { + getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode_in); + + if(!colored_done && (r != g || r != b)) { + stats->colored = 1; + colored_done = 1; + } + + if(!alpha_done) { + unsigned matchkey = (r == stats->key_r && g == stats->key_g && b == stats->key_b); + if(a != 65535 && (a != 0 || (stats->key && !matchkey))) { + stats->alpha = 1; + stats->key = 0; + alpha_done = 1; + } else if(a == 0 && !stats->alpha && !stats->key) { + stats->key = 1; + stats->key_r = r; + stats->key_g = g; + stats->key_b = b; + } else if(a == 65535 && stats->key && matchkey) { + /* Color key cannot be used if an opaque pixel also has that RGB color. */ + stats->alpha = 1; + stats->key = 0; + alpha_done = 1; + } + } + if(alpha_done && numcolors_done && colored_done && bits_done) break; + } + + if(stats->key && !stats->alpha) { + for(i = 0; i != numpixels; ++i) { + getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode_in); + if(a != 0 && r == stats->key_r && g == stats->key_g && b == stats->key_b) { + /* Color key cannot be used if an opaque pixel also has that RGB color. */ + stats->alpha = 1; + stats->key = 0; + alpha_done = 1; + } + } + } + } else /* < 16-bit */ { + unsigned char r = 0, g = 0, b = 0, a = 0; + for(i = 0; i != numpixels; ++i) { + getPixelColorRGBA8(&r, &g, &b, &a, in, i, mode_in); + + if(!bits_done && stats->bits < 8) { + /*only r is checked, < 8 bits is only relevant for grayscale*/ + unsigned bits = getValueRequiredBits(r); + if(bits > stats->bits) stats->bits = bits; + } + bits_done = (stats->bits >= bpp); + + if(!colored_done && (r != g || r != b)) { + stats->colored = 1; + colored_done = 1; + if(stats->bits < 8) stats->bits = 8; /*PNG has no colored modes with less than 8-bit per channel*/ + } + + if(!alpha_done) { + unsigned matchkey = (r == stats->key_r && g == stats->key_g && b == stats->key_b); + if(a != 255 && (a != 0 || (stats->key && !matchkey))) { + stats->alpha = 1; + stats->key = 0; + alpha_done = 1; + if(stats->bits < 8) stats->bits = 8; /*PNG has no alphachannel modes with less than 8-bit per channel*/ + } else if(a == 0 && !stats->alpha && !stats->key) { + stats->key = 1; + stats->key_r = r; + stats->key_g = g; + stats->key_b = b; + } else if(a == 255 && stats->key && matchkey) { + /* Color key cannot be used if an opaque pixel also has that RGB color. */ + stats->alpha = 1; + stats->key = 0; + alpha_done = 1; + if(stats->bits < 8) stats->bits = 8; /*PNG has no alphachannel modes with less than 8-bit per channel*/ + } + } + + if(!numcolors_done) { + if(!color_tree_has(&tree, r, g, b, a)) { + error = color_tree_add(&tree, r, g, b, a, stats->numcolors); + if(error) goto cleanup; + if(stats->numcolors < 256) { + unsigned char* p = stats->palette; + unsigned n = stats->numcolors; + p[n * 4 + 0] = r; + p[n * 4 + 1] = g; + p[n * 4 + 2] = b; + p[n * 4 + 3] = a; + } + ++stats->numcolors; + numcolors_done = stats->numcolors >= maxnumcolors; + } + } + + if(alpha_done && numcolors_done && colored_done && bits_done) break; + } + + if(stats->key && !stats->alpha) { + for(i = 0; i != numpixels; ++i) { + getPixelColorRGBA8(&r, &g, &b, &a, in, i, mode_in); + if(a != 0 && r == stats->key_r && g == stats->key_g && b == stats->key_b) { + /* Color key cannot be used if an opaque pixel also has that RGB color. */ + stats->alpha = 1; + stats->key = 0; + alpha_done = 1; + if(stats->bits < 8) stats->bits = 8; /*PNG has no alphachannel modes with less than 8-bit per channel*/ + } + } + } + + /*make the stats's key always 16-bit for consistency - repeat each byte twice*/ + stats->key_r += (stats->key_r << 8); + stats->key_g += (stats->key_g << 8); + stats->key_b += (stats->key_b << 8); + } + +cleanup: + color_tree_cleanup(&tree); + return error; +} + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS +/*Adds a single color to the color stats. The stats must already have been inited. The color must be given as 16-bit +(with 2 bytes repeating for 8-bit and 65535 for opaque alpha channel). This function is expensive, do not call it for +all pixels of an image but only for a few additional values. */ +static unsigned lodepng_color_stats_add(LodePNGColorStats* stats, + unsigned r, unsigned g, unsigned b, unsigned a) { + unsigned error = 0; + unsigned char image[8]; + LodePNGColorMode mode; + lodepng_color_mode_init(&mode); + image[0] = r >> 8; image[1] = r; image[2] = g >> 8; image[3] = g; + image[4] = b >> 8; image[5] = b; image[6] = a >> 8; image[7] = a; + mode.bitdepth = 16; + mode.colortype = LCT_RGBA; + error = lodepng_compute_color_stats(stats, image, 1, 1, &mode); + lodepng_color_mode_cleanup(&mode); + return error; +} +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +/*Computes a minimal PNG color model that can contain all colors as indicated by the stats. +The stats should be computed with lodepng_compute_color_stats. +mode_in is raw color profile of the image the stats were computed on, to copy palette order from when relevant. +Minimal PNG color model means the color type and bit depth that gives smallest amount of bits in the output image, +e.g. gray if only grayscale pixels, palette if less than 256 colors, color key if only single transparent color, ... +This is used if auto_convert is enabled (it is by default). +*/ +static unsigned auto_choose_color(LodePNGColorMode* mode_out, + const LodePNGColorMode* mode_in, + const LodePNGColorStats* stats) { + unsigned error = 0; + unsigned palettebits; + size_t i, n; + size_t numpixels = stats->numpixels; + unsigned palette_ok, gray_ok; + + unsigned alpha = stats->alpha; + unsigned key = stats->key; + unsigned bits = stats->bits; + + mode_out->key_defined = 0; + + if(key && numpixels <= 16) { + alpha = 1; /*too few pixels to justify tRNS chunk overhead*/ + key = 0; + if(bits < 8) bits = 8; /*PNG has no alphachannel modes with less than 8-bit per channel*/ + } + + gray_ok = !stats->colored; + if(!stats->allow_greyscale) gray_ok = 0; + if(!gray_ok && bits < 8) bits = 8; + + n = stats->numcolors; + palettebits = n <= 2 ? 1 : (n <= 4 ? 2 : (n <= 16 ? 4 : 8)); + palette_ok = n <= 256 && bits <= 8 && n != 0; /*n==0 means likely numcolors wasn't computed*/ + if(numpixels < n * 2) palette_ok = 0; /*don't add palette overhead if image has only a few pixels*/ + if(gray_ok && !alpha && bits <= palettebits) palette_ok = 0; /*gray is less overhead*/ + if(!stats->allow_palette) palette_ok = 0; + + if(palette_ok) { + const unsigned char* p = stats->palette; + lodepng_palette_clear(mode_out); /*remove potential earlier palette*/ + for(i = 0; i != stats->numcolors; ++i) { + error = lodepng_palette_add(mode_out, p[i * 4 + 0], p[i * 4 + 1], p[i * 4 + 2], p[i * 4 + 3]); + if(error) break; + } + + mode_out->colortype = LCT_PALETTE; + mode_out->bitdepth = palettebits; + + if(mode_in->colortype == LCT_PALETTE && mode_in->palettesize >= mode_out->palettesize + && mode_in->bitdepth == mode_out->bitdepth) { + /*If input should have same palette colors, keep original to preserve its order and prevent conversion*/ + lodepng_color_mode_cleanup(mode_out); + lodepng_color_mode_copy(mode_out, mode_in); + } + } else /*8-bit or 16-bit per channel*/ { + mode_out->bitdepth = bits; + mode_out->colortype = alpha ? (gray_ok ? LCT_GREY_ALPHA : LCT_RGBA) + : (gray_ok ? LCT_GREY : LCT_RGB); + if(key) { + unsigned mask = (1u << mode_out->bitdepth) - 1u; /*stats always uses 16-bit, mask converts it*/ + mode_out->key_r = stats->key_r & mask; + mode_out->key_g = stats->key_g & mask; + mode_out->key_b = stats->key_b & mask; + mode_out->key_defined = 1; + } + } + + return error; +} + +#endif /* #ifdef LODEPNG_COMPILE_ENCODER */ + +/* +Paeth predictor, used by PNG filter type 4 +The parameters are of type short, but should come from unsigned chars, the shorts +are only needed to make the paeth calculation correct. +*/ +static unsigned char paethPredictor(short a, short b, short c) { + short pa = LODEPNG_ABS(b - c); + short pb = LODEPNG_ABS(a - c); + short pc = LODEPNG_ABS(a + b - c - c); + /* return input value associated with smallest of pa, pb, pc (with certain priority if equal) */ + if(pb < pa) { a = b; pa = pb; } + return (pc < pa) ? c : a; +} + +/*shared values used by multiple Adam7 related functions*/ + +static const unsigned ADAM7_IX[7] = { 0, 4, 0, 2, 0, 1, 0 }; /*x start values*/ +static const unsigned ADAM7_IY[7] = { 0, 0, 4, 0, 2, 0, 1 }; /*y start values*/ +static const unsigned ADAM7_DX[7] = { 8, 8, 4, 4, 2, 2, 1 }; /*x delta values*/ +static const unsigned ADAM7_DY[7] = { 8, 8, 8, 4, 4, 2, 2 }; /*y delta values*/ + +/* +Outputs various dimensions and positions in the image related to the Adam7 reduced images. +passw: output containing the width of the 7 passes +passh: output containing the height of the 7 passes +filter_passstart: output containing the index of the start and end of each + reduced image with filter bytes +padded_passstart output containing the index of the start and end of each + reduced image when without filter bytes but with padded scanlines +passstart: output containing the index of the start and end of each reduced + image without padding between scanlines, but still padding between the images +w, h: width and height of non-interlaced image +bpp: bits per pixel +"padded" is only relevant if bpp is less than 8 and a scanline or image does not + end at a full byte +*/ +static void Adam7_getpassvalues(unsigned passw[7], unsigned passh[7], size_t filter_passstart[8], + size_t padded_passstart[8], size_t passstart[8], unsigned w, unsigned h, unsigned bpp) { + /*the passstart values have 8 values: the 8th one indicates the byte after the end of the 7th (= last) pass*/ + unsigned i; + + /*calculate width and height in pixels of each pass*/ + for(i = 0; i != 7; ++i) { + passw[i] = (w + ADAM7_DX[i] - ADAM7_IX[i] - 1) / ADAM7_DX[i]; + passh[i] = (h + ADAM7_DY[i] - ADAM7_IY[i] - 1) / ADAM7_DY[i]; + if(passw[i] == 0) passh[i] = 0; + if(passh[i] == 0) passw[i] = 0; + } + + filter_passstart[0] = padded_passstart[0] = passstart[0] = 0; + for(i = 0; i != 7; ++i) { + /*if passw[i] is 0, it's 0 bytes, not 1 (no filtertype-byte)*/ + filter_passstart[i + 1] = filter_passstart[i] + + ((passw[i] && passh[i]) ? passh[i] * (1u + (passw[i] * bpp + 7u) / 8u) : 0); + /*bits padded if needed to fill full byte at end of each scanline*/ + padded_passstart[i + 1] = padded_passstart[i] + passh[i] * ((passw[i] * bpp + 7u) / 8u); + /*only padded at end of reduced image*/ + passstart[i + 1] = passstart[i] + (passh[i] * passw[i] * bpp + 7u) / 8u; + } +} + +#ifdef LODEPNG_COMPILE_DECODER + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / PNG Decoder / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +/*read the information from the header and store it in the LodePNGInfo. return value is error*/ +unsigned lodepng_inspect(unsigned* w, unsigned* h, LodePNGState* state, + const unsigned char* in, size_t insize) { + unsigned width, height; + LodePNGInfo* info = &state->info_png; + if(insize == 0 || in == 0) { + CERROR_RETURN_ERROR(state->error, 48); /*error: the given data is empty*/ + } + if(insize < 33) { + CERROR_RETURN_ERROR(state->error, 27); /*error: the data length is smaller than the length of a PNG header*/ + } + + /*when decoding a new PNG image, make sure all parameters created after previous decoding are reset*/ + /* TODO: remove this. One should use a new LodePNGState for new sessions */ + lodepng_info_cleanup(info); + lodepng_info_init(info); + + if(in[0] != 137 || in[1] != 80 || in[2] != 78 || in[3] != 71 + || in[4] != 13 || in[5] != 10 || in[6] != 26 || in[7] != 10) { + CERROR_RETURN_ERROR(state->error, 28); /*error: the first 8 bytes are not the correct PNG signature*/ + } + if(lodepng_chunk_length(in + 8) != 13) { + CERROR_RETURN_ERROR(state->error, 94); /*error: header size must be 13 bytes*/ + } + if(!lodepng_chunk_type_equals(in + 8, "IHDR")) { + CERROR_RETURN_ERROR(state->error, 29); /*error: it doesn't start with a IHDR chunk!*/ + } + + /*read the values given in the header*/ + width = lodepng_read32bitInt(&in[16]); + height = lodepng_read32bitInt(&in[20]); + /*TODO: remove the undocumented feature that allows to give null pointers to width or height*/ + if(w) *w = width; + if(h) *h = height; + info->color.bitdepth = in[24]; + info->color.colortype = (LodePNGColorType)in[25]; + info->compression_method = in[26]; + info->filter_method = in[27]; + info->interlace_method = in[28]; + + /*errors returned only after the parsing so other values are still output*/ + + /*error: invalid image size*/ + if(width == 0 || height == 0) CERROR_RETURN_ERROR(state->error, 93); + /*error: invalid colortype or bitdepth combination*/ + state->error = checkColorValidity(info->color.colortype, info->color.bitdepth); + if(state->error) return state->error; + /*error: only compression method 0 is allowed in the specification*/ + if(info->compression_method != 0) CERROR_RETURN_ERROR(state->error, 32); + /*error: only filter method 0 is allowed in the specification*/ + if(info->filter_method != 0) CERROR_RETURN_ERROR(state->error, 33); + /*error: only interlace methods 0 and 1 exist in the specification*/ + if(info->interlace_method > 1) CERROR_RETURN_ERROR(state->error, 34); + + if(!state->decoder.ignore_crc) { + unsigned CRC = lodepng_read32bitInt(&in[29]); + unsigned checksum = lodepng_crc32(&in[12], 17); + if(CRC != checksum) { + CERROR_RETURN_ERROR(state->error, 57); /*invalid CRC*/ + } + } + + return state->error; +} + +static unsigned unfilterScanline(unsigned char* recon, const unsigned char* scanline, const unsigned char* precon, + size_t bytewidth, unsigned char filterType, size_t length) { + /* + For PNG filter method 0 + unfilter a PNG image scanline by scanline. when the pixels are smaller than 1 byte, + the filter works byte per byte (bytewidth = 1) + precon is the previous unfiltered scanline, recon the result, scanline the current one + the incoming scanlines do NOT include the filtertype byte, that one is given in the parameter filterType instead + recon and scanline MAY be the same memory address! precon must be disjoint. + */ + + size_t i; + switch(filterType) { + case 0: + for(i = 0; i != length; ++i) recon[i] = scanline[i]; + break; + case 1: + for(i = 0; i != bytewidth; ++i) recon[i] = scanline[i]; + for(i = bytewidth; i < length; ++i) recon[i] = scanline[i] + recon[i - bytewidth]; + break; + case 2: + if(precon) { + for(i = 0; i != length; ++i) recon[i] = scanline[i] + precon[i]; + } else { + for(i = 0; i != length; ++i) recon[i] = scanline[i]; + } + break; + case 3: + if(precon) { + for(i = 0; i != bytewidth; ++i) recon[i] = scanline[i] + (precon[i] >> 1u); + for(i = bytewidth; i < length; ++i) recon[i] = scanline[i] + ((recon[i - bytewidth] + precon[i]) >> 1u); + } else { + for(i = 0; i != bytewidth; ++i) recon[i] = scanline[i]; + for(i = bytewidth; i < length; ++i) recon[i] = scanline[i] + (recon[i - bytewidth] >> 1u); + } + break; + case 4: + if(precon) { + for(i = 0; i != bytewidth; ++i) { + recon[i] = (scanline[i] + precon[i]); /*paethPredictor(0, precon[i], 0) is always precon[i]*/ + } + + /* Unroll independent paths of the paeth predictor. A 6x and 8x version would also be possible but that + adds too much code. Whether this actually speeds anything up at all depends on compiler and settings. */ + if(bytewidth >= 4) { + for(; i + 3 < length; i += 4) { + size_t j = i - bytewidth; + unsigned char s0 = scanline[i + 0], s1 = scanline[i + 1], s2 = scanline[i + 2], s3 = scanline[i + 3]; + unsigned char r0 = recon[j + 0], r1 = recon[j + 1], r2 = recon[j + 2], r3 = recon[j + 3]; + unsigned char p0 = precon[i + 0], p1 = precon[i + 1], p2 = precon[i + 2], p3 = precon[i + 3]; + unsigned char q0 = precon[j + 0], q1 = precon[j + 1], q2 = precon[j + 2], q3 = precon[j + 3]; + recon[i + 0] = s0 + paethPredictor(r0, p0, q0); + recon[i + 1] = s1 + paethPredictor(r1, p1, q1); + recon[i + 2] = s2 + paethPredictor(r2, p2, q2); + recon[i + 3] = s3 + paethPredictor(r3, p3, q3); + } + } else if(bytewidth >= 3) { + for(; i + 2 < length; i += 3) { + size_t j = i - bytewidth; + unsigned char s0 = scanline[i + 0], s1 = scanline[i + 1], s2 = scanline[i + 2]; + unsigned char r0 = recon[j + 0], r1 = recon[j + 1], r2 = recon[j + 2]; + unsigned char p0 = precon[i + 0], p1 = precon[i + 1], p2 = precon[i + 2]; + unsigned char q0 = precon[j + 0], q1 = precon[j + 1], q2 = precon[j + 2]; + recon[i + 0] = s0 + paethPredictor(r0, p0, q0); + recon[i + 1] = s1 + paethPredictor(r1, p1, q1); + recon[i + 2] = s2 + paethPredictor(r2, p2, q2); + } + } else if(bytewidth >= 2) { + for(; i + 1 < length; i += 2) { + size_t j = i - bytewidth; + unsigned char s0 = scanline[i + 0], s1 = scanline[i + 1]; + unsigned char r0 = recon[j + 0], r1 = recon[j + 1]; + unsigned char p0 = precon[i + 0], p1 = precon[i + 1]; + unsigned char q0 = precon[j + 0], q1 = precon[j + 1]; + recon[i + 0] = s0 + paethPredictor(r0, p0, q0); + recon[i + 1] = s1 + paethPredictor(r1, p1, q1); + } + } + + for(; i != length; ++i) { + recon[i] = (scanline[i] + paethPredictor(recon[i - bytewidth], precon[i], precon[i - bytewidth])); + } + } else { + for(i = 0; i != bytewidth; ++i) { + recon[i] = scanline[i]; + } + for(i = bytewidth; i < length; ++i) { + /*paethPredictor(recon[i - bytewidth], 0, 0) is always recon[i - bytewidth]*/ + recon[i] = (scanline[i] + recon[i - bytewidth]); + } + } + break; + default: return 36; /*error: invalid filter type given*/ + } + return 0; +} + +static unsigned unfilter(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp) { + /* + For PNG filter method 0 + this function unfilters a single image (e.g. without interlacing this is called once, with Adam7 seven times) + out must have enough bytes allocated already, in must have the scanlines + 1 filtertype byte per scanline + w and h are image dimensions or dimensions of reduced image, bpp is bits per pixel + in and out are allowed to be the same memory address (but aren't the same size since in has the extra filter bytes) + */ + + unsigned y; + unsigned char* prevline = 0; + + /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise*/ + size_t bytewidth = (bpp + 7u) / 8u; + /*the width of a scanline in bytes, not including the filter type*/ + size_t linebytes = lodepng_get_raw_size_idat(w, 1, bpp) - 1u; + + for(y = 0; y < h; ++y) { + size_t outindex = linebytes * y; + size_t inindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/ + unsigned char filterType = in[inindex]; + + CERROR_TRY_RETURN(unfilterScanline(&out[outindex], &in[inindex + 1], prevline, bytewidth, filterType, linebytes)); + + prevline = &out[outindex]; + } + + return 0; +} + +/* +in: Adam7 interlaced image, with no padding bits between scanlines, but between + reduced images so that each reduced image starts at a byte. +out: the same pixels, but re-ordered so that they're now a non-interlaced image with size w*h +bpp: bits per pixel +out has the following size in bits: w * h * bpp. +in is possibly bigger due to padding bits between reduced images. +out must be big enough AND must be 0 everywhere if bpp < 8 in the current implementation +(because that's likely a little bit faster) +NOTE: comments about padding bits are only relevant if bpp < 8 +*/ +static void Adam7_deinterlace(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp) { + unsigned passw[7], passh[7]; + size_t filter_passstart[8], padded_passstart[8], passstart[8]; + unsigned i; + + Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); + + if(bpp >= 8) { + for(i = 0; i != 7; ++i) { + unsigned x, y, b; + size_t bytewidth = bpp / 8u; + for(y = 0; y < passh[i]; ++y) + for(x = 0; x < passw[i]; ++x) { + size_t pixelinstart = passstart[i] + (y * passw[i] + x) * bytewidth; + size_t pixeloutstart = ((ADAM7_IY[i] + (size_t)y * ADAM7_DY[i]) * (size_t)w + + ADAM7_IX[i] + (size_t)x * ADAM7_DX[i]) * bytewidth; + for(b = 0; b < bytewidth; ++b) { + out[pixeloutstart + b] = in[pixelinstart + b]; + } + } + } + } else /*bpp < 8: Adam7 with pixels < 8 bit is a bit trickier: with bit pointers*/ { + for(i = 0; i != 7; ++i) { + unsigned x, y, b; + unsigned ilinebits = bpp * passw[i]; + unsigned olinebits = bpp * w; + size_t obp, ibp; /*bit pointers (for out and in buffer)*/ + for(y = 0; y < passh[i]; ++y) + for(x = 0; x < passw[i]; ++x) { + ibp = (8 * passstart[i]) + (y * ilinebits + x * bpp); + obp = (ADAM7_IY[i] + (size_t)y * ADAM7_DY[i]) * olinebits + (ADAM7_IX[i] + (size_t)x * ADAM7_DX[i]) * bpp; + for(b = 0; b < bpp; ++b) { + unsigned char bit = readBitFromReversedStream(&ibp, in); + setBitOfReversedStream(&obp, out, bit); + } + } + } + } +} + +static void removePaddingBits(unsigned char* out, const unsigned char* in, + size_t olinebits, size_t ilinebits, unsigned h) { + /* + After filtering there are still padding bits if scanlines have non multiple of 8 bit amounts. They need + to be removed (except at last scanline of (Adam7-reduced) image) before working with pure image buffers + for the Adam7 code, the color convert code and the output to the user. + in and out are allowed to be the same buffer, in may also be higher but still overlapping; in must + have >= ilinebits*h bits, out must have >= olinebits*h bits, olinebits must be <= ilinebits + also used to move bits after earlier such operations happened, e.g. in a sequence of reduced images from Adam7 + only useful if (ilinebits - olinebits) is a value in the range 1..7 + */ + unsigned y; + size_t diff = ilinebits - olinebits; + size_t ibp = 0, obp = 0; /*input and output bit pointers*/ + for(y = 0; y < h; ++y) { + size_t x; + for(x = 0; x < olinebits; ++x) { + unsigned char bit = readBitFromReversedStream(&ibp, in); + setBitOfReversedStream(&obp, out, bit); + } + ibp += diff; + } +} + +/*out must be buffer big enough to contain full image, and in must contain the full decompressed data from +the IDAT chunks (with filter index bytes and possible padding bits) +return value is error*/ +static unsigned postProcessScanlines(unsigned char* out, unsigned char* in, + unsigned w, unsigned h, const LodePNGInfo* info_png) { + /* + This function converts the filtered-padded-interlaced data into pure 2D image buffer with the PNG's colortype. + Steps: + *) if no Adam7: 1) unfilter 2) remove padding bits (= possible extra bits per scanline if bpp < 8) + *) if adam7: 1) 7x unfilter 2) 7x remove padding bits 3) Adam7_deinterlace + NOTE: the in buffer will be overwritten with intermediate data! + */ + unsigned bpp = lodepng_get_bpp(&info_png->color); + if(bpp == 0) return 31; /*error: invalid colortype*/ + + if(info_png->interlace_method == 0) { + if(bpp < 8 && w * bpp != ((w * bpp + 7u) / 8u) * 8u) { + CERROR_TRY_RETURN(unfilter(in, in, w, h, bpp)); + removePaddingBits(out, in, w * bpp, ((w * bpp + 7u) / 8u) * 8u, h); + } + /*we can immediately filter into the out buffer, no other steps needed*/ + else CERROR_TRY_RETURN(unfilter(out, in, w, h, bpp)); + } else /*interlace_method is 1 (Adam7)*/ { + unsigned passw[7], passh[7]; size_t filter_passstart[8], padded_passstart[8], passstart[8]; + unsigned i; + + Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); + + for(i = 0; i != 7; ++i) { + CERROR_TRY_RETURN(unfilter(&in[padded_passstart[i]], &in[filter_passstart[i]], passw[i], passh[i], bpp)); + /*TODO: possible efficiency improvement: if in this reduced image the bits fit nicely in 1 scanline, + move bytes instead of bits or move not at all*/ + if(bpp < 8) { + /*remove padding bits in scanlines; after this there still may be padding + bits between the different reduced images: each reduced image still starts nicely at a byte*/ + removePaddingBits(&in[passstart[i]], &in[padded_passstart[i]], passw[i] * bpp, + ((passw[i] * bpp + 7u) / 8u) * 8u, passh[i]); + } + } + + Adam7_deinterlace(out, in, w, h, bpp); + } + + return 0; +} + +static unsigned readChunk_PLTE(LodePNGColorMode* color, const unsigned char* data, size_t chunkLength) { + unsigned pos = 0, i; + color->palettesize = chunkLength / 3u; + if(color->palettesize == 0 || color->palettesize > 256) return 38; /*error: palette too small or big*/ + lodepng_color_mode_alloc_palette(color); + if(!color->palette && color->palettesize) { + color->palettesize = 0; + return 83; /*alloc fail*/ + } + + for(i = 0; i != color->palettesize; ++i) { + color->palette[4 * i + 0] = data[pos++]; /*R*/ + color->palette[4 * i + 1] = data[pos++]; /*G*/ + color->palette[4 * i + 2] = data[pos++]; /*B*/ + color->palette[4 * i + 3] = 255; /*alpha*/ + } + + return 0; /* OK */ +} + +static unsigned readChunk_tRNS(LodePNGColorMode* color, const unsigned char* data, size_t chunkLength) { + unsigned i; + if(color->colortype == LCT_PALETTE) { + /*error: more alpha values given than there are palette entries*/ + if(chunkLength > color->palettesize) return 39; + + for(i = 0; i != chunkLength; ++i) color->palette[4 * i + 3] = data[i]; + } else if(color->colortype == LCT_GREY) { + /*error: this chunk must be 2 bytes for grayscale image*/ + if(chunkLength != 2) return 30; + + color->key_defined = 1; + color->key_r = color->key_g = color->key_b = 256u * data[0] + data[1]; + } else if(color->colortype == LCT_RGB) { + /*error: this chunk must be 6 bytes for RGB image*/ + if(chunkLength != 6) return 41; + + color->key_defined = 1; + color->key_r = 256u * data[0] + data[1]; + color->key_g = 256u * data[2] + data[3]; + color->key_b = 256u * data[4] + data[5]; + } + else return 42; /*error: tRNS chunk not allowed for other color models*/ + + return 0; /* OK */ +} + + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS +/*background color chunk (bKGD)*/ +static unsigned readChunk_bKGD(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) { + if(info->color.colortype == LCT_PALETTE) { + /*error: this chunk must be 1 byte for indexed color image*/ + if(chunkLength != 1) return 43; + + /*error: invalid palette index, or maybe this chunk appeared before PLTE*/ + if(data[0] >= info->color.palettesize) return 103; + + info->background_defined = 1; + info->background_r = info->background_g = info->background_b = data[0]; + } else if(info->color.colortype == LCT_GREY || info->color.colortype == LCT_GREY_ALPHA) { + /*error: this chunk must be 2 bytes for grayscale image*/ + if(chunkLength != 2) return 44; + + /*the values are truncated to bitdepth in the PNG file*/ + info->background_defined = 1; + info->background_r = info->background_g = info->background_b = 256u * data[0] + data[1]; + } else if(info->color.colortype == LCT_RGB || info->color.colortype == LCT_RGBA) { + /*error: this chunk must be 6 bytes for grayscale image*/ + if(chunkLength != 6) return 45; + + /*the values are truncated to bitdepth in the PNG file*/ + info->background_defined = 1; + info->background_r = 256u * data[0] + data[1]; + info->background_g = 256u * data[2] + data[3]; + info->background_b = 256u * data[4] + data[5]; + } + + return 0; /* OK */ +} + +/*text chunk (tEXt)*/ +static unsigned readChunk_tEXt(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) { + unsigned error = 0; + char *key = 0, *str = 0; + + while(!error) /*not really a while loop, only used to break on error*/ { + unsigned length, string2_begin; + + length = 0; + while(length < chunkLength && data[length] != 0) ++length; + /*even though it's not allowed by the standard, no error is thrown if + there's no null termination char, if the text is empty*/ + if(length < 1 || length > 79) CERROR_BREAK(error, 89); /*keyword too short or long*/ + + key = (char*)lodepng_malloc(length + 1); + if(!key) CERROR_BREAK(error, 83); /*alloc fail*/ + + lodepng_memcpy(key, data, length); + key[length] = 0; + + string2_begin = length + 1; /*skip keyword null terminator*/ + + length = (unsigned)(chunkLength < string2_begin ? 0 : chunkLength - string2_begin); + str = (char*)lodepng_malloc(length + 1); + if(!str) CERROR_BREAK(error, 83); /*alloc fail*/ + + lodepng_memcpy(str, data + string2_begin, length); + str[length] = 0; + + error = lodepng_add_text(info, key, str); + + break; + } + + lodepng_free(key); + lodepng_free(str); + + return error; +} + +/*compressed text chunk (zTXt)*/ +static unsigned readChunk_zTXt(LodePNGInfo* info, const LodePNGDecoderSettings* decoder, + const unsigned char* data, size_t chunkLength) { + unsigned error = 0; + + /*copy the object to change parameters in it*/ + LodePNGDecompressSettings zlibsettings = decoder->zlibsettings; + + unsigned length, string2_begin; + char *key = 0; + unsigned char* str = 0; + size_t size = 0; + + while(!error) /*not really a while loop, only used to break on error*/ { + for(length = 0; length < chunkLength && data[length] != 0; ++length) ; + if(length + 2 >= chunkLength) CERROR_BREAK(error, 75); /*no null termination, corrupt?*/ + if(length < 1 || length > 79) CERROR_BREAK(error, 89); /*keyword too short or long*/ + + key = (char*)lodepng_malloc(length + 1); + if(!key) CERROR_BREAK(error, 83); /*alloc fail*/ + + lodepng_memcpy(key, data, length); + key[length] = 0; + + if(data[length + 1] != 0) CERROR_BREAK(error, 72); /*the 0 byte indicating compression must be 0*/ + + string2_begin = length + 2; + if(string2_begin > chunkLength) CERROR_BREAK(error, 75); /*no null termination, corrupt?*/ + + length = (unsigned)chunkLength - string2_begin; + zlibsettings.max_output_size = decoder->max_text_size; + /*will fail if zlib error, e.g. if length is too small*/ + error = zlib_decompress(&str, &size, 0, &data[string2_begin], + length, &zlibsettings); + /*error: compressed text larger than decoder->max_text_size*/ + if(error && size > zlibsettings.max_output_size) error = 112; + if(error) break; + error = lodepng_add_text_sized(info, key, (char*)str, size); + break; + } + + lodepng_free(key); + lodepng_free(str); + + return error; +} + +/*international text chunk (iTXt)*/ +static unsigned readChunk_iTXt(LodePNGInfo* info, const LodePNGDecoderSettings* decoder, + const unsigned char* data, size_t chunkLength) { + unsigned error = 0; + unsigned i; + + /*copy the object to change parameters in it*/ + LodePNGDecompressSettings zlibsettings = decoder->zlibsettings; + + unsigned length, begin, compressed; + char *key = 0, *langtag = 0, *transkey = 0; + + while(!error) /*not really a while loop, only used to break on error*/ { + /*Quick check if the chunk length isn't too small. Even without check + it'd still fail with other error checks below if it's too short. This just gives a different error code.*/ + if(chunkLength < 5) CERROR_BREAK(error, 30); /*iTXt chunk too short*/ + + /*read the key*/ + for(length = 0; length < chunkLength && data[length] != 0; ++length) ; + if(length + 3 >= chunkLength) CERROR_BREAK(error, 75); /*no null termination char, corrupt?*/ + if(length < 1 || length > 79) CERROR_BREAK(error, 89); /*keyword too short or long*/ + + key = (char*)lodepng_malloc(length + 1); + if(!key) CERROR_BREAK(error, 83); /*alloc fail*/ + + lodepng_memcpy(key, data, length); + key[length] = 0; + + /*read the compression method*/ + compressed = data[length + 1]; + if(data[length + 2] != 0) CERROR_BREAK(error, 72); /*the 0 byte indicating compression must be 0*/ + + /*even though it's not allowed by the standard, no error is thrown if + there's no null termination char, if the text is empty for the next 3 texts*/ + + /*read the langtag*/ + begin = length + 3; + length = 0; + for(i = begin; i < chunkLength && data[i] != 0; ++i) ++length; + + langtag = (char*)lodepng_malloc(length + 1); + if(!langtag) CERROR_BREAK(error, 83); /*alloc fail*/ + + lodepng_memcpy(langtag, data + begin, length); + langtag[length] = 0; + + /*read the transkey*/ + begin += length + 1; + length = 0; + for(i = begin; i < chunkLength && data[i] != 0; ++i) ++length; + + transkey = (char*)lodepng_malloc(length + 1); + if(!transkey) CERROR_BREAK(error, 83); /*alloc fail*/ + + lodepng_memcpy(transkey, data + begin, length); + transkey[length] = 0; + + /*read the actual text*/ + begin += length + 1; + + length = (unsigned)chunkLength < begin ? 0 : (unsigned)chunkLength - begin; + + if(compressed) { + unsigned char* str = 0; + size_t size = 0; + zlibsettings.max_output_size = decoder->max_text_size; + /*will fail if zlib error, e.g. if length is too small*/ + error = zlib_decompress(&str, &size, 0, &data[begin], + length, &zlibsettings); + /*error: compressed text larger than decoder->max_text_size*/ + if(error && size > zlibsettings.max_output_size) error = 112; + if(!error) error = lodepng_add_itext_sized(info, key, langtag, transkey, (char*)str, size); + lodepng_free(str); + } else { + error = lodepng_add_itext_sized(info, key, langtag, transkey, (char*)(data + begin), length); + } + + break; + } + + lodepng_free(key); + lodepng_free(langtag); + lodepng_free(transkey); + + return error; +} + +static unsigned readChunk_tIME(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) { + if(chunkLength != 7) return 73; /*invalid tIME chunk size*/ + + info->time_defined = 1; + info->time.year = 256u * data[0] + data[1]; + info->time.month = data[2]; + info->time.day = data[3]; + info->time.hour = data[4]; + info->time.minute = data[5]; + info->time.second = data[6]; + + return 0; /* OK */ +} + +static unsigned readChunk_pHYs(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) { + if(chunkLength != 9) return 74; /*invalid pHYs chunk size*/ + + info->phys_defined = 1; + info->phys_x = 16777216u * data[0] + 65536u * data[1] + 256u * data[2] + data[3]; + info->phys_y = 16777216u * data[4] + 65536u * data[5] + 256u * data[6] + data[7]; + info->phys_unit = data[8]; + + return 0; /* OK */ +} + +static unsigned readChunk_gAMA(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) { + if(chunkLength != 4) return 96; /*invalid gAMA chunk size*/ + + info->gama_defined = 1; + info->gama_gamma = 16777216u * data[0] + 65536u * data[1] + 256u * data[2] + data[3]; + + return 0; /* OK */ +} + +static unsigned readChunk_cHRM(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) { + if(chunkLength != 32) return 97; /*invalid cHRM chunk size*/ + + info->chrm_defined = 1; + info->chrm_white_x = 16777216u * data[ 0] + 65536u * data[ 1] + 256u * data[ 2] + data[ 3]; + info->chrm_white_y = 16777216u * data[ 4] + 65536u * data[ 5] + 256u * data[ 6] + data[ 7]; + info->chrm_red_x = 16777216u * data[ 8] + 65536u * data[ 9] + 256u * data[10] + data[11]; + info->chrm_red_y = 16777216u * data[12] + 65536u * data[13] + 256u * data[14] + data[15]; + info->chrm_green_x = 16777216u * data[16] + 65536u * data[17] + 256u * data[18] + data[19]; + info->chrm_green_y = 16777216u * data[20] + 65536u * data[21] + 256u * data[22] + data[23]; + info->chrm_blue_x = 16777216u * data[24] + 65536u * data[25] + 256u * data[26] + data[27]; + info->chrm_blue_y = 16777216u * data[28] + 65536u * data[29] + 256u * data[30] + data[31]; + + return 0; /* OK */ +} + +static unsigned readChunk_sRGB(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) { + if(chunkLength != 1) return 98; /*invalid sRGB chunk size (this one is never ignored)*/ + + info->srgb_defined = 1; + info->srgb_intent = data[0]; + + return 0; /* OK */ +} + +static unsigned readChunk_iCCP(LodePNGInfo* info, const LodePNGDecoderSettings* decoder, + const unsigned char* data, size_t chunkLength) { + unsigned error = 0; + unsigned i; + size_t size = 0; + /*copy the object to change parameters in it*/ + LodePNGDecompressSettings zlibsettings = decoder->zlibsettings; + + unsigned length, string2_begin; + + info->iccp_defined = 1; + if(info->iccp_name) lodepng_clear_icc(info); + + for(length = 0; length < chunkLength && data[length] != 0; ++length) ; + if(length + 2 >= chunkLength) return 75; /*no null termination, corrupt?*/ + if(length < 1 || length > 79) return 89; /*keyword too short or long*/ + + info->iccp_name = (char*)lodepng_malloc(length + 1); + if(!info->iccp_name) return 83; /*alloc fail*/ + + info->iccp_name[length] = 0; + for(i = 0; i != length; ++i) info->iccp_name[i] = (char)data[i]; + + if(data[length + 1] != 0) return 72; /*the 0 byte indicating compression must be 0*/ + + string2_begin = length + 2; + if(string2_begin > chunkLength) return 75; /*no null termination, corrupt?*/ + + length = (unsigned)chunkLength - string2_begin; + zlibsettings.max_output_size = decoder->max_icc_size; + error = zlib_decompress(&info->iccp_profile, &size, 0, + &data[string2_begin], + length, &zlibsettings); + /*error: ICC profile larger than decoder->max_icc_size*/ + if(error && size > zlibsettings.max_output_size) error = 113; + info->iccp_profile_size = size; + if(!error && !info->iccp_profile_size) error = 100; /*invalid ICC profile size*/ + return error; +} +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +unsigned lodepng_inspect_chunk(LodePNGState* state, size_t pos, + const unsigned char* in, size_t insize) { + const unsigned char* chunk = in + pos; + unsigned chunkLength; + const unsigned char* data; + unsigned unhandled = 0; + unsigned error = 0; + + if(pos + 4 > insize) return 30; + chunkLength = lodepng_chunk_length(chunk); + if(chunkLength > 2147483647) return 63; + data = lodepng_chunk_data_const(chunk); + if(data + chunkLength + 4 > in + insize) return 30; + + if(lodepng_chunk_type_equals(chunk, "PLTE")) { + error = readChunk_PLTE(&state->info_png.color, data, chunkLength); + } else if(lodepng_chunk_type_equals(chunk, "tRNS")) { + error = readChunk_tRNS(&state->info_png.color, data, chunkLength); +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + } else if(lodepng_chunk_type_equals(chunk, "bKGD")) { + error = readChunk_bKGD(&state->info_png, data, chunkLength); + } else if(lodepng_chunk_type_equals(chunk, "tEXt")) { + error = readChunk_tEXt(&state->info_png, data, chunkLength); + } else if(lodepng_chunk_type_equals(chunk, "zTXt")) { + error = readChunk_zTXt(&state->info_png, &state->decoder, data, chunkLength); + } else if(lodepng_chunk_type_equals(chunk, "iTXt")) { + error = readChunk_iTXt(&state->info_png, &state->decoder, data, chunkLength); + } else if(lodepng_chunk_type_equals(chunk, "tIME")) { + error = readChunk_tIME(&state->info_png, data, chunkLength); + } else if(lodepng_chunk_type_equals(chunk, "pHYs")) { + error = readChunk_pHYs(&state->info_png, data, chunkLength); + } else if(lodepng_chunk_type_equals(chunk, "gAMA")) { + error = readChunk_gAMA(&state->info_png, data, chunkLength); + } else if(lodepng_chunk_type_equals(chunk, "cHRM")) { + error = readChunk_cHRM(&state->info_png, data, chunkLength); + } else if(lodepng_chunk_type_equals(chunk, "sRGB")) { + error = readChunk_sRGB(&state->info_png, data, chunkLength); + } else if(lodepng_chunk_type_equals(chunk, "iCCP")) { + error = readChunk_iCCP(&state->info_png, &state->decoder, data, chunkLength); +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + } else { + /* unhandled chunk is ok (is not an error) */ + unhandled = 1; + } + + if(!error && !unhandled && !state->decoder.ignore_crc) { + if(lodepng_chunk_check_crc(chunk)) return 57; /*invalid CRC*/ + } + + return error; +} + +/*read a PNG, the result will be in the same color type as the PNG (hence "generic")*/ +static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h, + LodePNGState* state, + const unsigned char* in, size_t insize) { + unsigned char IEND = 0; + const unsigned char* chunk; + unsigned char* idat; /*the data from idat chunks, zlib compressed*/ + size_t idatsize = 0; + unsigned char* scanlines = 0; + size_t scanlines_size = 0, expected_size = 0; + size_t outsize = 0; + + /*for unknown chunk order*/ + unsigned unknown = 0; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + unsigned critical_pos = 1; /*1 = after IHDR, 2 = after PLTE, 3 = after IDAT*/ +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + + + /* safe output values in case error happens */ + *out = 0; + *w = *h = 0; + + state->error = lodepng_inspect(w, h, state, in, insize); /*reads header and resets other parameters in state->info_png*/ + if(state->error) return; + + if(lodepng_pixel_overflow(*w, *h, &state->info_png.color, &state->info_raw)) { + CERROR_RETURN(state->error, 92); /*overflow possible due to amount of pixels*/ + } + + /*the input filesize is a safe upper bound for the sum of idat chunks size*/ + idat = (unsigned char*)lodepng_malloc(insize); + if(!idat) CERROR_RETURN(state->error, 83); /*alloc fail*/ + + chunk = &in[33]; /*first byte of the first chunk after the header*/ + + /*loop through the chunks, ignoring unknown chunks and stopping at IEND chunk. + IDAT data is put at the start of the in buffer*/ + while(!IEND && !state->error) { + unsigned chunkLength; + const unsigned char* data; /*the data in the chunk*/ + + /*error: size of the in buffer too small to contain next chunk*/ + if((size_t)((chunk - in) + 12) > insize || chunk < in) { + if(state->decoder.ignore_end) break; /*other errors may still happen though*/ + CERROR_BREAK(state->error, 30); + } + + /*length of the data of the chunk, excluding the length bytes, chunk type and CRC bytes*/ + chunkLength = lodepng_chunk_length(chunk); + /*error: chunk length larger than the max PNG chunk size*/ + if(chunkLength > 2147483647) { + if(state->decoder.ignore_end) break; /*other errors may still happen though*/ + CERROR_BREAK(state->error, 63); + } + + if((size_t)((chunk - in) + chunkLength + 12) > insize || (chunk + chunkLength + 12) < in) { + CERROR_BREAK(state->error, 64); /*error: size of the in buffer too small to contain next chunk*/ + } + + data = lodepng_chunk_data_const(chunk); + + unknown = 0; + + /*IDAT chunk, containing compressed image data*/ + if(lodepng_chunk_type_equals(chunk, "IDAT")) { + size_t newsize; + if(lodepng_addofl(idatsize, chunkLength, &newsize)) CERROR_BREAK(state->error, 95); + if(newsize > insize) CERROR_BREAK(state->error, 95); + lodepng_memcpy(idat + idatsize, data, chunkLength); + idatsize += chunkLength; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + critical_pos = 3; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + } else if(lodepng_chunk_type_equals(chunk, "IEND")) { + /*IEND chunk*/ + IEND = 1; + } else if(lodepng_chunk_type_equals(chunk, "PLTE")) { + /*palette chunk (PLTE)*/ + state->error = readChunk_PLTE(&state->info_png.color, data, chunkLength); + if(state->error) break; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + critical_pos = 2; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + } else if(lodepng_chunk_type_equals(chunk, "tRNS")) { + /*palette transparency chunk (tRNS). Even though this one is an ancillary chunk , it is still compiled + in without 'LODEPNG_COMPILE_ANCILLARY_CHUNKS' because it contains essential color information that + affects the alpha channel of pixels. */ + state->error = readChunk_tRNS(&state->info_png.color, data, chunkLength); + if(state->error) break; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /*background color chunk (bKGD)*/ + } else if(lodepng_chunk_type_equals(chunk, "bKGD")) { + state->error = readChunk_bKGD(&state->info_png, data, chunkLength); + if(state->error) break; + } else if(lodepng_chunk_type_equals(chunk, "tEXt")) { + /*text chunk (tEXt)*/ + if(state->decoder.read_text_chunks) { + state->error = readChunk_tEXt(&state->info_png, data, chunkLength); + if(state->error) break; + } + } else if(lodepng_chunk_type_equals(chunk, "zTXt")) { + /*compressed text chunk (zTXt)*/ + if(state->decoder.read_text_chunks) { + state->error = readChunk_zTXt(&state->info_png, &state->decoder, data, chunkLength); + if(state->error) break; + } + } else if(lodepng_chunk_type_equals(chunk, "iTXt")) { + /*international text chunk (iTXt)*/ + if(state->decoder.read_text_chunks) { + state->error = readChunk_iTXt(&state->info_png, &state->decoder, data, chunkLength); + if(state->error) break; + } + } else if(lodepng_chunk_type_equals(chunk, "tIME")) { + state->error = readChunk_tIME(&state->info_png, data, chunkLength); + if(state->error) break; + } else if(lodepng_chunk_type_equals(chunk, "pHYs")) { + state->error = readChunk_pHYs(&state->info_png, data, chunkLength); + if(state->error) break; + } else if(lodepng_chunk_type_equals(chunk, "gAMA")) { + state->error = readChunk_gAMA(&state->info_png, data, chunkLength); + if(state->error) break; + } else if(lodepng_chunk_type_equals(chunk, "cHRM")) { + state->error = readChunk_cHRM(&state->info_png, data, chunkLength); + if(state->error) break; + } else if(lodepng_chunk_type_equals(chunk, "sRGB")) { + state->error = readChunk_sRGB(&state->info_png, data, chunkLength); + if(state->error) break; + } else if(lodepng_chunk_type_equals(chunk, "iCCP")) { + state->error = readChunk_iCCP(&state->info_png, &state->decoder, data, chunkLength); + if(state->error) break; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + } else /*it's not an implemented chunk type, so ignore it: skip over the data*/ { + /*error: unknown critical chunk (5th bit of first byte of chunk type is 0)*/ + if(!state->decoder.ignore_critical && !lodepng_chunk_ancillary(chunk)) { + CERROR_BREAK(state->error, 69); + } + + unknown = 1; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + if(state->decoder.remember_unknown_chunks) { + state->error = lodepng_chunk_append(&state->info_png.unknown_chunks_data[critical_pos - 1], + &state->info_png.unknown_chunks_size[critical_pos - 1], chunk); + if(state->error) break; + } +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + } + + if(!state->decoder.ignore_crc && !unknown) /*check CRC if wanted, only on known chunk types*/ { + if(lodepng_chunk_check_crc(chunk)) CERROR_BREAK(state->error, 57); /*invalid CRC*/ + } + + if(!IEND) chunk = lodepng_chunk_next_const(chunk, in + insize); + } + + if(!state->error && state->info_png.color.colortype == LCT_PALETTE && !state->info_png.color.palette) { + state->error = 106; /* error: PNG file must have PLTE chunk if color type is palette */ + } + + if(!state->error) { + /*predict output size, to allocate exact size for output buffer to avoid more dynamic allocation. + If the decompressed size does not match the prediction, the image must be corrupt.*/ + if(state->info_png.interlace_method == 0) { + size_t bpp = lodepng_get_bpp(&state->info_png.color); + expected_size = lodepng_get_raw_size_idat(*w, *h, bpp); + } else { + size_t bpp = lodepng_get_bpp(&state->info_png.color); + /*Adam-7 interlaced: expected size is the sum of the 7 sub-images sizes*/ + expected_size = 0; + expected_size += lodepng_get_raw_size_idat((*w + 7) >> 3, (*h + 7) >> 3, bpp); + if(*w > 4) expected_size += lodepng_get_raw_size_idat((*w + 3) >> 3, (*h + 7) >> 3, bpp); + expected_size += lodepng_get_raw_size_idat((*w + 3) >> 2, (*h + 3) >> 3, bpp); + if(*w > 2) expected_size += lodepng_get_raw_size_idat((*w + 1) >> 2, (*h + 3) >> 2, bpp); + expected_size += lodepng_get_raw_size_idat((*w + 1) >> 1, (*h + 1) >> 2, bpp); + if(*w > 1) expected_size += lodepng_get_raw_size_idat((*w + 0) >> 1, (*h + 1) >> 1, bpp); + expected_size += lodepng_get_raw_size_idat((*w + 0), (*h + 0) >> 1, bpp); + } + + state->error = zlib_decompress(&scanlines, &scanlines_size, expected_size, idat, idatsize, &state->decoder.zlibsettings); + } + if(!state->error && scanlines_size != expected_size) state->error = 91; /*decompressed size doesn't match prediction*/ + lodepng_free(idat); + + if(!state->error) { + outsize = lodepng_get_raw_size(*w, *h, &state->info_png.color); + *out = (unsigned char*)lodepng_malloc(outsize); + if(!*out) state->error = 83; /*alloc fail*/ + } + if(!state->error) { + lodepng_memset(*out, 0, outsize); + state->error = postProcessScanlines(*out, scanlines, *w, *h, &state->info_png); + } + lodepng_free(scanlines); +} + +unsigned lodepng_decode(unsigned char** out, unsigned* w, unsigned* h, + LodePNGState* state, + const unsigned char* in, size_t insize) { + *out = 0; + decodeGeneric(out, w, h, state, in, insize); + if(state->error) return state->error; + if(!state->decoder.color_convert || lodepng_color_mode_equal(&state->info_raw, &state->info_png.color)) { + /*same color type, no copying or converting of data needed*/ + /*store the info_png color settings on the info_raw so that the info_raw still reflects what colortype + the raw image has to the end user*/ + if(!state->decoder.color_convert) { + state->error = lodepng_color_mode_copy(&state->info_raw, &state->info_png.color); + if(state->error) return state->error; + } + } else { /*color conversion needed*/ + unsigned char* data = *out; + size_t outsize; + + /*TODO: check if this works according to the statement in the documentation: "The converter can convert + from grayscale input color type, to 8-bit grayscale or grayscale with alpha"*/ + if(!(state->info_raw.colortype == LCT_RGB || state->info_raw.colortype == LCT_RGBA) + && !(state->info_raw.bitdepth == 8)) { + return 56; /*unsupported color mode conversion*/ + } + + outsize = lodepng_get_raw_size(*w, *h, &state->info_raw); + *out = (unsigned char*)lodepng_malloc(outsize); + if(!(*out)) { + state->error = 83; /*alloc fail*/ + } + else state->error = lodepng_convert(*out, data, &state->info_raw, + &state->info_png.color, *w, *h); + lodepng_free(data); + } + return state->error; +} + +unsigned lodepng_decode_memory(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, + size_t insize, LodePNGColorType colortype, unsigned bitdepth) { + unsigned error; + LodePNGState state; + lodepng_state_init(&state); + state.info_raw.colortype = colortype; + state.info_raw.bitdepth = bitdepth; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /*disable reading things that this function doesn't output*/ + state.decoder.read_text_chunks = 0; + state.decoder.remember_unknown_chunks = 0; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + error = lodepng_decode(out, w, h, &state, in, insize); + lodepng_state_cleanup(&state); + return error; +} + +unsigned lodepng_decode32(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize) { + return lodepng_decode_memory(out, w, h, in, insize, LCT_RGBA, 8); +} + +unsigned lodepng_decode24(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize) { + return lodepng_decode_memory(out, w, h, in, insize, LCT_RGB, 8); +} + +#ifdef LODEPNG_COMPILE_DISK +unsigned lodepng_decode_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename, + LodePNGColorType colortype, unsigned bitdepth) { + unsigned char* buffer = 0; + size_t buffersize; + unsigned error; + /* safe output values in case error happens */ + *out = 0; + *w = *h = 0; + error = lodepng_load_file(&buffer, &buffersize, filename); + if(!error) error = lodepng_decode_memory(out, w, h, buffer, buffersize, colortype, bitdepth); + lodepng_free(buffer); + return error; +} + +unsigned lodepng_decode32_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename) { + return lodepng_decode_file(out, w, h, filename, LCT_RGBA, 8); +} + +unsigned lodepng_decode24_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename) { + return lodepng_decode_file(out, w, h, filename, LCT_RGB, 8); +} +#endif /*LODEPNG_COMPILE_DISK*/ + +void lodepng_decoder_settings_init(LodePNGDecoderSettings* settings) { + settings->color_convert = 1; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + settings->read_text_chunks = 1; + settings->remember_unknown_chunks = 0; + settings->max_text_size = 16777216; + settings->max_icc_size = 16777216; /* 16MB is much more than enough for any reasonable ICC profile */ +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + settings->ignore_crc = 0; + settings->ignore_critical = 0; + settings->ignore_end = 0; + lodepng_decompress_settings_init(&settings->zlibsettings); +} + +#endif /*LODEPNG_COMPILE_DECODER*/ + +#if defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) + +void lodepng_state_init(LodePNGState* state) { +#ifdef LODEPNG_COMPILE_DECODER + lodepng_decoder_settings_init(&state->decoder); +#endif /*LODEPNG_COMPILE_DECODER*/ +#ifdef LODEPNG_COMPILE_ENCODER + lodepng_encoder_settings_init(&state->encoder); +#endif /*LODEPNG_COMPILE_ENCODER*/ + lodepng_color_mode_init(&state->info_raw); + lodepng_info_init(&state->info_png); + state->error = 1; +} + +void lodepng_state_cleanup(LodePNGState* state) { + lodepng_color_mode_cleanup(&state->info_raw); + lodepng_info_cleanup(&state->info_png); +} + +void lodepng_state_copy(LodePNGState* dest, const LodePNGState* source) { + lodepng_state_cleanup(dest); + *dest = *source; + lodepng_color_mode_init(&dest->info_raw); + lodepng_info_init(&dest->info_png); + dest->error = lodepng_color_mode_copy(&dest->info_raw, &source->info_raw); if(dest->error) return; + dest->error = lodepng_info_copy(&dest->info_png, &source->info_png); if(dest->error) return; +} + +#endif /* defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) */ + +#ifdef LODEPNG_COMPILE_ENCODER + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / PNG Encoder / */ +/* ////////////////////////////////////////////////////////////////////////// */ + + +static unsigned writeSignature(ucvector* out) { + size_t pos = out->size; + const unsigned char signature[] = {137, 80, 78, 71, 13, 10, 26, 10}; + /*8 bytes PNG signature, aka the magic bytes*/ + if(!ucvector_resize(out, out->size + 8)) return 83; /*alloc fail*/ + lodepng_memcpy(out->data + pos, signature, 8); + return 0; +} + +static unsigned addChunk_IHDR(ucvector* out, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth, unsigned interlace_method) { + unsigned char *chunk, *data; + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 13, "IHDR")); + data = chunk + 8; + + lodepng_set32bitInt(data + 0, w); /*width*/ + lodepng_set32bitInt(data + 4, h); /*height*/ + data[8] = (unsigned char)bitdepth; /*bit depth*/ + data[9] = (unsigned char)colortype; /*color type*/ + data[10] = 0; /*compression method*/ + data[11] = 0; /*filter method*/ + data[12] = interlace_method; /*interlace method*/ + + lodepng_chunk_generate_crc(chunk); + return 0; +} + +/* only adds the chunk if needed (there is a key or palette with alpha) */ +static unsigned addChunk_PLTE(ucvector* out, const LodePNGColorMode* info) { + unsigned char* chunk; + size_t i, j = 8; + + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, info->palettesize * 3, "PLTE")); + + for(i = 0; i != info->palettesize; ++i) { + /*add all channels except alpha channel*/ + chunk[j++] = info->palette[i * 4 + 0]; + chunk[j++] = info->palette[i * 4 + 1]; + chunk[j++] = info->palette[i * 4 + 2]; + } + + lodepng_chunk_generate_crc(chunk); + return 0; +} + +static unsigned addChunk_tRNS(ucvector* out, const LodePNGColorMode* info) { + unsigned char* chunk = 0; + + if(info->colortype == LCT_PALETTE) { + size_t i, amount = info->palettesize; + /*the tail of palette values that all have 255 as alpha, does not have to be encoded*/ + for(i = info->palettesize; i != 0; --i) { + if(info->palette[4 * (i - 1) + 3] != 255) break; + --amount; + } + if(amount) { + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, amount, "tRNS")); + /*add the alpha channel values from the palette*/ + for(i = 0; i != amount; ++i) chunk[8 + i] = info->palette[4 * i + 3]; + } + } else if(info->colortype == LCT_GREY) { + if(info->key_defined) { + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 2, "tRNS")); + chunk[8] = (unsigned char)(info->key_r >> 8); + chunk[9] = (unsigned char)(info->key_r & 255); + } + } else if(info->colortype == LCT_RGB) { + if(info->key_defined) { + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 6, "tRNS")); + chunk[8] = (unsigned char)(info->key_r >> 8); + chunk[9] = (unsigned char)(info->key_r & 255); + chunk[10] = (unsigned char)(info->key_g >> 8); + chunk[11] = (unsigned char)(info->key_g & 255); + chunk[12] = (unsigned char)(info->key_b >> 8); + chunk[13] = (unsigned char)(info->key_b & 255); + } + } + + if(chunk) lodepng_chunk_generate_crc(chunk); + return 0; +} + +static unsigned addChunk_IDAT(ucvector* out, const unsigned char* data, size_t datasize, + LodePNGCompressSettings* zlibsettings) { + unsigned error = 0; + unsigned char* zlib = 0; + size_t zlibsize = 0; + + error = zlib_compress(&zlib, &zlibsize, data, datasize, zlibsettings); + if(!error) { + error = lodepng_chunk_createv(out, zlibsize, "IDAT", zlib); + } + lodepng_free(zlib); + return error; +} + +static unsigned addChunk_IEND(ucvector* out) { + return lodepng_chunk_createv(out, 0, "IEND", 0); +} + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + +static unsigned addChunk_tEXt(ucvector* out, const char* keyword, const char* textstring) { + unsigned char* chunk = 0; + size_t keysize = lodepng_strlen(keyword), textsize = lodepng_strlen(textstring); + size_t size = keysize + 1 + textsize; + if(keysize < 1 || keysize > 79) return 89; /*error: invalid keyword size*/ + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, size, "tEXt")); + lodepng_memcpy(chunk + 8, keyword, keysize); + chunk[8 + keysize] = 0; /*null termination char*/ + lodepng_memcpy(chunk + 9 + keysize, textstring, textsize); + lodepng_chunk_generate_crc(chunk); + return 0; +} + +static unsigned addChunk_zTXt(ucvector* out, const char* keyword, const char* textstring, + LodePNGCompressSettings* zlibsettings) { + unsigned error = 0; + unsigned char* chunk = 0; + unsigned char* compressed = 0; + size_t compressedsize = 0; + size_t textsize = lodepng_strlen(textstring); + size_t keysize = lodepng_strlen(keyword); + if(keysize < 1 || keysize > 79) return 89; /*error: invalid keyword size*/ + + error = zlib_compress(&compressed, &compressedsize, + (const unsigned char*)textstring, textsize, zlibsettings); + if(!error) { + size_t size = keysize + 2 + compressedsize; + error = lodepng_chunk_init(&chunk, out, size, "zTXt"); + } + if(!error) { + lodepng_memcpy(chunk + 8, keyword, keysize); + chunk[8 + keysize] = 0; /*null termination char*/ + chunk[9 + keysize] = 0; /*compression method: 0*/ + lodepng_memcpy(chunk + 10 + keysize, compressed, compressedsize); + lodepng_chunk_generate_crc(chunk); + } + + lodepng_free(compressed); + return error; +} + +static unsigned addChunk_iTXt(ucvector* out, unsigned compress, const char* keyword, const char* langtag, + const char* transkey, const char* textstring, LodePNGCompressSettings* zlibsettings) { + unsigned error = 0; + unsigned char* chunk = 0; + unsigned char* compressed = 0; + size_t compressedsize = 0; + size_t textsize = lodepng_strlen(textstring); + size_t keysize = lodepng_strlen(keyword), langsize = lodepng_strlen(langtag), transsize = lodepng_strlen(transkey); + + if(keysize < 1 || keysize > 79) return 89; /*error: invalid keyword size*/ + + if(compress) { + error = zlib_compress(&compressed, &compressedsize, + (const unsigned char*)textstring, textsize, zlibsettings); + } + if(!error) { + size_t size = keysize + 3 + langsize + 1 + transsize + 1 + (compress ? compressedsize : textsize); + error = lodepng_chunk_init(&chunk, out, size, "iTXt"); + } + if(!error) { + size_t pos = 8; + lodepng_memcpy(chunk + pos, keyword, keysize); + pos += keysize; + chunk[pos++] = 0; /*null termination char*/ + chunk[pos++] = (compress ? 1 : 0); /*compression flag*/ + chunk[pos++] = 0; /*compression method: 0*/ + lodepng_memcpy(chunk + pos, langtag, langsize); + pos += langsize; + chunk[pos++] = 0; /*null termination char*/ + lodepng_memcpy(chunk + pos, transkey, transsize); + pos += transsize; + chunk[pos++] = 0; /*null termination char*/ + if(compress) { + lodepng_memcpy(chunk + pos, compressed, compressedsize); + } else { + lodepng_memcpy(chunk + pos, textstring, textsize); + } + lodepng_chunk_generate_crc(chunk); + } + + lodepng_free(compressed); + return error; +} + +static unsigned addChunk_bKGD(ucvector* out, const LodePNGInfo* info) { + unsigned char* chunk = 0; + if(info->color.colortype == LCT_GREY || info->color.colortype == LCT_GREY_ALPHA) { + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 2, "bKGD")); + chunk[8] = (unsigned char)(info->background_r >> 8); + chunk[9] = (unsigned char)(info->background_r & 255); + } else if(info->color.colortype == LCT_RGB || info->color.colortype == LCT_RGBA) { + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 6, "bKGD")); + chunk[8] = (unsigned char)(info->background_r >> 8); + chunk[9] = (unsigned char)(info->background_r & 255); + chunk[10] = (unsigned char)(info->background_g >> 8); + chunk[11] = (unsigned char)(info->background_g & 255); + chunk[12] = (unsigned char)(info->background_b >> 8); + chunk[13] = (unsigned char)(info->background_b & 255); + } else if(info->color.colortype == LCT_PALETTE) { + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 1, "bKGD")); + chunk[8] = (unsigned char)(info->background_r & 255); /*palette index*/ + } + if(chunk) lodepng_chunk_generate_crc(chunk); + return 0; +} + +static unsigned addChunk_tIME(ucvector* out, const LodePNGTime* time) { + unsigned char* chunk; + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 7, "tIME")); + chunk[8] = (unsigned char)(time->year >> 8); + chunk[9] = (unsigned char)(time->year & 255); + chunk[10] = (unsigned char)time->month; + chunk[11] = (unsigned char)time->day; + chunk[12] = (unsigned char)time->hour; + chunk[13] = (unsigned char)time->minute; + chunk[14] = (unsigned char)time->second; + lodepng_chunk_generate_crc(chunk); + return 0; +} + +static unsigned addChunk_pHYs(ucvector* out, const LodePNGInfo* info) { + unsigned char* chunk; + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 9, "pHYs")); + lodepng_set32bitInt(chunk + 8, info->phys_x); + lodepng_set32bitInt(chunk + 12, info->phys_y); + chunk[16] = info->phys_unit; + lodepng_chunk_generate_crc(chunk); + return 0; +} + +static unsigned addChunk_gAMA(ucvector* out, const LodePNGInfo* info) { + unsigned char* chunk; + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 4, "gAMA")); + lodepng_set32bitInt(chunk + 8, info->gama_gamma); + lodepng_chunk_generate_crc(chunk); + return 0; +} + +static unsigned addChunk_cHRM(ucvector* out, const LodePNGInfo* info) { + unsigned char* chunk; + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 32, "cHRM")); + lodepng_set32bitInt(chunk + 8, info->chrm_white_x); + lodepng_set32bitInt(chunk + 12, info->chrm_white_y); + lodepng_set32bitInt(chunk + 16, info->chrm_red_x); + lodepng_set32bitInt(chunk + 20, info->chrm_red_y); + lodepng_set32bitInt(chunk + 24, info->chrm_green_x); + lodepng_set32bitInt(chunk + 28, info->chrm_green_y); + lodepng_set32bitInt(chunk + 32, info->chrm_blue_x); + lodepng_set32bitInt(chunk + 36, info->chrm_blue_y); + lodepng_chunk_generate_crc(chunk); + return 0; +} + +static unsigned addChunk_sRGB(ucvector* out, const LodePNGInfo* info) { + unsigned char data = info->srgb_intent; + return lodepng_chunk_createv(out, 1, "sRGB", &data); +} + +static unsigned addChunk_iCCP(ucvector* out, const LodePNGInfo* info, LodePNGCompressSettings* zlibsettings) { + unsigned error = 0; + unsigned char* chunk = 0; + unsigned char* compressed = 0; + size_t compressedsize = 0; + size_t keysize = lodepng_strlen(info->iccp_name); + + if(keysize < 1 || keysize > 79) return 89; /*error: invalid keyword size*/ + error = zlib_compress(&compressed, &compressedsize, + info->iccp_profile, info->iccp_profile_size, zlibsettings); + if(!error) { + size_t size = keysize + 2 + compressedsize; + error = lodepng_chunk_init(&chunk, out, size, "iCCP"); + } + if(!error) { + lodepng_memcpy(chunk + 8, info->iccp_name, keysize); + chunk[8 + keysize] = 0; /*null termination char*/ + chunk[9 + keysize] = 0; /*compression method: 0*/ + lodepng_memcpy(chunk + 10 + keysize, compressed, compressedsize); + lodepng_chunk_generate_crc(chunk); + } + + lodepng_free(compressed); + return error; +} + +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +static void filterScanline(unsigned char* out, const unsigned char* scanline, const unsigned char* prevline, + size_t length, size_t bytewidth, unsigned char filterType) { + size_t i; + switch(filterType) { + case 0: /*None*/ + for(i = 0; i != length; ++i) out[i] = scanline[i]; + break; + case 1: /*Sub*/ + for(i = 0; i != bytewidth; ++i) out[i] = scanline[i]; + for(i = bytewidth; i < length; ++i) out[i] = scanline[i] - scanline[i - bytewidth]; + break; + case 2: /*Up*/ + if(prevline) { + for(i = 0; i != length; ++i) out[i] = scanline[i] - prevline[i]; + } else { + for(i = 0; i != length; ++i) out[i] = scanline[i]; + } + break; + case 3: /*Average*/ + if(prevline) { + for(i = 0; i != bytewidth; ++i) out[i] = scanline[i] - (prevline[i] >> 1); + for(i = bytewidth; i < length; ++i) out[i] = scanline[i] - ((scanline[i - bytewidth] + prevline[i]) >> 1); + } else { + for(i = 0; i != bytewidth; ++i) out[i] = scanline[i]; + for(i = bytewidth; i < length; ++i) out[i] = scanline[i] - (scanline[i - bytewidth] >> 1); + } + break; + case 4: /*Paeth*/ + if(prevline) { + /*paethPredictor(0, prevline[i], 0) is always prevline[i]*/ + for(i = 0; i != bytewidth; ++i) out[i] = (scanline[i] - prevline[i]); + for(i = bytewidth; i < length; ++i) { + out[i] = (scanline[i] - paethPredictor(scanline[i - bytewidth], prevline[i], prevline[i - bytewidth])); + } + } else { + for(i = 0; i != bytewidth; ++i) out[i] = scanline[i]; + /*paethPredictor(scanline[i - bytewidth], 0, 0) is always scanline[i - bytewidth]*/ + for(i = bytewidth; i < length; ++i) out[i] = (scanline[i] - scanline[i - bytewidth]); + } + break; + default: return; /*invalid filter type given*/ + } +} + +/* integer binary logarithm, max return value is 31 */ +static size_t ilog2(size_t i) { + size_t result = 0; + if(i >= 65536) { result += 16; i >>= 16; } + if(i >= 256) { result += 8; i >>= 8; } + if(i >= 16) { result += 4; i >>= 4; } + if(i >= 4) { result += 2; i >>= 2; } + if(i >= 2) { result += 1; /*i >>= 1;*/ } + return result; +} + +/* integer approximation for i * log2(i), helper function for LFS_ENTROPY */ +static size_t ilog2i(size_t i) { + size_t l; + if(i == 0) return 0; + l = ilog2(i); + /* approximate i*log2(i): l is integer logarithm, ((i - (1u << l)) << 1u) + linearly approximates the missing fractional part multiplied by i */ + return i * l + ((i - (1u << l)) << 1u); +} + +static unsigned filter(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, + const LodePNGColorMode* color, const LodePNGEncoderSettings* settings) { + /* + For PNG filter method 0 + out must be a buffer with as size: h + (w * h * bpp + 7u) / 8u, because there are + the scanlines with 1 extra byte per scanline + */ + + unsigned bpp = lodepng_get_bpp(color); + /*the width of a scanline in bytes, not including the filter type*/ + size_t linebytes = lodepng_get_raw_size_idat(w, 1, bpp) - 1u; + + /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise*/ + size_t bytewidth = (bpp + 7u) / 8u; + const unsigned char* prevline = 0; + unsigned x, y; + unsigned error = 0; + LodePNGFilterStrategy strategy = settings->filter_strategy; + + /* + There is a heuristic called the minimum sum of absolute differences heuristic, suggested by the PNG standard: + * If the image type is Palette, or the bit depth is smaller than 8, then do not filter the image (i.e. + use fixed filtering, with the filter None). + * (The other case) If the image type is Grayscale or RGB (with or without Alpha), and the bit depth is + not smaller than 8, then use adaptive filtering heuristic as follows: independently for each row, apply + all five filters and select the filter that produces the smallest sum of absolute values per row. + This heuristic is used if filter strategy is LFS_MINSUM and filter_palette_zero is true. + + If filter_palette_zero is true and filter_strategy is not LFS_MINSUM, the above heuristic is followed, + but for "the other case", whatever strategy filter_strategy is set to instead of the minimum sum + heuristic is used. + */ + if(settings->filter_palette_zero && + (color->colortype == LCT_PALETTE || color->bitdepth < 8)) strategy = LFS_ZERO; + + if(bpp == 0) return 31; /*error: invalid color type*/ + + if(strategy >= LFS_ZERO && strategy <= LFS_FOUR) { + unsigned char type = (unsigned char)strategy; + for(y = 0; y != h; ++y) { + size_t outindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/ + size_t inindex = linebytes * y; + out[outindex] = type; /*filter type byte*/ + filterScanline(&out[outindex + 1], &in[inindex], prevline, linebytes, bytewidth, type); + prevline = &in[inindex]; + } + } else if(strategy == LFS_MINSUM) { + /*adaptive filtering*/ + unsigned char* attempt[5]; /*five filtering attempts, one for each filter type*/ + size_t smallest = 0; + unsigned char type, bestType = 0; + + for(type = 0; type != 5; ++type) { + attempt[type] = (unsigned char*)lodepng_malloc(linebytes); + if(!attempt[type]) error = 83; /*alloc fail*/ + } + + if(!error) { + for(y = 0; y != h; ++y) { + /*try the 5 filter types*/ + for(type = 0; type != 5; ++type) { + size_t sum = 0; + filterScanline(attempt[type], &in[y * linebytes], prevline, linebytes, bytewidth, type); + + /*calculate the sum of the result*/ + if(type == 0) { + for(x = 0; x != linebytes; ++x) sum += (unsigned char)(attempt[type][x]); + } else { + for(x = 0; x != linebytes; ++x) { + /*For differences, each byte should be treated as signed, values above 127 are negative + (converted to signed char). Filtertype 0 isn't a difference though, so use unsigned there. + This means filtertype 0 is almost never chosen, but that is justified.*/ + unsigned char s = attempt[type][x]; + sum += s < 128 ? s : (255U - s); + } + } + + /*check if this is smallest sum (or if type == 0 it's the first case so always store the values)*/ + if(type == 0 || sum < smallest) { + bestType = type; + smallest = sum; + } + } + + prevline = &in[y * linebytes]; + + /*now fill the out values*/ + out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/ + for(x = 0; x != linebytes; ++x) out[y * (linebytes + 1) + 1 + x] = attempt[bestType][x]; + } + } + + for(type = 0; type != 5; ++type) lodepng_free(attempt[type]); + } else if(strategy == LFS_ENTROPY) { + unsigned char* attempt[5]; /*five filtering attempts, one for each filter type*/ + size_t bestSum = 0; + unsigned type, bestType = 0; + unsigned count[256]; + + for(type = 0; type != 5; ++type) { + attempt[type] = (unsigned char*)lodepng_malloc(linebytes); + if(!attempt[type]) error = 83; /*alloc fail*/ + } + + if(!error) { + for(y = 0; y != h; ++y) { + /*try the 5 filter types*/ + for(type = 0; type != 5; ++type) { + size_t sum = 0; + filterScanline(attempt[type], &in[y * linebytes], prevline, linebytes, bytewidth, type); + lodepng_memset(count, 0, 256 * sizeof(*count)); + for(x = 0; x != linebytes; ++x) ++count[attempt[type][x]]; + ++count[type]; /*the filter type itself is part of the scanline*/ + for(x = 0; x != 256; ++x) { + sum += ilog2i(count[x]); + } + /*check if this is smallest sum (or if type == 0 it's the first case so always store the values)*/ + if(type == 0 || sum > bestSum) { + bestType = type; + bestSum = sum; + } + } + + prevline = &in[y * linebytes]; + + /*now fill the out values*/ + out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/ + for(x = 0; x != linebytes; ++x) out[y * (linebytes + 1) + 1 + x] = attempt[bestType][x]; + } + } + + for(type = 0; type != 5; ++type) lodepng_free(attempt[type]); + } else if(strategy == LFS_PREDEFINED) { + for(y = 0; y != h; ++y) { + size_t outindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/ + size_t inindex = linebytes * y; + unsigned char type = settings->predefined_filters[y]; + out[outindex] = type; /*filter type byte*/ + filterScanline(&out[outindex + 1], &in[inindex], prevline, linebytes, bytewidth, type); + prevline = &in[inindex]; + } + } else if(strategy == LFS_BRUTE_FORCE) { + /*brute force filter chooser. + deflate the scanline after every filter attempt to see which one deflates best. + This is very slow and gives only slightly smaller, sometimes even larger, result*/ + size_t size[5]; + unsigned char* attempt[5]; /*five filtering attempts, one for each filter type*/ + size_t smallest = 0; + unsigned type = 0, bestType = 0; + unsigned char* dummy; + LodePNGCompressSettings zlibsettings; + lodepng_memcpy(&zlibsettings, &settings->zlibsettings, sizeof(LodePNGCompressSettings)); + /*use fixed tree on the attempts so that the tree is not adapted to the filtertype on purpose, + to simulate the true case where the tree is the same for the whole image. Sometimes it gives + better result with dynamic tree anyway. Using the fixed tree sometimes gives worse, but in rare + cases better compression. It does make this a bit less slow, so it's worth doing this.*/ + zlibsettings.btype = 1; + /*a custom encoder likely doesn't read the btype setting and is optimized for complete PNG + images only, so disable it*/ + zlibsettings.custom_zlib = 0; + zlibsettings.custom_deflate = 0; + for(type = 0; type != 5; ++type) { + attempt[type] = (unsigned char*)lodepng_malloc(linebytes); + if(!attempt[type]) error = 83; /*alloc fail*/ + } + if(!error) { + for(y = 0; y != h; ++y) /*try the 5 filter types*/ { + for(type = 0; type != 5; ++type) { + unsigned testsize = (unsigned)linebytes; + /*if(testsize > 8) testsize /= 8;*/ /*it already works good enough by testing a part of the row*/ + + filterScanline(attempt[type], &in[y * linebytes], prevline, linebytes, bytewidth, type); + size[type] = 0; + dummy = 0; + zlib_compress(&dummy, &size[type], attempt[type], testsize, &zlibsettings); + lodepng_free(dummy); + /*check if this is smallest size (or if type == 0 it's the first case so always store the values)*/ + if(type == 0 || size[type] < smallest) { + bestType = type; + smallest = size[type]; + } + } + prevline = &in[y * linebytes]; + out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/ + for(x = 0; x != linebytes; ++x) out[y * (linebytes + 1) + 1 + x] = attempt[bestType][x]; + } + } + for(type = 0; type != 5; ++type) lodepng_free(attempt[type]); + } + else return 88; /* unknown filter strategy */ + + return error; +} + +static void addPaddingBits(unsigned char* out, const unsigned char* in, + size_t olinebits, size_t ilinebits, unsigned h) { + /*The opposite of the removePaddingBits function + olinebits must be >= ilinebits*/ + unsigned y; + size_t diff = olinebits - ilinebits; + size_t obp = 0, ibp = 0; /*bit pointers*/ + for(y = 0; y != h; ++y) { + size_t x; + for(x = 0; x < ilinebits; ++x) { + unsigned char bit = readBitFromReversedStream(&ibp, in); + setBitOfReversedStream(&obp, out, bit); + } + /*obp += diff; --> no, fill in some value in the padding bits too, to avoid + "Use of uninitialised value of size ###" warning from valgrind*/ + for(x = 0; x != diff; ++x) setBitOfReversedStream(&obp, out, 0); + } +} + +/* +in: non-interlaced image with size w*h +out: the same pixels, but re-ordered according to PNG's Adam7 interlacing, with + no padding bits between scanlines, but between reduced images so that each + reduced image starts at a byte. +bpp: bits per pixel +there are no padding bits, not between scanlines, not between reduced images +in has the following size in bits: w * h * bpp. +out is possibly bigger due to padding bits between reduced images +NOTE: comments about padding bits are only relevant if bpp < 8 +*/ +static void Adam7_interlace(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp) { + unsigned passw[7], passh[7]; + size_t filter_passstart[8], padded_passstart[8], passstart[8]; + unsigned i; + + Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); + + if(bpp >= 8) { + for(i = 0; i != 7; ++i) { + unsigned x, y, b; + size_t bytewidth = bpp / 8u; + for(y = 0; y < passh[i]; ++y) + for(x = 0; x < passw[i]; ++x) { + size_t pixelinstart = ((ADAM7_IY[i] + y * ADAM7_DY[i]) * w + ADAM7_IX[i] + x * ADAM7_DX[i]) * bytewidth; + size_t pixeloutstart = passstart[i] + (y * passw[i] + x) * bytewidth; + for(b = 0; b < bytewidth; ++b) { + out[pixeloutstart + b] = in[pixelinstart + b]; + } + } + } + } else /*bpp < 8: Adam7 with pixels < 8 bit is a bit trickier: with bit pointers*/ { + for(i = 0; i != 7; ++i) { + unsigned x, y, b; + unsigned ilinebits = bpp * passw[i]; + unsigned olinebits = bpp * w; + size_t obp, ibp; /*bit pointers (for out and in buffer)*/ + for(y = 0; y < passh[i]; ++y) + for(x = 0; x < passw[i]; ++x) { + ibp = (ADAM7_IY[i] + y * ADAM7_DY[i]) * olinebits + (ADAM7_IX[i] + x * ADAM7_DX[i]) * bpp; + obp = (8 * passstart[i]) + (y * ilinebits + x * bpp); + for(b = 0; b < bpp; ++b) { + unsigned char bit = readBitFromReversedStream(&ibp, in); + setBitOfReversedStream(&obp, out, bit); + } + } + } + } +} + +/*out must be buffer big enough to contain uncompressed IDAT chunk data, and in must contain the full image. +return value is error**/ +static unsigned preProcessScanlines(unsigned char** out, size_t* outsize, const unsigned char* in, + unsigned w, unsigned h, + const LodePNGInfo* info_png, const LodePNGEncoderSettings* settings) { + /* + This function converts the pure 2D image with the PNG's colortype, into filtered-padded-interlaced data. Steps: + *) if no Adam7: 1) add padding bits (= possible extra bits per scanline if bpp < 8) 2) filter + *) if adam7: 1) Adam7_interlace 2) 7x add padding bits 3) 7x filter + */ + unsigned bpp = lodepng_get_bpp(&info_png->color); + unsigned error = 0; + + if(info_png->interlace_method == 0) { + *outsize = h + (h * ((w * bpp + 7u) / 8u)); /*image size plus an extra byte per scanline + possible padding bits*/ + *out = (unsigned char*)lodepng_malloc(*outsize); + if(!(*out) && (*outsize)) error = 83; /*alloc fail*/ + + if(!error) { + /*non multiple of 8 bits per scanline, padding bits needed per scanline*/ + if(bpp < 8 && w * bpp != ((w * bpp + 7u) / 8u) * 8u) { + unsigned char* padded = (unsigned char*)lodepng_malloc(h * ((w * bpp + 7u) / 8u)); + if(!padded) error = 83; /*alloc fail*/ + if(!error) { + addPaddingBits(padded, in, ((w * bpp + 7u) / 8u) * 8u, w * bpp, h); + error = filter(*out, padded, w, h, &info_png->color, settings); + } + lodepng_free(padded); + } else { + /*we can immediately filter into the out buffer, no other steps needed*/ + error = filter(*out, in, w, h, &info_png->color, settings); + } + } + } else /*interlace_method is 1 (Adam7)*/ { + unsigned passw[7], passh[7]; + size_t filter_passstart[8], padded_passstart[8], passstart[8]; + unsigned char* adam7; + + Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); + + *outsize = filter_passstart[7]; /*image size plus an extra byte per scanline + possible padding bits*/ + *out = (unsigned char*)lodepng_malloc(*outsize); + if(!(*out)) error = 83; /*alloc fail*/ + + adam7 = (unsigned char*)lodepng_malloc(passstart[7]); + if(!adam7 && passstart[7]) error = 83; /*alloc fail*/ + + if(!error) { + unsigned i; + + Adam7_interlace(adam7, in, w, h, bpp); + for(i = 0; i != 7; ++i) { + if(bpp < 8) { + unsigned char* padded = (unsigned char*)lodepng_malloc(padded_passstart[i + 1] - padded_passstart[i]); + if(!padded) ERROR_BREAK(83); /*alloc fail*/ + addPaddingBits(padded, &adam7[passstart[i]], + ((passw[i] * bpp + 7u) / 8u) * 8u, passw[i] * bpp, passh[i]); + error = filter(&(*out)[filter_passstart[i]], padded, + passw[i], passh[i], &info_png->color, settings); + lodepng_free(padded); + } else { + error = filter(&(*out)[filter_passstart[i]], &adam7[padded_passstart[i]], + passw[i], passh[i], &info_png->color, settings); + } + + if(error) break; + } + } + + lodepng_free(adam7); + } + + return error; +} + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS +static unsigned addUnknownChunks(ucvector* out, unsigned char* data, size_t datasize) { + unsigned char* inchunk = data; + while((size_t)(inchunk - data) < datasize) { + CERROR_TRY_RETURN(lodepng_chunk_append(&out->data, &out->size, inchunk)); + out->allocsize = out->size; /*fix the allocsize again*/ + inchunk = lodepng_chunk_next(inchunk, data + datasize); + } + return 0; +} + +static unsigned isGrayICCProfile(const unsigned char* profile, unsigned size) { + /* + It is a gray profile if bytes 16-19 are "GRAY", rgb profile if bytes 16-19 + are "RGB ". We do not perform any full parsing of the ICC profile here, other + than check those 4 bytes to grayscale profile. Other than that, validity of + the profile is not checked. This is needed only because the PNG specification + requires using a non-gray color model if there is an ICC profile with "RGB " + (sadly limiting compression opportunities if the input data is grayscale RGB + data), and requires using a gray color model if it is "GRAY". + */ + if(size < 20) return 0; + return profile[16] == 'G' && profile[17] == 'R' && profile[18] == 'A' && profile[19] == 'Y'; +} + +static unsigned isRGBICCProfile(const unsigned char* profile, unsigned size) { + /* See comment in isGrayICCProfile*/ + if(size < 20) return 0; + return profile[16] == 'R' && profile[17] == 'G' && profile[18] == 'B' && profile[19] == ' '; +} +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +unsigned lodepng_encode(unsigned char** out, size_t* outsize, + const unsigned char* image, unsigned w, unsigned h, + LodePNGState* state) { + unsigned char* data = 0; /*uncompressed version of the IDAT chunk data*/ + size_t datasize = 0; + ucvector outv = ucvector_init(NULL, 0); + LodePNGInfo info; + const LodePNGInfo* info_png = &state->info_png; + + lodepng_info_init(&info); + + /*provide some proper output values if error will happen*/ + *out = 0; + *outsize = 0; + state->error = 0; + + /*check input values validity*/ + if((info_png->color.colortype == LCT_PALETTE || state->encoder.force_palette) + && (info_png->color.palettesize == 0 || info_png->color.palettesize > 256)) { + state->error = 68; /*invalid palette size, it is only allowed to be 1-256*/ + goto cleanup; + } + if(state->encoder.zlibsettings.btype > 2) { + state->error = 61; /*error: invalid btype*/ + goto cleanup; + } + if(info_png->interlace_method > 1) { + state->error = 71; /*error: invalid interlace mode*/ + goto cleanup; + } + state->error = checkColorValidity(info_png->color.colortype, info_png->color.bitdepth); + if(state->error) goto cleanup; /*error: invalid color type given*/ + state->error = checkColorValidity(state->info_raw.colortype, state->info_raw.bitdepth); + if(state->error) goto cleanup; /*error: invalid color type given*/ + + /* color convert and compute scanline filter types */ + lodepng_info_copy(&info, &state->info_png); + if(state->encoder.auto_convert) { + LodePNGColorStats stats; + lodepng_color_stats_init(&stats); +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + if(info_png->iccp_defined && + isGrayICCProfile(info_png->iccp_profile, info_png->iccp_profile_size)) { + /*the PNG specification does not allow to use palette with a GRAY ICC profile, even + if the palette has only gray colors, so disallow it.*/ + stats.allow_palette = 0; + } + if(info_png->iccp_defined && + isRGBICCProfile(info_png->iccp_profile, info_png->iccp_profile_size)) { + /*the PNG specification does not allow to use grayscale color with RGB ICC profile, so disallow gray.*/ + stats.allow_greyscale = 0; + } +#endif /* LODEPNG_COMPILE_ANCILLARY_CHUNKS */ + state->error = lodepng_compute_color_stats(&stats, image, w, h, &state->info_raw); + if(state->error) goto cleanup; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + if(info_png->background_defined) { + /*the background chunk's color must be taken into account as well*/ + unsigned r = 0, g = 0, b = 0; + LodePNGColorMode mode16 = lodepng_color_mode_make(LCT_RGB, 16); + lodepng_convert_rgb(&r, &g, &b, info_png->background_r, info_png->background_g, info_png->background_b, &mode16, &info_png->color); + state->error = lodepng_color_stats_add(&stats, r, g, b, 65535); + if(state->error) goto cleanup; + } +#endif /* LODEPNG_COMPILE_ANCILLARY_CHUNKS */ + state->error = auto_choose_color(&info.color, &state->info_raw, &stats); + if(state->error) goto cleanup; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /*also convert the background chunk*/ + if(info_png->background_defined) { + if(lodepng_convert_rgb(&info.background_r, &info.background_g, &info.background_b, + info_png->background_r, info_png->background_g, info_png->background_b, &info.color, &info_png->color)) { + state->error = 104; + goto cleanup; + } + } +#endif /* LODEPNG_COMPILE_ANCILLARY_CHUNKS */ + } +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + if(info_png->iccp_defined) { + unsigned gray_icc = isGrayICCProfile(info_png->iccp_profile, info_png->iccp_profile_size); + unsigned rgb_icc = isRGBICCProfile(info_png->iccp_profile, info_png->iccp_profile_size); + unsigned gray_png = info.color.colortype == LCT_GREY || info.color.colortype == LCT_GREY_ALPHA; + if(!gray_icc && !rgb_icc) { + state->error = 100; /* Disallowed profile color type for PNG */ + goto cleanup; + } + if(gray_icc != gray_png) { + /*Not allowed to use RGB/RGBA/palette with GRAY ICC profile or vice versa, + or in case of auto_convert, it wasn't possible to find appropriate model*/ + state->error = state->encoder.auto_convert ? 102 : 101; + goto cleanup; + } + } +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + if(!lodepng_color_mode_equal(&state->info_raw, &info.color)) { + unsigned char* converted; + size_t size = ((size_t)w * (size_t)h * (size_t)lodepng_get_bpp(&info.color) + 7u) / 8u; + + converted = (unsigned char*)lodepng_malloc(size); + if(!converted && size) state->error = 83; /*alloc fail*/ + if(!state->error) { + state->error = lodepng_convert(converted, image, &info.color, &state->info_raw, w, h); + } + if(!state->error) { + state->error = preProcessScanlines(&data, &datasize, converted, w, h, &info, &state->encoder); + } + lodepng_free(converted); + if(state->error) goto cleanup; + } else { + state->error = preProcessScanlines(&data, &datasize, image, w, h, &info, &state->encoder); + if(state->error) goto cleanup; + } + + /* output all PNG chunks */ { +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + size_t i; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + /*write signature and chunks*/ + state->error = writeSignature(&outv); + if(state->error) goto cleanup; + /*IHDR*/ + state->error = addChunk_IHDR(&outv, w, h, info.color.colortype, info.color.bitdepth, info.interlace_method); + if(state->error) goto cleanup; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /*unknown chunks between IHDR and PLTE*/ + if(info.unknown_chunks_data[0]) { + state->error = addUnknownChunks(&outv, info.unknown_chunks_data[0], info.unknown_chunks_size[0]); + if(state->error) goto cleanup; + } + /*color profile chunks must come before PLTE */ + if(info.iccp_defined) { + state->error = addChunk_iCCP(&outv, &info, &state->encoder.zlibsettings); + if(state->error) goto cleanup; + } + if(info.srgb_defined) { + state->error = addChunk_sRGB(&outv, &info); + if(state->error) goto cleanup; + } + if(info.gama_defined) { + state->error = addChunk_gAMA(&outv, &info); + if(state->error) goto cleanup; + } + if(info.chrm_defined) { + state->error = addChunk_cHRM(&outv, &info); + if(state->error) goto cleanup; + } +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + /*PLTE*/ + if(info.color.colortype == LCT_PALETTE) { + state->error = addChunk_PLTE(&outv, &info.color); + if(state->error) goto cleanup; + } + if(state->encoder.force_palette && (info.color.colortype == LCT_RGB || info.color.colortype == LCT_RGBA)) { + /*force_palette means: write suggested palette for truecolor in PLTE chunk*/ + state->error = addChunk_PLTE(&outv, &info.color); + if(state->error) goto cleanup; + } + /*tRNS (this will only add if when necessary) */ + state->error = addChunk_tRNS(&outv, &info.color); + if(state->error) goto cleanup; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /*bKGD (must come between PLTE and the IDAt chunks*/ + if(info.background_defined) { + state->error = addChunk_bKGD(&outv, &info); + if(state->error) goto cleanup; + } + /*pHYs (must come before the IDAT chunks)*/ + if(info.phys_defined) { + state->error = addChunk_pHYs(&outv, &info); + if(state->error) goto cleanup; + } + + /*unknown chunks between PLTE and IDAT*/ + if(info.unknown_chunks_data[1]) { + state->error = addUnknownChunks(&outv, info.unknown_chunks_data[1], info.unknown_chunks_size[1]); + if(state->error) goto cleanup; + } +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + /*IDAT (multiple IDAT chunks must be consecutive)*/ + state->error = addChunk_IDAT(&outv, data, datasize, &state->encoder.zlibsettings); + if(state->error) goto cleanup; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /*tIME*/ + if(info.time_defined) { + state->error = addChunk_tIME(&outv, &info.time); + if(state->error) goto cleanup; + } + /*tEXt and/or zTXt*/ + for(i = 0; i != info.text_num; ++i) { + if(lodepng_strlen(info.text_keys[i]) > 79) { + state->error = 66; /*text chunk too large*/ + goto cleanup; + } + if(lodepng_strlen(info.text_keys[i]) < 1) { + state->error = 67; /*text chunk too small*/ + goto cleanup; + } + if(state->encoder.text_compression) { + state->error = addChunk_zTXt(&outv, info.text_keys[i], info.text_strings[i], &state->encoder.zlibsettings); + if(state->error) goto cleanup; + } else { + state->error = addChunk_tEXt(&outv, info.text_keys[i], info.text_strings[i]); + if(state->error) goto cleanup; + } + } + /*LodePNG version id in text chunk*/ + if(state->encoder.add_id) { + unsigned already_added_id_text = 0; + for(i = 0; i != info.text_num; ++i) { + const char* k = info.text_keys[i]; + /* Could use strcmp, but we're not calling or reimplementing this C library function for this use only */ + if(k[0] == 'L' && k[1] == 'o' && k[2] == 'd' && k[3] == 'e' && + k[4] == 'P' && k[5] == 'N' && k[6] == 'G' && k[7] == '\0') { + already_added_id_text = 1; + break; + } + } + if(already_added_id_text == 0) { + state->error = addChunk_tEXt(&outv, "LodePNG", LODEPNG_VERSION_STRING); /*it's shorter as tEXt than as zTXt chunk*/ + if(state->error) goto cleanup; + } + } + /*iTXt*/ + for(i = 0; i != info.itext_num; ++i) { + if(lodepng_strlen(info.itext_keys[i]) > 79) { + state->error = 66; /*text chunk too large*/ + goto cleanup; + } + if(lodepng_strlen(info.itext_keys[i]) < 1) { + state->error = 67; /*text chunk too small*/ + goto cleanup; + } + state->error = addChunk_iTXt( + &outv, state->encoder.text_compression, + info.itext_keys[i], info.itext_langtags[i], info.itext_transkeys[i], info.itext_strings[i], + &state->encoder.zlibsettings); + if(state->error) goto cleanup; + } + + /*unknown chunks between IDAT and IEND*/ + if(info.unknown_chunks_data[2]) { + state->error = addUnknownChunks(&outv, info.unknown_chunks_data[2], info.unknown_chunks_size[2]); + if(state->error) goto cleanup; + } +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + state->error = addChunk_IEND(&outv); + if(state->error) goto cleanup; + } + +cleanup: + lodepng_info_cleanup(&info); + lodepng_free(data); + + /*instead of cleaning the vector up, give it to the output*/ + *out = outv.data; + *outsize = outv.size; + + return state->error; +} + +unsigned lodepng_encode_memory(unsigned char** out, size_t* outsize, const unsigned char* image, + unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth) { + unsigned error; + LodePNGState state; + lodepng_state_init(&state); + state.info_raw.colortype = colortype; + state.info_raw.bitdepth = bitdepth; + state.info_png.color.colortype = colortype; + state.info_png.color.bitdepth = bitdepth; + lodepng_encode(out, outsize, image, w, h, &state); + error = state.error; + lodepng_state_cleanup(&state); + return error; +} + +unsigned lodepng_encode32(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h) { + return lodepng_encode_memory(out, outsize, image, w, h, LCT_RGBA, 8); +} + +unsigned lodepng_encode24(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h) { + return lodepng_encode_memory(out, outsize, image, w, h, LCT_RGB, 8); +} + +#ifdef LODEPNG_COMPILE_DISK +unsigned lodepng_encode_file(const char* filename, const unsigned char* image, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth) { + unsigned char* buffer; + size_t buffersize; + unsigned error = lodepng_encode_memory(&buffer, &buffersize, image, w, h, colortype, bitdepth); + if(!error) error = lodepng_save_file(buffer, buffersize, filename); + lodepng_free(buffer); + return error; +} + +unsigned lodepng_encode32_file(const char* filename, const unsigned char* image, unsigned w, unsigned h) { + return lodepng_encode_file(filename, image, w, h, LCT_RGBA, 8); +} + +unsigned lodepng_encode24_file(const char* filename, const unsigned char* image, unsigned w, unsigned h) { + return lodepng_encode_file(filename, image, w, h, LCT_RGB, 8); +} +#endif /*LODEPNG_COMPILE_DISK*/ + +void lodepng_encoder_settings_init(LodePNGEncoderSettings* settings) { + lodepng_compress_settings_init(&settings->zlibsettings); + settings->filter_palette_zero = 1; + settings->filter_strategy = LFS_MINSUM; + settings->auto_convert = 1; + settings->force_palette = 0; + settings->predefined_filters = 0; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + settings->add_id = 0; + settings->text_compression = 1; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} + +#endif /*LODEPNG_COMPILE_ENCODER*/ +#endif /*LODEPNG_COMPILE_PNG*/ + +#ifdef LODEPNG_COMPILE_ERROR_TEXT +/* +This returns the description of a numerical error code in English. This is also +the documentation of all the error codes. +*/ +const char* lodepng_error_text(unsigned code) { + switch(code) { + case 0: return "no error, everything went ok"; + case 1: return "nothing done yet"; /*the Encoder/Decoder has done nothing yet, error checking makes no sense yet*/ + case 10: return "end of input memory reached without huffman end code"; /*while huffman decoding*/ + case 11: return "error in code tree made it jump outside of huffman tree"; /*while huffman decoding*/ + case 13: return "problem while processing dynamic deflate block"; + case 14: return "problem while processing dynamic deflate block"; + case 15: return "problem while processing dynamic deflate block"; + /*this error could happen if there are only 0 or 1 symbols present in the huffman code:*/ + case 16: return "invalid code while processing dynamic deflate block"; + case 17: return "end of out buffer memory reached while inflating"; + case 18: return "invalid distance code while inflating"; + case 19: return "end of out buffer memory reached while inflating"; + case 20: return "invalid deflate block BTYPE encountered while decoding"; + case 21: return "NLEN is not ones complement of LEN in a deflate block"; + + /*end of out buffer memory reached while inflating: + This can happen if the inflated deflate data is longer than the amount of bytes required to fill up + all the pixels of the image, given the color depth and image dimensions. Something that doesn't + happen in a normal, well encoded, PNG image.*/ + case 22: return "end of out buffer memory reached while inflating"; + case 23: return "end of in buffer memory reached while inflating"; + case 24: return "invalid FCHECK in zlib header"; + case 25: return "invalid compression method in zlib header"; + case 26: return "FDICT encountered in zlib header while it's not used for PNG"; + case 27: return "PNG file is smaller than a PNG header"; + /*Checks the magic file header, the first 8 bytes of the PNG file*/ + case 28: return "incorrect PNG signature, it's no PNG or corrupted"; + case 29: return "first chunk is not the header chunk"; + case 30: return "chunk length too large, chunk broken off at end of file"; + case 31: return "illegal PNG color type or bpp"; + case 32: return "illegal PNG compression method"; + case 33: return "illegal PNG filter method"; + case 34: return "illegal PNG interlace method"; + case 35: return "chunk length of a chunk is too large or the chunk too small"; + case 36: return "illegal PNG filter type encountered"; + case 37: return "illegal bit depth for this color type given"; + case 38: return "the palette is too small or too big"; /*0, or more than 256 colors*/ + case 39: return "tRNS chunk before PLTE or has more entries than palette size"; + case 40: return "tRNS chunk has wrong size for grayscale image"; + case 41: return "tRNS chunk has wrong size for RGB image"; + case 42: return "tRNS chunk appeared while it was not allowed for this color type"; + case 43: return "bKGD chunk has wrong size for palette image"; + case 44: return "bKGD chunk has wrong size for grayscale image"; + case 45: return "bKGD chunk has wrong size for RGB image"; + case 48: return "empty input buffer given to decoder. Maybe caused by non-existing file?"; + case 49: return "jumped past memory while generating dynamic huffman tree"; + case 50: return "jumped past memory while generating dynamic huffman tree"; + case 51: return "jumped past memory while inflating huffman block"; + case 52: return "jumped past memory while inflating"; + case 53: return "size of zlib data too small"; + case 54: return "repeat symbol in tree while there was no value symbol yet"; + /*jumped past tree while generating huffman tree, this could be when the + tree will have more leaves than symbols after generating it out of the + given lengths. They call this an oversubscribed dynamic bit lengths tree in zlib.*/ + case 55: return "jumped past tree while generating huffman tree"; + case 56: return "given output image colortype or bitdepth not supported for color conversion"; + case 57: return "invalid CRC encountered (checking CRC can be disabled)"; + case 58: return "invalid ADLER32 encountered (checking ADLER32 can be disabled)"; + case 59: return "requested color conversion not supported"; + case 60: return "invalid window size given in the settings of the encoder (must be 0-32768)"; + case 61: return "invalid BTYPE given in the settings of the encoder (only 0, 1 and 2 are allowed)"; + /*LodePNG leaves the choice of RGB to grayscale conversion formula to the user.*/ + case 62: return "conversion from color to grayscale not supported"; + /*(2^31-1)*/ + case 63: return "length of a chunk too long, max allowed for PNG is 2147483647 bytes per chunk"; + /*this would result in the inability of a deflated block to ever contain an end code. It must be at least 1.*/ + case 64: return "the length of the END symbol 256 in the Huffman tree is 0"; + case 66: return "the length of a text chunk keyword given to the encoder is longer than the maximum of 79 bytes"; + case 67: return "the length of a text chunk keyword given to the encoder is smaller than the minimum of 1 byte"; + case 68: return "tried to encode a PLTE chunk with a palette that has less than 1 or more than 256 colors"; + case 69: return "unknown chunk type with 'critical' flag encountered by the decoder"; + case 71: return "invalid interlace mode given to encoder (must be 0 or 1)"; + case 72: return "while decoding, invalid compression method encountering in zTXt or iTXt chunk (it must be 0)"; + case 73: return "invalid tIME chunk size"; + case 74: return "invalid pHYs chunk size"; + /*length could be wrong, or data chopped off*/ + case 75: return "no null termination char found while decoding text chunk"; + case 76: return "iTXt chunk too short to contain required bytes"; + case 77: return "integer overflow in buffer size"; + case 78: return "failed to open file for reading"; /*file doesn't exist or couldn't be opened for reading*/ + case 79: return "failed to open file for writing"; + case 80: return "tried creating a tree of 0 symbols"; + case 81: return "lazy matching at pos 0 is impossible"; + case 82: return "color conversion to palette requested while a color isn't in palette, or index out of bounds"; + case 83: return "memory allocation failed"; + case 84: return "given image too small to contain all pixels to be encoded"; + case 86: return "impossible offset in lz77 encoding (internal bug)"; + case 87: return "must provide custom zlib function pointer if LODEPNG_COMPILE_ZLIB is not defined"; + case 88: return "invalid filter strategy given for LodePNGEncoderSettings.filter_strategy"; + case 89: return "text chunk keyword too short or long: must have size 1-79"; + /*the windowsize in the LodePNGCompressSettings. Requiring POT(==> & instead of %) makes encoding 12% faster.*/ + case 90: return "windowsize must be a power of two"; + case 91: return "invalid decompressed idat size"; + case 92: return "integer overflow due to too many pixels"; + case 93: return "zero width or height is invalid"; + case 94: return "header chunk must have a size of 13 bytes"; + case 95: return "integer overflow with combined idat chunk size"; + case 96: return "invalid gAMA chunk size"; + case 97: return "invalid cHRM chunk size"; + case 98: return "invalid sRGB chunk size"; + case 99: return "invalid sRGB rendering intent"; + case 100: return "invalid ICC profile color type, the PNG specification only allows RGB or GRAY"; + case 101: return "PNG specification does not allow RGB ICC profile on gray color types and vice versa"; + case 102: return "not allowed to set grayscale ICC profile with colored pixels by PNG specification"; + case 103: return "invalid palette index in bKGD chunk. Maybe it came before PLTE chunk?"; + case 104: return "invalid bKGD color while encoding (e.g. palette index out of range)"; + case 105: return "integer overflow of bitsize"; + case 106: return "PNG file must have PLTE chunk if color type is palette"; + case 107: return "color convert from palette mode requested without setting the palette data in it"; + case 108: return "tried to add more than 256 values to a palette"; + /*this limit can be configured in LodePNGDecompressSettings*/ + case 109: return "tried to decompress zlib or deflate data larger than desired max_output_size"; + case 110: return "custom zlib or inflate decompression failed"; + case 111: return "custom zlib or deflate compression failed"; + /*max text size limit can be configured in LodePNGDecoderSettings. This error prevents + unreasonable memory consumption when decoding due to impossibly large text sizes.*/ + case 112: return "compressed text unreasonably large"; + /*max ICC size limit can be configured in LodePNGDecoderSettings. This error prevents + unreasonable memory consumption when decoding due to impossibly large ICC profile*/ + case 113: return "ICC profile unreasonably large"; + } + return "unknown error code"; +} +#endif /*LODEPNG_COMPILE_ERROR_TEXT*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* // C++ Wrapper // */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_CPP +namespace lodepng { + +#ifdef LODEPNG_COMPILE_DISK +unsigned load_file(std::vector& buffer, const std::string& filename) { + long size = lodepng_filesize(filename.c_str()); + if(size < 0) return 78; + buffer.resize((size_t)size); + return size == 0 ? 0 : lodepng_buffer_file(&buffer[0], (size_t)size, filename.c_str()); +} + +/*write given buffer to the file, overwriting the file, it doesn't append to it.*/ +unsigned save_file(const std::vector& buffer, const std::string& filename) { + return lodepng_save_file(buffer.empty() ? 0 : &buffer[0], buffer.size(), filename.c_str()); +} +#endif /* LODEPNG_COMPILE_DISK */ + +#ifdef LODEPNG_COMPILE_ZLIB +#ifdef LODEPNG_COMPILE_DECODER +unsigned decompress(std::vector& out, const unsigned char* in, size_t insize, + const LodePNGDecompressSettings& settings) { + unsigned char* buffer = 0; + size_t buffersize = 0; + unsigned error = zlib_decompress(&buffer, &buffersize, 0, in, insize, &settings); + if(buffer) { + out.insert(out.end(), &buffer[0], &buffer[buffersize]); + lodepng_free(buffer); + } + return error; +} + +unsigned decompress(std::vector& out, const std::vector& in, + const LodePNGDecompressSettings& settings) { + return decompress(out, in.empty() ? 0 : &in[0], in.size(), settings); +} +#endif /* LODEPNG_COMPILE_DECODER */ + +#ifdef LODEPNG_COMPILE_ENCODER +unsigned compress(std::vector& out, const unsigned char* in, size_t insize, + const LodePNGCompressSettings& settings) { + unsigned char* buffer = 0; + size_t buffersize = 0; + unsigned error = zlib_compress(&buffer, &buffersize, in, insize, &settings); + if(buffer) { + out.insert(out.end(), &buffer[0], &buffer[buffersize]); + lodepng_free(buffer); + } + return error; +} + +unsigned compress(std::vector& out, const std::vector& in, + const LodePNGCompressSettings& settings) { + return compress(out, in.empty() ? 0 : &in[0], in.size(), settings); +} +#endif /* LODEPNG_COMPILE_ENCODER */ +#endif /* LODEPNG_COMPILE_ZLIB */ + + +#ifdef LODEPNG_COMPILE_PNG + +State::State() { + lodepng_state_init(this); +} + +State::State(const State& other) { + lodepng_state_init(this); + lodepng_state_copy(this, &other); +} + +State::~State() { + lodepng_state_cleanup(this); +} + +State& State::operator=(const State& other) { + lodepng_state_copy(this, &other); + return *this; +} + +#ifdef LODEPNG_COMPILE_DECODER + +unsigned decode(std::vector& out, unsigned& w, unsigned& h, const unsigned char* in, + size_t insize, LodePNGColorType colortype, unsigned bitdepth) { + unsigned char* buffer = 0; + unsigned error = lodepng_decode_memory(&buffer, &w, &h, in, insize, colortype, bitdepth); + if(buffer && !error) { + State state; + state.info_raw.colortype = colortype; + state.info_raw.bitdepth = bitdepth; + size_t buffersize = lodepng_get_raw_size(w, h, &state.info_raw); + out.insert(out.end(), &buffer[0], &buffer[buffersize]); + } + lodepng_free(buffer); + return error; +} + +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + const std::vector& in, LodePNGColorType colortype, unsigned bitdepth) { + return decode(out, w, h, in.empty() ? 0 : &in[0], (unsigned)in.size(), colortype, bitdepth); +} + +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + State& state, + const unsigned char* in, size_t insize) { + unsigned char* buffer = NULL; + unsigned error = lodepng_decode(&buffer, &w, &h, &state, in, insize); + if(buffer && !error) { + size_t buffersize = lodepng_get_raw_size(w, h, &state.info_raw); + out.insert(out.end(), &buffer[0], &buffer[buffersize]); + } + lodepng_free(buffer); + return error; +} + +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + State& state, + const std::vector& in) { + return decode(out, w, h, state, in.empty() ? 0 : &in[0], in.size()); +} + +#ifdef LODEPNG_COMPILE_DISK +unsigned decode(std::vector& out, unsigned& w, unsigned& h, const std::string& filename, + LodePNGColorType colortype, unsigned bitdepth) { + std::vector buffer; + /* safe output values in case error happens */ + w = h = 0; + unsigned error = load_file(buffer, filename); + if(error) return error; + return decode(out, w, h, buffer, colortype, bitdepth); +} +#endif /* LODEPNG_COMPILE_DECODER */ +#endif /* LODEPNG_COMPILE_DISK */ + +#ifdef LODEPNG_COMPILE_ENCODER +unsigned encode(std::vector& out, const unsigned char* in, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth) { + unsigned char* buffer; + size_t buffersize; + unsigned error = lodepng_encode_memory(&buffer, &buffersize, in, w, h, colortype, bitdepth); + if(buffer) { + out.insert(out.end(), &buffer[0], &buffer[buffersize]); + lodepng_free(buffer); + } + return error; +} + +unsigned encode(std::vector& out, + const std::vector& in, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth) { + if(lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size()) return 84; + return encode(out, in.empty() ? 0 : &in[0], w, h, colortype, bitdepth); +} + +unsigned encode(std::vector& out, + const unsigned char* in, unsigned w, unsigned h, + State& state) { + unsigned char* buffer; + size_t buffersize; + unsigned error = lodepng_encode(&buffer, &buffersize, in, w, h, &state); + if(buffer) { + out.insert(out.end(), &buffer[0], &buffer[buffersize]); + lodepng_free(buffer); + } + return error; +} + +unsigned encode(std::vector& out, + const std::vector& in, unsigned w, unsigned h, + State& state) { + if(lodepng_get_raw_size(w, h, &state.info_raw) > in.size()) return 84; + return encode(out, in.empty() ? 0 : &in[0], w, h, state); +} + +#ifdef LODEPNG_COMPILE_DISK +unsigned encode(const std::string& filename, + const unsigned char* in, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth) { + std::vector buffer; + unsigned error = encode(buffer, in, w, h, colortype, bitdepth); + if(!error) error = save_file(buffer, filename); + return error; +} + +unsigned encode(const std::string& filename, + const std::vector& in, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth) { + if(lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size()) return 84; + return encode(filename, in.empty() ? 0 : &in[0], w, h, colortype, bitdepth); +} +#endif /* LODEPNG_COMPILE_DISK */ +#endif /* LODEPNG_COMPILE_ENCODER */ +#endif /* LODEPNG_COMPILE_PNG */ +} /* namespace lodepng */ +#endif /*LODEPNG_COMPILE_CPP*/ diff --git a/depends/lodepng/lodepng.h b/depends/lodepng/lodepng.h new file mode 100644 index 0000000000..6801cb789d --- /dev/null +++ b/depends/lodepng/lodepng.h @@ -0,0 +1,1977 @@ +/* +LodePNG version 20201017 + +Copyright (c) 2005-2020 Lode Vandevenne + +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 acknowledgment 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. +*/ + +#ifndef LODEPNG_H +#define LODEPNG_H + +#include /*for size_t*/ + +extern const char* LODEPNG_VERSION_STRING; + +/* +The following #defines are used to create code sections. They can be disabled +to disable code sections, which can give faster compile time and smaller binary. +The "NO_COMPILE" defines are designed to be used to pass as defines to the +compiler command to disable them without modifying this header, e.g. +-DLODEPNG_NO_COMPILE_ZLIB for gcc. +In addition to those below, you can also define LODEPNG_NO_COMPILE_CRC to +allow implementing a custom lodepng_crc32. +*/ +/*deflate & zlib. If disabled, you must specify alternative zlib functions in +the custom_zlib field of the compress and decompress settings*/ +#ifndef LODEPNG_NO_COMPILE_ZLIB +#define LODEPNG_COMPILE_ZLIB +#endif + +/*png encoder and png decoder*/ +#ifndef LODEPNG_NO_COMPILE_PNG +#define LODEPNG_COMPILE_PNG +#endif + +/*deflate&zlib decoder and png decoder*/ +#ifndef LODEPNG_NO_COMPILE_DECODER +#define LODEPNG_COMPILE_DECODER +#endif + +/*deflate&zlib encoder and png encoder*/ +#ifndef LODEPNG_NO_COMPILE_ENCODER +#define LODEPNG_COMPILE_ENCODER +#endif + +/*the optional built in harddisk file loading and saving functions*/ +#ifndef LODEPNG_NO_COMPILE_DISK +#define LODEPNG_COMPILE_DISK +#endif + +/*support for chunks other than IHDR, IDAT, PLTE, tRNS, IEND: ancillary and unknown chunks*/ +#ifndef LODEPNG_NO_COMPILE_ANCILLARY_CHUNKS +#define LODEPNG_COMPILE_ANCILLARY_CHUNKS +#endif + +/*ability to convert error numerical codes to English text string*/ +#ifndef LODEPNG_NO_COMPILE_ERROR_TEXT +#define LODEPNG_COMPILE_ERROR_TEXT +#endif + +/*Compile the default allocators (C's free, malloc and realloc). If you disable this, +you can define the functions lodepng_free, lodepng_malloc and lodepng_realloc in your +source files with custom allocators.*/ +#ifndef LODEPNG_NO_COMPILE_ALLOCATORS +#define LODEPNG_COMPILE_ALLOCATORS +#endif + +/*compile the C++ version (you can disable the C++ wrapper here even when compiling for C++)*/ +#ifdef __cplusplus +#ifndef LODEPNG_NO_COMPILE_CPP +#define LODEPNG_COMPILE_CPP +#endif +#endif + +#ifdef LODEPNG_COMPILE_CPP +#include +#include +#endif /*LODEPNG_COMPILE_CPP*/ + +#ifdef LODEPNG_COMPILE_PNG +/*The PNG color types (also used for raw image).*/ +typedef enum LodePNGColorType { + LCT_GREY = 0, /*grayscale: 1,2,4,8,16 bit*/ + LCT_RGB = 2, /*RGB: 8,16 bit*/ + LCT_PALETTE = 3, /*palette: 1,2,4,8 bit*/ + LCT_GREY_ALPHA = 4, /*grayscale with alpha: 8,16 bit*/ + LCT_RGBA = 6, /*RGB with alpha: 8,16 bit*/ + /*LCT_MAX_OCTET_VALUE lets the compiler allow this enum to represent any invalid + byte value from 0 to 255 that could be present in an invalid PNG file header. Do + not use, compare with or set the name LCT_MAX_OCTET_VALUE, instead either use + the valid color type names above, or numeric values like 1 or 7 when checking for + particular disallowed color type byte values, or cast to integer to print it.*/ + LCT_MAX_OCTET_VALUE = 255 +} LodePNGColorType; + +#ifdef LODEPNG_COMPILE_DECODER +/* +Converts PNG data in memory to raw pixel data. +out: Output parameter. Pointer to buffer that will contain the raw pixel data. + After decoding, its size is w * h * (bytes per pixel) bytes larger than + initially. Bytes per pixel depends on colortype and bitdepth. + Must be freed after usage with free(*out). + Note: for 16-bit per channel colors, uses big endian format like PNG does. +w: Output parameter. Pointer to width of pixel data. +h: Output parameter. Pointer to height of pixel data. +in: Memory buffer with the PNG file. +insize: size of the in buffer. +colortype: the desired color type for the raw output image. See explanation on PNG color types. +bitdepth: the desired bit depth for the raw output image. See explanation on PNG color types. +Return value: LodePNG error code (0 means no error). +*/ +unsigned lodepng_decode_memory(unsigned char** out, unsigned* w, unsigned* h, + const unsigned char* in, size_t insize, + LodePNGColorType colortype, unsigned bitdepth); + +/*Same as lodepng_decode_memory, but always decodes to 32-bit RGBA raw image*/ +unsigned lodepng_decode32(unsigned char** out, unsigned* w, unsigned* h, + const unsigned char* in, size_t insize); + +/*Same as lodepng_decode_memory, but always decodes to 24-bit RGB raw image*/ +unsigned lodepng_decode24(unsigned char** out, unsigned* w, unsigned* h, + const unsigned char* in, size_t insize); + +#ifdef LODEPNG_COMPILE_DISK +/* +Load PNG from disk, from file with given name. +Same as the other decode functions, but instead takes a filename as input. +*/ +unsigned lodepng_decode_file(unsigned char** out, unsigned* w, unsigned* h, + const char* filename, + LodePNGColorType colortype, unsigned bitdepth); + +/*Same as lodepng_decode_file, but always decodes to 32-bit RGBA raw image.*/ +unsigned lodepng_decode32_file(unsigned char** out, unsigned* w, unsigned* h, + const char* filename); + +/*Same as lodepng_decode_file, but always decodes to 24-bit RGB raw image.*/ +unsigned lodepng_decode24_file(unsigned char** out, unsigned* w, unsigned* h, + const char* filename); +#endif /*LODEPNG_COMPILE_DISK*/ +#endif /*LODEPNG_COMPILE_DECODER*/ + + +#ifdef LODEPNG_COMPILE_ENCODER +/* +Converts raw pixel data into a PNG image in memory. The colortype and bitdepth + of the output PNG image cannot be chosen, they are automatically determined + by the colortype, bitdepth and content of the input pixel data. + Note: for 16-bit per channel colors, needs big endian format like PNG does. +out: Output parameter. Pointer to buffer that will contain the PNG image data. + Must be freed after usage with free(*out). +outsize: Output parameter. Pointer to the size in bytes of the out buffer. +image: The raw pixel data to encode. The size of this buffer should be + w * h * (bytes per pixel), bytes per pixel depends on colortype and bitdepth. +w: width of the raw pixel data in pixels. +h: height of the raw pixel data in pixels. +colortype: the color type of the raw input image. See explanation on PNG color types. +bitdepth: the bit depth of the raw input image. See explanation on PNG color types. +Return value: LodePNG error code (0 means no error). +*/ +unsigned lodepng_encode_memory(unsigned char** out, size_t* outsize, + const unsigned char* image, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth); + +/*Same as lodepng_encode_memory, but always encodes from 32-bit RGBA raw image.*/ +unsigned lodepng_encode32(unsigned char** out, size_t* outsize, + const unsigned char* image, unsigned w, unsigned h); + +/*Same as lodepng_encode_memory, but always encodes from 24-bit RGB raw image.*/ +unsigned lodepng_encode24(unsigned char** out, size_t* outsize, + const unsigned char* image, unsigned w, unsigned h); + +#ifdef LODEPNG_COMPILE_DISK +/* +Converts raw pixel data into a PNG file on disk. +Same as the other encode functions, but instead takes a filename as output. +NOTE: This overwrites existing files without warning! +*/ +unsigned lodepng_encode_file(const char* filename, + const unsigned char* image, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth); + +/*Same as lodepng_encode_file, but always encodes from 32-bit RGBA raw image.*/ +unsigned lodepng_encode32_file(const char* filename, + const unsigned char* image, unsigned w, unsigned h); + +/*Same as lodepng_encode_file, but always encodes from 24-bit RGB raw image.*/ +unsigned lodepng_encode24_file(const char* filename, + const unsigned char* image, unsigned w, unsigned h); +#endif /*LODEPNG_COMPILE_DISK*/ +#endif /*LODEPNG_COMPILE_ENCODER*/ + + +#ifdef LODEPNG_COMPILE_CPP +namespace lodepng { +#ifdef LODEPNG_COMPILE_DECODER +/*Same as lodepng_decode_memory, but decodes to an std::vector. The colortype +is the format to output the pixels to. Default is RGBA 8-bit per channel.*/ +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + const unsigned char* in, size_t insize, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + const std::vector& in, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +#ifdef LODEPNG_COMPILE_DISK +/* +Converts PNG file from disk to raw pixel data in memory. +Same as the other decode functions, but instead takes a filename as input. +*/ +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + const std::string& filename, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +#endif /* LODEPNG_COMPILE_DISK */ +#endif /* LODEPNG_COMPILE_DECODER */ + +#ifdef LODEPNG_COMPILE_ENCODER +/*Same as lodepng_encode_memory, but encodes to an std::vector. colortype +is that of the raw input data. The output PNG color type will be auto chosen.*/ +unsigned encode(std::vector& out, + const unsigned char* in, unsigned w, unsigned h, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +unsigned encode(std::vector& out, + const std::vector& in, unsigned w, unsigned h, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +#ifdef LODEPNG_COMPILE_DISK +/* +Converts 32-bit RGBA raw pixel data into a PNG file on disk. +Same as the other encode functions, but instead takes a filename as output. +NOTE: This overwrites existing files without warning! +*/ +unsigned encode(const std::string& filename, + const unsigned char* in, unsigned w, unsigned h, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +unsigned encode(const std::string& filename, + const std::vector& in, unsigned w, unsigned h, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +#endif /* LODEPNG_COMPILE_DISK */ +#endif /* LODEPNG_COMPILE_ENCODER */ +} /* namespace lodepng */ +#endif /*LODEPNG_COMPILE_CPP*/ +#endif /*LODEPNG_COMPILE_PNG*/ + +#ifdef LODEPNG_COMPILE_ERROR_TEXT +/*Returns an English description of the numerical error code.*/ +const char* lodepng_error_text(unsigned code); +#endif /*LODEPNG_COMPILE_ERROR_TEXT*/ + +#ifdef LODEPNG_COMPILE_DECODER +/*Settings for zlib decompression*/ +typedef struct LodePNGDecompressSettings LodePNGDecompressSettings; +struct LodePNGDecompressSettings { + /* Check LodePNGDecoderSettings for more ignorable errors such as ignore_crc */ + unsigned ignore_adler32; /*if 1, continue and don't give an error message if the Adler32 checksum is corrupted*/ + unsigned ignore_nlen; /*ignore complement of len checksum in uncompressed blocks*/ + + /*Maximum decompressed size, beyond this the decoder may (and is encouraged to) stop decoding, + return an error, output a data size > max_output_size and all the data up to that point. This is + not hard limit nor a guarantee, but can prevent excessive memory usage. This setting is + ignored by the PNG decoder, but is used by the deflate/zlib decoder and can be used by custom ones. + Set to 0 to impose no limit (the default).*/ + size_t max_output_size; + + /*use custom zlib decoder instead of built in one (default: null). + Should return 0 if success, any non-0 if error (numeric value not exposed).*/ + unsigned (*custom_zlib)(unsigned char**, size_t*, + const unsigned char*, size_t, + const LodePNGDecompressSettings*); + /*use custom deflate decoder instead of built in one (default: null) + if custom_zlib is not null, custom_inflate is ignored (the zlib format uses deflate). + Should return 0 if success, any non-0 if error (numeric value not exposed).*/ + unsigned (*custom_inflate)(unsigned char**, size_t*, + const unsigned char*, size_t, + const LodePNGDecompressSettings*); + + const void* custom_context; /*optional custom settings for custom functions*/ +}; + +extern const LodePNGDecompressSettings lodepng_default_decompress_settings; +void lodepng_decompress_settings_init(LodePNGDecompressSettings* settings); +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER +/* +Settings for zlib compression. Tweaking these settings tweaks the balance +between speed and compression ratio. +*/ +typedef struct LodePNGCompressSettings LodePNGCompressSettings; +struct LodePNGCompressSettings /*deflate = compress*/ { + /*LZ77 related settings*/ + unsigned btype; /*the block type for LZ (0, 1, 2 or 3, see zlib standard). Should be 2 for proper compression.*/ + unsigned use_lz77; /*whether or not to use LZ77. Should be 1 for proper compression.*/ + unsigned windowsize; /*must be a power of two <= 32768. higher compresses more but is slower. Default value: 2048.*/ + unsigned minmatch; /*minimum lz77 length. 3 is normally best, 6 can be better for some PNGs. Default: 0*/ + unsigned nicematch; /*stop searching if >= this length found. Set to 258 for best compression. Default: 128*/ + unsigned lazymatching; /*use lazy matching: better compression but a bit slower. Default: true*/ + + /*use custom zlib encoder instead of built in one (default: null)*/ + unsigned (*custom_zlib)(unsigned char**, size_t*, + const unsigned char*, size_t, + const LodePNGCompressSettings*); + /*use custom deflate encoder instead of built in one (default: null) + if custom_zlib is used, custom_deflate is ignored since only the built in + zlib function will call custom_deflate*/ + unsigned (*custom_deflate)(unsigned char**, size_t*, + const unsigned char*, size_t, + const LodePNGCompressSettings*); + + const void* custom_context; /*optional custom settings for custom functions*/ +}; + +extern const LodePNGCompressSettings lodepng_default_compress_settings; +void lodepng_compress_settings_init(LodePNGCompressSettings* settings); +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#ifdef LODEPNG_COMPILE_PNG +/* +Color mode of an image. Contains all information required to decode the pixel +bits to RGBA colors. This information is the same as used in the PNG file +format, and is used both for PNG and raw image data in LodePNG. +*/ +typedef struct LodePNGColorMode { + /*header (IHDR)*/ + LodePNGColorType colortype; /*color type, see PNG standard or documentation further in this header file*/ + unsigned bitdepth; /*bits per sample, see PNG standard or documentation further in this header file*/ + + /* + palette (PLTE and tRNS) + + Dynamically allocated with the colors of the palette, including alpha. + This field may not be allocated directly, use lodepng_color_mode_init first, + then lodepng_palette_add per color to correctly initialize it (to ensure size + of exactly 1024 bytes). + + The alpha channels must be set as well, set them to 255 for opaque images. + + When decoding, by default you can ignore this palette, since LodePNG already + fills the palette colors in the pixels of the raw RGBA output. + + The palette is only supported for color type 3. + */ + unsigned char* palette; /*palette in RGBARGBA... order. Must be either 0, or when allocated must have 1024 bytes*/ + size_t palettesize; /*palette size in number of colors (amount of used bytes is 4 * palettesize)*/ + + /* + transparent color key (tRNS) + + This color uses the same bit depth as the bitdepth value in this struct, which can be 1-bit to 16-bit. + For grayscale PNGs, r, g and b will all 3 be set to the same. + + When decoding, by default you can ignore this information, since LodePNG sets + pixels with this key to transparent already in the raw RGBA output. + + The color key is only supported for color types 0 and 2. + */ + unsigned key_defined; /*is a transparent color key given? 0 = false, 1 = true*/ + unsigned key_r; /*red/grayscale component of color key*/ + unsigned key_g; /*green component of color key*/ + unsigned key_b; /*blue component of color key*/ +} LodePNGColorMode; + +/*init, cleanup and copy functions to use with this struct*/ +void lodepng_color_mode_init(LodePNGColorMode* info); +void lodepng_color_mode_cleanup(LodePNGColorMode* info); +/*return value is error code (0 means no error)*/ +unsigned lodepng_color_mode_copy(LodePNGColorMode* dest, const LodePNGColorMode* source); +/* Makes a temporary LodePNGColorMode that does not need cleanup (no palette) */ +LodePNGColorMode lodepng_color_mode_make(LodePNGColorType colortype, unsigned bitdepth); + +void lodepng_palette_clear(LodePNGColorMode* info); +/*add 1 color to the palette*/ +unsigned lodepng_palette_add(LodePNGColorMode* info, + unsigned char r, unsigned char g, unsigned char b, unsigned char a); + +/*get the total amount of bits per pixel, based on colortype and bitdepth in the struct*/ +unsigned lodepng_get_bpp(const LodePNGColorMode* info); +/*get the amount of color channels used, based on colortype in the struct. +If a palette is used, it counts as 1 channel.*/ +unsigned lodepng_get_channels(const LodePNGColorMode* info); +/*is it a grayscale type? (only colortype 0 or 4)*/ +unsigned lodepng_is_greyscale_type(const LodePNGColorMode* info); +/*has it got an alpha channel? (only colortype 2 or 6)*/ +unsigned lodepng_is_alpha_type(const LodePNGColorMode* info); +/*has it got a palette? (only colortype 3)*/ +unsigned lodepng_is_palette_type(const LodePNGColorMode* info); +/*only returns true if there is a palette and there is a value in the palette with alpha < 255. +Loops through the palette to check this.*/ +unsigned lodepng_has_palette_alpha(const LodePNGColorMode* info); +/* +Check if the given color info indicates the possibility of having non-opaque pixels in the PNG image. +Returns true if the image can have translucent or invisible pixels (it still be opaque if it doesn't use such pixels). +Returns false if the image can only have opaque pixels. +In detail, it returns true only if it's a color type with alpha, or has a palette with non-opaque values, +or if "key_defined" is true. +*/ +unsigned lodepng_can_have_alpha(const LodePNGColorMode* info); +/*Returns the byte size of a raw image buffer with given width, height and color mode*/ +size_t lodepng_get_raw_size(unsigned w, unsigned h, const LodePNGColorMode* color); + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS +/*The information of a Time chunk in PNG.*/ +typedef struct LodePNGTime { + unsigned year; /*2 bytes used (0-65535)*/ + unsigned month; /*1-12*/ + unsigned day; /*1-31*/ + unsigned hour; /*0-23*/ + unsigned minute; /*0-59*/ + unsigned second; /*0-60 (to allow for leap seconds)*/ +} LodePNGTime; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +/*Information about the PNG image, except pixels, width and height.*/ +typedef struct LodePNGInfo { + /*header (IHDR), palette (PLTE) and transparency (tRNS) chunks*/ + unsigned compression_method;/*compression method of the original file. Always 0.*/ + unsigned filter_method; /*filter method of the original file*/ + unsigned interlace_method; /*interlace method of the original file: 0=none, 1=Adam7*/ + LodePNGColorMode color; /*color type and bits, palette and transparency of the PNG file*/ + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /* + Suggested background color chunk (bKGD) + + This uses the same color mode and bit depth as the PNG (except no alpha channel), + with values truncated to the bit depth in the unsigned integer. + + For grayscale and palette PNGs, the value is stored in background_r. The values + in background_g and background_b are then unused. + + So when decoding, you may get these in a different color mode than the one you requested + for the raw pixels. + + When encoding with auto_convert, you must use the color model defined in info_png.color for + these values. The encoder normally ignores info_png.color when auto_convert is on, but will + use it to interpret these values (and convert copies of them to its chosen color model). + + When encoding, avoid setting this to an expensive color, such as a non-gray value + when the image is gray, or the compression will be worse since it will be forced to + write the PNG with a more expensive color mode (when auto_convert is on). + + The decoder does not use this background color to edit the color of pixels. This is a + completely optional metadata feature. + */ + unsigned background_defined; /*is a suggested background color given?*/ + unsigned background_r; /*red/gray/palette component of suggested background color*/ + unsigned background_g; /*green component of suggested background color*/ + unsigned background_b; /*blue component of suggested background color*/ + + /* + Non-international text chunks (tEXt and zTXt) + + The char** arrays each contain num strings. The actual messages are in + text_strings, while text_keys are keywords that give a short description what + the actual text represents, e.g. Title, Author, Description, or anything else. + + All the string fields below including strings, keys, names and language tags are null terminated. + The PNG specification uses null characters for the keys, names and tags, and forbids null + characters to appear in the main text which is why we can use null termination everywhere here. + + A keyword is minimum 1 character and maximum 79 characters long (plus the + additional null terminator). It's discouraged to use a single line length + longer than 79 characters for texts. + + Don't allocate these text buffers yourself. Use the init/cleanup functions + correctly and use lodepng_add_text and lodepng_clear_text. + + Standard text chunk keywords and strings are encoded using Latin-1. + */ + size_t text_num; /*the amount of texts in these char** buffers (there may be more texts in itext)*/ + char** text_keys; /*the keyword of a text chunk (e.g. "Comment")*/ + char** text_strings; /*the actual text*/ + + /* + International text chunks (iTXt) + Similar to the non-international text chunks, but with additional strings + "langtags" and "transkeys", and the following text encodings are used: + keys: Latin-1, langtags: ASCII, transkeys and strings: UTF-8. + keys must be 1-79 characters (plus the additional null terminator), the other + strings are any length. + */ + size_t itext_num; /*the amount of international texts in this PNG*/ + char** itext_keys; /*the English keyword of the text chunk (e.g. "Comment")*/ + char** itext_langtags; /*language tag for this text's language, ISO/IEC 646 string, e.g. ISO 639 language tag*/ + char** itext_transkeys; /*keyword translated to the international language - UTF-8 string*/ + char** itext_strings; /*the actual international text - UTF-8 string*/ + + /*time chunk (tIME)*/ + unsigned time_defined; /*set to 1 to make the encoder generate a tIME chunk*/ + LodePNGTime time; + + /*phys chunk (pHYs)*/ + unsigned phys_defined; /*if 0, there is no pHYs chunk and the values below are undefined, if 1 else there is one*/ + unsigned phys_x; /*pixels per unit in x direction*/ + unsigned phys_y; /*pixels per unit in y direction*/ + unsigned phys_unit; /*may be 0 (unknown unit) or 1 (metre)*/ + + /* + Color profile related chunks: gAMA, cHRM, sRGB, iCPP + + LodePNG does not apply any color conversions on pixels in the encoder or decoder and does not interpret these color + profile values. It merely passes on the information. If you wish to use color profiles and convert colors, please + use these values with a color management library. + + See the PNG, ICC and sRGB specifications for more information about the meaning of these values. + */ + + /* gAMA chunk: optional, overridden by sRGB or iCCP if those are present. */ + unsigned gama_defined; /* Whether a gAMA chunk is present (0 = not present, 1 = present). */ + unsigned gama_gamma; /* Gamma exponent times 100000 */ + + /* cHRM chunk: optional, overridden by sRGB or iCCP if those are present. */ + unsigned chrm_defined; /* Whether a cHRM chunk is present (0 = not present, 1 = present). */ + unsigned chrm_white_x; /* White Point x times 100000 */ + unsigned chrm_white_y; /* White Point y times 100000 */ + unsigned chrm_red_x; /* Red x times 100000 */ + unsigned chrm_red_y; /* Red y times 100000 */ + unsigned chrm_green_x; /* Green x times 100000 */ + unsigned chrm_green_y; /* Green y times 100000 */ + unsigned chrm_blue_x; /* Blue x times 100000 */ + unsigned chrm_blue_y; /* Blue y times 100000 */ + + /* + sRGB chunk: optional. May not appear at the same time as iCCP. + If gAMA is also present gAMA must contain value 45455. + If cHRM is also present cHRM must contain respectively 31270,32900,64000,33000,30000,60000,15000,6000. + */ + unsigned srgb_defined; /* Whether an sRGB chunk is present (0 = not present, 1 = present). */ + unsigned srgb_intent; /* Rendering intent: 0=perceptual, 1=rel. colorimetric, 2=saturation, 3=abs. colorimetric */ + + /* + iCCP chunk: optional. May not appear at the same time as sRGB. + + LodePNG does not parse or use the ICC profile (except its color space header field for an edge case), a + separate library to handle the ICC data (not included in LodePNG) format is needed to use it for color + management and conversions. + + For encoding, if iCCP is present, gAMA and cHRM are recommended to be added as well with values that match the ICC + profile as closely as possible, if you wish to do this you should provide the correct values for gAMA and cHRM and + enable their '_defined' flags since LodePNG will not automatically compute them from the ICC profile. + + For encoding, the ICC profile is required by the PNG specification to be an "RGB" profile for non-gray + PNG color types and a "GRAY" profile for gray PNG color types. If you disable auto_convert, you must ensure + the ICC profile type matches your requested color type, else the encoder gives an error. If auto_convert is + enabled (the default), and the ICC profile is not a good match for the pixel data, this will result in an encoder + error if the pixel data has non-gray pixels for a GRAY profile, or a silent less-optimal compression of the pixel + data if the pixels could be encoded as grayscale but the ICC profile is RGB. + + To avoid this do not set an ICC profile in the image unless there is a good reason for it, and when doing so + make sure you compute it carefully to avoid the above problems. + */ + unsigned iccp_defined; /* Whether an iCCP chunk is present (0 = not present, 1 = present). */ + char* iccp_name; /* Null terminated string with profile name, 1-79 bytes */ + /* + The ICC profile in iccp_profile_size bytes. + Don't allocate this buffer yourself. Use the init/cleanup functions + correctly and use lodepng_set_icc and lodepng_clear_icc. + */ + unsigned char* iccp_profile; + unsigned iccp_profile_size; /* The size of iccp_profile in bytes */ + + /* End of color profile related chunks */ + + + /* + unknown chunks: chunks not known by LodePNG, passed on byte for byte. + + There are 3 buffers, one for each position in the PNG where unknown chunks can appear. + Each buffer contains all unknown chunks for that position consecutively. + The 3 positions are: + 0: between IHDR and PLTE, 1: between PLTE and IDAT, 2: between IDAT and IEND. + + For encoding, do not store critical chunks or known chunks that are enabled with a "_defined" flag + above in here, since the encoder will blindly follow this and could then encode an invalid PNG file + (such as one with two IHDR chunks or the disallowed combination of sRGB with iCCP). But do use + this if you wish to store an ancillary chunk that is not supported by LodePNG (such as sPLT or hIST), + or any non-standard PNG chunk. + + Do not allocate or traverse this data yourself. Use the chunk traversing functions declared + later, such as lodepng_chunk_next and lodepng_chunk_append, to read/write this struct. + */ + unsigned char* unknown_chunks_data[3]; + size_t unknown_chunks_size[3]; /*size in bytes of the unknown chunks, given for protection*/ +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} LodePNGInfo; + +/*init, cleanup and copy functions to use with this struct*/ +void lodepng_info_init(LodePNGInfo* info); +void lodepng_info_cleanup(LodePNGInfo* info); +/*return value is error code (0 means no error)*/ +unsigned lodepng_info_copy(LodePNGInfo* dest, const LodePNGInfo* source); + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS +unsigned lodepng_add_text(LodePNGInfo* info, const char* key, const char* str); /*push back both texts at once*/ +void lodepng_clear_text(LodePNGInfo* info); /*use this to clear the texts again after you filled them in*/ + +unsigned lodepng_add_itext(LodePNGInfo* info, const char* key, const char* langtag, + const char* transkey, const char* str); /*push back the 4 texts of 1 chunk at once*/ +void lodepng_clear_itext(LodePNGInfo* info); /*use this to clear the itexts again after you filled them in*/ + +/*replaces if exists*/ +unsigned lodepng_set_icc(LodePNGInfo* info, const char* name, const unsigned char* profile, unsigned profile_size); +void lodepng_clear_icc(LodePNGInfo* info); /*use this to clear the texts again after you filled them in*/ +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +/* +Converts raw buffer from one color type to another color type, based on +LodePNGColorMode structs to describe the input and output color type. +See the reference manual at the end of this header file to see which color conversions are supported. +return value = LodePNG error code (0 if all went ok, an error if the conversion isn't supported) +The out buffer must have size (w * h * bpp + 7) / 8, where bpp is the bits per pixel +of the output color type (lodepng_get_bpp). +For < 8 bpp images, there should not be padding bits at the end of scanlines. +For 16-bit per channel colors, uses big endian format like PNG does. +Return value is LodePNG error code +*/ +unsigned lodepng_convert(unsigned char* out, const unsigned char* in, + const LodePNGColorMode* mode_out, const LodePNGColorMode* mode_in, + unsigned w, unsigned h); + +#ifdef LODEPNG_COMPILE_DECODER +/* +Settings for the decoder. This contains settings for the PNG and the Zlib +decoder, but not the Info settings from the Info structs. +*/ +typedef struct LodePNGDecoderSettings { + LodePNGDecompressSettings zlibsettings; /*in here is the setting to ignore Adler32 checksums*/ + + /* Check LodePNGDecompressSettings for more ignorable errors such as ignore_adler32 */ + unsigned ignore_crc; /*ignore CRC checksums*/ + unsigned ignore_critical; /*ignore unknown critical chunks*/ + unsigned ignore_end; /*ignore issues at end of file if possible (missing IEND chunk, too large chunk, ...)*/ + /* TODO: make a system involving warnings with levels and a strict mode instead. Other potentially recoverable + errors: srgb rendering intent value, size of content of ancillary chunks, more than 79 characters for some + strings, placement/combination rules for ancillary chunks, crc of unknown chunks, allowed characters + in string keys, etc... */ + + unsigned color_convert; /*whether to convert the PNG to the color type you want. Default: yes*/ + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + unsigned read_text_chunks; /*if false but remember_unknown_chunks is true, they're stored in the unknown chunks*/ + + /*store all bytes from unknown chunks in the LodePNGInfo (off by default, useful for a png editor)*/ + unsigned remember_unknown_chunks; + + /* maximum size for decompressed text chunks. If a text chunk's text is larger than this, an error is returned, + unless reading text chunks is disabled or this limit is set higher or disabled. Set to 0 to allow any size. + By default it is a value that prevents unreasonably large strings from hogging memory. */ + size_t max_text_size; + + /* maximum size for compressed ICC chunks. If the ICC profile is larger than this, an error will be returned. Set to + 0 to allow any size. By default this is a value that prevents ICC profiles that would be much larger than any + legitimate profile could be to hog memory. */ + size_t max_icc_size; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} LodePNGDecoderSettings; + +void lodepng_decoder_settings_init(LodePNGDecoderSettings* settings); +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER +/*automatically use color type with less bits per pixel if losslessly possible. Default: AUTO*/ +typedef enum LodePNGFilterStrategy { + /*every filter at zero*/ + LFS_ZERO = 0, + /*every filter at 1, 2, 3 or 4 (paeth), unlike LFS_ZERO not a good choice, but for testing*/ + LFS_ONE = 1, + LFS_TWO = 2, + LFS_THREE = 3, + LFS_FOUR = 4, + /*Use filter that gives minimum sum, as described in the official PNG filter heuristic.*/ + LFS_MINSUM, + /*Use the filter type that gives smallest Shannon entropy for this scanline. Depending + on the image, this is better or worse than minsum.*/ + LFS_ENTROPY, + /* + Brute-force-search PNG filters by compressing each filter for each scanline. + Experimental, very slow, and only rarely gives better compression than MINSUM. + */ + LFS_BRUTE_FORCE, + /*use predefined_filters buffer: you specify the filter type for each scanline*/ + LFS_PREDEFINED +} LodePNGFilterStrategy; + +/*Gives characteristics about the integer RGBA colors of the image (count, alpha channel usage, bit depth, ...), +which helps decide which color model to use for encoding. +Used internally by default if "auto_convert" is enabled. Public because it's useful for custom algorithms.*/ +typedef struct LodePNGColorStats { + unsigned colored; /*not grayscale*/ + unsigned key; /*image is not opaque and color key is possible instead of full alpha*/ + unsigned short key_r; /*key values, always as 16-bit, in 8-bit case the byte is duplicated, e.g. 65535 means 255*/ + unsigned short key_g; + unsigned short key_b; + unsigned alpha; /*image is not opaque and alpha channel or alpha palette required*/ + unsigned numcolors; /*amount of colors, up to 257. Not valid if bits == 16 or allow_palette is disabled.*/ + unsigned char palette[1024]; /*Remembers up to the first 256 RGBA colors, in no particular order, only valid when numcolors is valid*/ + unsigned bits; /*bits per channel (not for palette). 1,2 or 4 for grayscale only. 16 if 16-bit per channel required.*/ + size_t numpixels; + + /*user settings for computing/using the stats*/ + unsigned allow_palette; /*default 1. if 0, disallow choosing palette colortype in auto_choose_color, and don't count numcolors*/ + unsigned allow_greyscale; /*default 1. if 0, choose RGB or RGBA even if the image only has gray colors*/ +} LodePNGColorStats; + +void lodepng_color_stats_init(LodePNGColorStats* stats); + +/*Get a LodePNGColorStats of the image. The stats must already have been inited. +Returns error code (e.g. alloc fail) or 0 if ok.*/ +unsigned lodepng_compute_color_stats(LodePNGColorStats* stats, + const unsigned char* image, unsigned w, unsigned h, + const LodePNGColorMode* mode_in); + +/*Settings for the encoder.*/ +typedef struct LodePNGEncoderSettings { + LodePNGCompressSettings zlibsettings; /*settings for the zlib encoder, such as window size, ...*/ + + unsigned auto_convert; /*automatically choose output PNG color type. Default: true*/ + + /*If true, follows the official PNG heuristic: if the PNG uses a palette or lower than + 8 bit depth, set all filters to zero. Otherwise use the filter_strategy. Note that to + completely follow the official PNG heuristic, filter_palette_zero must be true and + filter_strategy must be LFS_MINSUM*/ + unsigned filter_palette_zero; + /*Which filter strategy to use when not using zeroes due to filter_palette_zero. + Set filter_palette_zero to 0 to ensure always using your chosen strategy. Default: LFS_MINSUM*/ + LodePNGFilterStrategy filter_strategy; + /*used if filter_strategy is LFS_PREDEFINED. In that case, this must point to a buffer with + the same length as the amount of scanlines in the image, and each value must <= 5. You + have to cleanup this buffer, LodePNG will never free it. Don't forget that filter_palette_zero + must be set to 0 to ensure this is also used on palette or low bitdepth images.*/ + const unsigned char* predefined_filters; + + /*force creating a PLTE chunk if colortype is 2 or 6 (= a suggested palette). + If colortype is 3, PLTE is _always_ created.*/ + unsigned force_palette; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /*add LodePNG identifier and version as a text chunk, for debugging*/ + unsigned add_id; + /*encode text chunks as zTXt chunks instead of tEXt chunks, and use compression in iTXt chunks*/ + unsigned text_compression; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} LodePNGEncoderSettings; + +void lodepng_encoder_settings_init(LodePNGEncoderSettings* settings); +#endif /*LODEPNG_COMPILE_ENCODER*/ + + +#if defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) +/*The settings, state and information for extended encoding and decoding.*/ +typedef struct LodePNGState { +#ifdef LODEPNG_COMPILE_DECODER + LodePNGDecoderSettings decoder; /*the decoding settings*/ +#endif /*LODEPNG_COMPILE_DECODER*/ +#ifdef LODEPNG_COMPILE_ENCODER + LodePNGEncoderSettings encoder; /*the encoding settings*/ +#endif /*LODEPNG_COMPILE_ENCODER*/ + LodePNGColorMode info_raw; /*specifies the format in which you would like to get the raw pixel buffer*/ + LodePNGInfo info_png; /*info of the PNG image obtained after decoding*/ + unsigned error; +} LodePNGState; + +/*init, cleanup and copy functions to use with this struct*/ +void lodepng_state_init(LodePNGState* state); +void lodepng_state_cleanup(LodePNGState* state); +void lodepng_state_copy(LodePNGState* dest, const LodePNGState* source); +#endif /* defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) */ + +#ifdef LODEPNG_COMPILE_DECODER +/* +Same as lodepng_decode_memory, but uses a LodePNGState to allow custom settings and +getting much more information about the PNG image and color mode. +*/ +unsigned lodepng_decode(unsigned char** out, unsigned* w, unsigned* h, + LodePNGState* state, + const unsigned char* in, size_t insize); + +/* +Read the PNG header, but not the actual data. This returns only the information +that is in the IHDR chunk of the PNG, such as width, height and color type. The +information is placed in the info_png field of the LodePNGState. +*/ +unsigned lodepng_inspect(unsigned* w, unsigned* h, + LodePNGState* state, + const unsigned char* in, size_t insize); +#endif /*LODEPNG_COMPILE_DECODER*/ + +/* +Reads one metadata chunk (other than IHDR) of the PNG file and outputs what it +read in the state. Returns error code on failure. +Use lodepng_inspect first with a new state, then e.g. lodepng_chunk_find_const +to find the desired chunk type, and if non null use lodepng_inspect_chunk (with +chunk_pointer - start_of_file as pos). +Supports most metadata chunks from the PNG standard (gAMA, bKGD, tEXt, ...). +Ignores unsupported, unknown, non-metadata or IHDR chunks (without error). +Requirements: &in[pos] must point to start of a chunk, must use regular +lodepng_inspect first since format of most other chunks depends on IHDR, and if +there is a PLTE chunk, that one must be inspected before tRNS or bKGD. +*/ +unsigned lodepng_inspect_chunk(LodePNGState* state, size_t pos, + const unsigned char* in, size_t insize); + +#ifdef LODEPNG_COMPILE_ENCODER +/*This function allocates the out buffer with standard malloc and stores the size in *outsize.*/ +unsigned lodepng_encode(unsigned char** out, size_t* outsize, + const unsigned char* image, unsigned w, unsigned h, + LodePNGState* state); +#endif /*LODEPNG_COMPILE_ENCODER*/ + +/* +The lodepng_chunk functions are normally not needed, except to traverse the +unknown chunks stored in the LodePNGInfo struct, or add new ones to it. +It also allows traversing the chunks of an encoded PNG file yourself. + +The chunk pointer always points to the beginning of the chunk itself, that is +the first byte of the 4 length bytes. + +In the PNG file format, chunks have the following format: +-4 bytes length: length of the data of the chunk in bytes (chunk itself is 12 bytes longer) +-4 bytes chunk type (ASCII a-z,A-Z only, see below) +-length bytes of data (may be 0 bytes if length was 0) +-4 bytes of CRC, computed on chunk name + data + +The first chunk starts at the 8th byte of the PNG file, the entire rest of the file +exists out of concatenated chunks with the above format. + +PNG standard chunk ASCII naming conventions: +-First byte: uppercase = critical, lowercase = ancillary +-Second byte: uppercase = public, lowercase = private +-Third byte: must be uppercase +-Fourth byte: uppercase = unsafe to copy, lowercase = safe to copy +*/ + +/* +Gets the length of the data of the chunk. Total chunk length has 12 bytes more. +There must be at least 4 bytes to read from. If the result value is too large, +it may be corrupt data. +*/ +unsigned lodepng_chunk_length(const unsigned char* chunk); + +/*puts the 4-byte type in null terminated string*/ +void lodepng_chunk_type(char type[5], const unsigned char* chunk); + +/*check if the type is the given type*/ +unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type); + +/*0: it's one of the critical chunk types, 1: it's an ancillary chunk (see PNG standard)*/ +unsigned char lodepng_chunk_ancillary(const unsigned char* chunk); + +/*0: public, 1: private (see PNG standard)*/ +unsigned char lodepng_chunk_private(const unsigned char* chunk); + +/*0: the chunk is unsafe to copy, 1: the chunk is safe to copy (see PNG standard)*/ +unsigned char lodepng_chunk_safetocopy(const unsigned char* chunk); + +/*get pointer to the data of the chunk, where the input points to the header of the chunk*/ +unsigned char* lodepng_chunk_data(unsigned char* chunk); +const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk); + +/*returns 0 if the crc is correct, 1 if it's incorrect (0 for OK as usual!)*/ +unsigned lodepng_chunk_check_crc(const unsigned char* chunk); + +/*generates the correct CRC from the data and puts it in the last 4 bytes of the chunk*/ +void lodepng_chunk_generate_crc(unsigned char* chunk); + +/* +Iterate to next chunks, allows iterating through all chunks of the PNG file. +Input must be at the beginning of a chunk (result of a previous lodepng_chunk_next call, +or the 8th byte of a PNG file which always has the first chunk), or alternatively may +point to the first byte of the PNG file (which is not a chunk but the magic header, the +function will then skip over it and return the first real chunk). +Will output pointer to the start of the next chunk, or at or beyond end of the file if there +is no more chunk after this or possibly if the chunk is corrupt. +Start this process at the 8th byte of the PNG file. +In a non-corrupt PNG file, the last chunk should have name "IEND". +*/ +unsigned char* lodepng_chunk_next(unsigned char* chunk, unsigned char* end); +const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk, const unsigned char* end); + +/*Finds the first chunk with the given type in the range [chunk, end), or returns NULL if not found.*/ +unsigned char* lodepng_chunk_find(unsigned char* chunk, unsigned char* end, const char type[5]); +const unsigned char* lodepng_chunk_find_const(const unsigned char* chunk, const unsigned char* end, const char type[5]); + +/* +Appends chunk to the data in out. The given chunk should already have its chunk header. +The out variable and outsize are updated to reflect the new reallocated buffer. +Returns error code (0 if it went ok) +*/ +unsigned lodepng_chunk_append(unsigned char** out, size_t* outsize, const unsigned char* chunk); + +/* +Appends new chunk to out. The chunk to append is given by giving its length, type +and data separately. The type is a 4-letter string. +The out variable and outsize are updated to reflect the new reallocated buffer. +Returne error code (0 if it went ok) +*/ +unsigned lodepng_chunk_create(unsigned char** out, size_t* outsize, unsigned length, + const char* type, const unsigned char* data); + + +/*Calculate CRC32 of buffer*/ +unsigned lodepng_crc32(const unsigned char* buf, size_t len); +#endif /*LODEPNG_COMPILE_PNG*/ + + +#ifdef LODEPNG_COMPILE_ZLIB +/* +This zlib part can be used independently to zlib compress and decompress a +buffer. It cannot be used to create gzip files however, and it only supports the +part of zlib that is required for PNG, it does not support dictionaries. +*/ + +#ifdef LODEPNG_COMPILE_DECODER +/*Inflate a buffer. Inflate is the decompression step of deflate. Out buffer must be freed after use.*/ +unsigned lodepng_inflate(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGDecompressSettings* settings); + +/* +Decompresses Zlib data. Reallocates the out buffer and appends the data. The +data must be according to the zlib specification. +Either, *out must be NULL and *outsize must be 0, or, *out must be a valid +buffer and *outsize its size in bytes. out must be freed by user after usage. +*/ +unsigned lodepng_zlib_decompress(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGDecompressSettings* settings); +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER +/* +Compresses data with Zlib. Reallocates the out buffer and appends the data. +Zlib adds a small header and trailer around the deflate data. +The data is output in the format of the zlib specification. +Either, *out must be NULL and *outsize must be 0, or, *out must be a valid +buffer and *outsize its size in bytes. out must be freed by user after usage. +*/ +unsigned lodepng_zlib_compress(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGCompressSettings* settings); + +/* +Find length-limited Huffman code for given frequencies. This function is in the +public interface only for tests, it's used internally by lodepng_deflate. +*/ +unsigned lodepng_huffman_code_lengths(unsigned* lengths, const unsigned* frequencies, + size_t numcodes, unsigned maxbitlen); + +/*Compress a buffer with deflate. See RFC 1951. Out buffer must be freed after use.*/ +unsigned lodepng_deflate(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGCompressSettings* settings); + +#endif /*LODEPNG_COMPILE_ENCODER*/ +#endif /*LODEPNG_COMPILE_ZLIB*/ + +#ifdef LODEPNG_COMPILE_DISK +/* +Load a file from disk into buffer. The function allocates the out buffer, and +after usage you should free it. +out: output parameter, contains pointer to loaded buffer. +outsize: output parameter, size of the allocated out buffer +filename: the path to the file to load +return value: error code (0 means ok) +*/ +unsigned lodepng_load_file(unsigned char** out, size_t* outsize, const char* filename); + +/* +Save a file from buffer to disk. Warning, if it exists, this function overwrites +the file without warning! +buffer: the buffer to write +buffersize: size of the buffer to write +filename: the path to the file to save to +return value: error code (0 means ok) +*/ +unsigned lodepng_save_file(const unsigned char* buffer, size_t buffersize, const char* filename); +#endif /*LODEPNG_COMPILE_DISK*/ + +#ifdef LODEPNG_COMPILE_CPP +/* The LodePNG C++ wrapper uses std::vectors instead of manually allocated memory buffers. */ +namespace lodepng { +#ifdef LODEPNG_COMPILE_PNG +class State : public LodePNGState { + public: + State(); + State(const State& other); + ~State(); + State& operator=(const State& other); +}; + +#ifdef LODEPNG_COMPILE_DECODER +/* Same as other lodepng::decode, but using a State for more settings and information. */ +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + State& state, + const unsigned char* in, size_t insize); +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + State& state, + const std::vector& in); +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER +/* Same as other lodepng::encode, but using a State for more settings and information. */ +unsigned encode(std::vector& out, + const unsigned char* in, unsigned w, unsigned h, + State& state); +unsigned encode(std::vector& out, + const std::vector& in, unsigned w, unsigned h, + State& state); +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#ifdef LODEPNG_COMPILE_DISK +/* +Load a file from disk into an std::vector. +return value: error code (0 means ok) +*/ +unsigned load_file(std::vector& buffer, const std::string& filename); + +/* +Save the binary data in an std::vector to a file on disk. The file is overwritten +without warning. +*/ +unsigned save_file(const std::vector& buffer, const std::string& filename); +#endif /* LODEPNG_COMPILE_DISK */ +#endif /* LODEPNG_COMPILE_PNG */ + +#ifdef LODEPNG_COMPILE_ZLIB +#ifdef LODEPNG_COMPILE_DECODER +/* Zlib-decompress an unsigned char buffer */ +unsigned decompress(std::vector& out, const unsigned char* in, size_t insize, + const LodePNGDecompressSettings& settings = lodepng_default_decompress_settings); + +/* Zlib-decompress an std::vector */ +unsigned decompress(std::vector& out, const std::vector& in, + const LodePNGDecompressSettings& settings = lodepng_default_decompress_settings); +#endif /* LODEPNG_COMPILE_DECODER */ + +#ifdef LODEPNG_COMPILE_ENCODER +/* Zlib-compress an unsigned char buffer */ +unsigned compress(std::vector& out, const unsigned char* in, size_t insize, + const LodePNGCompressSettings& settings = lodepng_default_compress_settings); + +/* Zlib-compress an std::vector */ +unsigned compress(std::vector& out, const std::vector& in, + const LodePNGCompressSettings& settings = lodepng_default_compress_settings); +#endif /* LODEPNG_COMPILE_ENCODER */ +#endif /* LODEPNG_COMPILE_ZLIB */ +} /* namespace lodepng */ +#endif /*LODEPNG_COMPILE_CPP*/ + +/* +TODO: +[.] test if there are no memory leaks or security exploits - done a lot but needs to be checked often +[.] check compatibility with various compilers - done but needs to be redone for every newer version +[X] converting color to 16-bit per channel types +[X] support color profile chunk types (but never let them touch RGB values by default) +[ ] support all public PNG chunk types (almost done except sBIT, sPLT and hIST) +[ ] make sure encoder generates no chunks with size > (2^31)-1 +[ ] partial decoding (stream processing) +[X] let the "isFullyOpaque" function check color keys and transparent palettes too +[X] better name for the variables "codes", "codesD", "codelengthcodes", "clcl" and "lldl" +[ ] allow treating some errors like warnings, when image is recoverable (e.g. 69, 57, 58) +[ ] make warnings like: oob palette, checksum fail, data after iend, wrong/unknown crit chunk, no null terminator in text, ... +[ ] error messages with line numbers (and version) +[ ] errors in state instead of as return code? +[ ] new errors/warnings like suspiciously big decompressed ztxt or iccp chunk +[ ] let the C++ wrapper catch exceptions coming from the standard library and return LodePNG error codes +[ ] allow user to provide custom color conversion functions, e.g. for premultiplied alpha, padding bits or not, ... +[ ] allow user to give data (void*) to custom allocator +[X] provide alternatives for C library functions not present on some platforms (memcpy, ...) +*/ + +#endif /*LODEPNG_H inclusion guard*/ + +/* +LodePNG Documentation +--------------------- + +0. table of contents +-------------------- + + 1. about + 1.1. supported features + 1.2. features not supported + 2. C and C++ version + 3. security + 4. decoding + 5. encoding + 6. color conversions + 6.1. PNG color types + 6.2. color conversions + 6.3. padding bits + 6.4. A note about 16-bits per channel and endianness + 7. error values + 8. chunks and PNG editing + 9. compiler support + 10. examples + 10.1. decoder C++ example + 10.2. decoder C example + 11. state settings reference + 12. changes + 13. contact information + + +1. about +-------- + +PNG is a file format to store raster images losslessly with good compression, +supporting different color types and alpha channel. + +LodePNG is a PNG codec according to the Portable Network Graphics (PNG) +Specification (Second Edition) - W3C Recommendation 10 November 2003. + +The specifications used are: + +*) Portable Network Graphics (PNG) Specification (Second Edition): + http://www.w3.org/TR/2003/REC-PNG-20031110 +*) RFC 1950 ZLIB Compressed Data Format version 3.3: + http://www.gzip.org/zlib/rfc-zlib.html +*) RFC 1951 DEFLATE Compressed Data Format Specification ver 1.3: + http://www.gzip.org/zlib/rfc-deflate.html + +The most recent version of LodePNG can currently be found at +http://lodev.org/lodepng/ + +LodePNG works both in C (ISO C90) and C++, with a C++ wrapper that adds +extra functionality. + +LodePNG exists out of two files: +-lodepng.h: the header file for both C and C++ +-lodepng.c(pp): give it the name lodepng.c or lodepng.cpp (or .cc) depending on your usage + +If you want to start using LodePNG right away without reading this doc, get the +examples from the LodePNG website to see how to use it in code, or check the +smaller examples in chapter 13 here. + +LodePNG is simple but only supports the basic requirements. To achieve +simplicity, the following design choices were made: There are no dependencies +on any external library. There are functions to decode and encode a PNG with +a single function call, and extended versions of these functions taking a +LodePNGState struct allowing to specify or get more information. By default +the colors of the raw image are always RGB or RGBA, no matter what color type +the PNG file uses. To read and write files, there are simple functions to +convert the files to/from buffers in memory. + +This all makes LodePNG suitable for loading textures in games, demos and small +programs, ... It's less suitable for full fledged image editors, loading PNGs +over network (it requires all the image data to be available before decoding can +begin), life-critical systems, ... + +1.1. supported features +----------------------- + +The following features are supported by the decoder: + +*) decoding of PNGs with any color type, bit depth and interlace mode, to a 24- or 32-bit color raw image, + or the same color type as the PNG +*) encoding of PNGs, from any raw image to 24- or 32-bit color, or the same color type as the raw image +*) Adam7 interlace and deinterlace for any color type +*) loading the image from harddisk or decoding it from a buffer from other sources than harddisk +*) support for alpha channels, including RGBA color model, translucent palettes and color keying +*) zlib decompression (inflate) +*) zlib compression (deflate) +*) CRC32 and ADLER32 checksums +*) colorimetric color profile conversions: currently experimentally available in lodepng_util.cpp only, + plus alternatively ability to pass on chroma/gamma/ICC profile information to other color management system. +*) handling of unknown chunks, allowing making a PNG editor that stores custom and unknown chunks. +*) the following chunks are supported by both encoder and decoder: + IHDR: header information + PLTE: color palette + IDAT: pixel data + IEND: the final chunk + tRNS: transparency for palettized images + tEXt: textual information + zTXt: compressed textual information + iTXt: international textual information + bKGD: suggested background color + pHYs: physical dimensions + tIME: modification time + cHRM: RGB chromaticities + gAMA: RGB gamma correction + iCCP: ICC color profile + sRGB: rendering intent + +1.2. features not supported +--------------------------- + +The following features are _not_ supported: + +*) some features needed to make a conformant PNG-Editor might be still missing. +*) partial loading/stream processing. All data must be available and is processed in one call. +*) The following public chunks are not (yet) supported but treated as unknown chunks by LodePNG: + sBIT + hIST + sPLT + + +2. C and C++ version +-------------------- + +The C version uses buffers allocated with alloc that you need to free() +yourself. You need to use init and cleanup functions for each struct whenever +using a struct from the C version to avoid exploits and memory leaks. + +The C++ version has extra functions with std::vectors in the interface and the +lodepng::State class which is a LodePNGState with constructor and destructor. + +These files work without modification for both C and C++ compilers because all +the additional C++ code is in "#ifdef __cplusplus" blocks that make C-compilers +ignore it, and the C code is made to compile both with strict ISO C90 and C++. + +To use the C++ version, you need to rename the source file to lodepng.cpp +(instead of lodepng.c), and compile it with a C++ compiler. + +To use the C version, you need to rename the source file to lodepng.c (instead +of lodepng.cpp), and compile it with a C compiler. + + +3. Security +----------- + +Even if carefully designed, it's always possible that LodePNG contains possible +exploits. If you discover one, please let me know, and it will be fixed. + +When using LodePNG, care has to be taken with the C version of LodePNG, as well +as the C-style structs when working with C++. The following conventions are used +for all C-style structs: + +-if a struct has a corresponding init function, always call the init function when making a new one +-if a struct has a corresponding cleanup function, call it before the struct disappears to avoid memory leaks +-if a struct has a corresponding copy function, use the copy function instead of "=". + The destination must also be inited already. + + +4. Decoding +----------- + +Decoding converts a PNG compressed image to a raw pixel buffer. + +Most documentation on using the decoder is at its declarations in the header +above. For C, simple decoding can be done with functions such as +lodepng_decode32, and more advanced decoding can be done with the struct +LodePNGState and lodepng_decode. For C++, all decoding can be done with the +various lodepng::decode functions, and lodepng::State can be used for advanced +features. + +When using the LodePNGState, it uses the following fields for decoding: +*) LodePNGInfo info_png: it stores extra information about the PNG (the input) in here +*) LodePNGColorMode info_raw: here you can say what color mode of the raw image (the output) you want to get +*) LodePNGDecoderSettings decoder: you can specify a few extra settings for the decoder to use + +LodePNGInfo info_png +-------------------- + +After decoding, this contains extra information of the PNG image, except the actual +pixels, width and height because these are already gotten directly from the decoder +functions. + +It contains for example the original color type of the PNG image, text comments, +suggested background color, etc... More details about the LodePNGInfo struct are +at its declaration documentation. + +LodePNGColorMode info_raw +------------------------- + +When decoding, here you can specify which color type you want +the resulting raw image to be. If this is different from the colortype of the +PNG, then the decoder will automatically convert the result. This conversion +always works, except if you want it to convert a color PNG to grayscale or to +a palette with missing colors. + +By default, 32-bit color is used for the result. + +LodePNGDecoderSettings decoder +------------------------------ + +The settings can be used to ignore the errors created by invalid CRC and Adler32 +chunks, and to disable the decoding of tEXt chunks. + +There's also a setting color_convert, true by default. If false, no conversion +is done, the resulting data will be as it was in the PNG (after decompression) +and you'll have to puzzle the colors of the pixels together yourself using the +color type information in the LodePNGInfo. + + +5. Encoding +----------- + +Encoding converts a raw pixel buffer to a PNG compressed image. + +Most documentation on using the encoder is at its declarations in the header +above. For C, simple encoding can be done with functions such as +lodepng_encode32, and more advanced decoding can be done with the struct +LodePNGState and lodepng_encode. For C++, all encoding can be done with the +various lodepng::encode functions, and lodepng::State can be used for advanced +features. + +Like the decoder, the encoder can also give errors. However it gives less errors +since the encoder input is trusted, the decoder input (a PNG image that could +be forged by anyone) is not trusted. + +When using the LodePNGState, it uses the following fields for encoding: +*) LodePNGInfo info_png: here you specify how you want the PNG (the output) to be. +*) LodePNGColorMode info_raw: here you say what color type of the raw image (the input) has +*) LodePNGEncoderSettings encoder: you can specify a few settings for the encoder to use + +LodePNGInfo info_png +-------------------- + +When encoding, you use this the opposite way as when decoding: for encoding, +you fill in the values you want the PNG to have before encoding. By default it's +not needed to specify a color type for the PNG since it's automatically chosen, +but it's possible to choose it yourself given the right settings. + +The encoder will not always exactly match the LodePNGInfo struct you give, +it tries as close as possible. Some things are ignored by the encoder. The +encoder uses, for example, the following settings from it when applicable: +colortype and bitdepth, text chunks, time chunk, the color key, the palette, the +background color, the interlace method, unknown chunks, ... + +When encoding to a PNG with colortype 3, the encoder will generate a PLTE chunk. +If the palette contains any colors for which the alpha channel is not 255 (so +there are translucent colors in the palette), it'll add a tRNS chunk. + +LodePNGColorMode info_raw +------------------------- + +You specify the color type of the raw image that you give to the input here, +including a possible transparent color key and palette you happen to be using in +your raw image data. + +By default, 32-bit color is assumed, meaning your input has to be in RGBA +format with 4 bytes (unsigned chars) per pixel. + +LodePNGEncoderSettings encoder +------------------------------ + +The following settings are supported (some are in sub-structs): +*) auto_convert: when this option is enabled, the encoder will +automatically choose the smallest possible color mode (including color key) that +can encode the colors of all pixels without information loss. +*) btype: the block type for LZ77. 0 = uncompressed, 1 = fixed huffman tree, + 2 = dynamic huffman tree (best compression). Should be 2 for proper + compression. +*) use_lz77: whether or not to use LZ77 for compressed block types. Should be + true for proper compression. +*) windowsize: the window size used by the LZ77 encoder (1 - 32768). Has value + 2048 by default, but can be set to 32768 for better, but slow, compression. +*) force_palette: if colortype is 2 or 6, you can make the encoder write a PLTE + chunk if force_palette is true. This can used as suggested palette to convert + to by viewers that don't support more than 256 colors (if those still exist) +*) add_id: add text chunk "Encoder: LodePNG " to the image. +*) text_compression: default 1. If 1, it'll store texts as zTXt instead of tEXt chunks. + zTXt chunks use zlib compression on the text. This gives a smaller result on + large texts but a larger result on small texts (such as a single program name). + It's all tEXt or all zTXt though, there's no separate setting per text yet. + + +6. color conversions +-------------------- + +An important thing to note about LodePNG, is that the color type of the PNG, and +the color type of the raw image, are completely independent. By default, when +you decode a PNG, you get the result as a raw image in the color type you want, +no matter whether the PNG was encoded with a palette, grayscale or RGBA color. +And if you encode an image, by default LodePNG will automatically choose the PNG +color type that gives good compression based on the values of colors and amount +of colors in the image. It can be configured to let you control it instead as +well, though. + +To be able to do this, LodePNG does conversions from one color mode to another. +It can convert from almost any color type to any other color type, except the +following conversions: RGB to grayscale is not supported, and converting to a +palette when the palette doesn't have a required color is not supported. This is +not supported on purpose: this is information loss which requires a color +reduction algorithm that is beyond the scope of a PNG encoder (yes, RGB to gray +is easy, but there are multiple ways if you want to give some channels more +weight). + +By default, when decoding, you get the raw image in 32-bit RGBA or 24-bit RGB +color, no matter what color type the PNG has. And by default when encoding, +LodePNG automatically picks the best color model for the output PNG, and expects +the input image to be 32-bit RGBA or 24-bit RGB. So, unless you want to control +the color format of the images yourself, you can skip this chapter. + +6.1. PNG color types +-------------------- + +A PNG image can have many color types, ranging from 1-bit color to 64-bit color, +as well as palettized color modes. After the zlib decompression and unfiltering +in the PNG image is done, the raw pixel data will have that color type and thus +a certain amount of bits per pixel. If you want the output raw image after +decoding to have another color type, a conversion is done by LodePNG. + +The PNG specification gives the following color types: + +0: grayscale, bit depths 1, 2, 4, 8, 16 +2: RGB, bit depths 8 and 16 +3: palette, bit depths 1, 2, 4 and 8 +4: grayscale with alpha, bit depths 8 and 16 +6: RGBA, bit depths 8 and 16 + +Bit depth is the amount of bits per pixel per color channel. So the total amount +of bits per pixel is: amount of channels * bitdepth. + +6.2. color conversions +---------------------- + +As explained in the sections about the encoder and decoder, you can specify +color types and bit depths in info_png and info_raw to change the default +behaviour. + +If, when decoding, you want the raw image to be something else than the default, +you need to set the color type and bit depth you want in the LodePNGColorMode, +or the parameters colortype and bitdepth of the simple decoding function. + +If, when encoding, you use another color type than the default in the raw input +image, you need to specify its color type and bit depth in the LodePNGColorMode +of the raw image, or use the parameters colortype and bitdepth of the simple +encoding function. + +If, when encoding, you don't want LodePNG to choose the output PNG color type +but control it yourself, you need to set auto_convert in the encoder settings +to false, and specify the color type you want in the LodePNGInfo of the +encoder (including palette: it can generate a palette if auto_convert is true, +otherwise not). + +If the input and output color type differ (whether user chosen or auto chosen), +LodePNG will do a color conversion, which follows the rules below, and may +sometimes result in an error. + +To avoid some confusion: +-the decoder converts from PNG to raw image +-the encoder converts from raw image to PNG +-the colortype and bitdepth in LodePNGColorMode info_raw, are those of the raw image +-the colortype and bitdepth in the color field of LodePNGInfo info_png, are those of the PNG +-when encoding, the color type in LodePNGInfo is ignored if auto_convert + is enabled, it is automatically generated instead +-when decoding, the color type in LodePNGInfo is set by the decoder to that of the original + PNG image, but it can be ignored since the raw image has the color type you requested instead +-if the color type of the LodePNGColorMode and PNG image aren't the same, a conversion + between the color types is done if the color types are supported. If it is not + supported, an error is returned. If the types are the same, no conversion is done. +-even though some conversions aren't supported, LodePNG supports loading PNGs from any + colortype and saving PNGs to any colortype, sometimes it just requires preparing + the raw image correctly before encoding. +-both encoder and decoder use the same color converter. + +The function lodepng_convert does the color conversion. It is available in the +interface but normally isn't needed since the encoder and decoder already call +it. + +Non supported color conversions: +-color to grayscale when non-gray pixels are present: no error is thrown, but +the result will look ugly because only the red channel is taken (it assumes all +three channels are the same in this case so ignores green and blue). The reason +no error is given is to allow converting from three-channel grayscale images to +one-channel even if there are numerical imprecisions. +-anything to palette when the palette does not have an exact match for a from-color +in it: in this case an error is thrown + +Supported color conversions: +-anything to 8-bit RGB, 8-bit RGBA, 16-bit RGB, 16-bit RGBA +-any gray or gray+alpha, to gray or gray+alpha +-anything to a palette, as long as the palette has the requested colors in it +-removing alpha channel +-higher to smaller bitdepth, and vice versa + +If you want no color conversion to be done (e.g. for speed or control): +-In the encoder, you can make it save a PNG with any color type by giving the +raw color mode and LodePNGInfo the same color mode, and setting auto_convert to +false. +-In the decoder, you can make it store the pixel data in the same color type +as the PNG has, by setting the color_convert setting to false. Settings in +info_raw are then ignored. + +6.3. padding bits +----------------- + +In the PNG file format, if a less than 8-bit per pixel color type is used and the scanlines +have a bit amount that isn't a multiple of 8, then padding bits are used so that each +scanline starts at a fresh byte. But that is NOT true for the LodePNG raw input and output. +The raw input image you give to the encoder, and the raw output image you get from the decoder +will NOT have these padding bits, e.g. in the case of a 1-bit image with a width +of 7 pixels, the first pixel of the second scanline will the 8th bit of the first byte, +not the first bit of a new byte. + +6.4. A note about 16-bits per channel and endianness +---------------------------------------------------- + +LodePNG uses unsigned char arrays for 16-bit per channel colors too, just like +for any other color format. The 16-bit values are stored in big endian (most +significant byte first) in these arrays. This is the opposite order of the +little endian used by x86 CPU's. + +LodePNG always uses big endian because the PNG file format does so internally. +Conversions to other formats than PNG uses internally are not supported by +LodePNG on purpose, there are myriads of formats, including endianness of 16-bit +colors, the order in which you store R, G, B and A, and so on. Supporting and +converting to/from all that is outside the scope of LodePNG. + +This may mean that, depending on your use case, you may want to convert the big +endian output of LodePNG to little endian with a for loop. This is certainly not +always needed, many applications and libraries support big endian 16-bit colors +anyway, but it means you cannot simply cast the unsigned char* buffer to an +unsigned short* buffer on x86 CPUs. + + +7. error values +--------------- + +All functions in LodePNG that return an error code, return 0 if everything went +OK, or a non-zero code if there was an error. + +The meaning of the LodePNG error values can be retrieved with the function +lodepng_error_text: given the numerical error code, it returns a description +of the error in English as a string. + +Check the implementation of lodepng_error_text to see the meaning of each code. + +It is not recommended to use the numerical values to programmatically make +different decisions based on error types as the numbers are not guaranteed to +stay backwards compatible. They are for human consumption only. Programmatically +only 0 or non-0 matter. + + +8. chunks and PNG editing +------------------------- + +If you want to add extra chunks to a PNG you encode, or use LodePNG for a PNG +editor that should follow the rules about handling of unknown chunks, or if your +program is able to read other types of chunks than the ones handled by LodePNG, +then that's possible with the chunk functions of LodePNG. + +A PNG chunk has the following layout: + +4 bytes length +4 bytes type name +length bytes data +4 bytes CRC + +8.1. iterating through chunks +----------------------------- + +If you have a buffer containing the PNG image data, then the first chunk (the +IHDR chunk) starts at byte number 8 of that buffer. The first 8 bytes are the +signature of the PNG and are not part of a chunk. But if you start at byte 8 +then you have a chunk, and can check the following things of it. + +NOTE: none of these functions check for memory buffer boundaries. To avoid +exploits, always make sure the buffer contains all the data of the chunks. +When using lodepng_chunk_next, make sure the returned value is within the +allocated memory. + +unsigned lodepng_chunk_length(const unsigned char* chunk): + +Get the length of the chunk's data. The total chunk length is this length + 12. + +void lodepng_chunk_type(char type[5], const unsigned char* chunk): +unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type): + +Get the type of the chunk or compare if it's a certain type + +unsigned char lodepng_chunk_critical(const unsigned char* chunk): +unsigned char lodepng_chunk_private(const unsigned char* chunk): +unsigned char lodepng_chunk_safetocopy(const unsigned char* chunk): + +Check if the chunk is critical in the PNG standard (only IHDR, PLTE, IDAT and IEND are). +Check if the chunk is private (public chunks are part of the standard, private ones not). +Check if the chunk is safe to copy. If it's not, then, when modifying data in a critical +chunk, unsafe to copy chunks of the old image may NOT be saved in the new one if your +program doesn't handle that type of unknown chunk. + +unsigned char* lodepng_chunk_data(unsigned char* chunk): +const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk): + +Get a pointer to the start of the data of the chunk. + +unsigned lodepng_chunk_check_crc(const unsigned char* chunk): +void lodepng_chunk_generate_crc(unsigned char* chunk): + +Check if the crc is correct or generate a correct one. + +unsigned char* lodepng_chunk_next(unsigned char* chunk): +const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk): + +Iterate to the next chunk. This works if you have a buffer with consecutive chunks. Note that these +functions do no boundary checking of the allocated data whatsoever, so make sure there is enough +data available in the buffer to be able to go to the next chunk. + +unsigned lodepng_chunk_append(unsigned char** out, size_t* outsize, const unsigned char* chunk): +unsigned lodepng_chunk_create(unsigned char** out, size_t* outsize, unsigned length, + const char* type, const unsigned char* data): + +These functions are used to create new chunks that are appended to the data in *out that has +length *outsize. The append function appends an existing chunk to the new data. The create +function creates a new chunk with the given parameters and appends it. Type is the 4-letter +name of the chunk. + +8.2. chunks in info_png +----------------------- + +The LodePNGInfo struct contains fields with the unknown chunk in it. It has 3 +buffers (each with size) to contain 3 types of unknown chunks: +the ones that come before the PLTE chunk, the ones that come between the PLTE +and the IDAT chunks, and the ones that come after the IDAT chunks. +It's necessary to make the distinction between these 3 cases because the PNG +standard forces to keep the ordering of unknown chunks compared to the critical +chunks, but does not force any other ordering rules. + +info_png.unknown_chunks_data[0] is the chunks before PLTE +info_png.unknown_chunks_data[1] is the chunks after PLTE, before IDAT +info_png.unknown_chunks_data[2] is the chunks after IDAT + +The chunks in these 3 buffers can be iterated through and read by using the same +way described in the previous subchapter. + +When using the decoder to decode a PNG, you can make it store all unknown chunks +if you set the option settings.remember_unknown_chunks to 1. By default, this +option is off (0). + +The encoder will always encode unknown chunks that are stored in the info_png. +If you need it to add a particular chunk that isn't known by LodePNG, you can +use lodepng_chunk_append or lodepng_chunk_create to the chunk data in +info_png.unknown_chunks_data[x]. + +Chunks that are known by LodePNG should not be added in that way. E.g. to make +LodePNG add a bKGD chunk, set background_defined to true and add the correct +parameters there instead. + + +9. compiler support +------------------- + +No libraries other than the current standard C library are needed to compile +LodePNG. For the C++ version, only the standard C++ library is needed on top. +Add the files lodepng.c(pp) and lodepng.h to your project, include +lodepng.h where needed, and your program can read/write PNG files. + +It is compatible with C90 and up, and C++03 and up. + +If performance is important, use optimization when compiling! For both the +encoder and decoder, this makes a large difference. + +Make sure that LodePNG is compiled with the same compiler of the same version +and with the same settings as the rest of the program, or the interfaces with +std::vectors and std::strings in C++ can be incompatible. + +CHAR_BITS must be 8 or higher, because LodePNG uses unsigned chars for octets. + +*) gcc and g++ + +LodePNG is developed in gcc so this compiler is natively supported. It gives no +warnings with compiler options "-Wall -Wextra -pedantic -ansi", with gcc and g++ +version 4.7.1 on Linux, 32-bit and 64-bit. + +*) Clang + +Fully supported and warning-free. + +*) Mingw + +The Mingw compiler (a port of gcc for Windows) should be fully supported by +LodePNG. + +*) Visual Studio and Visual C++ Express Edition + +LodePNG should be warning-free with warning level W4. Two warnings were disabled +with pragmas though: warning 4244 about implicit conversions, and warning 4996 +where it wants to use a non-standard function fopen_s instead of the standard C +fopen. + +Visual Studio may want "stdafx.h" files to be included in each source file and +give an error "unexpected end of file while looking for precompiled header". +This is not standard C++ and will not be added to the stock LodePNG. You can +disable it for lodepng.cpp only by right clicking it, Properties, C/C++, +Precompiled Headers, and set it to Not Using Precompiled Headers there. + +NOTE: Modern versions of VS should be fully supported, but old versions, e.g. +VS6, are not guaranteed to work. + +*) Compilers on Macintosh + +LodePNG has been reported to work both with gcc and LLVM for Macintosh, both for +C and C++. + +*) Other Compilers + +If you encounter problems on any compilers, feel free to let me know and I may +try to fix it if the compiler is modern and standards compliant. + + +10. examples +------------ + +This decoder example shows the most basic usage of LodePNG. More complex +examples can be found on the LodePNG website. + +10.1. decoder C++ example +------------------------- + +#include "lodepng.h" +#include + +int main(int argc, char *argv[]) { + const char* filename = argc > 1 ? argv[1] : "test.png"; + + //load and decode + std::vector image; + unsigned width, height; + unsigned error = lodepng::decode(image, width, height, filename); + + //if there's an error, display it + if(error) std::cout << "decoder error " << error << ": " << lodepng_error_text(error) << std::endl; + + //the pixels are now in the vector "image", 4 bytes per pixel, ordered RGBARGBA..., use it as texture, draw it, ... +} + +10.2. decoder C example +----------------------- + +#include "lodepng.h" + +int main(int argc, char *argv[]) { + unsigned error; + unsigned char* image; + size_t width, height; + const char* filename = argc > 1 ? argv[1] : "test.png"; + + error = lodepng_decode32_file(&image, &width, &height, filename); + + if(error) printf("decoder error %u: %s\n", error, lodepng_error_text(error)); + + / * use image here * / + + free(image); + return 0; +} + +11. state settings reference +---------------------------- + +A quick reference of some settings to set on the LodePNGState + +For decoding: + +state.decoder.zlibsettings.ignore_adler32: ignore ADLER32 checksums +state.decoder.zlibsettings.custom_...: use custom inflate function +state.decoder.ignore_crc: ignore CRC checksums +state.decoder.ignore_critical: ignore unknown critical chunks +state.decoder.ignore_end: ignore missing IEND chunk. May fail if this corruption causes other errors +state.decoder.color_convert: convert internal PNG color to chosen one +state.decoder.read_text_chunks: whether to read in text metadata chunks +state.decoder.remember_unknown_chunks: whether to read in unknown chunks +state.info_raw.colortype: desired color type for decoded image +state.info_raw.bitdepth: desired bit depth for decoded image +state.info_raw....: more color settings, see struct LodePNGColorMode +state.info_png....: no settings for decoder but ouput, see struct LodePNGInfo + +For encoding: + +state.encoder.zlibsettings.btype: disable compression by setting it to 0 +state.encoder.zlibsettings.use_lz77: use LZ77 in compression +state.encoder.zlibsettings.windowsize: tweak LZ77 windowsize +state.encoder.zlibsettings.minmatch: tweak min LZ77 length to match +state.encoder.zlibsettings.nicematch: tweak LZ77 match where to stop searching +state.encoder.zlibsettings.lazymatching: try one more LZ77 matching +state.encoder.zlibsettings.custom_...: use custom deflate function +state.encoder.auto_convert: choose optimal PNG color type, if 0 uses info_png +state.encoder.filter_palette_zero: PNG filter strategy for palette +state.encoder.filter_strategy: PNG filter strategy to encode with +state.encoder.force_palette: add palette even if not encoding to one +state.encoder.add_id: add LodePNG identifier and version as a text chunk +state.encoder.text_compression: use compressed text chunks for metadata +state.info_raw.colortype: color type of raw input image you provide +state.info_raw.bitdepth: bit depth of raw input image you provide +state.info_raw: more color settings, see struct LodePNGColorMode +state.info_png.color.colortype: desired color type if auto_convert is false +state.info_png.color.bitdepth: desired bit depth if auto_convert is false +state.info_png.color....: more color settings, see struct LodePNGColorMode +state.info_png....: more PNG related settings, see struct LodePNGInfo + + +12. changes +----------- + +The version number of LodePNG is the date of the change given in the format +yyyymmdd. + +Some changes aren't backwards compatible. Those are indicated with a (!) +symbol. + +Not all changes are listed here, the commit history in github lists more: +https://github.com/lvandeve/lodepng + +*) 17 okt 2020: prevent decoding too large text/icc chunks by default. +*) 06 mar 2020: simplified some of the dynamic memory allocations. +*) 12 jan 2020: (!) added 'end' argument to lodepng_chunk_next to allow correct + overflow checks. +*) 14 aug 2019: around 25% faster decoding thanks to huffman lookup tables. +*) 15 jun 2019: (!) auto_choose_color API changed (for bugfix: don't use palette + if gray ICC profile) and non-ICC LodePNGColorProfile renamed to + LodePNGColorStats. +*) 30 dec 2018: code style changes only: removed newlines before opening braces. +*) 10 sep 2018: added way to inspect metadata chunks without full decoding. +*) 19 aug 2018: (!) fixed color mode bKGD is encoded with and made it use + palette index in case of palette. +*) 10 aug 2018: (!) added support for gAMA, cHRM, sRGB and iCCP chunks. This + change is backwards compatible unless you relied on unknown_chunks for those. +*) 11 jun 2018: less restrictive check for pixel size integer overflow +*) 14 jan 2018: allow optionally ignoring a few more recoverable errors +*) 17 sep 2017: fix memory leak for some encoder input error cases +*) 27 nov 2016: grey+alpha auto color model detection bugfix +*) 18 apr 2016: Changed qsort to custom stable sort (for platforms w/o qsort). +*) 09 apr 2016: Fixed colorkey usage detection, and better file loading (within + the limits of pure C90). +*) 08 dec 2015: Made load_file function return error if file can't be opened. +*) 24 okt 2015: Bugfix with decoding to palette output. +*) 18 apr 2015: Boundary PM instead of just package-merge for faster encoding. +*) 24 aug 2014: Moved to github +*) 23 aug 2014: Reduced needless memory usage of decoder. +*) 28 jun 2014: Removed fix_png setting, always support palette OOB for + simplicity. Made ColorProfile public. +*) 09 jun 2014: Faster encoder by fixing hash bug and more zeros optimization. +*) 22 dec 2013: Power of two windowsize required for optimization. +*) 15 apr 2013: Fixed bug with LAC_ALPHA and color key. +*) 25 mar 2013: Added an optional feature to ignore some PNG errors (fix_png). +*) 11 mar 2013: (!) Bugfix with custom free. Changed from "my" to "lodepng_" + prefix for the custom allocators and made it possible with a new #define to + use custom ones in your project without needing to change lodepng's code. +*) 28 jan 2013: Bugfix with color key. +*) 27 okt 2012: Tweaks in text chunk keyword length error handling. +*) 8 okt 2012: (!) Added new filter strategy (entropy) and new auto color mode. + (no palette). Better deflate tree encoding. New compression tweak settings. + Faster color conversions while decoding. Some internal cleanups. +*) 23 sep 2012: Reduced warnings in Visual Studio a little bit. +*) 1 sep 2012: (!) Removed #define's for giving custom (de)compression functions + and made it work with function pointers instead. +*) 23 jun 2012: Added more filter strategies. Made it easier to use custom alloc + and free functions and toggle #defines from compiler flags. Small fixes. +*) 6 may 2012: (!) Made plugging in custom zlib/deflate functions more flexible. +*) 22 apr 2012: (!) Made interface more consistent, renaming a lot. Removed + redundant C++ codec classes. Reduced amount of structs. Everything changed, + but it is cleaner now imho and functionality remains the same. Also fixed + several bugs and shrunk the implementation code. Made new samples. +*) 6 nov 2011: (!) By default, the encoder now automatically chooses the best + PNG color model and bit depth, based on the amount and type of colors of the + raw image. For this, autoLeaveOutAlphaChannel replaced by auto_choose_color. +*) 9 okt 2011: simpler hash chain implementation for the encoder. +*) 8 sep 2011: lz77 encoder lazy matching instead of greedy matching. +*) 23 aug 2011: tweaked the zlib compression parameters after benchmarking. + A bug with the PNG filtertype heuristic was fixed, so that it chooses much + better ones (it's quite significant). A setting to do an experimental, slow, + brute force search for PNG filter types is added. +*) 17 aug 2011: (!) changed some C zlib related function names. +*) 16 aug 2011: made the code less wide (max 120 characters per line). +*) 17 apr 2011: code cleanup. Bugfixes. Convert low to 16-bit per sample colors. +*) 21 feb 2011: fixed compiling for C90. Fixed compiling with sections disabled. +*) 11 dec 2010: encoding is made faster, based on suggestion by Peter Eastman + to optimize long sequences of zeros. +*) 13 nov 2010: added LodePNG_InfoColor_hasPaletteAlpha and + LodePNG_InfoColor_canHaveAlpha functions for convenience. +*) 7 nov 2010: added LodePNG_error_text function to get error code description. +*) 30 okt 2010: made decoding slightly faster +*) 26 okt 2010: (!) changed some C function and struct names (more consistent). + Reorganized the documentation and the declaration order in the header. +*) 08 aug 2010: only changed some comments and external samples. +*) 05 jul 2010: fixed bug thanks to warnings in the new gcc version. +*) 14 mar 2010: fixed bug where too much memory was allocated for char buffers. +*) 02 sep 2008: fixed bug where it could create empty tree that linux apps could + read by ignoring the problem but windows apps couldn't. +*) 06 jun 2008: added more error checks for out of memory cases. +*) 26 apr 2008: added a few more checks here and there to ensure more safety. +*) 06 mar 2008: crash with encoding of strings fixed +*) 02 feb 2008: support for international text chunks added (iTXt) +*) 23 jan 2008: small cleanups, and #defines to divide code in sections +*) 20 jan 2008: support for unknown chunks allowing using LodePNG for an editor. +*) 18 jan 2008: support for tIME and pHYs chunks added to encoder and decoder. +*) 17 jan 2008: ability to encode and decode compressed zTXt chunks added + Also various fixes, such as in the deflate and the padding bits code. +*) 13 jan 2008: Added ability to encode Adam7-interlaced images. Improved + filtering code of encoder. +*) 07 jan 2008: (!) changed LodePNG to use ISO C90 instead of C++. A + C++ wrapper around this provides an interface almost identical to before. + Having LodePNG be pure ISO C90 makes it more portable. The C and C++ code + are together in these files but it works both for C and C++ compilers. +*) 29 dec 2007: (!) changed most integer types to unsigned int + other tweaks +*) 30 aug 2007: bug fixed which makes this Borland C++ compatible +*) 09 aug 2007: some VS2005 warnings removed again +*) 21 jul 2007: deflate code placed in new namespace separate from zlib code +*) 08 jun 2007: fixed bug with 2- and 4-bit color, and small interlaced images +*) 04 jun 2007: improved support for Visual Studio 2005: crash with accessing + invalid std::vector element [0] fixed, and level 3 and 4 warnings removed +*) 02 jun 2007: made the encoder add a tag with version by default +*) 27 may 2007: zlib and png code separated (but still in the same file), + simple encoder/decoder functions added for more simple usage cases +*) 19 may 2007: minor fixes, some code cleaning, new error added (error 69), + moved some examples from here to lodepng_examples.cpp +*) 12 may 2007: palette decoding bug fixed +*) 24 apr 2007: changed the license from BSD to the zlib license +*) 11 mar 2007: very simple addition: ability to encode bKGD chunks. +*) 04 mar 2007: (!) tEXt chunk related fixes, and support for encoding + palettized PNG images. Plus little interface change with palette and texts. +*) 03 mar 2007: Made it encode dynamic Huffman shorter with repeat codes. + Fixed a bug where the end code of a block had length 0 in the Huffman tree. +*) 26 feb 2007: Huffman compression with dynamic trees (BTYPE 2) now implemented + and supported by the encoder, resulting in smaller PNGs at the output. +*) 27 jan 2007: Made the Adler-32 test faster so that a timewaste is gone. +*) 24 jan 2007: gave encoder an error interface. Added color conversion from any + greyscale type to 8-bit greyscale with or without alpha. +*) 21 jan 2007: (!) Totally changed the interface. It allows more color types + to convert to and is more uniform. See the manual for how it works now. +*) 07 jan 2007: Some cleanup & fixes, and a few changes over the last days: + encode/decode custom tEXt chunks, separate classes for zlib & deflate, and + at last made the decoder give errors for incorrect Adler32 or Crc. +*) 01 jan 2007: Fixed bug with encoding PNGs with less than 8 bits per channel. +*) 29 dec 2006: Added support for encoding images without alpha channel, and + cleaned out code as well as making certain parts faster. +*) 28 dec 2006: Added "Settings" to the encoder. +*) 26 dec 2006: The encoder now does LZ77 encoding and produces much smaller files now. + Removed some code duplication in the decoder. Fixed little bug in an example. +*) 09 dec 2006: (!) Placed output parameters of public functions as first parameter. + Fixed a bug of the decoder with 16-bit per color. +*) 15 okt 2006: Changed documentation structure +*) 09 okt 2006: Encoder class added. It encodes a valid PNG image from the + given image buffer, however for now it's not compressed. +*) 08 sep 2006: (!) Changed to interface with a Decoder class +*) 30 jul 2006: (!) LodePNG_InfoPng , width and height are now retrieved in different + way. Renamed decodePNG to decodePNGGeneric. +*) 29 jul 2006: (!) Changed the interface: image info is now returned as a + struct of type LodePNG::LodePNG_Info, instead of a vector, which was a bit clumsy. +*) 28 jul 2006: Cleaned the code and added new error checks. + Corrected terminology "deflate" into "inflate". +*) 23 jun 2006: Added SDL example in the documentation in the header, this + example allows easy debugging by displaying the PNG and its transparency. +*) 22 jun 2006: (!) Changed way to obtain error value. Added + loadFile function for convenience. Made decodePNG32 faster. +*) 21 jun 2006: (!) Changed type of info vector to unsigned. + Changed position of palette in info vector. Fixed an important bug that + happened on PNGs with an uncompressed block. +*) 16 jun 2006: Internally changed unsigned into unsigned where + needed, and performed some optimizations. +*) 07 jun 2006: (!) Renamed functions to decodePNG and placed them + in LodePNG namespace. Changed the order of the parameters. Rewrote the + documentation in the header. Renamed files to lodepng.cpp and lodepng.h +*) 22 apr 2006: Optimized and improved some code +*) 07 sep 2005: (!) Changed to std::vector interface +*) 12 aug 2005: Initial release (C++, decoder only) + + +13. contact information +----------------------- + +Feel free to contact me with suggestions, problems, comments, ... concerning +LodePNG. If you encounter a PNG image that doesn't work properly with this +decoder, feel free to send it and I'll use it to find and fix the problem. + +My email address is (puzzle the account and domain together with an @ symbol): +Domain: gmail dot com. +Account: lode dot vandevenne. + + +Copyright (c) 2005-2020 Lode Vandevenne +*/ diff --git a/depends/lua/CMakeLists.txt b/depends/lua/CMakeLists.txt new file mode 100644 index 0000000000..44b16e56cc --- /dev/null +++ b/depends/lua/CMakeLists.txt @@ -0,0 +1,112 @@ +project(lua CXX) +cmake_minimum_required(VERSION 3.21) + +set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -DLUA_USE_APICHECK") + +# Make bit32 library available (for things like bit32.extract()) +add_definitions(-DLUA_COMPAT_BITLIB) + +if(WIN32) + add_definitions(-D_CRT_SECURE_NO_DEPRECATE /wd4334) +else() + add_definitions(-DLUA_USE_POSIX -DLUA_USE_DLOPEN) + set(LIBS m dl) +endif() + +if(UNIX) + add_definitions(-DLINUX_BUILD) + if(DFHACK_BUILD_64) + set(CMAKE_C_FLAGS "-m64 -mno-avx") + else() + set(CMAKE_C_FLAGS "-m32") + endif() +endif() + +set(HDR_LIBLUA + include/lapi.h + include/lauxlib.h + include/lcode.h + include/lctype.h + include/ldebug.h + include/ldo.h + include/lfunc.h + include/lgc.h + include/llex.h + include/llimits.h + include/lmem.h + include/lobject.h + include/lopcodes.h + include/lparser.h + include/lstate.h + include/lstring.h + include/ltable.h + include/ltm.h + include/lua.h + include/luaconf.h + include/lualib.h + include/lundump.h + include/lvm.h + include/lzio.h +) +set_source_files_properties(${HDR_LIBLUA} PROPERTIES HEADER_FILE_ONLY TRUE) +include_directories(include) + +# Build Libraries +set(SRC_LIBLUA + src/lapi.c + src/lauxlib.c + src/lbaselib.c + src/lbitlib.c + src/lcode.c + src/lcorolib.c + src/lctype.c + src/ldblib.c + src/ldebug.c + src/ldo.c + src/ldump.c + src/lfunc.c + src/lgc.c + src/linit.c + src/liolib.c + src/llex.c + src/lmathlib.c + src/lmem.c + src/loadlib.c + src/lobject.c + src/lopcodes.c + src/loslib.c + src/lparser.c + src/lstate.c + src/lstring.c + src/lstrlib.c + src/ltable.c + src/ltablib.c + src/ltm.c + src/lundump.c + src/lutf8lib.c + src/lvm.c + src/lzio.c +) +# compile with C++ compiler +set_source_files_properties(${SRC_LIBLUA} PROPERTIES LANGUAGE CXX) +# append headers to sources to make them show up in MSVC GUI +list(APPEND SRC_LIBLUA ${HDR_LIBLUA}) + +add_library(lua SHARED ${SRC_LIBLUA}) +set_target_properties(lua PROPERTIES OUTPUT_NAME lua53) +target_link_libraries(lua ${LIBS}) +target_include_directories(lua INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include) + +if(MSVC) + # need no space to prevent /FI from being stripped: https://github.com/DFHack/dfhack/issues/1455 + target_compile_options(lua PRIVATE "/FIdfhack_llimits.h") +else() + target_compile_options(lua PRIVATE -include dfhack_llimits.h) + set_source_files_properties(src/lstring.c PROPERTIES COMPILE_FLAGS "-Wno-stringop-overflow") +endif() + +install(TARGETS lua + LIBRARY DESTINATION ${DFHACK_LIBRARY_DESTINATION} + RUNTIME DESTINATION ${DFHACK_LIBRARY_DESTINATION}) + +ide_folder(lua "Depends") diff --git a/depends/lua/COPYRIGHT b/depends/lua/COPYRIGHT new file mode 100644 index 0000000000..3a53e741e0 --- /dev/null +++ b/depends/lua/COPYRIGHT @@ -0,0 +1,34 @@ +Lua License +----------- + +Lua is licensed under the terms of the MIT license reproduced below. +This means that Lua is free software and can be used for both academic +and commercial purposes at absolutely no cost. + +For details and rationale, see http://www.lua.org/license.html . + +=============================================================================== + +Copyright (C) 1994-2008 Lua.org, PUC-Rio. + +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. + +=============================================================================== + +(end of COPYRIGHT) diff --git a/depends/lua/README b/depends/lua/README new file mode 100644 index 0000000000..83535f6ac7 --- /dev/null +++ b/depends/lua/README @@ -0,0 +1,7 @@ + +This is Lua 5.3.6, released on 14 Sep 2020. + +For installation instructions, license details, and +further information about Lua, see +https://www.lua.org/manual/5.3/readme.html + diff --git a/depends/lua/include/dfhack_llimits.h b/depends/lua/include/dfhack_llimits.h new file mode 100644 index 0000000000..73aa52ef0b --- /dev/null +++ b/depends/lua/include/dfhack_llimits.h @@ -0,0 +1,72 @@ +/** +Copyright © 2018 Pauli + +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 acknowledgment 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. + */ + +#pragma once + +#ifdef _MSC_VER +#include +#else +#include +#endif + +#include + +/*! \file dfhack_llimits.h + * dfhack specific lua porting header that overrides lua defaults for thread + * safety. + */ + +#ifdef _MSC_VER +typedef CRITICAL_SECTION mutex_t; +#else +typedef pthread_mutex_t mutex_t; +#endif + +struct lua_extra_state { + mutex_t* mutex; +}; + +#define luai_mutex(L) ((lua_extra_state*)lua_getextraspace(L))->mutex + +#ifdef _MSC_VER +#define luai_userstateopen(L) luai_mutex(L) = (mutex_t*)malloc(sizeof(mutex_t)); InitializeCriticalSection(luai_mutex(L)) +#define luai_userstateclose(L) lua_unlock(L); DeleteCriticalSection(luai_mutex(L)); free(luai_mutex(L)) +#define lua_lock(L) EnterCriticalSection(luai_mutex(L)) +#define lua_unlock(L) LeaveCriticalSection(luai_mutex(L)) +#else +#define luai_userstateopen(L) do { \ + luai_mutex(L) = (mutex_t*)malloc(sizeof(mutex_t)); \ + pthread_mutexattr_t attr; \ + pthread_mutexattr_init(&attr); \ + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); \ + pthread_mutex_init(luai_mutex(L), &attr); \ + pthread_mutexattr_destroy(&attr); \ + } while (0) +#define luai_userstateclose(L) do { \ + lua_unlock(L); \ + pthread_mutex_destroy(luai_mutex(L)); \ + free(luai_mutex(L)); \ + } while (0) +#define lua_lock(L) pthread_mutex_lock(luai_mutex(L)) +#define lua_unlock(L) pthread_mutex_unlock(luai_mutex(L)) +#endif diff --git a/depends/lua/include/lapi.h b/depends/lua/include/lapi.h new file mode 100644 index 0000000000..8e16ad53d9 --- /dev/null +++ b/depends/lua/include/lapi.h @@ -0,0 +1,24 @@ +/* +** $Id: lapi.h,v 2.9.1.1 2017/04/19 17:20:42 roberto Exp $ +** Auxiliary functions from Lua API +** See Copyright Notice in lua.h +*/ + +#ifndef lapi_h +#define lapi_h + + +#include "llimits.h" +#include "lstate.h" + +#define api_incr_top(L) {L->top++; api_check(L, L->top <= L->ci->top, \ + "stack overflow");} + +#define adjustresults(L,nres) \ + { if ((nres) == LUA_MULTRET && L->ci->top < L->top) L->ci->top = L->top; } + +#define api_checknelems(L,n) api_check(L, (n) < (L->top - L->ci->func), \ + "not enough elements in the stack") + + +#endif diff --git a/depends/lua/include/lauxlib.h b/depends/lua/include/lauxlib.h new file mode 100644 index 0000000000..9857d3a835 --- /dev/null +++ b/depends/lua/include/lauxlib.h @@ -0,0 +1,264 @@ +/* +** $Id: lauxlib.h,v 1.131.1.1 2017/04/19 17:20:42 roberto Exp $ +** Auxiliary functions for building Lua libraries +** See Copyright Notice in lua.h +*/ + + +#ifndef lauxlib_h +#define lauxlib_h + + +#include +#include + +#include "lua.h" + + + +/* extra error code for 'luaL_loadfilex' */ +#define LUA_ERRFILE (LUA_ERRERR+1) + + +/* key, in the registry, for table of loaded modules */ +#define LUA_LOADED_TABLE "_LOADED" + + +/* key, in the registry, for table of preloaded loaders */ +#define LUA_PRELOAD_TABLE "_PRELOAD" + + +typedef struct luaL_Reg { + const char *name; + lua_CFunction func; +} luaL_Reg; + + +#define LUAL_NUMSIZES (sizeof(lua_Integer)*16 + sizeof(lua_Number)) + +LUALIB_API void (luaL_checkversion_) (lua_State *L, lua_Number ver, size_t sz); +#define luaL_checkversion(L) \ + luaL_checkversion_(L, LUA_VERSION_NUM, LUAL_NUMSIZES) + +LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e); +LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e); +LUALIB_API const char *(luaL_tolstring) (lua_State *L, int idx, size_t *len); +LUALIB_API int (luaL_argerror) (lua_State *L, int arg, const char *extramsg); +LUALIB_API const char *(luaL_checklstring) (lua_State *L, int arg, + size_t *l); +LUALIB_API const char *(luaL_optlstring) (lua_State *L, int arg, + const char *def, size_t *l); +LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int arg); +LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int arg, lua_Number def); + +LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int arg); +LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int arg, + lua_Integer def); + +LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg); +LUALIB_API void (luaL_checktype) (lua_State *L, int arg, int t); +LUALIB_API void (luaL_checkany) (lua_State *L, int arg); + +LUALIB_API int (luaL_newmetatable) (lua_State *L, const char *tname); +LUALIB_API void (luaL_setmetatable) (lua_State *L, const char *tname); +LUALIB_API void *(luaL_testudata) (lua_State *L, int ud, const char *tname); +LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname); + +LUALIB_API void (luaL_where) (lua_State *L, int lvl); +LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...); + +LUALIB_API int (luaL_checkoption) (lua_State *L, int arg, const char *def, + const char *const lst[]); + +LUALIB_API int (luaL_fileresult) (lua_State *L, int stat, const char *fname); +LUALIB_API int (luaL_execresult) (lua_State *L, int stat); + +/* predefined references */ +#define LUA_NOREF (-2) +#define LUA_REFNIL (-1) + +LUALIB_API int (luaL_ref) (lua_State *L, int t); +LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref); + +LUALIB_API int (luaL_loadfilex) (lua_State *L, const char *filename, + const char *mode); + +#define luaL_loadfile(L,f) luaL_loadfilex(L,f,NULL) + +LUALIB_API int (luaL_loadbufferx) (lua_State *L, const char *buff, size_t sz, + const char *name, const char *mode); +LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s); + +LUALIB_API lua_State *(luaL_newstate) (void); + +LUALIB_API lua_Integer (luaL_len) (lua_State *L, int idx); + +LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p, + const char *r); + +LUALIB_API void (luaL_setfuncs) (lua_State *L, const luaL_Reg *l, int nup); + +LUALIB_API int (luaL_getsubtable) (lua_State *L, int idx, const char *fname); + +LUALIB_API void (luaL_traceback) (lua_State *L, lua_State *L1, + const char *msg, int level); + +LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname, + lua_CFunction openf, int glb); + +/* +** =============================================================== +** some useful macros +** =============================================================== +*/ + + +#define luaL_newlibtable(L,l) \ + lua_createtable(L, 0, sizeof(l)/sizeof((l)[0]) - 1) + +#define luaL_newlib(L,l) \ + (luaL_checkversion(L), luaL_newlibtable(L,l), luaL_setfuncs(L,l,0)) + +#define luaL_argcheck(L, cond,arg,extramsg) \ + ((void)((cond) || luaL_argerror(L, (arg), (extramsg)))) +#define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL)) +#define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL)) + +#define luaL_typename(L,i) lua_typename(L, lua_type(L,(i))) + +#define luaL_dofile(L, fn) \ + (luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0)) + +#define luaL_dostring(L, s) \ + (luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0)) + +#define luaL_getmetatable(L,n) (lua_getfield(L, LUA_REGISTRYINDEX, (n))) + +#define luaL_opt(L,f,n,d) (lua_isnoneornil(L,(n)) ? (d) : f(L,(n))) + +#define luaL_loadbuffer(L,s,sz,n) luaL_loadbufferx(L,s,sz,n,NULL) + + +/* +** {====================================================== +** Generic Buffer manipulation +** ======================================================= +*/ + +typedef struct luaL_Buffer { + char *b; /* buffer address */ + size_t size; /* buffer size */ + size_t n; /* number of characters in buffer */ + lua_State *L; + char initb[LUAL_BUFFERSIZE]; /* initial buffer */ +} luaL_Buffer; + + +#define luaL_addchar(B,c) \ + ((void)((B)->n < (B)->size || luaL_prepbuffsize((B), 1)), \ + ((B)->b[(B)->n++] = (c))) + +#define luaL_addsize(B,s) ((B)->n += (s)) + +LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B); +LUALIB_API char *(luaL_prepbuffsize) (luaL_Buffer *B, size_t sz); +LUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l); +LUALIB_API void (luaL_addstring) (luaL_Buffer *B, const char *s); +LUALIB_API void (luaL_addvalue) (luaL_Buffer *B); +LUALIB_API void (luaL_pushresult) (luaL_Buffer *B); +LUALIB_API void (luaL_pushresultsize) (luaL_Buffer *B, size_t sz); +LUALIB_API char *(luaL_buffinitsize) (lua_State *L, luaL_Buffer *B, size_t sz); + +#define luaL_prepbuffer(B) luaL_prepbuffsize(B, LUAL_BUFFERSIZE) + +/* }====================================================== */ + + + +/* +** {====================================================== +** File handles for IO library +** ======================================================= +*/ + +/* +** A file handle is a userdata with metatable 'LUA_FILEHANDLE' and +** initial structure 'luaL_Stream' (it may contain other fields +** after that initial structure). +*/ + +#define LUA_FILEHANDLE "FILE*" + + +typedef struct luaL_Stream { + FILE *f; /* stream (NULL for incompletely created streams) */ + lua_CFunction closef; /* to close stream (NULL for closed streams) */ +} luaL_Stream; + +/* }====================================================== */ + + + +/* compatibility with old module system */ +#if defined(LUA_COMPAT_MODULE) + +LUALIB_API void (luaL_pushmodule) (lua_State *L, const char *modname, + int sizehint); +LUALIB_API void (luaL_openlib) (lua_State *L, const char *libname, + const luaL_Reg *l, int nup); + +#define luaL_register(L,n,l) (luaL_openlib(L,(n),(l),0)) + +#endif + + +/* +** {================================================================== +** "Abstraction Layer" for basic report of messages and errors +** =================================================================== +*/ + +/* print a string */ +#if !defined(lua_writestring) +#define lua_writestring(s,l) fwrite((s), sizeof(char), (l), stdout) +#endif + +/* print a newline and flush the output */ +#if !defined(lua_writeline) +#define lua_writeline() (lua_writestring("\n", 1), fflush(stdout)) +#endif + +/* print an error message */ +#if !defined(lua_writestringerror) +#define lua_writestringerror(s,p) \ + (fprintf(stderr, (s), (p)), fflush(stderr)) +#endif + +/* }================================================================== */ + + +/* +** {============================================================ +** Compatibility with deprecated conversions +** ============================================================= +*/ +#if defined(LUA_COMPAT_APIINTCASTS) + +#define luaL_checkunsigned(L,a) ((lua_Unsigned)luaL_checkinteger(L,a)) +#define luaL_optunsigned(L,a,d) \ + ((lua_Unsigned)luaL_optinteger(L,a,(lua_Integer)(d))) + +#define luaL_checkint(L,n) ((int)luaL_checkinteger(L, (n))) +#define luaL_optint(L,n,d) ((int)luaL_optinteger(L, (n), (d))) + +#define luaL_checklong(L,n) ((long)luaL_checkinteger(L, (n))) +#define luaL_optlong(L,n,d) ((long)luaL_optinteger(L, (n), (d))) + +#endif +/* }============================================================ */ + + + +#endif + + diff --git a/depends/lua/include/lcode.h b/depends/lua/include/lcode.h new file mode 100644 index 0000000000..882dc9c156 --- /dev/null +++ b/depends/lua/include/lcode.h @@ -0,0 +1,88 @@ +/* +** $Id: lcode.h,v 1.64.1.1 2017/04/19 17:20:42 roberto Exp $ +** Code generator for Lua +** See Copyright Notice in lua.h +*/ + +#ifndef lcode_h +#define lcode_h + +#include "llex.h" +#include "lobject.h" +#include "lopcodes.h" +#include "lparser.h" + + +/* +** Marks the end of a patch list. It is an invalid value both as an absolute +** address, and as a list link (would link an element to itself). +*/ +#define NO_JUMP (-1) + + +/* +** grep "ORDER OPR" if you change these enums (ORDER OP) +*/ +typedef enum BinOpr { + OPR_ADD, OPR_SUB, OPR_MUL, OPR_MOD, OPR_POW, + OPR_DIV, + OPR_IDIV, + OPR_BAND, OPR_BOR, OPR_BXOR, + OPR_SHL, OPR_SHR, + OPR_CONCAT, + OPR_EQ, OPR_LT, OPR_LE, + OPR_NE, OPR_GT, OPR_GE, + OPR_AND, OPR_OR, + OPR_NOBINOPR +} BinOpr; + + +typedef enum UnOpr { OPR_MINUS, OPR_BNOT, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr; + + +/* get (pointer to) instruction of given 'expdesc' */ +#define getinstruction(fs,e) ((fs)->f->code[(e)->u.info]) + +#define luaK_codeAsBx(fs,o,A,sBx) luaK_codeABx(fs,o,A,(sBx)+MAXARG_sBx) + +#define luaK_setmultret(fs,e) luaK_setreturns(fs, e, LUA_MULTRET) + +#define luaK_jumpto(fs,t) luaK_patchlist(fs, luaK_jump(fs), t) + +LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx); +LUAI_FUNC int luaK_codeABC (FuncState *fs, OpCode o, int A, int B, int C); +LUAI_FUNC int luaK_codek (FuncState *fs, int reg, int k); +LUAI_FUNC void luaK_fixline (FuncState *fs, int line); +LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n); +LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n); +LUAI_FUNC void luaK_checkstack (FuncState *fs, int n); +LUAI_FUNC int luaK_stringK (FuncState *fs, TString *s); +LUAI_FUNC int luaK_intK (FuncState *fs, lua_Integer n); +LUAI_FUNC void luaK_dischargevars (FuncState *fs, expdesc *e); +LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e); +LUAI_FUNC void luaK_exp2anyregup (FuncState *fs, expdesc *e); +LUAI_FUNC void luaK_exp2nextreg (FuncState *fs, expdesc *e); +LUAI_FUNC void luaK_exp2val (FuncState *fs, expdesc *e); +LUAI_FUNC int luaK_exp2RK (FuncState *fs, expdesc *e); +LUAI_FUNC void luaK_self (FuncState *fs, expdesc *e, expdesc *key); +LUAI_FUNC void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k); +LUAI_FUNC void luaK_goiftrue (FuncState *fs, expdesc *e); +LUAI_FUNC void luaK_goiffalse (FuncState *fs, expdesc *e); +LUAI_FUNC void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e); +LUAI_FUNC void luaK_setreturns (FuncState *fs, expdesc *e, int nresults); +LUAI_FUNC void luaK_setoneret (FuncState *fs, expdesc *e); +LUAI_FUNC int luaK_jump (FuncState *fs); +LUAI_FUNC void luaK_ret (FuncState *fs, int first, int nret); +LUAI_FUNC void luaK_patchlist (FuncState *fs, int list, int target); +LUAI_FUNC void luaK_patchtohere (FuncState *fs, int list); +LUAI_FUNC void luaK_patchclose (FuncState *fs, int list, int level); +LUAI_FUNC void luaK_concat (FuncState *fs, int *l1, int l2); +LUAI_FUNC int luaK_getlabel (FuncState *fs); +LUAI_FUNC void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v, int line); +LUAI_FUNC void luaK_infix (FuncState *fs, BinOpr op, expdesc *v); +LUAI_FUNC void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1, + expdesc *v2, int line); +LUAI_FUNC void luaK_setlist (FuncState *fs, int base, int nelems, int tostore); + + +#endif diff --git a/depends/lua/include/lctype.h b/depends/lua/include/lctype.h new file mode 100644 index 0000000000..b09b21a337 --- /dev/null +++ b/depends/lua/include/lctype.h @@ -0,0 +1,95 @@ +/* +** $Id: lctype.h,v 1.12.1.1 2013/04/12 18:48:47 roberto Exp $ +** 'ctype' functions for Lua +** See Copyright Notice in lua.h +*/ + +#ifndef lctype_h +#define lctype_h + +#include "lua.h" + + +/* +** WARNING: the functions defined here do not necessarily correspond +** to the similar functions in the standard C ctype.h. They are +** optimized for the specific needs of Lua +*/ + +#if !defined(LUA_USE_CTYPE) + +#if 'A' == 65 && '0' == 48 +/* ASCII case: can use its own tables; faster and fixed */ +#define LUA_USE_CTYPE 0 +#else +/* must use standard C ctype */ +#define LUA_USE_CTYPE 1 +#endif + +#endif + + +#if !LUA_USE_CTYPE /* { */ + +#include + +#include "llimits.h" + + +#define ALPHABIT 0 +#define DIGITBIT 1 +#define PRINTBIT 2 +#define SPACEBIT 3 +#define XDIGITBIT 4 + + +#define MASK(B) (1 << (B)) + + +/* +** add 1 to char to allow index -1 (EOZ) +*/ +#define testprop(c,p) (luai_ctype_[(c)+1] & (p)) + +/* +** 'lalpha' (Lua alphabetic) and 'lalnum' (Lua alphanumeric) both include '_' +*/ +#define lislalpha(c) testprop(c, MASK(ALPHABIT)) +#define lislalnum(c) testprop(c, (MASK(ALPHABIT) | MASK(DIGITBIT))) +#define lisdigit(c) testprop(c, MASK(DIGITBIT)) +#define lisspace(c) testprop(c, MASK(SPACEBIT)) +#define lisprint(c) testprop(c, MASK(PRINTBIT)) +#define lisxdigit(c) testprop(c, MASK(XDIGITBIT)) + +/* +** this 'ltolower' only works for alphabetic characters +*/ +#define ltolower(c) ((c) | ('A' ^ 'a')) + + +/* two more entries for 0 and -1 (EOZ) */ +LUAI_DDEC const lu_byte luai_ctype_[UCHAR_MAX + 2]; + + +#else /* }{ */ + +/* +** use standard C ctypes +*/ + +#include + + +#define lislalpha(c) (isalpha(c) || (c) == '_') +#define lislalnum(c) (isalnum(c) || (c) == '_') +#define lisdigit(c) (isdigit(c)) +#define lisspace(c) (isspace(c)) +#define lisprint(c) (isprint(c)) +#define lisxdigit(c) (isxdigit(c)) + +#define ltolower(c) (tolower(c)) + +#endif /* } */ + +#endif + diff --git a/depends/lua/include/ldebug.h b/depends/lua/include/ldebug.h new file mode 100644 index 0000000000..8cea0ee0a7 --- /dev/null +++ b/depends/lua/include/ldebug.h @@ -0,0 +1,39 @@ +/* +** $Id: ldebug.h,v 2.14.1.1 2017/04/19 17:20:42 roberto Exp $ +** Auxiliary functions from Debug Interface module +** See Copyright Notice in lua.h +*/ + +#ifndef ldebug_h +#define ldebug_h + + +#include "lstate.h" + + +#define pcRel(pc, p) (cast(int, (pc) - (p)->code) - 1) + +#define getfuncline(f,pc) (((f)->lineinfo) ? (f)->lineinfo[pc] : -1) + +#define resethookcount(L) (L->hookcount = L->basehookcount) + + +LUAI_FUNC l_noret luaG_typeerror (lua_State *L, const TValue *o, + const char *opname); +LUAI_FUNC l_noret luaG_concaterror (lua_State *L, const TValue *p1, + const TValue *p2); +LUAI_FUNC l_noret luaG_opinterror (lua_State *L, const TValue *p1, + const TValue *p2, + const char *msg); +LUAI_FUNC l_noret luaG_tointerror (lua_State *L, const TValue *p1, + const TValue *p2); +LUAI_FUNC l_noret luaG_ordererror (lua_State *L, const TValue *p1, + const TValue *p2); +LUAI_FUNC l_noret luaG_runerror (lua_State *L, const char *fmt, ...); +LUAI_FUNC const char *luaG_addinfo (lua_State *L, const char *msg, + TString *src, int line); +LUAI_FUNC l_noret luaG_errormsg (lua_State *L); +LUAI_FUNC void luaG_traceexec (lua_State *L); + + +#endif diff --git a/depends/lua/include/ldo.h b/depends/lua/include/ldo.h new file mode 100644 index 0000000000..3b2983a386 --- /dev/null +++ b/depends/lua/include/ldo.h @@ -0,0 +1,58 @@ +/* +** $Id: ldo.h,v 2.29.1.1 2017/04/19 17:20:42 roberto Exp $ +** Stack and Call structure of Lua +** See Copyright Notice in lua.h +*/ + +#ifndef ldo_h +#define ldo_h + + +#include "lobject.h" +#include "lstate.h" +#include "lzio.h" + + +/* +** Macro to check stack size and grow stack if needed. Parameters +** 'pre'/'pos' allow the macro to preserve a pointer into the +** stack across reallocations, doing the work only when needed. +** 'condmovestack' is used in heavy tests to force a stack reallocation +** at every check. +*/ +#define luaD_checkstackaux(L,n,pre,pos) \ + if (L->stack_last - L->top <= (n)) \ + { pre; luaD_growstack(L, n); pos; } else { condmovestack(L,pre,pos); } + +/* In general, 'pre'/'pos' are empty (nothing to save) */ +#define luaD_checkstack(L,n) luaD_checkstackaux(L,n,(void)0,(void)0) + + + +#define savestack(L,p) ((char *)(p) - (char *)L->stack) +#define restorestack(L,n) ((TValue *)((char *)L->stack + (n))) + + +/* type of protected functions, to be ran by 'runprotected' */ +typedef void (*Pfunc) (lua_State *L, void *ud); + +LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name, + const char *mode); +LUAI_FUNC void luaD_hook (lua_State *L, int event, int line); +LUAI_FUNC int luaD_precall (lua_State *L, StkId func, int nresults); +LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults); +LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults); +LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u, + ptrdiff_t oldtop, ptrdiff_t ef); +LUAI_FUNC int luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, + int nres); +LUAI_FUNC void luaD_reallocstack (lua_State *L, int newsize); +LUAI_FUNC void luaD_growstack (lua_State *L, int n); +LUAI_FUNC void luaD_shrinkstack (lua_State *L); +LUAI_FUNC void luaD_inctop (lua_State *L); + +LUAI_FUNC l_noret luaD_throw (lua_State *L, int errcode); +LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud); + +#endif + diff --git a/depends/lua/include/lfunc.h b/depends/lua/include/lfunc.h new file mode 100644 index 0000000000..c916e9878a --- /dev/null +++ b/depends/lua/include/lfunc.h @@ -0,0 +1,61 @@ +/* +** $Id: lfunc.h,v 2.15.1.1 2017/04/19 17:39:34 roberto Exp $ +** Auxiliary functions to manipulate prototypes and closures +** See Copyright Notice in lua.h +*/ + +#ifndef lfunc_h +#define lfunc_h + + +#include "lobject.h" + + +#define sizeCclosure(n) (cast(int, sizeof(CClosure)) + \ + cast(int, sizeof(TValue)*((n)-1))) + +#define sizeLclosure(n) (cast(int, sizeof(LClosure)) + \ + cast(int, sizeof(TValue *)*((n)-1))) + + +/* test whether thread is in 'twups' list */ +#define isintwups(L) (L->twups != L) + + +/* +** maximum number of upvalues in a closure (both C and Lua). (Value +** must fit in a VM register.) +*/ +#define MAXUPVAL 255 + + +/* +** Upvalues for Lua closures +*/ +struct UpVal { + TValue *v; /* points to stack or to its own value */ + lu_mem refcount; /* reference counter */ + union { + struct { /* (when open) */ + UpVal *next; /* linked list */ + int touched; /* mark to avoid cycles with dead threads */ + } open; + TValue value; /* the value (when closed) */ + } u; +}; + +#define upisopen(up) ((up)->v != &(up)->u.value) + + +LUAI_FUNC Proto *luaF_newproto (lua_State *L); +LUAI_FUNC CClosure *luaF_newCclosure (lua_State *L, int nelems); +LUAI_FUNC LClosure *luaF_newLclosure (lua_State *L, int nelems); +LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl); +LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level); +LUAI_FUNC void luaF_close (lua_State *L, StkId level); +LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f); +LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number, + int pc); + + +#endif diff --git a/depends/lua/include/lgc.h b/depends/lua/include/lgc.h new file mode 100644 index 0000000000..425cd7cef3 --- /dev/null +++ b/depends/lua/include/lgc.h @@ -0,0 +1,147 @@ +/* +** $Id: lgc.h,v 2.91.1.1 2017/04/19 17:39:34 roberto Exp $ +** Garbage Collector +** See Copyright Notice in lua.h +*/ + +#ifndef lgc_h +#define lgc_h + + +#include "lobject.h" +#include "lstate.h" + +/* +** Collectable objects may have one of three colors: white, which +** means the object is not marked; gray, which means the +** object is marked, but its references may be not marked; and +** black, which means that the object and all its references are marked. +** The main invariant of the garbage collector, while marking objects, +** is that a black object can never point to a white one. Moreover, +** any gray object must be in a "gray list" (gray, grayagain, weak, +** allweak, ephemeron) so that it can be visited again before finishing +** the collection cycle. These lists have no meaning when the invariant +** is not being enforced (e.g., sweep phase). +*/ + + + +/* how much to allocate before next GC step */ +#if !defined(GCSTEPSIZE) +/* ~100 small strings */ +#define GCSTEPSIZE (cast_int(100 * sizeof(TString))) +#endif + + +/* +** Possible states of the Garbage Collector +*/ +#define GCSpropagate 0 +#define GCSatomic 1 +#define GCSswpallgc 2 +#define GCSswpfinobj 3 +#define GCSswptobefnz 4 +#define GCSswpend 5 +#define GCScallfin 6 +#define GCSpause 7 + + +#define issweepphase(g) \ + (GCSswpallgc <= (g)->gcstate && (g)->gcstate <= GCSswpend) + + +/* +** macro to tell when main invariant (white objects cannot point to black +** ones) must be kept. During a collection, the sweep +** phase may break the invariant, as objects turned white may point to +** still-black objects. The invariant is restored when sweep ends and +** all objects are white again. +*/ + +#define keepinvariant(g) ((g)->gcstate <= GCSatomic) + + +/* +** some useful bit tricks +*/ +#define resetbits(x,m) ((x) &= cast(lu_byte, ~(m))) +#define setbits(x,m) ((x) |= (m)) +#define testbits(x,m) ((x) & (m)) +#define bitmask(b) (1<<(b)) +#define bit2mask(b1,b2) (bitmask(b1) | bitmask(b2)) +#define l_setbit(x,b) setbits(x, bitmask(b)) +#define resetbit(x,b) resetbits(x, bitmask(b)) +#define testbit(x,b) testbits(x, bitmask(b)) + + +/* Layout for bit use in 'marked' field: */ +#define WHITE0BIT 0 /* object is white (type 0) */ +#define WHITE1BIT 1 /* object is white (type 1) */ +#define BLACKBIT 2 /* object is black */ +#define FINALIZEDBIT 3 /* object has been marked for finalization */ +/* bit 7 is currently used by tests (luaL_checkmemory) */ + +#define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT) + + +#define iswhite(x) testbits((x)->marked, WHITEBITS) +#define isblack(x) testbit((x)->marked, BLACKBIT) +#define isgray(x) /* neither white nor black */ \ + (!testbits((x)->marked, WHITEBITS | bitmask(BLACKBIT))) + +#define tofinalize(x) testbit((x)->marked, FINALIZEDBIT) + +#define otherwhite(g) ((g)->currentwhite ^ WHITEBITS) +#define isdeadm(ow,m) (!(((m) ^ WHITEBITS) & (ow))) +#define isdead(g,v) isdeadm(otherwhite(g), (v)->marked) + +#define changewhite(x) ((x)->marked ^= WHITEBITS) +#define gray2black(x) l_setbit((x)->marked, BLACKBIT) + +#define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS) + + +/* +** Does one step of collection when debt becomes positive. 'pre'/'pos' +** allows some adjustments to be done only when needed. macro +** 'condchangemem' is used only for heavy tests (forcing a full +** GC cycle on every opportunity) +*/ +#define luaC_condGC(L,pre,pos) \ + { if (G(L)->GCdebt > 0) { pre; luaC_step(L); pos;}; \ + condchangemem(L,pre,pos); } + +/* more often than not, 'pre'/'pos' are empty */ +#define luaC_checkGC(L) luaC_condGC(L,(void)0,(void)0) + + +#define luaC_barrier(L,p,v) ( \ + (iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \ + luaC_barrier_(L,obj2gco(p),gcvalue(v)) : cast_void(0)) + +#define luaC_barrierback(L,p,v) ( \ + (iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \ + luaC_barrierback_(L,p) : cast_void(0)) + +#define luaC_objbarrier(L,p,o) ( \ + (isblack(p) && iswhite(o)) ? \ + luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0)) + +#define luaC_upvalbarrier(L,uv) ( \ + (iscollectable((uv)->v) && !upisopen(uv)) ? \ + luaC_upvalbarrier_(L,uv) : cast_void(0)) + +LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o); +LUAI_FUNC void luaC_freeallobjects (lua_State *L); +LUAI_FUNC void luaC_step (lua_State *L); +LUAI_FUNC void luaC_runtilstate (lua_State *L, int statesmask); +LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency); +LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz); +LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v); +LUAI_FUNC void luaC_barrierback_ (lua_State *L, Table *o); +LUAI_FUNC void luaC_upvalbarrier_ (lua_State *L, UpVal *uv); +LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt); +LUAI_FUNC void luaC_upvdeccount (lua_State *L, UpVal *uv); + + +#endif diff --git a/depends/lua/include/llex.h b/depends/lua/include/llex.h new file mode 100644 index 0000000000..2ed0af66a4 --- /dev/null +++ b/depends/lua/include/llex.h @@ -0,0 +1,85 @@ +/* +** $Id: llex.h,v 1.79.1.1 2017/04/19 17:20:42 roberto Exp $ +** Lexical Analyzer +** See Copyright Notice in lua.h +*/ + +#ifndef llex_h +#define llex_h + +#include "lobject.h" +#include "lzio.h" + + +#define FIRST_RESERVED 257 + + +#if !defined(LUA_ENV) +#define LUA_ENV "_ENV" +#endif + + +/* +* WARNING: if you change the order of this enumeration, +* grep "ORDER RESERVED" +*/ +enum RESERVED { + /* terminal symbols denoted by reserved words */ + TK_AND = FIRST_RESERVED, TK_BREAK, + TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FALSE, TK_FOR, TK_FUNCTION, + TK_GOTO, TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT, + TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE, + /* other terminal symbols */ + TK_IDIV, TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, + TK_SHL, TK_SHR, + TK_DBCOLON, TK_EOS, + TK_FLT, TK_INT, TK_NAME, TK_STRING +}; + +/* number of reserved words */ +#define NUM_RESERVED (cast(int, TK_WHILE-FIRST_RESERVED+1)) + + +typedef union { + lua_Number r; + lua_Integer i; + TString *ts; +} SemInfo; /* semantics information */ + + +typedef struct Token { + int token; + SemInfo seminfo; +} Token; + + +/* state of the lexer plus state of the parser when shared by all + functions */ +typedef struct LexState { + int current; /* current character (charint) */ + int linenumber; /* input line counter */ + int lastline; /* line of last token 'consumed' */ + Token t; /* current token */ + Token lookahead; /* look ahead token */ + struct FuncState *fs; /* current function (parser) */ + struct lua_State *L; + ZIO *z; /* input stream */ + Mbuffer *buff; /* buffer for tokens */ + Table *h; /* to avoid collection/reuse strings */ + struct Dyndata *dyd; /* dynamic structures used by the parser */ + TString *source; /* current source name */ + TString *envn; /* environment variable name */ +} LexState; + + +LUAI_FUNC void luaX_init (lua_State *L); +LUAI_FUNC void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, + TString *source, int firstchar); +LUAI_FUNC TString *luaX_newstring (LexState *ls, const char *str, size_t l); +LUAI_FUNC void luaX_next (LexState *ls); +LUAI_FUNC int luaX_lookahead (LexState *ls); +LUAI_FUNC l_noret luaX_syntaxerror (LexState *ls, const char *s); +LUAI_FUNC const char *luaX_token2str (LexState *ls, int token); + + +#endif diff --git a/depends/lua/include/llimits.h b/depends/lua/include/llimits.h new file mode 100644 index 0000000000..d1036f6bc8 --- /dev/null +++ b/depends/lua/include/llimits.h @@ -0,0 +1,323 @@ +/* +** $Id: llimits.h,v 1.141.1.1 2017/04/19 17:20:42 roberto Exp $ +** Limits, basic types, and some other 'installation-dependent' definitions +** See Copyright Notice in lua.h +*/ + +#ifndef llimits_h +#define llimits_h + + +#include +#include + + +#include "lua.h" + +/* +** 'lu_mem' and 'l_mem' are unsigned/signed integers big enough to count +** the total memory used by Lua (in bytes). Usually, 'size_t' and +** 'ptrdiff_t' should work, but we use 'long' for 16-bit machines. +*/ +#if defined(LUAI_MEM) /* { external definitions? */ +typedef LUAI_UMEM lu_mem; +typedef LUAI_MEM l_mem; +#elif LUAI_BITSINT >= 32 /* }{ */ +typedef size_t lu_mem; +typedef ptrdiff_t l_mem; +#else /* 16-bit ints */ /* }{ */ +typedef unsigned long lu_mem; +typedef long l_mem; +#endif /* } */ + + +/* chars used as small naturals (so that 'char' is reserved for characters) */ +typedef unsigned char lu_byte; + + +/* maximum value for size_t */ +#define MAX_SIZET ((size_t)(~(size_t)0)) + +/* maximum size visible for Lua (must be representable in a lua_Integer */ +#define MAX_SIZE (sizeof(size_t) < sizeof(lua_Integer) ? MAX_SIZET \ + : (size_t)(LUA_MAXINTEGER)) + + +#define MAX_LUMEM ((lu_mem)(~(lu_mem)0)) + +#define MAX_LMEM ((l_mem)(MAX_LUMEM >> 1)) + + +#define MAX_INT INT_MAX /* maximum value of an int */ + + +/* +** conversion of pointer to unsigned integer: +** this is for hashing only; there is no problem if the integer +** cannot hold the whole pointer value +*/ +#define point2uint(p) ((unsigned int)((size_t)(p) & UINT_MAX)) + + + +/* type to ensure maximum alignment */ +#if defined(LUAI_USER_ALIGNMENT_T) +typedef LUAI_USER_ALIGNMENT_T L_Umaxalign; +#else +typedef union { + lua_Number n; + double u; + void *s; + lua_Integer i; + long l; +} L_Umaxalign; +#endif + + + +/* types of 'usual argument conversions' for lua_Number and lua_Integer */ +typedef LUAI_UACNUMBER l_uacNumber; +typedef LUAI_UACINT l_uacInt; + + +/* internal assertions for in-house debugging */ +#if defined(lua_assert) +#define check_exp(c,e) (lua_assert(c), (e)) +/* to avoid problems with conditions too long */ +#define lua_longassert(c) ((c) ? (void)0 : lua_assert(0)) +#else +#define lua_assert(c) ((void)0) +#define check_exp(c,e) (e) +#define lua_longassert(c) ((void)0) +#endif + +/* +** assertion for checking API calls +*/ +#if !defined(luai_apicheck) +#define luai_apicheck(l,e) lua_assert(e) +#endif + +#define api_check(l,e,msg) luai_apicheck(l,(e) && msg) + + +/* macro to avoid warnings about unused variables */ +#if !defined(UNUSED) +#define UNUSED(x) ((void)(x)) +#endif + + +/* type casts (a macro highlights casts in the code) */ +#define cast(t, exp) ((t)(exp)) + +#define cast_void(i) cast(void, (i)) +#define cast_byte(i) cast(lu_byte, (i)) +#define cast_num(i) cast(lua_Number, (i)) +#define cast_int(i) cast(int, (i)) +#define cast_uchar(i) cast(unsigned char, (i)) + + +/* cast a signed lua_Integer to lua_Unsigned */ +#if !defined(l_castS2U) +#define l_castS2U(i) ((lua_Unsigned)(i)) +#endif + +/* +** cast a lua_Unsigned to a signed lua_Integer; this cast is +** not strict ISO C, but two-complement architectures should +** work fine. +*/ +#if !defined(l_castU2S) +#define l_castU2S(i) ((lua_Integer)(i)) +#endif + + +/* +** non-return type +*/ +#if defined(__GNUC__) +#define l_noret void __attribute__((noreturn)) +#elif defined(_MSC_VER) && _MSC_VER >= 1200 +#define l_noret void __declspec(noreturn) +#else +#define l_noret void +#endif + + + +/* +** maximum depth for nested C calls and syntactical nested non-terminals +** in a program. (Value must fit in an unsigned short int.) +*/ +#if !defined(LUAI_MAXCCALLS) +#define LUAI_MAXCCALLS 200 +#endif + + + +/* +** type for virtual-machine instructions; +** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h) +*/ +#if LUAI_BITSINT >= 32 +typedef unsigned int Instruction; +#else +typedef unsigned long Instruction; +#endif + + + +/* +** Maximum length for short strings, that is, strings that are +** internalized. (Cannot be smaller than reserved words or tags for +** metamethods, as these strings must be internalized; +** #("function") = 8, #("__newindex") = 10.) +*/ +#if !defined(LUAI_MAXSHORTLEN) +#define LUAI_MAXSHORTLEN 40 +#endif + + +/* +** Initial size for the string table (must be power of 2). +** The Lua core alone registers ~50 strings (reserved words + +** metaevent keys + a few others). Libraries would typically add +** a few dozens more. +*/ +#if !defined(MINSTRTABSIZE) +#define MINSTRTABSIZE 128 +#endif + + +/* +** Size of cache for strings in the API. 'N' is the number of +** sets (better be a prime) and "M" is the size of each set (M == 1 +** makes a direct cache.) +*/ +#if !defined(STRCACHE_N) +#define STRCACHE_N 53 +#define STRCACHE_M 2 +#endif + + +/* minimum size for string buffer */ +#if !defined(LUA_MINBUFFER) +#define LUA_MINBUFFER 32 +#endif + + +/* +** macros that are executed whenever program enters the Lua core +** ('lua_lock') and leaves the core ('lua_unlock') +*/ +#if !defined(lua_lock) +#define lua_lock(L) ((void) 0) +#define lua_unlock(L) ((void) 0) +#endif + +/* +** macro executed during Lua functions at points where the +** function can yield. +*/ +#if !defined(luai_threadyield) +#define luai_threadyield(L) {lua_unlock(L); lua_lock(L);} +#endif + + +/* +** these macros allow user-specific actions on threads when you defined +** LUAI_EXTRASPACE and need to do something extra when a thread is +** created/deleted/resumed/yielded. +*/ +#if !defined(luai_userstateopen) +#define luai_userstateopen(L) ((void)L) +#endif + +#if !defined(luai_userstateclose) +#define luai_userstateclose(L) ((void)L) +#endif + +#if !defined(luai_userstatethread) +#define luai_userstatethread(L,L1) ((void)L) +#endif + +#if !defined(luai_userstatefree) +#define luai_userstatefree(L,L1) ((void)L) +#endif + +#if !defined(luai_userstateresume) +#define luai_userstateresume(L,n) ((void)L) +#endif + +#if !defined(luai_userstateyield) +#define luai_userstateyield(L,n) ((void)L) +#endif + + + +/* +** The luai_num* macros define the primitive operations over numbers. +*/ + +/* floor division (defined as 'floor(a/b)') */ +#if !defined(luai_numidiv) +#define luai_numidiv(L,a,b) ((void)L, l_floor(luai_numdiv(L,a,b))) +#endif + +/* float division */ +#if !defined(luai_numdiv) +#define luai_numdiv(L,a,b) ((a)/(b)) +#endif + +/* +** modulo: defined as 'a - floor(a/b)*b'; this definition gives NaN when +** 'b' is huge, but the result should be 'a'. 'fmod' gives the result of +** 'a - trunc(a/b)*b', and therefore must be corrected when 'trunc(a/b) +** ~= floor(a/b)'. That happens when the division has a non-integer +** negative result, which is equivalent to the test below. +*/ +#if !defined(luai_nummod) +#define luai_nummod(L,a,b,m) \ + { (m) = l_mathop(fmod)(a,b); if ((m)*(b) < 0) (m) += (b); } +#endif + +/* exponentiation */ +#if !defined(luai_numpow) +#define luai_numpow(L,a,b) ((void)L, l_mathop(pow)(a,b)) +#endif + +/* the others are quite standard operations */ +#if !defined(luai_numadd) +#define luai_numadd(L,a,b) ((a)+(b)) +#define luai_numsub(L,a,b) ((a)-(b)) +#define luai_nummul(L,a,b) ((a)*(b)) +#define luai_numunm(L,a) (-(a)) +#define luai_numeq(a,b) ((a)==(b)) +#define luai_numlt(a,b) ((a)<(b)) +#define luai_numle(a,b) ((a)<=(b)) +#define luai_numisnan(a) (!luai_numeq((a), (a))) +#endif + + + + + +/* +** macro to control inclusion of some hard tests on stack reallocation +*/ +#if !defined(HARDSTACKTESTS) +#define condmovestack(L,pre,pos) ((void)0) +#else +/* realloc stack keeping its size */ +#define condmovestack(L,pre,pos) \ + { int sz_ = (L)->stacksize; pre; luaD_reallocstack((L), sz_); pos; } +#endif + +#if !defined(HARDMEMTESTS) +#define condchangemem(L,pre,pos) ((void)0) +#else +#define condchangemem(L,pre,pos) \ + { if (G(L)->gcrunning) { pre; luaC_fullgc(L, 0); pos; } } +#endif + +#endif diff --git a/depends/lua/include/lmem.h b/depends/lua/include/lmem.h new file mode 100644 index 0000000000..357b1e43e7 --- /dev/null +++ b/depends/lua/include/lmem.h @@ -0,0 +1,69 @@ +/* +** $Id: lmem.h,v 1.43.1.1 2017/04/19 17:20:42 roberto Exp $ +** Interface to Memory Manager +** See Copyright Notice in lua.h +*/ + +#ifndef lmem_h +#define lmem_h + + +#include + +#include "llimits.h" +#include "lua.h" + + +/* +** This macro reallocs a vector 'b' from 'on' to 'n' elements, where +** each element has size 'e'. In case of arithmetic overflow of the +** product 'n'*'e', it raises an error (calling 'luaM_toobig'). Because +** 'e' is always constant, it avoids the runtime division MAX_SIZET/(e). +** +** (The macro is somewhat complex to avoid warnings: The 'sizeof' +** comparison avoids a runtime comparison when overflow cannot occur. +** The compiler should be able to optimize the real test by itself, but +** when it does it, it may give a warning about "comparison is always +** false due to limited range of data type"; the +1 tricks the compiler, +** avoiding this warning but also this optimization.) +*/ +#define luaM_reallocv(L,b,on,n,e) \ + (((sizeof(n) >= sizeof(size_t) && cast(size_t, (n)) + 1 > MAX_SIZET/(e)) \ + ? luaM_toobig(L) : cast_void(0)) , \ + luaM_realloc_(L, (b), (on)*(e), (n)*(e))) + +/* +** Arrays of chars do not need any test +*/ +#define luaM_reallocvchar(L,b,on,n) \ + cast(char *, luaM_realloc_(L, (b), (on)*sizeof(char), (n)*sizeof(char))) + +#define luaM_freemem(L, b, s) luaM_realloc_(L, (b), (s), 0) +#define luaM_free(L, b) luaM_realloc_(L, (b), sizeof(*(b)), 0) +#define luaM_freearray(L, b, n) luaM_realloc_(L, (b), (n)*sizeof(*(b)), 0) + +#define luaM_malloc(L,s) luaM_realloc_(L, NULL, 0, (s)) +#define luaM_new(L,t) cast(t *, luaM_malloc(L, sizeof(t))) +#define luaM_newvector(L,n,t) \ + cast(t *, luaM_reallocv(L, NULL, 0, n, sizeof(t))) + +#define luaM_newobject(L,tag,s) luaM_realloc_(L, NULL, tag, (s)) + +#define luaM_growvector(L,v,nelems,size,t,limit,e) \ + if ((nelems)+1 > (size)) \ + ((v)=cast(t *, luaM_growaux_(L,v,&(size),sizeof(t),limit,e))) + +#define luaM_reallocvector(L, v,oldn,n,t) \ + ((v)=cast(t *, luaM_reallocv(L, v, oldn, n, sizeof(t)))) + +LUAI_FUNC l_noret luaM_toobig (lua_State *L); + +/* not to be called directly */ +LUAI_FUNC void *luaM_realloc_ (lua_State *L, void *block, size_t oldsize, + size_t size); +LUAI_FUNC void *luaM_growaux_ (lua_State *L, void *block, int *size, + size_t size_elem, int limit, + const char *what); + +#endif + diff --git a/depends/lua/include/lobject.h b/depends/lua/include/lobject.h new file mode 100644 index 0000000000..2408861402 --- /dev/null +++ b/depends/lua/include/lobject.h @@ -0,0 +1,549 @@ +/* +** $Id: lobject.h,v 2.117.1.1 2017/04/19 17:39:34 roberto Exp $ +** Type definitions for Lua objects +** See Copyright Notice in lua.h +*/ + + +#ifndef lobject_h +#define lobject_h + + +#include + + +#include "llimits.h" +#include "lua.h" + + +/* +** Extra tags for non-values +*/ +#define LUA_TPROTO LUA_NUMTAGS /* function prototypes */ +#define LUA_TDEADKEY (LUA_NUMTAGS+1) /* removed keys in tables */ + +/* +** number of all possible tags (including LUA_TNONE but excluding DEADKEY) +*/ +#define LUA_TOTALTAGS (LUA_TPROTO + 2) + + +/* +** tags for Tagged Values have the following use of bits: +** bits 0-3: actual tag (a LUA_T* value) +** bits 4-5: variant bits +** bit 6: whether value is collectable +*/ + + +/* +** LUA_TFUNCTION variants: +** 0 - Lua function +** 1 - light C function +** 2 - regular C function (closure) +*/ + +/* Variant tags for functions */ +#define LUA_TLCL (LUA_TFUNCTION | (0 << 4)) /* Lua closure */ +#define LUA_TLCF (LUA_TFUNCTION | (1 << 4)) /* light C function */ +#define LUA_TCCL (LUA_TFUNCTION | (2 << 4)) /* C closure */ + + +/* Variant tags for strings */ +#define LUA_TSHRSTR (LUA_TSTRING | (0 << 4)) /* short strings */ +#define LUA_TLNGSTR (LUA_TSTRING | (1 << 4)) /* long strings */ + + +/* Variant tags for numbers */ +#define LUA_TNUMFLT (LUA_TNUMBER | (0 << 4)) /* float numbers */ +#define LUA_TNUMINT (LUA_TNUMBER | (1 << 4)) /* integer numbers */ + + +/* Bit mark for collectable types */ +#define BIT_ISCOLLECTABLE (1 << 6) + +/* mark a tag as collectable */ +#define ctb(t) ((t) | BIT_ISCOLLECTABLE) + + +/* +** Common type for all collectable objects +*/ +typedef struct GCObject GCObject; + + +/* +** Common Header for all collectable objects (in macro form, to be +** included in other objects) +*/ +#define CommonHeader GCObject *next; lu_byte tt; lu_byte marked + + +/* +** Common type has only the common header +*/ +struct GCObject { + CommonHeader; +}; + + + + +/* +** Tagged Values. This is the basic representation of values in Lua, +** an actual value plus a tag with its type. +*/ + +/* +** Union of all Lua values +*/ +typedef union Value { + GCObject *gc; /* collectable objects */ + void *p; /* light userdata */ + int b; /* booleans */ + lua_CFunction f; /* light C functions */ + lua_Integer i; /* integer numbers */ + lua_Number n; /* float numbers */ +} Value; + + +#define TValuefields Value value_; int tt_ + + +typedef struct lua_TValue { + TValuefields; +} TValue; + + + +/* macro defining a nil value */ +#define NILCONSTANT {NULL}, LUA_TNIL + + +#define val_(o) ((o)->value_) + + +/* raw type tag of a TValue */ +#define rttype(o) ((o)->tt_) + +/* tag with no variants (bits 0-3) */ +#define novariant(x) ((x) & 0x0F) + +/* type tag of a TValue (bits 0-3 for tags + variant bits 4-5) */ +#define ttype(o) (rttype(o) & 0x3F) + +/* type tag of a TValue with no variants (bits 0-3) */ +#define ttnov(o) (novariant(rttype(o))) + + +/* Macros to test type */ +#define checktag(o,t) (rttype(o) == (t)) +#define checktype(o,t) (ttnov(o) == (t)) +#define ttisnumber(o) checktype((o), LUA_TNUMBER) +#define ttisfloat(o) checktag((o), LUA_TNUMFLT) +#define ttisinteger(o) checktag((o), LUA_TNUMINT) +#define ttisnil(o) checktag((o), LUA_TNIL) +#define ttisboolean(o) checktag((o), LUA_TBOOLEAN) +#define ttislightuserdata(o) checktag((o), LUA_TLIGHTUSERDATA) +#define ttisstring(o) checktype((o), LUA_TSTRING) +#define ttisshrstring(o) checktag((o), ctb(LUA_TSHRSTR)) +#define ttislngstring(o) checktag((o), ctb(LUA_TLNGSTR)) +#define ttistable(o) checktag((o), ctb(LUA_TTABLE)) +#define ttisfunction(o) checktype(o, LUA_TFUNCTION) +#define ttisclosure(o) ((rttype(o) & 0x1F) == LUA_TFUNCTION) +#define ttisCclosure(o) checktag((o), ctb(LUA_TCCL)) +#define ttisLclosure(o) checktag((o), ctb(LUA_TLCL)) +#define ttislcf(o) checktag((o), LUA_TLCF) +#define ttisfulluserdata(o) checktag((o), ctb(LUA_TUSERDATA)) +#define ttisthread(o) checktag((o), ctb(LUA_TTHREAD)) +#define ttisdeadkey(o) checktag((o), LUA_TDEADKEY) + + +/* Macros to access values */ +#define ivalue(o) check_exp(ttisinteger(o), val_(o).i) +#define fltvalue(o) check_exp(ttisfloat(o), val_(o).n) +#define nvalue(o) check_exp(ttisnumber(o), \ + (ttisinteger(o) ? cast_num(ivalue(o)) : fltvalue(o))) +#define gcvalue(o) check_exp(iscollectable(o), val_(o).gc) +#define pvalue(o) check_exp(ttislightuserdata(o), val_(o).p) +#define tsvalue(o) check_exp(ttisstring(o), gco2ts(val_(o).gc)) +#define uvalue(o) check_exp(ttisfulluserdata(o), gco2u(val_(o).gc)) +#define clvalue(o) check_exp(ttisclosure(o), gco2cl(val_(o).gc)) +#define clLvalue(o) check_exp(ttisLclosure(o), gco2lcl(val_(o).gc)) +#define clCvalue(o) check_exp(ttisCclosure(o), gco2ccl(val_(o).gc)) +#define fvalue(o) check_exp(ttislcf(o), val_(o).f) +#define hvalue(o) check_exp(ttistable(o), gco2t(val_(o).gc)) +#define bvalue(o) check_exp(ttisboolean(o), val_(o).b) +#define thvalue(o) check_exp(ttisthread(o), gco2th(val_(o).gc)) +/* a dead value may get the 'gc' field, but cannot access its contents */ +#define deadvalue(o) check_exp(ttisdeadkey(o), cast(void *, val_(o).gc)) + +#define l_isfalse(o) (ttisnil(o) || (ttisboolean(o) && bvalue(o) == 0)) + + +#define iscollectable(o) (rttype(o) & BIT_ISCOLLECTABLE) + + +/* Macros for internal tests */ +#define righttt(obj) (ttype(obj) == gcvalue(obj)->tt) + +#define checkliveness(L,obj) \ + lua_longassert(!iscollectable(obj) || \ + (righttt(obj) && (L == NULL || !isdead(G(L),gcvalue(obj))))) + + +/* Macros to set values */ +#define settt_(o,t) ((o)->tt_=(t)) + +#define setfltvalue(obj,x) \ + { TValue *io=(obj); val_(io).n=(x); settt_(io, LUA_TNUMFLT); } + +#define chgfltvalue(obj,x) \ + { TValue *io=(obj); lua_assert(ttisfloat(io)); val_(io).n=(x); } + +#define setivalue(obj,x) \ + { TValue *io=(obj); val_(io).i=(x); settt_(io, LUA_TNUMINT); } + +#define chgivalue(obj,x) \ + { TValue *io=(obj); lua_assert(ttisinteger(io)); val_(io).i=(x); } + +#define setnilvalue(obj) settt_(obj, LUA_TNIL) + +#define setfvalue(obj,x) \ + { TValue *io=(obj); val_(io).f=(x); settt_(io, LUA_TLCF); } + +#define setpvalue(obj,x) \ + { TValue *io=(obj); val_(io).p=(x); settt_(io, LUA_TLIGHTUSERDATA); } + +#define setbvalue(obj,x) \ + { TValue *io=(obj); val_(io).b=(x); settt_(io, LUA_TBOOLEAN); } + +#define setgcovalue(L,obj,x) \ + { TValue *io = (obj); GCObject *i_g=(x); \ + val_(io).gc = i_g; settt_(io, ctb(i_g->tt)); } + +#define setsvalue(L,obj,x) \ + { TValue *io = (obj); TString *x_ = (x); \ + val_(io).gc = obj2gco(x_); settt_(io, ctb(x_->tt)); \ + checkliveness(L,io); } + +#define setuvalue(L,obj,x) \ + { TValue *io = (obj); Udata *x_ = (x); \ + val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TUSERDATA)); \ + checkliveness(L,io); } + +#define setthvalue(L,obj,x) \ + { TValue *io = (obj); lua_State *x_ = (x); \ + val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TTHREAD)); \ + checkliveness(L,io); } + +#define setclLvalue(L,obj,x) \ + { TValue *io = (obj); LClosure *x_ = (x); \ + val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TLCL)); \ + checkliveness(L,io); } + +#define setclCvalue(L,obj,x) \ + { TValue *io = (obj); CClosure *x_ = (x); \ + val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TCCL)); \ + checkliveness(L,io); } + +#define sethvalue(L,obj,x) \ + { TValue *io = (obj); Table *x_ = (x); \ + val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TTABLE)); \ + checkliveness(L,io); } + +#define setdeadvalue(obj) settt_(obj, LUA_TDEADKEY) + + + +#define setobj(L,obj1,obj2) \ + { TValue *io1=(obj1); *io1 = *(obj2); \ + (void)L; checkliveness(L,io1); } + + +/* +** different types of assignments, according to destination +*/ + +/* from stack to (same) stack */ +#define setobjs2s setobj +/* to stack (not from same stack) */ +#define setobj2s setobj +#define setsvalue2s setsvalue +#define sethvalue2s sethvalue +#define setptvalue2s setptvalue +/* from table to same table */ +#define setobjt2t setobj +/* to new object */ +#define setobj2n setobj +#define setsvalue2n setsvalue + +/* to table (define it as an expression to be used in macros) */ +#define setobj2t(L,o1,o2) ((void)L, *(o1)=*(o2), checkliveness(L,(o1))) + + + + +/* +** {====================================================== +** types and prototypes +** ======================================================= +*/ + + +typedef TValue *StkId; /* index to stack elements */ + + + + +/* +** Header for string value; string bytes follow the end of this structure +** (aligned according to 'UTString'; see next). +*/ +typedef struct TString { + CommonHeader; + lu_byte extra; /* reserved words for short strings; "has hash" for longs */ + lu_byte shrlen; /* length for short strings */ + unsigned int hash; + union { + size_t lnglen; /* length for long strings */ + struct TString *hnext; /* linked list for hash table */ + } u; +} TString; + + +/* +** Ensures that address after this type is always fully aligned. +*/ +typedef union UTString { + L_Umaxalign dummy; /* ensures maximum alignment for strings */ + TString tsv; +} UTString; + + +/* +** Get the actual string (array of bytes) from a 'TString'. +** (Access to 'extra' ensures that value is really a 'TString'.) +*/ +#define getstr(ts) \ + check_exp(sizeof((ts)->extra), cast(char *, (ts)) + sizeof(UTString)) + + +/* get the actual string (array of bytes) from a Lua value */ +#define svalue(o) getstr(tsvalue(o)) + +/* get string length from 'TString *s' */ +#define tsslen(s) ((s)->tt == LUA_TSHRSTR ? (s)->shrlen : (s)->u.lnglen) + +/* get string length from 'TValue *o' */ +#define vslen(o) tsslen(tsvalue(o)) + + +/* +** Header for userdata; memory area follows the end of this structure +** (aligned according to 'UUdata'; see next). +*/ +typedef struct Udata { + CommonHeader; + lu_byte ttuv_; /* user value's tag */ + struct Table *metatable; + size_t len; /* number of bytes */ + union Value user_; /* user value */ +} Udata; + + +/* +** Ensures that address after this type is always fully aligned. +*/ +typedef union UUdata { + L_Umaxalign dummy; /* ensures maximum alignment for 'local' udata */ + Udata uv; +} UUdata; + + +/* +** Get the address of memory block inside 'Udata'. +** (Access to 'ttuv_' ensures that value is really a 'Udata'.) +*/ +#define getudatamem(u) \ + check_exp(sizeof((u)->ttuv_), (cast(char*, (u)) + sizeof(UUdata))) + +#define setuservalue(L,u,o) \ + { const TValue *io=(o); Udata *iu = (u); \ + iu->user_ = io->value_; iu->ttuv_ = rttype(io); \ + checkliveness(L,io); } + + +#define getuservalue(L,u,o) \ + { TValue *io=(o); const Udata *iu = (u); \ + io->value_ = iu->user_; settt_(io, iu->ttuv_); \ + checkliveness(L,io); } + + +/* +** Description of an upvalue for function prototypes +*/ +typedef struct Upvaldesc { + TString *name; /* upvalue name (for debug information) */ + lu_byte instack; /* whether it is in stack (register) */ + lu_byte idx; /* index of upvalue (in stack or in outer function's list) */ +} Upvaldesc; + + +/* +** Description of a local variable for function prototypes +** (used for debug information) +*/ +typedef struct LocVar { + TString *varname; + int startpc; /* first point where variable is active */ + int endpc; /* first point where variable is dead */ +} LocVar; + + +/* +** Function Prototypes +*/ +typedef struct Proto { + CommonHeader; + lu_byte numparams; /* number of fixed parameters */ + lu_byte is_vararg; + lu_byte maxstacksize; /* number of registers needed by this function */ + int sizeupvalues; /* size of 'upvalues' */ + int sizek; /* size of 'k' */ + int sizecode; + int sizelineinfo; + int sizep; /* size of 'p' */ + int sizelocvars; + int linedefined; /* debug information */ + int lastlinedefined; /* debug information */ + TValue *k; /* constants used by the function */ + Instruction *code; /* opcodes */ + struct Proto **p; /* functions defined inside the function */ + int *lineinfo; /* map from opcodes to source lines (debug information) */ + LocVar *locvars; /* information about local variables (debug information) */ + Upvaldesc *upvalues; /* upvalue information */ + struct LClosure *cache; /* last-created closure with this prototype */ + TString *source; /* used for debug information */ + GCObject *gclist; +} Proto; + + + +/* +** Lua Upvalues +*/ +typedef struct UpVal UpVal; + + +/* +** Closures +*/ + +#define ClosureHeader \ + CommonHeader; lu_byte nupvalues; GCObject *gclist + +typedef struct CClosure { + ClosureHeader; + lua_CFunction f; + TValue upvalue[1]; /* list of upvalues */ +} CClosure; + + +typedef struct LClosure { + ClosureHeader; + struct Proto *p; + UpVal *upvals[1]; /* list of upvalues */ +} LClosure; + + +typedef union Closure { + CClosure c; + LClosure l; +} Closure; + + +#define isLfunction(o) ttisLclosure(o) + +#define getproto(o) (clLvalue(o)->p) + + +/* +** Tables +*/ + +typedef union TKey { + struct { + TValuefields; + int next; /* for chaining (offset for next node) */ + } nk; + TValue tvk; +} TKey; + + +/* copy a value into a key without messing up field 'next' */ +#define setnodekey(L,key,obj) \ + { TKey *k_=(key); const TValue *io_=(obj); \ + k_->nk.value_ = io_->value_; k_->nk.tt_ = io_->tt_; \ + (void)L; checkliveness(L,io_); } + + +typedef struct Node { + TValue i_val; + TKey i_key; +} Node; + + +typedef struct Table { + CommonHeader; + lu_byte flags; /* 1<

lsizenode)) + + +/* +** (address of) a fixed nil value +*/ +#define luaO_nilobject (&luaO_nilobject_) + + +LUAI_DDEC const TValue luaO_nilobject_; + +/* size of buffer for 'luaO_utf8esc' function */ +#define UTF8BUFFSZ 8 + +LUAI_FUNC int luaO_int2fb (unsigned int x); +LUAI_FUNC int luaO_fb2int (int x); +LUAI_FUNC int luaO_utf8esc (char *buff, unsigned long x); +LUAI_FUNC int luaO_ceillog2 (unsigned int x); +LUAI_FUNC void luaO_arith (lua_State *L, int op, const TValue *p1, + const TValue *p2, TValue *res); +LUAI_FUNC size_t luaO_str2num (const char *s, TValue *o); +LUAI_FUNC int luaO_hexavalue (int c); +LUAI_FUNC void luaO_tostring (lua_State *L, StkId obj); +LUAI_FUNC const char *luaO_pushvfstring (lua_State *L, const char *fmt, + va_list argp); +LUAI_FUNC const char *luaO_pushfstring (lua_State *L, const char *fmt, ...); +LUAI_FUNC void luaO_chunkid (char *out, const char *source, size_t len); + + +#endif + diff --git a/depends/lua/include/lopcodes.h b/depends/lua/include/lopcodes.h new file mode 100644 index 0000000000..6feaa1cd07 --- /dev/null +++ b/depends/lua/include/lopcodes.h @@ -0,0 +1,297 @@ +/* +** $Id: lopcodes.h,v 1.149.1.1 2017/04/19 17:20:42 roberto Exp $ +** Opcodes for Lua virtual machine +** See Copyright Notice in lua.h +*/ + +#ifndef lopcodes_h +#define lopcodes_h + +#include "llimits.h" + + +/*=========================================================================== + We assume that instructions are unsigned numbers. + All instructions have an opcode in the first 6 bits. + Instructions can have the following fields: + 'A' : 8 bits + 'B' : 9 bits + 'C' : 9 bits + 'Ax' : 26 bits ('A', 'B', and 'C' together) + 'Bx' : 18 bits ('B' and 'C' together) + 'sBx' : signed Bx + + A signed argument is represented in excess K; that is, the number + value is the unsigned value minus K. K is exactly the maximum value + for that argument (so that -max is represented by 0, and +max is + represented by 2*max), which is half the maximum for the corresponding + unsigned argument. +===========================================================================*/ + + +enum OpMode {iABC, iABx, iAsBx, iAx}; /* basic instruction format */ + + +/* +** size and position of opcode arguments. +*/ +#define SIZE_C 9 +#define SIZE_B 9 +#define SIZE_Bx (SIZE_C + SIZE_B) +#define SIZE_A 8 +#define SIZE_Ax (SIZE_C + SIZE_B + SIZE_A) + +#define SIZE_OP 6 + +#define POS_OP 0 +#define POS_A (POS_OP + SIZE_OP) +#define POS_C (POS_A + SIZE_A) +#define POS_B (POS_C + SIZE_C) +#define POS_Bx POS_C +#define POS_Ax POS_A + + +/* +** limits for opcode arguments. +** we use (signed) int to manipulate most arguments, +** so they must fit in LUAI_BITSINT-1 bits (-1 for sign) +*/ +#if SIZE_Bx < LUAI_BITSINT-1 +#define MAXARG_Bx ((1<>1) /* 'sBx' is signed */ +#else +#define MAXARG_Bx MAX_INT +#define MAXARG_sBx MAX_INT +#endif + +#if SIZE_Ax < LUAI_BITSINT-1 +#define MAXARG_Ax ((1<>POS_OP) & MASK1(SIZE_OP,0))) +#define SET_OPCODE(i,o) ((i) = (((i)&MASK0(SIZE_OP,POS_OP)) | \ + ((cast(Instruction, o)<>pos) & MASK1(size,0))) +#define setarg(i,v,pos,size) ((i) = (((i)&MASK0(size,pos)) | \ + ((cast(Instruction, v)<> RK(C) */ +OP_UNM,/* A B R(A) := -R(B) */ +OP_BNOT,/* A B R(A) := ~R(B) */ +OP_NOT,/* A B R(A) := not R(B) */ +OP_LEN,/* A B R(A) := length of R(B) */ + +OP_CONCAT,/* A B C R(A) := R(B).. ... ..R(C) */ + +OP_JMP,/* A sBx pc+=sBx; if (A) close all upvalues >= R(A - 1) */ +OP_EQ,/* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */ +OP_LT,/* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */ +OP_LE,/* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */ + +OP_TEST,/* A C if not (R(A) <=> C) then pc++ */ +OP_TESTSET,/* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */ + +OP_CALL,/* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */ +OP_TAILCALL,/* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */ +OP_RETURN,/* A B return R(A), ... ,R(A+B-2) (see note) */ + +OP_FORLOOP,/* A sBx R(A)+=R(A+2); + if R(A) > 4) & 3)) +#define getCMode(m) (cast(enum OpArgMask, (luaP_opmodes[m] >> 2) & 3)) +#define testAMode(m) (luaP_opmodes[m] & (1 << 6)) +#define testTMode(m) (luaP_opmodes[m] & (1 << 7)) + + +LUAI_DDEC const char *const luaP_opnames[NUM_OPCODES+1]; /* opcode names */ + + +/* number of list items to accumulate before a SETLIST instruction */ +#define LFIELDS_PER_FLUSH 50 + + +#endif diff --git a/depends/lua/include/lparser.h b/depends/lua/include/lparser.h new file mode 100644 index 0000000000..f45b23cba5 --- /dev/null +++ b/depends/lua/include/lparser.h @@ -0,0 +1,133 @@ +/* +** $Id: lparser.h,v 1.76.1.1 2017/04/19 17:20:42 roberto Exp $ +** Lua Parser +** See Copyright Notice in lua.h +*/ + +#ifndef lparser_h +#define lparser_h + +#include "llimits.h" +#include "lobject.h" +#include "lzio.h" + + +/* +** Expression and variable descriptor. +** Code generation for variables and expressions can be delayed to allow +** optimizations; An 'expdesc' structure describes a potentially-delayed +** variable/expression. It has a description of its "main" value plus a +** list of conditional jumps that can also produce its value (generated +** by short-circuit operators 'and'/'or'). +*/ + +/* kinds of variables/expressions */ +typedef enum { + VVOID, /* when 'expdesc' describes the last expression a list, + this kind means an empty list (so, no expression) */ + VNIL, /* constant nil */ + VTRUE, /* constant true */ + VFALSE, /* constant false */ + VK, /* constant in 'k'; info = index of constant in 'k' */ + VKFLT, /* floating constant; nval = numerical float value */ + VKINT, /* integer constant; nval = numerical integer value */ + VNONRELOC, /* expression has its value in a fixed register; + info = result register */ + VLOCAL, /* local variable; info = local register */ + VUPVAL, /* upvalue variable; info = index of upvalue in 'upvalues' */ + VINDEXED, /* indexed variable; + ind.vt = whether 't' is register or upvalue; + ind.t = table register or upvalue; + ind.idx = key's R/K index */ + VJMP, /* expression is a test/comparison; + info = pc of corresponding jump instruction */ + VRELOCABLE, /* expression can put result in any register; + info = instruction pc */ + VCALL, /* expression is a function call; info = instruction pc */ + VVARARG /* vararg expression; info = instruction pc */ +} expkind; + + +#define vkisvar(k) (VLOCAL <= (k) && (k) <= VINDEXED) +#define vkisinreg(k) ((k) == VNONRELOC || (k) == VLOCAL) + +typedef struct expdesc { + expkind k; + union { + lua_Integer ival; /* for VKINT */ + lua_Number nval; /* for VKFLT */ + int info; /* for generic use */ + struct { /* for indexed variables (VINDEXED) */ + short idx; /* index (R/K) */ + lu_byte t; /* table (register or upvalue) */ + lu_byte vt; /* whether 't' is register (VLOCAL) or upvalue (VUPVAL) */ + } ind; + } u; + int t; /* patch list of 'exit when true' */ + int f; /* patch list of 'exit when false' */ +} expdesc; + + +/* description of active local variable */ +typedef struct Vardesc { + short idx; /* variable index in stack */ +} Vardesc; + + +/* description of pending goto statements and label statements */ +typedef struct Labeldesc { + TString *name; /* label identifier */ + int pc; /* position in code */ + int line; /* line where it appeared */ + lu_byte nactvar; /* local level where it appears in current block */ +} Labeldesc; + + +/* list of labels or gotos */ +typedef struct Labellist { + Labeldesc *arr; /* array */ + int n; /* number of entries in use */ + int size; /* array size */ +} Labellist; + + +/* dynamic structures used by the parser */ +typedef struct Dyndata { + struct { /* list of active local variables */ + Vardesc *arr; + int n; + int size; + } actvar; + Labellist gt; /* list of pending gotos */ + Labellist label; /* list of active labels */ +} Dyndata; + + +/* control of blocks */ +struct BlockCnt; /* defined in lparser.c */ + + +/* state needed to generate code for a given function */ +typedef struct FuncState { + Proto *f; /* current function header */ + struct FuncState *prev; /* enclosing function */ + struct LexState *ls; /* lexical state */ + struct BlockCnt *bl; /* chain of current blocks */ + int pc; /* next position to code (equivalent to 'ncode') */ + int lasttarget; /* 'label' of last 'jump label' */ + int jpc; /* list of pending jumps to 'pc' */ + int nk; /* number of elements in 'k' */ + int np; /* number of elements in 'p' */ + int firstlocal; /* index of first local var (in Dyndata array) */ + short nlocvars; /* number of elements in 'f->locvars' */ + lu_byte nactvar; /* number of active local variables */ + lu_byte nups; /* number of upvalues */ + lu_byte freereg; /* first free register */ +} FuncState; + + +LUAI_FUNC LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, + Dyndata *dyd, const char *name, int firstchar); + + +#endif diff --git a/depends/lua/include/lprefix.h b/depends/lua/include/lprefix.h new file mode 100644 index 0000000000..9a749a3f30 --- /dev/null +++ b/depends/lua/include/lprefix.h @@ -0,0 +1,45 @@ +/* +** $Id: lprefix.h,v 1.2.1.1 2017/04/19 17:20:42 roberto Exp $ +** Definitions for Lua code that must come before any other header file +** See Copyright Notice in lua.h +*/ + +#ifndef lprefix_h +#define lprefix_h + + +/* +** Allows POSIX/XSI stuff +*/ +#if !defined(LUA_USE_C89) /* { */ + +#if !defined(_XOPEN_SOURCE) +#define _XOPEN_SOURCE 600 +#elif _XOPEN_SOURCE == 0 +#undef _XOPEN_SOURCE /* use -D_XOPEN_SOURCE=0 to undefine it */ +#endif + +/* +** Allows manipulation of large files in gcc and some other compilers +*/ +#if !defined(LUA_32BITS) && !defined(_FILE_OFFSET_BITS) +#define _LARGEFILE_SOURCE 1 +#define _FILE_OFFSET_BITS 64 +#endif + +#endif /* } */ + + +/* +** Windows stuff +*/ +#if defined(_WIN32) /* { */ + +#if !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS /* avoid warnings about ISO C functions */ +#endif + +#endif /* } */ + +#endif + diff --git a/depends/lua/include/lstate.h b/depends/lua/include/lstate.h new file mode 100644 index 0000000000..56b3741000 --- /dev/null +++ b/depends/lua/include/lstate.h @@ -0,0 +1,253 @@ +/* +** $Id: lstate.h,v 2.133.1.1 2017/04/19 17:39:34 roberto Exp $ +** Global State +** See Copyright Notice in lua.h +*/ + +#ifndef lstate_h +#define lstate_h + +#include "lua.h" + +#include "lobject.h" +#include "ltm.h" +#include "lzio.h" + + +/* + +** Some notes about garbage-collected objects: All objects in Lua must +** be kept somehow accessible until being freed, so all objects always +** belong to one (and only one) of these lists, using field 'next' of +** the 'CommonHeader' for the link: +** +** 'allgc': all objects not marked for finalization; +** 'finobj': all objects marked for finalization; +** 'tobefnz': all objects ready to be finalized; +** 'fixedgc': all objects that are not to be collected (currently +** only small strings, such as reserved words). +** +** Moreover, there is another set of lists that control gray objects. +** These lists are linked by fields 'gclist'. (All objects that +** can become gray have such a field. The field is not the same +** in all objects, but it always has this name.) Any gray object +** must belong to one of these lists, and all objects in these lists +** must be gray: +** +** 'gray': regular gray objects, still waiting to be visited. +** 'grayagain': objects that must be revisited at the atomic phase. +** That includes +** - black objects got in a write barrier; +** - all kinds of weak tables during propagation phase; +** - all threads. +** 'weak': tables with weak values to be cleared; +** 'ephemeron': ephemeron tables with white->white entries; +** 'allweak': tables with weak keys and/or weak values to be cleared. +** The last three lists are used only during the atomic phase. + +*/ + + +struct lua_longjmp; /* defined in ldo.c */ + + +/* +** Atomic type (relative to signals) to better ensure that 'lua_sethook' +** is thread safe +*/ +#if !defined(l_signalT) +#include +#define l_signalT sig_atomic_t +#endif + + +/* extra stack space to handle TM calls and some other extras */ +#define EXTRA_STACK 5 + + +#define BASIC_STACK_SIZE (2*LUA_MINSTACK) + + +/* kinds of Garbage Collection */ +#define KGC_NORMAL 0 +#define KGC_EMERGENCY 1 /* gc was forced by an allocation failure */ + + +typedef struct stringtable { + TString **hash; + int nuse; /* number of elements */ + int size; +} stringtable; + + +/* +** Information about a call. +** When a thread yields, 'func' is adjusted to pretend that the +** top function has only the yielded values in its stack; in that +** case, the actual 'func' value is saved in field 'extra'. +** When a function calls another with a continuation, 'extra' keeps +** the function index so that, in case of errors, the continuation +** function can be called with the correct top. +*/ +typedef struct CallInfo { + StkId func; /* function index in the stack */ + StkId top; /* top for this function */ + struct CallInfo *previous, *next; /* dynamic call link */ + union { + struct { /* only for Lua functions */ + StkId base; /* base for this function */ + const Instruction *savedpc; + } l; + struct { /* only for C functions */ + lua_KFunction k; /* continuation in case of yields */ + ptrdiff_t old_errfunc; + lua_KContext ctx; /* context info. in case of yields */ + } c; + } u; + ptrdiff_t extra; + short nresults; /* expected number of results from this function */ + unsigned short callstatus; +} CallInfo; + + +/* +** Bits in CallInfo status +*/ +#define CIST_OAH (1<<0) /* original value of 'allowhook' */ +#define CIST_LUA (1<<1) /* call is running a Lua function */ +#define CIST_HOOKED (1<<2) /* call is running a debug hook */ +#define CIST_FRESH (1<<3) /* call is running on a fresh invocation + of luaV_execute */ +#define CIST_YPCALL (1<<4) /* call is a yieldable protected call */ +#define CIST_TAIL (1<<5) /* call was tail called */ +#define CIST_HOOKYIELD (1<<6) /* last hook called yielded */ +#define CIST_LEQ (1<<7) /* using __lt for __le */ +#define CIST_FIN (1<<8) /* call is running a finalizer */ + +#define isLua(ci) ((ci)->callstatus & CIST_LUA) + +/* assume that CIST_OAH has offset 0 and that 'v' is strictly 0/1 */ +#define setoah(st,v) ((st) = ((st) & ~CIST_OAH) | (v)) +#define getoah(st) ((st) & CIST_OAH) + + +/* +** 'global state', shared by all threads of this state +*/ +typedef struct global_State { + lua_Alloc frealloc; /* function to reallocate memory */ + void *ud; /* auxiliary data to 'frealloc' */ + l_mem totalbytes; /* number of bytes currently allocated - GCdebt */ + l_mem GCdebt; /* bytes allocated not yet compensated by the collector */ + lu_mem GCmemtrav; /* memory traversed by the GC */ + lu_mem GCestimate; /* an estimate of the non-garbage memory in use */ + stringtable strt; /* hash table for strings */ + TValue l_registry; + unsigned int seed; /* randomized seed for hashes */ + lu_byte currentwhite; + lu_byte gcstate; /* state of garbage collector */ + lu_byte gckind; /* kind of GC running */ + lu_byte gcrunning; /* true if GC is running */ + GCObject *allgc; /* list of all collectable objects */ + GCObject **sweepgc; /* current position of sweep in list */ + GCObject *finobj; /* list of collectable objects with finalizers */ + GCObject *gray; /* list of gray objects */ + GCObject *grayagain; /* list of objects to be traversed atomically */ + GCObject *weak; /* list of tables with weak values */ + GCObject *ephemeron; /* list of ephemeron tables (weak keys) */ + GCObject *allweak; /* list of all-weak tables */ + GCObject *tobefnz; /* list of userdata to be GC */ + GCObject *fixedgc; /* list of objects not to be collected */ + struct lua_State *twups; /* list of threads with open upvalues */ + unsigned int gcfinnum; /* number of finalizers to call in each GC step */ + int gcpause; /* size of pause between successive GCs */ + int gcstepmul; /* GC 'granularity' */ + lua_CFunction panic; /* to be called in unprotected errors */ + struct lua_State *mainthread; + const lua_Number *version; /* pointer to version number */ + TString *memerrmsg; /* memory-error message */ + TString *tmname[TM_N]; /* array with tag-method names */ + struct Table *mt[LUA_NUMTAGS]; /* metatables for basic types */ + TString *strcache[STRCACHE_N][STRCACHE_M]; /* cache for strings in API */ +} global_State; + + +/* +** 'per thread' state +*/ +struct lua_State { + CommonHeader; + unsigned short nci; /* number of items in 'ci' list */ + lu_byte status; + StkId top; /* first free slot in the stack */ + global_State *l_G; + CallInfo *ci; /* call info for current function */ + const Instruction *oldpc; /* last pc traced */ + StkId stack_last; /* last free slot in the stack */ + StkId stack; /* stack base */ + UpVal *openupval; /* list of open upvalues in this stack */ + GCObject *gclist; + struct lua_State *twups; /* list of threads with open upvalues */ + struct lua_longjmp *errorJmp; /* current error recover point */ + CallInfo base_ci; /* CallInfo for first level (C calling Lua) */ + volatile lua_Hook hook; + ptrdiff_t errfunc; /* current error handling function (stack index) */ + int stacksize; + int basehookcount; + int hookcount; + unsigned short nny; /* number of non-yieldable calls in stack */ + unsigned short nCcalls; /* number of nested C calls */ + l_signalT hookmask; + lu_byte allowhook; +}; + + +#define G(L) (L->l_G) + + +/* +** Union of all collectable objects (only for conversions) +*/ +union GCUnion { + GCObject gc; /* common header */ + struct TString ts; + struct Udata u; + union Closure cl; + struct Table h; + struct Proto p; + struct lua_State th; /* thread */ +}; + + +#define cast_u(o) cast(union GCUnion *, (o)) + +/* macros to convert a GCObject into a specific value */ +#define gco2ts(o) \ + check_exp(novariant((o)->tt) == LUA_TSTRING, &((cast_u(o))->ts)) +#define gco2u(o) check_exp((o)->tt == LUA_TUSERDATA, &((cast_u(o))->u)) +#define gco2lcl(o) check_exp((o)->tt == LUA_TLCL, &((cast_u(o))->cl.l)) +#define gco2ccl(o) check_exp((o)->tt == LUA_TCCL, &((cast_u(o))->cl.c)) +#define gco2cl(o) \ + check_exp(novariant((o)->tt) == LUA_TFUNCTION, &((cast_u(o))->cl)) +#define gco2t(o) check_exp((o)->tt == LUA_TTABLE, &((cast_u(o))->h)) +#define gco2p(o) check_exp((o)->tt == LUA_TPROTO, &((cast_u(o))->p)) +#define gco2th(o) check_exp((o)->tt == LUA_TTHREAD, &((cast_u(o))->th)) + + +/* macro to convert a Lua object into a GCObject */ +#define obj2gco(v) \ + check_exp(novariant((v)->tt) < LUA_TDEADKEY, (&(cast_u(v)->gc))) + + +/* actual number of total bytes allocated */ +#define gettotalbytes(g) cast(lu_mem, (g)->totalbytes + (g)->GCdebt) + +LUAI_FUNC void luaE_setdebt (global_State *g, l_mem debt); +LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1); +LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L); +LUAI_FUNC void luaE_freeCI (lua_State *L); +LUAI_FUNC void luaE_shrinkCI (lua_State *L); + + +#endif + diff --git a/depends/lua/include/lstring.h b/depends/lua/include/lstring.h new file mode 100644 index 0000000000..d612abd333 --- /dev/null +++ b/depends/lua/include/lstring.h @@ -0,0 +1,49 @@ +/* +** $Id: lstring.h,v 1.61.1.1 2017/04/19 17:20:42 roberto Exp $ +** String table (keep all strings handled by Lua) +** See Copyright Notice in lua.h +*/ + +#ifndef lstring_h +#define lstring_h + +#include "lgc.h" +#include "lobject.h" +#include "lstate.h" + + +#define sizelstring(l) (sizeof(union UTString) + ((l) + 1) * sizeof(char)) + +#define sizeludata(l) (sizeof(union UUdata) + (l)) +#define sizeudata(u) sizeludata((u)->len) + +#define luaS_newliteral(L, s) (luaS_newlstr(L, "" s, \ + (sizeof(s)/sizeof(char))-1)) + + +/* +** test whether a string is a reserved word +*/ +#define isreserved(s) ((s)->tt == LUA_TSHRSTR && (s)->extra > 0) + + +/* +** equality for short strings, which are always internalized +*/ +#define eqshrstr(a,b) check_exp((a)->tt == LUA_TSHRSTR, (a) == (b)) + + +LUAI_FUNC unsigned int luaS_hash (const char *str, size_t l, unsigned int seed); +LUAI_FUNC unsigned int luaS_hashlongstr (TString *ts); +LUAI_FUNC int luaS_eqlngstr (TString *a, TString *b); +LUAI_FUNC void luaS_resize (lua_State *L, int newsize); +LUAI_FUNC void luaS_clearcache (global_State *g); +LUAI_FUNC void luaS_init (lua_State *L); +LUAI_FUNC void luaS_remove (lua_State *L, TString *ts); +LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s); +LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l); +LUAI_FUNC TString *luaS_new (lua_State *L, const char *str); +LUAI_FUNC TString *luaS_createlngstrobj (lua_State *L, size_t l); + + +#endif diff --git a/depends/lua/include/ltable.h b/depends/lua/include/ltable.h new file mode 100644 index 0000000000..92db0ac7bf --- /dev/null +++ b/depends/lua/include/ltable.h @@ -0,0 +1,66 @@ +/* +** $Id: ltable.h,v 2.23.1.2 2018/05/24 19:39:05 roberto Exp $ +** Lua tables (hash) +** See Copyright Notice in lua.h +*/ + +#ifndef ltable_h +#define ltable_h + +#include "lobject.h" + + +#define gnode(t,i) (&(t)->node[i]) +#define gval(n) (&(n)->i_val) +#define gnext(n) ((n)->i_key.nk.next) + + +/* 'const' to avoid wrong writings that can mess up field 'next' */ +#define gkey(n) cast(const TValue*, (&(n)->i_key.tvk)) + +/* +** writable version of 'gkey'; allows updates to individual fields, +** but not to the whole (which has incompatible type) +*/ +#define wgkey(n) (&(n)->i_key.nk) + +#define invalidateTMcache(t) ((t)->flags = 0) + + +/* true when 't' is using 'dummynode' as its hash part */ +#define isdummy(t) ((t)->lastfree == NULL) + + +/* allocated size for hash nodes */ +#define allocsizenode(t) (isdummy(t) ? 0 : sizenode(t)) + + +/* returns the key, given the value of a table entry */ +#define keyfromval(v) \ + (gkey(cast(Node *, cast(char *, (v)) - offsetof(Node, i_val)))) + + +LUAI_FUNC const TValue *luaH_getint (Table *t, lua_Integer key); +LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key, + TValue *value); +LUAI_FUNC const TValue *luaH_getshortstr (Table *t, TString *key); +LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key); +LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key); +LUAI_FUNC TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key); +LUAI_FUNC TValue *luaH_set (lua_State *L, Table *t, const TValue *key); +LUAI_FUNC Table *luaH_new (lua_State *L); +LUAI_FUNC void luaH_resize (lua_State *L, Table *t, unsigned int nasize, + unsigned int nhsize); +LUAI_FUNC void luaH_resizearray (lua_State *L, Table *t, unsigned int nasize); +LUAI_FUNC void luaH_free (lua_State *L, Table *t); +LUAI_FUNC int luaH_next (lua_State *L, Table *t, StkId key); +LUAI_FUNC lua_Unsigned luaH_getn (Table *t); + + +#if defined(LUA_DEBUG) +LUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key); +LUAI_FUNC int luaH_isdummy (const Table *t); +#endif + + +#endif diff --git a/depends/lua/include/ltm.h b/depends/lua/include/ltm.h new file mode 100644 index 0000000000..8170688dae --- /dev/null +++ b/depends/lua/include/ltm.h @@ -0,0 +1,76 @@ +/* +** $Id: ltm.h,v 2.22.1.1 2017/04/19 17:20:42 roberto Exp $ +** Tag methods +** See Copyright Notice in lua.h +*/ + +#ifndef ltm_h +#define ltm_h + + +#include "lobject.h" + + +/* +* WARNING: if you change the order of this enumeration, +* grep "ORDER TM" and "ORDER OP" +*/ +typedef enum { + TM_INDEX, + TM_NEWINDEX, + TM_GC, + TM_MODE, + TM_LEN, + TM_EQ, /* last tag method with fast access */ + TM_ADD, + TM_SUB, + TM_MUL, + TM_MOD, + TM_POW, + TM_DIV, + TM_IDIV, + TM_BAND, + TM_BOR, + TM_BXOR, + TM_SHL, + TM_SHR, + TM_UNM, + TM_BNOT, + TM_LT, + TM_LE, + TM_CONCAT, + TM_CALL, + TM_N /* number of elements in the enum */ +} TMS; + + + +#define gfasttm(g,et,e) ((et) == NULL ? NULL : \ + ((et)->flags & (1u<<(e))) ? NULL : luaT_gettm(et, e, (g)->tmname[e])) + +#define fasttm(l,et,e) gfasttm(G(l), et, e) + +#define ttypename(x) luaT_typenames_[(x) + 1] + +LUAI_DDEC const char *const luaT_typenames_[LUA_TOTALTAGS]; + + +LUAI_FUNC const char *luaT_objtypename (lua_State *L, const TValue *o); + +LUAI_FUNC const TValue *luaT_gettm (Table *events, TMS event, TString *ename); +LUAI_FUNC const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, + TMS event); +LUAI_FUNC void luaT_init (lua_State *L); + +LUAI_FUNC void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1, + const TValue *p2, TValue *p3, int hasres); +LUAI_FUNC int luaT_callbinTM (lua_State *L, const TValue *p1, const TValue *p2, + StkId res, TMS event); +LUAI_FUNC void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2, + StkId res, TMS event); +LUAI_FUNC int luaT_callorderTM (lua_State *L, const TValue *p1, + const TValue *p2, TMS event); + + + +#endif diff --git a/depends/lua/include/lua.h b/depends/lua/include/lua.h new file mode 100644 index 0000000000..9394c5ef8f --- /dev/null +++ b/depends/lua/include/lua.h @@ -0,0 +1,485 @@ +/* +** Lua - A Scripting Language +** Lua.org, PUC-Rio, Brazil (http://www.lua.org) +** See Copyright Notice at the end of this file +*/ + + +#ifndef lua_h +#define lua_h + +#include +#include + + +#include "luaconf.h" + + +#define LUA_VERSION_MAJOR "5" +#define LUA_VERSION_MINOR "3" +#define LUA_VERSION_NUM 503 +#define LUA_VERSION_RELEASE "6" + +#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR +#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE +#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2020 Lua.org, PUC-Rio" +#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes" + + +/* mark for precompiled code ('Lua') */ +#define LUA_SIGNATURE "\x1bLua" + +/* option for multiple returns in 'lua_pcall' and 'lua_call' */ +#define LUA_MULTRET (-1) + + +/* +** Pseudo-indices +** (-LUAI_MAXSTACK is the minimum valid index; we keep some free empty +** space after that to help overflow detection) +*/ +#define LUA_REGISTRYINDEX (-LUAI_MAXSTACK - 1000) +#define lua_upvalueindex(i) (LUA_REGISTRYINDEX - (i)) + + +/* thread status */ +#define LUA_OK 0 +#define LUA_YIELD 1 +#define LUA_ERRRUN 2 +#define LUA_ERRSYNTAX 3 +#define LUA_ERRMEM 4 +#define LUA_ERRGCMM 5 +#define LUA_ERRERR 6 + + +typedef struct lua_State lua_State; + + +/* +** basic types +*/ +#define LUA_TNONE (-1) + +#define LUA_TNIL 0 +#define LUA_TBOOLEAN 1 +#define LUA_TLIGHTUSERDATA 2 +#define LUA_TNUMBER 3 +#define LUA_TSTRING 4 +#define LUA_TTABLE 5 +#define LUA_TFUNCTION 6 +#define LUA_TUSERDATA 7 +#define LUA_TTHREAD 8 + +#define LUA_NUMTAGS 9 + + + +/* minimum Lua stack available to a C function */ +#define LUA_MINSTACK 20 + + +/* predefined values in the registry */ +#define LUA_RIDX_MAINTHREAD 1 +#define LUA_RIDX_GLOBALS 2 +#define LUA_RIDX_LAST LUA_RIDX_GLOBALS + + +/* type of numbers in Lua */ +typedef LUA_NUMBER lua_Number; + + +/* type for integer functions */ +typedef LUA_INTEGER lua_Integer; + +/* unsigned integer type */ +typedef LUA_UNSIGNED lua_Unsigned; + +/* type for continuation-function contexts */ +typedef LUA_KCONTEXT lua_KContext; + + +/* +** Type for C functions registered with Lua +*/ +typedef int (*lua_CFunction) (lua_State *L); + +/* +** Type for continuation functions +*/ +typedef int (*lua_KFunction) (lua_State *L, int status, lua_KContext ctx); + + +/* +** Type for functions that read/write blocks when loading/dumping Lua chunks +*/ +typedef const char * (*lua_Reader) (lua_State *L, void *ud, size_t *sz); + +typedef int (*lua_Writer) (lua_State *L, const void *p, size_t sz, void *ud); + + +/* +** Type for memory-allocation functions +*/ +typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize); + + + +/* +** generic extra include file +*/ +#if defined(LUA_USER_H) +#include LUA_USER_H +#endif + + +/* +** RCS ident string +*/ +extern const char lua_ident[]; + + +/* +** state manipulation +*/ +LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud); +LUA_API void (lua_close) (lua_State *L); +LUA_API lua_State *(lua_newthread) (lua_State *L); + +LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf); + + +LUA_API const lua_Number *(lua_version) (lua_State *L); + + +/* +** basic stack manipulation +*/ +LUA_API int (lua_absindex) (lua_State *L, int idx); +LUA_API int (lua_gettop) (lua_State *L); +LUA_API void (lua_settop) (lua_State *L, int idx); +LUA_API void (lua_pushvalue) (lua_State *L, int idx); +LUA_API void (lua_rotate) (lua_State *L, int idx, int n); +LUA_API void (lua_copy) (lua_State *L, int fromidx, int toidx); +LUA_API int (lua_checkstack) (lua_State *L, int n); + +LUA_API void (lua_xmove) (lua_State *from, lua_State *to, int n); + + +/* +** access functions (stack -> C) +*/ + +LUA_API int (lua_isnumber) (lua_State *L, int idx); +LUA_API int (lua_isstring) (lua_State *L, int idx); +LUA_API int (lua_iscfunction) (lua_State *L, int idx); +LUA_API int (lua_isinteger) (lua_State *L, int idx); +LUA_API int (lua_isuserdata) (lua_State *L, int idx); +LUA_API int (lua_type) (lua_State *L, int idx); +LUA_API const char *(lua_typename) (lua_State *L, int tp); + +LUA_API lua_Number (lua_tonumberx) (lua_State *L, int idx, int *isnum); +LUA_API lua_Integer (lua_tointegerx) (lua_State *L, int idx, int *isnum); +LUA_API int (lua_toboolean) (lua_State *L, int idx); +LUA_API const char *(lua_tolstring) (lua_State *L, int idx, size_t *len); +LUA_API size_t (lua_rawlen) (lua_State *L, int idx); +LUA_API lua_CFunction (lua_tocfunction) (lua_State *L, int idx); +LUA_API void *(lua_touserdata) (lua_State *L, int idx); +LUA_API lua_State *(lua_tothread) (lua_State *L, int idx); +LUA_API const void *(lua_topointer) (lua_State *L, int idx); + + +/* +** Comparison and arithmetic functions +*/ + +#define LUA_OPADD 0 /* ORDER TM, ORDER OP */ +#define LUA_OPSUB 1 +#define LUA_OPMUL 2 +#define LUA_OPMOD 3 +#define LUA_OPPOW 4 +#define LUA_OPDIV 5 +#define LUA_OPIDIV 6 +#define LUA_OPBAND 7 +#define LUA_OPBOR 8 +#define LUA_OPBXOR 9 +#define LUA_OPSHL 10 +#define LUA_OPSHR 11 +#define LUA_OPUNM 12 +#define LUA_OPBNOT 13 + +LUA_API void (lua_arith) (lua_State *L, int op); + +#define LUA_OPEQ 0 +#define LUA_OPLT 1 +#define LUA_OPLE 2 + +LUA_API int (lua_rawequal) (lua_State *L, int idx1, int idx2); +LUA_API int (lua_compare) (lua_State *L, int idx1, int idx2, int op); + + +/* +** push functions (C -> stack) +*/ +LUA_API void (lua_pushnil) (lua_State *L); +LUA_API void (lua_pushnumber) (lua_State *L, lua_Number n); +LUA_API void (lua_pushinteger) (lua_State *L, lua_Integer n); +LUA_API const char *(lua_pushlstring) (lua_State *L, const char *s, size_t len); +LUA_API const char *(lua_pushstring) (lua_State *L, const char *s); +LUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt, + va_list argp); +LUA_API const char *(lua_pushfstring) (lua_State *L, const char *fmt, ...); +LUA_API void (lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n); +LUA_API void (lua_pushboolean) (lua_State *L, int b); +LUA_API void (lua_pushlightuserdata) (lua_State *L, void *p); +LUA_API int (lua_pushthread) (lua_State *L); + + +/* +** get functions (Lua -> stack) +*/ +LUA_API int (lua_getglobal) (lua_State *L, const char *name); +LUA_API int (lua_gettable) (lua_State *L, int idx); +LUA_API int (lua_getfield) (lua_State *L, int idx, const char *k); +LUA_API int (lua_geti) (lua_State *L, int idx, lua_Integer n); +LUA_API int (lua_rawget) (lua_State *L, int idx); +LUA_API int (lua_rawgeti) (lua_State *L, int idx, lua_Integer n); +LUA_API int (lua_rawgetp) (lua_State *L, int idx, const void *p); + +LUA_API void (lua_createtable) (lua_State *L, int narr, int nrec); +LUA_API void *(lua_newuserdata) (lua_State *L, size_t sz); +LUA_API int (lua_getmetatable) (lua_State *L, int objindex); +LUA_API int (lua_getuservalue) (lua_State *L, int idx); + + +/* +** set functions (stack -> Lua) +*/ +LUA_API void (lua_setglobal) (lua_State *L, const char *name); +LUA_API void (lua_settable) (lua_State *L, int idx); +LUA_API void (lua_setfield) (lua_State *L, int idx, const char *k); +LUA_API void (lua_seti) (lua_State *L, int idx, lua_Integer n); +LUA_API void (lua_rawset) (lua_State *L, int idx); +LUA_API void (lua_rawseti) (lua_State *L, int idx, lua_Integer n); +LUA_API void (lua_rawsetp) (lua_State *L, int idx, const void *p); +LUA_API int (lua_setmetatable) (lua_State *L, int objindex); +LUA_API void (lua_setuservalue) (lua_State *L, int idx); + + +/* +** 'load' and 'call' functions (load and run Lua code) +*/ +LUA_API void (lua_callk) (lua_State *L, int nargs, int nresults, + lua_KContext ctx, lua_KFunction k); +#define lua_call(L,n,r) lua_callk(L, (n), (r), 0, NULL) + +LUA_API int (lua_pcallk) (lua_State *L, int nargs, int nresults, int errfunc, + lua_KContext ctx, lua_KFunction k); +#define lua_pcall(L,n,r,f) lua_pcallk(L, (n), (r), (f), 0, NULL) + +LUA_API int (lua_load) (lua_State *L, lua_Reader reader, void *dt, + const char *chunkname, const char *mode); + +LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data, int strip); + + +/* +** coroutine functions +*/ +LUA_API int (lua_yieldk) (lua_State *L, int nresults, lua_KContext ctx, + lua_KFunction k); +LUA_API int (lua_resume) (lua_State *L, lua_State *from, int narg); +LUA_API int (lua_status) (lua_State *L); +LUA_API int (lua_isyieldable) (lua_State *L); + +#define lua_yield(L,n) lua_yieldk(L, (n), 0, NULL) + + +/* +** garbage-collection function and options +*/ + +#define LUA_GCSTOP 0 +#define LUA_GCRESTART 1 +#define LUA_GCCOLLECT 2 +#define LUA_GCCOUNT 3 +#define LUA_GCCOUNTB 4 +#define LUA_GCSTEP 5 +#define LUA_GCSETPAUSE 6 +#define LUA_GCSETSTEPMUL 7 +#define LUA_GCISRUNNING 9 + +LUA_API int (lua_gc) (lua_State *L, int what, int data); + + +/* +** miscellaneous functions +*/ + +LUA_API int (lua_error) (lua_State *L); + +LUA_API int (lua_next) (lua_State *L, int idx); + +LUA_API void (lua_concat) (lua_State *L, int n); +LUA_API void (lua_len) (lua_State *L, int idx); + +LUA_API size_t (lua_stringtonumber) (lua_State *L, const char *s); + +LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud); +LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud); + + + +/* +** {============================================================== +** some useful macros +** =============================================================== +*/ + +#define lua_getextraspace(L) ((void *)((char *)(L) - LUA_EXTRASPACE)) + +#define lua_tonumber(L,i) lua_tonumberx(L,(i),NULL) +#define lua_tointeger(L,i) lua_tointegerx(L,(i),NULL) + +#define lua_pop(L,n) lua_settop(L, -(n)-1) + +#define lua_newtable(L) lua_createtable(L, 0, 0) + +#define lua_register(L,n,f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n))) + +#define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0) + +#define lua_isfunction(L,n) (lua_type(L, (n)) == LUA_TFUNCTION) +#define lua_istable(L,n) (lua_type(L, (n)) == LUA_TTABLE) +#define lua_islightuserdata(L,n) (lua_type(L, (n)) == LUA_TLIGHTUSERDATA) +#define lua_isnil(L,n) (lua_type(L, (n)) == LUA_TNIL) +#define lua_isboolean(L,n) (lua_type(L, (n)) == LUA_TBOOLEAN) +#define lua_isthread(L,n) (lua_type(L, (n)) == LUA_TTHREAD) +#define lua_isnone(L,n) (lua_type(L, (n)) == LUA_TNONE) +#define lua_isnoneornil(L, n) (lua_type(L, (n)) <= 0) + +#define lua_pushliteral(L, s) lua_pushstring(L, "" s) + +#define lua_pushglobaltable(L) \ + ((void)lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS)) + +#define lua_tostring(L,i) lua_tolstring(L, (i), NULL) + + +#define lua_insert(L,idx) lua_rotate(L, (idx), 1) + +#define lua_remove(L,idx) (lua_rotate(L, (idx), -1), lua_pop(L, 1)) + +#define lua_replace(L,idx) (lua_copy(L, -1, (idx)), lua_pop(L, 1)) + +/* }============================================================== */ + + +/* +** {============================================================== +** compatibility macros for unsigned conversions +** =============================================================== +*/ +#if defined(LUA_COMPAT_APIINTCASTS) + +#define lua_pushunsigned(L,n) lua_pushinteger(L, (lua_Integer)(n)) +#define lua_tounsignedx(L,i,is) ((lua_Unsigned)lua_tointegerx(L,i,is)) +#define lua_tounsigned(L,i) lua_tounsignedx(L,(i),NULL) + +#endif +/* }============================================================== */ + +/* +** {====================================================================== +** Debug API +** ======================================================================= +*/ + + +/* +** Event codes +*/ +#define LUA_HOOKCALL 0 +#define LUA_HOOKRET 1 +#define LUA_HOOKLINE 2 +#define LUA_HOOKCOUNT 3 +#define LUA_HOOKTAILCALL 4 + + +/* +** Event masks +*/ +#define LUA_MASKCALL (1 << LUA_HOOKCALL) +#define LUA_MASKRET (1 << LUA_HOOKRET) +#define LUA_MASKLINE (1 << LUA_HOOKLINE) +#define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT) + +typedef struct lua_Debug lua_Debug; /* activation record */ + + +/* Functions to be called by the debugger in specific events */ +typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar); + + +LUA_API int (lua_getstack) (lua_State *L, int level, lua_Debug *ar); +LUA_API int (lua_getinfo) (lua_State *L, const char *what, lua_Debug *ar); +LUA_API const char *(lua_getlocal) (lua_State *L, const lua_Debug *ar, int n); +LUA_API const char *(lua_setlocal) (lua_State *L, const lua_Debug *ar, int n); +LUA_API const char *(lua_getupvalue) (lua_State *L, int funcindex, int n); +LUA_API const char *(lua_setupvalue) (lua_State *L, int funcindex, int n); + +LUA_API void *(lua_upvalueid) (lua_State *L, int fidx, int n); +LUA_API void (lua_upvaluejoin) (lua_State *L, int fidx1, int n1, + int fidx2, int n2); + +LUA_API void (lua_sethook) (lua_State *L, lua_Hook func, int mask, int count); +LUA_API lua_Hook (lua_gethook) (lua_State *L); +LUA_API int (lua_gethookmask) (lua_State *L); +LUA_API int (lua_gethookcount) (lua_State *L); + + +struct lua_Debug { + int event; + const char *name; /* (n) */ + const char *namewhat; /* (n) 'global', 'local', 'field', 'method' */ + const char *what; /* (S) 'Lua', 'C', 'main', 'tail' */ + const char *source; /* (S) */ + int currentline; /* (l) */ + int linedefined; /* (S) */ + int lastlinedefined; /* (S) */ + unsigned char nups; /* (u) number of upvalues */ + unsigned char nparams;/* (u) number of parameters */ + char isvararg; /* (u) */ + char istailcall; /* (t) */ + char short_src[LUA_IDSIZE]; /* (S) */ + /* private part */ + struct CallInfo *i_ci; /* active function */ +}; + +/* }====================================================================== */ + + +/****************************************************************************** +* Copyright (C) 1994-2020 Lua.org, PUC-Rio. +* +* 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. +******************************************************************************/ + + +#endif diff --git a/depends/lua/include/luaconf.h b/depends/lua/include/luaconf.h new file mode 100644 index 0000000000..ffdfe05953 --- /dev/null +++ b/depends/lua/include/luaconf.h @@ -0,0 +1,803 @@ +/* +** $Id: luaconf.h,v 1.259.1.1 2017/04/19 17:29:57 roberto Exp $ +** Configuration file for Lua +** See Copyright Notice in lua.h +*/ + + +#ifndef luaconf_h +#define luaconf_h + +#include +#include + +// !! BEGIN DFHack modifications: compatibility +#define LUA_COMPAT_APIINTCASTS +#define LUA_COMPAT_IPAIRS + +// Patch for old glibc versions +#if !defined(LLONG_MAX) && defined(__LONG_LONG_MAX__) +#define LLONG_MAX __LONG_LONG_MAX__ +#endif + +#if !defined(LLONG_MIN) && defined(__LONG_LONG_MAX__) +#define LLONG_MIN (-__LONG_LONG_MAX__ - 1LL) +#endif +// !! END DFHack modifications: compatibility + +/* +** =================================================================== +** Search for "@@" to find all configurable definitions. +** =================================================================== +*/ + + +/* +** {==================================================================== +** System Configuration: macros to adapt (if needed) Lua to some +** particular platform, for instance compiling it with 32-bit numbers or +** restricting it to C89. +** ===================================================================== +*/ + +/* +@@ LUA_32BITS enables Lua with 32-bit integers and 32-bit floats. You +** can also define LUA_32BITS in the make file, but changing here you +** ensure that all software connected to Lua will be compiled with the +** same configuration. +*/ +/* #define LUA_32BITS */ + + +/* +@@ LUA_USE_C89 controls the use of non-ISO-C89 features. +** Define it if you want Lua to avoid the use of a few C99 features +** or Windows-specific features on Windows. +*/ +/* #define LUA_USE_C89 */ + + +/* +** By default, Lua on Windows use (some) specific Windows features +*/ +#if !defined(LUA_USE_C89) && defined(_WIN32) && !defined(_WIN32_WCE) +#define LUA_USE_WINDOWS /* enable goodies for regular Windows */ +#endif + + +#if defined(LUA_USE_WINDOWS) +#define LUA_DL_DLL /* enable support for DLL */ +#define LUA_USE_C89 /* broadly, Windows is C89 */ +#endif + + +#if defined(LUA_USE_LINUX) +#define LUA_USE_POSIX +#define LUA_USE_DLOPEN /* needs an extra library: -ldl */ +#define LUA_USE_READLINE /* needs some extra libraries */ +#endif + + +#if defined(LUA_USE_MACOSX) +#define LUA_USE_POSIX +#define LUA_USE_DLOPEN /* MacOS does not need -ldl */ +#define LUA_USE_READLINE /* needs an extra library: -lreadline */ +#endif + + +/* +@@ LUA_C89_NUMBERS ensures that Lua uses the largest types available for +** C89 ('long' and 'double'); Windows always has '__int64', so it does +** not need to use this case. +*/ +#if defined(LUA_USE_C89) && !defined(LUA_USE_WINDOWS) +#define LUA_C89_NUMBERS +#endif + + + +/* +@@ LUAI_BITSINT defines the (minimum) number of bits in an 'int'. +*/ +/* avoid undefined shifts */ +#if ((INT_MAX >> 15) >> 15) >= 1 +#define LUAI_BITSINT 32 +#else +/* 'int' always must have at least 16 bits */ +#define LUAI_BITSINT 16 +#endif + + +/* +@@ LUA_INT_TYPE defines the type for Lua integers. +@@ LUA_FLOAT_TYPE defines the type for Lua floats. +** Lua should work fine with any mix of these options (if supported +** by your C compiler). The usual configurations are 64-bit integers +** and 'double' (the default), 32-bit integers and 'float' (for +** restricted platforms), and 'long'/'double' (for C compilers not +** compliant with C99, which may not have support for 'long long'). +*/ + +/* predefined options for LUA_INT_TYPE */ +#define LUA_INT_INT 1 +#define LUA_INT_LONG 2 +#define LUA_INT_LONGLONG 3 + +/* predefined options for LUA_FLOAT_TYPE */ +#define LUA_FLOAT_FLOAT 1 +#define LUA_FLOAT_DOUBLE 2 +#define LUA_FLOAT_LONGDOUBLE 3 + +#if defined(LUA_32BITS) /* { */ +/* +** 32-bit integers and 'float' +*/ +#if LUAI_BITSINT >= 32 /* use 'int' if big enough */ +#define LUA_INT_TYPE LUA_INT_INT +#else /* otherwise use 'long' */ +#define LUA_INT_TYPE LUA_INT_LONG +#endif +#define LUA_FLOAT_TYPE LUA_FLOAT_FLOAT + +#elif defined(LUA_C89_NUMBERS) /* }{ */ +/* +** largest types available for C89 ('long' and 'double') +*/ +#define LUA_INT_TYPE LUA_INT_LONG +#define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE + +#endif /* } */ + + +/* +** default configuration for 64-bit Lua ('long long' and 'double') +*/ +#if !defined(LUA_INT_TYPE) +#define LUA_INT_TYPE LUA_INT_LONGLONG +#endif + +#if !defined(LUA_FLOAT_TYPE) +#define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE +#endif + +/* }================================================================== */ + + + + +/* +** {================================================================== +** Configuration for Paths. +** =================================================================== +*/ + +/* +** LUA_PATH_SEP is the character that separates templates in a path. +** LUA_PATH_MARK is the string that marks the substitution points in a +** template. +** LUA_EXEC_DIR in a Windows path is replaced by the executable's +** directory. +*/ +#define LUA_PATH_SEP ";" +#define LUA_PATH_MARK "?" +#define LUA_EXEC_DIR "!" + + +// !! BEGIN DFHack modifications: library paths +/* +@@ LUA_PATH_DEFAULT is the default path that Lua uses to look for +** Lua libraries. +@@ LUA_CPATH_DEFAULT is the default path that Lua uses to look for +** C libraries. +** CHANGE them if your machine has a non-conventional directory +** hierarchy or if you want to install your libraries in +** non-conventional directories. +*/ +#if defined(_WIN32) /* { */ +/* +** In Windows, any exclamation mark ('!') in the path is replaced by the +** path of the directory of the executable file of the current process. +*/ +#define LUA_LDIR "!\\hack\\lua\\" +#define LUA_CDIR "!\\" +#define LUA_PATH_DEFAULT \ + LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" ".\\?.lua" +#define LUA_CPATH_DEFAULT \ + LUA_CDIR"?.dll;" ".\\?.dll" + +#else /* }{ */ + +#define LUA_LDIR "./hack/lua/" +#define LUA_CDIR "./hack/" +#define LUA_PATH_DEFAULT \ + LUA_LDIR"?.lua;" LUA_LDIR"?/init.lua;" "./?.lua" +#define LUA_CPATH_DEFAULT \ + LUA_CDIR"?.so;" "./?.so" +#endif /* } */ + +#define LUA_PATH_VAR "DFHACK_LUA_PATH" +#define LUA_CPATH_VAR "DFHACK_LUA_CPATH" +// !! END DFHack modifications: library paths + +/* +@@ LUA_DIRSEP is the directory separator (for submodules). +** CHANGE it if your machine does not use "/" as the directory separator +** and is not Windows. (On Windows Lua automatically uses "\".) +*/ +#if defined(_WIN32) +#define LUA_DIRSEP "\\" +#else +#define LUA_DIRSEP "/" +#endif + +/* }================================================================== */ + + +/* +** {================================================================== +** Marks for exported symbols in the C code +** =================================================================== +*/ + +/* +@@ LUA_API is a mark for all core API functions. +@@ LUALIB_API is a mark for all auxiliary library functions. +@@ LUAMOD_API is a mark for all standard library opening functions. +** CHANGE them if you need to define those functions in some special way. +** For instance, if you want to create one Windows DLL with the core and +** the libraries, you may want to use the following definition (define +** LUA_BUILD_AS_DLL to get it). +*/ +#if defined(LUA_BUILD_AS_DLL) /* { */ + +// !! BEGIN DFHack modifications: symbol exporting +#if defined(_MSC_VER) +#if defined(LUA_CORE) || defined(LUA_LIB) /* { */ +#define LUA_API __declspec(dllexport) +#else /* }{ */ +#define LUA_API __declspec(dllimport) +#endif /* } */ +#else +#define LUA_API __attribute__ ((visibility("default"))) +#endif +// !! END DFHack modifications: symbol exporting + +#else /* }{ */ + +#define LUA_API extern + +#endif /* } */ + + +/* more often than not the libs go together with the core */ +#define LUALIB_API LUA_API +#define LUAMOD_API LUALIB_API + + +/* +@@ LUAI_FUNC is a mark for all extern functions that are not to be +** exported to outside modules. +@@ LUAI_DDEF and LUAI_DDEC are marks for all extern (const) variables +** that are not to be exported to outside modules (LUAI_DDEF for +** definitions and LUAI_DDEC for declarations). +** CHANGE them if you need to mark them in some special way. Elf/gcc +** (versions 3.2 and later) mark them as "hidden" to optimize access +** when Lua is compiled as a shared library. Not all elf targets support +** this attribute. Unfortunately, gcc does not offer a way to check +** whether the target offers that support, and those without support +** give a warning about it. To avoid these warnings, change to the +** default definition. +*/ +#if defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \ + defined(__ELF__) /* { */ +#define LUAI_FUNC __attribute__((visibility("hidden"))) extern +#else /* }{ */ +#define LUAI_FUNC extern +#endif /* } */ + +#define LUAI_DDEC LUAI_FUNC +#define LUAI_DDEF /* empty */ + +/* }================================================================== */ + + +/* +** {================================================================== +** Compatibility with previous versions +** =================================================================== +*/ + +/* +@@ LUA_COMPAT_5_2 controls other macros for compatibility with Lua 5.2. +@@ LUA_COMPAT_5_1 controls other macros for compatibility with Lua 5.1. +** You can define it to get all options, or change specific options +** to fit your specific needs. +*/ +#if defined(LUA_COMPAT_5_2) /* { */ + +/* +@@ LUA_COMPAT_MATHLIB controls the presence of several deprecated +** functions in the mathematical library. +*/ +#define LUA_COMPAT_MATHLIB + +/* +@@ LUA_COMPAT_BITLIB controls the presence of library 'bit32'. +*/ +#define LUA_COMPAT_BITLIB + +/* +@@ LUA_COMPAT_IPAIRS controls the effectiveness of the __ipairs metamethod. +*/ +#define LUA_COMPAT_IPAIRS + +/* +@@ LUA_COMPAT_APIINTCASTS controls the presence of macros for +** manipulating other integer types (lua_pushunsigned, lua_tounsigned, +** luaL_checkint, luaL_checklong, etc.) +*/ +#define LUA_COMPAT_APIINTCASTS + +#endif /* } */ + + +#if defined(LUA_COMPAT_5_1) /* { */ + +/* Incompatibilities from 5.2 -> 5.3 */ +#define LUA_COMPAT_MATHLIB +#define LUA_COMPAT_APIINTCASTS + +/* +@@ LUA_COMPAT_UNPACK controls the presence of global 'unpack'. +** You can replace it with 'table.unpack'. +*/ +#define LUA_COMPAT_UNPACK + +/* +@@ LUA_COMPAT_LOADERS controls the presence of table 'package.loaders'. +** You can replace it with 'package.searchers'. +*/ +#define LUA_COMPAT_LOADERS + +/* +@@ macro 'lua_cpcall' emulates deprecated function lua_cpcall. +** You can call your C function directly (with light C functions). +*/ +#define lua_cpcall(L,f,u) \ + (lua_pushcfunction(L, (f)), \ + lua_pushlightuserdata(L,(u)), \ + lua_pcall(L,1,0,0)) + + +/* +@@ LUA_COMPAT_LOG10 defines the function 'log10' in the math library. +** You can rewrite 'log10(x)' as 'log(x, 10)'. +*/ +#define LUA_COMPAT_LOG10 + +/* +@@ LUA_COMPAT_LOADSTRING defines the function 'loadstring' in the base +** library. You can rewrite 'loadstring(s)' as 'load(s)'. +*/ +#define LUA_COMPAT_LOADSTRING + +/* +@@ LUA_COMPAT_MAXN defines the function 'maxn' in the table library. +*/ +#define LUA_COMPAT_MAXN + +/* +@@ The following macros supply trivial compatibility for some +** changes in the API. The macros themselves document how to +** change your code to avoid using them. +*/ +#define lua_strlen(L,i) lua_rawlen(L, (i)) + +#define lua_objlen(L,i) lua_rawlen(L, (i)) + +#define lua_equal(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPEQ) +#define lua_lessthan(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPLT) + +/* +@@ LUA_COMPAT_MODULE controls compatibility with previous +** module functions 'module' (Lua) and 'luaL_register' (C). +*/ +#define LUA_COMPAT_MODULE + +#endif /* } */ + + +/* +@@ LUA_COMPAT_FLOATSTRING makes Lua format integral floats without a +@@ a float mark ('.0'). +** This macro is not on by default even in compatibility mode, +** because this is not really an incompatibility. +*/ +/* #define LUA_COMPAT_FLOATSTRING */ + +/* }================================================================== */ + + + +/* +** {================================================================== +** Configuration for Numbers. +** Change these definitions if no predefined LUA_FLOAT_* / LUA_INT_* +** satisfy your needs. +** =================================================================== +*/ + +/* +@@ LUA_NUMBER is the floating-point type used by Lua. +@@ LUAI_UACNUMBER is the result of a 'default argument promotion' +@@ over a floating number. +@@ l_mathlim(x) corrects limit name 'x' to the proper float type +** by prefixing it with one of FLT/DBL/LDBL. +@@ LUA_NUMBER_FRMLEN is the length modifier for writing floats. +@@ LUA_NUMBER_FMT is the format for writing floats. +@@ lua_number2str converts a float to a string. +@@ l_mathop allows the addition of an 'l' or 'f' to all math operations. +@@ l_floor takes the floor of a float. +@@ lua_str2number converts a decimal numeric string to a number. +*/ + + +/* The following definitions are good for most cases here */ + +#define l_floor(x) (l_mathop(floor)(x)) + +#define lua_number2str(s,sz,n) \ + l_sprintf((s), sz, LUA_NUMBER_FMT, (LUAI_UACNUMBER)(n)) + +/* +@@ lua_numbertointeger converts a float number to an integer, or +** returns 0 if float is not within the range of a lua_Integer. +** (The range comparisons are tricky because of rounding. The tests +** here assume a two-complement representation, where MININTEGER always +** has an exact representation as a float; MAXINTEGER may not have one, +** and therefore its conversion to float may have an ill-defined value.) +*/ +#define lua_numbertointeger(n,p) \ + ((n) >= (LUA_NUMBER)(LUA_MININTEGER) && \ + (n) < -(LUA_NUMBER)(LUA_MININTEGER) && \ + (*(p) = (LUA_INTEGER)(n), 1)) + + +/* now the variable definitions */ + +#if LUA_FLOAT_TYPE == LUA_FLOAT_FLOAT /* { single float */ + +#define LUA_NUMBER float + +#define l_mathlim(n) (FLT_##n) + +#define LUAI_UACNUMBER double + +#define LUA_NUMBER_FRMLEN "" +#define LUA_NUMBER_FMT "%.7g" + +#define l_mathop(op) op##f + +#define lua_str2number(s,p) strtof((s), (p)) + + +#elif LUA_FLOAT_TYPE == LUA_FLOAT_LONGDOUBLE /* }{ long double */ + +#define LUA_NUMBER long double + +#define l_mathlim(n) (LDBL_##n) + +#define LUAI_UACNUMBER long double + +#define LUA_NUMBER_FRMLEN "L" +#define LUA_NUMBER_FMT "%.19Lg" + +#define l_mathop(op) op##l + +#define lua_str2number(s,p) strtold((s), (p)) + +#elif LUA_FLOAT_TYPE == LUA_FLOAT_DOUBLE /* }{ double */ + +#define LUA_NUMBER double + +#define l_mathlim(n) (DBL_##n) + +#define LUAI_UACNUMBER double + +#define LUA_NUMBER_FRMLEN "" +#define LUA_NUMBER_FMT "%.14g" + +#define l_mathop(op) op + +#define lua_str2number(s,p) strtod((s), (p)) + +#else /* }{ */ + +#error "numeric float type not defined" + +#endif /* } */ + + + +/* +@@ LUA_INTEGER is the integer type used by Lua. +** +@@ LUA_UNSIGNED is the unsigned version of LUA_INTEGER. +** +@@ LUAI_UACINT is the result of a 'default argument promotion' +@@ over a lUA_INTEGER. +@@ LUA_INTEGER_FRMLEN is the length modifier for reading/writing integers. +@@ LUA_INTEGER_FMT is the format for writing integers. +@@ LUA_MAXINTEGER is the maximum value for a LUA_INTEGER. +@@ LUA_MININTEGER is the minimum value for a LUA_INTEGER. +@@ lua_integer2str converts an integer to a string. +*/ + + +/* The following definitions are good for most cases here */ + +#define LUA_INTEGER_FMT "%" LUA_INTEGER_FRMLEN "d" + +#define LUAI_UACINT LUA_INTEGER + +#define lua_integer2str(s,sz,n) \ + l_sprintf((s), sz, LUA_INTEGER_FMT, (LUAI_UACINT)(n)) + +/* +** use LUAI_UACINT here to avoid problems with promotions (which +** can turn a comparison between unsigneds into a signed comparison) +*/ +#define LUA_UNSIGNED unsigned LUAI_UACINT + + +/* now the variable definitions */ + +#if LUA_INT_TYPE == LUA_INT_INT /* { int */ + +#define LUA_INTEGER int +#define LUA_INTEGER_FRMLEN "" + +#define LUA_MAXINTEGER INT_MAX +#define LUA_MININTEGER INT_MIN + +#elif LUA_INT_TYPE == LUA_INT_LONG /* }{ long */ + +#define LUA_INTEGER long +#define LUA_INTEGER_FRMLEN "l" + +#define LUA_MAXINTEGER LONG_MAX +#define LUA_MININTEGER LONG_MIN + +#elif LUA_INT_TYPE == LUA_INT_LONGLONG /* }{ long long */ + +/* use presence of macro LLONG_MAX as proxy for C99 compliance */ +#if defined(LLONG_MAX) /* { */ +/* use ISO C99 stuff */ + +#define LUA_INTEGER long long +#define LUA_INTEGER_FRMLEN "ll" + +#define LUA_MAXINTEGER LLONG_MAX +#define LUA_MININTEGER LLONG_MIN + +#elif defined(LUA_USE_WINDOWS) /* }{ */ +/* in Windows, can use specific Windows types */ + +#define LUA_INTEGER __int64 +#define LUA_INTEGER_FRMLEN "I64" + +#define LUA_MAXINTEGER _I64_MAX +#define LUA_MININTEGER _I64_MIN + +#else /* }{ */ + +#error "Compiler does not support 'long long'. Use option '-DLUA_32BITS' \ + or '-DLUA_C89_NUMBERS' (see file 'luaconf.h' for details)" + +#endif /* } */ + +#else /* }{ */ + +#error "numeric integer type not defined" + +#endif /* } */ + +/* }================================================================== */ + + +/* +** {================================================================== +** Dependencies with C99 and other C details +** =================================================================== +*/ + +/* +@@ l_sprintf is equivalent to 'snprintf' or 'sprintf' in C89. +** (All uses in Lua have only one format item.) +*/ +#if !defined(LUA_USE_C89) +#define l_sprintf(s,sz,f,i) snprintf(s,sz,f,i) +#else +#define l_sprintf(s,sz,f,i) ((void)(sz), sprintf(s,f,i)) +#endif + + +/* +@@ lua_strx2number converts an hexadecimal numeric string to a number. +** In C99, 'strtod' does that conversion. Otherwise, you can +** leave 'lua_strx2number' undefined and Lua will provide its own +** implementation. +*/ +#if !defined(LUA_USE_C89) +#define lua_strx2number(s,p) lua_str2number(s,p) +#endif + + +/* +@@ lua_pointer2str converts a pointer to a readable string in a +** non-specified way. +*/ +#define lua_pointer2str(buff,sz,p) l_sprintf(buff,sz,"%p",p) + + +/* +@@ lua_number2strx converts a float to an hexadecimal numeric string. +** In C99, 'sprintf' (with format specifiers '%a'/'%A') does that. +** Otherwise, you can leave 'lua_number2strx' undefined and Lua will +** provide its own implementation. +*/ +#if !defined(LUA_USE_C89) +#define lua_number2strx(L,b,sz,f,n) \ + ((void)L, l_sprintf(b,sz,f,(LUAI_UACNUMBER)(n))) +#endif + + +/* +** 'strtof' and 'opf' variants for math functions are not valid in +** C89. Otherwise, the macro 'HUGE_VALF' is a good proxy for testing the +** availability of these variants. ('math.h' is already included in +** all files that use these macros.) +*/ +#if defined(LUA_USE_C89) || (defined(HUGE_VAL) && !defined(HUGE_VALF)) +#undef l_mathop /* variants not available */ +#undef lua_str2number +#define l_mathop(op) (lua_Number)op /* no variant */ +#define lua_str2number(s,p) ((lua_Number)strtod((s), (p))) +#endif + + +/* +@@ LUA_KCONTEXT is the type of the context ('ctx') for continuation +** functions. It must be a numerical type; Lua will use 'intptr_t' if +** available, otherwise it will use 'ptrdiff_t' (the nearest thing to +** 'intptr_t' in C89) +*/ +#define LUA_KCONTEXT ptrdiff_t + +#if !defined(LUA_USE_C89) && defined(__STDC_VERSION__) && \ + __STDC_VERSION__ >= 199901L +#include +#if defined(INTPTR_MAX) /* even in C99 this type is optional */ +#undef LUA_KCONTEXT +#define LUA_KCONTEXT intptr_t +#endif +#endif + + +/* +@@ lua_getlocaledecpoint gets the locale "radix character" (decimal point). +** Change that if you do not want to use C locales. (Code using this +** macro must include header 'locale.h'.) +*/ +#if !defined(lua_getlocaledecpoint) +#define lua_getlocaledecpoint() (localeconv()->decimal_point[0]) +#endif + +/* }================================================================== */ + + +/* +** {================================================================== +** Language Variations +** ===================================================================== +*/ + +/* +@@ LUA_NOCVTN2S/LUA_NOCVTS2N control how Lua performs some +** coercions. Define LUA_NOCVTN2S to turn off automatic coercion from +** numbers to strings. Define LUA_NOCVTS2N to turn off automatic +** coercion from strings to numbers. +*/ +/* #define LUA_NOCVTN2S */ +/* #define LUA_NOCVTS2N */ + + +/* +@@ LUA_USE_APICHECK turns on several consistency checks on the C API. +** Define it as a help when debugging C code. +*/ +#if defined(LUA_USE_APICHECK) +#include +#define luai_apicheck(l,e) assert(e) +#endif + +/* }================================================================== */ + + +/* +** {================================================================== +** Macros that affect the API and must be stable (that is, must be the +** same when you compile Lua and when you compile code that links to +** Lua). You probably do not want/need to change them. +** ===================================================================== +*/ + +/* +@@ LUAI_MAXSTACK limits the size of the Lua stack. +** CHANGE it if you need a different limit. This limit is arbitrary; +** its only purpose is to stop Lua from consuming unlimited stack +** space (and to reserve some numbers for pseudo-indices). +*/ +#if LUAI_BITSINT >= 32 +#define LUAI_MAXSTACK 1000000 +#else +#define LUAI_MAXSTACK 15000 +#endif + + +/* +@@ LUA_EXTRASPACE defines the size of a raw memory area associated with +** a Lua state with very fast access. +** CHANGE it if you need a different size. +*/ +#define LUA_EXTRASPACE (sizeof(void *)) + + +/* +@@ LUA_IDSIZE gives the maximum size for the description of the source +@@ of a function in debug information. +** CHANGE it if you want a different size. +*/ +#define LUA_IDSIZE 60 + + +/* +@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system. +** CHANGE it if it uses too much C-stack space. (For long double, +** 'string.format("%.99f", -1e4932)' needs 5034 bytes, so a +** smaller buffer would force a memory allocation for each call to +** 'string.format'.) +*/ +#if LUA_FLOAT_TYPE == LUA_FLOAT_LONGDOUBLE +#define LUAL_BUFFERSIZE 8192 +#else +#define LUAL_BUFFERSIZE ((int)(0x80 * sizeof(void*) * sizeof(lua_Integer))) +#endif + +/* }================================================================== */ + + +/* +@@ LUA_QL describes how error messages quote program elements. +** Lua does not use these macros anymore; they are here for +** compatibility only. +*/ +#define LUA_QL(x) "'" x "'" +#define LUA_QS LUA_QL("%s") + + + + +/* =================================================================== */ + +/* +** Local configuration. You can use this space to add your redefinitions +** without modifying the main part of the file. +*/ + + + + + +#endif + diff --git a/depends/lua/include/lualib.h b/depends/lua/include/lualib.h new file mode 100644 index 0000000000..f5304aa0dd --- /dev/null +++ b/depends/lua/include/lualib.h @@ -0,0 +1,61 @@ +/* +** $Id: lualib.h,v 1.45.1.1 2017/04/19 17:20:42 roberto Exp $ +** Lua standard libraries +** See Copyright Notice in lua.h +*/ + + +#ifndef lualib_h +#define lualib_h + +#include "lua.h" + + +/* version suffix for environment variable names */ +#define LUA_VERSUFFIX "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR + + +LUAMOD_API int (luaopen_base) (lua_State *L); + +#define LUA_COLIBNAME "coroutine" +LUAMOD_API int (luaopen_coroutine) (lua_State *L); + +#define LUA_TABLIBNAME "table" +LUAMOD_API int (luaopen_table) (lua_State *L); + +#define LUA_IOLIBNAME "io" +LUAMOD_API int (luaopen_io) (lua_State *L); + +#define LUA_OSLIBNAME "os" +LUAMOD_API int (luaopen_os) (lua_State *L); + +#define LUA_STRLIBNAME "string" +LUAMOD_API int (luaopen_string) (lua_State *L); + +#define LUA_UTF8LIBNAME "utf8" +LUAMOD_API int (luaopen_utf8) (lua_State *L); + +#define LUA_BITLIBNAME "bit32" +LUAMOD_API int (luaopen_bit32) (lua_State *L); + +#define LUA_MATHLIBNAME "math" +LUAMOD_API int (luaopen_math) (lua_State *L); + +#define LUA_DBLIBNAME "debug" +LUAMOD_API int (luaopen_debug) (lua_State *L); + +#define LUA_LOADLIBNAME "package" +LUAMOD_API int (luaopen_package) (lua_State *L); + + +/* open all previous libraries */ +LUALIB_API void (luaL_openlibs) (lua_State *L); + + + +#if !defined(lua_assert) +#define lua_assert(x) ((void)0) +#endif + + +#endif diff --git a/depends/lua/include/lundump.h b/depends/lua/include/lundump.h new file mode 100644 index 0000000000..ce492d689c --- /dev/null +++ b/depends/lua/include/lundump.h @@ -0,0 +1,32 @@ +/* +** $Id: lundump.h,v 1.45.1.1 2017/04/19 17:20:42 roberto Exp $ +** load precompiled Lua chunks +** See Copyright Notice in lua.h +*/ + +#ifndef lundump_h +#define lundump_h + +#include "llimits.h" +#include "lobject.h" +#include "lzio.h" + + +/* data to catch conversion errors */ +#define LUAC_DATA "\x19\x93\r\n\x1a\n" + +#define LUAC_INT 0x5678 +#define LUAC_NUM cast_num(370.5) + +#define MYINT(s) (s[0]-'0') +#define LUAC_VERSION (MYINT(LUA_VERSION_MAJOR)*16+MYINT(LUA_VERSION_MINOR)) +#define LUAC_FORMAT 0 /* this is the official format */ + +/* load one chunk; from lundump.c */ +LUAI_FUNC LClosure* luaU_undump (lua_State* L, ZIO* Z, const char* name); + +/* dump one chunk; from ldump.c */ +LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, + void* data, int strip); + +#endif diff --git a/depends/lua/include/lvm.h b/depends/lua/include/lvm.h new file mode 100644 index 0000000000..a8f954f04c --- /dev/null +++ b/depends/lua/include/lvm.h @@ -0,0 +1,113 @@ +/* +** $Id: lvm.h,v 2.41.1.1 2017/04/19 17:20:42 roberto Exp $ +** Lua virtual machine +** See Copyright Notice in lua.h +*/ + +#ifndef lvm_h +#define lvm_h + + +#include "ldo.h" +#include "lobject.h" +#include "ltm.h" + + +#if !defined(LUA_NOCVTN2S) +#define cvt2str(o) ttisnumber(o) +#else +#define cvt2str(o) 0 /* no conversion from numbers to strings */ +#endif + + +#if !defined(LUA_NOCVTS2N) +#define cvt2num(o) ttisstring(o) +#else +#define cvt2num(o) 0 /* no conversion from strings to numbers */ +#endif + + +/* +** You can define LUA_FLOORN2I if you want to convert floats to integers +** by flooring them (instead of raising an error if they are not +** integral values) +*/ +#if !defined(LUA_FLOORN2I) +#define LUA_FLOORN2I 0 +#endif + + +#define tonumber(o,n) \ + (ttisfloat(o) ? (*(n) = fltvalue(o), 1) : luaV_tonumber_(o,n)) + +#define tointeger(o,i) \ + (ttisinteger(o) ? (*(i) = ivalue(o), 1) : luaV_tointeger(o,i,LUA_FLOORN2I)) + +#define intop(op,v1,v2) l_castU2S(l_castS2U(v1) op l_castS2U(v2)) + +#define luaV_rawequalobj(t1,t2) luaV_equalobj(NULL,t1,t2) + + +/* +** fast track for 'gettable': if 't' is a table and 't[k]' is not nil, +** return 1 with 'slot' pointing to 't[k]' (final result). Otherwise, +** return 0 (meaning it will have to check metamethod) with 'slot' +** pointing to a nil 't[k]' (if 't' is a table) or NULL (otherwise). +** 'f' is the raw get function to use. +*/ +#define luaV_fastget(L,t,k,slot,f) \ + (!ttistable(t) \ + ? (slot = NULL, 0) /* not a table; 'slot' is NULL and result is 0 */ \ + : (slot = f(hvalue(t), k), /* else, do raw access */ \ + !ttisnil(slot))) /* result not nil? */ + +/* +** standard implementation for 'gettable' +*/ +#define luaV_gettable(L,t,k,v) { const TValue *slot; \ + if (luaV_fastget(L,t,k,slot,luaH_get)) { setobj2s(L, v, slot); } \ + else luaV_finishget(L,t,k,v,slot); } + + +/* +** Fast track for set table. If 't' is a table and 't[k]' is not nil, +** call GC barrier, do a raw 't[k]=v', and return true; otherwise, +** return false with 'slot' equal to NULL (if 't' is not a table) or +** 'nil'. (This is needed by 'luaV_finishget'.) Note that, if the macro +** returns true, there is no need to 'invalidateTMcache', because the +** call is not creating a new entry. +*/ +#define luaV_fastset(L,t,k,slot,f,v) \ + (!ttistable(t) \ + ? (slot = NULL, 0) \ + : (slot = f(hvalue(t), k), \ + ttisnil(slot) ? 0 \ + : (luaC_barrierback(L, hvalue(t), v), \ + setobj2t(L, cast(TValue *,slot), v), \ + 1))) + + +#define luaV_settable(L,t,k,v) { const TValue *slot; \ + if (!luaV_fastset(L,t,k,slot,luaH_get,v)) \ + luaV_finishset(L,t,k,v,slot); } + + + +LUAI_FUNC int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2); +LUAI_FUNC int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r); +LUAI_FUNC int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r); +LUAI_FUNC int luaV_tonumber_ (const TValue *obj, lua_Number *n); +LUAI_FUNC int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode); +LUAI_FUNC void luaV_finishget (lua_State *L, const TValue *t, TValue *key, + StkId val, const TValue *slot); +LUAI_FUNC void luaV_finishset (lua_State *L, const TValue *t, TValue *key, + StkId val, const TValue *slot); +LUAI_FUNC void luaV_finishOp (lua_State *L); +LUAI_FUNC void luaV_execute (lua_State *L); +LUAI_FUNC void luaV_concat (lua_State *L, int total); +LUAI_FUNC lua_Integer luaV_div (lua_State *L, lua_Integer x, lua_Integer y); +LUAI_FUNC lua_Integer luaV_mod (lua_State *L, lua_Integer x, lua_Integer y); +LUAI_FUNC lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y); +LUAI_FUNC void luaV_objlen (lua_State *L, StkId ra, const TValue *rb); + +#endif diff --git a/depends/lua/include/lzio.h b/depends/lua/include/lzio.h new file mode 100644 index 0000000000..d897870815 --- /dev/null +++ b/depends/lua/include/lzio.h @@ -0,0 +1,66 @@ +/* +** $Id: lzio.h,v 1.31.1.1 2017/04/19 17:20:42 roberto Exp $ +** Buffered streams +** See Copyright Notice in lua.h +*/ + + +#ifndef lzio_h +#define lzio_h + +#include "lua.h" + +#include "lmem.h" + + +#define EOZ (-1) /* end of stream */ + +typedef struct Zio ZIO; + +#define zgetc(z) (((z)->n--)>0 ? cast_uchar(*(z)->p++) : luaZ_fill(z)) + + +typedef struct Mbuffer { + char *buffer; + size_t n; + size_t buffsize; +} Mbuffer; + +#define luaZ_initbuffer(L, buff) ((buff)->buffer = NULL, (buff)->buffsize = 0) + +#define luaZ_buffer(buff) ((buff)->buffer) +#define luaZ_sizebuffer(buff) ((buff)->buffsize) +#define luaZ_bufflen(buff) ((buff)->n) + +#define luaZ_buffremove(buff,i) ((buff)->n -= (i)) +#define luaZ_resetbuffer(buff) ((buff)->n = 0) + + +#define luaZ_resizebuffer(L, buff, size) \ + ((buff)->buffer = luaM_reallocvchar(L, (buff)->buffer, \ + (buff)->buffsize, size), \ + (buff)->buffsize = size) + +#define luaZ_freebuffer(L, buff) luaZ_resizebuffer(L, buff, 0) + + +LUAI_FUNC void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, + void *data); +LUAI_FUNC size_t luaZ_read (ZIO* z, void *b, size_t n); /* read next n bytes */ + + + +/* --------- Private Part ------------------ */ + +struct Zio { + size_t n; /* bytes still unread */ + const char *p; /* current position in buffer */ + lua_Reader reader; /* reader function */ + void *data; /* additional data */ + lua_State *L; /* Lua state (for reader) */ +}; + + +LUAI_FUNC int luaZ_fill (ZIO *z); + +#endif diff --git a/depends/lua/src/lapi.c b/depends/lua/src/lapi.c new file mode 100644 index 0000000000..aa01148ab1 --- /dev/null +++ b/depends/lua/src/lapi.c @@ -0,0 +1,1299 @@ +/* +** $Id: lapi.c,v 2.259.1.2 2017/12/06 18:35:12 roberto Exp $ +** Lua API +** See Copyright Notice in lua.h +*/ + +#define lapi_c +#define LUA_CORE + +#include "lprefix.h" + + +#include +#include + +#include "lua.h" + +#include "lapi.h" +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "lgc.h" +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" +#include "lundump.h" +#include "lvm.h" + + + +const char lua_ident[] = + "$LuaVersion: " LUA_COPYRIGHT " $" + "$LuaAuthors: " LUA_AUTHORS " $"; + + +/* value at a non-valid index */ +#define NONVALIDVALUE cast(TValue *, luaO_nilobject) + +/* corresponding test */ +#define isvalid(o) ((o) != luaO_nilobject) + +/* test for pseudo index */ +#define ispseudo(i) ((i) <= LUA_REGISTRYINDEX) + +/* test for upvalue */ +#define isupvalue(i) ((i) < LUA_REGISTRYINDEX) + +/* test for valid but not pseudo index */ +#define isstackindex(i, o) (isvalid(o) && !ispseudo(i)) + +#define api_checkvalidindex(l,o) api_check(l, isvalid(o), "invalid index") + +#define api_checkstackindex(l, i, o) \ + api_check(l, isstackindex(i, o), "index not in the stack") + + +static TValue *index2addr (lua_State *L, int idx) { + CallInfo *ci = L->ci; + if (idx > 0) { + TValue *o = ci->func + idx; + api_check(L, idx <= ci->top - (ci->func + 1), "unacceptable index"); + if (o >= L->top) return NONVALIDVALUE; + else return o; + } + else if (!ispseudo(idx)) { /* negative index */ + api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index"); + return L->top + idx; + } + else if (idx == LUA_REGISTRYINDEX) + return &G(L)->l_registry; + else { /* upvalues */ + idx = LUA_REGISTRYINDEX - idx; + api_check(L, idx <= MAXUPVAL + 1, "upvalue index too large"); + if (ttislcf(ci->func)) /* light C function? */ + return NONVALIDVALUE; /* it has no upvalues */ + else { + CClosure *func = clCvalue(ci->func); + return (idx <= func->nupvalues) ? &func->upvalue[idx-1] : NONVALIDVALUE; + } + } +} + + +/* +** to be called by 'lua_checkstack' in protected mode, to grow stack +** capturing memory errors +*/ +static void growstack (lua_State *L, void *ud) { + int size = *(int *)ud; + luaD_growstack(L, size); +} + + +LUA_API int lua_checkstack (lua_State *L, int n) { + int res; + CallInfo *ci = L->ci; + lua_lock(L); + api_check(L, n >= 0, "negative 'n'"); + if (L->stack_last - L->top > n) /* stack large enough? */ + res = 1; /* yes; check is OK */ + else { /* no; need to grow stack */ + int inuse = cast_int(L->top - L->stack) + EXTRA_STACK; + if (inuse > LUAI_MAXSTACK - n) /* can grow without overflow? */ + res = 0; /* no */ + else /* try to grow stack */ + res = (luaD_rawrunprotected(L, &growstack, &n) == LUA_OK); + } + if (res && ci->top < L->top + n) + ci->top = L->top + n; /* adjust frame top */ + lua_unlock(L); + return res; +} + + +LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) { + int i; + if (from == to) return; + lua_lock(to); + api_checknelems(from, n); + api_check(from, G(from) == G(to), "moving among independent states"); + api_check(from, to->ci->top - to->top >= n, "stack overflow"); + from->top -= n; + for (i = 0; i < n; i++) { + setobj2s(to, to->top, from->top + i); + to->top++; /* stack already checked by previous 'api_check' */ + } + lua_unlock(to); +} + + +LUA_API lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf) { + lua_CFunction old; + lua_lock(L); + old = G(L)->panic; + G(L)->panic = panicf; + lua_unlock(L); + return old; +} + + +LUA_API const lua_Number *lua_version (lua_State *L) { + static const lua_Number version = LUA_VERSION_NUM; + if (L == NULL) return &version; + else return G(L)->version; +} + + + +/* +** basic stack manipulation +*/ + + +/* +** convert an acceptable stack index into an absolute index +*/ +LUA_API int lua_absindex (lua_State *L, int idx) { + return (idx > 0 || ispseudo(idx)) + ? idx + : cast_int(L->top - L->ci->func) + idx; +} + + +LUA_API int lua_gettop (lua_State *L) { + return cast_int(L->top - (L->ci->func + 1)); +} + + +LUA_API void lua_settop (lua_State *L, int idx) { + StkId func = L->ci->func; + lua_lock(L); + if (idx >= 0) { + api_check(L, idx <= L->stack_last - (func + 1), "new top too large"); + while (L->top < (func + 1) + idx) + setnilvalue(L->top++); + L->top = (func + 1) + idx; + } + else { + api_check(L, -(idx+1) <= (L->top - (func + 1)), "invalid new top"); + L->top += idx+1; /* 'subtract' index (index is negative) */ + } + lua_unlock(L); +} + + +/* +** Reverse the stack segment from 'from' to 'to' +** (auxiliary to 'lua_rotate') +*/ +static void reverse (lua_State *L, StkId from, StkId to) { + for (; from < to; from++, to--) { + TValue temp; + setobj(L, &temp, from); + setobjs2s(L, from, to); + setobj2s(L, to, &temp); + } +} + + +/* +** Let x = AB, where A is a prefix of length 'n'. Then, +** rotate x n == BA. But BA == (A^r . B^r)^r. +*/ +LUA_API void lua_rotate (lua_State *L, int idx, int n) { + StkId p, t, m; + lua_lock(L); + t = L->top - 1; /* end of stack segment being rotated */ + p = index2addr(L, idx); /* start of segment */ + api_checkstackindex(L, idx, p); + api_check(L, (n >= 0 ? n : -n) <= (t - p + 1), "invalid 'n'"); + m = (n >= 0 ? t - n : p - n - 1); /* end of prefix */ + reverse(L, p, m); /* reverse the prefix with length 'n' */ + reverse(L, m + 1, t); /* reverse the suffix */ + reverse(L, p, t); /* reverse the entire segment */ + lua_unlock(L); +} + + +LUA_API void lua_copy (lua_State *L, int fromidx, int toidx) { + TValue *fr, *to; + lua_lock(L); + fr = index2addr(L, fromidx); + to = index2addr(L, toidx); + api_checkvalidindex(L, to); + setobj(L, to, fr); + if (isupvalue(toidx)) /* function upvalue? */ + luaC_barrier(L, clCvalue(L->ci->func), fr); + /* LUA_REGISTRYINDEX does not need gc barrier + (collector revisits it before finishing collection) */ + lua_unlock(L); +} + + +LUA_API void lua_pushvalue (lua_State *L, int idx) { + lua_lock(L); + setobj2s(L, L->top, index2addr(L, idx)); + api_incr_top(L); + lua_unlock(L); +} + + + +/* +** access functions (stack -> C) +*/ + + +LUA_API int lua_type (lua_State *L, int idx) { + StkId o = index2addr(L, idx); + return (isvalid(o) ? ttnov(o) : LUA_TNONE); +} + + +LUA_API const char *lua_typename (lua_State *L, int t) { + UNUSED(L); + api_check(L, LUA_TNONE <= t && t < LUA_NUMTAGS, "invalid tag"); + return ttypename(t); +} + + +LUA_API int lua_iscfunction (lua_State *L, int idx) { + StkId o = index2addr(L, idx); + return (ttislcf(o) || (ttisCclosure(o))); +} + + +LUA_API int lua_isinteger (lua_State *L, int idx) { + StkId o = index2addr(L, idx); + return ttisinteger(o); +} + + +LUA_API int lua_isnumber (lua_State *L, int idx) { + lua_Number n; + const TValue *o = index2addr(L, idx); + return tonumber(o, &n); +} + + +LUA_API int lua_isstring (lua_State *L, int idx) { + const TValue *o = index2addr(L, idx); + return (ttisstring(o) || cvt2str(o)); +} + + +LUA_API int lua_isuserdata (lua_State *L, int idx) { + const TValue *o = index2addr(L, idx); + return (ttisfulluserdata(o) || ttislightuserdata(o)); +} + + +LUA_API int lua_rawequal (lua_State *L, int index1, int index2) { + StkId o1 = index2addr(L, index1); + StkId o2 = index2addr(L, index2); + return (isvalid(o1) && isvalid(o2)) ? luaV_rawequalobj(o1, o2) : 0; +} + + +LUA_API void lua_arith (lua_State *L, int op) { + lua_lock(L); + if (op != LUA_OPUNM && op != LUA_OPBNOT) + api_checknelems(L, 2); /* all other operations expect two operands */ + else { /* for unary operations, add fake 2nd operand */ + api_checknelems(L, 1); + setobjs2s(L, L->top, L->top - 1); + api_incr_top(L); + } + /* first operand at top - 2, second at top - 1; result go to top - 2 */ + luaO_arith(L, op, L->top - 2, L->top - 1, L->top - 2); + L->top--; /* remove second operand */ + lua_unlock(L); +} + + +LUA_API int lua_compare (lua_State *L, int index1, int index2, int op) { + StkId o1, o2; + int i = 0; + lua_lock(L); /* may call tag method */ + o1 = index2addr(L, index1); + o2 = index2addr(L, index2); + if (isvalid(o1) && isvalid(o2)) { + switch (op) { + case LUA_OPEQ: i = luaV_equalobj(L, o1, o2); break; + case LUA_OPLT: i = luaV_lessthan(L, o1, o2); break; + case LUA_OPLE: i = luaV_lessequal(L, o1, o2); break; + default: api_check(L, 0, "invalid option"); + } + } + lua_unlock(L); + return i; +} + + +LUA_API size_t lua_stringtonumber (lua_State *L, const char *s) { + size_t sz = luaO_str2num(s, L->top); + if (sz != 0) + api_incr_top(L); + return sz; +} + + +LUA_API lua_Number lua_tonumberx (lua_State *L, int idx, int *pisnum) { + lua_Number n; + const TValue *o = index2addr(L, idx); + int isnum = tonumber(o, &n); + if (!isnum) + n = 0; /* call to 'tonumber' may change 'n' even if it fails */ + if (pisnum) *pisnum = isnum; + return n; +} + + +LUA_API lua_Integer lua_tointegerx (lua_State *L, int idx, int *pisnum) { + lua_Integer res; + const TValue *o = index2addr(L, idx); + int isnum = tointeger(o, &res); + if (!isnum) + res = 0; /* call to 'tointeger' may change 'n' even if it fails */ + if (pisnum) *pisnum = isnum; + return res; +} + + +LUA_API int lua_toboolean (lua_State *L, int idx) { + const TValue *o = index2addr(L, idx); + return !l_isfalse(o); +} + + +LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) { + StkId o = index2addr(L, idx); + if (!ttisstring(o)) { + if (!cvt2str(o)) { /* not convertible? */ + if (len != NULL) *len = 0; + return NULL; + } + lua_lock(L); /* 'luaO_tostring' may create a new string */ + luaO_tostring(L, o); + luaC_checkGC(L); + o = index2addr(L, idx); /* previous call may reallocate the stack */ + lua_unlock(L); + } + if (len != NULL) + *len = vslen(o); + return svalue(o); +} + + +LUA_API size_t lua_rawlen (lua_State *L, int idx) { + StkId o = index2addr(L, idx); + switch (ttype(o)) { + case LUA_TSHRSTR: return tsvalue(o)->shrlen; + case LUA_TLNGSTR: return tsvalue(o)->u.lnglen; + case LUA_TUSERDATA: return uvalue(o)->len; + case LUA_TTABLE: return size_t(luaH_getn(hvalue(o))); + default: return 0; + } +} + + +LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx) { + StkId o = index2addr(L, idx); + if (ttislcf(o)) return fvalue(o); + else if (ttisCclosure(o)) + return clCvalue(o)->f; + else return NULL; /* not a C function */ +} + + +LUA_API void *lua_touserdata (lua_State *L, int idx) { + StkId o = index2addr(L, idx); + switch (ttnov(o)) { + case LUA_TUSERDATA: return getudatamem(uvalue(o)); + case LUA_TLIGHTUSERDATA: return pvalue(o); + default: return NULL; + } +} + + +LUA_API lua_State *lua_tothread (lua_State *L, int idx) { + StkId o = index2addr(L, idx); + return (!ttisthread(o)) ? NULL : thvalue(o); +} + + +LUA_API const void *lua_topointer (lua_State *L, int idx) { + StkId o = index2addr(L, idx); + switch (ttype(o)) { + case LUA_TTABLE: return hvalue(o); + case LUA_TLCL: return clLvalue(o); + case LUA_TCCL: return clCvalue(o); + case LUA_TLCF: return cast(void *, cast(size_t, fvalue(o))); + case LUA_TTHREAD: return thvalue(o); + case LUA_TUSERDATA: return getudatamem(uvalue(o)); + case LUA_TLIGHTUSERDATA: return pvalue(o); + default: return NULL; + } +} + + + +/* +** push functions (C -> stack) +*/ + + +LUA_API void lua_pushnil (lua_State *L) { + lua_lock(L); + setnilvalue(L->top); + api_incr_top(L); + lua_unlock(L); +} + + +LUA_API void lua_pushnumber (lua_State *L, lua_Number n) { + lua_lock(L); + setfltvalue(L->top, n); + api_incr_top(L); + lua_unlock(L); +} + + +LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) { + lua_lock(L); + setivalue(L->top, n); + api_incr_top(L); + lua_unlock(L); +} + + +/* +** Pushes on the stack a string with given length. Avoid using 's' when +** 'len' == 0 (as 's' can be NULL in that case), due to later use of +** 'memcmp' and 'memcpy'. +*/ +LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) { + TString *ts; + lua_lock(L); + ts = (len == 0) ? luaS_new(L, "") : luaS_newlstr(L, s, len); + setsvalue2s(L, L->top, ts); + api_incr_top(L); + luaC_checkGC(L); + lua_unlock(L); + return getstr(ts); +} + + +LUA_API const char *lua_pushstring (lua_State *L, const char *s) { + lua_lock(L); + if (s == NULL) + setnilvalue(L->top); + else { + TString *ts; + ts = luaS_new(L, s); + setsvalue2s(L, L->top, ts); + s = getstr(ts); /* internal copy's address */ + } + api_incr_top(L); + luaC_checkGC(L); + lua_unlock(L); + return s; +} + + +LUA_API const char *lua_pushvfstring (lua_State *L, const char *fmt, + va_list argp) { + const char *ret; + lua_lock(L); + ret = luaO_pushvfstring(L, fmt, argp); + luaC_checkGC(L); + lua_unlock(L); + return ret; +} + + +LUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...) { + const char *ret; + va_list argp; + lua_lock(L); + va_start(argp, fmt); + ret = luaO_pushvfstring(L, fmt, argp); + va_end(argp); + luaC_checkGC(L); + lua_unlock(L); + return ret; +} + + +LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) { + lua_lock(L); + if (n == 0) { + setfvalue(L->top, fn); + api_incr_top(L); + } + else { + CClosure *cl; + api_checknelems(L, n); + api_check(L, n <= MAXUPVAL, "upvalue index too large"); + cl = luaF_newCclosure(L, n); + cl->f = fn; + L->top -= n; + while (n--) { + setobj2n(L, &cl->upvalue[n], L->top + n); + /* does not need barrier because closure is white */ + } + setclCvalue(L, L->top, cl); + api_incr_top(L); + luaC_checkGC(L); + } + lua_unlock(L); +} + + +LUA_API void lua_pushboolean (lua_State *L, int b) { + lua_lock(L); + setbvalue(L->top, (b != 0)); /* ensure that true is 1 */ + api_incr_top(L); + lua_unlock(L); +} + + +LUA_API void lua_pushlightuserdata (lua_State *L, void *p) { + lua_lock(L); + setpvalue(L->top, p); + api_incr_top(L); + lua_unlock(L); +} + + +LUA_API int lua_pushthread (lua_State *L) { + lua_lock(L); + setthvalue(L, L->top, L); + api_incr_top(L); + lua_unlock(L); + return (G(L)->mainthread == L); +} + + + +/* +** get functions (Lua -> stack) +*/ + + +static int auxgetstr (lua_State *L, const TValue *t, const char *k) { + const TValue *slot; + TString *str = luaS_new(L, k); + if (luaV_fastget(L, t, str, slot, luaH_getstr)) { + setobj2s(L, L->top, slot); + api_incr_top(L); + } + else { + setsvalue2s(L, L->top, str); + api_incr_top(L); + luaV_finishget(L, t, L->top - 1, L->top - 1, slot); + } + lua_unlock(L); + return ttnov(L->top - 1); +} + + +LUA_API int lua_getglobal (lua_State *L, const char *name) { + Table *reg = hvalue(&G(L)->l_registry); + lua_lock(L); + return auxgetstr(L, luaH_getint(reg, LUA_RIDX_GLOBALS), name); +} + + +LUA_API int lua_gettable (lua_State *L, int idx) { + StkId t; + lua_lock(L); + t = index2addr(L, idx); + luaV_gettable(L, t, L->top - 1, L->top - 1); + lua_unlock(L); + return ttnov(L->top - 1); +} + + +LUA_API int lua_getfield (lua_State *L, int idx, const char *k) { + lua_lock(L); + return auxgetstr(L, index2addr(L, idx), k); +} + + +LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) { + StkId t; + const TValue *slot; + lua_lock(L); + t = index2addr(L, idx); + if (luaV_fastget(L, t, n, slot, luaH_getint)) { + setobj2s(L, L->top, slot); + api_incr_top(L); + } + else { + setivalue(L->top, n); + api_incr_top(L); + luaV_finishget(L, t, L->top - 1, L->top - 1, slot); + } + lua_unlock(L); + return ttnov(L->top - 1); +} + + +LUA_API int lua_rawget (lua_State *L, int idx) { + StkId t; + lua_lock(L); + t = index2addr(L, idx); + api_check(L, ttistable(t), "table expected"); + setobj2s(L, L->top - 1, luaH_get(hvalue(t), L->top - 1)); + lua_unlock(L); + return ttnov(L->top - 1); +} + + +LUA_API int lua_rawgeti (lua_State *L, int idx, lua_Integer n) { + StkId t; + lua_lock(L); + t = index2addr(L, idx); + api_check(L, ttistable(t), "table expected"); + setobj2s(L, L->top, luaH_getint(hvalue(t), n)); + api_incr_top(L); + lua_unlock(L); + return ttnov(L->top - 1); +} + + +LUA_API int lua_rawgetp (lua_State *L, int idx, const void *p) { + StkId t; + TValue k; + lua_lock(L); + t = index2addr(L, idx); + api_check(L, ttistable(t), "table expected"); + setpvalue(&k, cast(void *, p)); + setobj2s(L, L->top, luaH_get(hvalue(t), &k)); + api_incr_top(L); + lua_unlock(L); + return ttnov(L->top - 1); +} + + +LUA_API void lua_createtable (lua_State *L, int narray, int nrec) { + Table *t; + lua_lock(L); + t = luaH_new(L); + sethvalue(L, L->top, t); + api_incr_top(L); + if (narray > 0 || nrec > 0) + luaH_resize(L, t, narray, nrec); + luaC_checkGC(L); + lua_unlock(L); +} + + +LUA_API int lua_getmetatable (lua_State *L, int objindex) { + const TValue *obj; + Table *mt; + int res = 0; + lua_lock(L); + obj = index2addr(L, objindex); + switch (ttnov(obj)) { + case LUA_TTABLE: + mt = hvalue(obj)->metatable; + break; + case LUA_TUSERDATA: + mt = uvalue(obj)->metatable; + break; + default: + mt = G(L)->mt[ttnov(obj)]; + break; + } + if (mt != NULL) { + sethvalue(L, L->top, mt); + api_incr_top(L); + res = 1; + } + lua_unlock(L); + return res; +} + + +LUA_API int lua_getuservalue (lua_State *L, int idx) { + StkId o; + lua_lock(L); + o = index2addr(L, idx); + api_check(L, ttisfulluserdata(o), "full userdata expected"); + getuservalue(L, uvalue(o), L->top); + api_incr_top(L); + lua_unlock(L); + return ttnov(L->top - 1); +} + + +/* +** set functions (stack -> Lua) +*/ + +/* +** t[k] = value at the top of the stack (where 'k' is a string) +*/ +static void auxsetstr (lua_State *L, const TValue *t, const char *k) { + const TValue *slot; + TString *str = luaS_new(L, k); + api_checknelems(L, 1); + if (luaV_fastset(L, t, str, slot, luaH_getstr, L->top - 1)) + L->top--; /* pop value */ + else { + setsvalue2s(L, L->top, str); /* push 'str' (to make it a TValue) */ + api_incr_top(L); + luaV_finishset(L, t, L->top - 1, L->top - 2, slot); + L->top -= 2; /* pop value and key */ + } + lua_unlock(L); /* lock done by caller */ +} + + +LUA_API void lua_setglobal (lua_State *L, const char *name) { + Table *reg = hvalue(&G(L)->l_registry); + lua_lock(L); /* unlock done in 'auxsetstr' */ + auxsetstr(L, luaH_getint(reg, LUA_RIDX_GLOBALS), name); +} + + +LUA_API void lua_settable (lua_State *L, int idx) { + StkId t; + lua_lock(L); + api_checknelems(L, 2); + t = index2addr(L, idx); + luaV_settable(L, t, L->top - 2, L->top - 1); + L->top -= 2; /* pop index and value */ + lua_unlock(L); +} + + +LUA_API void lua_setfield (lua_State *L, int idx, const char *k) { + lua_lock(L); /* unlock done in 'auxsetstr' */ + auxsetstr(L, index2addr(L, idx), k); +} + + +LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) { + StkId t; + const TValue *slot; + lua_lock(L); + api_checknelems(L, 1); + t = index2addr(L, idx); + if (luaV_fastset(L, t, n, slot, luaH_getint, L->top - 1)) + L->top--; /* pop value */ + else { + setivalue(L->top, n); + api_incr_top(L); + luaV_finishset(L, t, L->top - 1, L->top - 2, slot); + L->top -= 2; /* pop value and key */ + } + lua_unlock(L); +} + + +LUA_API void lua_rawset (lua_State *L, int idx) { + StkId o; + TValue *slot; + lua_lock(L); + api_checknelems(L, 2); + o = index2addr(L, idx); + api_check(L, ttistable(o), "table expected"); + slot = luaH_set(L, hvalue(o), L->top - 2); + setobj2t(L, slot, L->top - 1); + invalidateTMcache(hvalue(o)); + luaC_barrierback(L, hvalue(o), L->top-1); + L->top -= 2; + lua_unlock(L); +} + + +LUA_API void lua_rawseti (lua_State *L, int idx, lua_Integer n) { + StkId o; + lua_lock(L); + api_checknelems(L, 1); + o = index2addr(L, idx); + api_check(L, ttistable(o), "table expected"); + luaH_setint(L, hvalue(o), n, L->top - 1); + luaC_barrierback(L, hvalue(o), L->top-1); + L->top--; + lua_unlock(L); +} + + +LUA_API void lua_rawsetp (lua_State *L, int idx, const void *p) { + StkId o; + TValue k, *slot; + lua_lock(L); + api_checknelems(L, 1); + o = index2addr(L, idx); + api_check(L, ttistable(o), "table expected"); + setpvalue(&k, cast(void *, p)); + slot = luaH_set(L, hvalue(o), &k); + setobj2t(L, slot, L->top - 1); + luaC_barrierback(L, hvalue(o), L->top - 1); + L->top--; + lua_unlock(L); +} + + +LUA_API int lua_setmetatable (lua_State *L, int objindex) { + TValue *obj; + Table *mt; + lua_lock(L); + api_checknelems(L, 1); + obj = index2addr(L, objindex); + if (ttisnil(L->top - 1)) + mt = NULL; + else { + api_check(L, ttistable(L->top - 1), "table expected"); + mt = hvalue(L->top - 1); + } + switch (ttnov(obj)) { + case LUA_TTABLE: { + hvalue(obj)->metatable = mt; + if (mt) { + luaC_objbarrier(L, gcvalue(obj), mt); + luaC_checkfinalizer(L, gcvalue(obj), mt); + } + break; + } + case LUA_TUSERDATA: { + uvalue(obj)->metatable = mt; + if (mt) { + luaC_objbarrier(L, uvalue(obj), mt); + luaC_checkfinalizer(L, gcvalue(obj), mt); + } + break; + } + default: { + G(L)->mt[ttnov(obj)] = mt; + break; + } + } + L->top--; + lua_unlock(L); + return 1; +} + + +LUA_API void lua_setuservalue (lua_State *L, int idx) { + StkId o; + lua_lock(L); + api_checknelems(L, 1); + o = index2addr(L, idx); + api_check(L, ttisfulluserdata(o), "full userdata expected"); + setuservalue(L, uvalue(o), L->top - 1); + luaC_barrier(L, gcvalue(o), L->top - 1); + L->top--; + lua_unlock(L); +} + + +/* +** 'load' and 'call' functions (run Lua code) +*/ + + +#define checkresults(L,na,nr) \ + api_check(L, (nr) == LUA_MULTRET || (L->ci->top - L->top >= (nr) - (na)), \ + "results from function overflow current stack size") + + +LUA_API void lua_callk (lua_State *L, int nargs, int nresults, + lua_KContext ctx, lua_KFunction k) { + StkId func; + lua_lock(L); + api_check(L, k == NULL || !isLua(L->ci), + "cannot use continuations inside hooks"); + api_checknelems(L, nargs+1); + api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread"); + checkresults(L, nargs, nresults); + func = L->top - (nargs+1); + if (k != NULL && L->nny == 0) { /* need to prepare continuation? */ + L->ci->u.c.k = k; /* save continuation */ + L->ci->u.c.ctx = ctx; /* save context */ + luaD_call(L, func, nresults); /* do the call */ + } + else /* no continuation or no yieldable */ + luaD_callnoyield(L, func, nresults); /* just do the call */ + adjustresults(L, nresults); + lua_unlock(L); +} + + + +/* +** Execute a protected call. +*/ +struct CallS { /* data to 'f_call' */ + StkId func; + int nresults; +}; + + +static void f_call (lua_State *L, void *ud) { + struct CallS *c = cast(struct CallS *, ud); + luaD_callnoyield(L, c->func, c->nresults); +} + + + +LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc, + lua_KContext ctx, lua_KFunction k) { + struct CallS c; + int status; + ptrdiff_t func; + lua_lock(L); + api_check(L, k == NULL || !isLua(L->ci), + "cannot use continuations inside hooks"); + api_checknelems(L, nargs+1); + api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread"); + checkresults(L, nargs, nresults); + if (errfunc == 0) + func = 0; + else { + StkId o = index2addr(L, errfunc); + api_checkstackindex(L, errfunc, o); + func = savestack(L, o); + } + c.func = L->top - (nargs+1); /* function to be called */ + if (k == NULL || L->nny > 0) { /* no continuation or no yieldable? */ + c.nresults = nresults; /* do a 'conventional' protected call */ + status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func); + } + else { /* prepare continuation (call is already protected by 'resume') */ + CallInfo *ci = L->ci; + ci->u.c.k = k; /* save continuation */ + ci->u.c.ctx = ctx; /* save context */ + /* save information for error recovery */ + ci->extra = savestack(L, c.func); + ci->u.c.old_errfunc = L->errfunc; + L->errfunc = func; + setoah(ci->callstatus, L->allowhook); /* save value of 'allowhook' */ + ci->callstatus |= CIST_YPCALL; /* function can do error recovery */ + luaD_call(L, c.func, nresults); /* do the call */ + ci->callstatus &= ~CIST_YPCALL; + L->errfunc = ci->u.c.old_errfunc; + status = LUA_OK; /* if it is here, there were no errors */ + } + adjustresults(L, nresults); + lua_unlock(L); + return status; +} + + +LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data, + const char *chunkname, const char *mode) { + ZIO z; + int status; + lua_lock(L); + if (!chunkname) chunkname = "?"; + luaZ_init(L, &z, reader, data); + status = luaD_protectedparser(L, &z, chunkname, mode); + if (status == LUA_OK) { /* no errors? */ + LClosure *f = clLvalue(L->top - 1); /* get newly created function */ + if (f->nupvalues >= 1) { /* does it have an upvalue? */ + /* get global table from registry */ + Table *reg = hvalue(&G(L)->l_registry); + const TValue *gt = luaH_getint(reg, LUA_RIDX_GLOBALS); + /* set global table as 1st upvalue of 'f' (may be LUA_ENV) */ + setobj(L, f->upvals[0]->v, gt); + luaC_upvalbarrier(L, f->upvals[0]); + } + } + lua_unlock(L); + return status; +} + + +LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data, int strip) { + int status; + TValue *o; + lua_lock(L); + api_checknelems(L, 1); + o = L->top - 1; + if (isLfunction(o)) + status = luaU_dump(L, getproto(o), writer, data, strip); + else + status = 1; + lua_unlock(L); + return status; +} + + +LUA_API int lua_status (lua_State *L) { + return L->status; +} + + +/* +** Garbage-collection function +*/ + +LUA_API int lua_gc (lua_State *L, int what, int data) { + int res = 0; + global_State *g; + lua_lock(L); + g = G(L); + switch (what) { + case LUA_GCSTOP: { + g->gcrunning = 0; + break; + } + case LUA_GCRESTART: { + luaE_setdebt(g, 0); + g->gcrunning = 1; + break; + } + case LUA_GCCOLLECT: { + luaC_fullgc(L, 0); + break; + } + case LUA_GCCOUNT: { + /* GC values are expressed in Kbytes: #bytes/2^10 */ + res = cast_int(gettotalbytes(g) >> 10); + break; + } + case LUA_GCCOUNTB: { + res = cast_int(gettotalbytes(g) & 0x3ff); + break; + } + case LUA_GCSTEP: { + l_mem debt = 1; /* =1 to signal that it did an actual step */ + lu_byte oldrunning = g->gcrunning; + g->gcrunning = 1; /* allow GC to run */ + if (data == 0) { + luaE_setdebt(g, -GCSTEPSIZE); /* to do a "small" step */ + luaC_step(L); + } + else { /* add 'data' to total debt */ + debt = cast(l_mem, data) * 1024 + g->GCdebt; + luaE_setdebt(g, debt); + luaC_checkGC(L); + } + g->gcrunning = oldrunning; /* restore previous state */ + if (debt > 0 && g->gcstate == GCSpause) /* end of cycle? */ + res = 1; /* signal it */ + break; + } + case LUA_GCSETPAUSE: { + res = g->gcpause; + g->gcpause = data; + break; + } + case LUA_GCSETSTEPMUL: { + res = g->gcstepmul; + if (data < 40) data = 40; /* avoid ridiculous low values (and 0) */ + g->gcstepmul = data; + break; + } + case LUA_GCISRUNNING: { + res = g->gcrunning; + break; + } + default: res = -1; /* invalid option */ + } + lua_unlock(L); + return res; +} + + + +/* +** miscellaneous functions +*/ + + +LUA_API int lua_error (lua_State *L) { + lua_lock(L); + api_checknelems(L, 1); + luaG_errormsg(L); + /* code unreachable; will unlock when control actually leaves the kernel */ + return 0; /* to avoid warnings */ +} + + +LUA_API int lua_next (lua_State *L, int idx) { + StkId t; + int more; + lua_lock(L); + t = index2addr(L, idx); + api_check(L, ttistable(t), "table expected"); + more = luaH_next(L, hvalue(t), L->top - 1); + if (more) { + api_incr_top(L); + } + else /* no more elements */ + L->top -= 1; /* remove key */ + lua_unlock(L); + return more; +} + + +LUA_API void lua_concat (lua_State *L, int n) { + lua_lock(L); + api_checknelems(L, n); + if (n >= 2) { + luaV_concat(L, n); + } + else if (n == 0) { /* push empty string */ + setsvalue2s(L, L->top, luaS_newlstr(L, "", 0)); + api_incr_top(L); + } + /* else n == 1; nothing to do */ + luaC_checkGC(L); + lua_unlock(L); +} + + +LUA_API void lua_len (lua_State *L, int idx) { + StkId t; + lua_lock(L); + t = index2addr(L, idx); + luaV_objlen(L, L->top, t); + api_incr_top(L); + lua_unlock(L); +} + + +LUA_API lua_Alloc lua_getallocf (lua_State *L, void **ud) { + lua_Alloc f; + lua_lock(L); + if (ud) *ud = G(L)->ud; + f = G(L)->frealloc; + lua_unlock(L); + return f; +} + + +LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud) { + lua_lock(L); + G(L)->ud = ud; + G(L)->frealloc = f; + lua_unlock(L); +} + + +LUA_API void *lua_newuserdata (lua_State *L, size_t size) { + Udata *u; + lua_lock(L); + u = luaS_newudata(L, size); + setuvalue(L, L->top, u); + api_incr_top(L); + luaC_checkGC(L); + lua_unlock(L); + return getudatamem(u); +} + + + +static const char *aux_upvalue (StkId fi, int n, TValue **val, + CClosure **owner, UpVal **uv) { + switch (ttype(fi)) { + case LUA_TCCL: { /* C closure */ + CClosure *f = clCvalue(fi); + if (!(1 <= n && n <= f->nupvalues)) return NULL; + *val = &f->upvalue[n-1]; + if (owner) *owner = f; + return ""; + } + case LUA_TLCL: { /* Lua closure */ + LClosure *f = clLvalue(fi); + TString *name; + Proto *p = f->p; + if (!(1 <= n && n <= p->sizeupvalues)) return NULL; + *val = f->upvals[n-1]->v; + if (uv) *uv = f->upvals[n - 1]; + name = p->upvalues[n-1].name; + return (name == NULL) ? "(*no name)" : getstr(name); + } + default: return NULL; /* not a closure */ + } +} + + +LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) { + const char *name; + TValue *val = NULL; /* to avoid warnings */ + lua_lock(L); + name = aux_upvalue(index2addr(L, funcindex), n, &val, NULL, NULL); + if (name) { + setobj2s(L, L->top, val); + api_incr_top(L); + } + lua_unlock(L); + return name; +} + + +LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) { + const char *name; + TValue *val = NULL; /* to avoid warnings */ + CClosure *owner = NULL; + UpVal *uv = NULL; + StkId fi; + lua_lock(L); + fi = index2addr(L, funcindex); + api_checknelems(L, 1); + name = aux_upvalue(fi, n, &val, &owner, &uv); + if (name) { + L->top--; + setobj(L, val, L->top); + if (owner) { luaC_barrier(L, owner, L->top); } + else if (uv) { luaC_upvalbarrier(L, uv); } + } + lua_unlock(L); + return name; +} + + +static UpVal **getupvalref (lua_State *L, int fidx, int n) { + LClosure *f; + StkId fi = index2addr(L, fidx); + api_check(L, ttisLclosure(fi), "Lua function expected"); + f = clLvalue(fi); + api_check(L, (1 <= n && n <= f->p->sizeupvalues), "invalid upvalue index"); + return &f->upvals[n - 1]; /* get its upvalue pointer */ +} + + +LUA_API void *lua_upvalueid (lua_State *L, int fidx, int n) { + StkId fi = index2addr(L, fidx); + switch (ttype(fi)) { + case LUA_TLCL: { /* lua closure */ + return *getupvalref(L, fidx, n); + } + case LUA_TCCL: { /* C closure */ + CClosure *f = clCvalue(fi); + api_check(L, 1 <= n && n <= f->nupvalues, "invalid upvalue index"); + return &f->upvalue[n - 1]; + } + default: { + api_check(L, 0, "closure expected"); + return NULL; + } + } +} + + +LUA_API void lua_upvaluejoin (lua_State *L, int fidx1, int n1, + int fidx2, int n2) { + UpVal **up1 = getupvalref(L, fidx1, n1); + UpVal **up2 = getupvalref(L, fidx2, n2); + if (*up1 == *up2) + return; + luaC_upvdeccount(L, *up1); + *up1 = *up2; + (*up1)->refcount++; + if (upisopen(*up1)) (*up1)->u.open.touched = 1; + luaC_upvalbarrier(L, *up1); +} + + diff --git a/depends/lua/src/lauxlib.c b/depends/lua/src/lauxlib.c new file mode 100644 index 0000000000..ac68bd32da --- /dev/null +++ b/depends/lua/src/lauxlib.c @@ -0,0 +1,1048 @@ +/* +** $Id: lauxlib.c,v 1.289.1.1 2017/04/19 17:20:42 roberto Exp $ +** Auxiliary functions for building Lua libraries +** See Copyright Notice in lua.h +*/ + +#define lauxlib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include +#include +#include +#include +#include + + +/* +** This file uses only the official API of Lua. +** Any function declared here could be written as an application function. +*/ + +#include "lua.h" + +#include "lauxlib.h" + + +/* +** {====================================================== +** Traceback +** ======================================================= +*/ + + +#define LEVELS1 10 /* size of the first part of the stack */ +#define LEVELS2 11 /* size of the second part of the stack */ + + + +/* +** search for 'objidx' in table at index -1. +** return 1 + string at top if find a good name. +*/ +static int findfield (lua_State *L, int objidx, int level) { + if (level == 0 || !lua_istable(L, -1)) + return 0; /* not found */ + lua_pushnil(L); /* start 'next' loop */ + while (lua_next(L, -2)) { /* for each pair in table */ + if (lua_type(L, -2) == LUA_TSTRING) { /* ignore non-string keys */ + if (lua_rawequal(L, objidx, -1)) { /* found object? */ + lua_pop(L, 1); /* remove value (but keep name) */ + return 1; + } + else if (findfield(L, objidx, level - 1)) { /* try recursively */ + lua_remove(L, -2); /* remove table (but keep name) */ + lua_pushliteral(L, "."); + lua_insert(L, -2); /* place '.' between the two names */ + lua_concat(L, 3); + return 1; + } + } + lua_pop(L, 1); /* remove value */ + } + return 0; /* not found */ +} + + +/* +** Search for a name for a function in all loaded modules +*/ +static int pushglobalfuncname (lua_State *L, lua_Debug *ar) { + int top = lua_gettop(L); + lua_getinfo(L, "f", ar); /* push function */ + lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); + if (findfield(L, top + 1, 2)) { + const char *name = lua_tostring(L, -1); + if (strncmp(name, "_G.", 3) == 0) { /* name start with '_G.'? */ + lua_pushstring(L, name + 3); /* push name without prefix */ + lua_remove(L, -2); /* remove original name */ + } + lua_copy(L, -1, top + 1); /* move name to proper place */ + lua_pop(L, 2); /* remove pushed values */ + return 1; + } + else { + lua_settop(L, top); /* remove function and global table */ + return 0; + } +} + + +static void pushfuncname (lua_State *L, lua_Debug *ar) { + if (pushglobalfuncname(L, ar)) { /* try first a global name */ + lua_pushfstring(L, "function '%s'", lua_tostring(L, -1)); + lua_remove(L, -2); /* remove name */ + } + else if (*ar->namewhat != '\0') /* is there a name from code? */ + lua_pushfstring(L, "%s '%s'", ar->namewhat, ar->name); /* use it */ + else if (*ar->what == 'm') /* main? */ + lua_pushliteral(L, "main chunk"); + else if (*ar->what != 'C') /* for Lua functions, use */ + lua_pushfstring(L, "function <%s:%d>", ar->short_src, ar->linedefined); + else /* nothing left... */ + lua_pushliteral(L, "?"); +} + + +static int lastlevel (lua_State *L) { + lua_Debug ar; + int li = 1, le = 1; + /* find an upper bound */ + while (lua_getstack(L, le, &ar)) { li = le; le *= 2; } + /* do a binary search */ + while (li < le) { + int m = (li + le)/2; + if (lua_getstack(L, m, &ar)) li = m + 1; + else le = m; + } + return le - 1; +} + + +LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1, + const char *msg, int level) { + lua_Debug ar; + int top = lua_gettop(L); + int last = lastlevel(L1); + int n1 = (last - level > LEVELS1 + LEVELS2) ? LEVELS1 : -1; + if (msg) + lua_pushfstring(L, "%s\n", msg); + luaL_checkstack(L, 10, NULL); + lua_pushliteral(L, "stack traceback:"); + while (lua_getstack(L1, level++, &ar)) { + if (n1-- == 0) { /* too many levels? */ + lua_pushliteral(L, "\n\t..."); /* add a '...' */ + level = last - LEVELS2 + 1; /* and skip to last ones */ + } + else { + lua_getinfo(L1, "Slnt", &ar); + lua_pushfstring(L, "\n\t%s:", ar.short_src); + if (ar.currentline > 0) + lua_pushfstring(L, "%d:", ar.currentline); + lua_pushliteral(L, " in "); + pushfuncname(L, &ar); + if (ar.istailcall) + lua_pushliteral(L, "\n\t(...tail calls...)"); + lua_concat(L, lua_gettop(L) - top); + } + } + lua_concat(L, lua_gettop(L) - top); +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Error-report functions +** ======================================================= +*/ + +LUALIB_API int luaL_argerror (lua_State *L, int arg, const char *extramsg) { + lua_Debug ar; + if (!lua_getstack(L, 0, &ar)) /* no stack frame? */ + return luaL_error(L, "bad argument #%d (%s)", arg, extramsg); + lua_getinfo(L, "n", &ar); + if (strcmp(ar.namewhat, "method") == 0) { + arg--; /* do not count 'self' */ + if (arg == 0) /* error is in the self argument itself? */ + return luaL_error(L, "calling '%s' on bad self (%s)", + ar.name, extramsg); + } + if (ar.name == NULL) + ar.name = (pushglobalfuncname(L, &ar)) ? lua_tostring(L, -1) : "?"; + return luaL_error(L, "bad argument #%d to '%s' (%s)", + arg, ar.name, extramsg); +} + + +static int typeerror (lua_State *L, int arg, const char *tname) { + const char *msg; + const char *typearg; /* name for the type of the actual argument */ + if (luaL_getmetafield(L, arg, "__name") == LUA_TSTRING) + typearg = lua_tostring(L, -1); /* use the given type name */ + else if (lua_type(L, arg) == LUA_TLIGHTUSERDATA) + typearg = "light userdata"; /* special name for messages */ + else + typearg = luaL_typename(L, arg); /* standard name */ + msg = lua_pushfstring(L, "%s expected, got %s", tname, typearg); + return luaL_argerror(L, arg, msg); +} + + +static void tag_error (lua_State *L, int arg, int tag) { + typeerror(L, arg, lua_typename(L, tag)); +} + + +/* +** The use of 'lua_pushfstring' ensures this function does not +** need reserved stack space when called. +*/ +LUALIB_API void luaL_where (lua_State *L, int level) { + lua_Debug ar; + if (lua_getstack(L, level, &ar)) { /* check function at level */ + lua_getinfo(L, "Sl", &ar); /* get info about it */ + if (ar.currentline > 0) { /* is there info? */ + lua_pushfstring(L, "%s:%d: ", ar.short_src, ar.currentline); + return; + } + } + lua_pushfstring(L, ""); /* else, no information available... */ +} + + +/* +** Again, the use of 'lua_pushvfstring' ensures this function does +** not need reserved stack space when called. (At worst, it generates +** an error with "stack overflow" instead of the given message.) +*/ +LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) { + va_list argp; + va_start(argp, fmt); + luaL_where(L, 1); + lua_pushvfstring(L, fmt, argp); + va_end(argp); + lua_concat(L, 2); + return lua_error(L); +} + + +LUALIB_API int luaL_fileresult (lua_State *L, int stat, const char *fname) { + int en = errno; /* calls to Lua API may change this value */ + if (stat) { + lua_pushboolean(L, 1); + return 1; + } + else { + lua_pushnil(L); + if (fname) + lua_pushfstring(L, "%s: %s", fname, strerror(en)); + else + lua_pushstring(L, strerror(en)); + lua_pushinteger(L, en); + return 3; + } +} + + +#if !defined(l_inspectstat) /* { */ + +#if defined(LUA_USE_POSIX) + +#include + +/* +** use appropriate macros to interpret 'pclose' return status +*/ +#define l_inspectstat(stat,what) \ + if (WIFEXITED(stat)) { stat = WEXITSTATUS(stat); } \ + else if (WIFSIGNALED(stat)) { stat = WTERMSIG(stat); what = "signal"; } + +#else + +#define l_inspectstat(stat,what) /* no op */ + +#endif + +#endif /* } */ + + +LUALIB_API int luaL_execresult (lua_State *L, int stat) { + const char *what = "exit"; /* type of termination */ + if (stat == -1) /* error? */ + return luaL_fileresult(L, 0, NULL); + else { + l_inspectstat(stat, what); /* interpret result */ + if (*what == 'e' && stat == 0) /* successful termination? */ + lua_pushboolean(L, 1); + else + lua_pushnil(L); + lua_pushstring(L, what); + lua_pushinteger(L, stat); + return 3; /* return true/nil,what,code */ + } +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Userdata's metatable manipulation +** ======================================================= +*/ + +LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) { + if (luaL_getmetatable(L, tname) != LUA_TNIL) /* name already in use? */ + return 0; /* leave previous value on top, but return 0 */ + lua_pop(L, 1); + lua_createtable(L, 0, 2); /* create metatable */ + lua_pushstring(L, tname); + lua_setfield(L, -2, "__name"); /* metatable.__name = tname */ + lua_pushvalue(L, -1); + lua_setfield(L, LUA_REGISTRYINDEX, tname); /* registry.name = metatable */ + return 1; +} + + +LUALIB_API void luaL_setmetatable (lua_State *L, const char *tname) { + luaL_getmetatable(L, tname); + lua_setmetatable(L, -2); +} + + +LUALIB_API void *luaL_testudata (lua_State *L, int ud, const char *tname) { + void *p = lua_touserdata(L, ud); + if (p != NULL) { /* value is a userdata? */ + if (lua_getmetatable(L, ud)) { /* does it have a metatable? */ + luaL_getmetatable(L, tname); /* get correct metatable */ + if (!lua_rawequal(L, -1, -2)) /* not the same? */ + p = NULL; /* value is a userdata with wrong metatable */ + lua_pop(L, 2); /* remove both metatables */ + return p; + } + } + return NULL; /* value is not a userdata with a metatable */ +} + + +LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname) { + void *p = luaL_testudata(L, ud, tname); + if (p == NULL) typeerror(L, ud, tname); + return p; +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Argument check functions +** ======================================================= +*/ + +LUALIB_API int luaL_checkoption (lua_State *L, int arg, const char *def, + const char *const lst[]) { + const char *name = (def) ? luaL_optstring(L, arg, def) : + luaL_checkstring(L, arg); + int i; + for (i=0; lst[i]; i++) + if (strcmp(lst[i], name) == 0) + return i; + return luaL_argerror(L, arg, + lua_pushfstring(L, "invalid option '%s'", name)); +} + + +/* +** Ensures the stack has at least 'space' extra slots, raising an error +** if it cannot fulfill the request. (The error handling needs a few +** extra slots to format the error message. In case of an error without +** this extra space, Lua will generate the same 'stack overflow' error, +** but without 'msg'.) +*/ +LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg) { + if (!lua_checkstack(L, space)) { + if (msg) + luaL_error(L, "stack overflow (%s)", msg); + else + luaL_error(L, "stack overflow"); + } +} + + +LUALIB_API void luaL_checktype (lua_State *L, int arg, int t) { + if (lua_type(L, arg) != t) + tag_error(L, arg, t); +} + + +LUALIB_API void luaL_checkany (lua_State *L, int arg) { + if (lua_type(L, arg) == LUA_TNONE) + luaL_argerror(L, arg, "value expected"); +} + + +LUALIB_API const char *luaL_checklstring (lua_State *L, int arg, size_t *len) { + const char *s = lua_tolstring(L, arg, len); + if (!s) tag_error(L, arg, LUA_TSTRING); + return s; +} + + +LUALIB_API const char *luaL_optlstring (lua_State *L, int arg, + const char *def, size_t *len) { + if (lua_isnoneornil(L, arg)) { + if (len) + *len = (def ? strlen(def) : 0); + return def; + } + else return luaL_checklstring(L, arg, len); +} + + +LUALIB_API lua_Number luaL_checknumber (lua_State *L, int arg) { + int isnum; + lua_Number d = lua_tonumberx(L, arg, &isnum); + if (!isnum) + tag_error(L, arg, LUA_TNUMBER); + return d; +} + + +LUALIB_API lua_Number luaL_optnumber (lua_State *L, int arg, lua_Number def) { + return luaL_opt(L, luaL_checknumber, arg, def); +} + + +static void interror (lua_State *L, int arg) { + if (lua_isnumber(L, arg)) + luaL_argerror(L, arg, "number has no integer representation"); + else + tag_error(L, arg, LUA_TNUMBER); +} + + +LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int arg) { + int isnum; + lua_Integer d = lua_tointegerx(L, arg, &isnum); + if (!isnum) { + interror(L, arg); + } + return d; +} + + +LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int arg, + lua_Integer def) { + return luaL_opt(L, luaL_checkinteger, arg, def); +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Generic Buffer manipulation +** ======================================================= +*/ + +/* userdata to box arbitrary data */ +typedef struct UBox { + void *box; + size_t bsize; +} UBox; + + +static void *resizebox (lua_State *L, int idx, size_t newsize) { + void *ud; + lua_Alloc allocf = lua_getallocf(L, &ud); + UBox *box = (UBox *)lua_touserdata(L, idx); + void *temp = allocf(ud, box->box, box->bsize, newsize); + if (temp == NULL && newsize > 0) { /* allocation error? */ + resizebox(L, idx, 0); /* free buffer */ + luaL_error(L, "not enough memory for buffer allocation"); + } + box->box = temp; + box->bsize = newsize; + return temp; +} + + +static int boxgc (lua_State *L) { + resizebox(L, 1, 0); + return 0; +} + + +static void *newbox (lua_State *L, size_t newsize) { + UBox *box = (UBox *)lua_newuserdata(L, sizeof(UBox)); + box->box = NULL; + box->bsize = 0; + if (luaL_newmetatable(L, "LUABOX")) { /* creating metatable? */ + lua_pushcfunction(L, boxgc); + lua_setfield(L, -2, "__gc"); /* metatable.__gc = boxgc */ + } + lua_setmetatable(L, -2); + return resizebox(L, -1, newsize); +} + + +/* +** check whether buffer is using a userdata on the stack as a temporary +** buffer +*/ +#define buffonstack(B) ((B)->b != (B)->initb) + + +/* +** returns a pointer to a free area with at least 'sz' bytes +*/ +LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) { + lua_State *L = B->L; + if (B->size - B->n < sz) { /* not enough space? */ + char *newbuff; + size_t newsize = B->size * 2; /* double buffer size */ + if (newsize - B->n < sz) /* not big enough? */ + newsize = B->n + sz; + if (newsize < B->n || newsize - B->n < sz) + luaL_error(L, "buffer too large"); + /* create larger buffer */ + if (buffonstack(B)) + newbuff = (char *)resizebox(L, -1, newsize); + else { /* no buffer yet */ + newbuff = (char *)newbox(L, newsize); + memcpy(newbuff, B->b, B->n * sizeof(char)); /* copy original content */ + } + B->b = newbuff; + B->size = newsize; + } + return &B->b[B->n]; +} + + +LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) { + if (l > 0) { /* avoid 'memcpy' when 's' can be NULL */ + char *b = luaL_prepbuffsize(B, l); + memcpy(b, s, l * sizeof(char)); + luaL_addsize(B, l); + } +} + + +LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) { + luaL_addlstring(B, s, strlen(s)); +} + + +LUALIB_API void luaL_pushresult (luaL_Buffer *B) { + lua_State *L = B->L; + lua_pushlstring(L, B->b, B->n); + if (buffonstack(B)) { + resizebox(L, -2, 0); /* delete old buffer */ + lua_remove(L, -2); /* remove its header from the stack */ + } +} + + +LUALIB_API void luaL_pushresultsize (luaL_Buffer *B, size_t sz) { + luaL_addsize(B, sz); + luaL_pushresult(B); +} + + +LUALIB_API void luaL_addvalue (luaL_Buffer *B) { + lua_State *L = B->L; + size_t l; + const char *s = lua_tolstring(L, -1, &l); + if (buffonstack(B)) + lua_insert(L, -2); /* put value below buffer */ + luaL_addlstring(B, s, l); + lua_remove(L, (buffonstack(B)) ? -2 : -1); /* remove value */ +} + + +LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) { + B->L = L; + B->b = B->initb; + B->n = 0; + B->size = LUAL_BUFFERSIZE; +} + + +LUALIB_API char *luaL_buffinitsize (lua_State *L, luaL_Buffer *B, size_t sz) { + luaL_buffinit(L, B); + return luaL_prepbuffsize(B, sz); +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Reference system +** ======================================================= +*/ + +/* index of free-list header */ +#define freelist 0 + + +LUALIB_API int luaL_ref (lua_State *L, int t) { + int ref; + if (lua_isnil(L, -1)) { + lua_pop(L, 1); /* remove from stack */ + return LUA_REFNIL; /* 'nil' has a unique fixed reference */ + } + t = lua_absindex(L, t); + lua_rawgeti(L, t, freelist); /* get first free element */ + ref = (int)lua_tointeger(L, -1); /* ref = t[freelist] */ + lua_pop(L, 1); /* remove it from stack */ + if (ref != 0) { /* any free element? */ + lua_rawgeti(L, t, ref); /* remove it from list */ + lua_rawseti(L, t, freelist); /* (t[freelist] = t[ref]) */ + } + else /* no free elements */ + ref = (int)lua_rawlen(L, t) + 1; /* get a new reference */ + lua_rawseti(L, t, ref); + return ref; +} + + +LUALIB_API void luaL_unref (lua_State *L, int t, int ref) { + if (ref >= 0) { + t = lua_absindex(L, t); + lua_rawgeti(L, t, freelist); + lua_rawseti(L, t, ref); /* t[ref] = t[freelist] */ + lua_pushinteger(L, ref); + lua_rawseti(L, t, freelist); /* t[freelist] = ref */ + } +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Load functions +** ======================================================= +*/ + +typedef struct LoadF { + int n; /* number of pre-read characters */ + FILE *f; /* file being read */ + char buff[BUFSIZ]; /* area for reading file */ +} LoadF; + + +static const char *getF (lua_State *L, void *ud, size_t *size) { + LoadF *lf = (LoadF *)ud; + (void)L; /* not used */ + if (lf->n > 0) { /* are there pre-read characters to be read? */ + *size = lf->n; /* return them (chars already in buffer) */ + lf->n = 0; /* no more pre-read characters */ + } + else { /* read a block from file */ + /* 'fread' can return > 0 *and* set the EOF flag. If next call to + 'getF' called 'fread', it might still wait for user input. + The next check avoids this problem. */ + if (feof(lf->f)) return NULL; + *size = fread(lf->buff, 1, sizeof(lf->buff), lf->f); /* read block */ + } + return lf->buff; +} + + +static int errfile (lua_State *L, const char *what, int fnameindex) { + const char *serr = strerror(errno); + const char *filename = lua_tostring(L, fnameindex) + 1; + lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr); + lua_remove(L, fnameindex); + return LUA_ERRFILE; +} + + +static int skipBOM (LoadF *lf) { + const char *p = "\xEF\xBB\xBF"; /* UTF-8 BOM mark */ + int c; + lf->n = 0; + do { + c = getc(lf->f); + if (c == EOF || c != *(const unsigned char *)p++) return c; + lf->buff[lf->n++] = c; /* to be read by the parser */ + } while (*p != '\0'); + lf->n = 0; /* prefix matched; discard it */ + return getc(lf->f); /* return next character */ +} + + +/* +** reads the first character of file 'f' and skips an optional BOM mark +** in its beginning plus its first line if it starts with '#'. Returns +** true if it skipped the first line. In any case, '*cp' has the +** first "valid" character of the file (after the optional BOM and +** a first-line comment). +*/ +static int skipcomment (LoadF *lf, int *cp) { + int c = *cp = skipBOM(lf); + if (c == '#') { /* first line is a comment (Unix exec. file)? */ + do { /* skip first line */ + c = getc(lf->f); + } while (c != EOF && c != '\n'); + *cp = getc(lf->f); /* skip end-of-line, if present */ + return 1; /* there was a comment */ + } + else return 0; /* no comment */ +} + + +LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename, + const char *mode) { + LoadF lf; + int status, readstatus; + int c; + int fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */ + if (filename == NULL) { + lua_pushliteral(L, "=stdin"); + lf.f = stdin; + } + else { + lua_pushfstring(L, "@%s", filename); + lf.f = fopen(filename, "r"); + if (lf.f == NULL) return errfile(L, "open", fnameindex); + } + if (skipcomment(&lf, &c)) /* read initial portion */ + lf.buff[lf.n++] = '\n'; /* add line to correct line numbers */ + if (c == LUA_SIGNATURE[0] && filename) { /* binary file? */ + lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */ + if (lf.f == NULL) return errfile(L, "reopen", fnameindex); + skipcomment(&lf, &c); /* re-read initial portion */ + } + if (c != EOF) + lf.buff[lf.n++] = c; /* 'c' is the first character of the stream */ + status = lua_load(L, getF, &lf, lua_tostring(L, -1), mode); + readstatus = ferror(lf.f); + if (filename) fclose(lf.f); /* close file (even in case of errors) */ + if (readstatus) { + lua_settop(L, fnameindex); /* ignore results from 'lua_load' */ + return errfile(L, "read", fnameindex); + } + lua_remove(L, fnameindex); + return status; +} + + +typedef struct LoadS { + const char *s; + size_t size; +} LoadS; + + +static const char *getS (lua_State *L, void *ud, size_t *size) { + LoadS *ls = (LoadS *)ud; + (void)L; /* not used */ + if (ls->size == 0) return NULL; + *size = ls->size; + ls->size = 0; + return ls->s; +} + + +LUALIB_API int luaL_loadbufferx (lua_State *L, const char *buff, size_t size, + const char *name, const char *mode) { + LoadS ls; + ls.s = buff; + ls.size = size; + return lua_load(L, getS, &ls, name, mode); +} + + +LUALIB_API int luaL_loadstring (lua_State *L, const char *s) { + return luaL_loadbuffer(L, s, strlen(s), s); +} + +/* }====================================================== */ + + + +LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) { + if (!lua_getmetatable(L, obj)) /* no metatable? */ + return LUA_TNIL; + else { + int tt; + lua_pushstring(L, event); + tt = lua_rawget(L, -2); + if (tt == LUA_TNIL) /* is metafield nil? */ + lua_pop(L, 2); /* remove metatable and metafield */ + else + lua_remove(L, -2); /* remove only metatable */ + return tt; /* return metafield type */ + } +} + + +LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) { + obj = lua_absindex(L, obj); + if (luaL_getmetafield(L, obj, event) == LUA_TNIL) /* no metafield? */ + return 0; + lua_pushvalue(L, obj); + lua_call(L, 1, 1); + return 1; +} + + +LUALIB_API lua_Integer luaL_len (lua_State *L, int idx) { + lua_Integer l; + int isnum; + lua_len(L, idx); + l = lua_tointegerx(L, -1, &isnum); + if (!isnum) + luaL_error(L, "object length is not an integer"); + lua_pop(L, 1); /* remove object */ + return l; +} + + +LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) { + if (luaL_callmeta(L, idx, "__tostring")) { /* metafield? */ + if (!lua_isstring(L, -1)) + luaL_error(L, "'__tostring' must return a string"); + } + else { + switch (lua_type(L, idx)) { + case LUA_TNUMBER: { + if (lua_isinteger(L, idx)) + lua_pushfstring(L, "%I", (LUAI_UACINT)lua_tointeger(L, idx)); + else + lua_pushfstring(L, "%f", (LUAI_UACNUMBER)lua_tonumber(L, idx)); + break; + } + case LUA_TSTRING: + lua_pushvalue(L, idx); + break; + case LUA_TBOOLEAN: + lua_pushstring(L, (lua_toboolean(L, idx) ? "true" : "false")); + break; + case LUA_TNIL: + lua_pushliteral(L, "nil"); + break; + default: { + int tt = luaL_getmetafield(L, idx, "__name"); /* try name */ + const char *kind = (tt == LUA_TSTRING) ? lua_tostring(L, -1) : + luaL_typename(L, idx); + lua_pushfstring(L, "%s: %p", kind, lua_topointer(L, idx)); + if (tt != LUA_TNIL) + lua_remove(L, -2); /* remove '__name' */ + break; + } + } + } + return lua_tolstring(L, -1, len); +} + + +/* +** {====================================================== +** Compatibility with 5.1 module functions +** ======================================================= +*/ +#if defined(LUA_COMPAT_MODULE) + +static const char *luaL_findtable (lua_State *L, int idx, + const char *fname, int szhint) { + const char *e; + if (idx) lua_pushvalue(L, idx); + do { + e = strchr(fname, '.'); + if (e == NULL) e = fname + strlen(fname); + lua_pushlstring(L, fname, e - fname); + if (lua_rawget(L, -2) == LUA_TNIL) { /* no such field? */ + lua_pop(L, 1); /* remove this nil */ + lua_createtable(L, 0, (*e == '.' ? 1 : szhint)); /* new table for field */ + lua_pushlstring(L, fname, e - fname); + lua_pushvalue(L, -2); + lua_settable(L, -4); /* set new table into field */ + } + else if (!lua_istable(L, -1)) { /* field has a non-table value? */ + lua_pop(L, 2); /* remove table and value */ + return fname; /* return problematic part of the name */ + } + lua_remove(L, -2); /* remove previous table */ + fname = e + 1; + } while (*e == '.'); + return NULL; +} + + +/* +** Count number of elements in a luaL_Reg list. +*/ +static int libsize (const luaL_Reg *l) { + int size = 0; + for (; l && l->name; l++) size++; + return size; +} + + +/* +** Find or create a module table with a given name. The function +** first looks at the LOADED table and, if that fails, try a +** global variable with that name. In any case, leaves on the stack +** the module table. +*/ +LUALIB_API void luaL_pushmodule (lua_State *L, const char *modname, + int sizehint) { + luaL_findtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE, 1); + if (lua_getfield(L, -1, modname) != LUA_TTABLE) { /* no LOADED[modname]? */ + lua_pop(L, 1); /* remove previous result */ + /* try global variable (and create one if it does not exist) */ + lua_pushglobaltable(L); + if (luaL_findtable(L, 0, modname, sizehint) != NULL) + luaL_error(L, "name conflict for module '%s'", modname); + lua_pushvalue(L, -1); + lua_setfield(L, -3, modname); /* LOADED[modname] = new table */ + } + lua_remove(L, -2); /* remove LOADED table */ +} + + +LUALIB_API void luaL_openlib (lua_State *L, const char *libname, + const luaL_Reg *l, int nup) { + luaL_checkversion(L); + if (libname) { + luaL_pushmodule(L, libname, libsize(l)); /* get/create library table */ + lua_insert(L, -(nup + 1)); /* move library table to below upvalues */ + } + if (l) + luaL_setfuncs(L, l, nup); + else + lua_pop(L, nup); /* remove upvalues */ +} + +#endif +/* }====================================================== */ + +/* +** set functions from list 'l' into table at top - 'nup'; each +** function gets the 'nup' elements at the top as upvalues. +** Returns with only the table at the stack. +*/ +LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) { + luaL_checkstack(L, nup, "too many upvalues"); + for (; l->name != NULL; l++) { /* fill the table with given functions */ + int i; + for (i = 0; i < nup; i++) /* copy upvalues to the top */ + lua_pushvalue(L, -nup); + lua_pushcclosure(L, l->func, nup); /* closure with those upvalues */ + lua_setfield(L, -(nup + 2), l->name); + } + lua_pop(L, nup); /* remove upvalues */ +} + + +/* +** ensure that stack[idx][fname] has a table and push that table +** into the stack +*/ +LUALIB_API int luaL_getsubtable (lua_State *L, int idx, const char *fname) { + if (lua_getfield(L, idx, fname) == LUA_TTABLE) + return 1; /* table already there */ + else { + lua_pop(L, 1); /* remove previous result */ + idx = lua_absindex(L, idx); + lua_newtable(L); + lua_pushvalue(L, -1); /* copy to be left at top */ + lua_setfield(L, idx, fname); /* assign new table to field */ + return 0; /* false, because did not find table there */ + } +} + + +/* +** Stripped-down 'require': After checking "loaded" table, calls 'openf' +** to open a module, registers the result in 'package.loaded' table and, +** if 'glb' is true, also registers the result in the global table. +** Leaves resulting module on the top. +*/ +LUALIB_API void luaL_requiref (lua_State *L, const char *modname, + lua_CFunction openf, int glb) { + luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); + lua_getfield(L, -1, modname); /* LOADED[modname] */ + if (!lua_toboolean(L, -1)) { /* package not already loaded? */ + lua_pop(L, 1); /* remove field */ + lua_pushcfunction(L, openf); + lua_pushstring(L, modname); /* argument to open function */ + lua_call(L, 1, 1); /* call 'openf' to open module */ + lua_pushvalue(L, -1); /* make copy of module (call result) */ + lua_setfield(L, -3, modname); /* LOADED[modname] = module */ + } + lua_remove(L, -2); /* remove LOADED table */ + if (glb) { + lua_pushvalue(L, -1); /* copy of module */ + lua_setglobal(L, modname); /* _G[modname] = module */ + } +} + + +LUALIB_API const char *luaL_gsub (lua_State *L, const char *s, const char *p, + const char *r) { + const char *wild; + size_t l = strlen(p); + luaL_Buffer b; + luaL_buffinit(L, &b); + while ((wild = strstr(s, p)) != NULL) { + luaL_addlstring(&b, s, wild - s); /* push prefix */ + luaL_addstring(&b, r); /* push replacement in place of pattern */ + s = wild + l; /* continue after 'p' */ + } + luaL_addstring(&b, s); /* push last suffix */ + luaL_pushresult(&b); + return lua_tostring(L, -1); +} + + +static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { + (void)ud; (void)osize; /* not used */ + if (nsize == 0) { + free(ptr); + return NULL; + } + else { /* cannot fail when shrinking a block */ + void *newptr = realloc(ptr, nsize); + if (newptr == NULL && ptr != NULL && nsize <= osize) + return ptr; /* keep the original block */ + else /* no fail or not shrinking */ + return newptr; /* use the new block */ + } +} + + +static int panic (lua_State *L) { + lua_writestringerror("PANIC: unprotected error in call to Lua API (%s)\n", + lua_tostring(L, -1)); + return 0; /* return to Lua to abort */ +} + + +LUALIB_API lua_State *luaL_newstate (void) { + lua_State *L = lua_newstate(l_alloc, NULL); + if (L) lua_atpanic(L, &panic); + return L; +} + + +LUALIB_API void luaL_checkversion_ (lua_State *L, lua_Number ver, size_t sz) { + const lua_Number *v = lua_version(L); + if (sz != LUAL_NUMSIZES) /* check numeric types */ + luaL_error(L, "core and library have incompatible numeric types"); + if (v != lua_version(NULL)) + luaL_error(L, "multiple Lua VMs detected"); + else if (*v != ver) + luaL_error(L, "version mismatch: app. needs %f, Lua core provides %f", + (LUAI_UACNUMBER)ver, (LUAI_UACNUMBER)*v); +} + diff --git a/depends/lua/src/lbaselib.c b/depends/lua/src/lbaselib.c new file mode 100644 index 0000000000..6460e4f8d4 --- /dev/null +++ b/depends/lua/src/lbaselib.c @@ -0,0 +1,498 @@ +/* +** $Id: lbaselib.c,v 1.314.1.1 2017/04/19 17:39:34 roberto Exp $ +** Basic library +** See Copyright Notice in lua.h +*/ + +#define lbaselib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include +#include +#include +#include + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +static int luaB_print (lua_State *L) { + int n = lua_gettop(L); /* number of arguments */ + int i; + lua_getglobal(L, "tostring"); + for (i=1; i<=n; i++) { + const char *s; + size_t l; + lua_pushvalue(L, -1); /* function to be called */ + lua_pushvalue(L, i); /* value to print */ + lua_call(L, 1, 1); + s = lua_tolstring(L, -1, &l); /* get result */ + if (s == NULL) + return luaL_error(L, "'tostring' must return a string to 'print'"); + if (i>1) lua_writestring("\t", 1); + lua_writestring(s, l); + lua_pop(L, 1); /* pop result */ + } + lua_writeline(); + return 0; +} + + +#define SPACECHARS " \f\n\r\t\v" + +static const char *b_str2int (const char *s, int base, lua_Integer *pn) { + lua_Unsigned n = 0; + int neg = 0; + s += strspn(s, SPACECHARS); /* skip initial spaces */ + if (*s == '-') { s++; neg = 1; } /* handle signal */ + else if (*s == '+') s++; + if (!isalnum((unsigned char)*s)) /* no digit? */ + return NULL; + do { + int digit = (isdigit((unsigned char)*s)) ? *s - '0' + : (toupper((unsigned char)*s) - 'A') + 10; + if (digit >= base) return NULL; /* invalid numeral */ + n = n * base + digit; + s++; + } while (isalnum((unsigned char)*s)); + s += strspn(s, SPACECHARS); /* skip trailing spaces */ + *pn = (lua_Integer)((neg) ? (0u - n) : n); + return s; +} + + +static int luaB_tonumber (lua_State *L) { + if (lua_isnoneornil(L, 2)) { /* standard conversion? */ + luaL_checkany(L, 1); + if (lua_type(L, 1) == LUA_TNUMBER) { /* already a number? */ + lua_settop(L, 1); /* yes; return it */ + return 1; + } + else { + size_t l; + const char *s = lua_tolstring(L, 1, &l); + if (s != NULL && lua_stringtonumber(L, s) == l + 1) + return 1; /* successful conversion to number */ + /* else not a number */ + } + } + else { + size_t l; + const char *s; + lua_Integer n = 0; /* to avoid warnings */ + lua_Integer base = luaL_checkinteger(L, 2); + luaL_checktype(L, 1, LUA_TSTRING); /* no numbers as strings */ + s = lua_tolstring(L, 1, &l); + luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range"); + if (b_str2int(s, (int)base, &n) == s + l) { + lua_pushinteger(L, n); + return 1; + } /* else not a number */ + } /* else not a number */ + lua_pushnil(L); /* not a number */ + return 1; +} + + +static int luaB_error (lua_State *L) { + int level = (int)luaL_optinteger(L, 2, 1); + lua_settop(L, 1); + if (lua_type(L, 1) == LUA_TSTRING && level > 0) { + luaL_where(L, level); /* add extra information */ + lua_pushvalue(L, 1); + lua_concat(L, 2); + } + return lua_error(L); +} + + +static int luaB_getmetatable (lua_State *L) { + luaL_checkany(L, 1); + if (!lua_getmetatable(L, 1)) { + lua_pushnil(L); + return 1; /* no metatable */ + } + luaL_getmetafield(L, 1, "__metatable"); + return 1; /* returns either __metatable field (if present) or metatable */ +} + + +static int luaB_setmetatable (lua_State *L) { + int t = lua_type(L, 2); + luaL_checktype(L, 1, LUA_TTABLE); + luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, + "nil or table expected"); + if (luaL_getmetafield(L, 1, "__metatable") != LUA_TNIL) + return luaL_error(L, "cannot change a protected metatable"); + lua_settop(L, 2); + lua_setmetatable(L, 1); + return 1; +} + + +static int luaB_rawequal (lua_State *L) { + luaL_checkany(L, 1); + luaL_checkany(L, 2); + lua_pushboolean(L, lua_rawequal(L, 1, 2)); + return 1; +} + + +static int luaB_rawlen (lua_State *L) { + int t = lua_type(L, 1); + luaL_argcheck(L, t == LUA_TTABLE || t == LUA_TSTRING, 1, + "table or string expected"); + lua_pushinteger(L, lua_rawlen(L, 1)); + return 1; +} + + +static int luaB_rawget (lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); + luaL_checkany(L, 2); + lua_settop(L, 2); + lua_rawget(L, 1); + return 1; +} + +static int luaB_rawset (lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); + luaL_checkany(L, 2); + luaL_checkany(L, 3); + lua_settop(L, 3); + lua_rawset(L, 1); + return 1; +} + + +static int luaB_collectgarbage (lua_State *L) { + static const char *const opts[] = {"stop", "restart", "collect", + "count", "step", "setpause", "setstepmul", + "isrunning", NULL}; + static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT, + LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL, + LUA_GCISRUNNING}; + int o = optsnum[luaL_checkoption(L, 1, "collect", opts)]; + int ex = (int)luaL_optinteger(L, 2, 0); + int res = lua_gc(L, o, ex); + switch (o) { + case LUA_GCCOUNT: { + int b = lua_gc(L, LUA_GCCOUNTB, 0); + lua_pushnumber(L, (lua_Number)res + ((lua_Number)b/1024)); + return 1; + } + case LUA_GCSTEP: case LUA_GCISRUNNING: { + lua_pushboolean(L, res); + return 1; + } + default: { + lua_pushinteger(L, res); + return 1; + } + } +} + + +static int luaB_type (lua_State *L) { + int t = lua_type(L, 1); + luaL_argcheck(L, t != LUA_TNONE, 1, "value expected"); + lua_pushstring(L, lua_typename(L, t)); + return 1; +} + + +static int pairsmeta (lua_State *L, const char *method, int iszero, + lua_CFunction iter) { + luaL_checkany(L, 1); + if (luaL_getmetafield(L, 1, method) == LUA_TNIL) { /* no metamethod? */ + lua_pushcfunction(L, iter); /* will return generator, */ + lua_pushvalue(L, 1); /* state, */ + if (iszero) lua_pushinteger(L, 0); /* and initial value */ + else lua_pushnil(L); + } + else { + lua_pushvalue(L, 1); /* argument 'self' to metamethod */ + lua_call(L, 1, 3); /* get 3 values from metamethod */ + } + return 3; +} + + +static int luaB_next (lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); + lua_settop(L, 2); /* create a 2nd argument if there isn't one */ + if (lua_next(L, 1)) + return 2; + else { + lua_pushnil(L); + return 1; + } +} + + +static int luaB_pairs (lua_State *L) { + return pairsmeta(L, "__pairs", 0, luaB_next); +} + + +/* +** Traversal function for 'ipairs' +*/ +static int ipairsaux (lua_State *L) { + lua_Integer i = luaL_checkinteger(L, 2) + 1; + lua_pushinteger(L, i); + return (lua_geti(L, 1, i) == LUA_TNIL) ? 1 : 2; +} + + +/* +** 'ipairs' function. Returns 'ipairsaux', given "table", 0. +** (The given "table" may not be a table.) +*/ +static int luaB_ipairs (lua_State *L) { +#if defined(LUA_COMPAT_IPAIRS) + return pairsmeta(L, "__ipairs", 1, ipairsaux); +#else + luaL_checkany(L, 1); + lua_pushcfunction(L, ipairsaux); /* iteration function */ + lua_pushvalue(L, 1); /* state */ + lua_pushinteger(L, 0); /* initial value */ + return 3; +#endif +} + + +static int load_aux (lua_State *L, int status, int envidx) { + if (status == LUA_OK) { + if (envidx != 0) { /* 'env' parameter? */ + lua_pushvalue(L, envidx); /* environment for loaded function */ + if (!lua_setupvalue(L, -2, 1)) /* set it as 1st upvalue */ + lua_pop(L, 1); /* remove 'env' if not used by previous call */ + } + return 1; + } + else { /* error (message is on top of the stack) */ + lua_pushnil(L); + lua_insert(L, -2); /* put before error message */ + return 2; /* return nil plus error message */ + } +} + + +static int luaB_loadfile (lua_State *L) { + const char *fname = luaL_optstring(L, 1, NULL); + const char *mode = luaL_optstring(L, 2, NULL); + int env = (!lua_isnone(L, 3) ? 3 : 0); /* 'env' index or 0 if no 'env' */ + int status = luaL_loadfilex(L, fname, mode); + return load_aux(L, status, env); +} + + +/* +** {====================================================== +** Generic Read function +** ======================================================= +*/ + + +/* +** reserved slot, above all arguments, to hold a copy of the returned +** string to avoid it being collected while parsed. 'load' has four +** optional arguments (chunk, source name, mode, and environment). +*/ +#define RESERVEDSLOT 5 + + +/* +** Reader for generic 'load' function: 'lua_load' uses the +** stack for internal stuff, so the reader cannot change the +** stack top. Instead, it keeps its resulting string in a +** reserved slot inside the stack. +*/ +static const char *generic_reader (lua_State *L, void *ud, size_t *size) { + (void)(ud); /* not used */ + luaL_checkstack(L, 2, "too many nested functions"); + lua_pushvalue(L, 1); /* get function */ + lua_call(L, 0, 1); /* call it */ + if (lua_isnil(L, -1)) { + lua_pop(L, 1); /* pop result */ + *size = 0; + return NULL; + } + else if (!lua_isstring(L, -1)) + luaL_error(L, "reader function must return a string"); + lua_replace(L, RESERVEDSLOT); /* save string in reserved slot */ + return lua_tolstring(L, RESERVEDSLOT, size); +} + + +static int luaB_load (lua_State *L) { + int status; + size_t l; + const char *s = lua_tolstring(L, 1, &l); + const char *mode = luaL_optstring(L, 3, "bt"); + int env = (!lua_isnone(L, 4) ? 4 : 0); /* 'env' index or 0 if no 'env' */ + if (s != NULL) { /* loading a string? */ + const char *chunkname = luaL_optstring(L, 2, s); + status = luaL_loadbufferx(L, s, l, chunkname, mode); + } + else { /* loading from a reader function */ + const char *chunkname = luaL_optstring(L, 2, "=(load)"); + luaL_checktype(L, 1, LUA_TFUNCTION); + lua_settop(L, RESERVEDSLOT); /* create reserved slot */ + status = lua_load(L, generic_reader, NULL, chunkname, mode); + } + return load_aux(L, status, env); +} + +/* }====================================================== */ + + +static int dofilecont (lua_State *L, int d1, lua_KContext d2) { + (void)d1; (void)d2; /* only to match 'lua_Kfunction' prototype */ + return lua_gettop(L) - 1; +} + + +static int luaB_dofile (lua_State *L) { + const char *fname = luaL_optstring(L, 1, NULL); + lua_settop(L, 1); + if (luaL_loadfile(L, fname) != LUA_OK) + return lua_error(L); + lua_callk(L, 0, LUA_MULTRET, 0, dofilecont); + return dofilecont(L, 0, 0); +} + + +static int luaB_assert (lua_State *L) { + if (lua_toboolean(L, 1)) /* condition is true? */ + return lua_gettop(L); /* return all arguments */ + else { /* error */ + luaL_checkany(L, 1); /* there must be a condition */ + lua_remove(L, 1); /* remove it */ + lua_pushliteral(L, "assertion failed!"); /* default message */ + lua_settop(L, 1); /* leave only message (default if no other one) */ + return luaB_error(L); /* call 'error' */ + } +} + + +static int luaB_select (lua_State *L) { + int n = lua_gettop(L); + if (lua_type(L, 1) == LUA_TSTRING && *lua_tostring(L, 1) == '#') { + lua_pushinteger(L, n-1); + return 1; + } + else { + lua_Integer i = luaL_checkinteger(L, 1); + if (i < 0) i = n + i; + else if (i > n) i = n; + luaL_argcheck(L, 1 <= i, 1, "index out of range"); + return n - (int)i; + } +} + + +/* +** Continuation function for 'pcall' and 'xpcall'. Both functions +** already pushed a 'true' before doing the call, so in case of success +** 'finishpcall' only has to return everything in the stack minus +** 'extra' values (where 'extra' is exactly the number of items to be +** ignored). +*/ +static int finishpcall (lua_State *L, int status, lua_KContext extra) { + if (status != LUA_OK && status != LUA_YIELD) { /* error? */ + lua_pushboolean(L, 0); /* first result (false) */ + lua_pushvalue(L, -2); /* error message */ + return 2; /* return false, msg */ + } + else + return lua_gettop(L) - (int)extra; /* return all results */ +} + + +static int luaB_pcall (lua_State *L) { + int status; + luaL_checkany(L, 1); + lua_pushboolean(L, 1); /* first result if no errors */ + lua_insert(L, 1); /* put it in place */ + status = lua_pcallk(L, lua_gettop(L) - 2, LUA_MULTRET, 0, 0, finishpcall); + return finishpcall(L, status, 0); +} + + +/* +** Do a protected call with error handling. After 'lua_rotate', the +** stack will have ; so, the function passes +** 2 to 'finishpcall' to skip the 2 first values when returning results. +*/ +static int luaB_xpcall (lua_State *L) { + int status; + int n = lua_gettop(L); + luaL_checktype(L, 2, LUA_TFUNCTION); /* check error function */ + lua_pushboolean(L, 1); /* first result */ + lua_pushvalue(L, 1); /* function */ + lua_rotate(L, 3, 2); /* move them below function's arguments */ + status = lua_pcallk(L, n - 2, LUA_MULTRET, 2, 2, finishpcall); + return finishpcall(L, status, 2); +} + + +static int luaB_tostring (lua_State *L) { + luaL_checkany(L, 1); + luaL_tolstring(L, 1, NULL); + return 1; +} + + +static const luaL_Reg base_funcs[] = { + {"assert", luaB_assert}, + {"collectgarbage", luaB_collectgarbage}, + {"dofile", luaB_dofile}, + {"error", luaB_error}, + {"getmetatable", luaB_getmetatable}, + {"ipairs", luaB_ipairs}, + {"loadfile", luaB_loadfile}, + {"load", luaB_load}, +#if defined(LUA_COMPAT_LOADSTRING) + {"loadstring", luaB_load}, +#endif + {"next", luaB_next}, + {"pairs", luaB_pairs}, + {"pcall", luaB_pcall}, + {"print", luaB_print}, + {"rawequal", luaB_rawequal}, + {"rawlen", luaB_rawlen}, + {"rawget", luaB_rawget}, + {"rawset", luaB_rawset}, + {"select", luaB_select}, + {"setmetatable", luaB_setmetatable}, + {"tonumber", luaB_tonumber}, + {"tostring", luaB_tostring}, + {"type", luaB_type}, + {"xpcall", luaB_xpcall}, + /* placeholders */ + {"_G", NULL}, + {"_VERSION", NULL}, + {NULL, NULL} +}; + + +LUAMOD_API int luaopen_base (lua_State *L) { + /* open lib into global table */ + lua_pushglobaltable(L); + luaL_setfuncs(L, base_funcs, 0); + /* set global _G */ + lua_pushvalue(L, -1); + lua_setfield(L, -2, "_G"); + /* set global _VERSION */ + lua_pushliteral(L, LUA_VERSION); + lua_setfield(L, -2, "_VERSION"); + return 1; +} + diff --git a/depends/lua/src/lbitlib.c b/depends/lua/src/lbitlib.c new file mode 100644 index 0000000000..4786c0d483 --- /dev/null +++ b/depends/lua/src/lbitlib.c @@ -0,0 +1,233 @@ +/* +** $Id: lbitlib.c,v 1.30.1.1 2017/04/19 17:20:42 roberto Exp $ +** Standard library for bitwise operations +** See Copyright Notice in lua.h +*/ + +#define lbitlib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +#if defined(LUA_COMPAT_BITLIB) /* { */ + + +#define pushunsigned(L,n) lua_pushinteger(L, (lua_Integer)(n)) +#define checkunsigned(L,i) ((lua_Unsigned)luaL_checkinteger(L,i)) + + +/* number of bits to consider in a number */ +#if !defined(LUA_NBITS) +#define LUA_NBITS 32 +#endif + + +/* +** a lua_Unsigned with its first LUA_NBITS bits equal to 1. (Shift must +** be made in two parts to avoid problems when LUA_NBITS is equal to the +** number of bits in a lua_Unsigned.) +*/ +#define ALLONES (~(((~(lua_Unsigned)0) << (LUA_NBITS - 1)) << 1)) + + +/* macro to trim extra bits */ +#define trim(x) ((x) & ALLONES) + + +/* builds a number with 'n' ones (1 <= n <= LUA_NBITS) */ +#define mask(n) (~((ALLONES << 1) << ((n) - 1))) + + + +static lua_Unsigned andaux (lua_State *L) { + int i, n = lua_gettop(L); + lua_Unsigned r = ~(lua_Unsigned)0; + for (i = 1; i <= n; i++) + r &= checkunsigned(L, i); + return trim(r); +} + + +static int b_and (lua_State *L) { + lua_Unsigned r = andaux(L); + pushunsigned(L, r); + return 1; +} + + +static int b_test (lua_State *L) { + lua_Unsigned r = andaux(L); + lua_pushboolean(L, r != 0); + return 1; +} + + +static int b_or (lua_State *L) { + int i, n = lua_gettop(L); + lua_Unsigned r = 0; + for (i = 1; i <= n; i++) + r |= checkunsigned(L, i); + pushunsigned(L, trim(r)); + return 1; +} + + +static int b_xor (lua_State *L) { + int i, n = lua_gettop(L); + lua_Unsigned r = 0; + for (i = 1; i <= n; i++) + r ^= checkunsigned(L, i); + pushunsigned(L, trim(r)); + return 1; +} + + +static int b_not (lua_State *L) { + lua_Unsigned r = ~checkunsigned(L, 1); + pushunsigned(L, trim(r)); + return 1; +} + + +static int b_shift (lua_State *L, lua_Unsigned r, lua_Integer i) { + if (i < 0) { /* shift right? */ + i = -i; + r = trim(r); + if (i >= LUA_NBITS) r = 0; + else r >>= i; + } + else { /* shift left */ + if (i >= LUA_NBITS) r = 0; + else r <<= i; + r = trim(r); + } + pushunsigned(L, r); + return 1; +} + + +static int b_lshift (lua_State *L) { + return b_shift(L, checkunsigned(L, 1), luaL_checkinteger(L, 2)); +} + + +static int b_rshift (lua_State *L) { + return b_shift(L, checkunsigned(L, 1), -luaL_checkinteger(L, 2)); +} + + +static int b_arshift (lua_State *L) { + lua_Unsigned r = checkunsigned(L, 1); + lua_Integer i = luaL_checkinteger(L, 2); + if (i < 0 || !(r & ((lua_Unsigned)1 << (LUA_NBITS - 1)))) + return b_shift(L, r, -i); + else { /* arithmetic shift for 'negative' number */ + if (i >= LUA_NBITS) r = ALLONES; + else + r = trim((r >> i) | ~(trim(~(lua_Unsigned)0) >> i)); /* add signal bit */ + pushunsigned(L, r); + return 1; + } +} + + +static int b_rot (lua_State *L, lua_Integer d) { + lua_Unsigned r = checkunsigned(L, 1); + int i = d & (LUA_NBITS - 1); /* i = d % NBITS */ + r = trim(r); + if (i != 0) /* avoid undefined shift of LUA_NBITS when i == 0 */ + r = (r << i) | (r >> (LUA_NBITS - i)); + pushunsigned(L, trim(r)); + return 1; +} + + +static int b_lrot (lua_State *L) { + return b_rot(L, luaL_checkinteger(L, 2)); +} + + +static int b_rrot (lua_State *L) { + return b_rot(L, -luaL_checkinteger(L, 2)); +} + + +/* +** get field and width arguments for field-manipulation functions, +** checking whether they are valid. +** ('luaL_error' called without 'return' to avoid later warnings about +** 'width' being used uninitialized.) +*/ +static int fieldargs (lua_State *L, int farg, int *width) { + lua_Integer f = luaL_checkinteger(L, farg); + lua_Integer w = luaL_optinteger(L, farg + 1, 1); + luaL_argcheck(L, 0 <= f, farg, "field cannot be negative"); + luaL_argcheck(L, 0 < w, farg + 1, "width must be positive"); + if (f + w > LUA_NBITS) + luaL_error(L, "trying to access non-existent bits"); + *width = (int)w; + return (int)f; +} + + +static int b_extract (lua_State *L) { + int w; + lua_Unsigned r = trim(checkunsigned(L, 1)); + int f = fieldargs(L, 2, &w); + r = (r >> f) & mask(w); + pushunsigned(L, r); + return 1; +} + + +static int b_replace (lua_State *L) { + int w; + lua_Unsigned r = trim(checkunsigned(L, 1)); + lua_Unsigned v = trim(checkunsigned(L, 2)); + int f = fieldargs(L, 3, &w); + lua_Unsigned m = mask(w); + r = (r & ~(m << f)) | ((v & m) << f); + pushunsigned(L, r); + return 1; +} + + +static const luaL_Reg bitlib[] = { + {"arshift", b_arshift}, + {"band", b_and}, + {"bnot", b_not}, + {"bor", b_or}, + {"bxor", b_xor}, + {"btest", b_test}, + {"extract", b_extract}, + {"lrotate", b_lrot}, + {"lshift", b_lshift}, + {"replace", b_replace}, + {"rrotate", b_rrot}, + {"rshift", b_rshift}, + {NULL, NULL} +}; + + + +LUAMOD_API int luaopen_bit32 (lua_State *L) { + luaL_newlib(L, bitlib); + return 1; +} + + +#else /* }{ */ + + +LUAMOD_API int luaopen_bit32 (lua_State *L) { + return luaL_error(L, "library 'bit32' has been deprecated"); +} + +#endif /* } */ diff --git a/depends/lua/src/lcode.c b/depends/lua/src/lcode.c new file mode 100644 index 0000000000..dc7271d614 --- /dev/null +++ b/depends/lua/src/lcode.c @@ -0,0 +1,1203 @@ +/* +** $Id: lcode.c,v 2.112.1.1 2017/04/19 17:20:42 roberto Exp $ +** Code generator for Lua +** See Copyright Notice in lua.h +*/ + +#define lcode_c +#define LUA_CORE + +#include "lprefix.h" + + +#include +#include + +#include "lua.h" + +#include "lcode.h" +#include "ldebug.h" +#include "ldo.h" +#include "lgc.h" +#include "llex.h" +#include "lmem.h" +#include "lobject.h" +#include "lopcodes.h" +#include "lparser.h" +#include "lstring.h" +#include "ltable.h" +#include "lvm.h" + + +/* Maximum number of registers in a Lua function (must fit in 8 bits) */ +#define MAXREGS 255 + + +#define hasjumps(e) ((e)->t != (e)->f) + + +/* +** If expression is a numeric constant, fills 'v' with its value +** and returns 1. Otherwise, returns 0. +*/ +static int tonumeral(const expdesc *e, TValue *v) { + if (hasjumps(e)) + return 0; /* not a numeral */ + switch (e->k) { + case VKINT: + if (v) setivalue(v, e->u.ival); + return 1; + case VKFLT: + if (v) setfltvalue(v, e->u.nval); + return 1; + default: return 0; + } +} + + +/* +** Create a OP_LOADNIL instruction, but try to optimize: if the previous +** instruction is also OP_LOADNIL and ranges are compatible, adjust +** range of previous instruction instead of emitting a new one. (For +** instance, 'local a; local b' will generate a single opcode.) +*/ +void luaK_nil (FuncState *fs, int from, int n) { + Instruction *previous; + int l = from + n - 1; /* last register to set nil */ + if (fs->pc > fs->lasttarget) { /* no jumps to current position? */ + previous = &fs->f->code[fs->pc-1]; + if (GET_OPCODE(*previous) == OP_LOADNIL) { /* previous is LOADNIL? */ + int pfrom = GETARG_A(*previous); /* get previous range */ + int pl = pfrom + GETARG_B(*previous); + if ((pfrom <= from && from <= pl + 1) || + (from <= pfrom && pfrom <= l + 1)) { /* can connect both? */ + if (pfrom < from) from = pfrom; /* from = min(from, pfrom) */ + if (pl > l) l = pl; /* l = max(l, pl) */ + SETARG_A(*previous, from); + SETARG_B(*previous, l - from); + return; + } + } /* else go through */ + } + luaK_codeABC(fs, OP_LOADNIL, from, n - 1, 0); /* else no optimization */ +} + + +/* +** Gets the destination address of a jump instruction. Used to traverse +** a list of jumps. +*/ +static int getjump (FuncState *fs, int pc) { + int offset = GETARG_sBx(fs->f->code[pc]); + if (offset == NO_JUMP) /* point to itself represents end of list */ + return NO_JUMP; /* end of list */ + else + return (pc+1)+offset; /* turn offset into absolute position */ +} + + +/* +** Fix jump instruction at position 'pc' to jump to 'dest'. +** (Jump addresses are relative in Lua) +*/ +static void fixjump (FuncState *fs, int pc, int dest) { + Instruction *jmp = &fs->f->code[pc]; + int offset = dest - (pc + 1); + lua_assert(dest != NO_JUMP); + if (abs(offset) > MAXARG_sBx) + luaX_syntaxerror(fs->ls, "control structure too long"); + SETARG_sBx(*jmp, offset); +} + + +/* +** Concatenate jump-list 'l2' into jump-list 'l1' +*/ +void luaK_concat (FuncState *fs, int *l1, int l2) { + if (l2 == NO_JUMP) return; /* nothing to concatenate? */ + else if (*l1 == NO_JUMP) /* no original list? */ + *l1 = l2; /* 'l1' points to 'l2' */ + else { + int list = *l1; + int next; + while ((next = getjump(fs, list)) != NO_JUMP) /* find last element */ + list = next; + fixjump(fs, list, l2); /* last element links to 'l2' */ + } +} + + +/* +** Create a jump instruction and return its position, so its destination +** can be fixed later (with 'fixjump'). If there are jumps to +** this position (kept in 'jpc'), link them all together so that +** 'patchlistaux' will fix all them directly to the final destination. +*/ +int luaK_jump (FuncState *fs) { + int jpc = fs->jpc; /* save list of jumps to here */ + int j; + fs->jpc = NO_JUMP; /* no more jumps to here */ + j = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP); + luaK_concat(fs, &j, jpc); /* keep them on hold */ + return j; +} + + +/* +** Code a 'return' instruction +*/ +void luaK_ret (FuncState *fs, int first, int nret) { + luaK_codeABC(fs, OP_RETURN, first, nret+1, 0); +} + + +/* +** Code a "conditional jump", that is, a test or comparison opcode +** followed by a jump. Return jump position. +*/ +static int condjump (FuncState *fs, OpCode op, int A, int B, int C) { + luaK_codeABC(fs, op, A, B, C); + return luaK_jump(fs); +} + + +/* +** returns current 'pc' and marks it as a jump target (to avoid wrong +** optimizations with consecutive instructions not in the same basic block). +*/ +int luaK_getlabel (FuncState *fs) { + fs->lasttarget = fs->pc; + return fs->pc; +} + + +/* +** Returns the position of the instruction "controlling" a given +** jump (that is, its condition), or the jump itself if it is +** unconditional. +*/ +static Instruction *getjumpcontrol (FuncState *fs, int pc) { + Instruction *pi = &fs->f->code[pc]; + if (pc >= 1 && testTMode(GET_OPCODE(*(pi-1)))) + return pi-1; + else + return pi; +} + + +/* +** Patch destination register for a TESTSET instruction. +** If instruction in position 'node' is not a TESTSET, return 0 ("fails"). +** Otherwise, if 'reg' is not 'NO_REG', set it as the destination +** register. Otherwise, change instruction to a simple 'TEST' (produces +** no register value) +*/ +static int patchtestreg (FuncState *fs, int node, int reg) { + Instruction *i = getjumpcontrol(fs, node); + if (GET_OPCODE(*i) != OP_TESTSET) + return 0; /* cannot patch other instructions */ + if (reg != NO_REG && reg != GETARG_B(*i)) + SETARG_A(*i, reg); + else { + /* no register to put value or register already has the value; + change instruction to simple test */ + *i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i)); + } + return 1; +} + + +/* +** Traverse a list of tests ensuring no one produces a value +*/ +static void removevalues (FuncState *fs, int list) { + for (; list != NO_JUMP; list = getjump(fs, list)) + patchtestreg(fs, list, NO_REG); +} + + +/* +** Traverse a list of tests, patching their destination address and +** registers: tests producing values jump to 'vtarget' (and put their +** values in 'reg'), other tests jump to 'dtarget'. +*/ +static void patchlistaux (FuncState *fs, int list, int vtarget, int reg, + int dtarget) { + while (list != NO_JUMP) { + int next = getjump(fs, list); + if (patchtestreg(fs, list, reg)) + fixjump(fs, list, vtarget); + else + fixjump(fs, list, dtarget); /* jump to default target */ + list = next; + } +} + + +/* +** Ensure all pending jumps to current position are fixed (jumping +** to current position with no values) and reset list of pending +** jumps +*/ +static void dischargejpc (FuncState *fs) { + patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc); + fs->jpc = NO_JUMP; +} + + +/* +** Add elements in 'list' to list of pending jumps to "here" +** (current position) +*/ +void luaK_patchtohere (FuncState *fs, int list) { + luaK_getlabel(fs); /* mark "here" as a jump target */ + luaK_concat(fs, &fs->jpc, list); +} + + +/* +** Path all jumps in 'list' to jump to 'target'. +** (The assert means that we cannot fix a jump to a forward address +** because we only know addresses once code is generated.) +*/ +void luaK_patchlist (FuncState *fs, int list, int target) { + if (target == fs->pc) /* 'target' is current position? */ + luaK_patchtohere(fs, list); /* add list to pending jumps */ + else { + lua_assert(target < fs->pc); + patchlistaux(fs, list, target, NO_REG, target); + } +} + + +/* +** Path all jumps in 'list' to close upvalues up to given 'level' +** (The assertion checks that jumps either were closing nothing +** or were closing higher levels, from inner blocks.) +*/ +void luaK_patchclose (FuncState *fs, int list, int level) { + level++; /* argument is +1 to reserve 0 as non-op */ + for (; list != NO_JUMP; list = getjump(fs, list)) { + lua_assert(GET_OPCODE(fs->f->code[list]) == OP_JMP && + (GETARG_A(fs->f->code[list]) == 0 || + GETARG_A(fs->f->code[list]) >= level)); + SETARG_A(fs->f->code[list], level); + } +} + + +/* +** Emit instruction 'i', checking for array sizes and saving also its +** line information. Return 'i' position. +*/ +static int luaK_code (FuncState *fs, Instruction i) { + Proto *f = fs->f; + dischargejpc(fs); /* 'pc' will change */ + /* put new instruction in code array */ + luaM_growvector(fs->ls->L, f->code, fs->pc, f->sizecode, Instruction, + MAX_INT, "opcodes"); + f->code[fs->pc] = i; + /* save corresponding line information */ + luaM_growvector(fs->ls->L, f->lineinfo, fs->pc, f->sizelineinfo, int, + MAX_INT, "opcodes"); + f->lineinfo[fs->pc] = fs->ls->lastline; + return fs->pc++; +} + + +/* +** Format and emit an 'iABC' instruction. (Assertions check consistency +** of parameters versus opcode.) +*/ +int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) { + lua_assert(getOpMode(o) == iABC); + lua_assert(getBMode(o) != OpArgN || b == 0); + lua_assert(getCMode(o) != OpArgN || c == 0); + lua_assert(a <= MAXARG_A && b <= MAXARG_B && c <= MAXARG_C); + return luaK_code(fs, CREATE_ABC(o, a, b, c)); +} + + +/* +** Format and emit an 'iABx' instruction. +*/ +int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) { + lua_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx); + lua_assert(getCMode(o) == OpArgN); + lua_assert(a <= MAXARG_A && bc <= MAXARG_Bx); + return luaK_code(fs, CREATE_ABx(o, a, bc)); +} + + +/* +** Emit an "extra argument" instruction (format 'iAx') +*/ +static int codeextraarg (FuncState *fs, int a) { + lua_assert(a <= MAXARG_Ax); + return luaK_code(fs, CREATE_Ax(OP_EXTRAARG, a)); +} + + +/* +** Emit a "load constant" instruction, using either 'OP_LOADK' +** (if constant index 'k' fits in 18 bits) or an 'OP_LOADKX' +** instruction with "extra argument". +*/ +int luaK_codek (FuncState *fs, int reg, int k) { + if (k <= MAXARG_Bx) + return luaK_codeABx(fs, OP_LOADK, reg, k); + else { + int p = luaK_codeABx(fs, OP_LOADKX, reg, 0); + codeextraarg(fs, k); + return p; + } +} + + +/* +** Check register-stack level, keeping track of its maximum size +** in field 'maxstacksize' +*/ +void luaK_checkstack (FuncState *fs, int n) { + int newstack = fs->freereg + n; + if (newstack > fs->f->maxstacksize) { + if (newstack >= MAXREGS) + luaX_syntaxerror(fs->ls, + "function or expression needs too many registers"); + fs->f->maxstacksize = cast_byte(newstack); + } +} + + +/* +** Reserve 'n' registers in register stack +*/ +void luaK_reserveregs (FuncState *fs, int n) { + luaK_checkstack(fs, n); + fs->freereg += n; +} + + +/* +** Free register 'reg', if it is neither a constant index nor +** a local variable. +) +*/ +static void freereg (FuncState *fs, int reg) { + if (!ISK(reg) && reg >= fs->nactvar) { + fs->freereg--; + lua_assert(reg == fs->freereg); + } +} + + +/* +** Free register used by expression 'e' (if any) +*/ +static void freeexp (FuncState *fs, expdesc *e) { + if (e->k == VNONRELOC) + freereg(fs, e->u.info); +} + + +/* +** Free registers used by expressions 'e1' and 'e2' (if any) in proper +** order. +*/ +static void freeexps (FuncState *fs, expdesc *e1, expdesc *e2) { + int r1 = (e1->k == VNONRELOC) ? e1->u.info : -1; + int r2 = (e2->k == VNONRELOC) ? e2->u.info : -1; + if (r1 > r2) { + freereg(fs, r1); + freereg(fs, r2); + } + else { + freereg(fs, r2); + freereg(fs, r1); + } +} + + +/* +** Add constant 'v' to prototype's list of constants (field 'k'). +** Use scanner's table to cache position of constants in constant list +** and try to reuse constants. Because some values should not be used +** as keys (nil cannot be a key, integer keys can collapse with float +** keys), the caller must provide a useful 'key' for indexing the cache. +*/ +static int addk (FuncState *fs, TValue *key, TValue *v) { + lua_State *L = fs->ls->L; + Proto *f = fs->f; + TValue *idx = luaH_set(L, fs->ls->h, key); /* index scanner table */ + int k, oldsize; + if (ttisinteger(idx)) { /* is there an index there? */ + k = cast_int(ivalue(idx)); + /* correct value? (warning: must distinguish floats from integers!) */ + if (k < fs->nk && ttype(&f->k[k]) == ttype(v) && + luaV_rawequalobj(&f->k[k], v)) + return k; /* reuse index */ + } + /* constant not found; create a new entry */ + oldsize = f->sizek; + k = fs->nk; + /* numerical value does not need GC barrier; + table has no metatable, so it does not need to invalidate cache */ + setivalue(idx, k); + luaM_growvector(L, f->k, k, f->sizek, TValue, MAXARG_Ax, "constants"); + while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]); + setobj(L, &f->k[k], v); + fs->nk++; + luaC_barrier(L, f, v); + return k; +} + + +/* +** Add a string to list of constants and return its index. +*/ +int luaK_stringK (FuncState *fs, TString *s) { + TValue o; + setsvalue(fs->ls->L, &o, s); + return addk(fs, &o, &o); /* use string itself as key */ +} + + +/* +** Add an integer to list of constants and return its index. +** Integers use userdata as keys to avoid collision with floats with +** same value; conversion to 'void*' is used only for hashing, so there +** are no "precision" problems. +*/ +int luaK_intK (FuncState *fs, lua_Integer n) { + TValue k, o; + setpvalue(&k, cast(void*, cast(size_t, n))); + setivalue(&o, n); + return addk(fs, &k, &o); +} + +/* +** Add a float to list of constants and return its index. +*/ +static int luaK_numberK (FuncState *fs, lua_Number r) { + TValue o; + setfltvalue(&o, r); + return addk(fs, &o, &o); /* use number itself as key */ +} + + +/* +** Add a boolean to list of constants and return its index. +*/ +static int boolK (FuncState *fs, int b) { + TValue o; + setbvalue(&o, b); + return addk(fs, &o, &o); /* use boolean itself as key */ +} + + +/* +** Add nil to list of constants and return its index. +*/ +static int nilK (FuncState *fs) { + TValue k, v; + setnilvalue(&v); + /* cannot use nil as key; instead use table itself to represent nil */ + sethvalue(fs->ls->L, &k, fs->ls->h); + return addk(fs, &k, &v); +} + + +/* +** Fix an expression to return the number of results 'nresults'. +** Either 'e' is a multi-ret expression (function call or vararg) +** or 'nresults' is LUA_MULTRET (as any expression can satisfy that). +*/ +void luaK_setreturns (FuncState *fs, expdesc *e, int nresults) { + if (e->k == VCALL) { /* expression is an open function call? */ + SETARG_C(getinstruction(fs, e), nresults + 1); + } + else if (e->k == VVARARG) { + Instruction *pc = &getinstruction(fs, e); + SETARG_B(*pc, nresults + 1); + SETARG_A(*pc, fs->freereg); + luaK_reserveregs(fs, 1); + } + else lua_assert(nresults == LUA_MULTRET); +} + + +/* +** Fix an expression to return one result. +** If expression is not a multi-ret expression (function call or +** vararg), it already returns one result, so nothing needs to be done. +** Function calls become VNONRELOC expressions (as its result comes +** fixed in the base register of the call), while vararg expressions +** become VRELOCABLE (as OP_VARARG puts its results where it wants). +** (Calls are created returning one result, so that does not need +** to be fixed.) +*/ +void luaK_setoneret (FuncState *fs, expdesc *e) { + if (e->k == VCALL) { /* expression is an open function call? */ + /* already returns 1 value */ + lua_assert(GETARG_C(getinstruction(fs, e)) == 2); + e->k = VNONRELOC; /* result has fixed position */ + e->u.info = GETARG_A(getinstruction(fs, e)); + } + else if (e->k == VVARARG) { + SETARG_B(getinstruction(fs, e), 2); + e->k = VRELOCABLE; /* can relocate its simple result */ + } +} + + +/* +** Ensure that expression 'e' is not a variable. +*/ +void luaK_dischargevars (FuncState *fs, expdesc *e) { + switch (e->k) { + case VLOCAL: { /* already in a register */ + e->k = VNONRELOC; /* becomes a non-relocatable value */ + break; + } + case VUPVAL: { /* move value to some (pending) register */ + e->u.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.info, 0); + e->k = VRELOCABLE; + break; + } + case VINDEXED: { + OpCode op; + freereg(fs, e->u.ind.idx); + if (e->u.ind.vt == VLOCAL) { /* is 't' in a register? */ + freereg(fs, e->u.ind.t); + op = OP_GETTABLE; + } + else { + lua_assert(e->u.ind.vt == VUPVAL); + op = OP_GETTABUP; /* 't' is in an upvalue */ + } + e->u.info = luaK_codeABC(fs, op, 0, e->u.ind.t, e->u.ind.idx); + e->k = VRELOCABLE; + break; + } + case VVARARG: case VCALL: { + luaK_setoneret(fs, e); + break; + } + default: break; /* there is one value available (somewhere) */ + } +} + + +/* +** Ensures expression value is in register 'reg' (and therefore +** 'e' will become a non-relocatable expression). +*/ +static void discharge2reg (FuncState *fs, expdesc *e, int reg) { + luaK_dischargevars(fs, e); + switch (e->k) { + case VNIL: { + luaK_nil(fs, reg, 1); + break; + } + case VFALSE: case VTRUE: { + luaK_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0); + break; + } + case VK: { + luaK_codek(fs, reg, e->u.info); + break; + } + case VKFLT: { + luaK_codek(fs, reg, luaK_numberK(fs, e->u.nval)); + break; + } + case VKINT: { + luaK_codek(fs, reg, luaK_intK(fs, e->u.ival)); + break; + } + case VRELOCABLE: { + Instruction *pc = &getinstruction(fs, e); + SETARG_A(*pc, reg); /* instruction will put result in 'reg' */ + break; + } + case VNONRELOC: { + if (reg != e->u.info) + luaK_codeABC(fs, OP_MOVE, reg, e->u.info, 0); + break; + } + default: { + lua_assert(e->k == VJMP); + return; /* nothing to do... */ + } + } + e->u.info = reg; + e->k = VNONRELOC; +} + + +/* +** Ensures expression value is in any register. +*/ +static void discharge2anyreg (FuncState *fs, expdesc *e) { + if (e->k != VNONRELOC) { /* no fixed register yet? */ + luaK_reserveregs(fs, 1); /* get a register */ + discharge2reg(fs, e, fs->freereg-1); /* put value there */ + } +} + + +static int code_loadbool (FuncState *fs, int A, int b, int jump) { + luaK_getlabel(fs); /* those instructions may be jump targets */ + return luaK_codeABC(fs, OP_LOADBOOL, A, b, jump); +} + + +/* +** check whether list has any jump that do not produce a value +** or produce an inverted value +*/ +static int need_value (FuncState *fs, int list) { + for (; list != NO_JUMP; list = getjump(fs, list)) { + Instruction i = *getjumpcontrol(fs, list); + if (GET_OPCODE(i) != OP_TESTSET) return 1; + } + return 0; /* not found */ +} + + +/* +** Ensures final expression result (including results from its jump +** lists) is in register 'reg'. +** If expression has jumps, need to patch these jumps either to +** its final position or to "load" instructions (for those tests +** that do not produce values). +*/ +static void exp2reg (FuncState *fs, expdesc *e, int reg) { + discharge2reg(fs, e, reg); + if (e->k == VJMP) /* expression itself is a test? */ + luaK_concat(fs, &e->t, e->u.info); /* put this jump in 't' list */ + if (hasjumps(e)) { + int final; /* position after whole expression */ + int p_f = NO_JUMP; /* position of an eventual LOAD false */ + int p_t = NO_JUMP; /* position of an eventual LOAD true */ + if (need_value(fs, e->t) || need_value(fs, e->f)) { + int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs); + p_f = code_loadbool(fs, reg, 0, 1); + p_t = code_loadbool(fs, reg, 1, 0); + luaK_patchtohere(fs, fj); + } + final = luaK_getlabel(fs); + patchlistaux(fs, e->f, final, reg, p_f); + patchlistaux(fs, e->t, final, reg, p_t); + } + e->f = e->t = NO_JUMP; + e->u.info = reg; + e->k = VNONRELOC; +} + + +/* +** Ensures final expression result (including results from its jump +** lists) is in next available register. +*/ +void luaK_exp2nextreg (FuncState *fs, expdesc *e) { + luaK_dischargevars(fs, e); + freeexp(fs, e); + luaK_reserveregs(fs, 1); + exp2reg(fs, e, fs->freereg - 1); +} + + +/* +** Ensures final expression result (including results from its jump +** lists) is in some (any) register and return that register. +*/ +int luaK_exp2anyreg (FuncState *fs, expdesc *e) { + luaK_dischargevars(fs, e); + if (e->k == VNONRELOC) { /* expression already has a register? */ + if (!hasjumps(e)) /* no jumps? */ + return e->u.info; /* result is already in a register */ + if (e->u.info >= fs->nactvar) { /* reg. is not a local? */ + exp2reg(fs, e, e->u.info); /* put final result in it */ + return e->u.info; + } + } + luaK_exp2nextreg(fs, e); /* otherwise, use next available register */ + return e->u.info; +} + + +/* +** Ensures final expression result is either in a register or in an +** upvalue. +*/ +void luaK_exp2anyregup (FuncState *fs, expdesc *e) { + if (e->k != VUPVAL || hasjumps(e)) + luaK_exp2anyreg(fs, e); +} + + +/* +** Ensures final expression result is either in a register or it is +** a constant. +*/ +void luaK_exp2val (FuncState *fs, expdesc *e) { + if (hasjumps(e)) + luaK_exp2anyreg(fs, e); + else + luaK_dischargevars(fs, e); +} + + +/* +** Ensures final expression result is in a valid R/K index +** (that is, it is either in a register or in 'k' with an index +** in the range of R/K indices). +** Returns R/K index. +*/ +int luaK_exp2RK (FuncState *fs, expdesc *e) { + luaK_exp2val(fs, e); + switch (e->k) { /* move constants to 'k' */ + case VTRUE: e->u.info = boolK(fs, 1); goto vk; + case VFALSE: e->u.info = boolK(fs, 0); goto vk; + case VNIL: e->u.info = nilK(fs); goto vk; + case VKINT: e->u.info = luaK_intK(fs, e->u.ival); goto vk; + case VKFLT: e->u.info = luaK_numberK(fs, e->u.nval); goto vk; + case VK: + vk: + e->k = VK; + if (e->u.info <= MAXINDEXRK) /* constant fits in 'argC'? */ + return RKASK(e->u.info); + else break; + default: break; + } + /* not a constant in the right range: put it in a register */ + return luaK_exp2anyreg(fs, e); +} + + +/* +** Generate code to store result of expression 'ex' into variable 'var'. +*/ +void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) { + switch (var->k) { + case VLOCAL: { + freeexp(fs, ex); + exp2reg(fs, ex, var->u.info); /* compute 'ex' into proper place */ + return; + } + case VUPVAL: { + int e = luaK_exp2anyreg(fs, ex); + luaK_codeABC(fs, OP_SETUPVAL, e, var->u.info, 0); + break; + } + case VINDEXED: { + OpCode op = (var->u.ind.vt == VLOCAL) ? OP_SETTABLE : OP_SETTABUP; + int e = luaK_exp2RK(fs, ex); + luaK_codeABC(fs, op, var->u.ind.t, var->u.ind.idx, e); + break; + } + default: lua_assert(0); /* invalid var kind to store */ + } + freeexp(fs, ex); +} + + +/* +** Emit SELF instruction (convert expression 'e' into 'e:key(e,'). +*/ +void luaK_self (FuncState *fs, expdesc *e, expdesc *key) { + int ereg; + luaK_exp2anyreg(fs, e); + ereg = e->u.info; /* register where 'e' was placed */ + freeexp(fs, e); + e->u.info = fs->freereg; /* base register for op_self */ + e->k = VNONRELOC; /* self expression has a fixed register */ + luaK_reserveregs(fs, 2); /* function and 'self' produced by op_self */ + luaK_codeABC(fs, OP_SELF, e->u.info, ereg, luaK_exp2RK(fs, key)); + freeexp(fs, key); +} + + +/* +** Negate condition 'e' (where 'e' is a comparison). +*/ +static void negatecondition (FuncState *fs, expdesc *e) { + Instruction *pc = getjumpcontrol(fs, e->u.info); + lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET && + GET_OPCODE(*pc) != OP_TEST); + SETARG_A(*pc, !(GETARG_A(*pc))); +} + + +/* +** Emit instruction to jump if 'e' is 'cond' (that is, if 'cond' +** is true, code will jump if 'e' is true.) Return jump position. +** Optimize when 'e' is 'not' something, inverting the condition +** and removing the 'not'. +*/ +static int jumponcond (FuncState *fs, expdesc *e, int cond) { + if (e->k == VRELOCABLE) { + Instruction ie = getinstruction(fs, e); + if (GET_OPCODE(ie) == OP_NOT) { + fs->pc--; /* remove previous OP_NOT */ + return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond); + } + /* else go through */ + } + discharge2anyreg(fs, e); + freeexp(fs, e); + return condjump(fs, OP_TESTSET, NO_REG, e->u.info, cond); +} + + +/* +** Emit code to go through if 'e' is true, jump otherwise. +*/ +void luaK_goiftrue (FuncState *fs, expdesc *e) { + int pc; /* pc of new jump */ + luaK_dischargevars(fs, e); + switch (e->k) { + case VJMP: { /* condition? */ + negatecondition(fs, e); /* jump when it is false */ + pc = e->u.info; /* save jump position */ + break; + } + case VK: case VKFLT: case VKINT: case VTRUE: { + pc = NO_JUMP; /* always true; do nothing */ + break; + } + default: { + pc = jumponcond(fs, e, 0); /* jump when false */ + break; + } + } + luaK_concat(fs, &e->f, pc); /* insert new jump in false list */ + luaK_patchtohere(fs, e->t); /* true list jumps to here (to go through) */ + e->t = NO_JUMP; +} + + +/* +** Emit code to go through if 'e' is false, jump otherwise. +*/ +void luaK_goiffalse (FuncState *fs, expdesc *e) { + int pc; /* pc of new jump */ + luaK_dischargevars(fs, e); + switch (e->k) { + case VJMP: { + pc = e->u.info; /* already jump if true */ + break; + } + case VNIL: case VFALSE: { + pc = NO_JUMP; /* always false; do nothing */ + break; + } + default: { + pc = jumponcond(fs, e, 1); /* jump if true */ + break; + } + } + luaK_concat(fs, &e->t, pc); /* insert new jump in 't' list */ + luaK_patchtohere(fs, e->f); /* false list jumps to here (to go through) */ + e->f = NO_JUMP; +} + + +/* +** Code 'not e', doing constant folding. +*/ +static void codenot (FuncState *fs, expdesc *e) { + luaK_dischargevars(fs, e); + switch (e->k) { + case VNIL: case VFALSE: { + e->k = VTRUE; /* true == not nil == not false */ + break; + } + case VK: case VKFLT: case VKINT: case VTRUE: { + e->k = VFALSE; /* false == not "x" == not 0.5 == not 1 == not true */ + break; + } + case VJMP: { + negatecondition(fs, e); + break; + } + case VRELOCABLE: + case VNONRELOC: { + discharge2anyreg(fs, e); + freeexp(fs, e); + e->u.info = luaK_codeABC(fs, OP_NOT, 0, e->u.info, 0); + e->k = VRELOCABLE; + break; + } + default: lua_assert(0); /* cannot happen */ + } + /* interchange true and false lists */ + { int temp = e->f; e->f = e->t; e->t = temp; } + removevalues(fs, e->f); /* values are useless when negated */ + removevalues(fs, e->t); +} + + +/* +** Create expression 't[k]'. 't' must have its final result already in a +** register or upvalue. +*/ +void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) { + lua_assert(!hasjumps(t) && (vkisinreg(t->k) || t->k == VUPVAL)); + t->u.ind.t = t->u.info; /* register or upvalue index */ + t->u.ind.idx = luaK_exp2RK(fs, k); /* R/K index for key */ + t->u.ind.vt = (t->k == VUPVAL) ? VUPVAL : VLOCAL; + t->k = VINDEXED; +} + + +/* +** Return false if folding can raise an error. +** Bitwise operations need operands convertible to integers; division +** operations cannot have 0 as divisor. +*/ +static int validop (int op, TValue *v1, TValue *v2) { + switch (op) { + case LUA_OPBAND: case LUA_OPBOR: case LUA_OPBXOR: + case LUA_OPSHL: case LUA_OPSHR: case LUA_OPBNOT: { /* conversion errors */ + lua_Integer i; + return (tointeger(v1, &i) && tointeger(v2, &i)); + } + case LUA_OPDIV: case LUA_OPIDIV: case LUA_OPMOD: /* division by 0 */ + return (nvalue(v2) != 0); + default: return 1; /* everything else is valid */ + } +} + + +/* +** Try to "constant-fold" an operation; return 1 iff successful. +** (In this case, 'e1' has the final result.) +*/ +static int constfolding (FuncState *fs, int op, expdesc *e1, + const expdesc *e2) { + TValue v1, v2, res; + if (!tonumeral(e1, &v1) || !tonumeral(e2, &v2) || !validop(op, &v1, &v2)) + return 0; /* non-numeric operands or not safe to fold */ + luaO_arith(fs->ls->L, op, &v1, &v2, &res); /* does operation */ + if (ttisinteger(&res)) { + e1->k = VKINT; + e1->u.ival = ivalue(&res); + } + else { /* folds neither NaN nor 0.0 (to avoid problems with -0.0) */ + lua_Number n = fltvalue(&res); + if (luai_numisnan(n) || n == 0) + return 0; + e1->k = VKFLT; + e1->u.nval = n; + } + return 1; +} + + +/* +** Emit code for unary expressions that "produce values" +** (everything but 'not'). +** Expression to produce final result will be encoded in 'e'. +*/ +static void codeunexpval (FuncState *fs, OpCode op, expdesc *e, int line) { + int r = luaK_exp2anyreg(fs, e); /* opcodes operate only on registers */ + freeexp(fs, e); + e->u.info = luaK_codeABC(fs, op, 0, r, 0); /* generate opcode */ + e->k = VRELOCABLE; /* all those operations are relocatable */ + luaK_fixline(fs, line); +} + + +/* +** Emit code for binary expressions that "produce values" +** (everything but logical operators 'and'/'or' and comparison +** operators). +** Expression to produce final result will be encoded in 'e1'. +** Because 'luaK_exp2RK' can free registers, its calls must be +** in "stack order" (that is, first on 'e2', which may have more +** recent registers to be released). +*/ +static void codebinexpval (FuncState *fs, OpCode op, + expdesc *e1, expdesc *e2, int line) { + int rk2 = luaK_exp2RK(fs, e2); /* both operands are "RK" */ + int rk1 = luaK_exp2RK(fs, e1); + freeexps(fs, e1, e2); + e1->u.info = luaK_codeABC(fs, op, 0, rk1, rk2); /* generate opcode */ + e1->k = VRELOCABLE; /* all those operations are relocatable */ + luaK_fixline(fs, line); +} + + +/* +** Emit code for comparisons. +** 'e1' was already put in R/K form by 'luaK_infix'. +*/ +static void codecomp (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) { + int rk1 = (e1->k == VK) ? RKASK(e1->u.info) + : check_exp(e1->k == VNONRELOC, e1->u.info); + int rk2 = luaK_exp2RK(fs, e2); + freeexps(fs, e1, e2); + switch (opr) { + case OPR_NE: { /* '(a ~= b)' ==> 'not (a == b)' */ + e1->u.info = condjump(fs, OP_EQ, 0, rk1, rk2); + break; + } + case OPR_GT: case OPR_GE: { + /* '(a > b)' ==> '(b < a)'; '(a >= b)' ==> '(b <= a)' */ + OpCode op = cast(OpCode, (opr - OPR_NE) + OP_EQ); + e1->u.info = condjump(fs, op, 1, rk2, rk1); /* invert operands */ + break; + } + default: { /* '==', '<', '<=' use their own opcodes */ + OpCode op = cast(OpCode, (opr - OPR_EQ) + OP_EQ); + e1->u.info = condjump(fs, op, 1, rk1, rk2); + break; + } + } + e1->k = VJMP; +} + + +/* +** Apply prefix operation 'op' to expression 'e'. +*/ +void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) { + static const expdesc ef = {VKINT, {0}, NO_JUMP, NO_JUMP}; + switch (op) { + case OPR_MINUS: case OPR_BNOT: /* use 'ef' as fake 2nd operand */ + if (constfolding(fs, op + LUA_OPUNM, e, &ef)) + break; + /* FALLTHROUGH */ + case OPR_LEN: + codeunexpval(fs, cast(OpCode, op + OP_UNM), e, line); + break; + case OPR_NOT: codenot(fs, e); break; + default: lua_assert(0); + } +} + + +/* +** Process 1st operand 'v' of binary operation 'op' before reading +** 2nd operand. +*/ +void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) { + switch (op) { + case OPR_AND: { + luaK_goiftrue(fs, v); /* go ahead only if 'v' is true */ + break; + } + case OPR_OR: { + luaK_goiffalse(fs, v); /* go ahead only if 'v' is false */ + break; + } + case OPR_CONCAT: { + luaK_exp2nextreg(fs, v); /* operand must be on the 'stack' */ + break; + } + case OPR_ADD: case OPR_SUB: + case OPR_MUL: case OPR_DIV: case OPR_IDIV: + case OPR_MOD: case OPR_POW: + case OPR_BAND: case OPR_BOR: case OPR_BXOR: + case OPR_SHL: case OPR_SHR: { + if (!tonumeral(v, NULL)) + luaK_exp2RK(fs, v); + /* else keep numeral, which may be folded with 2nd operand */ + break; + } + default: { + luaK_exp2RK(fs, v); + break; + } + } +} + + +/* +** Finalize code for binary operation, after reading 2nd operand. +** For '(a .. b .. c)' (which is '(a .. (b .. c))', because +** concatenation is right associative), merge second CONCAT into first +** one. +*/ +void luaK_posfix (FuncState *fs, BinOpr op, + expdesc *e1, expdesc *e2, int line) { + switch (op) { + case OPR_AND: { + lua_assert(e1->t == NO_JUMP); /* list closed by 'luK_infix' */ + luaK_dischargevars(fs, e2); + luaK_concat(fs, &e2->f, e1->f); + *e1 = *e2; + break; + } + case OPR_OR: { + lua_assert(e1->f == NO_JUMP); /* list closed by 'luK_infix' */ + luaK_dischargevars(fs, e2); + luaK_concat(fs, &e2->t, e1->t); + *e1 = *e2; + break; + } + case OPR_CONCAT: { + luaK_exp2val(fs, e2); + if (e2->k == VRELOCABLE && + GET_OPCODE(getinstruction(fs, e2)) == OP_CONCAT) { + lua_assert(e1->u.info == GETARG_B(getinstruction(fs, e2))-1); + freeexp(fs, e1); + SETARG_B(getinstruction(fs, e2), e1->u.info); + e1->k = VRELOCABLE; e1->u.info = e2->u.info; + } + else { + luaK_exp2nextreg(fs, e2); /* operand must be on the 'stack' */ + codebinexpval(fs, OP_CONCAT, e1, e2, line); + } + break; + } + case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV: + case OPR_IDIV: case OPR_MOD: case OPR_POW: + case OPR_BAND: case OPR_BOR: case OPR_BXOR: + case OPR_SHL: case OPR_SHR: { + if (!constfolding(fs, op + LUA_OPADD, e1, e2)) + codebinexpval(fs, cast(OpCode, op + OP_ADD), e1, e2, line); + break; + } + case OPR_EQ: case OPR_LT: case OPR_LE: + case OPR_NE: case OPR_GT: case OPR_GE: { + codecomp(fs, op, e1, e2); + break; + } + default: lua_assert(0); + } +} + + +/* +** Change line information associated with current position. +*/ +void luaK_fixline (FuncState *fs, int line) { + fs->f->lineinfo[fs->pc - 1] = line; +} + + +/* +** Emit a SETLIST instruction. +** 'base' is register that keeps table; +** 'nelems' is #table plus those to be stored now; +** 'tostore' is number of values (in registers 'base + 1',...) to add to +** table (or LUA_MULTRET to add up to stack top). +*/ +void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) { + int c = (nelems - 1)/LFIELDS_PER_FLUSH + 1; + int b = (tostore == LUA_MULTRET) ? 0 : tostore; + lua_assert(tostore != 0 && tostore <= LFIELDS_PER_FLUSH); + if (c <= MAXARG_C) + luaK_codeABC(fs, OP_SETLIST, base, b, c); + else if (c <= MAXARG_Ax) { + luaK_codeABC(fs, OP_SETLIST, base, b, 0); + codeextraarg(fs, c); + } + else + luaX_syntaxerror(fs->ls, "constructor too long"); + fs->freereg = base + 1; /* free registers with list values */ +} + diff --git a/depends/lua/src/lcorolib.c b/depends/lua/src/lcorolib.c new file mode 100644 index 0000000000..0b17af9e34 --- /dev/null +++ b/depends/lua/src/lcorolib.c @@ -0,0 +1,168 @@ +/* +** $Id: lcorolib.c,v 1.10.1.1 2017/04/19 17:20:42 roberto Exp $ +** Coroutine Library +** See Copyright Notice in lua.h +*/ + +#define lcorolib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +static lua_State *getco (lua_State *L) { + lua_State *co = lua_tothread(L, 1); + luaL_argcheck(L, co, 1, "thread expected"); + return co; +} + + +static int auxresume (lua_State *L, lua_State *co, int narg) { + int status; + if (!lua_checkstack(co, narg)) { + lua_pushliteral(L, "too many arguments to resume"); + return -1; /* error flag */ + } + if (lua_status(co) == LUA_OK && lua_gettop(co) == 0) { + lua_pushliteral(L, "cannot resume dead coroutine"); + return -1; /* error flag */ + } + lua_xmove(L, co, narg); + status = lua_resume(co, L, narg); + if (status == LUA_OK || status == LUA_YIELD) { + int nres = lua_gettop(co); + if (!lua_checkstack(L, nres + 1)) { + lua_pop(co, nres); /* remove results anyway */ + lua_pushliteral(L, "too many results to resume"); + return -1; /* error flag */ + } + lua_xmove(co, L, nres); /* move yielded values */ + return nres; + } + else { + lua_xmove(co, L, 1); /* move error message */ + return -1; /* error flag */ + } +} + + +static int luaB_coresume (lua_State *L) { + lua_State *co = getco(L); + int r; + r = auxresume(L, co, lua_gettop(L) - 1); + if (r < 0) { + lua_pushboolean(L, 0); + lua_insert(L, -2); + return 2; /* return false + error message */ + } + else { + lua_pushboolean(L, 1); + lua_insert(L, -(r + 1)); + return r + 1; /* return true + 'resume' returns */ + } +} + + +static int luaB_auxwrap (lua_State *L) { + lua_State *co = lua_tothread(L, lua_upvalueindex(1)); + int r = auxresume(L, co, lua_gettop(L)); + if (r < 0) { + if (lua_type(L, -1) == LUA_TSTRING) { /* error object is a string? */ + luaL_where(L, 1); /* add extra info */ + lua_insert(L, -2); + lua_concat(L, 2); + } + return lua_error(L); /* propagate error */ + } + return r; +} + + +static int luaB_cocreate (lua_State *L) { + lua_State *NL; + luaL_checktype(L, 1, LUA_TFUNCTION); + NL = lua_newthread(L); + lua_pushvalue(L, 1); /* move function to top */ + lua_xmove(L, NL, 1); /* move function from L to NL */ + return 1; +} + + +static int luaB_cowrap (lua_State *L) { + luaB_cocreate(L); + lua_pushcclosure(L, luaB_auxwrap, 1); + return 1; +} + + +static int luaB_yield (lua_State *L) { + return lua_yield(L, lua_gettop(L)); +} + + +static int luaB_costatus (lua_State *L) { + lua_State *co = getco(L); + if (L == co) lua_pushliteral(L, "running"); + else { + switch (lua_status(co)) { + case LUA_YIELD: + lua_pushliteral(L, "suspended"); + break; + case LUA_OK: { + lua_Debug ar; + if (lua_getstack(co, 0, &ar) > 0) /* does it have frames? */ + lua_pushliteral(L, "normal"); /* it is running */ + else if (lua_gettop(co) == 0) + lua_pushliteral(L, "dead"); + else + lua_pushliteral(L, "suspended"); /* initial state */ + break; + } + default: /* some error occurred */ + lua_pushliteral(L, "dead"); + break; + } + } + return 1; +} + + +static int luaB_yieldable (lua_State *L) { + lua_pushboolean(L, lua_isyieldable(L)); + return 1; +} + + +static int luaB_corunning (lua_State *L) { + int ismain = lua_pushthread(L); + lua_pushboolean(L, ismain); + return 2; +} + + +static const luaL_Reg co_funcs[] = { + {"create", luaB_cocreate}, + {"resume", luaB_coresume}, + {"running", luaB_corunning}, + {"status", luaB_costatus}, + {"wrap", luaB_cowrap}, + {"yield", luaB_yield}, + {"isyieldable", luaB_yieldable}, + {NULL, NULL} +}; + + + +LUAMOD_API int luaopen_coroutine (lua_State *L) { + luaL_newlib(L, co_funcs); + return 1; +} + diff --git a/depends/lua/src/lctype.c b/depends/lua/src/lctype.c new file mode 100644 index 0000000000..f8ad7a2edf --- /dev/null +++ b/depends/lua/src/lctype.c @@ -0,0 +1,55 @@ +/* +** $Id: lctype.c,v 1.12.1.1 2017/04/19 17:20:42 roberto Exp $ +** 'ctype' functions for Lua +** See Copyright Notice in lua.h +*/ + +#define lctype_c +#define LUA_CORE + +#include "lprefix.h" + + +#include "lctype.h" + +#if !LUA_USE_CTYPE /* { */ + +#include + +LUAI_DDEF const lu_byte luai_ctype_[UCHAR_MAX + 2] = { + 0x00, /* EOZ */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0. */ + 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 1. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, /* 2. */ + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, /* 3. */ + 0x16, 0x16, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x05, /* 4. */ + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 5. */ + 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x05, + 0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x05, /* 6. */ + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 7. */ + 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 8. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 9. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* a. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* b. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* c. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* d. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* e. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* f. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +#endif /* } */ diff --git a/depends/lua/src/ldblib.c b/depends/lua/src/ldblib.c new file mode 100644 index 0000000000..9d29afb0a8 --- /dev/null +++ b/depends/lua/src/ldblib.c @@ -0,0 +1,456 @@ +/* +** $Id: ldblib.c,v 1.151.1.1 2017/04/19 17:20:42 roberto Exp $ +** Interface from Lua to its debug API +** See Copyright Notice in lua.h +*/ + +#define ldblib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include +#include +#include + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +/* +** The hook table at registry[&HOOKKEY] maps threads to their current +** hook function. (We only need the unique address of 'HOOKKEY'.) +*/ +static const int HOOKKEY = 0; + + +/* +** If L1 != L, L1 can be in any state, and therefore there are no +** guarantees about its stack space; any push in L1 must be +** checked. +*/ +static void checkstack (lua_State *L, lua_State *L1, int n) { + if (L != L1 && !lua_checkstack(L1, n)) + luaL_error(L, "stack overflow"); +} + + +static int db_getregistry (lua_State *L) { + lua_pushvalue(L, LUA_REGISTRYINDEX); + return 1; +} + + +static int db_getmetatable (lua_State *L) { + luaL_checkany(L, 1); + if (!lua_getmetatable(L, 1)) { + lua_pushnil(L); /* no metatable */ + } + return 1; +} + + +static int db_setmetatable (lua_State *L) { + int t = lua_type(L, 2); + luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, + "nil or table expected"); + lua_settop(L, 2); + lua_setmetatable(L, 1); + return 1; /* return 1st argument */ +} + + +static int db_getuservalue (lua_State *L) { + if (lua_type(L, 1) != LUA_TUSERDATA) + lua_pushnil(L); + else + lua_getuservalue(L, 1); + return 1; +} + + +static int db_setuservalue (lua_State *L) { + luaL_checktype(L, 1, LUA_TUSERDATA); + luaL_checkany(L, 2); + lua_settop(L, 2); + lua_setuservalue(L, 1); + return 1; +} + + +/* +** Auxiliary function used by several library functions: check for +** an optional thread as function's first argument and set 'arg' with +** 1 if this argument is present (so that functions can skip it to +** access their other arguments) +*/ +static lua_State *getthread (lua_State *L, int *arg) { + if (lua_isthread(L, 1)) { + *arg = 1; + return lua_tothread(L, 1); + } + else { + *arg = 0; + return L; /* function will operate over current thread */ + } +} + + +/* +** Variations of 'lua_settable', used by 'db_getinfo' to put results +** from 'lua_getinfo' into result table. Key is always a string; +** value can be a string, an int, or a boolean. +*/ +static void settabss (lua_State *L, const char *k, const char *v) { + lua_pushstring(L, v); + lua_setfield(L, -2, k); +} + +static void settabsi (lua_State *L, const char *k, int v) { + lua_pushinteger(L, v); + lua_setfield(L, -2, k); +} + +static void settabsb (lua_State *L, const char *k, int v) { + lua_pushboolean(L, v); + lua_setfield(L, -2, k); +} + + +/* +** In function 'db_getinfo', the call to 'lua_getinfo' may push +** results on the stack; later it creates the result table to put +** these objects. Function 'treatstackoption' puts the result from +** 'lua_getinfo' on top of the result table so that it can call +** 'lua_setfield'. +*/ +static void treatstackoption (lua_State *L, lua_State *L1, const char *fname) { + if (L == L1) + lua_rotate(L, -2, 1); /* exchange object and table */ + else + lua_xmove(L1, L, 1); /* move object to the "main" stack */ + lua_setfield(L, -2, fname); /* put object into table */ +} + + +/* +** Calls 'lua_getinfo' and collects all results in a new table. +** L1 needs stack space for an optional input (function) plus +** two optional outputs (function and line table) from function +** 'lua_getinfo'. +*/ +static int db_getinfo (lua_State *L) { + lua_Debug ar; + int arg; + lua_State *L1 = getthread(L, &arg); + const char *options = luaL_optstring(L, arg+2, "flnStu"); + checkstack(L, L1, 3); + if (lua_isfunction(L, arg + 1)) { /* info about a function? */ + options = lua_pushfstring(L, ">%s", options); /* add '>' to 'options' */ + lua_pushvalue(L, arg + 1); /* move function to 'L1' stack */ + lua_xmove(L, L1, 1); + } + else { /* stack level */ + if (!lua_getstack(L1, (int)luaL_checkinteger(L, arg + 1), &ar)) { + lua_pushnil(L); /* level out of range */ + return 1; + } + } + if (!lua_getinfo(L1, options, &ar)) + return luaL_argerror(L, arg+2, "invalid option"); + lua_newtable(L); /* table to collect results */ + if (strchr(options, 'S')) { + settabss(L, "source", ar.source); + settabss(L, "short_src", ar.short_src); + settabsi(L, "linedefined", ar.linedefined); + settabsi(L, "lastlinedefined", ar.lastlinedefined); + settabss(L, "what", ar.what); + } + if (strchr(options, 'l')) + settabsi(L, "currentline", ar.currentline); + if (strchr(options, 'u')) { + settabsi(L, "nups", ar.nups); + settabsi(L, "nparams", ar.nparams); + settabsb(L, "isvararg", ar.isvararg); + } + if (strchr(options, 'n')) { + settabss(L, "name", ar.name); + settabss(L, "namewhat", ar.namewhat); + } + if (strchr(options, 't')) + settabsb(L, "istailcall", ar.istailcall); + if (strchr(options, 'L')) + treatstackoption(L, L1, "activelines"); + if (strchr(options, 'f')) + treatstackoption(L, L1, "func"); + return 1; /* return table */ +} + + +static int db_getlocal (lua_State *L) { + int arg; + lua_State *L1 = getthread(L, &arg); + lua_Debug ar; + const char *name; + int nvar = (int)luaL_checkinteger(L, arg + 2); /* local-variable index */ + if (lua_isfunction(L, arg + 1)) { /* function argument? */ + lua_pushvalue(L, arg + 1); /* push function */ + lua_pushstring(L, lua_getlocal(L, NULL, nvar)); /* push local name */ + return 1; /* return only name (there is no value) */ + } + else { /* stack-level argument */ + int level = (int)luaL_checkinteger(L, arg + 1); + if (!lua_getstack(L1, level, &ar)) /* out of range? */ + return luaL_argerror(L, arg+1, "level out of range"); + checkstack(L, L1, 1); + name = lua_getlocal(L1, &ar, nvar); + if (name) { + lua_xmove(L1, L, 1); /* move local value */ + lua_pushstring(L, name); /* push name */ + lua_rotate(L, -2, 1); /* re-order */ + return 2; + } + else { + lua_pushnil(L); /* no name (nor value) */ + return 1; + } + } +} + + +static int db_setlocal (lua_State *L) { + int arg; + const char *name; + lua_State *L1 = getthread(L, &arg); + lua_Debug ar; + int level = (int)luaL_checkinteger(L, arg + 1); + int nvar = (int)luaL_checkinteger(L, arg + 2); + if (!lua_getstack(L1, level, &ar)) /* out of range? */ + return luaL_argerror(L, arg+1, "level out of range"); + luaL_checkany(L, arg+3); + lua_settop(L, arg+3); + checkstack(L, L1, 1); + lua_xmove(L, L1, 1); + name = lua_setlocal(L1, &ar, nvar); + if (name == NULL) + lua_pop(L1, 1); /* pop value (if not popped by 'lua_setlocal') */ + lua_pushstring(L, name); + return 1; +} + + +/* +** get (if 'get' is true) or set an upvalue from a closure +*/ +static int auxupvalue (lua_State *L, int get) { + const char *name; + int n = (int)luaL_checkinteger(L, 2); /* upvalue index */ + luaL_checktype(L, 1, LUA_TFUNCTION); /* closure */ + name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n); + if (name == NULL) return 0; + lua_pushstring(L, name); + lua_insert(L, -(get+1)); /* no-op if get is false */ + return get + 1; +} + + +static int db_getupvalue (lua_State *L) { + return auxupvalue(L, 1); +} + + +static int db_setupvalue (lua_State *L) { + luaL_checkany(L, 3); + return auxupvalue(L, 0); +} + + +/* +** Check whether a given upvalue from a given closure exists and +** returns its index +*/ +static int checkupval (lua_State *L, int argf, int argnup) { + int nup = (int)luaL_checkinteger(L, argnup); /* upvalue index */ + luaL_checktype(L, argf, LUA_TFUNCTION); /* closure */ + luaL_argcheck(L, (lua_getupvalue(L, argf, nup) != NULL), argnup, + "invalid upvalue index"); + return nup; +} + + +static int db_upvalueid (lua_State *L) { + int n = checkupval(L, 1, 2); + lua_pushlightuserdata(L, lua_upvalueid(L, 1, n)); + return 1; +} + + +static int db_upvaluejoin (lua_State *L) { + int n1 = checkupval(L, 1, 2); + int n2 = checkupval(L, 3, 4); + luaL_argcheck(L, !lua_iscfunction(L, 1), 1, "Lua function expected"); + luaL_argcheck(L, !lua_iscfunction(L, 3), 3, "Lua function expected"); + lua_upvaluejoin(L, 1, n1, 3, n2); + return 0; +} + + +/* +** Call hook function registered at hook table for the current +** thread (if there is one) +*/ +static void hookf (lua_State *L, lua_Debug *ar) { + static const char *const hooknames[] = + {"call", "return", "line", "count", "tail call"}; + lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY); + lua_pushthread(L); + if (lua_rawget(L, -2) == LUA_TFUNCTION) { /* is there a hook function? */ + lua_pushstring(L, hooknames[(int)ar->event]); /* push event name */ + if (ar->currentline >= 0) + lua_pushinteger(L, ar->currentline); /* push current line */ + else lua_pushnil(L); + lua_assert(lua_getinfo(L, "lS", ar)); + lua_call(L, 2, 0); /* call hook function */ + } +} + + +/* +** Convert a string mask (for 'sethook') into a bit mask +*/ +static int makemask (const char *smask, int count) { + int mask = 0; + if (strchr(smask, 'c')) mask |= LUA_MASKCALL; + if (strchr(smask, 'r')) mask |= LUA_MASKRET; + if (strchr(smask, 'l')) mask |= LUA_MASKLINE; + if (count > 0) mask |= LUA_MASKCOUNT; + return mask; +} + + +/* +** Convert a bit mask (for 'gethook') into a string mask +*/ +static char *unmakemask (int mask, char *smask) { + int i = 0; + if (mask & LUA_MASKCALL) smask[i++] = 'c'; + if (mask & LUA_MASKRET) smask[i++] = 'r'; + if (mask & LUA_MASKLINE) smask[i++] = 'l'; + smask[i] = '\0'; + return smask; +} + + +static int db_sethook (lua_State *L) { + int arg, mask, count; + lua_Hook func; + lua_State *L1 = getthread(L, &arg); + if (lua_isnoneornil(L, arg+1)) { /* no hook? */ + lua_settop(L, arg+1); + func = NULL; mask = 0; count = 0; /* turn off hooks */ + } + else { + const char *smask = luaL_checkstring(L, arg+2); + luaL_checktype(L, arg+1, LUA_TFUNCTION); + count = (int)luaL_optinteger(L, arg + 3, 0); + func = hookf; mask = makemask(smask, count); + } + if (lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY) == LUA_TNIL) { + lua_createtable(L, 0, 2); /* create a hook table */ + lua_pushvalue(L, -1); + lua_rawsetp(L, LUA_REGISTRYINDEX, &HOOKKEY); /* set it in position */ + lua_pushstring(L, "k"); + lua_setfield(L, -2, "__mode"); /** hooktable.__mode = "k" */ + lua_pushvalue(L, -1); + lua_setmetatable(L, -2); /* setmetatable(hooktable) = hooktable */ + } + checkstack(L, L1, 1); + lua_pushthread(L1); lua_xmove(L1, L, 1); /* key (thread) */ + lua_pushvalue(L, arg + 1); /* value (hook function) */ + lua_rawset(L, -3); /* hooktable[L1] = new Lua hook */ + lua_sethook(L1, func, mask, count); + return 0; +} + + +static int db_gethook (lua_State *L) { + int arg; + lua_State *L1 = getthread(L, &arg); + char buff[5]; + int mask = lua_gethookmask(L1); + lua_Hook hook = lua_gethook(L1); + if (hook == NULL) /* no hook? */ + lua_pushnil(L); + else if (hook != hookf) /* external hook? */ + lua_pushliteral(L, "external hook"); + else { /* hook table must exist */ + lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY); + checkstack(L, L1, 1); + lua_pushthread(L1); lua_xmove(L1, L, 1); + lua_rawget(L, -2); /* 1st result = hooktable[L1] */ + lua_remove(L, -2); /* remove hook table */ + } + lua_pushstring(L, unmakemask(mask, buff)); /* 2nd result = mask */ + lua_pushinteger(L, lua_gethookcount(L1)); /* 3rd result = count */ + return 3; +} + + +static int db_debug (lua_State *L) { + for (;;) { + char buffer[250]; + lua_writestringerror("%s", "lua_debug> "); + if (fgets(buffer, sizeof(buffer), stdin) == 0 || + strcmp(buffer, "cont\n") == 0) + return 0; + if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") || + lua_pcall(L, 0, 0, 0)) + lua_writestringerror("%s\n", lua_tostring(L, -1)); + lua_settop(L, 0); /* remove eventual returns */ + } +} + + +static int db_traceback (lua_State *L) { + int arg; + lua_State *L1 = getthread(L, &arg); + const char *msg = lua_tostring(L, arg + 1); + if (msg == NULL && !lua_isnoneornil(L, arg + 1)) /* non-string 'msg'? */ + lua_pushvalue(L, arg + 1); /* return it untouched */ + else { + int level = (int)luaL_optinteger(L, arg + 2, (L == L1) ? 1 : 0); + luaL_traceback(L, L1, msg, level); + } + return 1; +} + + +static const luaL_Reg dblib[] = { + {"debug", db_debug}, + {"getuservalue", db_getuservalue}, + {"gethook", db_gethook}, + {"getinfo", db_getinfo}, + {"getlocal", db_getlocal}, + {"getregistry", db_getregistry}, + {"getmetatable", db_getmetatable}, + {"getupvalue", db_getupvalue}, + {"upvaluejoin", db_upvaluejoin}, + {"upvalueid", db_upvalueid}, + {"setuservalue", db_setuservalue}, + {"sethook", db_sethook}, + {"setlocal", db_setlocal}, + {"setmetatable", db_setmetatable}, + {"setupvalue", db_setupvalue}, + {"traceback", db_traceback}, + {NULL, NULL} +}; + + +LUAMOD_API int luaopen_debug (lua_State *L) { + luaL_newlib(L, dblib); + return 1; +} + diff --git a/depends/lua/src/ldebug.c b/depends/lua/src/ldebug.c new file mode 100644 index 0000000000..bb0e1d4ace --- /dev/null +++ b/depends/lua/src/ldebug.c @@ -0,0 +1,700 @@ +/* +** $Id: ldebug.c,v 2.121.1.2 2017/07/10 17:21:50 roberto Exp $ +** Debug Interface +** See Copyright Notice in lua.h +*/ + +#define ldebug_c +#define LUA_CORE + +#include "lprefix.h" + + +#include +#include +#include + +#include "lua.h" + +#include "lapi.h" +#include "lcode.h" +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "lobject.h" +#include "lopcodes.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" +#include "lvm.h" + + + +#define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_TCCL) + + +/* Active Lua function (given call info) */ +#define ci_func(ci) (clLvalue((ci)->func)) + + +static const char *funcnamefromcode (lua_State *L, CallInfo *ci, + const char **name); + + +static int currentpc (CallInfo *ci) { + lua_assert(isLua(ci)); + return pcRel(ci->u.l.savedpc, ci_func(ci)->p); +} + + +static int currentline (CallInfo *ci) { + return getfuncline(ci_func(ci)->p, currentpc(ci)); +} + + +/* +** If function yielded, its 'func' can be in the 'extra' field. The +** next function restores 'func' to its correct value for debugging +** purposes. (It exchanges 'func' and 'extra'; so, when called again, +** after debugging, it also "re-restores" ** 'func' to its altered value. +*/ +static void swapextra (lua_State *L) { + if (L->status == LUA_YIELD) { + CallInfo *ci = L->ci; /* get function that yielded */ + StkId temp = ci->func; /* exchange its 'func' and 'extra' values */ + ci->func = restorestack(L, ci->extra); + ci->extra = savestack(L, temp); + } +} + + +/* +** This function can be called asynchronously (e.g. during a signal). +** Fields 'oldpc', 'basehookcount', and 'hookcount' (set by +** 'resethookcount') are for debug only, and it is no problem if they +** get arbitrary values (causes at most one wrong hook call). 'hookmask' +** is an atomic value. We assume that pointers are atomic too (e.g., gcc +** ensures that for all platforms where it runs). Moreover, 'hook' is +** always checked before being called (see 'luaD_hook'). +*/ +LUA_API void lua_sethook (lua_State *L, lua_Hook func, int mask, int count) { + if (func == NULL || mask == 0) { /* turn off hooks? */ + mask = 0; + func = NULL; + } + if (isLua(L->ci)) + L->oldpc = L->ci->u.l.savedpc; + L->hook = func; + L->basehookcount = count; + resethookcount(L); + L->hookmask = cast_byte(mask); +} + + +LUA_API lua_Hook lua_gethook (lua_State *L) { + return L->hook; +} + + +LUA_API int lua_gethookmask (lua_State *L) { + return L->hookmask; +} + + +LUA_API int lua_gethookcount (lua_State *L) { + return L->basehookcount; +} + + +LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) { + int status; + CallInfo *ci; + if (level < 0) return 0; /* invalid (negative) level */ + lua_lock(L); + for (ci = L->ci; level > 0 && ci != &L->base_ci; ci = ci->previous) + level--; + if (level == 0 && ci != &L->base_ci) { /* level found? */ + status = 1; + ar->i_ci = ci; + } + else status = 0; /* no such level */ + lua_unlock(L); + return status; +} + + +static const char *upvalname (Proto *p, int uv) { + TString *s = check_exp(uv < p->sizeupvalues, p->upvalues[uv].name); + if (s == NULL) return "?"; + else return getstr(s); +} + + +static const char *findvararg (CallInfo *ci, int n, StkId *pos) { + int nparams = clLvalue(ci->func)->p->numparams; + int nvararg = cast_int(ci->u.l.base - ci->func) - nparams; + if (n <= -nvararg) + return NULL; /* no such vararg */ + else { + *pos = ci->func + nparams - n; + return "(*vararg)"; /* generic name for any vararg */ + } +} + + +static const char *findlocal (lua_State *L, CallInfo *ci, int n, + StkId *pos) { + const char *name = NULL; + StkId base; + if (isLua(ci)) { + if (n < 0) /* access to vararg values? */ + return findvararg(ci, n, pos); + else { + base = ci->u.l.base; + name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci)); + } + } + else + base = ci->func + 1; + if (name == NULL) { /* no 'standard' name? */ + StkId limit = (ci == L->ci) ? L->top : ci->next->func; + if (limit - base >= n && n > 0) /* is 'n' inside 'ci' stack? */ + name = "(*temporary)"; /* generic name for any valid slot */ + else + return NULL; /* no name */ + } + *pos = base + (n - 1); + return name; +} + + +LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) { + const char *name; + lua_lock(L); + swapextra(L); + if (ar == NULL) { /* information about non-active function? */ + if (!isLfunction(L->top - 1)) /* not a Lua function? */ + name = NULL; + else /* consider live variables at function start (parameters) */ + name = luaF_getlocalname(clLvalue(L->top - 1)->p, n, 0); + } + else { /* active function; get information through 'ar' */ + StkId pos = NULL; /* to avoid warnings */ + name = findlocal(L, ar->i_ci, n, &pos); + if (name) { + setobj2s(L, L->top, pos); + api_incr_top(L); + } + } + swapextra(L); + lua_unlock(L); + return name; +} + + +LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) { + StkId pos = NULL; /* to avoid warnings */ + const char *name; + lua_lock(L); + swapextra(L); + name = findlocal(L, ar->i_ci, n, &pos); + if (name) { + setobjs2s(L, pos, L->top - 1); + L->top--; /* pop value */ + } + swapextra(L); + lua_unlock(L); + return name; +} + + +static void funcinfo (lua_Debug *ar, Closure *cl) { + if (noLuaClosure(cl)) { + ar->source = "=[C]"; + ar->linedefined = -1; + ar->lastlinedefined = -1; + ar->what = "C"; + } + else { + Proto *p = cl->l.p; + ar->source = p->source ? getstr(p->source) : "=?"; + ar->linedefined = p->linedefined; + ar->lastlinedefined = p->lastlinedefined; + ar->what = (ar->linedefined == 0) ? "main" : "Lua"; + } + luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE); +} + + +static void collectvalidlines (lua_State *L, Closure *f) { + if (noLuaClosure(f)) { + setnilvalue(L->top); + api_incr_top(L); + } + else { + int i; + TValue v; + int *lineinfo = f->l.p->lineinfo; + Table *t = luaH_new(L); /* new table to store active lines */ + sethvalue(L, L->top, t); /* push it on stack */ + api_incr_top(L); + setbvalue(&v, 1); /* boolean 'true' to be the value of all indices */ + for (i = 0; i < f->l.p->sizelineinfo; i++) /* for all lines with code */ + luaH_setint(L, t, lineinfo[i], &v); /* table[line] = true */ + } +} + + +static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) { + if (ci == NULL) /* no 'ci'? */ + return NULL; /* no info */ + else if (ci->callstatus & CIST_FIN) { /* is this a finalizer? */ + *name = "__gc"; + return "metamethod"; /* report it as such */ + } + /* calling function is a known Lua function? */ + else if (!(ci->callstatus & CIST_TAIL) && isLua(ci->previous)) + return funcnamefromcode(L, ci->previous, name); + else return NULL; /* no way to find a name */ +} + + +static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, + Closure *f, CallInfo *ci) { + int status = 1; + for (; *what; what++) { + switch (*what) { + case 'S': { + funcinfo(ar, f); + break; + } + case 'l': { + ar->currentline = (ci && isLua(ci)) ? currentline(ci) : -1; + break; + } + case 'u': { + ar->nups = (f == NULL) ? 0 : f->c.nupvalues; + if (noLuaClosure(f)) { + ar->isvararg = 1; + ar->nparams = 0; + } + else { + ar->isvararg = f->l.p->is_vararg; + ar->nparams = f->l.p->numparams; + } + break; + } + case 't': { + ar->istailcall = (ci) ? ci->callstatus & CIST_TAIL : 0; + break; + } + case 'n': { + ar->namewhat = getfuncname(L, ci, &ar->name); + if (ar->namewhat == NULL) { + ar->namewhat = ""; /* not found */ + ar->name = NULL; + } + break; + } + case 'L': + case 'f': /* handled by lua_getinfo */ + break; + default: status = 0; /* invalid option */ + } + } + return status; +} + + +LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { + int status; + Closure *cl; + CallInfo *ci; + StkId func; + lua_lock(L); + swapextra(L); + if (*what == '>') { + ci = NULL; + func = L->top - 1; + api_check(L, ttisfunction(func), "function expected"); + what++; /* skip the '>' */ + L->top--; /* pop function */ + } + else { + ci = ar->i_ci; + func = ci->func; + lua_assert(ttisfunction(ci->func)); + } + cl = ttisclosure(func) ? clvalue(func) : NULL; + status = auxgetinfo(L, what, ar, cl, ci); + if (strchr(what, 'f')) { + setobjs2s(L, L->top, func); + api_incr_top(L); + } + swapextra(L); /* correct before option 'L', which can raise a mem. error */ + if (strchr(what, 'L')) + collectvalidlines(L, cl); + lua_unlock(L); + return status; +} + + +/* +** {====================================================== +** Symbolic Execution +** ======================================================= +*/ + +static const char *getobjname (Proto *p, int lastpc, int reg, + const char **name); + + +/* +** find a "name" for the RK value 'c' +*/ +static void kname (Proto *p, int pc, int c, const char **name) { + if (ISK(c)) { /* is 'c' a constant? */ + TValue *kvalue = &p->k[INDEXK(c)]; + if (ttisstring(kvalue)) { /* literal constant? */ + *name = svalue(kvalue); /* it is its own name */ + return; + } + /* else no reasonable name found */ + } + else { /* 'c' is a register */ + const char *what = getobjname(p, pc, c, name); /* search for 'c' */ + if (what && *what == 'c') { /* found a constant name? */ + return; /* 'name' already filled */ + } + /* else no reasonable name found */ + } + *name = "?"; /* no reasonable name found */ +} + + +static int filterpc (int pc, int jmptarget) { + if (pc < jmptarget) /* is code conditional (inside a jump)? */ + return -1; /* cannot know who sets that register */ + else return pc; /* current position sets that register */ +} + + +/* +** try to find last instruction before 'lastpc' that modified register 'reg' +*/ +static int findsetreg (Proto *p, int lastpc, int reg) { + int pc; + int setreg = -1; /* keep last instruction that changed 'reg' */ + int jmptarget = 0; /* any code before this address is conditional */ + for (pc = 0; pc < lastpc; pc++) { + Instruction i = p->code[pc]; + OpCode op = GET_OPCODE(i); + int a = GETARG_A(i); + switch (op) { + case OP_LOADNIL: { + int b = GETARG_B(i); + if (a <= reg && reg <= a + b) /* set registers from 'a' to 'a+b' */ + setreg = filterpc(pc, jmptarget); + break; + } + case OP_TFORCALL: { + if (reg >= a + 2) /* affect all regs above its base */ + setreg = filterpc(pc, jmptarget); + break; + } + case OP_CALL: + case OP_TAILCALL: { + if (reg >= a) /* affect all registers above base */ + setreg = filterpc(pc, jmptarget); + break; + } + case OP_JMP: { + int b = GETARG_sBx(i); + int dest = pc + 1 + b; + /* jump is forward and do not skip 'lastpc'? */ + if (pc < dest && dest <= lastpc) { + if (dest > jmptarget) + jmptarget = dest; /* update 'jmptarget' */ + } + break; + } + default: + if (testAMode(op) && reg == a) /* any instruction that set A */ + setreg = filterpc(pc, jmptarget); + break; + } + } + return setreg; +} + + +static const char *getobjname (Proto *p, int lastpc, int reg, + const char **name) { + int pc; + *name = luaF_getlocalname(p, reg + 1, lastpc); + if (*name) /* is a local? */ + return "local"; + /* else try symbolic execution */ + pc = findsetreg(p, lastpc, reg); + if (pc != -1) { /* could find instruction? */ + Instruction i = p->code[pc]; + OpCode op = GET_OPCODE(i); + switch (op) { + case OP_MOVE: { + int b = GETARG_B(i); /* move from 'b' to 'a' */ + if (b < GETARG_A(i)) + return getobjname(p, pc, b, name); /* get name for 'b' */ + break; + } + case OP_GETTABUP: + case OP_GETTABLE: { + int k = GETARG_C(i); /* key index */ + int t = GETARG_B(i); /* table index */ + const char *vn = (op == OP_GETTABLE) /* name of indexed variable */ + ? luaF_getlocalname(p, t + 1, pc) + : upvalname(p, t); + kname(p, pc, k, name); + return (vn && strcmp(vn, LUA_ENV) == 0) ? "global" : "field"; + } + case OP_GETUPVAL: { + *name = upvalname(p, GETARG_B(i)); + return "upvalue"; + } + case OP_LOADK: + case OP_LOADKX: { + int b = (op == OP_LOADK) ? GETARG_Bx(i) + : GETARG_Ax(p->code[pc + 1]); + if (ttisstring(&p->k[b])) { + *name = svalue(&p->k[b]); + return "constant"; + } + break; + } + case OP_SELF: { + int k = GETARG_C(i); /* key index */ + kname(p, pc, k, name); + return "method"; + } + default: break; /* go through to return NULL */ + } + } + return NULL; /* could not find reasonable name */ +} + + +/* +** Try to find a name for a function based on the code that called it. +** (Only works when function was called by a Lua function.) +** Returns what the name is (e.g., "for iterator", "method", +** "metamethod") and sets '*name' to point to the name. +*/ +static const char *funcnamefromcode (lua_State *L, CallInfo *ci, + const char **name) { + TMS tm = (TMS)0; /* (initial value avoids warnings) */ + Proto *p = ci_func(ci)->p; /* calling function */ + int pc = currentpc(ci); /* calling instruction index */ + Instruction i = p->code[pc]; /* calling instruction */ + if (ci->callstatus & CIST_HOOKED) { /* was it called inside a hook? */ + *name = "?"; + return "hook"; + } + switch (GET_OPCODE(i)) { + case OP_CALL: + case OP_TAILCALL: + return getobjname(p, pc, GETARG_A(i), name); /* get function name */ + case OP_TFORCALL: { /* for iterator */ + *name = "for iterator"; + return "for iterator"; + } + /* other instructions can do calls through metamethods */ + case OP_SELF: case OP_GETTABUP: case OP_GETTABLE: + tm = TM_INDEX; + break; + case OP_SETTABUP: case OP_SETTABLE: + tm = TM_NEWINDEX; + break; + case OP_ADD: case OP_SUB: case OP_MUL: case OP_MOD: + case OP_POW: case OP_DIV: case OP_IDIV: case OP_BAND: + case OP_BOR: case OP_BXOR: case OP_SHL: case OP_SHR: { + int offset = cast_int(GET_OPCODE(i)) - cast_int(OP_ADD); /* ORDER OP */ + tm = cast(TMS, offset + cast_int(TM_ADD)); /* ORDER TM */ + break; + } + case OP_UNM: tm = TM_UNM; break; + case OP_BNOT: tm = TM_BNOT; break; + case OP_LEN: tm = TM_LEN; break; + case OP_CONCAT: tm = TM_CONCAT; break; + case OP_EQ: tm = TM_EQ; break; + case OP_LT: tm = TM_LT; break; + case OP_LE: tm = TM_LE; break; + default: + return NULL; /* cannot find a reasonable name */ + } + *name = getstr(G(L)->tmname[tm]); + return "metamethod"; +} + +/* }====================================================== */ + + + +/* +** The subtraction of two potentially unrelated pointers is +** not ISO C, but it should not crash a program; the subsequent +** checks are ISO C and ensure a correct result. +*/ +static int isinstack (CallInfo *ci, const TValue *o) { + ptrdiff_t i = o - ci->u.l.base; + return (0 <= i && i < (ci->top - ci->u.l.base) && ci->u.l.base + i == o); +} + + +/* +** Checks whether value 'o' came from an upvalue. (That can only happen +** with instructions OP_GETTABUP/OP_SETTABUP, which operate directly on +** upvalues.) +*/ +static const char *getupvalname (CallInfo *ci, const TValue *o, + const char **name) { + LClosure *c = ci_func(ci); + int i; + for (i = 0; i < c->nupvalues; i++) { + if (c->upvals[i]->v == o) { + *name = upvalname(c->p, i); + return "upvalue"; + } + } + return NULL; +} + + +static const char *varinfo (lua_State *L, const TValue *o) { + const char *name = NULL; /* to avoid warnings */ + CallInfo *ci = L->ci; + const char *kind = NULL; + if (isLua(ci)) { + kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */ + if (!kind && isinstack(ci, o)) /* no? try a register */ + kind = getobjname(ci_func(ci)->p, currentpc(ci), + cast_int(o - ci->u.l.base), &name); + } + return (kind) ? luaO_pushfstring(L, " (%s '%s')", kind, name) : ""; +} + + +l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) { + const char *t = luaT_objtypename(L, o); + luaG_runerror(L, "attempt to %s a %s value%s", op, t, varinfo(L, o)); +} + + +l_noret luaG_concaterror (lua_State *L, const TValue *p1, const TValue *p2) { + if (ttisstring(p1) || cvt2str(p1)) p1 = p2; + luaG_typeerror(L, p1, "concatenate"); +} + + +l_noret luaG_opinterror (lua_State *L, const TValue *p1, + const TValue *p2, const char *msg) { + lua_Number temp; + if (!tonumber(p1, &temp)) /* first operand is wrong? */ + p2 = p1; /* now second is wrong */ + luaG_typeerror(L, p2, msg); +} + + +/* +** Error when both values are convertible to numbers, but not to integers +*/ +l_noret luaG_tointerror (lua_State *L, const TValue *p1, const TValue *p2) { + lua_Integer temp; + if (!tointeger(p1, &temp)) + p2 = p1; + luaG_runerror(L, "number%s has no integer representation", varinfo(L, p2)); +} + + +l_noret luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) { + const char *t1 = luaT_objtypename(L, p1); + const char *t2 = luaT_objtypename(L, p2); + if (strcmp(t1, t2) == 0) + luaG_runerror(L, "attempt to compare two %s values", t1); + else + luaG_runerror(L, "attempt to compare %s with %s", t1, t2); +} + + +/* add src:line information to 'msg' */ +const char *luaG_addinfo (lua_State *L, const char *msg, TString *src, + int line) { + char buff[LUA_IDSIZE]; + if (src) + luaO_chunkid(buff, getstr(src), LUA_IDSIZE); + else { /* no source available; use "?" instead */ + buff[0] = '?'; buff[1] = '\0'; + } + return luaO_pushfstring(L, "%s:%d: %s", buff, line, msg); +} + + +l_noret luaG_errormsg (lua_State *L) { + if (L->errfunc != 0) { /* is there an error handling function? */ + StkId errfunc = restorestack(L, L->errfunc); + setobjs2s(L, L->top, L->top - 1); /* move argument */ + setobjs2s(L, L->top - 1, errfunc); /* push function */ + L->top++; /* assume EXTRA_STACK */ + luaD_callnoyield(L, L->top - 2, 1); /* call it */ + } + luaD_throw(L, LUA_ERRRUN); +} + + +l_noret luaG_runerror (lua_State *L, const char *fmt, ...) { + CallInfo *ci = L->ci; + const char *msg; + va_list argp; + luaC_checkGC(L); /* error message uses memory */ + va_start(argp, fmt); + msg = luaO_pushvfstring(L, fmt, argp); /* format message */ + va_end(argp); + if (isLua(ci)) /* if Lua function, add source:line information */ + luaG_addinfo(L, msg, ci_func(ci)->p->source, currentline(ci)); + luaG_errormsg(L); +} + + +void luaG_traceexec (lua_State *L) { + CallInfo *ci = L->ci; + lu_byte mask = L->hookmask; + int counthook = (--L->hookcount == 0 && (mask & LUA_MASKCOUNT)); + if (counthook) + resethookcount(L); /* reset count */ + else if (!(mask & LUA_MASKLINE)) + return; /* no line hook and count != 0; nothing to be done */ + if (ci->callstatus & CIST_HOOKYIELD) { /* called hook last time? */ + ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */ + return; /* do not call hook again (VM yielded, so it did not move) */ + } + if (counthook) + luaD_hook(L, LUA_HOOKCOUNT, -1); /* call count hook */ + if (mask & LUA_MASKLINE) { + Proto *p = ci_func(ci)->p; + int npc = pcRel(ci->u.l.savedpc, p); + int newline = getfuncline(p, npc); + if (npc == 0 || /* call linehook when enter a new function, */ + ci->u.l.savedpc <= L->oldpc || /* when jump back (loop), or when */ + newline != getfuncline(p, pcRel(L->oldpc, p))) /* enter a new line */ + luaD_hook(L, LUA_HOOKLINE, newline); /* call line hook */ + } + L->oldpc = ci->u.l.savedpc; + if (L->status == LUA_YIELD) { /* did hook yield? */ + if (counthook) + L->hookcount = 1; /* undo decrement to zero */ + ci->u.l.savedpc--; /* undo increment (resume will increment it again) */ + ci->callstatus |= CIST_HOOKYIELD; /* mark that it yielded */ + ci->func = L->top - 1; /* protect stack below results */ + luaD_throw(L, LUA_YIELD); + } +} + diff --git a/depends/lua/src/ldo.c b/depends/lua/src/ldo.c new file mode 100644 index 0000000000..65158df0b7 --- /dev/null +++ b/depends/lua/src/ldo.c @@ -0,0 +1,802 @@ +/* +** $Id: ldo.c,v 2.157.1.1 2017/04/19 17:20:42 roberto Exp $ +** Stack and Call structure of Lua +** See Copyright Notice in lua.h +*/ + +#define ldo_c +#define LUA_CORE + +#include "lprefix.h" + + +#include +#include +#include + +#include "lua.h" + +#include "lapi.h" +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "lgc.h" +#include "lmem.h" +#include "lobject.h" +#include "lopcodes.h" +#include "lparser.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" +#include "lundump.h" +#include "lvm.h" +#include "lzio.h" + + + +#define errorstatus(s) ((s) > LUA_YIELD) + + +/* +** {====================================================== +** Error-recovery functions +** ======================================================= +*/ + +/* +** LUAI_THROW/LUAI_TRY define how Lua does exception handling. By +** default, Lua handles errors with exceptions when compiling as +** C++ code, with _longjmp/_setjmp when asked to use them, and with +** longjmp/setjmp otherwise. +*/ +#if !defined(LUAI_THROW) /* { */ + +#if defined(__cplusplus) && !defined(LUA_USE_LONGJMP) /* { */ + +/* C++ exceptions */ +#define LUAI_THROW(L,c) throw(c) +#define LUAI_TRY(L,c,a) \ + try { a } catch(...) { if ((c)->status == 0) (c)->status = -1; } +#define luai_jmpbuf int /* dummy variable */ + +#elif defined(LUA_USE_POSIX) /* }{ */ + +/* in POSIX, try _longjmp/_setjmp (more efficient) */ +#define LUAI_THROW(L,c) _longjmp((c)->b, 1) +#define LUAI_TRY(L,c,a) if (_setjmp((c)->b) == 0) { a } +#define luai_jmpbuf jmp_buf + +#else /* }{ */ + +/* ISO C handling with long jumps */ +#define LUAI_THROW(L,c) longjmp((c)->b, 1) +#define LUAI_TRY(L,c,a) if (setjmp((c)->b) == 0) { a } +#define luai_jmpbuf jmp_buf + +#endif /* } */ + +#endif /* } */ + + + +/* chain list of long jump buffers */ +struct lua_longjmp { + struct lua_longjmp *previous; + luai_jmpbuf b; + volatile int status; /* error code */ +}; + + +static void seterrorobj (lua_State *L, int errcode, StkId oldtop) { + switch (errcode) { + case LUA_ERRMEM: { /* memory error? */ + setsvalue2s(L, oldtop, G(L)->memerrmsg); /* reuse preregistered msg. */ + break; + } + case LUA_ERRERR: { + setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling")); + break; + } + default: { + setobjs2s(L, oldtop, L->top - 1); /* error message on current top */ + break; + } + } + L->top = oldtop + 1; +} + + +l_noret luaD_throw (lua_State *L, int errcode) { + if (L->errorJmp) { /* thread has an error handler? */ + L->errorJmp->status = errcode; /* set status */ + LUAI_THROW(L, L->errorJmp); /* jump to it */ + } + else { /* thread has no error handler */ + global_State *g = G(L); + L->status = cast_byte(errcode); /* mark it as dead */ + if (g->mainthread->errorJmp) { /* main thread has a handler? */ + setobjs2s(L, g->mainthread->top++, L->top - 1); /* copy error obj. */ + luaD_throw(g->mainthread, errcode); /* re-throw in main thread */ + } + else { /* no handler at all; abort */ + if (g->panic) { /* panic function? */ + seterrorobj(L, errcode, L->top); /* assume EXTRA_STACK */ + if (L->ci->top < L->top) + L->ci->top = L->top; /* pushing msg. can break this invariant */ + lua_unlock(L); + g->panic(L); /* call panic function (last chance to jump out) */ + } + abort(); + } + } +} + + +int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { + unsigned short oldnCcalls = L->nCcalls; + struct lua_longjmp lj; + lj.status = LUA_OK; + lj.previous = L->errorJmp; /* chain new error handler */ + L->errorJmp = &lj; + LUAI_TRY(L, &lj, + (*f)(L, ud); + ); + L->errorJmp = lj.previous; /* restore old error handler */ + L->nCcalls = oldnCcalls; + return lj.status; +} + +/* }====================================================== */ + + +/* +** {================================================================== +** Stack reallocation +** =================================================================== +*/ +static void correctstack (lua_State *L, TValue *oldstack) { + CallInfo *ci; + UpVal *up; + L->top = (L->top - oldstack) + L->stack; + for (up = L->openupval; up != NULL; up = up->u.open.next) + up->v = (up->v - oldstack) + L->stack; + for (ci = L->ci; ci != NULL; ci = ci->previous) { + ci->top = (ci->top - oldstack) + L->stack; + ci->func = (ci->func - oldstack) + L->stack; + if (isLua(ci)) + ci->u.l.base = (ci->u.l.base - oldstack) + L->stack; + } +} + + +/* some space for error handling */ +#define ERRORSTACKSIZE (LUAI_MAXSTACK + 200) + + +void luaD_reallocstack (lua_State *L, int newsize) { + TValue *oldstack = L->stack; + int lim = L->stacksize; + lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE); + lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK); + luaM_reallocvector(L, L->stack, L->stacksize, newsize, TValue); + for (; lim < newsize; lim++) + setnilvalue(L->stack + lim); /* erase new segment */ + L->stacksize = newsize; + L->stack_last = L->stack + newsize - EXTRA_STACK; + correctstack(L, oldstack); +} + + +void luaD_growstack (lua_State *L, int n) { + int size = L->stacksize; + if (size > LUAI_MAXSTACK) /* error after extra size? */ + luaD_throw(L, LUA_ERRERR); + else { + int needed = cast_int(L->top - L->stack) + n + EXTRA_STACK; + int newsize = 2 * size; + if (newsize > LUAI_MAXSTACK) newsize = LUAI_MAXSTACK; + if (newsize < needed) newsize = needed; + if (newsize > LUAI_MAXSTACK) { /* stack overflow? */ + luaD_reallocstack(L, ERRORSTACKSIZE); + luaG_runerror(L, "stack overflow"); + } + else + luaD_reallocstack(L, newsize); + } +} + + +static int stackinuse (lua_State *L) { + CallInfo *ci; + StkId lim = L->top; + for (ci = L->ci; ci != NULL; ci = ci->previous) { + if (lim < ci->top) lim = ci->top; + } + lua_assert(lim <= L->stack_last); + return cast_int(lim - L->stack) + 1; /* part of stack in use */ +} + + +void luaD_shrinkstack (lua_State *L) { + int inuse = stackinuse(L); + int goodsize = inuse + (inuse / 8) + 2*EXTRA_STACK; + if (goodsize > LUAI_MAXSTACK) + goodsize = LUAI_MAXSTACK; /* respect stack limit */ + if (L->stacksize > LUAI_MAXSTACK) /* had been handling stack overflow? */ + luaE_freeCI(L); /* free all CIs (list grew because of an error) */ + else + luaE_shrinkCI(L); /* shrink list */ + /* if thread is currently not handling a stack overflow and its + good size is smaller than current size, shrink its stack */ + if (inuse <= (LUAI_MAXSTACK - EXTRA_STACK) && + goodsize < L->stacksize) + luaD_reallocstack(L, goodsize); + else /* don't change stack */ + condmovestack(L,{},{}); /* (change only for debugging) */ +} + + +void luaD_inctop (lua_State *L) { + luaD_checkstack(L, 1); + L->top++; +} + +/* }================================================================== */ + + +/* +** Call a hook for the given event. Make sure there is a hook to be +** called. (Both 'L->hook' and 'L->hookmask', which triggers this +** function, can be changed asynchronously by signals.) +*/ +void luaD_hook (lua_State *L, int event, int line) { + lua_Hook hook = L->hook; + if (hook && L->allowhook) { /* make sure there is a hook */ + CallInfo *ci = L->ci; + ptrdiff_t top = savestack(L, L->top); + ptrdiff_t ci_top = savestack(L, ci->top); + lua_Debug ar; + ar.event = event; + ar.currentline = line; + ar.i_ci = ci; + luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ + ci->top = L->top + LUA_MINSTACK; + lua_assert(ci->top <= L->stack_last); + L->allowhook = 0; /* cannot call hooks inside a hook */ + ci->callstatus |= CIST_HOOKED; + lua_unlock(L); + (*hook)(L, &ar); + lua_lock(L); + lua_assert(!L->allowhook); + L->allowhook = 1; + ci->top = restorestack(L, ci_top); + L->top = restorestack(L, top); + ci->callstatus &= ~CIST_HOOKED; + } +} + + +static void callhook (lua_State *L, CallInfo *ci) { + int hook = LUA_HOOKCALL; + ci->u.l.savedpc++; /* hooks assume 'pc' is already incremented */ + if (isLua(ci->previous) && + GET_OPCODE(*(ci->previous->u.l.savedpc - 1)) == OP_TAILCALL) { + ci->callstatus |= CIST_TAIL; + hook = LUA_HOOKTAILCALL; + } + luaD_hook(L, hook, -1); + ci->u.l.savedpc--; /* correct 'pc' */ +} + + +static StkId adjust_varargs (lua_State *L, Proto *p, int actual) { + int i; + int nfixargs = p->numparams; + StkId base, fixed; + /* move fixed parameters to final position */ + fixed = L->top - actual; /* first fixed argument */ + base = L->top; /* final position of first argument */ + for (i = 0; i < nfixargs && i < actual; i++) { + setobjs2s(L, L->top++, fixed + i); + setnilvalue(fixed + i); /* erase original copy (for GC) */ + } + for (; i < nfixargs; i++) + setnilvalue(L->top++); /* complete missing arguments */ + return base; +} + + +/* +** Check whether __call metafield of 'func' is a function. If so, put +** it in stack below original 'func' so that 'luaD_precall' can call +** it. Raise an error if __call metafield is not a function. +*/ +static void tryfuncTM (lua_State *L, StkId func) { + const TValue *tm = luaT_gettmbyobj(L, func, TM_CALL); + StkId p; + if (!ttisfunction(tm)) + luaG_typeerror(L, func, "call"); + /* Open a hole inside the stack at 'func' */ + for (p = L->top; p > func; p--) + setobjs2s(L, p, p-1); + L->top++; /* slot ensured by caller */ + setobj2s(L, func, tm); /* tag method is the new function to be called */ +} + + +/* +** Given 'nres' results at 'firstResult', move 'wanted' of them to 'res'. +** Handle most typical cases (zero results for commands, one result for +** expressions, multiple results for tail calls/single parameters) +** separated. +*/ +static int moveresults (lua_State *L, const TValue *firstResult, StkId res, + int nres, int wanted) { + switch (wanted) { /* handle typical cases separately */ + case 0: break; /* nothing to move */ + case 1: { /* one result needed */ + if (nres == 0) /* no results? */ + firstResult = luaO_nilobject; /* adjust with nil */ + setobjs2s(L, res, firstResult); /* move it to proper place */ + break; + } + case LUA_MULTRET: { + int i; + for (i = 0; i < nres; i++) /* move all results to correct place */ + setobjs2s(L, res + i, firstResult + i); + L->top = res + nres; + return 0; /* wanted == LUA_MULTRET */ + } + default: { + int i; + if (wanted <= nres) { /* enough results? */ + for (i = 0; i < wanted; i++) /* move wanted results to correct place */ + setobjs2s(L, res + i, firstResult + i); + } + else { /* not enough results; use all of them plus nils */ + for (i = 0; i < nres; i++) /* move all results to correct place */ + setobjs2s(L, res + i, firstResult + i); + for (; i < wanted; i++) /* complete wanted number of results */ + setnilvalue(res + i); + } + break; + } + } + L->top = res + wanted; /* top points after the last result */ + return 1; +} + + +/* +** Finishes a function call: calls hook if necessary, removes CallInfo, +** moves current number of results to proper place; returns 0 iff call +** wanted multiple (variable number of) results. +*/ +int luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, int nres) { + StkId res; + int wanted = ci->nresults; + if (L->hookmask & (LUA_MASKRET | LUA_MASKLINE)) { + if (L->hookmask & LUA_MASKRET) { + ptrdiff_t fr = savestack(L, firstResult); /* hook may change stack */ + luaD_hook(L, LUA_HOOKRET, -1); + firstResult = restorestack(L, fr); + } + L->oldpc = ci->previous->u.l.savedpc; /* 'oldpc' for caller function */ + } + res = ci->func; /* res == final position of 1st result */ + L->ci = ci->previous; /* back to caller */ + /* move results to proper place */ + return moveresults(L, firstResult, res, nres, wanted); +} + + + +#define next_ci(L) (L->ci = (L->ci->next ? L->ci->next : luaE_extendCI(L))) + + +/* macro to check stack size, preserving 'p' */ +#define checkstackp(L,n,p) \ + luaD_checkstackaux(L, n, \ + ptrdiff_t t__ = savestack(L, p); /* save 'p' */ \ + luaC_checkGC(L), /* stack grow uses memory */ \ + p = restorestack(L, t__)) /* 'pos' part: restore 'p' */ + + +/* +** Prepares a function call: checks the stack, creates a new CallInfo +** entry, fills in the relevant information, calls hook if needed. +** If function is a C function, does the call, too. (Otherwise, leave +** the execution ('luaV_execute') to the caller, to allow stackless +** calls.) Returns true iff function has been executed (C function). +*/ +int luaD_precall (lua_State *L, StkId func, int nresults) { + lua_CFunction f; + CallInfo *ci; + switch (ttype(func)) { + case LUA_TCCL: /* C closure */ + f = clCvalue(func)->f; + goto Cfunc; + case LUA_TLCF: /* light C function */ + f = fvalue(func); + Cfunc: { + int n; /* number of returns */ + checkstackp(L, LUA_MINSTACK, func); /* ensure minimum stack size */ + ci = next_ci(L); /* now 'enter' new function */ + ci->nresults = nresults; + ci->func = func; + ci->top = L->top + LUA_MINSTACK; + lua_assert(ci->top <= L->stack_last); + ci->callstatus = 0; + if (L->hookmask & LUA_MASKCALL) + luaD_hook(L, LUA_HOOKCALL, -1); + lua_unlock(L); + n = (*f)(L); /* do the actual call */ + lua_lock(L); + api_checknelems(L, n); + luaD_poscall(L, ci, L->top - n, n); + return 1; + } + case LUA_TLCL: { /* Lua function: prepare its call */ + StkId base; + Proto *p = clLvalue(func)->p; + int n = cast_int(L->top - func) - 1; /* number of real arguments */ + int fsize = p->maxstacksize; /* frame size */ + checkstackp(L, fsize, func); + if (p->is_vararg) + base = adjust_varargs(L, p, n); + else { /* non vararg function */ + for (; n < p->numparams; n++) + setnilvalue(L->top++); /* complete missing arguments */ + base = func + 1; + } + ci = next_ci(L); /* now 'enter' new function */ + ci->nresults = nresults; + ci->func = func; + ci->u.l.base = base; + L->top = ci->top = base + fsize; + lua_assert(ci->top <= L->stack_last); + ci->u.l.savedpc = p->code; /* starting point */ + ci->callstatus = CIST_LUA; + if (L->hookmask & LUA_MASKCALL) + callhook(L, ci); + return 0; + } + default: { /* not a function */ + checkstackp(L, 1, func); /* ensure space for metamethod */ + tryfuncTM(L, func); /* try to get '__call' metamethod */ + return luaD_precall(L, func, nresults); /* now it must be a function */ + } + } +} + + +/* +** Check appropriate error for stack overflow ("regular" overflow or +** overflow while handling stack overflow). If 'nCalls' is larger than +** LUAI_MAXCCALLS (which means it is handling a "regular" overflow) but +** smaller than 9/8 of LUAI_MAXCCALLS, does not report an error (to +** allow overflow handling to work) +*/ +static void stackerror (lua_State *L) { + if (L->nCcalls == LUAI_MAXCCALLS) + luaG_runerror(L, "C stack overflow"); + else if (L->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3))) + luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ +} + + +/* +** Call a function (C or Lua). The function to be called is at *func. +** The arguments are on the stack, right after the function. +** When returns, all the results are on the stack, starting at the original +** function position. +*/ +void luaD_call (lua_State *L, StkId func, int nResults) { + if (++L->nCcalls >= LUAI_MAXCCALLS) + stackerror(L); + if (!luaD_precall(L, func, nResults)) /* is a Lua function? */ + luaV_execute(L); /* call it */ + L->nCcalls--; +} + + +/* +** Similar to 'luaD_call', but does not allow yields during the call +*/ +void luaD_callnoyield (lua_State *L, StkId func, int nResults) { + L->nny++; + luaD_call(L, func, nResults); + L->nny--; +} + + +/* +** Completes the execution of an interrupted C function, calling its +** continuation function. +*/ +static void finishCcall (lua_State *L, int status) { + CallInfo *ci = L->ci; + int n; + /* must have a continuation and must be able to call it */ + lua_assert(ci->u.c.k != NULL && L->nny == 0); + /* error status can only happen in a protected call */ + lua_assert((ci->callstatus & CIST_YPCALL) || status == LUA_YIELD); + if (ci->callstatus & CIST_YPCALL) { /* was inside a pcall? */ + ci->callstatus &= ~CIST_YPCALL; /* continuation is also inside it */ + L->errfunc = ci->u.c.old_errfunc; /* with the same error function */ + } + /* finish 'lua_callk'/'lua_pcall'; CIST_YPCALL and 'errfunc' already + handled */ + adjustresults(L, ci->nresults); + lua_unlock(L); + n = (*ci->u.c.k)(L, status, ci->u.c.ctx); /* call continuation function */ + lua_lock(L); + api_checknelems(L, n); + luaD_poscall(L, ci, L->top - n, n); /* finish 'luaD_precall' */ +} + + +/* +** Executes "full continuation" (everything in the stack) of a +** previously interrupted coroutine until the stack is empty (or another +** interruption long-jumps out of the loop). If the coroutine is +** recovering from an error, 'ud' points to the error status, which must +** be passed to the first continuation function (otherwise the default +** status is LUA_YIELD). +*/ +static void unroll (lua_State *L, void *ud) { + if (ud != NULL) /* error status? */ + finishCcall(L, *(int *)ud); /* finish 'lua_pcallk' callee */ + while (L->ci != &L->base_ci) { /* something in the stack */ + if (!isLua(L->ci)) /* C function? */ + finishCcall(L, LUA_YIELD); /* complete its execution */ + else { /* Lua function */ + luaV_finishOp(L); /* finish interrupted instruction */ + luaV_execute(L); /* execute down to higher C 'boundary' */ + } + } +} + + +/* +** Try to find a suspended protected call (a "recover point") for the +** given thread. +*/ +static CallInfo *findpcall (lua_State *L) { + CallInfo *ci; + for (ci = L->ci; ci != NULL; ci = ci->previous) { /* search for a pcall */ + if (ci->callstatus & CIST_YPCALL) + return ci; + } + return NULL; /* no pending pcall */ +} + + +/* +** Recovers from an error in a coroutine. Finds a recover point (if +** there is one) and completes the execution of the interrupted +** 'luaD_pcall'. If there is no recover point, returns zero. +*/ +static int recover (lua_State *L, int status) { + StkId oldtop; + CallInfo *ci = findpcall(L); + if (ci == NULL) return 0; /* no recovery point */ + /* "finish" luaD_pcall */ + oldtop = restorestack(L, ci->extra); + luaF_close(L, oldtop); + seterrorobj(L, status, oldtop); + L->ci = ci; + L->allowhook = getoah(ci->callstatus); /* restore original 'allowhook' */ + L->nny = 0; /* should be zero to be yieldable */ + luaD_shrinkstack(L); + L->errfunc = ci->u.c.old_errfunc; + return 1; /* continue running the coroutine */ +} + + +/* +** Signal an error in the call to 'lua_resume', not in the execution +** of the coroutine itself. (Such errors should not be handled by any +** coroutine error handler and should not kill the coroutine.) +*/ +static int resume_error (lua_State *L, const char *msg, int narg) { + L->top -= narg; /* remove args from the stack */ + setsvalue2s(L, L->top, luaS_new(L, msg)); /* push error message */ + api_incr_top(L); + lua_unlock(L); + return LUA_ERRRUN; +} + + +/* +** Do the work for 'lua_resume' in protected mode. Most of the work +** depends on the status of the coroutine: initial state, suspended +** inside a hook, or regularly suspended (optionally with a continuation +** function), plus erroneous cases: non-suspended coroutine or dead +** coroutine. +*/ +static void resume (lua_State *L, void *ud) { + int n = *(cast(int*, ud)); /* number of arguments */ + StkId firstArg = L->top - n; /* first argument */ + CallInfo *ci = L->ci; + if (L->status == LUA_OK) { /* starting a coroutine? */ + if (!luaD_precall(L, firstArg - 1, LUA_MULTRET)) /* Lua function? */ + luaV_execute(L); /* call it */ + } + else { /* resuming from previous yield */ + lua_assert(L->status == LUA_YIELD); + L->status = LUA_OK; /* mark that it is running (again) */ + ci->func = restorestack(L, ci->extra); + if (isLua(ci)) /* yielded inside a hook? */ + luaV_execute(L); /* just continue running Lua code */ + else { /* 'common' yield */ + if (ci->u.c.k != NULL) { /* does it have a continuation function? */ + lua_unlock(L); + n = (*ci->u.c.k)(L, LUA_YIELD, ci->u.c.ctx); /* call continuation */ + lua_lock(L); + api_checknelems(L, n); + firstArg = L->top - n; /* yield results come from continuation */ + } + luaD_poscall(L, ci, firstArg, n); /* finish 'luaD_precall' */ + } + unroll(L, NULL); /* run continuation */ + } +} + + +LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs) { + int status; + unsigned short oldnny = L->nny; /* save "number of non-yieldable" calls */ + lua_lock(L); + if (L->status == LUA_OK) { /* may be starting a coroutine */ + if (L->ci != &L->base_ci) /* not in base level? */ + return resume_error(L, "cannot resume non-suspended coroutine", nargs); + } + else if (L->status != LUA_YIELD) + return resume_error(L, "cannot resume dead coroutine", nargs); + L->nCcalls = (from) ? from->nCcalls + 1 : 1; + if (L->nCcalls >= LUAI_MAXCCALLS) + return resume_error(L, "C stack overflow", nargs); + luai_userstateresume(L, nargs); + L->nny = 0; /* allow yields */ + api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs); + status = luaD_rawrunprotected(L, resume, &nargs); + if (status == -1) /* error calling 'lua_resume'? */ + status = LUA_ERRRUN; + else { /* continue running after recoverable errors */ + while (errorstatus(status) && recover(L, status)) { + /* unroll continuation */ + status = luaD_rawrunprotected(L, unroll, &status); + } + if (errorstatus(status)) { /* unrecoverable error? */ + L->status = cast_byte(status); /* mark thread as 'dead' */ + seterrorobj(L, status, L->top); /* push error message */ + L->ci->top = L->top; + } + else lua_assert(status == L->status); /* normal end or yield */ + } + L->nny = oldnny; /* restore 'nny' */ + L->nCcalls--; + lua_assert(L->nCcalls == ((from) ? from->nCcalls : 0)); + lua_unlock(L); + return status; +} + + +LUA_API int lua_isyieldable (lua_State *L) { + return (L->nny == 0); +} + + +LUA_API int lua_yieldk (lua_State *L, int nresults, lua_KContext ctx, + lua_KFunction k) { + CallInfo *ci = L->ci; + luai_userstateyield(L, nresults); + lua_lock(L); + api_checknelems(L, nresults); + if (L->nny > 0) { + if (L != G(L)->mainthread) + luaG_runerror(L, "attempt to yield across a C-call boundary"); + else + luaG_runerror(L, "attempt to yield from outside a coroutine"); + } + L->status = LUA_YIELD; + ci->extra = savestack(L, ci->func); /* save current 'func' */ + if (isLua(ci)) { /* inside a hook? */ + api_check(L, k == NULL, "hooks cannot continue after yielding"); + } + else { + if ((ci->u.c.k = k) != NULL) /* is there a continuation? */ + ci->u.c.ctx = ctx; /* save context */ + ci->func = L->top - nresults - 1; /* protect stack below results */ + luaD_throw(L, LUA_YIELD); + } + lua_assert(ci->callstatus & CIST_HOOKED); /* must be inside a hook */ + lua_unlock(L); + return 0; /* return to 'luaD_hook' */ +} + + +int luaD_pcall (lua_State *L, Pfunc func, void *u, + ptrdiff_t old_top, ptrdiff_t ef) { + int status; + CallInfo *old_ci = L->ci; + lu_byte old_allowhooks = L->allowhook; + unsigned short old_nny = L->nny; + ptrdiff_t old_errfunc = L->errfunc; + L->errfunc = ef; + status = luaD_rawrunprotected(L, func, u); + if (status != LUA_OK) { /* an error occurred? */ + StkId oldtop = restorestack(L, old_top); + luaF_close(L, oldtop); /* close possible pending closures */ + seterrorobj(L, status, oldtop); + L->ci = old_ci; + L->allowhook = old_allowhooks; + L->nny = old_nny; + luaD_shrinkstack(L); + } + L->errfunc = old_errfunc; + return status; +} + + + +/* +** Execute a protected parser. +*/ +struct SParser { /* data to 'f_parser' */ + ZIO *z; + Mbuffer buff; /* dynamic structure used by the scanner */ + Dyndata dyd; /* dynamic structures used by the parser */ + const char *mode; + const char *name; +}; + + +static void checkmode (lua_State *L, const char *mode, const char *x) { + if (mode && strchr(mode, x[0]) == NULL) { + luaO_pushfstring(L, + "attempt to load a %s chunk (mode is '%s')", x, mode); + luaD_throw(L, LUA_ERRSYNTAX); + } +} + + +static void f_parser (lua_State *L, void *ud) { + LClosure *cl; + struct SParser *p = cast(struct SParser *, ud); + int c = zgetc(p->z); /* read first character */ + // if (c == LUA_SIGNATURE[0]) { + // checkmode(L, p->mode, "binary"); + // cl = luaU_undump(L, p->z, p->name); + // } + // else { + checkmode(L, p->mode, "text"); + cl = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c); + // } + lua_assert(cl->nupvalues == cl->p->sizeupvalues); + luaF_initupvals(L, cl); +} + + +int luaD_protectedparser (lua_State *L, ZIO *z, const char *name, + const char *mode) { + struct SParser p; + int status; + L->nny++; /* cannot yield during parsing */ + p.z = z; p.name = name; p.mode = mode; + p.dyd.actvar.arr = NULL; p.dyd.actvar.size = 0; + p.dyd.gt.arr = NULL; p.dyd.gt.size = 0; + p.dyd.label.arr = NULL; p.dyd.label.size = 0; + luaZ_initbuffer(L, &p.buff); + status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), L->errfunc); + luaZ_freebuffer(L, &p.buff); + luaM_freearray(L, p.dyd.actvar.arr, p.dyd.actvar.size); + luaM_freearray(L, p.dyd.gt.arr, p.dyd.gt.size); + luaM_freearray(L, p.dyd.label.arr, p.dyd.label.size); + L->nny--; + return status; +} + + diff --git a/depends/lua/src/ldump.c b/depends/lua/src/ldump.c new file mode 100644 index 0000000000..f025acac3c --- /dev/null +++ b/depends/lua/src/ldump.c @@ -0,0 +1,215 @@ +/* +** $Id: ldump.c,v 2.37.1.1 2017/04/19 17:20:42 roberto Exp $ +** save precompiled Lua chunks +** See Copyright Notice in lua.h +*/ + +#define ldump_c +#define LUA_CORE + +#include "lprefix.h" + + +#include + +#include "lua.h" + +#include "lobject.h" +#include "lstate.h" +#include "lundump.h" + + +typedef struct { + lua_State *L; + lua_Writer writer; + void *data; + int strip; + int status; +} DumpState; + + +/* +** All high-level dumps go through DumpVector; you can change it to +** change the endianness of the result +*/ +#define DumpVector(v,n,D) DumpBlock(v,(n)*sizeof((v)[0]),D) + +#define DumpLiteral(s,D) DumpBlock(s, sizeof(s) - sizeof(char), D) + + +static void DumpBlock (const void *b, size_t size, DumpState *D) { + if (D->status == 0 && size > 0) { + lua_unlock(D->L); + D->status = (*D->writer)(D->L, b, size, D->data); + lua_lock(D->L); + } +} + + +#define DumpVar(x,D) DumpVector(&x,1,D) + + +static void DumpByte (int y, DumpState *D) { + lu_byte x = (lu_byte)y; + DumpVar(x, D); +} + + +static void DumpInt (int x, DumpState *D) { + DumpVar(x, D); +} + + +static void DumpNumber (lua_Number x, DumpState *D) { + DumpVar(x, D); +} + + +static void DumpInteger (lua_Integer x, DumpState *D) { + DumpVar(x, D); +} + + +static void DumpString (const TString *s, DumpState *D) { + if (s == NULL) + DumpByte(0, D); + else { + size_t size = tsslen(s) + 1; /* include trailing '\0' */ + const char *str = getstr(s); + if (size < 0xFF) + DumpByte(cast_int(size), D); + else { + DumpByte(0xFF, D); + DumpVar(size, D); + } + DumpVector(str, size - 1, D); /* no need to save '\0' */ + } +} + + +static void DumpCode (const Proto *f, DumpState *D) { + DumpInt(f->sizecode, D); + DumpVector(f->code, f->sizecode, D); +} + + +static void DumpFunction(const Proto *f, TString *psource, DumpState *D); + +static void DumpConstants (const Proto *f, DumpState *D) { + int i; + int n = f->sizek; + DumpInt(n, D); + for (i = 0; i < n; i++) { + const TValue *o = &f->k[i]; + DumpByte(ttype(o), D); + switch (ttype(o)) { + case LUA_TNIL: + break; + case LUA_TBOOLEAN: + DumpByte(bvalue(o), D); + break; + case LUA_TNUMFLT: + DumpNumber(fltvalue(o), D); + break; + case LUA_TNUMINT: + DumpInteger(ivalue(o), D); + break; + case LUA_TSHRSTR: + case LUA_TLNGSTR: + DumpString(tsvalue(o), D); + break; + default: + lua_assert(0); + } + } +} + + +static void DumpProtos (const Proto *f, DumpState *D) { + int i; + int n = f->sizep; + DumpInt(n, D); + for (i = 0; i < n; i++) + DumpFunction(f->p[i], f->source, D); +} + + +static void DumpUpvalues (const Proto *f, DumpState *D) { + int i, n = f->sizeupvalues; + DumpInt(n, D); + for (i = 0; i < n; i++) { + DumpByte(f->upvalues[i].instack, D); + DumpByte(f->upvalues[i].idx, D); + } +} + + +static void DumpDebug (const Proto *f, DumpState *D) { + int i, n; + n = (D->strip) ? 0 : f->sizelineinfo; + DumpInt(n, D); + DumpVector(f->lineinfo, n, D); + n = (D->strip) ? 0 : f->sizelocvars; + DumpInt(n, D); + for (i = 0; i < n; i++) { + DumpString(f->locvars[i].varname, D); + DumpInt(f->locvars[i].startpc, D); + DumpInt(f->locvars[i].endpc, D); + } + n = (D->strip) ? 0 : f->sizeupvalues; + DumpInt(n, D); + for (i = 0; i < n; i++) + DumpString(f->upvalues[i].name, D); +} + + +static void DumpFunction (const Proto *f, TString *psource, DumpState *D) { + if (D->strip || f->source == psource) + DumpString(NULL, D); /* no debug info or same source as its parent */ + else + DumpString(f->source, D); + DumpInt(f->linedefined, D); + DumpInt(f->lastlinedefined, D); + DumpByte(f->numparams, D); + DumpByte(f->is_vararg, D); + DumpByte(f->maxstacksize, D); + DumpCode(f, D); + DumpConstants(f, D); + DumpUpvalues(f, D); + DumpProtos(f, D); + DumpDebug(f, D); +} + + +static void DumpHeader (DumpState *D) { + DumpLiteral(LUA_SIGNATURE, D); + DumpByte(LUAC_VERSION, D); + DumpByte(LUAC_FORMAT, D); + DumpLiteral(LUAC_DATA, D); + DumpByte(sizeof(int), D); + DumpByte(sizeof(size_t), D); + DumpByte(sizeof(Instruction), D); + DumpByte(sizeof(lua_Integer), D); + DumpByte(sizeof(lua_Number), D); + DumpInteger(LUAC_INT, D); + DumpNumber(LUAC_NUM, D); +} + + +/* +** dump Lua function as precompiled chunk +*/ +int luaU_dump(lua_State *L, const Proto *f, lua_Writer w, void *data, + int strip) { + DumpState D; + D.L = L; + D.writer = w; + D.data = data; + D.strip = strip; + D.status = 0; + DumpHeader(&D); + DumpByte(f->sizeupvalues, &D); + DumpFunction(f, NULL, &D); + return D.status; +} + diff --git a/depends/lua/src/lfunc.c b/depends/lua/src/lfunc.c new file mode 100644 index 0000000000..ccafbb8ab3 --- /dev/null +++ b/depends/lua/src/lfunc.c @@ -0,0 +1,151 @@ +/* +** $Id: lfunc.c,v 2.45.1.1 2017/04/19 17:39:34 roberto Exp $ +** Auxiliary functions to manipulate prototypes and closures +** See Copyright Notice in lua.h +*/ + +#define lfunc_c +#define LUA_CORE + +#include "lprefix.h" + + +#include + +#include "lua.h" + +#include "lfunc.h" +#include "lgc.h" +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" + + + +CClosure *luaF_newCclosure (lua_State *L, int n) { + GCObject *o = luaC_newobj(L, LUA_TCCL, sizeCclosure(n)); + CClosure *c = gco2ccl(o); + c->nupvalues = cast_byte(n); + return c; +} + + +LClosure *luaF_newLclosure (lua_State *L, int n) { + GCObject *o = luaC_newobj(L, LUA_TLCL, sizeLclosure(n)); + LClosure *c = gco2lcl(o); + c->p = NULL; + c->nupvalues = cast_byte(n); + while (n--) c->upvals[n] = NULL; + return c; +} + +/* +** fill a closure with new closed upvalues +*/ +void luaF_initupvals (lua_State *L, LClosure *cl) { + int i; + for (i = 0; i < cl->nupvalues; i++) { + UpVal *uv = luaM_new(L, UpVal); + uv->refcount = 1; + uv->v = &uv->u.value; /* make it closed */ + setnilvalue(uv->v); + cl->upvals[i] = uv; + } +} + + +UpVal *luaF_findupval (lua_State *L, StkId level) { + UpVal **pp = &L->openupval; + UpVal *p; + UpVal *uv; + lua_assert(isintwups(L) || L->openupval == NULL); + while (*pp != NULL && (p = *pp)->v >= level) { + lua_assert(upisopen(p)); + if (p->v == level) /* found a corresponding upvalue? */ + return p; /* return it */ + pp = &p->u.open.next; + } + /* not found: create a new upvalue */ + uv = luaM_new(L, UpVal); + uv->refcount = 0; + uv->u.open.next = *pp; /* link it to list of open upvalues */ + uv->u.open.touched = 1; + *pp = uv; + uv->v = level; /* current value lives in the stack */ + if (!isintwups(L)) { /* thread not in list of threads with upvalues? */ + L->twups = G(L)->twups; /* link it to the list */ + G(L)->twups = L; + } + return uv; +} + + +void luaF_close (lua_State *L, StkId level) { + UpVal *uv; + while (L->openupval != NULL && (uv = L->openupval)->v >= level) { + lua_assert(upisopen(uv)); + L->openupval = uv->u.open.next; /* remove from 'open' list */ + if (uv->refcount == 0) /* no references? */ + luaM_free(L, uv); /* free upvalue */ + else { + setobj(L, &uv->u.value, uv->v); /* move value to upvalue slot */ + uv->v = &uv->u.value; /* now current value lives here */ + luaC_upvalbarrier(L, uv); + } + } +} + + +Proto *luaF_newproto (lua_State *L) { + GCObject *o = luaC_newobj(L, LUA_TPROTO, sizeof(Proto)); + Proto *f = gco2p(o); + f->k = NULL; + f->sizek = 0; + f->p = NULL; + f->sizep = 0; + f->code = NULL; + f->cache = NULL; + f->sizecode = 0; + f->lineinfo = NULL; + f->sizelineinfo = 0; + f->upvalues = NULL; + f->sizeupvalues = 0; + f->numparams = 0; + f->is_vararg = 0; + f->maxstacksize = 0; + f->locvars = NULL; + f->sizelocvars = 0; + f->linedefined = 0; + f->lastlinedefined = 0; + f->source = NULL; + return f; +} + + +void luaF_freeproto (lua_State *L, Proto *f) { + luaM_freearray(L, f->code, f->sizecode); + luaM_freearray(L, f->p, f->sizep); + luaM_freearray(L, f->k, f->sizek); + luaM_freearray(L, f->lineinfo, f->sizelineinfo); + luaM_freearray(L, f->locvars, f->sizelocvars); + luaM_freearray(L, f->upvalues, f->sizeupvalues); + luaM_free(L, f); +} + + +/* +** Look for n-th local variable at line 'line' in function 'func'. +** Returns NULL if not found. +*/ +const char *luaF_getlocalname (const Proto *f, int local_number, int pc) { + int i; + for (i = 0; isizelocvars && f->locvars[i].startpc <= pc; i++) { + if (pc < f->locvars[i].endpc) { /* is variable active? */ + local_number--; + if (local_number == 0) + return getstr(f->locvars[i].varname); + } + } + return NULL; /* not found */ +} + diff --git a/depends/lua/src/lgc.c b/depends/lua/src/lgc.c new file mode 100644 index 0000000000..db4df82922 --- /dev/null +++ b/depends/lua/src/lgc.c @@ -0,0 +1,1179 @@ +/* +** $Id: lgc.c,v 2.215.1.2 2017/08/31 16:15:27 roberto Exp $ +** Garbage Collector +** See Copyright Notice in lua.h +*/ + +#define lgc_c +#define LUA_CORE + +#include "lprefix.h" + + +#include + +#include "lua.h" + +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "lgc.h" +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" + + +/* +** internal state for collector while inside the atomic phase. The +** collector should never be in this state while running regular code. +*/ +#define GCSinsideatomic (GCSpause + 1) + +/* +** cost of sweeping one element (the size of a small object divided +** by some adjust for the sweep speed) +*/ +#define GCSWEEPCOST ((sizeof(TString) + 4) / 4) + +/* maximum number of elements to sweep in each single step */ +#define GCSWEEPMAX (cast_int((GCSTEPSIZE / GCSWEEPCOST) / 4)) + +/* cost of calling one finalizer */ +#define GCFINALIZECOST GCSWEEPCOST + + +/* +** macro to adjust 'stepmul': 'stepmul' is actually used like +** 'stepmul / STEPMULADJ' (value chosen by tests) +*/ +#define STEPMULADJ 200 + + +/* +** macro to adjust 'pause': 'pause' is actually used like +** 'pause / PAUSEADJ' (value chosen by tests) +*/ +#define PAUSEADJ 100 + + +/* +** 'makewhite' erases all color bits then sets only the current white +** bit +*/ +#define maskcolors (~(bitmask(BLACKBIT) | WHITEBITS)) +#define makewhite(g,x) \ + (x->marked = cast_byte((x->marked & maskcolors) | luaC_white(g))) + +#define white2gray(x) resetbits(x->marked, WHITEBITS) +#define black2gray(x) resetbit(x->marked, BLACKBIT) + + +#define valiswhite(x) (iscollectable(x) && iswhite(gcvalue(x))) + +#define checkdeadkey(n) lua_assert(!ttisdeadkey(gkey(n)) || ttisnil(gval(n))) + + +#define checkconsistency(obj) \ + lua_longassert(!iscollectable(obj) || righttt(obj)) + + +#define markvalue(g,o) { checkconsistency(o); \ + if (valiswhite(o)) reallymarkobject(g,gcvalue(o)); } + +#define markobject(g,t) { if (iswhite(t)) reallymarkobject(g, obj2gco(t)); } + +/* +** mark an object that can be NULL (either because it is really optional, +** or it was stripped as debug info, or inside an uncompleted structure) +*/ +#define markobjectN(g,t) { if (t) markobject(g,t); } + +static void reallymarkobject (global_State *g, GCObject *o); + + +/* +** {====================================================== +** Generic functions +** ======================================================= +*/ + + +/* +** one after last element in a hash array +*/ +#define gnodelast(h) gnode(h, cast(size_t, sizenode(h))) + + +/* +** link collectable object 'o' into list pointed by 'p' +*/ +#define linkgclist(o,p) ((o)->gclist = (p), (p) = obj2gco(o)) + + +/* +** If key is not marked, mark its entry as dead. This allows key to be +** collected, but keeps its entry in the table. A dead node is needed +** when Lua looks up for a key (it may be part of a chain) and when +** traversing a weak table (key might be removed from the table during +** traversal). Other places never manipulate dead keys, because its +** associated nil value is enough to signal that the entry is logically +** empty. +*/ +static void removeentry (Node *n) { + lua_assert(ttisnil(gval(n))); + if (valiswhite(gkey(n))) + setdeadvalue(wgkey(n)); /* unused and unmarked key; remove it */ +} + + +/* +** tells whether a key or value can be cleared from a weak +** table. Non-collectable objects are never removed from weak +** tables. Strings behave as 'values', so are never removed too. for +** other objects: if really collected, cannot keep them; for objects +** being finalized, keep them in keys, but not in values +*/ +static int iscleared (global_State *g, const TValue *o) { + if (!iscollectable(o)) return 0; + else if (ttisstring(o)) { + markobject(g, tsvalue(o)); /* strings are 'values', so are never weak */ + return 0; + } + else return iswhite(gcvalue(o)); +} + + +/* +** barrier that moves collector forward, that is, mark the white object +** being pointed by a black object. (If in sweep phase, clear the black +** object to white [sweep it] to avoid other barrier calls for this +** same object.) +*/ +void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) { + global_State *g = G(L); + lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); + if (keepinvariant(g)) /* must keep invariant? */ + reallymarkobject(g, v); /* restore invariant */ + else { /* sweep phase */ + lua_assert(issweepphase(g)); + makewhite(g, o); /* mark main obj. as white to avoid other barriers */ + } +} + + +/* +** barrier that moves collector backward, that is, mark the black object +** pointing to a white object as gray again. +*/ +void luaC_barrierback_ (lua_State *L, Table *t) { + global_State *g = G(L); + lua_assert(isblack(t) && !isdead(g, t)); + black2gray(t); /* make table gray (again) */ + linkgclist(t, g->grayagain); +} + + +/* +** barrier for assignments to closed upvalues. Because upvalues are +** shared among closures, it is impossible to know the color of all +** closures pointing to it. So, we assume that the object being assigned +** must be marked. +*/ +void luaC_upvalbarrier_ (lua_State *L, UpVal *uv) { + global_State *g = G(L); + GCObject *o = gcvalue(uv->v); + lua_assert(!upisopen(uv)); /* ensured by macro luaC_upvalbarrier */ + if (keepinvariant(g)) + markobject(g, o); +} + + +void luaC_fix (lua_State *L, GCObject *o) { + global_State *g = G(L); + lua_assert(g->allgc == o); /* object must be 1st in 'allgc' list! */ + white2gray(o); /* they will be gray forever */ + g->allgc = o->next; /* remove object from 'allgc' list */ + o->next = g->fixedgc; /* link it to 'fixedgc' list */ + g->fixedgc = o; +} + + +/* +** create a new collectable object (with given type and size) and link +** it to 'allgc' list. +*/ +GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) { + global_State *g = G(L); + GCObject *o = cast(GCObject *, luaM_newobject(L, novariant(tt), sz)); + o->marked = luaC_white(g); + o->tt = tt; + o->next = g->allgc; + g->allgc = o; + return o; +} + +/* }====================================================== */ + + + +/* +** {====================================================== +** Mark functions +** ======================================================= +*/ + + +/* +** mark an object. Userdata, strings, and closed upvalues are visited +** and turned black here. Other objects are marked gray and added +** to appropriate list to be visited (and turned black) later. (Open +** upvalues are already linked in 'headuv' list.) +*/ +static void reallymarkobject (global_State *g, GCObject *o) { + reentry: + white2gray(o); + switch (o->tt) { + case LUA_TSHRSTR: { + gray2black(o); + g->GCmemtrav += sizelstring(gco2ts(o)->shrlen); + break; + } + case LUA_TLNGSTR: { + gray2black(o); + g->GCmemtrav += sizelstring(gco2ts(o)->u.lnglen); + break; + } + case LUA_TUSERDATA: { + TValue uvalue; + markobjectN(g, gco2u(o)->metatable); /* mark its metatable */ + gray2black(o); + g->GCmemtrav += sizeudata(gco2u(o)); + getuservalue(g->mainthread, gco2u(o), &uvalue); + if (valiswhite(&uvalue)) { /* markvalue(g, &uvalue); */ + o = gcvalue(&uvalue); + goto reentry; + } + break; + } + case LUA_TLCL: { + linkgclist(gco2lcl(o), g->gray); + break; + } + case LUA_TCCL: { + linkgclist(gco2ccl(o), g->gray); + break; + } + case LUA_TTABLE: { + linkgclist(gco2t(o), g->gray); + break; + } + case LUA_TTHREAD: { + linkgclist(gco2th(o), g->gray); + break; + } + case LUA_TPROTO: { + linkgclist(gco2p(o), g->gray); + break; + } + default: lua_assert(0); break; + } +} + + +/* +** mark metamethods for basic types +*/ +static void markmt (global_State *g) { + int i; + for (i=0; i < LUA_NUMTAGS; i++) + markobjectN(g, g->mt[i]); +} + + +/* +** mark all objects in list of being-finalized +*/ +static void markbeingfnz (global_State *g) { + GCObject *o; + for (o = g->tobefnz; o != NULL; o = o->next) + markobject(g, o); +} + + +/* +** Mark all values stored in marked open upvalues from non-marked threads. +** (Values from marked threads were already marked when traversing the +** thread.) Remove from the list threads that no longer have upvalues and +** not-marked threads. +*/ +static void remarkupvals (global_State *g) { + lua_State *thread; + lua_State **p = &g->twups; + while ((thread = *p) != NULL) { + lua_assert(!isblack(thread)); /* threads are never black */ + if (isgray(thread) && thread->openupval != NULL) + p = &thread->twups; /* keep marked thread with upvalues in the list */ + else { /* thread is not marked or without upvalues */ + UpVal *uv; + *p = thread->twups; /* remove thread from the list */ + thread->twups = thread; /* mark that it is out of list */ + for (uv = thread->openupval; uv != NULL; uv = uv->u.open.next) { + if (uv->u.open.touched) { + markvalue(g, uv->v); /* remark upvalue's value */ + uv->u.open.touched = 0; + } + } + } + } +} + + +/* +** mark root set and reset all gray lists, to start a new collection +*/ +static void restartcollection (global_State *g) { + g->gray = g->grayagain = NULL; + g->weak = g->allweak = g->ephemeron = NULL; + markobject(g, g->mainthread); + markvalue(g, &g->l_registry); + markmt(g); + markbeingfnz(g); /* mark any finalizing object left from previous cycle */ +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Traverse functions +** ======================================================= +*/ + +/* +** Traverse a table with weak values and link it to proper list. During +** propagate phase, keep it in 'grayagain' list, to be revisited in the +** atomic phase. In the atomic phase, if table has any white value, +** put it in 'weak' list, to be cleared. +*/ +static void traverseweakvalue (global_State *g, Table *h) { + Node *n, *limit = gnodelast(h); + /* if there is array part, assume it may have white values (it is not + worth traversing it now just to check) */ + int hasclears = (h->sizearray > 0); + for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */ + checkdeadkey(n); + if (ttisnil(gval(n))) /* entry is empty? */ + removeentry(n); /* remove it */ + else { + lua_assert(!ttisnil(gkey(n))); + markvalue(g, gkey(n)); /* mark key */ + if (!hasclears && iscleared(g, gval(n))) /* is there a white value? */ + hasclears = 1; /* table will have to be cleared */ + } + } + if (g->gcstate == GCSpropagate) + linkgclist(h, g->grayagain); /* must retraverse it in atomic phase */ + else if (hasclears) + linkgclist(h, g->weak); /* has to be cleared later */ +} + + +/* +** Traverse an ephemeron table and link it to proper list. Returns true +** iff any object was marked during this traversal (which implies that +** convergence has to continue). During propagation phase, keep table +** in 'grayagain' list, to be visited again in the atomic phase. In +** the atomic phase, if table has any white->white entry, it has to +** be revisited during ephemeron convergence (as that key may turn +** black). Otherwise, if it has any white key, table has to be cleared +** (in the atomic phase). +*/ +static int traverseephemeron (global_State *g, Table *h) { + int marked = 0; /* true if an object is marked in this traversal */ + int hasclears = 0; /* true if table has white keys */ + int hasww = 0; /* true if table has entry "white-key -> white-value" */ + Node *n, *limit = gnodelast(h); + unsigned int i; + /* traverse array part */ + for (i = 0; i < h->sizearray; i++) { + if (valiswhite(&h->array[i])) { + marked = 1; + reallymarkobject(g, gcvalue(&h->array[i])); + } + } + /* traverse hash part */ + for (n = gnode(h, 0); n < limit; n++) { + checkdeadkey(n); + if (ttisnil(gval(n))) /* entry is empty? */ + removeentry(n); /* remove it */ + else if (iscleared(g, gkey(n))) { /* key is not marked (yet)? */ + hasclears = 1; /* table must be cleared */ + if (valiswhite(gval(n))) /* value not marked yet? */ + hasww = 1; /* white-white entry */ + } + else if (valiswhite(gval(n))) { /* value not marked yet? */ + marked = 1; + reallymarkobject(g, gcvalue(gval(n))); /* mark it now */ + } + } + /* link table into proper list */ + if (g->gcstate == GCSpropagate) + linkgclist(h, g->grayagain); /* must retraverse it in atomic phase */ + else if (hasww) /* table has white->white entries? */ + linkgclist(h, g->ephemeron); /* have to propagate again */ + else if (hasclears) /* table has white keys? */ + linkgclist(h, g->allweak); /* may have to clean white keys */ + return marked; +} + + +static void traversestrongtable (global_State *g, Table *h) { + Node *n, *limit = gnodelast(h); + unsigned int i; + for (i = 0; i < h->sizearray; i++) /* traverse array part */ + markvalue(g, &h->array[i]); + for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */ + checkdeadkey(n); + if (ttisnil(gval(n))) /* entry is empty? */ + removeentry(n); /* remove it */ + else { + lua_assert(!ttisnil(gkey(n))); + markvalue(g, gkey(n)); /* mark key */ + markvalue(g, gval(n)); /* mark value */ + } + } +} + + +static lu_mem traversetable (global_State *g, Table *h) { + const char *weakkey, *weakvalue; + const TValue *mode = gfasttm(g, h->metatable, TM_MODE); + markobjectN(g, h->metatable); + if (mode && ttisstring(mode) && /* is there a weak mode? */ + ((weakkey = strchr(svalue(mode), 'k')), + (weakvalue = strchr(svalue(mode), 'v')), + (weakkey || weakvalue))) { /* is really weak? */ + black2gray(h); /* keep table gray */ + if (!weakkey) /* strong keys? */ + traverseweakvalue(g, h); + else if (!weakvalue) /* strong values? */ + traverseephemeron(g, h); + else /* all weak */ + linkgclist(h, g->allweak); /* nothing to traverse now */ + } + else /* not weak */ + traversestrongtable(g, h); + return sizeof(Table) + sizeof(TValue) * h->sizearray + + sizeof(Node) * cast(size_t, allocsizenode(h)); +} + + +/* +** Traverse a prototype. (While a prototype is being build, its +** arrays can be larger than needed; the extra slots are filled with +** NULL, so the use of 'markobjectN') +*/ +static int traverseproto (global_State *g, Proto *f) { + int i; + if (f->cache && iswhite(f->cache)) + f->cache = NULL; /* allow cache to be collected */ + markobjectN(g, f->source); + for (i = 0; i < f->sizek; i++) /* mark literals */ + markvalue(g, &f->k[i]); + for (i = 0; i < f->sizeupvalues; i++) /* mark upvalue names */ + markobjectN(g, f->upvalues[i].name); + for (i = 0; i < f->sizep; i++) /* mark nested protos */ + markobjectN(g, f->p[i]); + for (i = 0; i < f->sizelocvars; i++) /* mark local-variable names */ + markobjectN(g, f->locvars[i].varname); + return sizeof(Proto) + sizeof(Instruction) * f->sizecode + + sizeof(Proto *) * f->sizep + + sizeof(TValue) * f->sizek + + sizeof(int) * f->sizelineinfo + + sizeof(LocVar) * f->sizelocvars + + sizeof(Upvaldesc) * f->sizeupvalues; +} + + +static lu_mem traverseCclosure (global_State *g, CClosure *cl) { + int i; + for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */ + markvalue(g, &cl->upvalue[i]); + return sizeCclosure(cl->nupvalues); +} + +/* +** open upvalues point to values in a thread, so those values should +** be marked when the thread is traversed except in the atomic phase +** (because then the value cannot be changed by the thread and the +** thread may not be traversed again) +*/ +static lu_mem traverseLclosure (global_State *g, LClosure *cl) { + int i; + markobjectN(g, cl->p); /* mark its prototype */ + for (i = 0; i < cl->nupvalues; i++) { /* mark its upvalues */ + UpVal *uv = cl->upvals[i]; + if (uv != NULL) { + if (upisopen(uv) && g->gcstate != GCSinsideatomic) + uv->u.open.touched = 1; /* can be marked in 'remarkupvals' */ + else + markvalue(g, uv->v); + } + } + return sizeLclosure(cl->nupvalues); +} + + +static lu_mem traversethread (global_State *g, lua_State *th) { + StkId o = th->stack; + if (o == NULL) + return 1; /* stack not completely built yet */ + lua_assert(g->gcstate == GCSinsideatomic || + th->openupval == NULL || isintwups(th)); + for (; o < th->top; o++) /* mark live elements in the stack */ + markvalue(g, o); + if (g->gcstate == GCSinsideatomic) { /* final traversal? */ + StkId lim = th->stack + th->stacksize; /* real end of stack */ + for (; o < lim; o++) /* clear not-marked stack slice */ + setnilvalue(o); + /* 'remarkupvals' may have removed thread from 'twups' list */ + if (!isintwups(th) && th->openupval != NULL) { + th->twups = g->twups; /* link it back to the list */ + g->twups = th; + } + } + else if (g->gckind != KGC_EMERGENCY) + luaD_shrinkstack(th); /* do not change stack in emergency cycle */ + return (sizeof(lua_State) + sizeof(TValue) * th->stacksize + + sizeof(CallInfo) * th->nci); +} + + +/* +** traverse one gray object, turning it to black (except for threads, +** which are always gray). +*/ +static void propagatemark (global_State *g) { + lu_mem size; + GCObject *o = g->gray; + lua_assert(isgray(o)); + gray2black(o); + switch (o->tt) { + case LUA_TTABLE: { + Table *h = gco2t(o); + g->gray = h->gclist; /* remove from 'gray' list */ + size = traversetable(g, h); + break; + } + case LUA_TLCL: { + LClosure *cl = gco2lcl(o); + g->gray = cl->gclist; /* remove from 'gray' list */ + size = traverseLclosure(g, cl); + break; + } + case LUA_TCCL: { + CClosure *cl = gco2ccl(o); + g->gray = cl->gclist; /* remove from 'gray' list */ + size = traverseCclosure(g, cl); + break; + } + case LUA_TTHREAD: { + lua_State *th = gco2th(o); + g->gray = th->gclist; /* remove from 'gray' list */ + linkgclist(th, g->grayagain); /* insert into 'grayagain' list */ + black2gray(o); + size = traversethread(g, th); + break; + } + case LUA_TPROTO: { + Proto *p = gco2p(o); + g->gray = p->gclist; /* remove from 'gray' list */ + size = traverseproto(g, p); + break; + } + default: lua_assert(0); return; + } + g->GCmemtrav += size; +} + + +static void propagateall (global_State *g) { + while (g->gray) propagatemark(g); +} + + +static void convergeephemerons (global_State *g) { + int changed; + do { + GCObject *w; + GCObject *next = g->ephemeron; /* get ephemeron list */ + g->ephemeron = NULL; /* tables may return to this list when traversed */ + changed = 0; + while ((w = next) != NULL) { + next = gco2t(w)->gclist; + if (traverseephemeron(g, gco2t(w))) { /* traverse marked some value? */ + propagateall(g); /* propagate changes */ + changed = 1; /* will have to revisit all ephemeron tables */ + } + } + } while (changed); +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Sweep Functions +** ======================================================= +*/ + + +/* +** clear entries with unmarked keys from all weaktables in list 'l' up +** to element 'f' +*/ +static void clearkeys (global_State *g, GCObject *l, GCObject *f) { + for (; l != f; l = gco2t(l)->gclist) { + Table *h = gco2t(l); + Node *n, *limit = gnodelast(h); + for (n = gnode(h, 0); n < limit; n++) { + if (!ttisnil(gval(n)) && (iscleared(g, gkey(n)))) { + setnilvalue(gval(n)); /* remove value ... */ + } + if (ttisnil(gval(n))) /* is entry empty? */ + removeentry(n); /* remove entry from table */ + } + } +} + + +/* +** clear entries with unmarked values from all weaktables in list 'l' up +** to element 'f' +*/ +static void clearvalues (global_State *g, GCObject *l, GCObject *f) { + for (; l != f; l = gco2t(l)->gclist) { + Table *h = gco2t(l); + Node *n, *limit = gnodelast(h); + unsigned int i; + for (i = 0; i < h->sizearray; i++) { + TValue *o = &h->array[i]; + if (iscleared(g, o)) /* value was collected? */ + setnilvalue(o); /* remove value */ + } + for (n = gnode(h, 0); n < limit; n++) { + if (!ttisnil(gval(n)) && iscleared(g, gval(n))) { + setnilvalue(gval(n)); /* remove value ... */ + removeentry(n); /* and remove entry from table */ + } + } + } +} + + +void luaC_upvdeccount (lua_State *L, UpVal *uv) { + lua_assert(uv->refcount > 0); + uv->refcount--; + if (uv->refcount == 0 && !upisopen(uv)) + luaM_free(L, uv); +} + + +static void freeLclosure (lua_State *L, LClosure *cl) { + int i; + for (i = 0; i < cl->nupvalues; i++) { + UpVal *uv = cl->upvals[i]; + if (uv) + luaC_upvdeccount(L, uv); + } + luaM_freemem(L, cl, sizeLclosure(cl->nupvalues)); +} + + +static void freeobj (lua_State *L, GCObject *o) { + switch (o->tt) { + case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break; + case LUA_TLCL: { + freeLclosure(L, gco2lcl(o)); + break; + } + case LUA_TCCL: { + luaM_freemem(L, o, sizeCclosure(gco2ccl(o)->nupvalues)); + break; + } + case LUA_TTABLE: luaH_free(L, gco2t(o)); break; + case LUA_TTHREAD: luaE_freethread(L, gco2th(o)); break; + case LUA_TUSERDATA: luaM_freemem(L, o, sizeudata(gco2u(o))); break; + case LUA_TSHRSTR: + luaS_remove(L, gco2ts(o)); /* remove it from hash table */ + luaM_freemem(L, o, sizelstring(gco2ts(o)->shrlen)); + break; + case LUA_TLNGSTR: { + luaM_freemem(L, o, sizelstring(gco2ts(o)->u.lnglen)); + break; + } + default: lua_assert(0); + } +} + + +#define sweepwholelist(L,p) sweeplist(L,p,MAX_LUMEM) +static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count); + + +/* +** sweep at most 'count' elements from a list of GCObjects erasing dead +** objects, where a dead object is one marked with the old (non current) +** white; change all non-dead objects back to white, preparing for next +** collection cycle. Return where to continue the traversal or NULL if +** list is finished. +*/ +static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { + global_State *g = G(L); + int ow = otherwhite(g); + int white = luaC_white(g); /* current white */ + while (*p != NULL && count-- > 0) { + GCObject *curr = *p; + int marked = curr->marked; + if (isdeadm(ow, marked)) { /* is 'curr' dead? */ + *p = curr->next; /* remove 'curr' from list */ + freeobj(L, curr); /* erase 'curr' */ + } + else { /* change mark to 'white' */ + curr->marked = cast_byte((marked & maskcolors) | white); + p = &curr->next; /* go to next element */ + } + } + return (*p == NULL) ? NULL : p; +} + + +/* +** sweep a list until a live object (or end of list) +*/ +static GCObject **sweeptolive (lua_State *L, GCObject **p) { + GCObject **old = p; + do { + p = sweeplist(L, p, 1); + } while (p == old); + return p; +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Finalization +** ======================================================= +*/ + +/* +** If possible, shrink string table +*/ +static void checkSizes (lua_State *L, global_State *g) { + if (g->gckind != KGC_EMERGENCY) { + l_mem olddebt = g->GCdebt; + if (g->strt.nuse < g->strt.size / 4) /* string table too big? */ + luaS_resize(L, g->strt.size / 2); /* shrink it a little */ + g->GCestimate += g->GCdebt - olddebt; /* update estimate */ + } +} + + +static GCObject *udata2finalize (global_State *g) { + GCObject *o = g->tobefnz; /* get first element */ + lua_assert(tofinalize(o)); + g->tobefnz = o->next; /* remove it from 'tobefnz' list */ + o->next = g->allgc; /* return it to 'allgc' list */ + g->allgc = o; + resetbit(o->marked, FINALIZEDBIT); /* object is "normal" again */ + if (issweepphase(g)) + makewhite(g, o); /* "sweep" object */ + return o; +} + + +static void dothecall (lua_State *L, void *ud) { + UNUSED(ud); + luaD_callnoyield(L, L->top - 2, 0); +} + + +static void GCTM (lua_State *L, int propagateerrors) { + global_State *g = G(L); + const TValue *tm; + TValue v; + setgcovalue(L, &v, udata2finalize(g)); + tm = luaT_gettmbyobj(L, &v, TM_GC); + if (tm != NULL && ttisfunction(tm)) { /* is there a finalizer? */ + int status; + lu_byte oldah = L->allowhook; + int running = g->gcrunning; + L->allowhook = 0; /* stop debug hooks during GC metamethod */ + g->gcrunning = 0; /* avoid GC steps */ + setobj2s(L, L->top, tm); /* push finalizer... */ + setobj2s(L, L->top + 1, &v); /* ... and its argument */ + L->top += 2; /* and (next line) call the finalizer */ + L->ci->callstatus |= CIST_FIN; /* will run a finalizer */ + status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top - 2), 0); + L->ci->callstatus &= ~CIST_FIN; /* not running a finalizer anymore */ + L->allowhook = oldah; /* restore hooks */ + g->gcrunning = running; /* restore state */ + if (status != LUA_OK && propagateerrors) { /* error while running __gc? */ + if (status == LUA_ERRRUN) { /* is there an error object? */ + const char *msg = (ttisstring(L->top - 1)) + ? svalue(L->top - 1) + : "no message"; + luaO_pushfstring(L, "error in __gc metamethod (%s)", msg); + status = LUA_ERRGCMM; /* error in __gc metamethod */ + } + luaD_throw(L, status); /* re-throw error */ + } + } +} + + +/* +** call a few (up to 'g->gcfinnum') finalizers +*/ +static int runafewfinalizers (lua_State *L) { + global_State *g = G(L); + unsigned int i; + lua_assert(!g->tobefnz || g->gcfinnum > 0); + for (i = 0; g->tobefnz && i < g->gcfinnum; i++) + GCTM(L, 1); /* call one finalizer */ + g->gcfinnum = (!g->tobefnz) ? 0 /* nothing more to finalize? */ + : g->gcfinnum * 2; /* else call a few more next time */ + return i; +} + + +/* +** call all pending finalizers +*/ +static void callallpendingfinalizers (lua_State *L) { + global_State *g = G(L); + while (g->tobefnz) + GCTM(L, 0); +} + + +/* +** find last 'next' field in list 'p' list (to add elements in its end) +*/ +static GCObject **findlast (GCObject **p) { + while (*p != NULL) + p = &(*p)->next; + return p; +} + + +/* +** move all unreachable objects (or 'all' objects) that need +** finalization from list 'finobj' to list 'tobefnz' (to be finalized) +*/ +static void separatetobefnz (global_State *g, int all) { + GCObject *curr; + GCObject **p = &g->finobj; + GCObject **lastnext = findlast(&g->tobefnz); + while ((curr = *p) != NULL) { /* traverse all finalizable objects */ + lua_assert(tofinalize(curr)); + if (!(iswhite(curr) || all)) /* not being collected? */ + p = &curr->next; /* don't bother with it */ + else { + *p = curr->next; /* remove 'curr' from 'finobj' list */ + curr->next = *lastnext; /* link at the end of 'tobefnz' list */ + *lastnext = curr; + lastnext = &curr->next; + } + } +} + + +/* +** if object 'o' has a finalizer, remove it from 'allgc' list (must +** search the list to find it) and link it in 'finobj' list. +*/ +void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { + global_State *g = G(L); + if (tofinalize(o) || /* obj. is already marked... */ + gfasttm(g, mt, TM_GC) == NULL) /* or has no finalizer? */ + return; /* nothing to be done */ + else { /* move 'o' to 'finobj' list */ + GCObject **p; + if (issweepphase(g)) { + makewhite(g, o); /* "sweep" object 'o' */ + if (g->sweepgc == &o->next) /* should not remove 'sweepgc' object */ + g->sweepgc = sweeptolive(L, g->sweepgc); /* change 'sweepgc' */ + } + /* search for pointer pointing to 'o' */ + for (p = &g->allgc; *p != o; p = &(*p)->next) { /* empty */ } + *p = o->next; /* remove 'o' from 'allgc' list */ + o->next = g->finobj; /* link it in 'finobj' list */ + g->finobj = o; + l_setbit(o->marked, FINALIZEDBIT); /* mark it as such */ + } +} + +/* }====================================================== */ + + + +/* +** {====================================================== +** GC control +** ======================================================= +*/ + + +/* +** Set a reasonable "time" to wait before starting a new GC cycle; cycle +** will start when memory use hits threshold. (Division by 'estimate' +** should be OK: it cannot be zero (because Lua cannot even start with +** less than PAUSEADJ bytes). +*/ +static void setpause (global_State *g) { + l_mem threshold, debt; + l_mem estimate = g->GCestimate / PAUSEADJ; /* adjust 'estimate' */ + lua_assert(estimate > 0); + threshold = (g->gcpause < MAX_LMEM / estimate) /* overflow? */ + ? estimate * g->gcpause /* no overflow */ + : MAX_LMEM; /* overflow; truncate to maximum */ + debt = gettotalbytes(g) - threshold; + luaE_setdebt(g, debt); +} + + +/* +** Enter first sweep phase. +** The call to 'sweeplist' tries to make pointer point to an object +** inside the list (instead of to the header), so that the real sweep do +** not need to skip objects created between "now" and the start of the +** real sweep. +*/ +static void entersweep (lua_State *L) { + global_State *g = G(L); + g->gcstate = GCSswpallgc; + lua_assert(g->sweepgc == NULL); + g->sweepgc = sweeplist(L, &g->allgc, 1); +} + + +void luaC_freeallobjects (lua_State *L) { + global_State *g = G(L); + separatetobefnz(g, 1); /* separate all objects with finalizers */ + lua_assert(g->finobj == NULL); + callallpendingfinalizers(L); + lua_assert(g->tobefnz == NULL); + g->currentwhite = WHITEBITS; /* this "white" makes all objects look dead */ + g->gckind = KGC_NORMAL; + sweepwholelist(L, &g->finobj); + sweepwholelist(L, &g->allgc); + sweepwholelist(L, &g->fixedgc); /* collect fixed objects */ + lua_assert(g->strt.nuse == 0); +} + + +static l_mem atomic (lua_State *L) { + global_State *g = G(L); + l_mem work; + GCObject *origweak, *origall; + GCObject *grayagain = g->grayagain; /* save original list */ + lua_assert(g->ephemeron == NULL && g->weak == NULL); + lua_assert(!iswhite(g->mainthread)); + g->gcstate = GCSinsideatomic; + g->GCmemtrav = 0; /* start counting work */ + markobject(g, L); /* mark running thread */ + /* registry and global metatables may be changed by API */ + markvalue(g, &g->l_registry); + markmt(g); /* mark global metatables */ + /* remark occasional upvalues of (maybe) dead threads */ + remarkupvals(g); + propagateall(g); /* propagate changes */ + work = g->GCmemtrav; /* stop counting (do not recount 'grayagain') */ + g->gray = grayagain; + propagateall(g); /* traverse 'grayagain' list */ + g->GCmemtrav = 0; /* restart counting */ + convergeephemerons(g); + /* at this point, all strongly accessible objects are marked. */ + /* Clear values from weak tables, before checking finalizers */ + clearvalues(g, g->weak, NULL); + clearvalues(g, g->allweak, NULL); + origweak = g->weak; origall = g->allweak; + work += g->GCmemtrav; /* stop counting (objects being finalized) */ + separatetobefnz(g, 0); /* separate objects to be finalized */ + g->gcfinnum = 1; /* there may be objects to be finalized */ + markbeingfnz(g); /* mark objects that will be finalized */ + propagateall(g); /* remark, to propagate 'resurrection' */ + g->GCmemtrav = 0; /* restart counting */ + convergeephemerons(g); + /* at this point, all resurrected objects are marked. */ + /* remove dead objects from weak tables */ + clearkeys(g, g->ephemeron, NULL); /* clear keys from all ephemeron tables */ + clearkeys(g, g->allweak, NULL); /* clear keys from all 'allweak' tables */ + /* clear values from resurrected weak tables */ + clearvalues(g, g->weak, origweak); + clearvalues(g, g->allweak, origall); + luaS_clearcache(g); + g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ + work += g->GCmemtrav; /* complete counting */ + return work; /* estimate of memory marked by 'atomic' */ +} + + +static lu_mem sweepstep (lua_State *L, global_State *g, + int nextstate, GCObject **nextlist) { + if (g->sweepgc) { + l_mem olddebt = g->GCdebt; + g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX); + g->GCestimate += g->GCdebt - olddebt; /* update estimate */ + if (g->sweepgc) /* is there still something to sweep? */ + return (GCSWEEPMAX * GCSWEEPCOST); + } + /* else enter next state */ + g->gcstate = nextstate; + g->sweepgc = nextlist; + return 0; +} + + +static lu_mem singlestep (lua_State *L) { + global_State *g = G(L); + switch (g->gcstate) { + case GCSpause: { + g->GCmemtrav = g->strt.size * sizeof(GCObject*); + restartcollection(g); + g->gcstate = GCSpropagate; + return g->GCmemtrav; + } + case GCSpropagate: { + g->GCmemtrav = 0; + lua_assert(g->gray); + propagatemark(g); + if (g->gray == NULL) /* no more gray objects? */ + g->gcstate = GCSatomic; /* finish propagate phase */ + return g->GCmemtrav; /* memory traversed in this step */ + } + case GCSatomic: { + lu_mem work; + propagateall(g); /* make sure gray list is empty */ + work = atomic(L); /* work is what was traversed by 'atomic' */ + entersweep(L); + g->GCestimate = gettotalbytes(g); /* first estimate */; + return work; + } + case GCSswpallgc: { /* sweep "regular" objects */ + return sweepstep(L, g, GCSswpfinobj, &g->finobj); + } + case GCSswpfinobj: { /* sweep objects with finalizers */ + return sweepstep(L, g, GCSswptobefnz, &g->tobefnz); + } + case GCSswptobefnz: { /* sweep objects to be finalized */ + return sweepstep(L, g, GCSswpend, NULL); + } + case GCSswpend: { /* finish sweeps */ + makewhite(g, g->mainthread); /* sweep main thread */ + checkSizes(L, g); + g->gcstate = GCScallfin; + return 0; + } + case GCScallfin: { /* call remaining finalizers */ + if (g->tobefnz && g->gckind != KGC_EMERGENCY) { + int n = runafewfinalizers(L); + return (n * GCFINALIZECOST); + } + else { /* emergency mode or no more finalizers */ + g->gcstate = GCSpause; /* finish collection */ + return 0; + } + } + default: lua_assert(0); return 0; + } +} + + +/* +** advances the garbage collector until it reaches a state allowed +** by 'statemask' +*/ +void luaC_runtilstate (lua_State *L, int statesmask) { + global_State *g = G(L); + while (!testbit(statesmask, g->gcstate)) + singlestep(L); +} + + +/* +** get GC debt and convert it from Kb to 'work units' (avoid zero debt +** and overflows) +*/ +static l_mem getdebt (global_State *g) { + l_mem debt = g->GCdebt; + int stepmul = g->gcstepmul; + if (debt <= 0) return 0; /* minimal debt */ + else { + debt = (debt / STEPMULADJ) + 1; + debt = (debt < MAX_LMEM / stepmul) ? debt * stepmul : MAX_LMEM; + return debt; + } +} + +/* +** performs a basic GC step when collector is running +*/ +void luaC_step (lua_State *L) { + global_State *g = G(L); + l_mem debt = getdebt(g); /* GC deficit (be paid now) */ + if (!g->gcrunning) { /* not running? */ + luaE_setdebt(g, -GCSTEPSIZE * 10); /* avoid being called too often */ + return; + } + do { /* repeat until pause or enough "credit" (negative debt) */ + lu_mem work = singlestep(L); /* perform one single step */ + debt -= work; + } while (debt > -GCSTEPSIZE && g->gcstate != GCSpause); + if (g->gcstate == GCSpause) + setpause(g); /* pause until next cycle */ + else { + debt = (debt / g->gcstepmul) * STEPMULADJ; /* convert 'work units' to Kb */ + luaE_setdebt(g, debt); + runafewfinalizers(L); + } +} + + +/* +** Performs a full GC cycle; if 'isemergency', set a flag to avoid +** some operations which could change the interpreter state in some +** unexpected ways (running finalizers and shrinking some structures). +** Before running the collection, check 'keepinvariant'; if it is true, +** there may be some objects marked as black, so the collector has +** to sweep all objects to turn them back to white (as white has not +** changed, nothing will be collected). +*/ +void luaC_fullgc (lua_State *L, int isemergency) { + global_State *g = G(L); + lua_assert(g->gckind == KGC_NORMAL); + if (isemergency) g->gckind = KGC_EMERGENCY; /* set flag */ + if (keepinvariant(g)) { /* black objects? */ + entersweep(L); /* sweep everything to turn them back to white */ + } + /* finish any pending sweep phase to start a new cycle */ + luaC_runtilstate(L, bitmask(GCSpause)); + luaC_runtilstate(L, ~bitmask(GCSpause)); /* start new collection */ + luaC_runtilstate(L, bitmask(GCScallfin)); /* run up to finalizers */ + /* estimate must be correct after a full GC cycle */ + lua_assert(g->GCestimate == gettotalbytes(g)); + luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */ + g->gckind = KGC_NORMAL; + setpause(g); +} + +/* }====================================================== */ + + diff --git a/depends/lua/src/linit.c b/depends/lua/src/linit.c new file mode 100644 index 0000000000..480da52c7e --- /dev/null +++ b/depends/lua/src/linit.c @@ -0,0 +1,68 @@ +/* +** $Id: linit.c,v 1.39.1.1 2017/04/19 17:20:42 roberto Exp $ +** Initialization of libraries for lua.c and other clients +** See Copyright Notice in lua.h +*/ + + +#define linit_c +#define LUA_LIB + +/* +** If you embed Lua in your program and need to open the standard +** libraries, call luaL_openlibs in your program. If you need a +** different set of libraries, copy this file to your project and edit +** it to suit your needs. +** +** You can also *preload* libraries, so that a later 'require' can +** open the library, which is already linked to the application. +** For that, do the following code: +** +** luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE); +** lua_pushcfunction(L, luaopen_modname); +** lua_setfield(L, -2, modname); +** lua_pop(L, 1); // remove PRELOAD table +*/ + +#include "lprefix.h" + + +#include + +#include "lua.h" + +#include "lualib.h" +#include "lauxlib.h" + + +/* +** these libs are loaded by lua.c and are readily available to any Lua +** program +*/ +static const luaL_Reg loadedlibs[] = { + {"_G", luaopen_base}, + {LUA_LOADLIBNAME, luaopen_package}, + {LUA_COLIBNAME, luaopen_coroutine}, + {LUA_TABLIBNAME, luaopen_table}, + {LUA_IOLIBNAME, luaopen_io}, + {LUA_OSLIBNAME, luaopen_os}, + {LUA_STRLIBNAME, luaopen_string}, + {LUA_MATHLIBNAME, luaopen_math}, + {LUA_UTF8LIBNAME, luaopen_utf8}, + {LUA_DBLIBNAME, luaopen_debug}, +#if defined(LUA_COMPAT_BITLIB) + {LUA_BITLIBNAME, luaopen_bit32}, +#endif + {NULL, NULL} +}; + + +LUALIB_API void luaL_openlibs (lua_State *L) { + const luaL_Reg *lib; + /* "require" functions from 'loadedlibs' and set results to global table */ + for (lib = loadedlibs; lib->func; lib++) { + luaL_requiref(L, lib->name, lib->func, 1); + lua_pop(L, 1); /* remove lib */ + } +} + diff --git a/depends/lua/src/liolib.c b/depends/lua/src/liolib.c new file mode 100644 index 0000000000..027d4bd0db --- /dev/null +++ b/depends/lua/src/liolib.c @@ -0,0 +1,778 @@ +/* +** $Id: liolib.c,v 2.151.1.1 2017/04/19 17:29:57 roberto Exp $ +** Standard I/O (and system) library +** See Copyright Notice in lua.h +*/ + +#define liolib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include +#include +#include +#include +#include +#include + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + + + +/* +** Change this macro to accept other modes for 'fopen' besides +** the standard ones. +*/ +#if !defined(l_checkmode) + +/* accepted extensions to 'mode' in 'fopen' */ +#if !defined(L_MODEEXT) +#define L_MODEEXT "b" +#endif + +/* Check whether 'mode' matches '[rwa]%+?[L_MODEEXT]*' */ +static int l_checkmode (const char *mode) { + return (*mode != '\0' && strchr("rwa", *(mode++)) != NULL && + (*mode != '+' || (++mode, 1)) && /* skip if char is '+' */ + (strspn(mode, L_MODEEXT) == strlen(mode))); /* check extensions */ +} + +#endif + +/* +** {====================================================== +** l_popen spawns a new process connected to the current +** one through the file streams. +** ======================================================= +*/ + +#if !defined(l_popen) /* { */ + +#if defined(LUA_USE_POSIX) /* { */ + +#define l_popen(L,c,m) (fflush(NULL), popen(c,m)) +#define l_pclose(L,file) (pclose(file)) + +#elif defined(LUA_USE_WINDOWS) /* }{ */ + +#define l_popen(L,c,m) (_popen(c,m)) +#define l_pclose(L,file) (_pclose(file)) + +#else /* }{ */ + +/* ISO C definitions */ +#define l_popen(L,c,m) \ + ((void)((void)c, m), \ + luaL_error(L, "'popen' not supported"), \ + (FILE*)0) +#define l_pclose(L,file) ((void)L, (void)file, -1) + +#endif /* } */ + +#endif /* } */ + +/* }====================================================== */ + + +#if !defined(l_getc) /* { */ + +#if defined(LUA_USE_POSIX) +#define l_getc(f) getc_unlocked(f) +#define l_lockfile(f) flockfile(f) +#define l_unlockfile(f) funlockfile(f) +#else +#define l_getc(f) getc(f) +#define l_lockfile(f) ((void)0) +#define l_unlockfile(f) ((void)0) +#endif + +#endif /* } */ + + +/* +** {====================================================== +** l_fseek: configuration for longer offsets +** ======================================================= +*/ + +#if !defined(l_fseek) /* { */ + +#if defined(LUA_USE_POSIX) /* { */ + +#include + +#define l_fseek(f,o,w) fseeko(f,o,w) +#define l_ftell(f) ftello(f) +#define l_seeknum off_t + +#elif defined(LUA_USE_WINDOWS) && !defined(_CRTIMP_TYPEINFO) \ + && defined(_MSC_VER) && (_MSC_VER >= 1400) /* }{ */ + +/* Windows (but not DDK) and Visual C++ 2005 or higher */ +#define l_fseek(f,o,w) _fseeki64(f,o,w) +#define l_ftell(f) _ftelli64(f) +#define l_seeknum __int64 + +#else /* }{ */ + +/* ISO C definitions */ +#define l_fseek(f,o,w) fseek(f,o,w) +#define l_ftell(f) ftell(f) +#define l_seeknum long + +#endif /* } */ + +#endif /* } */ + +/* }====================================================== */ + + +#define IO_PREFIX "_IO_" +#define IOPREF_LEN (sizeof(IO_PREFIX)/sizeof(char) - 1) +#define IO_INPUT (IO_PREFIX "input") +#define IO_OUTPUT (IO_PREFIX "output") + + +typedef luaL_Stream LStream; + + +#define tolstream(L) ((LStream *)luaL_checkudata(L, 1, LUA_FILEHANDLE)) + +#define isclosed(p) ((p)->closef == NULL) + + +static int io_type (lua_State *L) { + LStream *p; + luaL_checkany(L, 1); + p = (LStream *)luaL_testudata(L, 1, LUA_FILEHANDLE); + if (p == NULL) + lua_pushnil(L); /* not a file */ + else if (isclosed(p)) + lua_pushliteral(L, "closed file"); + else + lua_pushliteral(L, "file"); + return 1; +} + + +static int f_tostring (lua_State *L) { + LStream *p = tolstream(L); + if (isclosed(p)) + lua_pushliteral(L, "file (closed)"); + else + lua_pushfstring(L, "file (%p)", p->f); + return 1; +} + + +static FILE *tofile (lua_State *L) { + LStream *p = tolstream(L); + if (isclosed(p)) + luaL_error(L, "attempt to use a closed file"); + lua_assert(p->f); + return p->f; +} + + +/* +** When creating file handles, always creates a 'closed' file handle +** before opening the actual file; so, if there is a memory error, the +** handle is in a consistent state. +*/ +static LStream *newprefile (lua_State *L) { + LStream *p = (LStream *)lua_newuserdata(L, sizeof(LStream)); + p->closef = NULL; /* mark file handle as 'closed' */ + luaL_setmetatable(L, LUA_FILEHANDLE); + return p; +} + + +/* +** Calls the 'close' function from a file handle. The 'volatile' avoids +** a bug in some versions of the Clang compiler (e.g., clang 3.0 for +** 32 bits). +*/ +static int aux_close (lua_State *L) { + LStream *p = tolstream(L); + volatile lua_CFunction cf = p->closef; + p->closef = NULL; /* mark stream as closed */ + return (*cf)(L); /* close it */ +} + + +static int f_close (lua_State *L) { + tofile(L); /* make sure argument is an open stream */ + return aux_close(L); +} + + +static int io_close (lua_State *L) { + if (lua_isnone(L, 1)) /* no argument? */ + lua_getfield(L, LUA_REGISTRYINDEX, IO_OUTPUT); /* use standard output */ + return f_close(L); +} + + +static int f_gc (lua_State *L) { + LStream *p = tolstream(L); + if (!isclosed(p) && p->f != NULL) + aux_close(L); /* ignore closed and incompletely open files */ + return 0; +} + + +/* +** function to close regular files +*/ +static int io_fclose (lua_State *L) { + LStream *p = tolstream(L); + int res = fclose(p->f); + return luaL_fileresult(L, (res == 0), NULL); +} + + +static LStream *newfile (lua_State *L) { + LStream *p = newprefile(L); + p->f = NULL; + p->closef = &io_fclose; + return p; +} + + +static void opencheck (lua_State *L, const char *fname, const char *mode) { + LStream *p = newfile(L); + p->f = fopen(fname, mode); + if (p->f == NULL) + luaL_error(L, "cannot open file '%s' (%s)", fname, strerror(errno)); +} + + +static int io_open (lua_State *L) { + const char *filename = luaL_checkstring(L, 1); + const char *mode = luaL_optstring(L, 2, "r"); + LStream *p = newfile(L); + const char *md = mode; /* to traverse/check mode */ + luaL_argcheck(L, l_checkmode(md), 2, "invalid mode"); + p->f = fopen(filename, mode); + return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; +} + + +/* +** function to close 'popen' files +*/ +static int io_pclose (lua_State *L) { + LStream *p = tolstream(L); + return luaL_execresult(L, l_pclose(L, p->f)); +} + + +static int io_popen (lua_State *L) { + const char *filename = luaL_checkstring(L, 1); + const char *mode = luaL_optstring(L, 2, "r"); + LStream *p = newprefile(L); + luaL_argcheck(L, ((mode[0] == 'r' || mode[0] == 'w') && mode[1] == '\0'), + 2, "invalid mode"); + p->f = l_popen(L, filename, mode); + p->closef = &io_pclose; + return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; +} + + +static int io_tmpfile (lua_State *L) { + LStream *p = newfile(L); + p->f = tmpfile(); + return (p->f == NULL) ? luaL_fileresult(L, 0, NULL) : 1; +} + + +static FILE *getiofile (lua_State *L, const char *findex) { + LStream *p; + lua_getfield(L, LUA_REGISTRYINDEX, findex); + p = (LStream *)lua_touserdata(L, -1); + if (isclosed(p)) + luaL_error(L, "standard %s file is closed", findex + IOPREF_LEN); + return p->f; +} + + +static int g_iofile (lua_State *L, const char *f, const char *mode) { + if (!lua_isnoneornil(L, 1)) { + const char *filename = lua_tostring(L, 1); + if (filename) + opencheck(L, filename, mode); + else { + tofile(L); /* check that it's a valid file handle */ + lua_pushvalue(L, 1); + } + lua_setfield(L, LUA_REGISTRYINDEX, f); + } + /* return current value */ + lua_getfield(L, LUA_REGISTRYINDEX, f); + return 1; +} + + +static int io_input (lua_State *L) { + return g_iofile(L, IO_INPUT, "r"); +} + + +static int io_output (lua_State *L) { + return g_iofile(L, IO_OUTPUT, "w"); +} + + +static int io_readline (lua_State *L); + + +/* +** maximum number of arguments to 'f:lines'/'io.lines' (it + 3 must fit +** in the limit for upvalues of a closure) +*/ +#define MAXARGLINE 250 + +static void aux_lines (lua_State *L, int toclose) { + int n = lua_gettop(L) - 1; /* number of arguments to read */ + luaL_argcheck(L, n <= MAXARGLINE, MAXARGLINE + 2, "too many arguments"); + lua_pushinteger(L, n); /* number of arguments to read */ + lua_pushboolean(L, toclose); /* close/not close file when finished */ + lua_rotate(L, 2, 2); /* move 'n' and 'toclose' to their positions */ + lua_pushcclosure(L, io_readline, 3 + n); +} + + +static int f_lines (lua_State *L) { + tofile(L); /* check that it's a valid file handle */ + aux_lines(L, 0); + return 1; +} + + +static int io_lines (lua_State *L) { + int toclose; + if (lua_isnone(L, 1)) lua_pushnil(L); /* at least one argument */ + if (lua_isnil(L, 1)) { /* no file name? */ + lua_getfield(L, LUA_REGISTRYINDEX, IO_INPUT); /* get default input */ + lua_replace(L, 1); /* put it at index 1 */ + tofile(L); /* check that it's a valid file handle */ + toclose = 0; /* do not close it after iteration */ + } + else { /* open a new file */ + const char *filename = luaL_checkstring(L, 1); + opencheck(L, filename, "r"); + lua_replace(L, 1); /* put file at index 1 */ + toclose = 1; /* close it after iteration */ + } + aux_lines(L, toclose); + return 1; +} + + +/* +** {====================================================== +** READ +** ======================================================= +*/ + + +/* maximum length of a numeral */ +#if !defined (L_MAXLENNUM) +#define L_MAXLENNUM 200 +#endif + + +/* auxiliary structure used by 'read_number' */ +typedef struct { + FILE *f; /* file being read */ + int c; /* current character (look ahead) */ + int n; /* number of elements in buffer 'buff' */ + char buff[L_MAXLENNUM + 1]; /* +1 for ending '\0' */ +} RN; + + +/* +** Add current char to buffer (if not out of space) and read next one +*/ +static int nextc (RN *rn) { + if (rn->n >= L_MAXLENNUM) { /* buffer overflow? */ + rn->buff[0] = '\0'; /* invalidate result */ + return 0; /* fail */ + } + else { + rn->buff[rn->n++] = rn->c; /* save current char */ + rn->c = l_getc(rn->f); /* read next one */ + return 1; + } +} + + +/* +** Accept current char if it is in 'set' (of size 2) +*/ +static int test2 (RN *rn, const char *set) { + if (rn->c == set[0] || rn->c == set[1]) + return nextc(rn); + else return 0; +} + + +/* +** Read a sequence of (hex)digits +*/ +static int readdigits (RN *rn, int hex) { + int count = 0; + while ((hex ? isxdigit(rn->c) : isdigit(rn->c)) && nextc(rn)) + count++; + return count; +} + + +/* +** Read a number: first reads a valid prefix of a numeral into a buffer. +** Then it calls 'lua_stringtonumber' to check whether the format is +** correct and to convert it to a Lua number +*/ +static int read_number (lua_State *L, FILE *f) { + RN rn; + int count = 0; + int hex = 0; + char decp[2]; + rn.f = f; rn.n = 0; + decp[0] = lua_getlocaledecpoint(); /* get decimal point from locale */ + decp[1] = '.'; /* always accept a dot */ + l_lockfile(rn.f); + do { rn.c = l_getc(rn.f); } while (isspace(rn.c)); /* skip spaces */ + test2(&rn, "-+"); /* optional signal */ + if (test2(&rn, "00")) { + if (test2(&rn, "xX")) hex = 1; /* numeral is hexadecimal */ + else count = 1; /* count initial '0' as a valid digit */ + } + count += readdigits(&rn, hex); /* integral part */ + if (test2(&rn, decp)) /* decimal point? */ + count += readdigits(&rn, hex); /* fractional part */ + if (count > 0 && test2(&rn, (hex ? "pP" : "eE"))) { /* exponent mark? */ + test2(&rn, "-+"); /* exponent signal */ + readdigits(&rn, 0); /* exponent digits */ + } + ungetc(rn.c, rn.f); /* unread look-ahead char */ + l_unlockfile(rn.f); + rn.buff[rn.n] = '\0'; /* finish string */ + if (lua_stringtonumber(L, rn.buff)) /* is this a valid number? */ + return 1; /* ok */ + else { /* invalid format */ + lua_pushnil(L); /* "result" to be removed */ + return 0; /* read fails */ + } +} + + +static int test_eof (lua_State *L, FILE *f) { + int c = getc(f); + ungetc(c, f); /* no-op when c == EOF */ + lua_pushliteral(L, ""); + return (c != EOF); +} + + +static int read_line (lua_State *L, FILE *f, int chop) { + luaL_Buffer b; + int c = '\0'; + luaL_buffinit(L, &b); + while (c != EOF && c != '\n') { /* repeat until end of line */ + char *buff = luaL_prepbuffer(&b); /* preallocate buffer */ + int i = 0; + l_lockfile(f); /* no memory errors can happen inside the lock */ + while (i < LUAL_BUFFERSIZE && (c = l_getc(f)) != EOF && c != '\n') + buff[i++] = c; + l_unlockfile(f); + luaL_addsize(&b, i); + } + if (!chop && c == '\n') /* want a newline and have one? */ + luaL_addchar(&b, c); /* add ending newline to result */ + luaL_pushresult(&b); /* close buffer */ + /* return ok if read something (either a newline or something else) */ + return (c == '\n' || lua_rawlen(L, -1) > 0); +} + + +static void read_all (lua_State *L, FILE *f) { + size_t nr; + luaL_Buffer b; + luaL_buffinit(L, &b); + do { /* read file in chunks of LUAL_BUFFERSIZE bytes */ + char *p = luaL_prepbuffer(&b); + nr = fread(p, sizeof(char), LUAL_BUFFERSIZE, f); + luaL_addsize(&b, nr); + } while (nr == LUAL_BUFFERSIZE); + luaL_pushresult(&b); /* close buffer */ +} + + +static int read_chars (lua_State *L, FILE *f, size_t n) { + size_t nr; /* number of chars actually read */ + char *p; + luaL_Buffer b; + luaL_buffinit(L, &b); + p = luaL_prepbuffsize(&b, n); /* prepare buffer to read whole block */ + nr = fread(p, sizeof(char), n, f); /* try to read 'n' chars */ + luaL_addsize(&b, nr); + luaL_pushresult(&b); /* close buffer */ + return (nr > 0); /* true iff read something */ +} + + +static int g_read (lua_State *L, FILE *f, int first) { + int nargs = lua_gettop(L) - 1; + int success; + int n; + clearerr(f); + if (nargs == 0) { /* no arguments? */ + success = read_line(L, f, 1); + n = first+1; /* to return 1 result */ + } + else { /* ensure stack space for all results and for auxlib's buffer */ + luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments"); + success = 1; + for (n = first; nargs-- && success; n++) { + if (lua_type(L, n) == LUA_TNUMBER) { + size_t l = (size_t)luaL_checkinteger(L, n); + success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l); + } + else { + const char *p = luaL_checkstring(L, n); + if (*p == '*') p++; /* skip optional '*' (for compatibility) */ + switch (*p) { + case 'n': /* number */ + success = read_number(L, f); + break; + case 'l': /* line */ + success = read_line(L, f, 1); + break; + case 'L': /* line with end-of-line */ + success = read_line(L, f, 0); + break; + case 'a': /* file */ + read_all(L, f); /* read entire file */ + success = 1; /* always success */ + break; + default: + return luaL_argerror(L, n, "invalid format"); + } + } + } + } + if (ferror(f)) + return luaL_fileresult(L, 0, NULL); + if (!success) { + lua_pop(L, 1); /* remove last result */ + lua_pushnil(L); /* push nil instead */ + } + return n - first; +} + + +static int io_read (lua_State *L) { + return g_read(L, getiofile(L, IO_INPUT), 1); +} + + +static int f_read (lua_State *L) { + return g_read(L, tofile(L), 2); +} + + +static int io_readline (lua_State *L) { + LStream *p = (LStream *)lua_touserdata(L, lua_upvalueindex(1)); + int i; + int n = (int)lua_tointeger(L, lua_upvalueindex(2)); + if (isclosed(p)) /* file is already closed? */ + return luaL_error(L, "file is already closed"); + lua_settop(L , 1); + luaL_checkstack(L, n, "too many arguments"); + for (i = 1; i <= n; i++) /* push arguments to 'g_read' */ + lua_pushvalue(L, lua_upvalueindex(3 + i)); + n = g_read(L, p->f, 2); /* 'n' is number of results */ + lua_assert(n > 0); /* should return at least a nil */ + if (lua_toboolean(L, -n)) /* read at least one value? */ + return n; /* return them */ + else { /* first result is nil: EOF or error */ + if (n > 1) { /* is there error information? */ + /* 2nd result is error message */ + return luaL_error(L, "%s", lua_tostring(L, -n + 1)); + } + if (lua_toboolean(L, lua_upvalueindex(3))) { /* generator created file? */ + lua_settop(L, 0); + lua_pushvalue(L, lua_upvalueindex(1)); + aux_close(L); /* close it */ + } + return 0; + } +} + +/* }====================================================== */ + + +static int g_write (lua_State *L, FILE *f, int arg) { + int nargs = lua_gettop(L) - arg; + int status = 1; + for (; nargs--; arg++) { + if (lua_type(L, arg) == LUA_TNUMBER) { + /* optimization: could be done exactly as for strings */ + int len = lua_isinteger(L, arg) + ? fprintf(f, LUA_INTEGER_FMT, + (LUAI_UACINT)lua_tointeger(L, arg)) + : fprintf(f, LUA_NUMBER_FMT, + (LUAI_UACNUMBER)lua_tonumber(L, arg)); + status = status && (len > 0); + } + else { + size_t l; + const char *s = luaL_checklstring(L, arg, &l); + status = status && (fwrite(s, sizeof(char), l, f) == l); + } + } + if (status) return 1; /* file handle already on stack top */ + else return luaL_fileresult(L, status, NULL); +} + + +static int io_write (lua_State *L) { + return g_write(L, getiofile(L, IO_OUTPUT), 1); +} + + +static int f_write (lua_State *L) { + FILE *f = tofile(L); + lua_pushvalue(L, 1); /* push file at the stack top (to be returned) */ + return g_write(L, f, 2); +} + + +static int f_seek (lua_State *L) { + static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END}; + static const char *const modenames[] = {"set", "cur", "end", NULL}; + FILE *f = tofile(L); + int op = luaL_checkoption(L, 2, "cur", modenames); + lua_Integer p3 = luaL_optinteger(L, 3, 0); + l_seeknum offset = (l_seeknum)p3; + luaL_argcheck(L, (lua_Integer)offset == p3, 3, + "not an integer in proper range"); + op = l_fseek(f, offset, mode[op]); + if (op) + return luaL_fileresult(L, 0, NULL); /* error */ + else { + lua_pushinteger(L, (lua_Integer)l_ftell(f)); + return 1; + } +} + + +static int f_setvbuf (lua_State *L) { + static const int mode[] = {_IONBF, _IOFBF, _IOLBF}; + static const char *const modenames[] = {"no", "full", "line", NULL}; + FILE *f = tofile(L); + int op = luaL_checkoption(L, 2, NULL, modenames); + lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE); + int res = setvbuf(f, NULL, mode[op], (size_t)sz); + return luaL_fileresult(L, res == 0, NULL); +} + + + +static int io_flush (lua_State *L) { + return luaL_fileresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL); +} + + +static int f_flush (lua_State *L) { + return luaL_fileresult(L, fflush(tofile(L)) == 0, NULL); +} + + +/* +** functions for 'io' library +*/ +static const luaL_Reg iolib[] = { + {"close", io_close}, + {"flush", io_flush}, + {"input", io_input}, + {"lines", io_lines}, + {"open", io_open}, + {"output", io_output}, + {"popen", io_popen}, + {"read", io_read}, + {"tmpfile", io_tmpfile}, + {"type", io_type}, + {"write", io_write}, + {NULL, NULL} +}; + + +/* +** methods for file handles +*/ +static const luaL_Reg flib[] = { + {"close", f_close}, + {"flush", f_flush}, + {"lines", f_lines}, + {"read", f_read}, + {"seek", f_seek}, + {"setvbuf", f_setvbuf}, + {"write", f_write}, + {"__gc", f_gc}, + {"__tostring", f_tostring}, + {NULL, NULL} +}; + + +static void createmeta (lua_State *L) { + luaL_newmetatable(L, LUA_FILEHANDLE); /* create metatable for file handles */ + lua_pushvalue(L, -1); /* push metatable */ + lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */ + luaL_setfuncs(L, flib, 0); /* add file methods to new metatable */ + lua_pop(L, 1); /* pop new metatable */ +} + + +/* +** function to (not) close the standard files stdin, stdout, and stderr +*/ +static int io_noclose (lua_State *L) { + LStream *p = tolstream(L); + p->closef = &io_noclose; /* keep file opened */ + lua_pushnil(L); + lua_pushliteral(L, "cannot close standard file"); + return 2; +} + + +static void createstdfile (lua_State *L, FILE *f, const char *k, + const char *fname) { + LStream *p = newprefile(L); + p->f = f; + p->closef = &io_noclose; + if (k != NULL) { + lua_pushvalue(L, -1); + lua_setfield(L, LUA_REGISTRYINDEX, k); /* add file to registry */ + } + lua_setfield(L, -2, fname); /* add file to module */ +} + + +LUAMOD_API int luaopen_io (lua_State *L) { + luaL_newlib(L, iolib); /* new module */ + createmeta(L); + /* create (and set) default files */ + createstdfile(L, stdin, IO_INPUT, "stdin"); + createstdfile(L, stdout, IO_OUTPUT, "stdout"); + createstdfile(L, stderr, NULL, "stderr"); + return 1; +} + diff --git a/depends/lua/src/llex.c b/depends/lua/src/llex.c new file mode 100644 index 0000000000..b6d9a465fe --- /dev/null +++ b/depends/lua/src/llex.c @@ -0,0 +1,568 @@ +/* +** $Id: llex.c,v 2.96.1.1 2017/04/19 17:20:42 roberto Exp $ +** Lexical Analyzer +** See Copyright Notice in lua.h +*/ + +#define llex_c +#define LUA_CORE + +#include "lprefix.h" + + +#include +#include + +#include "lua.h" + +#include "lctype.h" +#include "ldebug.h" +#include "ldo.h" +#include "lgc.h" +#include "llex.h" +#include "lobject.h" +#include "lparser.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "lzio.h" + + + +#define next(ls) (ls->current = zgetc(ls->z)) + + + +#define currIsNewline(ls) (ls->current == '\n' || ls->current == '\r') + + +/* ORDER RESERVED */ +static const char *const luaX_tokens [] = { + "and", "break", "do", "else", "elseif", + "end", "false", "for", "function", "goto", "if", + "in", "local", "nil", "not", "or", "repeat", + "return", "then", "true", "until", "while", + "//", "..", "...", "==", ">=", "<=", "~=", + "<<", ">>", "::", "", + "", "", "", "" +}; + + +#define save_and_next(ls) (save(ls, ls->current), next(ls)) + + +static l_noret lexerror (LexState *ls, const char *msg, int token); + + +static void save (LexState *ls, int c) { + Mbuffer *b = ls->buff; + if (luaZ_bufflen(b) + 1 > luaZ_sizebuffer(b)) { + size_t newsize; + if (luaZ_sizebuffer(b) >= MAX_SIZE/2) + lexerror(ls, "lexical element too long", 0); + newsize = luaZ_sizebuffer(b) * 2; + luaZ_resizebuffer(ls->L, b, newsize); + } + b->buffer[luaZ_bufflen(b)++] = cast(char, c); +} + + +void luaX_init (lua_State *L) { + int i; + TString *e = luaS_newliteral(L, LUA_ENV); /* create env name */ + luaC_fix(L, obj2gco(e)); /* never collect this name */ + for (i=0; iextra = cast_byte(i+1); /* reserved word */ + } +} + + +const char *luaX_token2str (LexState *ls, int token) { + if (token < FIRST_RESERVED) { /* single-byte symbols? */ + lua_assert(token == cast_uchar(token)); + return luaO_pushfstring(ls->L, "'%c'", token); + } + else { + const char *s = luaX_tokens[token - FIRST_RESERVED]; + if (token < TK_EOS) /* fixed format (symbols and reserved words)? */ + return luaO_pushfstring(ls->L, "'%s'", s); + else /* names, strings, and numerals */ + return s; + } +} + + +static const char *txtToken (LexState *ls, int token) { + switch (token) { + case TK_NAME: case TK_STRING: + case TK_FLT: case TK_INT: + save(ls, '\0'); + return luaO_pushfstring(ls->L, "'%s'", luaZ_buffer(ls->buff)); + default: + return luaX_token2str(ls, token); + } +} + + +static l_noret lexerror (LexState *ls, const char *msg, int token) { + msg = luaG_addinfo(ls->L, msg, ls->source, ls->linenumber); + if (token) + luaO_pushfstring(ls->L, "%s near %s", msg, txtToken(ls, token)); + luaD_throw(ls->L, LUA_ERRSYNTAX); +} + + +l_noret luaX_syntaxerror (LexState *ls, const char *msg) { + lexerror(ls, msg, ls->t.token); +} + + +/* +** creates a new string and anchors it in scanner's table so that +** it will not be collected until the end of the compilation +** (by that time it should be anchored somewhere) +*/ +TString *luaX_newstring (LexState *ls, const char *str, size_t l) { + lua_State *L = ls->L; + TValue *o; /* entry for 'str' */ + TString *ts = luaS_newlstr(L, str, l); /* create new string */ + setsvalue2s(L, L->top++, ts); /* temporarily anchor it in stack */ + o = luaH_set(L, ls->h, L->top - 1); + if (ttisnil(o)) { /* not in use yet? */ + /* boolean value does not need GC barrier; + table has no metatable, so it does not need to invalidate cache */ + setbvalue(o, 1); /* t[string] = true */ + luaC_checkGC(L); + } + else { /* string already present */ + ts = tsvalue(keyfromval(o)); /* re-use value previously stored */ + } + L->top--; /* remove string from stack */ + return ts; +} + + +/* +** increment line number and skips newline sequence (any of +** \n, \r, \n\r, or \r\n) +*/ +static void inclinenumber (LexState *ls) { + int old = ls->current; + lua_assert(currIsNewline(ls)); + next(ls); /* skip '\n' or '\r' */ + if (currIsNewline(ls) && ls->current != old) + next(ls); /* skip '\n\r' or '\r\n' */ + if (++ls->linenumber >= MAX_INT) + lexerror(ls, "chunk has too many lines", 0); +} + + +void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source, + int firstchar) { + ls->t.token = 0; + ls->L = L; + ls->current = firstchar; + ls->lookahead.token = TK_EOS; /* no look-ahead token */ + ls->z = z; + ls->fs = NULL; + ls->linenumber = 1; + ls->lastline = 1; + ls->source = source; + ls->envn = luaS_newliteral(L, LUA_ENV); /* get env name */ + luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER); /* initialize buffer */ +} + + + +/* +** ======================================================= +** LEXICAL ANALYZER +** ======================================================= +*/ + + +static int check_next1 (LexState *ls, int c) { + if (ls->current == c) { + next(ls); + return 1; + } + else return 0; +} + + +/* +** Check whether current char is in set 'set' (with two chars) and +** saves it +*/ +static int check_next2 (LexState *ls, const char *set) { + lua_assert(set[2] == '\0'); + if (ls->current == set[0] || ls->current == set[1]) { + save_and_next(ls); + return 1; + } + else return 0; +} + + +/* LUA_NUMBER */ +/* +** this function is quite liberal in what it accepts, as 'luaO_str2num' +** will reject ill-formed numerals. +*/ +static int read_numeral (LexState *ls, SemInfo *seminfo) { + TValue obj; + const char *expo = "Ee"; + int first = ls->current; + lua_assert(lisdigit(ls->current)); + save_and_next(ls); + if (first == '0' && check_next2(ls, "xX")) /* hexadecimal? */ + expo = "Pp"; + for (;;) { + if (check_next2(ls, expo)) /* exponent part? */ + check_next2(ls, "-+"); /* optional exponent sign */ + if (lisxdigit(ls->current)) + save_and_next(ls); + else if (ls->current == '.') + save_and_next(ls); + else break; + } + save(ls, '\0'); + if (luaO_str2num(luaZ_buffer(ls->buff), &obj) == 0) /* format error? */ + lexerror(ls, "malformed number", TK_FLT); + if (ttisinteger(&obj)) { + seminfo->i = ivalue(&obj); + return TK_INT; + } + else { + lua_assert(ttisfloat(&obj)); + seminfo->r = fltvalue(&obj); + return TK_FLT; + } +} + + +/* +** reads a sequence '[=*[' or ']=*]', leaving the last bracket. +** If sequence is well formed, return its number of '='s + 2; otherwise, +** return 1 if there is no '='s or 0 otherwise (an unfinished '[==...'). +*/ +static size_t skip_sep (LexState *ls) { + size_t count = 0; + int s = ls->current; + lua_assert(s == '[' || s == ']'); + save_and_next(ls); + while (ls->current == '=') { + save_and_next(ls); + count++; + } + return (ls->current == s) ? count + 2 + : (count == 0) ? 1 + : 0; + +} + + +static void read_long_string (LexState *ls, SemInfo *seminfo, size_t sep) { + int line = ls->linenumber; /* initial line (for error message) */ + save_and_next(ls); /* skip 2nd '[' */ + if (currIsNewline(ls)) /* string starts with a newline? */ + inclinenumber(ls); /* skip it */ + for (;;) { + switch (ls->current) { + case EOZ: { /* error */ + const char *what = (seminfo ? "string" : "comment"); + const char *msg = luaO_pushfstring(ls->L, + "unfinished long %s (starting at line %d)", what, line); + lexerror(ls, msg, TK_EOS); + break; /* to avoid warnings */ + } + case ']': { + if (skip_sep(ls) == sep) { + save_and_next(ls); /* skip 2nd ']' */ + goto endloop; + } + break; + } + case '\n': case '\r': { + save(ls, '\n'); + inclinenumber(ls); + if (!seminfo) luaZ_resetbuffer(ls->buff); /* avoid wasting space */ + break; + } + default: { + if (seminfo) save_and_next(ls); + else next(ls); + } + } + } endloop: + if (seminfo) + seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + sep, + luaZ_bufflen(ls->buff) - 2 * sep); +} + + +static void esccheck (LexState *ls, int c, const char *msg) { + if (!c) { + if (ls->current != EOZ) + save_and_next(ls); /* add current to buffer for error message */ + lexerror(ls, msg, TK_STRING); + } +} + + +static int gethexa (LexState *ls) { + save_and_next(ls); + esccheck (ls, lisxdigit(ls->current), "hexadecimal digit expected"); + return luaO_hexavalue(ls->current); +} + + +static int readhexaesc (LexState *ls) { + int r = gethexa(ls); + r = (r << 4) + gethexa(ls); + luaZ_buffremove(ls->buff, 2); /* remove saved chars from buffer */ + return r; +} + + +static unsigned long readutf8esc (LexState *ls) { + unsigned long r; + int i = 4; /* chars to be removed: '\', 'u', '{', and first digit */ + save_and_next(ls); /* skip 'u' */ + esccheck(ls, ls->current == '{', "missing '{'"); + r = gethexa(ls); /* must have at least one digit */ + while ((save_and_next(ls), lisxdigit(ls->current))) { + i++; + r = (r << 4) + luaO_hexavalue(ls->current); + esccheck(ls, r <= 0x10FFFF, "UTF-8 value too large"); + } + esccheck(ls, ls->current == '}', "missing '}'"); + next(ls); /* skip '}' */ + luaZ_buffremove(ls->buff, i); /* remove saved chars from buffer */ + return r; +} + + +static void utf8esc (LexState *ls) { + char buff[UTF8BUFFSZ]; + int n = luaO_utf8esc(buff, readutf8esc(ls)); + for (; n > 0; n--) /* add 'buff' to string */ + save(ls, buff[UTF8BUFFSZ - n]); +} + + +static int readdecesc (LexState *ls) { + int i; + int r = 0; /* result accumulator */ + for (i = 0; i < 3 && lisdigit(ls->current); i++) { /* read up to 3 digits */ + r = 10*r + ls->current - '0'; + save_and_next(ls); + } + esccheck(ls, r <= UCHAR_MAX, "decimal escape too large"); + luaZ_buffremove(ls->buff, i); /* remove read digits from buffer */ + return r; +} + + +static void read_string (LexState *ls, int del, SemInfo *seminfo) { + save_and_next(ls); /* keep delimiter (for error messages) */ + while (ls->current != del) { + switch (ls->current) { + case EOZ: + lexerror(ls, "unfinished string", TK_EOS); + break; /* to avoid warnings */ + case '\n': + case '\r': + lexerror(ls, "unfinished string", TK_STRING); + break; /* to avoid warnings */ + case '\\': { /* escape sequences */ + int c; /* final character to be saved */ + save_and_next(ls); /* keep '\\' for error messages */ + switch (ls->current) { + case 'a': c = '\a'; goto read_save; + case 'b': c = '\b'; goto read_save; + case 'f': c = '\f'; goto read_save; + case 'n': c = '\n'; goto read_save; + case 'r': c = '\r'; goto read_save; + case 't': c = '\t'; goto read_save; + case 'v': c = '\v'; goto read_save; + case 'x': c = readhexaesc(ls); goto read_save; + case 'u': utf8esc(ls); goto no_save; + case '\n': case '\r': + inclinenumber(ls); c = '\n'; goto only_save; + case '\\': case '\"': case '\'': + c = ls->current; goto read_save; + case EOZ: goto no_save; /* will raise an error next loop */ + case 'z': { /* zap following span of spaces */ + luaZ_buffremove(ls->buff, 1); /* remove '\\' */ + next(ls); /* skip the 'z' */ + while (lisspace(ls->current)) { + if (currIsNewline(ls)) inclinenumber(ls); + else next(ls); + } + goto no_save; + } + default: { + esccheck(ls, lisdigit(ls->current), "invalid escape sequence"); + c = readdecesc(ls); /* digital escape '\ddd' */ + goto only_save; + } + } + read_save: + next(ls); + /* go through */ + only_save: + luaZ_buffremove(ls->buff, 1); /* remove '\\' */ + save(ls, c); + /* go through */ + no_save: break; + } + default: + save_and_next(ls); + } + } + save_and_next(ls); /* skip delimiter */ + seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + 1, + luaZ_bufflen(ls->buff) - 2); +} + + +static int llex (LexState *ls, SemInfo *seminfo) { + luaZ_resetbuffer(ls->buff); + for (;;) { + switch (ls->current) { + case '\n': case '\r': { /* line breaks */ + inclinenumber(ls); + break; + } + case ' ': case '\f': case '\t': case '\v': { /* spaces */ + next(ls); + break; + } + case '-': { /* '-' or '--' (comment) */ + next(ls); + if (ls->current != '-') return '-'; + /* else is a comment */ + next(ls); + if (ls->current == '[') { /* long comment? */ + size_t sep = skip_sep(ls); + luaZ_resetbuffer(ls->buff); /* 'skip_sep' may dirty the buffer */ + if (sep >= 2) { + read_long_string(ls, NULL, sep); /* skip long comment */ + luaZ_resetbuffer(ls->buff); /* previous call may dirty the buff. */ + break; + } + } + /* else short comment */ + while (!currIsNewline(ls) && ls->current != EOZ) + next(ls); /* skip until end of line (or end of file) */ + break; + } + case '[': { /* long string or simply '[' */ + size_t sep = skip_sep(ls); + if (sep >= 2) { + read_long_string(ls, seminfo, sep); + return TK_STRING; + } + else if (sep == 0) /* '[=...' missing second bracket */ + lexerror(ls, "invalid long string delimiter", TK_STRING); + return '['; + } + case '=': { + next(ls); + if (check_next1(ls, '=')) return TK_EQ; + else return '='; + } + case '<': { + next(ls); + if (check_next1(ls, '=')) return TK_LE; + else if (check_next1(ls, '<')) return TK_SHL; + else return '<'; + } + case '>': { + next(ls); + if (check_next1(ls, '=')) return TK_GE; + else if (check_next1(ls, '>')) return TK_SHR; + else return '>'; + } + case '/': { + next(ls); + if (check_next1(ls, '/')) return TK_IDIV; + else return '/'; + } + case '~': { + next(ls); + if (check_next1(ls, '=')) return TK_NE; + else return '~'; + } + case ':': { + next(ls); + if (check_next1(ls, ':')) return TK_DBCOLON; + else return ':'; + } + case '"': case '\'': { /* short literal strings */ + read_string(ls, ls->current, seminfo); + return TK_STRING; + } + case '.': { /* '.', '..', '...', or number */ + save_and_next(ls); + if (check_next1(ls, '.')) { + if (check_next1(ls, '.')) + return TK_DOTS; /* '...' */ + else return TK_CONCAT; /* '..' */ + } + else if (!lisdigit(ls->current)) return '.'; + else return read_numeral(ls, seminfo); + } + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': { + return read_numeral(ls, seminfo); + } + case EOZ: { + return TK_EOS; + } + default: { + if (lislalpha(ls->current)) { /* identifier or reserved word? */ + TString *ts; + do { + save_and_next(ls); + } while (lislalnum(ls->current)); + ts = luaX_newstring(ls, luaZ_buffer(ls->buff), + luaZ_bufflen(ls->buff)); + seminfo->ts = ts; + if (isreserved(ts)) /* reserved word? */ + return ts->extra - 1 + FIRST_RESERVED; + else { + return TK_NAME; + } + } + else { /* single-char tokens (+ - / ...) */ + int c = ls->current; + next(ls); + return c; + } + } + } + } +} + + +void luaX_next (LexState *ls) { + ls->lastline = ls->linenumber; + if (ls->lookahead.token != TK_EOS) { /* is there a look-ahead token? */ + ls->t = ls->lookahead; /* use this one */ + ls->lookahead.token = TK_EOS; /* and discharge it */ + } + else + ls->t.token = llex(ls, &ls->t.seminfo); /* read next token */ +} + + +int luaX_lookahead (LexState *ls) { + lua_assert(ls->lookahead.token == TK_EOS); + ls->lookahead.token = llex(ls, &ls->lookahead.seminfo); + return ls->lookahead.token; +} + diff --git a/depends/lua/src/lmathlib.c b/depends/lua/src/lmathlib.c new file mode 100644 index 0000000000..7ef7e593fd --- /dev/null +++ b/depends/lua/src/lmathlib.c @@ -0,0 +1,410 @@ +/* +** $Id: lmathlib.c,v 1.119.1.1 2017/04/19 17:20:42 roberto Exp $ +** Standard mathematical library +** See Copyright Notice in lua.h +*/ + +#define lmathlib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include +#include + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +#undef PI +#define PI (l_mathop(3.141592653589793238462643383279502884)) + + +#if !defined(l_rand) /* { */ +#if defined(LUA_USE_POSIX) +#define l_rand() random() +#define l_srand(x) srandom(x) +#define L_RANDMAX 2147483647 /* (2^31 - 1), following POSIX */ +#else +#define l_rand() rand() +#define l_srand(x) srand(x) +#define L_RANDMAX RAND_MAX +#endif +#endif /* } */ + + +static int math_abs (lua_State *L) { + if (lua_isinteger(L, 1)) { + lua_Integer n = lua_tointeger(L, 1); + if (n < 0) n = (lua_Integer)(0u - (lua_Unsigned)n); + lua_pushinteger(L, n); + } + else + lua_pushnumber(L, l_mathop(fabs)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_sin (lua_State *L) { + lua_pushnumber(L, l_mathop(sin)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_cos (lua_State *L) { + lua_pushnumber(L, l_mathop(cos)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_tan (lua_State *L) { + lua_pushnumber(L, l_mathop(tan)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_asin (lua_State *L) { + lua_pushnumber(L, l_mathop(asin)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_acos (lua_State *L) { + lua_pushnumber(L, l_mathop(acos)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_atan (lua_State *L) { + lua_Number y = luaL_checknumber(L, 1); + lua_Number x = luaL_optnumber(L, 2, 1); + lua_pushnumber(L, l_mathop(atan2)(y, x)); + return 1; +} + + +static int math_toint (lua_State *L) { + int valid; + lua_Integer n = lua_tointegerx(L, 1, &valid); + if (valid) + lua_pushinteger(L, n); + else { + luaL_checkany(L, 1); + lua_pushnil(L); /* value is not convertible to integer */ + } + return 1; +} + + +static void pushnumint (lua_State *L, lua_Number d) { + lua_Integer n; + if (lua_numbertointeger(d, &n)) /* does 'd' fit in an integer? */ + lua_pushinteger(L, n); /* result is integer */ + else + lua_pushnumber(L, d); /* result is float */ +} + + +static int math_floor (lua_State *L) { + if (lua_isinteger(L, 1)) + lua_settop(L, 1); /* integer is its own floor */ + else { + lua_Number d = l_mathop(floor)(luaL_checknumber(L, 1)); + pushnumint(L, d); + } + return 1; +} + + +static int math_ceil (lua_State *L) { + if (lua_isinteger(L, 1)) + lua_settop(L, 1); /* integer is its own ceil */ + else { + lua_Number d = l_mathop(ceil)(luaL_checknumber(L, 1)); + pushnumint(L, d); + } + return 1; +} + + +static int math_fmod (lua_State *L) { + if (lua_isinteger(L, 1) && lua_isinteger(L, 2)) { + lua_Integer d = lua_tointeger(L, 2); + if ((lua_Unsigned)d + 1u <= 1u) { /* special cases: -1 or 0 */ + luaL_argcheck(L, d != 0, 2, "zero"); + lua_pushinteger(L, 0); /* avoid overflow with 0x80000... / -1 */ + } + else + lua_pushinteger(L, lua_tointeger(L, 1) % d); + } + else + lua_pushnumber(L, l_mathop(fmod)(luaL_checknumber(L, 1), + luaL_checknumber(L, 2))); + return 1; +} + + +/* +** next function does not use 'modf', avoiding problems with 'double*' +** (which is not compatible with 'float*') when lua_Number is not +** 'double'. +*/ +static int math_modf (lua_State *L) { + if (lua_isinteger(L ,1)) { + lua_settop(L, 1); /* number is its own integer part */ + lua_pushnumber(L, 0); /* no fractional part */ + } + else { + lua_Number n = luaL_checknumber(L, 1); + /* integer part (rounds toward zero) */ + lua_Number ip = (n < 0) ? l_mathop(ceil)(n) : l_mathop(floor)(n); + pushnumint(L, ip); + /* fractional part (test needed for inf/-inf) */ + lua_pushnumber(L, (n == ip) ? l_mathop(0.0) : (n - ip)); + } + return 2; +} + + +static int math_sqrt (lua_State *L) { + lua_pushnumber(L, l_mathop(sqrt)(luaL_checknumber(L, 1))); + return 1; +} + + +static int math_ult (lua_State *L) { + lua_Integer a = luaL_checkinteger(L, 1); + lua_Integer b = luaL_checkinteger(L, 2); + lua_pushboolean(L, (lua_Unsigned)a < (lua_Unsigned)b); + return 1; +} + +static int math_log (lua_State *L) { + lua_Number x = luaL_checknumber(L, 1); + lua_Number res; + if (lua_isnoneornil(L, 2)) + res = l_mathop(log)(x); + else { + lua_Number base = luaL_checknumber(L, 2); +#if !defined(LUA_USE_C89) + if (base == l_mathop(2.0)) + res = l_mathop(log2)(x); else +#endif + if (base == l_mathop(10.0)) + res = l_mathop(log10)(x); + else + res = l_mathop(log)(x)/l_mathop(log)(base); + } + lua_pushnumber(L, res); + return 1; +} + +static int math_exp (lua_State *L) { + lua_pushnumber(L, l_mathop(exp)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_deg (lua_State *L) { + lua_pushnumber(L, luaL_checknumber(L, 1) * (l_mathop(180.0) / PI)); + return 1; +} + +static int math_rad (lua_State *L) { + lua_pushnumber(L, luaL_checknumber(L, 1) * (PI / l_mathop(180.0))); + return 1; +} + + +static int math_min (lua_State *L) { + int n = lua_gettop(L); /* number of arguments */ + int imin = 1; /* index of current minimum value */ + int i; + luaL_argcheck(L, n >= 1, 1, "value expected"); + for (i = 2; i <= n; i++) { + if (lua_compare(L, i, imin, LUA_OPLT)) + imin = i; + } + lua_pushvalue(L, imin); + return 1; +} + + +static int math_max (lua_State *L) { + int n = lua_gettop(L); /* number of arguments */ + int imax = 1; /* index of current maximum value */ + int i; + luaL_argcheck(L, n >= 1, 1, "value expected"); + for (i = 2; i <= n; i++) { + if (lua_compare(L, imax, i, LUA_OPLT)) + imax = i; + } + lua_pushvalue(L, imax); + return 1; +} + +/* +** This function uses 'double' (instead of 'lua_Number') to ensure that +** all bits from 'l_rand' can be represented, and that 'RANDMAX + 1.0' +** will keep full precision (ensuring that 'r' is always less than 1.0.) +*/ +static int math_random (lua_State *L) { + lua_Integer low, up; + double r = (double)l_rand() * (1.0 / ((double)L_RANDMAX + 1.0)); + switch (lua_gettop(L)) { /* check number of arguments */ + case 0: { /* no arguments */ + lua_pushnumber(L, (lua_Number)r); /* Number between 0 and 1 */ + return 1; + } + case 1: { /* only upper limit */ + low = 1; + up = luaL_checkinteger(L, 1); + break; + } + case 2: { /* lower and upper limits */ + low = luaL_checkinteger(L, 1); + up = luaL_checkinteger(L, 2); + break; + } + default: return luaL_error(L, "wrong number of arguments"); + } + /* random integer in the interval [low, up] */ + luaL_argcheck(L, low <= up, 1, "interval is empty"); + luaL_argcheck(L, low >= 0 || up <= LUA_MAXINTEGER + low, 1, + "interval too large"); + r *= (double)(up - low) + 1.0; + lua_pushinteger(L, (lua_Integer)r + low); + return 1; +} + + +static int math_randomseed (lua_State *L) { + l_srand((unsigned int)(lua_Integer)luaL_checknumber(L, 1)); + (void)l_rand(); /* discard first value to avoid undesirable correlations */ + return 0; +} + + +static int math_type (lua_State *L) { + if (lua_type(L, 1) == LUA_TNUMBER) { + if (lua_isinteger(L, 1)) + lua_pushliteral(L, "integer"); + else + lua_pushliteral(L, "float"); + } + else { + luaL_checkany(L, 1); + lua_pushnil(L); + } + return 1; +} + + +/* +** {================================================================== +** Deprecated functions (for compatibility only) +** =================================================================== +*/ +#if defined(LUA_COMPAT_MATHLIB) + +static int math_cosh (lua_State *L) { + lua_pushnumber(L, l_mathop(cosh)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_sinh (lua_State *L) { + lua_pushnumber(L, l_mathop(sinh)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_tanh (lua_State *L) { + lua_pushnumber(L, l_mathop(tanh)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_pow (lua_State *L) { + lua_Number x = luaL_checknumber(L, 1); + lua_Number y = luaL_checknumber(L, 2); + lua_pushnumber(L, l_mathop(pow)(x, y)); + return 1; +} + +static int math_frexp (lua_State *L) { + int e; + lua_pushnumber(L, l_mathop(frexp)(luaL_checknumber(L, 1), &e)); + lua_pushinteger(L, e); + return 2; +} + +static int math_ldexp (lua_State *L) { + lua_Number x = luaL_checknumber(L, 1); + int ep = (int)luaL_checkinteger(L, 2); + lua_pushnumber(L, l_mathop(ldexp)(x, ep)); + return 1; +} + +static int math_log10 (lua_State *L) { + lua_pushnumber(L, l_mathop(log10)(luaL_checknumber(L, 1))); + return 1; +} + +#endif +/* }================================================================== */ + + + +static const luaL_Reg mathlib[] = { + {"abs", math_abs}, + {"acos", math_acos}, + {"asin", math_asin}, + {"atan", math_atan}, + {"ceil", math_ceil}, + {"cos", math_cos}, + {"deg", math_deg}, + {"exp", math_exp}, + {"tointeger", math_toint}, + {"floor", math_floor}, + {"fmod", math_fmod}, + {"ult", math_ult}, + {"log", math_log}, + {"max", math_max}, + {"min", math_min}, + {"modf", math_modf}, + {"rad", math_rad}, + {"random", math_random}, + {"randomseed", math_randomseed}, + {"sin", math_sin}, + {"sqrt", math_sqrt}, + {"tan", math_tan}, + {"type", math_type}, +#if defined(LUA_COMPAT_MATHLIB) + {"atan2", math_atan}, + {"cosh", math_cosh}, + {"sinh", math_sinh}, + {"tanh", math_tanh}, + {"pow", math_pow}, + {"frexp", math_frexp}, + {"ldexp", math_ldexp}, + {"log10", math_log10}, +#endif + /* placeholders */ + {"pi", NULL}, + {"huge", NULL}, + {"maxinteger", NULL}, + {"mininteger", NULL}, + {NULL, NULL} +}; + + +/* +** Open math library +*/ +LUAMOD_API int luaopen_math (lua_State *L) { + luaL_newlib(L, mathlib); + lua_pushnumber(L, PI); + lua_setfield(L, -2, "pi"); + lua_pushnumber(L, (lua_Number)HUGE_VAL); + lua_setfield(L, -2, "huge"); + lua_pushinteger(L, LUA_MAXINTEGER); + lua_setfield(L, -2, "maxinteger"); + lua_pushinteger(L, LUA_MININTEGER); + lua_setfield(L, -2, "mininteger"); + return 1; +} + diff --git a/depends/lua/src/lmem.c b/depends/lua/src/lmem.c new file mode 100644 index 0000000000..0241cc3bac --- /dev/null +++ b/depends/lua/src/lmem.c @@ -0,0 +1,100 @@ +/* +** $Id: lmem.c,v 1.91.1.1 2017/04/19 17:20:42 roberto Exp $ +** Interface to Memory Manager +** See Copyright Notice in lua.h +*/ + +#define lmem_c +#define LUA_CORE + +#include "lprefix.h" + + +#include + +#include "lua.h" + +#include "ldebug.h" +#include "ldo.h" +#include "lgc.h" +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" + + + +/* +** About the realloc function: +** void * frealloc (void *ud, void *ptr, size_t osize, size_t nsize); +** ('osize' is the old size, 'nsize' is the new size) +** +** * frealloc(ud, NULL, x, s) creates a new block of size 's' (no +** matter 'x'). +** +** * frealloc(ud, p, x, 0) frees the block 'p' +** (in this specific case, frealloc must return NULL); +** particularly, frealloc(ud, NULL, 0, 0) does nothing +** (which is equivalent to free(NULL) in ISO C) +** +** frealloc returns NULL if it cannot create or reallocate the area +** (any reallocation to an equal or smaller size cannot fail!) +*/ + + + +#define MINSIZEARRAY 4 + + +void *luaM_growaux_ (lua_State *L, void *block, int *size, size_t size_elems, + int limit, const char *what) { + void *newblock; + int newsize; + if (*size >= limit/2) { /* cannot double it? */ + if (*size >= limit) /* cannot grow even a little? */ + luaG_runerror(L, "too many %s (limit is %d)", what, limit); + newsize = limit; /* still have at least one free place */ + } + else { + newsize = (*size)*2; + if (newsize < MINSIZEARRAY) + newsize = MINSIZEARRAY; /* minimum size */ + } + newblock = luaM_reallocv(L, block, *size, newsize, size_elems); + *size = newsize; /* update only when everything else is OK */ + return newblock; +} + + +l_noret luaM_toobig (lua_State *L) { + luaG_runerror(L, "memory allocation error: block too big"); +} + + + +/* +** generic allocation routine. +*/ +void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { + void *newblock; + global_State *g = G(L); + size_t realosize = (block) ? osize : 0; + lua_assert((realosize == 0) == (block == NULL)); +#if defined(HARDMEMTESTS) + if (nsize > realosize && g->gcrunning) + luaC_fullgc(L, 1); /* force a GC whenever possible */ +#endif + newblock = (*g->frealloc)(g->ud, block, osize, nsize); + if (newblock == NULL && nsize > 0) { + lua_assert(nsize > realosize); /* cannot fail when shrinking a block */ + if (g->version) { /* is state fully built? */ + luaC_fullgc(L, 1); /* try to free some memory... */ + newblock = (*g->frealloc)(g->ud, block, osize, nsize); /* try again */ + } + if (newblock == NULL) + luaD_throw(L, LUA_ERRMEM); + } + lua_assert((nsize == 0) == (newblock == NULL)); + g->GCdebt = (g->GCdebt + nsize) - realosize; + return newblock; +} + diff --git a/depends/lua/src/loadlib.c b/depends/lua/src/loadlib.c new file mode 100644 index 0000000000..45f44d3225 --- /dev/null +++ b/depends/lua/src/loadlib.c @@ -0,0 +1,790 @@ +/* +** $Id: loadlib.c,v 1.130.1.1 2017/04/19 17:20:42 roberto Exp $ +** Dynamic library loader for Lua +** See Copyright Notice in lua.h +** +** This module contains an implementation of loadlib for Unix systems +** that have dlfcn, an implementation for Windows, and a stub for other +** systems. +*/ + +#define loadlib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include +#include +#include + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +/* +** LUA_IGMARK is a mark to ignore all before it when building the +** luaopen_ function name. +*/ +#if !defined (LUA_IGMARK) +#define LUA_IGMARK "-" +#endif + + +/* +** LUA_CSUBSEP is the character that replaces dots in submodule names +** when searching for a C loader. +** LUA_LSUBSEP is the character that replaces dots in submodule names +** when searching for a Lua loader. +*/ +#if !defined(LUA_CSUBSEP) +#define LUA_CSUBSEP LUA_DIRSEP +#endif + +#if !defined(LUA_LSUBSEP) +#define LUA_LSUBSEP LUA_DIRSEP +#endif + + +/* prefix for open functions in C libraries */ +#define LUA_POF "luaopen_" + +/* separator for open functions in C libraries */ +#define LUA_OFSEP "_" + + +/* +** unique key for table in the registry that keeps handles +** for all loaded C libraries +*/ +static const int CLIBS = 0; + +#define LIB_FAIL "open" + + +#define setprogdir(L) ((void)0) + + +/* +** system-dependent functions +*/ + +/* +** unload library 'lib' +*/ +static void lsys_unloadlib (void *lib); + +/* +** load C library in file 'path'. If 'seeglb', load with all names in +** the library global. +** Returns the library; in case of error, returns NULL plus an +** error string in the stack. +*/ +static void *lsys_load (lua_State *L, const char *path, int seeglb); + +/* +** Try to find a function named 'sym' in library 'lib'. +** Returns the function; in case of error, returns NULL plus an +** error string in the stack. +*/ +static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym); + + + + +#if defined(LUA_USE_DLOPEN) /* { */ +/* +** {======================================================================== +** This is an implementation of loadlib based on the dlfcn interface. +** The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD, +** NetBSD, AIX 4.2, HPUX 11, and probably most other Unix flavors, at least +** as an emulation layer on top of native functions. +** ========================================================================= +*/ + +#include + +/* +** Macro to convert pointer-to-void* to pointer-to-function. This cast +** is undefined according to ISO C, but POSIX assumes that it works. +** (The '__extension__' in gnu compilers is only to avoid warnings.) +*/ +#if defined(__GNUC__) +#define cast_func(p) (__extension__ (lua_CFunction)(p)) +#else +#define cast_func(p) ((lua_CFunction)(p)) +#endif + + +static void lsys_unloadlib (void *lib) { + dlclose(lib); +} + + +static void *lsys_load (lua_State *L, const char *path, int seeglb) { + void *lib = dlopen(path, RTLD_NOW | (seeglb ? RTLD_GLOBAL : RTLD_LOCAL)); + if (lib == NULL) lua_pushstring(L, dlerror()); + return lib; +} + + +static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) { + lua_CFunction f = cast_func(dlsym(lib, sym)); + if (f == NULL) lua_pushstring(L, dlerror()); + return f; +} + +/* }====================================================== */ + + + +#elif defined(LUA_DL_DLL) /* }{ */ +/* +** {====================================================================== +** This is an implementation of loadlib for Windows using native functions. +** ======================================================================= +*/ + +#include + + +/* +** optional flags for LoadLibraryEx +*/ +#if !defined(LUA_LLE_FLAGS) +#define LUA_LLE_FLAGS 0 +#endif + + +#undef setprogdir + + +/* +** Replace in the path (on the top of the stack) any occurrence +** of LUA_EXEC_DIR with the executable's path. +*/ +static void setprogdir (lua_State *L) { + char buff[MAX_PATH + 1]; + char *lb; + DWORD nsize = sizeof(buff)/sizeof(char); + DWORD n = GetModuleFileNameA(NULL, buff, nsize); /* get exec. name */ + if (n == 0 || n == nsize || (lb = strrchr(buff, '\\')) == NULL) + luaL_error(L, "unable to get ModuleFileName"); + else { + *lb = '\0'; /* cut name on the last '\\' to get the path */ + luaL_gsub(L, lua_tostring(L, -1), LUA_EXEC_DIR, buff); + lua_remove(L, -2); /* remove original string */ + } +} + + + + +static void pusherror (lua_State *L) { + int error = GetLastError(); + char buffer[128]; + if (FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, error, 0, buffer, sizeof(buffer)/sizeof(char), NULL)) + lua_pushstring(L, buffer); + else + lua_pushfstring(L, "system error %d\n", error); +} + +static void lsys_unloadlib (void *lib) { + FreeLibrary((HMODULE)lib); +} + + +static void *lsys_load (lua_State *L, const char *path, int seeglb) { + HMODULE lib = LoadLibraryExA(path, NULL, LUA_LLE_FLAGS); + (void)(seeglb); /* not used: symbols are 'global' by default */ + if (lib == NULL) pusherror(L); + return lib; +} + + +static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) { + lua_CFunction f = (lua_CFunction)GetProcAddress((HMODULE)lib, sym); + if (f == NULL) pusherror(L); + return f; +} + +/* }====================================================== */ + + +#else /* }{ */ +/* +** {====================================================== +** Fallback for other systems +** ======================================================= +*/ + +#undef LIB_FAIL +#define LIB_FAIL "absent" + + +#define DLMSG "dynamic libraries not enabled; check your Lua installation" + + +static void lsys_unloadlib (void *lib) { + (void)(lib); /* not used */ +} + + +static void *lsys_load (lua_State *L, const char *path, int seeglb) { + (void)(path); (void)(seeglb); /* not used */ + lua_pushliteral(L, DLMSG); + return NULL; +} + + +static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) { + (void)(lib); (void)(sym); /* not used */ + lua_pushliteral(L, DLMSG); + return NULL; +} + +/* }====================================================== */ +#endif /* } */ + + +/* +** {================================================================== +** Set Paths +** =================================================================== +*/ + +/* +** LUA_PATH_VAR and LUA_CPATH_VAR are the names of the environment +** variables that Lua check to set its paths. +*/ +#if !defined(LUA_PATH_VAR) +#define LUA_PATH_VAR "LUA_PATH" +#endif + +#if !defined(LUA_CPATH_VAR) +#define LUA_CPATH_VAR "LUA_CPATH" +#endif + + +#define AUXMARK "\1" /* auxiliary mark */ + + +/* +** return registry.LUA_NOENV as a boolean +*/ +static int noenv (lua_State *L) { + int b; + lua_getfield(L, LUA_REGISTRYINDEX, "LUA_NOENV"); + b = lua_toboolean(L, -1); + lua_pop(L, 1); /* remove value */ + return b; +} + + +/* +** Set a path +*/ +static void setpath (lua_State *L, const char *fieldname, + const char *envname, + const char *dft) { + const char *nver = lua_pushfstring(L, "%s%s", envname, LUA_VERSUFFIX); + const char *path = getenv(nver); /* use versioned name */ + if (path == NULL) /* no environment variable? */ + path = getenv(envname); /* try unversioned name */ + if (path == NULL || noenv(L)) /* no environment variable? */ + lua_pushstring(L, dft); /* use default */ + else { + /* replace ";;" by ";AUXMARK;" and then AUXMARK by default path */ + path = luaL_gsub(L, path, LUA_PATH_SEP LUA_PATH_SEP, + LUA_PATH_SEP AUXMARK LUA_PATH_SEP); + luaL_gsub(L, path, AUXMARK, dft); + lua_remove(L, -2); /* remove result from 1st 'gsub' */ + } + setprogdir(L); + lua_setfield(L, -3, fieldname); /* package[fieldname] = path value */ + lua_pop(L, 1); /* pop versioned variable name */ +} + +/* }================================================================== */ + + +/* +** return registry.CLIBS[path] +*/ +static void *checkclib (lua_State *L, const char *path) { + void *plib; + lua_rawgetp(L, LUA_REGISTRYINDEX, &CLIBS); + lua_getfield(L, -1, path); + plib = lua_touserdata(L, -1); /* plib = CLIBS[path] */ + lua_pop(L, 2); /* pop CLIBS table and 'plib' */ + return plib; +} + + +/* +** registry.CLIBS[path] = plib -- for queries +** registry.CLIBS[#CLIBS + 1] = plib -- also keep a list of all libraries +*/ +static void addtoclib (lua_State *L, const char *path, void *plib) { + lua_rawgetp(L, LUA_REGISTRYINDEX, &CLIBS); + lua_pushlightuserdata(L, plib); + lua_pushvalue(L, -1); + lua_setfield(L, -3, path); /* CLIBS[path] = plib */ + lua_rawseti(L, -2, luaL_len(L, -2) + 1); /* CLIBS[#CLIBS + 1] = plib */ + lua_pop(L, 1); /* pop CLIBS table */ +} + + +/* +** __gc tag method for CLIBS table: calls 'lsys_unloadlib' for all lib +** handles in list CLIBS +*/ +static int gctm (lua_State *L) { + lua_Integer n = luaL_len(L, 1); + for (; n >= 1; n--) { /* for each handle, in reverse order */ + lua_rawgeti(L, 1, n); /* get handle CLIBS[n] */ + lsys_unloadlib(lua_touserdata(L, -1)); + lua_pop(L, 1); /* pop handle */ + } + return 0; +} + + + +/* error codes for 'lookforfunc' */ +#define ERRLIB 1 +#define ERRFUNC 2 + +/* +** Look for a C function named 'sym' in a dynamically loaded library +** 'path'. +** First, check whether the library is already loaded; if not, try +** to load it. +** Then, if 'sym' is '*', return true (as library has been loaded). +** Otherwise, look for symbol 'sym' in the library and push a +** C function with that symbol. +** Return 0 and 'true' or a function in the stack; in case of +** errors, return an error code and an error message in the stack. +*/ +static int lookforfunc (lua_State *L, const char *path, const char *sym) { + void *reg = checkclib(L, path); /* check loaded C libraries */ + if (reg == NULL) { /* must load library? */ + reg = lsys_load(L, path, *sym == '*'); /* global symbols if 'sym'=='*' */ + if (reg == NULL) return ERRLIB; /* unable to load library */ + addtoclib(L, path, reg); + } + if (*sym == '*') { /* loading only library (no function)? */ + lua_pushboolean(L, 1); /* return 'true' */ + return 0; /* no errors */ + } + else { + lua_CFunction f = lsys_sym(L, reg, sym); + if (f == NULL) + return ERRFUNC; /* unable to find function */ + lua_pushcfunction(L, f); /* else create new function */ + return 0; /* no errors */ + } +} + + +static int ll_loadlib (lua_State *L) { + const char *path = luaL_checkstring(L, 1); + const char *init = luaL_checkstring(L, 2); + int stat = lookforfunc(L, path, init); + if (stat == 0) /* no errors? */ + return 1; /* return the loaded function */ + else { /* error; error message is on stack top */ + lua_pushnil(L); + lua_insert(L, -2); + lua_pushstring(L, (stat == ERRLIB) ? LIB_FAIL : "init"); + return 3; /* return nil, error message, and where */ + } +} + + + +/* +** {====================================================== +** 'require' function +** ======================================================= +*/ + + +static int readable (const char *filename) { + FILE *f = fopen(filename, "r"); /* try to open file */ + if (f == NULL) return 0; /* open failed */ + fclose(f); + return 1; +} + + +static const char *pushnexttemplate (lua_State *L, const char *path) { + const char *l; + while (*path == *LUA_PATH_SEP) path++; /* skip separators */ + if (*path == '\0') return NULL; /* no more templates */ + l = strchr(path, *LUA_PATH_SEP); /* find next separator */ + if (l == NULL) l = path + strlen(path); + lua_pushlstring(L, path, l - path); /* template */ + return l; +} + + +static const char *searchpath (lua_State *L, const char *name, + const char *path, + const char *sep, + const char *dirsep) { + luaL_Buffer msg; /* to build error message */ + luaL_buffinit(L, &msg); + if (*sep != '\0') /* non-empty separator? */ + name = luaL_gsub(L, name, sep, dirsep); /* replace it by 'dirsep' */ + while ((path = pushnexttemplate(L, path)) != NULL) { + const char *filename = luaL_gsub(L, lua_tostring(L, -1), + LUA_PATH_MARK, name); + lua_remove(L, -2); /* remove path template */ + if (readable(filename)) /* does file exist and is readable? */ + return filename; /* return that file name */ + lua_pushfstring(L, "\n\tno file '%s'", filename); + lua_remove(L, -2); /* remove file name */ + luaL_addvalue(&msg); /* concatenate error msg. entry */ + } + luaL_pushresult(&msg); /* create error message */ + return NULL; /* not found */ +} + + +static int ll_searchpath (lua_State *L) { + const char *f = searchpath(L, luaL_checkstring(L, 1), + luaL_checkstring(L, 2), + luaL_optstring(L, 3, "."), + luaL_optstring(L, 4, LUA_DIRSEP)); + if (f != NULL) return 1; + else { /* error message is on top of the stack */ + lua_pushnil(L); + lua_insert(L, -2); + return 2; /* return nil + error message */ + } +} + + +static const char *findfile (lua_State *L, const char *name, + const char *pname, + const char *dirsep) { + const char *path; + lua_getfield(L, lua_upvalueindex(1), pname); + path = lua_tostring(L, -1); + if (path == NULL) + luaL_error(L, "'package.%s' must be a string", pname); + return searchpath(L, name, path, ".", dirsep); +} + + +static int checkload (lua_State *L, int stat, const char *filename) { + if (stat) { /* module loaded successfully? */ + lua_pushstring(L, filename); /* will be 2nd argument to module */ + return 2; /* return open function and file name */ + } + else + return luaL_error(L, "error loading module '%s' from file '%s':\n\t%s", + lua_tostring(L, 1), filename, lua_tostring(L, -1)); +} + + +static int searcher_Lua (lua_State *L) { + const char *filename; + const char *name = luaL_checkstring(L, 1); + filename = findfile(L, name, "path", LUA_LSUBSEP); + if (filename == NULL) return 1; /* module not found in this path */ + return checkload(L, (luaL_loadfile(L, filename) == LUA_OK), filename); +} + + +/* +** Try to find a load function for module 'modname' at file 'filename'. +** First, change '.' to '_' in 'modname'; then, if 'modname' has +** the form X-Y (that is, it has an "ignore mark"), build a function +** name "luaopen_X" and look for it. (For compatibility, if that +** fails, it also tries "luaopen_Y".) If there is no ignore mark, +** look for a function named "luaopen_modname". +*/ +static int loadfunc (lua_State *L, const char *filename, const char *modname) { + const char *openfunc; + const char *mark; + modname = luaL_gsub(L, modname, ".", LUA_OFSEP); + mark = strchr(modname, *LUA_IGMARK); + if (mark) { + int stat; + openfunc = lua_pushlstring(L, modname, mark - modname); + openfunc = lua_pushfstring(L, LUA_POF"%s", openfunc); + stat = lookforfunc(L, filename, openfunc); + if (stat != ERRFUNC) return stat; + modname = mark + 1; /* else go ahead and try old-style name */ + } + openfunc = lua_pushfstring(L, LUA_POF"%s", modname); + return lookforfunc(L, filename, openfunc); +} + + +static int searcher_C (lua_State *L) { + const char *name = luaL_checkstring(L, 1); + const char *filename = findfile(L, name, "cpath", LUA_CSUBSEP); + if (filename == NULL) return 1; /* module not found in this path */ + return checkload(L, (loadfunc(L, filename, name) == 0), filename); +} + + +static int searcher_Croot (lua_State *L) { + const char *filename; + const char *name = luaL_checkstring(L, 1); + const char *p = strchr(name, '.'); + int stat; + if (p == NULL) return 0; /* is root */ + lua_pushlstring(L, name, p - name); + filename = findfile(L, lua_tostring(L, -1), "cpath", LUA_CSUBSEP); + if (filename == NULL) return 1; /* root not found */ + if ((stat = loadfunc(L, filename, name)) != 0) { + if (stat != ERRFUNC) + return checkload(L, 0, filename); /* real error */ + else { /* open function not found */ + lua_pushfstring(L, "\n\tno module '%s' in file '%s'", name, filename); + return 1; + } + } + lua_pushstring(L, filename); /* will be 2nd argument to module */ + return 2; +} + + +static int searcher_preload (lua_State *L) { + const char *name = luaL_checkstring(L, 1); + lua_getfield(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE); + if (lua_getfield(L, -1, name) == LUA_TNIL) /* not found? */ + lua_pushfstring(L, "\n\tno field package.preload['%s']", name); + return 1; +} + + +static void findloader (lua_State *L, const char *name) { + int i; + luaL_Buffer msg; /* to build error message */ + luaL_buffinit(L, &msg); + /* push 'package.searchers' to index 3 in the stack */ + if (lua_getfield(L, lua_upvalueindex(1), "searchers") != LUA_TTABLE) + luaL_error(L, "'package.searchers' must be a table"); + /* iterate over available searchers to find a loader */ + for (i = 1; ; i++) { + if (lua_rawgeti(L, 3, i) == LUA_TNIL) { /* no more searchers? */ + lua_pop(L, 1); /* remove nil */ + luaL_pushresult(&msg); /* create error message */ + luaL_error(L, "module '%s' not found:%s", name, lua_tostring(L, -1)); + } + lua_pushstring(L, name); + lua_call(L, 1, 2); /* call it */ + if (lua_isfunction(L, -2)) /* did it find a loader? */ + return; /* module loader found */ + else if (lua_isstring(L, -2)) { /* searcher returned error message? */ + lua_pop(L, 1); /* remove extra return */ + luaL_addvalue(&msg); /* concatenate error message */ + } + else + lua_pop(L, 2); /* remove both returns */ + } +} + + +static int ll_require (lua_State *L) { + const char *name = luaL_checkstring(L, 1); + lua_settop(L, 1); /* LOADED table will be at index 2 */ + lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); + lua_getfield(L, 2, name); /* LOADED[name] */ + if (lua_toboolean(L, -1)) /* is it there? */ + return 1; /* package is already loaded */ + /* else must load package */ + lua_pop(L, 1); /* remove 'getfield' result */ + findloader(L, name); + lua_pushstring(L, name); /* pass name as argument to module loader */ + lua_insert(L, -2); /* name is 1st argument (before search data) */ + lua_call(L, 2, 1); /* run loader to load module */ + if (!lua_isnil(L, -1)) /* non-nil return? */ + lua_setfield(L, 2, name); /* LOADED[name] = returned value */ + if (lua_getfield(L, 2, name) == LUA_TNIL) { /* module set no value? */ + lua_pushboolean(L, 1); /* use true as result */ + lua_pushvalue(L, -1); /* extra copy to be returned */ + lua_setfield(L, 2, name); /* LOADED[name] = true */ + } + return 1; +} + +/* }====================================================== */ + + + +/* +** {====================================================== +** 'module' function +** ======================================================= +*/ +#if defined(LUA_COMPAT_MODULE) + +/* +** changes the environment variable of calling function +*/ +static void set_env (lua_State *L) { + lua_Debug ar; + if (lua_getstack(L, 1, &ar) == 0 || + lua_getinfo(L, "f", &ar) == 0 || /* get calling function */ + lua_iscfunction(L, -1)) + luaL_error(L, "'module' not called from a Lua function"); + lua_pushvalue(L, -2); /* copy new environment table to top */ + lua_setupvalue(L, -2, 1); + lua_pop(L, 1); /* remove function */ +} + + +static void dooptions (lua_State *L, int n) { + int i; + for (i = 2; i <= n; i++) { + if (lua_isfunction(L, i)) { /* avoid 'calling' extra info. */ + lua_pushvalue(L, i); /* get option (a function) */ + lua_pushvalue(L, -2); /* module */ + lua_call(L, 1, 0); + } + } +} + + +static void modinit (lua_State *L, const char *modname) { + const char *dot; + lua_pushvalue(L, -1); + lua_setfield(L, -2, "_M"); /* module._M = module */ + lua_pushstring(L, modname); + lua_setfield(L, -2, "_NAME"); + dot = strrchr(modname, '.'); /* look for last dot in module name */ + if (dot == NULL) dot = modname; + else dot++; + /* set _PACKAGE as package name (full module name minus last part) */ + lua_pushlstring(L, modname, dot - modname); + lua_setfield(L, -2, "_PACKAGE"); +} + + +static int ll_module (lua_State *L) { + const char *modname = luaL_checkstring(L, 1); + int lastarg = lua_gettop(L); /* last parameter */ + luaL_pushmodule(L, modname, 1); /* get/create module table */ + /* check whether table already has a _NAME field */ + if (lua_getfield(L, -1, "_NAME") != LUA_TNIL) + lua_pop(L, 1); /* table is an initialized module */ + else { /* no; initialize it */ + lua_pop(L, 1); + modinit(L, modname); + } + lua_pushvalue(L, -1); + set_env(L); + dooptions(L, lastarg); + return 1; +} + + +static int ll_seeall (lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); + if (!lua_getmetatable(L, 1)) { + lua_createtable(L, 0, 1); /* create new metatable */ + lua_pushvalue(L, -1); + lua_setmetatable(L, 1); + } + lua_pushglobaltable(L); + lua_setfield(L, -2, "__index"); /* mt.__index = _G */ + return 0; +} + +#endif +/* }====================================================== */ + + + +static const luaL_Reg pk_funcs[] = { + {"loadlib", ll_loadlib}, + {"searchpath", ll_searchpath}, +#if defined(LUA_COMPAT_MODULE) + {"seeall", ll_seeall}, +#endif + /* placeholders */ + {"preload", NULL}, + {"cpath", NULL}, + {"path", NULL}, + {"searchers", NULL}, + {"loaded", NULL}, + {NULL, NULL} +}; + + +static const luaL_Reg ll_funcs[] = { +#if defined(LUA_COMPAT_MODULE) + {"module", ll_module}, +#endif + {"require", ll_require}, + {NULL, NULL} +}; + + +static void createsearcherstable (lua_State *L) { + static const lua_CFunction searchers[] = + {searcher_preload, searcher_Lua, searcher_C, searcher_Croot, NULL}; + int i; + /* create 'searchers' table */ + lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0); + /* fill it with predefined searchers */ + for (i=0; searchers[i] != NULL; i++) { + lua_pushvalue(L, -2); /* set 'package' as upvalue for all searchers */ + lua_pushcclosure(L, searchers[i], 1); + lua_rawseti(L, -2, i+1); + } +#if defined(LUA_COMPAT_LOADERS) + lua_pushvalue(L, -1); /* make a copy of 'searchers' table */ + lua_setfield(L, -3, "loaders"); /* put it in field 'loaders' */ +#endif + lua_setfield(L, -2, "searchers"); /* put it in field 'searchers' */ +} + + +/* +** create table CLIBS to keep track of loaded C libraries, +** setting a finalizer to close all libraries when closing state. +*/ +static void createclibstable (lua_State *L) { + lua_newtable(L); /* create CLIBS table */ + lua_createtable(L, 0, 1); /* create metatable for CLIBS */ + lua_pushcfunction(L, gctm); + lua_setfield(L, -2, "__gc"); /* set finalizer for CLIBS table */ + lua_setmetatable(L, -2); + lua_rawsetp(L, LUA_REGISTRYINDEX, &CLIBS); /* set CLIBS table in registry */ +} + + +LUAMOD_API int luaopen_package (lua_State *L) { + createclibstable(L); + luaL_newlib(L, pk_funcs); /* create 'package' table */ + createsearcherstable(L); + /* set paths */ + setpath(L, "path", LUA_PATH_VAR, LUA_PATH_DEFAULT); + setpath(L, "cpath", LUA_CPATH_VAR, LUA_CPATH_DEFAULT); + /* store config information */ + lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATH_SEP "\n" LUA_PATH_MARK "\n" + LUA_EXEC_DIR "\n" LUA_IGMARK "\n"); + lua_setfield(L, -2, "config"); + /* set field 'loaded' */ + luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); + lua_setfield(L, -2, "loaded"); + /* set field 'preload' */ + luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE); + lua_setfield(L, -2, "preload"); + lua_pushglobaltable(L); + lua_pushvalue(L, -2); /* set 'package' as upvalue for next lib */ + luaL_setfuncs(L, ll_funcs, 1); /* open lib into global table */ + lua_pop(L, 1); /* pop global table */ + return 1; /* return 'package' table */ +} + diff --git a/depends/lua/src/lobject.c b/depends/lua/src/lobject.c new file mode 100644 index 0000000000..355bf58d63 --- /dev/null +++ b/depends/lua/src/lobject.c @@ -0,0 +1,522 @@ +/* +** $Id: lobject.c,v 2.113.1.1 2017/04/19 17:29:57 roberto Exp $ +** Some generic functions over Lua objects +** See Copyright Notice in lua.h +*/ + +#define lobject_c +#define LUA_CORE + +#include "lprefix.h" + + +#include +#include +#include +#include +#include +#include + +#include "lua.h" + +#include "lctype.h" +#include "ldebug.h" +#include "ldo.h" +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" +#include "lstring.h" +#include "lvm.h" + + + +LUAI_DDEF const TValue luaO_nilobject_ = {NILCONSTANT}; + + +/* +** converts an integer to a "floating point byte", represented as +** (eeeeexxx), where the real value is (1xxx) * 2^(eeeee - 1) if +** eeeee != 0 and (xxx) otherwise. +*/ +int luaO_int2fb (unsigned int x) { + int e = 0; /* exponent */ + if (x < 8) return x; + while (x >= (8 << 4)) { /* coarse steps */ + x = (x + 0xf) >> 4; /* x = ceil(x / 16) */ + e += 4; + } + while (x >= (8 << 1)) { /* fine steps */ + x = (x + 1) >> 1; /* x = ceil(x / 2) */ + e++; + } + return ((e+1) << 3) | (cast_int(x) - 8); +} + + +/* converts back */ +int luaO_fb2int (int x) { + return (x < 8) ? x : ((x & 7) + 8) << ((x >> 3) - 1); +} + + +/* +** Computes ceil(log2(x)) +*/ +int luaO_ceillog2 (unsigned int x) { + static const lu_byte log_2[256] = { /* log_2[i] = ceil(log2(i - 1)) */ + 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8 + }; + int l = 0; + x--; + while (x >= 256) { l += 8; x >>= 8; } + return l + log_2[x]; +} + + +static lua_Integer intarith (lua_State *L, int op, lua_Integer v1, + lua_Integer v2) { + switch (op) { + case LUA_OPADD: return intop(+, v1, v2); + case LUA_OPSUB:return intop(-, v1, v2); + case LUA_OPMUL:return intop(*, v1, v2); + case LUA_OPMOD: return luaV_mod(L, v1, v2); + case LUA_OPIDIV: return luaV_div(L, v1, v2); + case LUA_OPBAND: return intop(&, v1, v2); + case LUA_OPBOR: return intop(|, v1, v2); + case LUA_OPBXOR: return intop(^, v1, v2); + case LUA_OPSHL: return luaV_shiftl(v1, v2); + case LUA_OPSHR: return luaV_shiftl(v1, -v2); + case LUA_OPUNM: return intop(-, 0, v1); + case LUA_OPBNOT: return intop(^, ~l_castS2U(0), v1); + default: lua_assert(0); return 0; + } +} + + +static lua_Number numarith (lua_State *L, int op, lua_Number v1, + lua_Number v2) { + switch (op) { + case LUA_OPADD: return luai_numadd(L, v1, v2); + case LUA_OPSUB: return luai_numsub(L, v1, v2); + case LUA_OPMUL: return luai_nummul(L, v1, v2); + case LUA_OPDIV: return luai_numdiv(L, v1, v2); + case LUA_OPPOW: return luai_numpow(L, v1, v2); + case LUA_OPIDIV: return luai_numidiv(L, v1, v2); + case LUA_OPUNM: return luai_numunm(L, v1); + case LUA_OPMOD: { + lua_Number m; + luai_nummod(L, v1, v2, m); + return m; + } + default: lua_assert(0); return 0; + } +} + + +void luaO_arith (lua_State *L, int op, const TValue *p1, const TValue *p2, + TValue *res) { + switch (op) { + case LUA_OPBAND: case LUA_OPBOR: case LUA_OPBXOR: + case LUA_OPSHL: case LUA_OPSHR: + case LUA_OPBNOT: { /* operate only on integers */ + lua_Integer i1; lua_Integer i2; + if (tointeger(p1, &i1) && tointeger(p2, &i2)) { + setivalue(res, intarith(L, op, i1, i2)); + return; + } + else break; /* go to the end */ + } + case LUA_OPDIV: case LUA_OPPOW: { /* operate only on floats */ + lua_Number n1; lua_Number n2; + if (tonumber(p1, &n1) && tonumber(p2, &n2)) { + setfltvalue(res, numarith(L, op, n1, n2)); + return; + } + else break; /* go to the end */ + } + default: { /* other operations */ + lua_Number n1; lua_Number n2; + if (ttisinteger(p1) && ttisinteger(p2)) { + setivalue(res, intarith(L, op, ivalue(p1), ivalue(p2))); + return; + } + else if (tonumber(p1, &n1) && tonumber(p2, &n2)) { + setfltvalue(res, numarith(L, op, n1, n2)); + return; + } + else break; /* go to the end */ + } + } + /* could not perform raw operation; try metamethod */ + lua_assert(L != NULL); /* should not fail when folding (compile time) */ + luaT_trybinTM(L, p1, p2, res, cast(TMS, (op - LUA_OPADD) + TM_ADD)); +} + + +int luaO_hexavalue (int c) { + if (lisdigit(c)) return c - '0'; + else return (ltolower(c) - 'a') + 10; +} + + +static int isneg (const char **s) { + if (**s == '-') { (*s)++; return 1; } + else if (**s == '+') (*s)++; + return 0; +} + + + +/* +** {================================================================== +** Lua's implementation for 'lua_strx2number' +** =================================================================== +*/ + +#if !defined(lua_strx2number) + +/* maximum number of significant digits to read (to avoid overflows + even with single floats) */ +#define MAXSIGDIG 30 + +/* +** convert an hexadecimal numeric string to a number, following +** C99 specification for 'strtod' +*/ +static lua_Number lua_strx2number (const char *s, char **endptr) { + int dot = lua_getlocaledecpoint(); + lua_Number r = 0.0; /* result (accumulator) */ + int sigdig = 0; /* number of significant digits */ + int nosigdig = 0; /* number of non-significant digits */ + int e = 0; /* exponent correction */ + int neg; /* 1 if number is negative */ + int hasdot = 0; /* true after seen a dot */ + *endptr = cast(char *, s); /* nothing is valid yet */ + while (lisspace(cast_uchar(*s))) s++; /* skip initial spaces */ + neg = isneg(&s); /* check signal */ + if (!(*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X'))) /* check '0x' */ + return 0.0; /* invalid format (no '0x') */ + for (s += 2; ; s++) { /* skip '0x' and read numeral */ + if (*s == dot) { + if (hasdot) break; /* second dot? stop loop */ + else hasdot = 1; + } + else if (lisxdigit(cast_uchar(*s))) { + if (sigdig == 0 && *s == '0') /* non-significant digit (zero)? */ + nosigdig++; + else if (++sigdig <= MAXSIGDIG) /* can read it without overflow? */ + r = (r * cast_num(16.0)) + luaO_hexavalue(*s); + else e++; /* too many digits; ignore, but still count for exponent */ + if (hasdot) e--; /* decimal digit? correct exponent */ + } + else break; /* neither a dot nor a digit */ + } + if (nosigdig + sigdig == 0) /* no digits? */ + return 0.0; /* invalid format */ + *endptr = cast(char *, s); /* valid up to here */ + e *= 4; /* each digit multiplies/divides value by 2^4 */ + if (*s == 'p' || *s == 'P') { /* exponent part? */ + int exp1 = 0; /* exponent value */ + int neg1; /* exponent signal */ + s++; /* skip 'p' */ + neg1 = isneg(&s); /* signal */ + if (!lisdigit(cast_uchar(*s))) + return 0.0; /* invalid; must have at least one digit */ + while (lisdigit(cast_uchar(*s))) /* read exponent */ + exp1 = exp1 * 10 + *(s++) - '0'; + if (neg1) exp1 = -exp1; + e += exp1; + *endptr = cast(char *, s); /* valid up to here */ + } + if (neg) r = -r; + return l_mathop(ldexp)(r, e); +} + +#endif +/* }====================================================== */ + + +/* maximum length of a numeral */ +#if !defined (L_MAXLENNUM) +#define L_MAXLENNUM 200 +#endif + +static const char *l_str2dloc (const char *s, lua_Number *result, int mode) { + char *endptr; + *result = (mode == 'x') ? lua_strx2number(s, &endptr) /* try to convert */ + : lua_str2number(s, &endptr); + if (endptr == s) return NULL; /* nothing recognized? */ + while (lisspace(cast_uchar(*endptr))) endptr++; /* skip trailing spaces */ + return (*endptr == '\0') ? endptr : NULL; /* OK if no trailing characters */ +} + + +/* +** Convert string 's' to a Lua number (put in 'result'). Return NULL +** on fail or the address of the ending '\0' on success. +** 'pmode' points to (and 'mode' contains) special things in the string: +** - 'x'/'X' means an hexadecimal numeral +** - 'n'/'N' means 'inf' or 'nan' (which should be rejected) +** - '.' just optimizes the search for the common case (nothing special) +** This function accepts both the current locale or a dot as the radix +** mark. If the conversion fails, it may mean number has a dot but +** locale accepts something else. In that case, the code copies 's' +** to a buffer (because 's' is read-only), changes the dot to the +** current locale radix mark, and tries to convert again. +*/ +static const char *l_str2d (const char *s, lua_Number *result) { + const char *endptr; + const char *pmode = strpbrk(s, ".xXnN"); + int mode = pmode ? ltolower(cast_uchar(*pmode)) : 0; + if (mode == 'n') /* reject 'inf' and 'nan' */ + return NULL; + endptr = l_str2dloc(s, result, mode); /* try to convert */ + if (endptr == NULL) { /* failed? may be a different locale */ + char buff[L_MAXLENNUM + 1]; + const char *pdot = strchr(s, '.'); + if (strlen(s) > L_MAXLENNUM || pdot == NULL) + return NULL; /* string too long or no dot; fail */ + strcpy(buff, s); /* copy string to buffer */ + buff[pdot - s] = lua_getlocaledecpoint(); /* correct decimal point */ + endptr = l_str2dloc(buff, result, mode); /* try again */ + if (endptr != NULL) + endptr = s + (endptr - buff); /* make relative to 's' */ + } + return endptr; +} + + +#define MAXBY10 cast(lua_Unsigned, LUA_MAXINTEGER / 10) +#define MAXLASTD cast_int(LUA_MAXINTEGER % 10) + +static const char *l_str2int (const char *s, lua_Integer *result) { + lua_Unsigned a = 0; + int empty = 1; + int neg; + while (lisspace(cast_uchar(*s))) s++; /* skip initial spaces */ + neg = isneg(&s); + if (s[0] == '0' && + (s[1] == 'x' || s[1] == 'X')) { /* hex? */ + s += 2; /* skip '0x' */ + for (; lisxdigit(cast_uchar(*s)); s++) { + a = a * 16 + luaO_hexavalue(*s); + empty = 0; + } + } + else { /* decimal */ + for (; lisdigit(cast_uchar(*s)); s++) { + int d = *s - '0'; + if (a >= MAXBY10 && (a > MAXBY10 || d > MAXLASTD + neg)) /* overflow? */ + return NULL; /* do not accept it (as integer) */ + a = a * 10 + d; + empty = 0; + } + } + while (lisspace(cast_uchar(*s))) s++; /* skip trailing spaces */ + if (empty || *s != '\0') return NULL; /* something wrong in the numeral */ + else { + *result = l_castU2S((neg) ? 0u - a : a); + return s; + } +} + + +size_t luaO_str2num (const char *s, TValue *o) { + lua_Integer i; lua_Number n; + const char *e; + if ((e = l_str2int(s, &i)) != NULL) { /* try as an integer */ + setivalue(o, i); + } + else if ((e = l_str2d(s, &n)) != NULL) { /* else try as a float */ + setfltvalue(o, n); + } + else + return 0; /* conversion failed */ + return (e - s) + 1; /* success; return string size */ +} + + +int luaO_utf8esc (char *buff, unsigned long x) { + int n = 1; /* number of bytes put in buffer (backwards) */ + lua_assert(x <= 0x10FFFF); + if (x < 0x80) /* ascii? */ + buff[UTF8BUFFSZ - 1] = cast(char, x); + else { /* need continuation bytes */ + unsigned int mfb = 0x3f; /* maximum that fits in first byte */ + do { /* add continuation bytes */ + buff[UTF8BUFFSZ - (n++)] = cast(char, 0x80 | (x & 0x3f)); + x >>= 6; /* remove added bits */ + mfb >>= 1; /* now there is one less bit available in first byte */ + } while (x > mfb); /* still needs continuation byte? */ + buff[UTF8BUFFSZ - n] = cast(char, (~mfb << 1) | x); /* add first byte */ + } + return n; +} + + +/* maximum length of the conversion of a number to a string */ +#define MAXNUMBER2STR 50 + + +/* +** Convert a number object to a string +*/ +void luaO_tostring (lua_State *L, StkId obj) { + char buff[MAXNUMBER2STR]; + size_t len; + lua_assert(ttisnumber(obj)); + if (ttisinteger(obj)) + len = lua_integer2str(buff, sizeof(buff), ivalue(obj)); + else { + len = lua_number2str(buff, sizeof(buff), fltvalue(obj)); +#if !defined(LUA_COMPAT_FLOATSTRING) + if (buff[strspn(buff, "-0123456789")] == '\0') { /* looks like an int? */ + buff[len++] = lua_getlocaledecpoint(); + buff[len++] = '0'; /* adds '.0' to result */ + } +#endif + } + setsvalue2s(L, obj, luaS_newlstr(L, buff, len)); +} + + +static void pushstr (lua_State *L, const char *str, size_t l) { + setsvalue2s(L, L->top, luaS_newlstr(L, str, l)); + luaD_inctop(L); +} + + +/* +** this function handles only '%d', '%c', '%f', '%p', and '%s' + conventional formats, plus Lua-specific '%I' and '%U' +*/ +const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { + int n = 0; + for (;;) { + const char *e = strchr(fmt, '%'); + if (e == NULL) break; + pushstr(L, fmt, e - fmt); + switch (*(e+1)) { + case 's': { /* zero-terminated string */ + const char *s = va_arg(argp, char *); + if (s == NULL) s = "(null)"; + pushstr(L, s, strlen(s)); + break; + } + case 'c': { /* an 'int' as a character */ + char buff = cast(char, va_arg(argp, int)); + if (lisprint(cast_uchar(buff))) + pushstr(L, &buff, 1); + else /* non-printable character; print its code */ + luaO_pushfstring(L, "<\\%d>", cast_uchar(buff)); + break; + } + case 'd': { /* an 'int' */ + setivalue(L->top, va_arg(argp, int)); + goto top2str; + } + case 'I': { /* a 'lua_Integer' */ + setivalue(L->top, cast(lua_Integer, va_arg(argp, l_uacInt))); + goto top2str; + } + case 'f': { /* a 'lua_Number' */ + setfltvalue(L->top, cast_num(va_arg(argp, l_uacNumber))); + top2str: /* convert the top element to a string */ + luaD_inctop(L); + luaO_tostring(L, L->top - 1); + break; + } + case 'p': { /* a pointer */ + char buff[4*sizeof(void *) + 8]; /* should be enough space for a '%p' */ + void *p = va_arg(argp, void *); + int l = lua_pointer2str(buff, sizeof(buff), p); + pushstr(L, buff, l); + break; + } + case 'U': { /* an 'int' as a UTF-8 sequence */ + char buff[UTF8BUFFSZ]; + int l = luaO_utf8esc(buff, cast(long, va_arg(argp, long))); + pushstr(L, buff + UTF8BUFFSZ - l, l); + break; + } + case '%': { + pushstr(L, "%", 1); + break; + } + default: { + luaG_runerror(L, "invalid option '%%%c' to 'lua_pushfstring'", + *(e + 1)); + } + } + n += 2; + fmt = e+2; + } + luaD_checkstack(L, 1); + pushstr(L, fmt, strlen(fmt)); + if (n > 0) luaV_concat(L, n + 1); + return svalue(L->top - 1); +} + + +const char *luaO_pushfstring (lua_State *L, const char *fmt, ...) { + const char *msg; + va_list argp; + va_start(argp, fmt); + msg = luaO_pushvfstring(L, fmt, argp); + va_end(argp); + return msg; +} + + +/* number of chars of a literal string without the ending \0 */ +#define LL(x) (sizeof(x)/sizeof(char) - 1) + +#define RETS "..." +#define PRE "[string \"" +#define POS "\"]" + +#define addstr(a,b,l) ( memcpy(a,b,(l) * sizeof(char)), a += (l) ) + +void luaO_chunkid (char *out, const char *source, size_t bufflen) { + size_t l = strlen(source); + if (*source == '=') { /* 'literal' source */ + if (l <= bufflen) /* small enough? */ + memcpy(out, source + 1, l * sizeof(char)); + else { /* truncate it */ + addstr(out, source + 1, bufflen - 1); + *out = '\0'; + } + } + else if (*source == '@') { /* file name */ + if (l <= bufflen) /* small enough? */ + memcpy(out, source + 1, l * sizeof(char)); + else { /* add '...' before rest of name */ + addstr(out, RETS, LL(RETS)); + bufflen -= LL(RETS); + memcpy(out, source + 1 + l - bufflen, bufflen * sizeof(char)); + } + } + else { /* string; format as [string "source"] */ + const char *nl = strchr(source, '\n'); /* find first new line (if any) */ + addstr(out, PRE, LL(PRE)); /* add prefix */ + bufflen -= LL(PRE RETS POS) + 1; /* save space for prefix+suffix+'\0' */ + if (l < bufflen && nl == NULL) { /* small one-line source? */ + addstr(out, source, l); /* keep it */ + } + else { + if (nl != NULL) l = nl - source; /* stop at first newline */ + if (l > bufflen) l = bufflen; + addstr(out, source, l); + addstr(out, RETS, LL(RETS)); + } + memcpy(out, POS, (LL(POS) + 1) * sizeof(char)); + } +} + diff --git a/depends/lua/src/lopcodes.c b/depends/lua/src/lopcodes.c new file mode 100644 index 0000000000..5ca3eb261a --- /dev/null +++ b/depends/lua/src/lopcodes.c @@ -0,0 +1,124 @@ +/* +** $Id: lopcodes.c,v 1.55.1.1 2017/04/19 17:20:42 roberto Exp $ +** Opcodes for Lua virtual machine +** See Copyright Notice in lua.h +*/ + +#define lopcodes_c +#define LUA_CORE + +#include "lprefix.h" + + +#include + +#include "lopcodes.h" + + +/* ORDER OP */ + +LUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = { + "MOVE", + "LOADK", + "LOADKX", + "LOADBOOL", + "LOADNIL", + "GETUPVAL", + "GETTABUP", + "GETTABLE", + "SETTABUP", + "SETUPVAL", + "SETTABLE", + "NEWTABLE", + "SELF", + "ADD", + "SUB", + "MUL", + "MOD", + "POW", + "DIV", + "IDIV", + "BAND", + "BOR", + "BXOR", + "SHL", + "SHR", + "UNM", + "BNOT", + "NOT", + "LEN", + "CONCAT", + "JMP", + "EQ", + "LT", + "LE", + "TEST", + "TESTSET", + "CALL", + "TAILCALL", + "RETURN", + "FORLOOP", + "FORPREP", + "TFORCALL", + "TFORLOOP", + "SETLIST", + "CLOSURE", + "VARARG", + "EXTRAARG", + NULL +}; + + +#define opmode(t,a,b,c,m) (((t)<<7) | ((a)<<6) | ((b)<<4) | ((c)<<2) | (m)) + +LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = { +/* T A B C mode opcode */ + opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_MOVE */ + ,opmode(0, 1, OpArgK, OpArgN, iABx) /* OP_LOADK */ + ,opmode(0, 1, OpArgN, OpArgN, iABx) /* OP_LOADKX */ + ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_LOADBOOL */ + ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_LOADNIL */ + ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_GETUPVAL */ + ,opmode(0, 1, OpArgU, OpArgK, iABC) /* OP_GETTABUP */ + ,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_GETTABLE */ + ,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_SETTABUP */ + ,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_SETUPVAL */ + ,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_SETTABLE */ + ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_NEWTABLE */ + ,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_SELF */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_ADD */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_SUB */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_MUL */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_MOD */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_POW */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_DIV */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_IDIV */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_BAND */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_BOR */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_BXOR */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_SHL */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_SHR */ + ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_UNM */ + ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_BNOT */ + ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_NOT */ + ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_LEN */ + ,opmode(0, 1, OpArgR, OpArgR, iABC) /* OP_CONCAT */ + ,opmode(0, 0, OpArgR, OpArgN, iAsBx) /* OP_JMP */ + ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_EQ */ + ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_LT */ + ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_LE */ + ,opmode(1, 0, OpArgN, OpArgU, iABC) /* OP_TEST */ + ,opmode(1, 1, OpArgR, OpArgU, iABC) /* OP_TESTSET */ + ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_CALL */ + ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_TAILCALL */ + ,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_RETURN */ + ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_FORLOOP */ + ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_FORPREP */ + ,opmode(0, 0, OpArgN, OpArgU, iABC) /* OP_TFORCALL */ + ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_TFORLOOP */ + ,opmode(0, 0, OpArgU, OpArgU, iABC) /* OP_SETLIST */ + ,opmode(0, 1, OpArgU, OpArgN, iABx) /* OP_CLOSURE */ + ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_VARARG */ + ,opmode(0, 0, OpArgU, OpArgU, iAx) /* OP_EXTRAARG */ +}; + diff --git a/depends/lua/src/loslib.c b/depends/lua/src/loslib.c new file mode 100644 index 0000000000..de590c6b71 --- /dev/null +++ b/depends/lua/src/loslib.c @@ -0,0 +1,409 @@ +/* +** $Id: loslib.c,v 1.65.1.1 2017/04/19 17:29:57 roberto Exp $ +** Standard Operating System library +** See Copyright Notice in lua.h +*/ + +#define loslib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include +#include +#include +#include +#include + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +/* +** {================================================================== +** List of valid conversion specifiers for the 'strftime' function; +** options are grouped by length; group of length 2 start with '||'. +** =================================================================== +*/ +#if !defined(LUA_STRFTIMEOPTIONS) /* { */ + +/* options for ANSI C 89 (only 1-char options) */ +#define L_STRFTIMEC89 "aAbBcdHIjmMpSUwWxXyYZ%" + +/* options for ISO C 99 and POSIX */ +#define L_STRFTIMEC99 "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \ + "||" "EcECExEXEyEY" "OdOeOHOIOmOMOSOuOUOVOwOWOy" /* two-char options */ + +/* options for Windows */ +#define L_STRFTIMEWIN "aAbBcdHIjmMpSUwWxXyYzZ%" \ + "||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y" /* two-char options */ + +#if defined(LUA_USE_WINDOWS) +#define LUA_STRFTIMEOPTIONS L_STRFTIMEWIN +#elif defined(LUA_USE_C89) +#define LUA_STRFTIMEOPTIONS L_STRFTIMEC89 +#else /* C99 specification */ +#define LUA_STRFTIMEOPTIONS L_STRFTIMEC99 +#endif + +#endif /* } */ +/* }================================================================== */ + + +/* +** {================================================================== +** Configuration for time-related stuff +** =================================================================== +*/ + +#if !defined(l_time_t) /* { */ +/* +** type to represent time_t in Lua +*/ +#define l_timet lua_Integer +#define l_pushtime(L,t) lua_pushinteger(L,(lua_Integer)(t)) + +static time_t l_checktime (lua_State *L, int arg) { + lua_Integer t = luaL_checkinteger(L, arg); + luaL_argcheck(L, (time_t)t == t, arg, "time out-of-bounds"); + return (time_t)t; +} + +#endif /* } */ + + +#if !defined(l_gmtime) /* { */ +/* +** By default, Lua uses gmtime/localtime, except when POSIX is available, +** where it uses gmtime_r/localtime_r +*/ + +#if defined(LUA_USE_POSIX) /* { */ + +#define l_gmtime(t,r) gmtime_r(t,r) +#define l_localtime(t,r) localtime_r(t,r) + +#else /* }{ */ + +/* ISO C definitions */ +#define l_gmtime(t,r) ((void)(r)->tm_sec, gmtime(t)) +#define l_localtime(t,r) ((void)(r)->tm_sec, localtime(t)) + +#endif /* } */ + +#endif /* } */ + +/* }================================================================== */ + + +/* +** {================================================================== +** Configuration for 'tmpnam': +** By default, Lua uses tmpnam except when POSIX is available, where +** it uses mkstemp. +** =================================================================== +*/ +#if !defined(lua_tmpnam) /* { */ + +#if defined(LUA_USE_POSIX) /* { */ + +#include + +#define LUA_TMPNAMBUFSIZE 32 + +#if !defined(LUA_TMPNAMTEMPLATE) +#define LUA_TMPNAMTEMPLATE "/tmp/lua_XXXXXX" +#endif + +#define lua_tmpnam(b,e) { \ + strcpy(b, LUA_TMPNAMTEMPLATE); \ + e = mkstemp(b); \ + if (e != -1) close(e); \ + e = (e == -1); } + +#else /* }{ */ + +/* ISO C definitions */ +#define LUA_TMPNAMBUFSIZE L_tmpnam +#define lua_tmpnam(b,e) { e = (tmpnam(b) == NULL); } + +#endif /* } */ + +#endif /* } */ +/* }================================================================== */ + + + + +static int os_execute (lua_State *L) { + const char *cmd = luaL_optstring(L, 1, NULL); + int stat = system(cmd); + if (cmd != NULL) + return luaL_execresult(L, stat); + else { + lua_pushboolean(L, stat); /* true if there is a shell */ + return 1; + } +} + + +static int os_remove (lua_State *L) { + const char *filename = luaL_checkstring(L, 1); + return luaL_fileresult(L, remove(filename) == 0, filename); +} + + +static int os_rename (lua_State *L) { + const char *fromname = luaL_checkstring(L, 1); + const char *toname = luaL_checkstring(L, 2); + return luaL_fileresult(L, rename(fromname, toname) == 0, NULL); +} + + +static int os_tmpname (lua_State *L) { + char buff[LUA_TMPNAMBUFSIZE]; + int err; + lua_tmpnam(buff, err); + if (err) + return luaL_error(L, "unable to generate a unique filename"); + lua_pushstring(L, buff); + return 1; +} + + +static int os_getenv (lua_State *L) { + lua_pushstring(L, getenv(luaL_checkstring(L, 1))); /* if NULL push nil */ + return 1; +} + + +static int os_clock (lua_State *L) { + lua_pushnumber(L, ((lua_Number)clock())/(lua_Number)CLOCKS_PER_SEC); + return 1; +} + + +/* +** {====================================================== +** Time/Date operations +** { year=%Y, month=%m, day=%d, hour=%H, min=%M, sec=%S, +** wday=%w+1, yday=%j, isdst=? } +** ======================================================= +*/ + +static void setfield (lua_State *L, const char *key, int value) { + lua_pushinteger(L, value); + lua_setfield(L, -2, key); +} + +static void setboolfield (lua_State *L, const char *key, int value) { + if (value < 0) /* undefined? */ + return; /* does not set field */ + lua_pushboolean(L, value); + lua_setfield(L, -2, key); +} + + +/* +** Set all fields from structure 'tm' in the table on top of the stack +*/ +static void setallfields (lua_State *L, struct tm *stm) { + setfield(L, "sec", stm->tm_sec); + setfield(L, "min", stm->tm_min); + setfield(L, "hour", stm->tm_hour); + setfield(L, "day", stm->tm_mday); + setfield(L, "month", stm->tm_mon + 1); + setfield(L, "year", stm->tm_year + 1900); + setfield(L, "wday", stm->tm_wday + 1); + setfield(L, "yday", stm->tm_yday + 1); + setboolfield(L, "isdst", stm->tm_isdst); +} + + +static int getboolfield (lua_State *L, const char *key) { + int res; + res = (lua_getfield(L, -1, key) == LUA_TNIL) ? -1 : lua_toboolean(L, -1); + lua_pop(L, 1); + return res; +} + + +/* maximum value for date fields (to avoid arithmetic overflows with 'int') */ +#if !defined(L_MAXDATEFIELD) +#define L_MAXDATEFIELD (INT_MAX / 2) +#endif + +static int getfield (lua_State *L, const char *key, int d, int delta) { + int isnum; + int t = lua_getfield(L, -1, key); /* get field and its type */ + lua_Integer res = lua_tointegerx(L, -1, &isnum); + if (!isnum) { /* field is not an integer? */ + if (t != LUA_TNIL) /* some other value? */ + return luaL_error(L, "field '%s' is not an integer", key); + else if (d < 0) /* absent field; no default? */ + return luaL_error(L, "field '%s' missing in date table", key); + res = d; + } + else { + if (!(-L_MAXDATEFIELD <= res && res <= L_MAXDATEFIELD)) + return luaL_error(L, "field '%s' is out-of-bound", key); + res -= delta; + } + lua_pop(L, 1); + return (int)res; +} + + +static const char *checkoption (lua_State *L, const char *conv, + ptrdiff_t convlen, char *buff) { + const char *option = LUA_STRFTIMEOPTIONS; + int oplen = 1; /* length of options being checked */ + for (; *option != '\0' && oplen <= convlen; option += oplen) { + if (*option == '|') /* next block? */ + oplen++; /* will check options with next length (+1) */ + else if (memcmp(conv, option, oplen) == 0) { /* match? */ + memcpy(buff, conv, oplen); /* copy valid option to buffer */ + buff[oplen] = '\0'; + return conv + oplen; /* return next item */ + } + } + luaL_argerror(L, 1, + lua_pushfstring(L, "invalid conversion specifier '%%%s'", conv)); + return conv; /* to avoid warnings */ +} + + +/* maximum size for an individual 'strftime' item */ +#define SIZETIMEFMT 250 + + +static int os_date (lua_State *L) { + size_t slen; + const char *s = luaL_optlstring(L, 1, "%c", &slen); + time_t t = luaL_opt(L, l_checktime, 2, time(NULL)); + const char *se = s + slen; /* 's' end */ + struct tm tmr, *stm; + if (*s == '!') { /* UTC? */ + stm = l_gmtime(&t, &tmr); + s++; /* skip '!' */ + } + else + stm = l_localtime(&t, &tmr); + if (stm == NULL) /* invalid date? */ + return luaL_error(L, + "time result cannot be represented in this installation"); + if (strcmp(s, "*t") == 0) { + lua_createtable(L, 0, 9); /* 9 = number of fields */ + setallfields(L, stm); + } + else { + char cc[4]; /* buffer for individual conversion specifiers */ + luaL_Buffer b; + cc[0] = '%'; + luaL_buffinit(L, &b); + while (s < se) { + if (*s != '%') /* not a conversion specifier? */ + luaL_addchar(&b, *s++); + else { + size_t reslen; + char *buff = luaL_prepbuffsize(&b, SIZETIMEFMT); + s++; /* skip '%' */ + s = checkoption(L, s, se - s, cc + 1); /* copy specifier to 'cc' */ + reslen = strftime(buff, SIZETIMEFMT, cc, stm); + luaL_addsize(&b, reslen); + } + } + luaL_pushresult(&b); + } + return 1; +} + + +static int os_time (lua_State *L) { + time_t t; + if (lua_isnoneornil(L, 1)) /* called without args? */ + t = time(NULL); /* get current time */ + else { + struct tm ts; + luaL_checktype(L, 1, LUA_TTABLE); + lua_settop(L, 1); /* make sure table is at the top */ + ts.tm_sec = getfield(L, "sec", 0, 0); + ts.tm_min = getfield(L, "min", 0, 0); + ts.tm_hour = getfield(L, "hour", 12, 0); + ts.tm_mday = getfield(L, "day", -1, 0); + ts.tm_mon = getfield(L, "month", -1, 1); + ts.tm_year = getfield(L, "year", -1, 1900); + ts.tm_isdst = getboolfield(L, "isdst"); + t = mktime(&ts); + setallfields(L, &ts); /* update fields with normalized values */ + } + if (t != (time_t)(l_timet)t || t == (time_t)(-1)) + return luaL_error(L, + "time result cannot be represented in this installation"); + l_pushtime(L, t); + return 1; +} + + +static int os_difftime (lua_State *L) { + time_t t1 = l_checktime(L, 1); + time_t t2 = l_checktime(L, 2); + lua_pushnumber(L, (lua_Number)difftime(t1, t2)); + return 1; +} + +/* }====================================================== */ + + +static int os_setlocale (lua_State *L) { + static const int cat[] = {LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, + LC_NUMERIC, LC_TIME}; + static const char *const catnames[] = {"all", "collate", "ctype", "monetary", + "numeric", "time", NULL}; + const char *l = luaL_optstring(L, 1, NULL); + int op = luaL_checkoption(L, 2, "all", catnames); + lua_pushstring(L, setlocale(cat[op], l)); + return 1; +} + + +static int os_exit (lua_State *L) { + int status; + if (lua_isboolean(L, 1)) + status = (lua_toboolean(L, 1) ? EXIT_SUCCESS : EXIT_FAILURE); + else + status = (int)luaL_optinteger(L, 1, EXIT_SUCCESS); + if (lua_toboolean(L, 2)) + lua_close(L); + if (L) exit(status); /* 'if' to avoid warnings for unreachable 'return' */ + return 0; +} + + +static const luaL_Reg syslib[] = { + {"clock", os_clock}, + {"date", os_date}, + {"difftime", os_difftime}, + {"execute", os_execute}, + {"exit", os_exit}, + {"getenv", os_getenv}, + {"remove", os_remove}, + {"rename", os_rename}, + {"setlocale", os_setlocale}, + {"time", os_time}, + {"tmpname", os_tmpname}, + {NULL, NULL} +}; + +/* }====================================================== */ + + + +LUAMOD_API int luaopen_os (lua_State *L) { + luaL_newlib(L, syslib); + return 1; +} + diff --git a/depends/lua/src/lparser.c b/depends/lua/src/lparser.c new file mode 100644 index 0000000000..2f41e00b80 --- /dev/null +++ b/depends/lua/src/lparser.c @@ -0,0 +1,1653 @@ +/* +** $Id: lparser.c,v 2.155.1.2 2017/04/29 18:11:40 roberto Exp $ +** Lua Parser +** See Copyright Notice in lua.h +*/ + +#define lparser_c +#define LUA_CORE + +#include "lprefix.h" + + +#include + +#include "lua.h" + +#include "lcode.h" +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "llex.h" +#include "lmem.h" +#include "lobject.h" +#include "lopcodes.h" +#include "lparser.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" + + + +/* maximum number of local variables per function (must be smaller + than 250, due to the bytecode format) */ +#define MAXVARS 200 + + +#define hasmultret(k) ((k) == VCALL || (k) == VVARARG) + + +/* because all strings are unified by the scanner, the parser + can use pointer equality for string equality */ +#define eqstr(a,b) ((a) == (b)) + + +/* +** nodes for block list (list of active blocks) +*/ +typedef struct BlockCnt { + struct BlockCnt *previous; /* chain */ + int firstlabel; /* index of first label in this block */ + int firstgoto; /* index of first pending goto in this block */ + lu_byte nactvar; /* # active locals outside the block */ + lu_byte upval; /* true if some variable in the block is an upvalue */ + lu_byte isloop; /* true if 'block' is a loop */ +} BlockCnt; + + + +/* +** prototypes for recursive non-terminal functions +*/ +static void statement (LexState *ls); +static void expr (LexState *ls, expdesc *v); + + +/* semantic error */ +static l_noret semerror (LexState *ls, const char *msg) { + ls->t.token = 0; /* remove "near " from final message */ + luaX_syntaxerror(ls, msg); +} + + +static l_noret error_expected (LexState *ls, int token) { + luaX_syntaxerror(ls, + luaO_pushfstring(ls->L, "%s expected", luaX_token2str(ls, token))); +} + + +static l_noret errorlimit (FuncState *fs, int limit, const char *what) { + lua_State *L = fs->ls->L; + const char *msg; + int line = fs->f->linedefined; + const char *where = (line == 0) + ? "main function" + : luaO_pushfstring(L, "function at line %d", line); + msg = luaO_pushfstring(L, "too many %s (limit is %d) in %s", + what, limit, where); + luaX_syntaxerror(fs->ls, msg); +} + + +static void checklimit (FuncState *fs, int v, int l, const char *what) { + if (v > l) errorlimit(fs, l, what); +} + + +static int testnext (LexState *ls, int c) { + if (ls->t.token == c) { + luaX_next(ls); + return 1; + } + else return 0; +} + + +static void check (LexState *ls, int c) { + if (ls->t.token != c) + error_expected(ls, c); +} + + +static void checknext (LexState *ls, int c) { + check(ls, c); + luaX_next(ls); +} + + +#define check_condition(ls,c,msg) { if (!(c)) luaX_syntaxerror(ls, msg); } + + + +static void check_match (LexState *ls, int what, int who, int where) { + if (!testnext(ls, what)) { + if (where == ls->linenumber) + error_expected(ls, what); + else { + luaX_syntaxerror(ls, luaO_pushfstring(ls->L, + "%s expected (to close %s at line %d)", + luaX_token2str(ls, what), luaX_token2str(ls, who), where)); + } + } +} + + +static TString *str_checkname (LexState *ls) { + TString *ts; + check(ls, TK_NAME); + ts = ls->t.seminfo.ts; + luaX_next(ls); + return ts; +} + + +static void init_exp (expdesc *e, expkind k, int i) { + e->f = e->t = NO_JUMP; + e->k = k; + e->u.info = i; +} + + +static void codestring (LexState *ls, expdesc *e, TString *s) { + init_exp(e, VK, luaK_stringK(ls->fs, s)); +} + + +static void checkname (LexState *ls, expdesc *e) { + codestring(ls, e, str_checkname(ls)); +} + + +static int registerlocalvar (LexState *ls, TString *varname) { + FuncState *fs = ls->fs; + Proto *f = fs->f; + int oldsize = f->sizelocvars; + luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars, + LocVar, SHRT_MAX, "local variables"); + while (oldsize < f->sizelocvars) + f->locvars[oldsize++].varname = NULL; + f->locvars[fs->nlocvars].varname = varname; + luaC_objbarrier(ls->L, f, varname); + return fs->nlocvars++; +} + + +static void new_localvar (LexState *ls, TString *name) { + FuncState *fs = ls->fs; + Dyndata *dyd = ls->dyd; + int reg = registerlocalvar(ls, name); + checklimit(fs, dyd->actvar.n + 1 - fs->firstlocal, + MAXVARS, "local variables"); + luaM_growvector(ls->L, dyd->actvar.arr, dyd->actvar.n + 1, + dyd->actvar.size, Vardesc, MAX_INT, "local variables"); + dyd->actvar.arr[dyd->actvar.n++].idx = cast(short, reg); +} + + +static void new_localvarliteral_ (LexState *ls, const char *name, size_t sz) { + new_localvar(ls, luaX_newstring(ls, name, sz)); +} + +#define new_localvarliteral(ls,v) \ + new_localvarliteral_(ls, "" v, (sizeof(v)/sizeof(char))-1) + + +static LocVar *getlocvar (FuncState *fs, int i) { + int idx = fs->ls->dyd->actvar.arr[fs->firstlocal + i].idx; + lua_assert(idx < fs->nlocvars); + return &fs->f->locvars[idx]; +} + + +static void adjustlocalvars (LexState *ls, int nvars) { + FuncState *fs = ls->fs; + fs->nactvar = cast_byte(fs->nactvar + nvars); + for (; nvars; nvars--) { + getlocvar(fs, fs->nactvar - nvars)->startpc = fs->pc; + } +} + + +static void removevars (FuncState *fs, int tolevel) { + fs->ls->dyd->actvar.n -= (fs->nactvar - tolevel); + while (fs->nactvar > tolevel) + getlocvar(fs, --fs->nactvar)->endpc = fs->pc; +} + + +static int searchupvalue (FuncState *fs, TString *name) { + int i; + Upvaldesc *up = fs->f->upvalues; + for (i = 0; i < fs->nups; i++) { + if (eqstr(up[i].name, name)) return i; + } + return -1; /* not found */ +} + + +static int newupvalue (FuncState *fs, TString *name, expdesc *v) { + Proto *f = fs->f; + int oldsize = f->sizeupvalues; + checklimit(fs, fs->nups + 1, MAXUPVAL, "upvalues"); + luaM_growvector(fs->ls->L, f->upvalues, fs->nups, f->sizeupvalues, + Upvaldesc, MAXUPVAL, "upvalues"); + while (oldsize < f->sizeupvalues) + f->upvalues[oldsize++].name = NULL; + f->upvalues[fs->nups].instack = (v->k == VLOCAL); + f->upvalues[fs->nups].idx = cast_byte(v->u.info); + f->upvalues[fs->nups].name = name; + luaC_objbarrier(fs->ls->L, f, name); + return fs->nups++; +} + + +static int searchvar (FuncState *fs, TString *n) { + int i; + for (i = cast_int(fs->nactvar) - 1; i >= 0; i--) { + if (eqstr(n, getlocvar(fs, i)->varname)) + return i; + } + return -1; /* not found */ +} + + +/* + Mark block where variable at given level was defined + (to emit close instructions later). +*/ +static void markupval (FuncState *fs, int level) { + BlockCnt *bl = fs->bl; + while (bl->nactvar > level) + bl = bl->previous; + bl->upval = 1; +} + + +/* + Find variable with given name 'n'. If it is an upvalue, add this + upvalue into all intermediate functions. +*/ +static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) { + if (fs == NULL) /* no more levels? */ + init_exp(var, VVOID, 0); /* default is global */ + else { + int v = searchvar(fs, n); /* look up locals at current level */ + if (v >= 0) { /* found? */ + init_exp(var, VLOCAL, v); /* variable is local */ + if (!base) + markupval(fs, v); /* local will be used as an upval */ + } + else { /* not found as local at current level; try upvalues */ + int idx = searchupvalue(fs, n); /* try existing upvalues */ + if (idx < 0) { /* not found? */ + singlevaraux(fs->prev, n, var, 0); /* try upper levels */ + if (var->k == VVOID) /* not found? */ + return; /* it is a global */ + /* else was LOCAL or UPVAL */ + idx = newupvalue(fs, n, var); /* will be a new upvalue */ + } + init_exp(var, VUPVAL, idx); /* new or old upvalue */ + } + } +} + + +static void singlevar (LexState *ls, expdesc *var) { + TString *varname = str_checkname(ls); + FuncState *fs = ls->fs; + singlevaraux(fs, varname, var, 1); + if (var->k == VVOID) { /* global name? */ + expdesc key; + singlevaraux(fs, ls->envn, var, 1); /* get environment variable */ + lua_assert(var->k != VVOID); /* this one must exist */ + codestring(ls, &key, varname); /* key is variable name */ + luaK_indexed(fs, var, &key); /* env[varname] */ + } +} + + +static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) { + FuncState *fs = ls->fs; + int extra = nvars - nexps; + if (hasmultret(e->k)) { + extra++; /* includes call itself */ + if (extra < 0) extra = 0; + luaK_setreturns(fs, e, extra); /* last exp. provides the difference */ + if (extra > 1) luaK_reserveregs(fs, extra-1); + } + else { + if (e->k != VVOID) luaK_exp2nextreg(fs, e); /* close last expression */ + if (extra > 0) { + int reg = fs->freereg; + luaK_reserveregs(fs, extra); + luaK_nil(fs, reg, extra); + } + } + if (nexps > nvars) + ls->fs->freereg -= nexps - nvars; /* remove extra values */ +} + + +static void enterlevel (LexState *ls) { + lua_State *L = ls->L; + ++L->nCcalls; + checklimit(ls->fs, L->nCcalls, LUAI_MAXCCALLS, "C levels"); +} + + +#define leavelevel(ls) ((ls)->L->nCcalls--) + + +static void closegoto (LexState *ls, int g, Labeldesc *label) { + int i; + FuncState *fs = ls->fs; + Labellist *gl = &ls->dyd->gt; + Labeldesc *gt = &gl->arr[g]; + lua_assert(eqstr(gt->name, label->name)); + if (gt->nactvar < label->nactvar) { + TString *vname = getlocvar(fs, gt->nactvar)->varname; + const char *msg = luaO_pushfstring(ls->L, + " at line %d jumps into the scope of local '%s'", + getstr(gt->name), gt->line, getstr(vname)); + semerror(ls, msg); + } + luaK_patchlist(fs, gt->pc, label->pc); + /* remove goto from pending list */ + for (i = g; i < gl->n - 1; i++) + gl->arr[i] = gl->arr[i + 1]; + gl->n--; +} + + +/* +** try to close a goto with existing labels; this solves backward jumps +*/ +static int findlabel (LexState *ls, int g) { + int i; + BlockCnt *bl = ls->fs->bl; + Dyndata *dyd = ls->dyd; + Labeldesc *gt = &dyd->gt.arr[g]; + /* check labels in current block for a match */ + for (i = bl->firstlabel; i < dyd->label.n; i++) { + Labeldesc *lb = &dyd->label.arr[i]; + if (eqstr(lb->name, gt->name)) { /* correct label? */ + if (gt->nactvar > lb->nactvar && + (bl->upval || dyd->label.n > bl->firstlabel)) + luaK_patchclose(ls->fs, gt->pc, lb->nactvar); + closegoto(ls, g, lb); /* close it */ + return 1; + } + } + return 0; /* label not found; cannot close goto */ +} + + +static int newlabelentry (LexState *ls, Labellist *l, TString *name, + int line, int pc) { + int n = l->n; + luaM_growvector(ls->L, l->arr, n, l->size, + Labeldesc, SHRT_MAX, "labels/gotos"); + l->arr[n].name = name; + l->arr[n].line = line; + l->arr[n].nactvar = ls->fs->nactvar; + l->arr[n].pc = pc; + l->n = n + 1; + return n; +} + + +/* +** check whether new label 'lb' matches any pending gotos in current +** block; solves forward jumps +*/ +static void findgotos (LexState *ls, Labeldesc *lb) { + Labellist *gl = &ls->dyd->gt; + int i = ls->fs->bl->firstgoto; + while (i < gl->n) { + if (eqstr(gl->arr[i].name, lb->name)) + closegoto(ls, i, lb); + else + i++; + } +} + + +/* +** export pending gotos to outer level, to check them against +** outer labels; if the block being exited has upvalues, and +** the goto exits the scope of any variable (which can be the +** upvalue), close those variables being exited. +*/ +static void movegotosout (FuncState *fs, BlockCnt *bl) { + int i = bl->firstgoto; + Labellist *gl = &fs->ls->dyd->gt; + /* correct pending gotos to current block and try to close it + with visible labels */ + while (i < gl->n) { + Labeldesc *gt = &gl->arr[i]; + if (gt->nactvar > bl->nactvar) { + if (bl->upval) + luaK_patchclose(fs, gt->pc, bl->nactvar); + gt->nactvar = bl->nactvar; + } + if (!findlabel(fs->ls, i)) + i++; /* move to next one */ + } +} + + +static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isloop) { + bl->isloop = isloop; + bl->nactvar = fs->nactvar; + bl->firstlabel = fs->ls->dyd->label.n; + bl->firstgoto = fs->ls->dyd->gt.n; + bl->upval = 0; + bl->previous = fs->bl; + fs->bl = bl; + lua_assert(fs->freereg == fs->nactvar); +} + + +/* +** create a label named 'break' to resolve break statements +*/ +static void breaklabel (LexState *ls) { + TString *n = luaS_new(ls->L, "break"); + int l = newlabelentry(ls, &ls->dyd->label, n, 0, ls->fs->pc); + findgotos(ls, &ls->dyd->label.arr[l]); +} + +/* +** generates an error for an undefined 'goto'; choose appropriate +** message when label name is a reserved word (which can only be 'break') +*/ +static l_noret undefgoto (LexState *ls, Labeldesc *gt) { + const char *msg = isreserved(gt->name) + ? "<%s> at line %d not inside a loop" + : "no visible label '%s' for at line %d"; + msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line); + semerror(ls, msg); +} + + +static void leaveblock (FuncState *fs) { + BlockCnt *bl = fs->bl; + LexState *ls = fs->ls; + if (bl->previous && bl->upval) { + /* create a 'jump to here' to close upvalues */ + int j = luaK_jump(fs); + luaK_patchclose(fs, j, bl->nactvar); + luaK_patchtohere(fs, j); + } + if (bl->isloop) + breaklabel(ls); /* close pending breaks */ + fs->bl = bl->previous; + removevars(fs, bl->nactvar); + lua_assert(bl->nactvar == fs->nactvar); + fs->freereg = fs->nactvar; /* free registers */ + ls->dyd->label.n = bl->firstlabel; /* remove local labels */ + if (bl->previous) /* inner block? */ + movegotosout(fs, bl); /* update pending gotos to outer block */ + else if (bl->firstgoto < ls->dyd->gt.n) /* pending gotos in outer block? */ + undefgoto(ls, &ls->dyd->gt.arr[bl->firstgoto]); /* error */ +} + + +/* +** adds a new prototype into list of prototypes +*/ +static Proto *addprototype (LexState *ls) { + Proto *clp; + lua_State *L = ls->L; + FuncState *fs = ls->fs; + Proto *f = fs->f; /* prototype of current function */ + if (fs->np >= f->sizep) { + int oldsize = f->sizep; + luaM_growvector(L, f->p, fs->np, f->sizep, Proto *, MAXARG_Bx, "functions"); + while (oldsize < f->sizep) + f->p[oldsize++] = NULL; + } + f->p[fs->np++] = clp = luaF_newproto(L); + luaC_objbarrier(L, f, clp); + return clp; +} + + +/* +** codes instruction to create new closure in parent function. +** The OP_CLOSURE instruction must use the last available register, +** so that, if it invokes the GC, the GC knows which registers +** are in use at that time. +*/ +static void codeclosure (LexState *ls, expdesc *v) { + FuncState *fs = ls->fs->prev; + init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np - 1)); + luaK_exp2nextreg(fs, v); /* fix it at the last register */ +} + + +static void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) { + Proto *f; + fs->prev = ls->fs; /* linked list of funcstates */ + fs->ls = ls; + ls->fs = fs; + fs->pc = 0; + fs->lasttarget = 0; + fs->jpc = NO_JUMP; + fs->freereg = 0; + fs->nk = 0; + fs->np = 0; + fs->nups = 0; + fs->nlocvars = 0; + fs->nactvar = 0; + fs->firstlocal = ls->dyd->actvar.n; + fs->bl = NULL; + f = fs->f; + f->source = ls->source; + luaC_objbarrier(ls->L, f, f->source); + f->maxstacksize = 2; /* registers 0/1 are always valid */ + enterblock(fs, bl, 0); +} + + +static void close_func (LexState *ls) { + lua_State *L = ls->L; + FuncState *fs = ls->fs; + Proto *f = fs->f; + luaK_ret(fs, 0, 0); /* final return */ + leaveblock(fs); + luaM_reallocvector(L, f->code, f->sizecode, fs->pc, Instruction); + f->sizecode = fs->pc; + luaM_reallocvector(L, f->lineinfo, f->sizelineinfo, fs->pc, int); + f->sizelineinfo = fs->pc; + luaM_reallocvector(L, f->k, f->sizek, fs->nk, TValue); + f->sizek = fs->nk; + luaM_reallocvector(L, f->p, f->sizep, fs->np, Proto *); + f->sizep = fs->np; + luaM_reallocvector(L, f->locvars, f->sizelocvars, fs->nlocvars, LocVar); + f->sizelocvars = fs->nlocvars; + luaM_reallocvector(L, f->upvalues, f->sizeupvalues, fs->nups, Upvaldesc); + f->sizeupvalues = fs->nups; + lua_assert(fs->bl == NULL); + ls->fs = fs->prev; + luaC_checkGC(L); +} + + + +/*============================================================*/ +/* GRAMMAR RULES */ +/*============================================================*/ + + +/* +** check whether current token is in the follow set of a block. +** 'until' closes syntactical blocks, but do not close scope, +** so it is handled in separate. +*/ +static int block_follow (LexState *ls, int withuntil) { + switch (ls->t.token) { + case TK_ELSE: case TK_ELSEIF: + case TK_END: case TK_EOS: + return 1; + case TK_UNTIL: return withuntil; + default: return 0; + } +} + + +static void statlist (LexState *ls) { + /* statlist -> { stat [';'] } */ + while (!block_follow(ls, 1)) { + if (ls->t.token == TK_RETURN) { + statement(ls); + return; /* 'return' must be last statement */ + } + statement(ls); + } +} + + +static void fieldsel (LexState *ls, expdesc *v) { + /* fieldsel -> ['.' | ':'] NAME */ + FuncState *fs = ls->fs; + expdesc key; + luaK_exp2anyregup(fs, v); + luaX_next(ls); /* skip the dot or colon */ + checkname(ls, &key); + luaK_indexed(fs, v, &key); +} + + +static void yindex (LexState *ls, expdesc *v) { + /* index -> '[' expr ']' */ + luaX_next(ls); /* skip the '[' */ + expr(ls, v); + luaK_exp2val(ls->fs, v); + checknext(ls, ']'); +} + + +/* +** {====================================================================== +** Rules for Constructors +** ======================================================================= +*/ + + +struct ConsControl { + expdesc v; /* last list item read */ + expdesc *t; /* table descriptor */ + int nh; /* total number of 'record' elements */ + int na; /* total number of array elements */ + int tostore; /* number of array elements pending to be stored */ +}; + + +static void recfield (LexState *ls, struct ConsControl *cc) { + /* recfield -> (NAME | '['exp1']') = exp1 */ + FuncState *fs = ls->fs; + int reg = ls->fs->freereg; + expdesc key, val; + int rkkey; + if (ls->t.token == TK_NAME) { + checklimit(fs, cc->nh, MAX_INT, "items in a constructor"); + checkname(ls, &key); + } + else /* ls->t.token == '[' */ + yindex(ls, &key); + cc->nh++; + checknext(ls, '='); + rkkey = luaK_exp2RK(fs, &key); + expr(ls, &val); + luaK_codeABC(fs, OP_SETTABLE, cc->t->u.info, rkkey, luaK_exp2RK(fs, &val)); + fs->freereg = reg; /* free registers */ +} + + +static void closelistfield (FuncState *fs, struct ConsControl *cc) { + if (cc->v.k == VVOID) return; /* there is no list item */ + luaK_exp2nextreg(fs, &cc->v); + cc->v.k = VVOID; + if (cc->tostore == LFIELDS_PER_FLUSH) { + luaK_setlist(fs, cc->t->u.info, cc->na, cc->tostore); /* flush */ + cc->tostore = 0; /* no more items pending */ + } +} + + +static void lastlistfield (FuncState *fs, struct ConsControl *cc) { + if (cc->tostore == 0) return; + if (hasmultret(cc->v.k)) { + luaK_setmultret(fs, &cc->v); + luaK_setlist(fs, cc->t->u.info, cc->na, LUA_MULTRET); + cc->na--; /* do not count last expression (unknown number of elements) */ + } + else { + if (cc->v.k != VVOID) + luaK_exp2nextreg(fs, &cc->v); + luaK_setlist(fs, cc->t->u.info, cc->na, cc->tostore); + } +} + + +static void listfield (LexState *ls, struct ConsControl *cc) { + /* listfield -> exp */ + expr(ls, &cc->v); + checklimit(ls->fs, cc->na, MAX_INT, "items in a constructor"); + cc->na++; + cc->tostore++; +} + + +static void field (LexState *ls, struct ConsControl *cc) { + /* field -> listfield | recfield */ + switch(ls->t.token) { + case TK_NAME: { /* may be 'listfield' or 'recfield' */ + if (luaX_lookahead(ls) != '=') /* expression? */ + listfield(ls, cc); + else + recfield(ls, cc); + break; + } + case '[': { + recfield(ls, cc); + break; + } + default: { + listfield(ls, cc); + break; + } + } +} + + +static void constructor (LexState *ls, expdesc *t) { + /* constructor -> '{' [ field { sep field } [sep] ] '}' + sep -> ',' | ';' */ + FuncState *fs = ls->fs; + int line = ls->linenumber; + int pc = luaK_codeABC(fs, OP_NEWTABLE, 0, 0, 0); + struct ConsControl cc; + cc.na = cc.nh = cc.tostore = 0; + cc.t = t; + init_exp(t, VRELOCABLE, pc); + init_exp(&cc.v, VVOID, 0); /* no value (yet) */ + luaK_exp2nextreg(ls->fs, t); /* fix it at stack top */ + checknext(ls, '{'); + do { + lua_assert(cc.v.k == VVOID || cc.tostore > 0); + if (ls->t.token == '}') break; + closelistfield(fs, &cc); + field(ls, &cc); + } while (testnext(ls, ',') || testnext(ls, ';')); + check_match(ls, '}', '{', line); + lastlistfield(fs, &cc); + SETARG_B(fs->f->code[pc], luaO_int2fb(cc.na)); /* set initial array size */ + SETARG_C(fs->f->code[pc], luaO_int2fb(cc.nh)); /* set initial table size */ +} + +/* }====================================================================== */ + + + +static void parlist (LexState *ls) { + /* parlist -> [ param { ',' param } ] */ + FuncState *fs = ls->fs; + Proto *f = fs->f; + int nparams = 0; + f->is_vararg = 0; + if (ls->t.token != ')') { /* is 'parlist' not empty? */ + do { + switch (ls->t.token) { + case TK_NAME: { /* param -> NAME */ + new_localvar(ls, str_checkname(ls)); + nparams++; + break; + } + case TK_DOTS: { /* param -> '...' */ + luaX_next(ls); + f->is_vararg = 1; /* declared vararg */ + break; + } + default: luaX_syntaxerror(ls, " or '...' expected"); + } + } while (!f->is_vararg && testnext(ls, ',')); + } + adjustlocalvars(ls, nparams); + f->numparams = cast_byte(fs->nactvar); + luaK_reserveregs(fs, fs->nactvar); /* reserve register for parameters */ +} + + +static void body (LexState *ls, expdesc *e, int ismethod, int line) { + /* body -> '(' parlist ')' block END */ + FuncState new_fs; + BlockCnt bl; + new_fs.f = addprototype(ls); + new_fs.f->linedefined = line; + open_func(ls, &new_fs, &bl); + checknext(ls, '('); + if (ismethod) { + new_localvarliteral(ls, "self"); /* create 'self' parameter */ + adjustlocalvars(ls, 1); + } + parlist(ls); + checknext(ls, ')'); + statlist(ls); + new_fs.f->lastlinedefined = ls->linenumber; + check_match(ls, TK_END, TK_FUNCTION, line); + codeclosure(ls, e); + close_func(ls); +} + + +static int explist (LexState *ls, expdesc *v) { + /* explist -> expr { ',' expr } */ + int n = 1; /* at least one expression */ + expr(ls, v); + while (testnext(ls, ',')) { + luaK_exp2nextreg(ls->fs, v); + expr(ls, v); + n++; + } + return n; +} + + +static void funcargs (LexState *ls, expdesc *f, int line) { + FuncState *fs = ls->fs; + expdesc args; + int base, nparams; + switch (ls->t.token) { + case '(': { /* funcargs -> '(' [ explist ] ')' */ + luaX_next(ls); + if (ls->t.token == ')') /* arg list is empty? */ + args.k = VVOID; + else { + explist(ls, &args); + luaK_setmultret(fs, &args); + } + check_match(ls, ')', '(', line); + break; + } + case '{': { /* funcargs -> constructor */ + constructor(ls, &args); + break; + } + case TK_STRING: { /* funcargs -> STRING */ + codestring(ls, &args, ls->t.seminfo.ts); + luaX_next(ls); /* must use 'seminfo' before 'next' */ + break; + } + default: { + luaX_syntaxerror(ls, "function arguments expected"); + } + } + lua_assert(f->k == VNONRELOC); + base = f->u.info; /* base register for call */ + if (hasmultret(args.k)) + nparams = LUA_MULTRET; /* open call */ + else { + if (args.k != VVOID) + luaK_exp2nextreg(fs, &args); /* close last argument */ + nparams = fs->freereg - (base+1); + } + init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams+1, 2)); + luaK_fixline(fs, line); + fs->freereg = base+1; /* call remove function and arguments and leaves + (unless changed) one result */ +} + + + + +/* +** {====================================================================== +** Expression parsing +** ======================================================================= +*/ + + +static void primaryexp (LexState *ls, expdesc *v) { + /* primaryexp -> NAME | '(' expr ')' */ + switch (ls->t.token) { + case '(': { + int line = ls->linenumber; + luaX_next(ls); + expr(ls, v); + check_match(ls, ')', '(', line); + luaK_dischargevars(ls->fs, v); + return; + } + case TK_NAME: { + singlevar(ls, v); + return; + } + default: { + luaX_syntaxerror(ls, "unexpected symbol"); + } + } +} + + +static void suffixedexp (LexState *ls, expdesc *v) { + /* suffixedexp -> + primaryexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs } */ + FuncState *fs = ls->fs; + int line = ls->linenumber; + primaryexp(ls, v); + for (;;) { + switch (ls->t.token) { + case '.': { /* fieldsel */ + fieldsel(ls, v); + break; + } + case '[': { /* '[' exp1 ']' */ + expdesc key; + luaK_exp2anyregup(fs, v); + yindex(ls, &key); + luaK_indexed(fs, v, &key); + break; + } + case ':': { /* ':' NAME funcargs */ + expdesc key; + luaX_next(ls); + checkname(ls, &key); + luaK_self(fs, v, &key); + funcargs(ls, v, line); + break; + } + case '(': case TK_STRING: case '{': { /* funcargs */ + luaK_exp2nextreg(fs, v); + funcargs(ls, v, line); + break; + } + default: return; + } + } +} + + +static void simpleexp (LexState *ls, expdesc *v) { + /* simpleexp -> FLT | INT | STRING | NIL | TRUE | FALSE | ... | + constructor | FUNCTION body | suffixedexp */ + switch (ls->t.token) { + case TK_FLT: { + init_exp(v, VKFLT, 0); + v->u.nval = ls->t.seminfo.r; + break; + } + case TK_INT: { + init_exp(v, VKINT, 0); + v->u.ival = ls->t.seminfo.i; + break; + } + case TK_STRING: { + codestring(ls, v, ls->t.seminfo.ts); + break; + } + case TK_NIL: { + init_exp(v, VNIL, 0); + break; + } + case TK_TRUE: { + init_exp(v, VTRUE, 0); + break; + } + case TK_FALSE: { + init_exp(v, VFALSE, 0); + break; + } + case TK_DOTS: { /* vararg */ + FuncState *fs = ls->fs; + check_condition(ls, fs->f->is_vararg, + "cannot use '...' outside a vararg function"); + init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, 0)); + break; + } + case '{': { /* constructor */ + constructor(ls, v); + return; + } + case TK_FUNCTION: { + luaX_next(ls); + body(ls, v, 0, ls->linenumber); + return; + } + default: { + suffixedexp(ls, v); + return; + } + } + luaX_next(ls); +} + + +static UnOpr getunopr (int op) { + switch (op) { + case TK_NOT: return OPR_NOT; + case '-': return OPR_MINUS; + case '~': return OPR_BNOT; + case '#': return OPR_LEN; + default: return OPR_NOUNOPR; + } +} + + +static BinOpr getbinopr (int op) { + switch (op) { + case '+': return OPR_ADD; + case '-': return OPR_SUB; + case '*': return OPR_MUL; + case '%': return OPR_MOD; + case '^': return OPR_POW; + case '/': return OPR_DIV; + case TK_IDIV: return OPR_IDIV; + case '&': return OPR_BAND; + case '|': return OPR_BOR; + case '~': return OPR_BXOR; + case TK_SHL: return OPR_SHL; + case TK_SHR: return OPR_SHR; + case TK_CONCAT: return OPR_CONCAT; + case TK_NE: return OPR_NE; + case TK_EQ: return OPR_EQ; + case '<': return OPR_LT; + case TK_LE: return OPR_LE; + case '>': return OPR_GT; + case TK_GE: return OPR_GE; + case TK_AND: return OPR_AND; + case TK_OR: return OPR_OR; + default: return OPR_NOBINOPR; + } +} + + +static const struct { + lu_byte left; /* left priority for each binary operator */ + lu_byte right; /* right priority */ +} priority[] = { /* ORDER OPR */ + {10, 10}, {10, 10}, /* '+' '-' */ + {11, 11}, {11, 11}, /* '*' '%' */ + {14, 13}, /* '^' (right associative) */ + {11, 11}, {11, 11}, /* '/' '//' */ + {6, 6}, {4, 4}, {5, 5}, /* '&' '|' '~' */ + {7, 7}, {7, 7}, /* '<<' '>>' */ + {9, 8}, /* '..' (right associative) */ + {3, 3}, {3, 3}, {3, 3}, /* ==, <, <= */ + {3, 3}, {3, 3}, {3, 3}, /* ~=, >, >= */ + {2, 2}, {1, 1} /* and, or */ +}; + +#define UNARY_PRIORITY 12 /* priority for unary operators */ + + +/* +** subexpr -> (simpleexp | unop subexpr) { binop subexpr } +** where 'binop' is any binary operator with a priority higher than 'limit' +*/ +static BinOpr subexpr (LexState *ls, expdesc *v, int limit) { + BinOpr op; + UnOpr uop; + enterlevel(ls); + uop = getunopr(ls->t.token); + if (uop != OPR_NOUNOPR) { + int line = ls->linenumber; + luaX_next(ls); + subexpr(ls, v, UNARY_PRIORITY); + luaK_prefix(ls->fs, uop, v, line); + } + else simpleexp(ls, v); + /* expand while operators have priorities higher than 'limit' */ + op = getbinopr(ls->t.token); + while (op != OPR_NOBINOPR && priority[op].left > limit) { + expdesc v2; + BinOpr nextop; + int line = ls->linenumber; + luaX_next(ls); + luaK_infix(ls->fs, op, v); + /* read sub-expression with higher priority */ + nextop = subexpr(ls, &v2, priority[op].right); + luaK_posfix(ls->fs, op, v, &v2, line); + op = nextop; + } + leavelevel(ls); + return op; /* return first untreated operator */ +} + + +static void expr (LexState *ls, expdesc *v) { + subexpr(ls, v, 0); +} + +/* }==================================================================== */ + + + +/* +** {====================================================================== +** Rules for Statements +** ======================================================================= +*/ + + +static void block (LexState *ls) { + /* block -> statlist */ + FuncState *fs = ls->fs; + BlockCnt bl; + enterblock(fs, &bl, 0); + statlist(ls); + leaveblock(fs); +} + + +/* +** structure to chain all variables in the left-hand side of an +** assignment +*/ +struct LHS_assign { + struct LHS_assign *prev; + expdesc v; /* variable (global, local, upvalue, or indexed) */ +}; + + +/* +** check whether, in an assignment to an upvalue/local variable, the +** upvalue/local variable is begin used in a previous assignment to a +** table. If so, save original upvalue/local value in a safe place and +** use this safe copy in the previous assignment. +*/ +static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) { + FuncState *fs = ls->fs; + int extra = fs->freereg; /* eventual position to save local variable */ + int conflict = 0; + for (; lh; lh = lh->prev) { /* check all previous assignments */ + if (lh->v.k == VINDEXED) { /* assigning to a table? */ + /* table is the upvalue/local being assigned now? */ + if (lh->v.u.ind.vt == v->k && lh->v.u.ind.t == v->u.info) { + conflict = 1; + lh->v.u.ind.vt = VLOCAL; + lh->v.u.ind.t = extra; /* previous assignment will use safe copy */ + } + /* index is the local being assigned? (index cannot be upvalue) */ + if (v->k == VLOCAL && lh->v.u.ind.idx == v->u.info) { + conflict = 1; + lh->v.u.ind.idx = extra; /* previous assignment will use safe copy */ + } + } + } + if (conflict) { + /* copy upvalue/local value to a temporary (in position 'extra') */ + OpCode op = (v->k == VLOCAL) ? OP_MOVE : OP_GETUPVAL; + luaK_codeABC(fs, op, extra, v->u.info, 0); + luaK_reserveregs(fs, 1); + } +} + + +static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) { + expdesc e; + check_condition(ls, vkisvar(lh->v.k), "syntax error"); + if (testnext(ls, ',')) { /* assignment -> ',' suffixedexp assignment */ + struct LHS_assign nv; + nv.prev = lh; + suffixedexp(ls, &nv.v); + if (nv.v.k != VINDEXED) + check_conflict(ls, lh, &nv.v); + checklimit(ls->fs, nvars + ls->L->nCcalls, LUAI_MAXCCALLS, + "C levels"); + assignment(ls, &nv, nvars+1); + } + else { /* assignment -> '=' explist */ + int nexps; + checknext(ls, '='); + nexps = explist(ls, &e); + if (nexps != nvars) + adjust_assign(ls, nvars, nexps, &e); + else { + luaK_setoneret(ls->fs, &e); /* close last expression */ + luaK_storevar(ls->fs, &lh->v, &e); + return; /* avoid default */ + } + } + init_exp(&e, VNONRELOC, ls->fs->freereg-1); /* default assignment */ + luaK_storevar(ls->fs, &lh->v, &e); +} + + +static int cond (LexState *ls) { + /* cond -> exp */ + expdesc v; + expr(ls, &v); /* read condition */ + if (v.k == VNIL) v.k = VFALSE; /* 'falses' are all equal here */ + luaK_goiftrue(ls->fs, &v); + return v.f; +} + + +static void gotostat (LexState *ls, int pc) { + int line = ls->linenumber; + TString *label; + int g; + if (testnext(ls, TK_GOTO)) + label = str_checkname(ls); + else { + luaX_next(ls); /* skip break */ + label = luaS_new(ls->L, "break"); + } + g = newlabelentry(ls, &ls->dyd->gt, label, line, pc); + findlabel(ls, g); /* close it if label already defined */ +} + + +/* check for repeated labels on the same block */ +static void checkrepeated (FuncState *fs, Labellist *ll, TString *label) { + int i; + for (i = fs->bl->firstlabel; i < ll->n; i++) { + if (eqstr(label, ll->arr[i].name)) { + const char *msg = luaO_pushfstring(fs->ls->L, + "label '%s' already defined on line %d", + getstr(label), ll->arr[i].line); + semerror(fs->ls, msg); + } + } +} + + +/* skip no-op statements */ +static void skipnoopstat (LexState *ls) { + while (ls->t.token == ';' || ls->t.token == TK_DBCOLON) + statement(ls); +} + + +static void labelstat (LexState *ls, TString *label, int line) { + /* label -> '::' NAME '::' */ + FuncState *fs = ls->fs; + Labellist *ll = &ls->dyd->label; + int l; /* index of new label being created */ + checkrepeated(fs, ll, label); /* check for repeated labels */ + checknext(ls, TK_DBCOLON); /* skip double colon */ + /* create new entry for this label */ + l = newlabelentry(ls, ll, label, line, luaK_getlabel(fs)); + skipnoopstat(ls); /* skip other no-op statements */ + if (block_follow(ls, 0)) { /* label is last no-op statement in the block? */ + /* assume that locals are already out of scope */ + ll->arr[l].nactvar = fs->bl->nactvar; + } + findgotos(ls, &ll->arr[l]); +} + + +static void whilestat (LexState *ls, int line) { + /* whilestat -> WHILE cond DO block END */ + FuncState *fs = ls->fs; + int whileinit; + int condexit; + BlockCnt bl; + luaX_next(ls); /* skip WHILE */ + whileinit = luaK_getlabel(fs); + condexit = cond(ls); + enterblock(fs, &bl, 1); + checknext(ls, TK_DO); + block(ls); + luaK_jumpto(fs, whileinit); + check_match(ls, TK_END, TK_WHILE, line); + leaveblock(fs); + luaK_patchtohere(fs, condexit); /* false conditions finish the loop */ +} + + +static void repeatstat (LexState *ls, int line) { + /* repeatstat -> REPEAT block UNTIL cond */ + int condexit; + FuncState *fs = ls->fs; + int repeat_init = luaK_getlabel(fs); + BlockCnt bl1, bl2; + enterblock(fs, &bl1, 1); /* loop block */ + enterblock(fs, &bl2, 0); /* scope block */ + luaX_next(ls); /* skip REPEAT */ + statlist(ls); + check_match(ls, TK_UNTIL, TK_REPEAT, line); + condexit = cond(ls); /* read condition (inside scope block) */ + if (bl2.upval) /* upvalues? */ + luaK_patchclose(fs, condexit, bl2.nactvar); + leaveblock(fs); /* finish scope */ + luaK_patchlist(fs, condexit, repeat_init); /* close the loop */ + leaveblock(fs); /* finish loop */ +} + + +static int exp1 (LexState *ls) { + expdesc e; + int reg; + expr(ls, &e); + luaK_exp2nextreg(ls->fs, &e); + lua_assert(e.k == VNONRELOC); + reg = e.u.info; + return reg; +} + + +static void forbody (LexState *ls, int base, int line, int nvars, int isnum) { + /* forbody -> DO block */ + BlockCnt bl; + FuncState *fs = ls->fs; + int prep, endfor; + adjustlocalvars(ls, 3); /* control variables */ + checknext(ls, TK_DO); + prep = isnum ? luaK_codeAsBx(fs, OP_FORPREP, base, NO_JUMP) : luaK_jump(fs); + enterblock(fs, &bl, 0); /* scope for declared variables */ + adjustlocalvars(ls, nvars); + luaK_reserveregs(fs, nvars); + block(ls); + leaveblock(fs); /* end of scope for declared variables */ + luaK_patchtohere(fs, prep); + if (isnum) /* numeric for? */ + endfor = luaK_codeAsBx(fs, OP_FORLOOP, base, NO_JUMP); + else { /* generic for */ + luaK_codeABC(fs, OP_TFORCALL, base, 0, nvars); + luaK_fixline(fs, line); + endfor = luaK_codeAsBx(fs, OP_TFORLOOP, base + 2, NO_JUMP); + } + luaK_patchlist(fs, endfor, prep + 1); + luaK_fixline(fs, line); +} + + +static void fornum (LexState *ls, TString *varname, int line) { + /* fornum -> NAME = exp1,exp1[,exp1] forbody */ + FuncState *fs = ls->fs; + int base = fs->freereg; + new_localvarliteral(ls, "(for index)"); + new_localvarliteral(ls, "(for limit)"); + new_localvarliteral(ls, "(for step)"); + new_localvar(ls, varname); + checknext(ls, '='); + exp1(ls); /* initial value */ + checknext(ls, ','); + exp1(ls); /* limit */ + if (testnext(ls, ',')) + exp1(ls); /* optional step */ + else { /* default step = 1 */ + luaK_codek(fs, fs->freereg, luaK_intK(fs, 1)); + luaK_reserveregs(fs, 1); + } + forbody(ls, base, line, 1, 1); +} + + +static void forlist (LexState *ls, TString *indexname) { + /* forlist -> NAME {,NAME} IN explist forbody */ + FuncState *fs = ls->fs; + expdesc e; + int nvars = 4; /* gen, state, control, plus at least one declared var */ + int line; + int base = fs->freereg; + /* create control variables */ + new_localvarliteral(ls, "(for generator)"); + new_localvarliteral(ls, "(for state)"); + new_localvarliteral(ls, "(for control)"); + /* create declared variables */ + new_localvar(ls, indexname); + while (testnext(ls, ',')) { + new_localvar(ls, str_checkname(ls)); + nvars++; + } + checknext(ls, TK_IN); + line = ls->linenumber; + adjust_assign(ls, 3, explist(ls, &e), &e); + luaK_checkstack(fs, 3); /* extra space to call generator */ + forbody(ls, base, line, nvars - 3, 0); +} + + +static void forstat (LexState *ls, int line) { + /* forstat -> FOR (fornum | forlist) END */ + FuncState *fs = ls->fs; + TString *varname; + BlockCnt bl; + enterblock(fs, &bl, 1); /* scope for loop and control variables */ + luaX_next(ls); /* skip 'for' */ + varname = str_checkname(ls); /* first variable name */ + switch (ls->t.token) { + case '=': fornum(ls, varname, line); break; + case ',': case TK_IN: forlist(ls, varname); break; + default: luaX_syntaxerror(ls, "'=' or 'in' expected"); + } + check_match(ls, TK_END, TK_FOR, line); + leaveblock(fs); /* loop scope ('break' jumps to this point) */ +} + + +static void test_then_block (LexState *ls, int *escapelist) { + /* test_then_block -> [IF | ELSEIF] cond THEN block */ + BlockCnt bl; + FuncState *fs = ls->fs; + expdesc v; + int jf; /* instruction to skip 'then' code (if condition is false) */ + luaX_next(ls); /* skip IF or ELSEIF */ + expr(ls, &v); /* read condition */ + checknext(ls, TK_THEN); + if (ls->t.token == TK_GOTO || ls->t.token == TK_BREAK) { + luaK_goiffalse(ls->fs, &v); /* will jump to label if condition is true */ + enterblock(fs, &bl, 0); /* must enter block before 'goto' */ + gotostat(ls, v.t); /* handle goto/break */ + while (testnext(ls, ';')) {} /* skip colons */ + if (block_follow(ls, 0)) { /* 'goto' is the entire block? */ + leaveblock(fs); + return; /* and that is it */ + } + else /* must skip over 'then' part if condition is false */ + jf = luaK_jump(fs); + } + else { /* regular case (not goto/break) */ + luaK_goiftrue(ls->fs, &v); /* skip over block if condition is false */ + enterblock(fs, &bl, 0); + jf = v.f; + } + statlist(ls); /* 'then' part */ + leaveblock(fs); + if (ls->t.token == TK_ELSE || + ls->t.token == TK_ELSEIF) /* followed by 'else'/'elseif'? */ + luaK_concat(fs, escapelist, luaK_jump(fs)); /* must jump over it */ + luaK_patchtohere(fs, jf); +} + + +static void ifstat (LexState *ls, int line) { + /* ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END */ + FuncState *fs = ls->fs; + int escapelist = NO_JUMP; /* exit list for finished parts */ + test_then_block(ls, &escapelist); /* IF cond THEN block */ + while (ls->t.token == TK_ELSEIF) + test_then_block(ls, &escapelist); /* ELSEIF cond THEN block */ + if (testnext(ls, TK_ELSE)) + block(ls); /* 'else' part */ + check_match(ls, TK_END, TK_IF, line); + luaK_patchtohere(fs, escapelist); /* patch escape list to 'if' end */ +} + + +static void localfunc (LexState *ls) { + expdesc b; + FuncState *fs = ls->fs; + new_localvar(ls, str_checkname(ls)); /* new local variable */ + adjustlocalvars(ls, 1); /* enter its scope */ + body(ls, &b, 0, ls->linenumber); /* function created in next register */ + /* debug information will only see the variable after this point! */ + getlocvar(fs, b.u.info)->startpc = fs->pc; +} + + +static void localstat (LexState *ls) { + /* stat -> LOCAL NAME {',' NAME} ['=' explist] */ + int nvars = 0; + int nexps; + expdesc e; + do { + new_localvar(ls, str_checkname(ls)); + nvars++; + } while (testnext(ls, ',')); + if (testnext(ls, '=')) + nexps = explist(ls, &e); + else { + e.k = VVOID; + nexps = 0; + } + adjust_assign(ls, nvars, nexps, &e); + adjustlocalvars(ls, nvars); +} + + +static int funcname (LexState *ls, expdesc *v) { + /* funcname -> NAME {fieldsel} [':' NAME] */ + int ismethod = 0; + singlevar(ls, v); + while (ls->t.token == '.') + fieldsel(ls, v); + if (ls->t.token == ':') { + ismethod = 1; + fieldsel(ls, v); + } + return ismethod; +} + + +static void funcstat (LexState *ls, int line) { + /* funcstat -> FUNCTION funcname body */ + int ismethod; + expdesc v, b; + luaX_next(ls); /* skip FUNCTION */ + ismethod = funcname(ls, &v); + body(ls, &b, ismethod, line); + luaK_storevar(ls->fs, &v, &b); + luaK_fixline(ls->fs, line); /* definition "happens" in the first line */ +} + + +static void exprstat (LexState *ls) { + /* stat -> func | assignment */ + FuncState *fs = ls->fs; + struct LHS_assign v; + suffixedexp(ls, &v.v); + if (ls->t.token == '=' || ls->t.token == ',') { /* stat -> assignment ? */ + v.prev = NULL; + assignment(ls, &v, 1); + } + else { /* stat -> func */ + check_condition(ls, v.v.k == VCALL, "syntax error"); + SETARG_C(getinstruction(fs, &v.v), 1); /* call statement uses no results */ + } +} + + +static void retstat (LexState *ls) { + /* stat -> RETURN [explist] [';'] */ + FuncState *fs = ls->fs; + expdesc e; + int first, nret; /* registers with returned values */ + if (block_follow(ls, 1) || ls->t.token == ';') + first = nret = 0; /* return no values */ + else { + nret = explist(ls, &e); /* optional return values */ + if (hasmultret(e.k)) { + luaK_setmultret(fs, &e); + if (e.k == VCALL && nret == 1) { /* tail call? */ + SET_OPCODE(getinstruction(fs,&e), OP_TAILCALL); + lua_assert(GETARG_A(getinstruction(fs,&e)) == fs->nactvar); + } + first = fs->nactvar; + nret = LUA_MULTRET; /* return all values */ + } + else { + if (nret == 1) /* only one single value? */ + first = luaK_exp2anyreg(fs, &e); + else { + luaK_exp2nextreg(fs, &e); /* values must go to the stack */ + first = fs->nactvar; /* return all active values */ + lua_assert(nret == fs->freereg - first); + } + } + } + luaK_ret(fs, first, nret); + testnext(ls, ';'); /* skip optional semicolon */ +} + + +static void statement (LexState *ls) { + int line = ls->linenumber; /* may be needed for error messages */ + enterlevel(ls); + switch (ls->t.token) { + case ';': { /* stat -> ';' (empty statement) */ + luaX_next(ls); /* skip ';' */ + break; + } + case TK_IF: { /* stat -> ifstat */ + ifstat(ls, line); + break; + } + case TK_WHILE: { /* stat -> whilestat */ + whilestat(ls, line); + break; + } + case TK_DO: { /* stat -> DO block END */ + luaX_next(ls); /* skip DO */ + block(ls); + check_match(ls, TK_END, TK_DO, line); + break; + } + case TK_FOR: { /* stat -> forstat */ + forstat(ls, line); + break; + } + case TK_REPEAT: { /* stat -> repeatstat */ + repeatstat(ls, line); + break; + } + case TK_FUNCTION: { /* stat -> funcstat */ + funcstat(ls, line); + break; + } + case TK_LOCAL: { /* stat -> localstat */ + luaX_next(ls); /* skip LOCAL */ + if (testnext(ls, TK_FUNCTION)) /* local function? */ + localfunc(ls); + else + localstat(ls); + break; + } + case TK_DBCOLON: { /* stat -> label */ + luaX_next(ls); /* skip double colon */ + labelstat(ls, str_checkname(ls), line); + break; + } + case TK_RETURN: { /* stat -> retstat */ + luaX_next(ls); /* skip RETURN */ + retstat(ls); + break; + } + case TK_BREAK: /* stat -> breakstat */ + case TK_GOTO: { /* stat -> 'goto' NAME */ + gotostat(ls, luaK_jump(ls->fs)); + break; + } + default: { /* stat -> func | assignment */ + exprstat(ls); + break; + } + } + lua_assert(ls->fs->f->maxstacksize >= ls->fs->freereg && + ls->fs->freereg >= ls->fs->nactvar); + ls->fs->freereg = ls->fs->nactvar; /* free registers */ + leavelevel(ls); +} + +/* }====================================================================== */ + + +/* +** compiles the main function, which is a regular vararg function with an +** upvalue named LUA_ENV +*/ +static void mainfunc (LexState *ls, FuncState *fs) { + BlockCnt bl; + expdesc v; + open_func(ls, fs, &bl); + fs->f->is_vararg = 1; /* main function is always declared vararg */ + init_exp(&v, VLOCAL, 0); /* create and... */ + newupvalue(fs, ls->envn, &v); /* ...set environment upvalue */ + luaC_objbarrier(ls->L, fs->f, ls->envn); + luaX_next(ls); /* read first token */ + statlist(ls); /* parse main body */ + check(ls, TK_EOS); + close_func(ls); +} + + +LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, + Dyndata *dyd, const char *name, int firstchar) { + LexState lexstate; + FuncState funcstate; + LClosure *cl = luaF_newLclosure(L, 1); /* create main closure */ + setclLvalue(L, L->top, cl); /* anchor it (to avoid being collected) */ + luaD_inctop(L); + lexstate.h = luaH_new(L); /* create table for scanner */ + sethvalue(L, L->top, lexstate.h); /* anchor it */ + luaD_inctop(L); + funcstate.f = cl->p = luaF_newproto(L); + luaC_objbarrier(L, cl, cl->p); + funcstate.f->source = luaS_new(L, name); /* create and anchor TString */ + lua_assert(iswhite(funcstate.f)); /* do not need barrier here */ + lexstate.buff = buff; + lexstate.dyd = dyd; + dyd->actvar.n = dyd->gt.n = dyd->label.n = 0; + luaX_setinput(L, &lexstate, z, funcstate.f->source, firstchar); + mainfunc(&lexstate, &funcstate); + lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs); + /* all scopes should be correctly finished */ + lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0); + L->top--; /* remove scanner's table */ + return cl; /* closure is on the stack, too */ +} + diff --git a/depends/lua/src/lstate.c b/depends/lua/src/lstate.c new file mode 100644 index 0000000000..c1a76643c3 --- /dev/null +++ b/depends/lua/src/lstate.c @@ -0,0 +1,347 @@ +/* +** $Id: lstate.c,v 2.133.1.1 2017/04/19 17:39:34 roberto Exp $ +** Global State +** See Copyright Notice in lua.h +*/ + +#define lstate_c +#define LUA_CORE + +#include "lprefix.h" + + +#include +#include + +#include "lua.h" + +#include "lapi.h" +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "lgc.h" +#include "llex.h" +#include "lmem.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" + + +#if !defined(LUAI_GCPAUSE) +#define LUAI_GCPAUSE 200 /* 200% */ +#endif + +#if !defined(LUAI_GCMUL) +#define LUAI_GCMUL 200 /* GC runs 'twice the speed' of memory allocation */ +#endif + + +/* +** a macro to help the creation of a unique random seed when a state is +** created; the seed is used to randomize hashes. +*/ +#if !defined(luai_makeseed) +#include +#define luai_makeseed() cast(unsigned int, time(NULL)) +#endif + + + +/* +** thread state + extra space +*/ +typedef struct LX { + lu_byte extra_[LUA_EXTRASPACE]; + lua_State l; +} LX; + + +/* +** Main thread combines a thread state and the global state +*/ +typedef struct LG { + LX l; + global_State g; +} LG; + + + +#define fromstate(L) (cast(LX *, cast(lu_byte *, (L)) - offsetof(LX, l))) + + +/* +** Compute an initial seed as random as possible. Rely on Address Space +** Layout Randomization (if present) to increase randomness.. +*/ +#define addbuff(b,p,e) \ + { size_t t = cast(size_t, e); \ + memcpy(b + p, &t, sizeof(t)); p += sizeof(t); } + +static unsigned int makeseed (lua_State *L) { + char buff[4 * sizeof(size_t)]; + unsigned int h = luai_makeseed(); + int p = 0; + addbuff(buff, p, L); /* heap variable */ + addbuff(buff, p, &h); /* local variable */ + addbuff(buff, p, luaO_nilobject); /* global variable */ + addbuff(buff, p, &lua_newstate); /* public function */ + lua_assert(p == sizeof(buff)); + return luaS_hash(buff, p, h); +} + + +/* +** set GCdebt to a new value keeping the value (totalbytes + GCdebt) +** invariant (and avoiding underflows in 'totalbytes') +*/ +void luaE_setdebt (global_State *g, l_mem debt) { + l_mem tb = gettotalbytes(g); + lua_assert(tb > 0); + if (debt < tb - MAX_LMEM) + debt = tb - MAX_LMEM; /* will make 'totalbytes == MAX_LMEM' */ + g->totalbytes = tb - debt; + g->GCdebt = debt; +} + + +CallInfo *luaE_extendCI (lua_State *L) { + CallInfo *ci = luaM_new(L, CallInfo); + lua_assert(L->ci->next == NULL); + L->ci->next = ci; + ci->previous = L->ci; + ci->next = NULL; + L->nci++; + return ci; +} + + +/* +** free all CallInfo structures not in use by a thread +*/ +void luaE_freeCI (lua_State *L) { + CallInfo *ci = L->ci; + CallInfo *next = ci->next; + ci->next = NULL; + while ((ci = next) != NULL) { + next = ci->next; + luaM_free(L, ci); + L->nci--; + } +} + + +/* +** free half of the CallInfo structures not in use by a thread +*/ +void luaE_shrinkCI (lua_State *L) { + CallInfo *ci = L->ci; + CallInfo *next2; /* next's next */ + /* while there are two nexts */ + while (ci->next != NULL && (next2 = ci->next->next) != NULL) { + luaM_free(L, ci->next); /* free next */ + L->nci--; + ci->next = next2; /* remove 'next' from the list */ + next2->previous = ci; + ci = next2; /* keep next's next */ + } +} + + +static void stack_init (lua_State *L1, lua_State *L) { + int i; CallInfo *ci; + /* initialize stack array */ + L1->stack = luaM_newvector(L, BASIC_STACK_SIZE, TValue); + L1->stacksize = BASIC_STACK_SIZE; + for (i = 0; i < BASIC_STACK_SIZE; i++) + setnilvalue(L1->stack + i); /* erase new stack */ + L1->top = L1->stack; + L1->stack_last = L1->stack + L1->stacksize - EXTRA_STACK; + /* initialize first ci */ + ci = &L1->base_ci; + ci->next = ci->previous = NULL; + ci->callstatus = 0; + ci->func = L1->top; + setnilvalue(L1->top++); /* 'function' entry for this 'ci' */ + ci->top = L1->top + LUA_MINSTACK; + L1->ci = ci; +} + + +static void freestack (lua_State *L) { + if (L->stack == NULL) + return; /* stack not completely built yet */ + L->ci = &L->base_ci; /* free the entire 'ci' list */ + luaE_freeCI(L); + lua_assert(L->nci == 0); + luaM_freearray(L, L->stack, L->stacksize); /* free stack array */ +} + + +/* +** Create registry table and its predefined values +*/ +static void init_registry (lua_State *L, global_State *g) { + TValue temp; + /* create registry */ + Table *registry = luaH_new(L); + sethvalue(L, &g->l_registry, registry); + luaH_resize(L, registry, LUA_RIDX_LAST, 0); + /* registry[LUA_RIDX_MAINTHREAD] = L */ + setthvalue(L, &temp, L); /* temp = L */ + luaH_setint(L, registry, LUA_RIDX_MAINTHREAD, &temp); + /* registry[LUA_RIDX_GLOBALS] = table of globals */ + sethvalue(L, &temp, luaH_new(L)); /* temp = new table (global table) */ + luaH_setint(L, registry, LUA_RIDX_GLOBALS, &temp); +} + + +/* +** open parts of the state that may cause memory-allocation errors. +** ('g->version' != NULL flags that the state was completely build) +*/ +static void f_luaopen (lua_State *L, void *ud) { + global_State *g = G(L); + UNUSED(ud); + stack_init(L, L); /* init stack */ + init_registry(L, g); + luaS_init(L); + luaT_init(L); + luaX_init(L); + g->gcrunning = 1; /* allow gc */ + g->version = lua_version(NULL); + luai_userstateopen(L); +} + + +/* +** preinitialize a thread with consistent values without allocating +** any memory (to avoid errors) +*/ +static void preinit_thread (lua_State *L, global_State *g) { + G(L) = g; + L->stack = NULL; + L->ci = NULL; + L->nci = 0; + L->stacksize = 0; + L->twups = L; /* thread has no upvalues */ + L->errorJmp = NULL; + L->nCcalls = 0; + L->hook = NULL; + L->hookmask = 0; + L->basehookcount = 0; + L->allowhook = 1; + resethookcount(L); + L->openupval = NULL; + L->nny = 1; + L->status = LUA_OK; + L->errfunc = 0; +} + + +static void close_state (lua_State *L) { + global_State *g = G(L); + luaF_close(L, L->stack); /* close all upvalues for this thread */ + luaC_freeallobjects(L); /* collect all objects */ + if (g->version) /* closing a fully built state? */ + luai_userstateclose(L); + luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size); + freestack(L); + lua_assert(gettotalbytes(g) == sizeof(LG)); + (*g->frealloc)(g->ud, fromstate(L), sizeof(LG), 0); /* free main block */ +} + + +LUA_API lua_State *lua_newthread (lua_State *L) { + global_State *g = G(L); + lua_State *L1; + lua_lock(L); + luaC_checkGC(L); + /* create new thread */ + L1 = &cast(LX *, luaM_newobject(L, LUA_TTHREAD, sizeof(LX)))->l; + L1->marked = luaC_white(g); + L1->tt = LUA_TTHREAD; + /* link it on list 'allgc' */ + L1->next = g->allgc; + g->allgc = obj2gco(L1); + /* anchor it on L stack */ + setthvalue(L, L->top, L1); + api_incr_top(L); + preinit_thread(L1, g); + L1->hookmask = L->hookmask; + L1->basehookcount = L->basehookcount; + L1->hook = L->hook; + resethookcount(L1); + /* initialize L1 extra space */ + memcpy(lua_getextraspace(L1), lua_getextraspace(g->mainthread), + LUA_EXTRASPACE); + luai_userstatethread(L, L1); + stack_init(L1, L); /* init stack */ + lua_unlock(L); + return L1; +} + + +void luaE_freethread (lua_State *L, lua_State *L1) { + LX *l = fromstate(L1); + luaF_close(L1, L1->stack); /* close all upvalues for this thread */ + lua_assert(L1->openupval == NULL); + luai_userstatefree(L, L1); + freestack(L1); + luaM_free(L, l); +} + + +LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { + int i; + lua_State *L; + global_State *g; + LG *l = cast(LG *, (*f)(ud, NULL, LUA_TTHREAD, sizeof(LG))); + if (l == NULL) return NULL; + L = &l->l.l; + g = &l->g; + L->next = NULL; + L->tt = LUA_TTHREAD; + g->currentwhite = bitmask(WHITE0BIT); + L->marked = luaC_white(g); + preinit_thread(L, g); + g->frealloc = f; + g->ud = ud; + g->mainthread = L; + g->seed = makeseed(L); + g->gcrunning = 0; /* no GC while building state */ + g->GCestimate = 0; + g->strt.size = g->strt.nuse = 0; + g->strt.hash = NULL; + setnilvalue(&g->l_registry); + g->panic = NULL; + g->version = NULL; + g->gcstate = GCSpause; + g->gckind = KGC_NORMAL; + g->allgc = g->finobj = g->tobefnz = g->fixedgc = NULL; + g->sweepgc = NULL; + g->gray = g->grayagain = NULL; + g->weak = g->ephemeron = g->allweak = NULL; + g->twups = NULL; + g->totalbytes = sizeof(LG); + g->GCdebt = 0; + g->gcfinnum = 0; + g->gcpause = LUAI_GCPAUSE; + g->gcstepmul = LUAI_GCMUL; + for (i=0; i < LUA_NUMTAGS; i++) g->mt[i] = NULL; + if (luaD_rawrunprotected(L, f_luaopen, NULL) != LUA_OK) { + /* memory allocation error: free partial state */ + close_state(L); + L = NULL; + } + return L; +} + + +LUA_API void lua_close (lua_State *L) { + L = G(L)->mainthread; /* only the main thread can be closed */ + lua_lock(L); + close_state(L); +} + + diff --git a/depends/lua/src/lstring.c b/depends/lua/src/lstring.c new file mode 100644 index 0000000000..6257f211d9 --- /dev/null +++ b/depends/lua/src/lstring.c @@ -0,0 +1,248 @@ +/* +** $Id: lstring.c,v 2.56.1.1 2017/04/19 17:20:42 roberto Exp $ +** String table (keeps all strings handled by Lua) +** See Copyright Notice in lua.h +*/ + +#define lstring_c +#define LUA_CORE + +#include "lprefix.h" + + +#include + +#include "lua.h" + +#include "ldebug.h" +#include "ldo.h" +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" +#include "lstring.h" + + +#define MEMERRMSG "not enough memory" + + +/* +** Lua will use at most ~(2^LUAI_HASHLIMIT) bytes from a string to +** compute its hash +*/ +#if !defined(LUAI_HASHLIMIT) +#define LUAI_HASHLIMIT 5 +#endif + + +/* +** equality for long strings +*/ +int luaS_eqlngstr (TString *a, TString *b) { + size_t len = a->u.lnglen; + lua_assert(a->tt == LUA_TLNGSTR && b->tt == LUA_TLNGSTR); + return (a == b) || /* same instance or... */ + ((len == b->u.lnglen) && /* equal length and ... */ + (memcmp(getstr(a), getstr(b), len) == 0)); /* equal contents */ +} + + +unsigned int luaS_hash (const char *str, size_t l, unsigned int seed) { + unsigned int h = seed ^ cast(unsigned int, l); + size_t step = (l >> LUAI_HASHLIMIT) + 1; + for (; l >= step; l -= step) + h ^= ((h<<5) + (h>>2) + cast_byte(str[l - 1])); + return h; +} + + +unsigned int luaS_hashlongstr (TString *ts) { + lua_assert(ts->tt == LUA_TLNGSTR); + if (ts->extra == 0) { /* no hash? */ + ts->hash = luaS_hash(getstr(ts), ts->u.lnglen, ts->hash); + ts->extra = 1; /* now it has its hash */ + } + return ts->hash; +} + + +/* +** resizes the string table +*/ +void luaS_resize (lua_State *L, int newsize) { + int i; + stringtable *tb = &G(L)->strt; + if (newsize > tb->size) { /* grow table if needed */ + luaM_reallocvector(L, tb->hash, tb->size, newsize, TString *); + for (i = tb->size; i < newsize; i++) + tb->hash[i] = NULL; + } + for (i = 0; i < tb->size; i++) { /* rehash */ + TString *p = tb->hash[i]; + tb->hash[i] = NULL; + while (p) { /* for each node in the list */ + TString *hnext = p->u.hnext; /* save next */ + unsigned int h = lmod(p->hash, newsize); /* new position */ + p->u.hnext = tb->hash[h]; /* chain it */ + tb->hash[h] = p; + p = hnext; + } + } + if (newsize < tb->size) { /* shrink table if needed */ + /* vanishing slice should be empty */ + lua_assert(tb->hash[newsize] == NULL && tb->hash[tb->size - 1] == NULL); + luaM_reallocvector(L, tb->hash, tb->size, newsize, TString *); + } + tb->size = newsize; +} + + +/* +** Clear API string cache. (Entries cannot be empty, so fill them with +** a non-collectable string.) +*/ +void luaS_clearcache (global_State *g) { + int i, j; + for (i = 0; i < STRCACHE_N; i++) + for (j = 0; j < STRCACHE_M; j++) { + if (iswhite(g->strcache[i][j])) /* will entry be collected? */ + g->strcache[i][j] = g->memerrmsg; /* replace it with something fixed */ + } +} + + +/* +** Initialize the string table and the string cache +*/ +void luaS_init (lua_State *L) { + global_State *g = G(L); + int i, j; + luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */ + /* pre-create memory-error message */ + g->memerrmsg = luaS_newliteral(L, MEMERRMSG); + luaC_fix(L, obj2gco(g->memerrmsg)); /* it should never be collected */ + for (i = 0; i < STRCACHE_N; i++) /* fill cache with valid strings */ + for (j = 0; j < STRCACHE_M; j++) + g->strcache[i][j] = g->memerrmsg; +} + + + +/* +** creates a new string object +*/ +static TString *createstrobj (lua_State *L, size_t l, int tag, unsigned int h) { + TString *ts; + GCObject *o; + size_t totalsize; /* total size of TString object */ + totalsize = sizelstring(l); + o = luaC_newobj(L, tag, totalsize); + ts = gco2ts(o); + ts->hash = h; + ts->extra = 0; + getstr(ts)[l] = '\0'; /* ending 0 */ + return ts; +} + + +TString *luaS_createlngstrobj (lua_State *L, size_t l) { + TString *ts = createstrobj(L, l, LUA_TLNGSTR, G(L)->seed); + ts->u.lnglen = l; + return ts; +} + + +void luaS_remove (lua_State *L, TString *ts) { + stringtable *tb = &G(L)->strt; + TString **p = &tb->hash[lmod(ts->hash, tb->size)]; + while (*p != ts) /* find previous element */ + p = &(*p)->u.hnext; + *p = (*p)->u.hnext; /* remove element from its list */ + tb->nuse--; +} + + +/* +** checks whether short string exists and reuses it or creates a new one +*/ +static TString *internshrstr (lua_State *L, const char *str, size_t l) { + TString *ts; + global_State *g = G(L); + unsigned int h = luaS_hash(str, l, g->seed); + TString **list = &g->strt.hash[lmod(h, g->strt.size)]; + lua_assert(str != NULL); /* otherwise 'memcmp'/'memcpy' are undefined */ + for (ts = *list; ts != NULL; ts = ts->u.hnext) { + if (l == ts->shrlen && + (memcmp(str, getstr(ts), l * sizeof(char)) == 0)) { + /* found! */ + if (isdead(g, ts)) /* dead (but not collected yet)? */ + changewhite(ts); /* resurrect it */ + return ts; + } + } + if (g->strt.nuse >= g->strt.size && g->strt.size <= MAX_INT/2) { + luaS_resize(L, g->strt.size * 2); + list = &g->strt.hash[lmod(h, g->strt.size)]; /* recompute with new size */ + } + ts = createstrobj(L, l, LUA_TSHRSTR, h); + memcpy(getstr(ts), str, l * sizeof(char)); + ts->shrlen = cast_byte(l); + ts->u.hnext = *list; + *list = ts; + g->strt.nuse++; + return ts; +} + + +/* +** new string (with explicit length) +*/ +TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { + if (l <= LUAI_MAXSHORTLEN) /* short string? */ + return internshrstr(L, str, l); + else { + TString *ts; + if (l >= (MAX_SIZE - sizeof(TString))/sizeof(char)) + luaM_toobig(L); + ts = luaS_createlngstrobj(L, l); + memcpy(getstr(ts), str, l * sizeof(char)); + return ts; + } +} + + +/* +** Create or reuse a zero-terminated string, first checking in the +** cache (using the string address as a key). The cache can contain +** only zero-terminated strings, so it is safe to use 'strcmp' to +** check hits. +*/ +TString *luaS_new (lua_State *L, const char *str) { + unsigned int i = point2uint(str) % STRCACHE_N; /* hash */ + int j; + TString **p = G(L)->strcache[i]; + for (j = 0; j < STRCACHE_M; j++) { + if (strcmp(str, getstr(p[j])) == 0) /* hit? */ + return p[j]; /* that is it */ + } + /* normal route */ + for (j = STRCACHE_M - 1; j > 0; j--) + p[j] = p[j - 1]; /* move out last element */ + /* new element is first in the list */ + p[0] = luaS_newlstr(L, str, strlen(str)); + return p[0]; +} + + +Udata *luaS_newudata (lua_State *L, size_t s) { + Udata *u; + GCObject *o; + if (s > MAX_SIZE - sizeof(Udata)) + luaM_toobig(L); + o = luaC_newobj(L, LUA_TUSERDATA, sizeludata(s)); + u = gco2u(o); + u->len = s; + u->metatable = NULL; + setuservalue(L, u, luaO_nilobject); + return u; +} + diff --git a/depends/lua/src/lstrlib.c b/depends/lua/src/lstrlib.c new file mode 100644 index 0000000000..b4bed7e93d --- /dev/null +++ b/depends/lua/src/lstrlib.c @@ -0,0 +1,1584 @@ +/* +** $Id: lstrlib.c,v 1.254.1.1 2017/04/19 17:29:57 roberto Exp $ +** Standard library for string operations and pattern-matching +** See Copyright Notice in lua.h +*/ + +#define lstrlib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +/* +** maximum number of captures that a pattern can do during +** pattern-matching. This limit is arbitrary, but must fit in +** an unsigned char. +*/ +#if !defined(LUA_MAXCAPTURES) +#define LUA_MAXCAPTURES 32 +#endif + + +/* macro to 'unsign' a character */ +#define uchar(c) ((unsigned char)(c)) + + +/* +** Some sizes are better limited to fit in 'int', but must also fit in +** 'size_t'. (We assume that 'lua_Integer' cannot be smaller than 'int'.) +*/ +#define MAX_SIZET ((size_t)(~(size_t)0)) + +#define MAXSIZE \ + (sizeof(size_t) < sizeof(int) ? MAX_SIZET : (size_t)(INT_MAX)) + + + + +static int str_len (lua_State *L) { + size_t l; + luaL_checklstring(L, 1, &l); + lua_pushinteger(L, (lua_Integer)l); + return 1; +} + + +/* translate a relative string position: negative means back from end */ +static lua_Integer posrelat (lua_Integer pos, size_t len) { + if (pos >= 0) return pos; + else if (0u - (size_t)pos > len) return 0; + else return (lua_Integer)len + pos + 1; +} + + +static int str_sub (lua_State *L) { + size_t l; + const char *s = luaL_checklstring(L, 1, &l); + lua_Integer start = posrelat(luaL_checkinteger(L, 2), l); + lua_Integer end = posrelat(luaL_optinteger(L, 3, -1), l); + if (start < 1) start = 1; + if (end > (lua_Integer)l) end = l; + if (start <= end) + lua_pushlstring(L, s + start - 1, (size_t)(end - start) + 1); + else lua_pushliteral(L, ""); + return 1; +} + + +static int str_reverse (lua_State *L) { + size_t l, i; + luaL_Buffer b; + const char *s = luaL_checklstring(L, 1, &l); + char *p = luaL_buffinitsize(L, &b, l); + for (i = 0; i < l; i++) + p[i] = s[l - i - 1]; + luaL_pushresultsize(&b, l); + return 1; +} + + +static int str_lower (lua_State *L) { + size_t l; + size_t i; + luaL_Buffer b; + const char *s = luaL_checklstring(L, 1, &l); + char *p = luaL_buffinitsize(L, &b, l); + for (i=0; i MAXSIZE / n) /* may overflow? */ + return luaL_error(L, "resulting string too large"); + else { + size_t totallen = (size_t)n * l + (size_t)(n - 1) * lsep; + luaL_Buffer b; + char *p = luaL_buffinitsize(L, &b, totallen); + while (n-- > 1) { /* first n-1 copies (followed by separator) */ + memcpy(p, s, l * sizeof(char)); p += l; + if (lsep > 0) { /* empty 'memcpy' is not that cheap */ + memcpy(p, sep, lsep * sizeof(char)); + p += lsep; + } + } + memcpy(p, s, l * sizeof(char)); /* last copy (not followed by separator) */ + luaL_pushresultsize(&b, totallen); + } + return 1; +} + + +static int str_byte (lua_State *L) { + size_t l; + const char *s = luaL_checklstring(L, 1, &l); + lua_Integer posi = posrelat(luaL_optinteger(L, 2, 1), l); + lua_Integer pose = posrelat(luaL_optinteger(L, 3, posi), l); + int n, i; + if (posi < 1) posi = 1; + if (pose > (lua_Integer)l) pose = l; + if (posi > pose) return 0; /* empty interval; return no values */ + if (pose - posi >= INT_MAX) /* arithmetic overflow? */ + return luaL_error(L, "string slice too long"); + n = (int)(pose - posi) + 1; + luaL_checkstack(L, n, "string slice too long"); + for (i=0; i= ms->level || ms->capture[l].len == CAP_UNFINISHED) + return luaL_error(ms->L, "invalid capture index %%%d", l + 1); + return l; +} + + +static int capture_to_close (MatchState *ms) { + int level = ms->level; + for (level--; level>=0; level--) + if (ms->capture[level].len == CAP_UNFINISHED) return level; + return luaL_error(ms->L, "invalid pattern capture"); +} + + +static const char *classend (MatchState *ms, const char *p) { + switch (*p++) { + case L_ESC: { + if (p == ms->p_end) + luaL_error(ms->L, "malformed pattern (ends with '%%')"); + return p+1; + } + case '[': { + if (*p == '^') p++; + do { /* look for a ']' */ + if (p == ms->p_end) + luaL_error(ms->L, "malformed pattern (missing ']')"); + if (*(p++) == L_ESC && p < ms->p_end) + p++; /* skip escapes (e.g. '%]') */ + } while (*p != ']'); + return p+1; + } + default: { + return p; + } + } +} + + +static int match_class (int c, int cl) { + int res; + switch (tolower(cl)) { + case 'a' : res = isalpha(c); break; + case 'c' : res = iscntrl(c); break; + case 'd' : res = isdigit(c); break; + case 'g' : res = isgraph(c); break; + case 'l' : res = islower(c); break; + case 'p' : res = ispunct(c); break; + case 's' : res = isspace(c); break; + case 'u' : res = isupper(c); break; + case 'w' : res = isalnum(c); break; + case 'x' : res = isxdigit(c); break; + case 'z' : res = (c == 0); break; /* deprecated option */ + default: return (cl == c); + } + return (islower(cl) ? res : !res); +} + + +static int matchbracketclass (int c, const char *p, const char *ec) { + int sig = 1; + if (*(p+1) == '^') { + sig = 0; + p++; /* skip the '^' */ + } + while (++p < ec) { + if (*p == L_ESC) { + p++; + if (match_class(c, uchar(*p))) + return sig; + } + else if ((*(p+1) == '-') && (p+2 < ec)) { + p+=2; + if (uchar(*(p-2)) <= c && c <= uchar(*p)) + return sig; + } + else if (uchar(*p) == c) return sig; + } + return !sig; +} + + +static int singlematch (MatchState *ms, const char *s, const char *p, + const char *ep) { + if (s >= ms->src_end) + return 0; + else { + int c = uchar(*s); + switch (*p) { + case '.': return 1; /* matches any char */ + case L_ESC: return match_class(c, uchar(*(p+1))); + case '[': return matchbracketclass(c, p, ep-1); + default: return (uchar(*p) == c); + } + } +} + + +static const char *matchbalance (MatchState *ms, const char *s, + const char *p) { + if (p >= ms->p_end - 1) + luaL_error(ms->L, "malformed pattern (missing arguments to '%%b')"); + if (*s != *p) return NULL; + else { + int b = *p; + int e = *(p+1); + int cont = 1; + while (++s < ms->src_end) { + if (*s == e) { + if (--cont == 0) return s+1; + } + else if (*s == b) cont++; + } + } + return NULL; /* string ends out of balance */ +} + + +static const char *max_expand (MatchState *ms, const char *s, + const char *p, const char *ep) { + ptrdiff_t i = 0; /* counts maximum expand for item */ + while (singlematch(ms, s + i, p, ep)) + i++; + /* keeps trying to match with the maximum repetitions */ + while (i>=0) { + const char *res = match(ms, (s+i), ep+1); + if (res) return res; + i--; /* else didn't match; reduce 1 repetition to try again */ + } + return NULL; +} + + +static const char *min_expand (MatchState *ms, const char *s, + const char *p, const char *ep) { + for (;;) { + const char *res = match(ms, s, ep+1); + if (res != NULL) + return res; + else if (singlematch(ms, s, p, ep)) + s++; /* try with one more repetition */ + else return NULL; + } +} + + +static const char *start_capture (MatchState *ms, const char *s, + const char *p, int what) { + const char *res; + int level = ms->level; + if (level >= LUA_MAXCAPTURES) luaL_error(ms->L, "too many captures"); + ms->capture[level].init = s; + ms->capture[level].len = what; + ms->level = level+1; + if ((res=match(ms, s, p)) == NULL) /* match failed? */ + ms->level--; /* undo capture */ + return res; +} + + +static const char *end_capture (MatchState *ms, const char *s, + const char *p) { + int l = capture_to_close(ms); + const char *res; + ms->capture[l].len = s - ms->capture[l].init; /* close capture */ + if ((res = match(ms, s, p)) == NULL) /* match failed? */ + ms->capture[l].len = CAP_UNFINISHED; /* undo capture */ + return res; +} + + +static const char *match_capture (MatchState *ms, const char *s, int l) { + size_t len; + l = check_capture(ms, l); + len = ms->capture[l].len; + if ((size_t)(ms->src_end-s) >= len && + memcmp(ms->capture[l].init, s, len) == 0) + return s+len; + else return NULL; +} + + +static const char *match (MatchState *ms, const char *s, const char *p) { + if (ms->matchdepth-- == 0) + luaL_error(ms->L, "pattern too complex"); + init: /* using goto's to optimize tail recursion */ + if (p != ms->p_end) { /* end of pattern? */ + switch (*p) { + case '(': { /* start capture */ + if (*(p + 1) == ')') /* position capture? */ + s = start_capture(ms, s, p + 2, CAP_POSITION); + else + s = start_capture(ms, s, p + 1, CAP_UNFINISHED); + break; + } + case ')': { /* end capture */ + s = end_capture(ms, s, p + 1); + break; + } + case '$': { + if ((p + 1) != ms->p_end) /* is the '$' the last char in pattern? */ + goto dflt; /* no; go to default */ + s = (s == ms->src_end) ? s : NULL; /* check end of string */ + break; + } + case L_ESC: { /* escaped sequences not in the format class[*+?-]? */ + switch (*(p + 1)) { + case 'b': { /* balanced string? */ + s = matchbalance(ms, s, p + 2); + if (s != NULL) { + p += 4; goto init; /* return match(ms, s, p + 4); */ + } /* else fail (s == NULL) */ + break; + } + case 'f': { /* frontier? */ + const char *ep; char previous; + p += 2; + if (*p != '[') + luaL_error(ms->L, "missing '[' after '%%f' in pattern"); + ep = classend(ms, p); /* points to what is next */ + previous = (s == ms->src_init) ? '\0' : *(s - 1); + if (!matchbracketclass(uchar(previous), p, ep - 1) && + matchbracketclass(uchar(*s), p, ep - 1)) { + p = ep; goto init; /* return match(ms, s, ep); */ + } + s = NULL; /* match failed */ + break; + } + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + case '8': case '9': { /* capture results (%0-%9)? */ + s = match_capture(ms, s, uchar(*(p + 1))); + if (s != NULL) { + p += 2; goto init; /* return match(ms, s, p + 2) */ + } + break; + } + default: goto dflt; + } + break; + } + default: dflt: { /* pattern class plus optional suffix */ + const char *ep = classend(ms, p); /* points to optional suffix */ + /* does not match at least once? */ + if (!singlematch(ms, s, p, ep)) { + if (*ep == '*' || *ep == '?' || *ep == '-') { /* accept empty? */ + p = ep + 1; goto init; /* return match(ms, s, ep + 1); */ + } + else /* '+' or no suffix */ + s = NULL; /* fail */ + } + else { /* matched once */ + switch (*ep) { /* handle optional suffix */ + case '?': { /* optional */ + const char *res; + if ((res = match(ms, s + 1, ep + 1)) != NULL) + s = res; + else { + p = ep + 1; goto init; /* else return match(ms, s, ep + 1); */ + } + break; + } + case '+': /* 1 or more repetitions */ + s++; /* 1 match already done */ + /* FALLTHROUGH */ + case '*': /* 0 or more repetitions */ + s = max_expand(ms, s, p, ep); + break; + case '-': /* 0 or more repetitions (minimum) */ + s = min_expand(ms, s, p, ep); + break; + default: /* no suffix */ + s++; p = ep; goto init; /* return match(ms, s + 1, ep); */ + } + } + break; + } + } + } + ms->matchdepth++; + return s; +} + + + +static const char *lmemfind (const char *s1, size_t l1, + const char *s2, size_t l2) { + if (l2 == 0) return s1; /* empty strings are everywhere */ + else if (l2 > l1) return NULL; /* avoids a negative 'l1' */ + else { + const char *init; /* to search for a '*s2' inside 's1' */ + l2--; /* 1st char will be checked by 'memchr' */ + l1 = l1-l2; /* 's2' cannot be found after that */ + while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) { + init++; /* 1st char is already checked */ + if (memcmp(init, s2+1, l2) == 0) + return init-1; + else { /* correct 'l1' and 's1' to try again */ + l1 -= init-s1; + s1 = init; + } + } + return NULL; /* not found */ + } +} + + +static void push_onecapture (MatchState *ms, int i, const char *s, + const char *e) { + if (i >= ms->level) { + if (i == 0) /* ms->level == 0, too */ + lua_pushlstring(ms->L, s, e - s); /* add whole match */ + else + luaL_error(ms->L, "invalid capture index %%%d", i + 1); + } + else { + ptrdiff_t l = ms->capture[i].len; + if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture"); + if (l == CAP_POSITION) + lua_pushinteger(ms->L, (ms->capture[i].init - ms->src_init) + 1); + else + lua_pushlstring(ms->L, ms->capture[i].init, l); + } +} + + +static int push_captures (MatchState *ms, const char *s, const char *e) { + int i; + int nlevels = (ms->level == 0 && s) ? 1 : ms->level; + luaL_checkstack(ms->L, nlevels, "too many captures"); + for (i = 0; i < nlevels; i++) + push_onecapture(ms, i, s, e); + return nlevels; /* number of strings pushed */ +} + + +/* check whether pattern has no special characters */ +static int nospecials (const char *p, size_t l) { + size_t upto = 0; + do { + if (strpbrk(p + upto, SPECIALS)) + return 0; /* pattern has a special character */ + upto += strlen(p + upto) + 1; /* may have more after \0 */ + } while (upto <= l); + return 1; /* no special chars found */ +} + + +static void prepstate (MatchState *ms, lua_State *L, + const char *s, size_t ls, const char *p, size_t lp) { + ms->L = L; + ms->matchdepth = MAXCCALLS; + ms->src_init = s; + ms->src_end = s + ls; + ms->p_end = p + lp; +} + + +static void reprepstate (MatchState *ms) { + ms->level = 0; + lua_assert(ms->matchdepth == MAXCCALLS); +} + + +static int str_find_aux (lua_State *L, int find) { + size_t ls, lp; + const char *s = luaL_checklstring(L, 1, &ls); + const char *p = luaL_checklstring(L, 2, &lp); + lua_Integer init = posrelat(luaL_optinteger(L, 3, 1), ls); + if (init < 1) init = 1; + else if (init > (lua_Integer)ls + 1) { /* start after string's end? */ + lua_pushnil(L); /* cannot find anything */ + return 1; + } + /* explicit request or no special characters? */ + if (find && (lua_toboolean(L, 4) || nospecials(p, lp))) { + /* do a plain search */ + const char *s2 = lmemfind(s + init - 1, ls - (size_t)init + 1, p, lp); + if (s2) { + lua_pushinteger(L, (s2 - s) + 1); + lua_pushinteger(L, (s2 - s) + lp); + return 2; + } + } + else { + MatchState ms; + const char *s1 = s + init - 1; + int anchor = (*p == '^'); + if (anchor) { + p++; lp--; /* skip anchor character */ + } + prepstate(&ms, L, s, ls, p, lp); + do { + const char *res; + reprepstate(&ms); + if ((res=match(&ms, s1, p)) != NULL) { + if (find) { + lua_pushinteger(L, (s1 - s) + 1); /* start */ + lua_pushinteger(L, res - s); /* end */ + return push_captures(&ms, NULL, 0) + 2; + } + else + return push_captures(&ms, s1, res); + } + } while (s1++ < ms.src_end && !anchor); + } + lua_pushnil(L); /* not found */ + return 1; +} + + +static int str_find (lua_State *L) { + return str_find_aux(L, 1); +} + + +static int str_match (lua_State *L) { + return str_find_aux(L, 0); +} + + +/* state for 'gmatch' */ +typedef struct GMatchState { + const char *src; /* current position */ + const char *p; /* pattern */ + const char *lastmatch; /* end of last match */ + MatchState ms; /* match state */ +} GMatchState; + + +static int gmatch_aux (lua_State *L) { + GMatchState *gm = (GMatchState *)lua_touserdata(L, lua_upvalueindex(3)); + const char *src; + gm->ms.L = L; + for (src = gm->src; src <= gm->ms.src_end; src++) { + const char *e; + reprepstate(&gm->ms); + if ((e = match(&gm->ms, src, gm->p)) != NULL && e != gm->lastmatch) { + gm->src = gm->lastmatch = e; + return push_captures(&gm->ms, src, e); + } + } + return 0; /* not found */ +} + + +static int gmatch (lua_State *L) { + size_t ls, lp; + const char *s = luaL_checklstring(L, 1, &ls); + const char *p = luaL_checklstring(L, 2, &lp); + GMatchState *gm; + lua_settop(L, 2); /* keep them on closure to avoid being collected */ + gm = (GMatchState *)lua_newuserdata(L, sizeof(GMatchState)); + prepstate(&gm->ms, L, s, ls, p, lp); + gm->src = s; gm->p = p; gm->lastmatch = NULL; + lua_pushcclosure(L, gmatch_aux, 3); + return 1; +} + + +static void add_s (MatchState *ms, luaL_Buffer *b, const char *s, + const char *e) { + size_t l, i; + lua_State *L = ms->L; + const char *news = lua_tolstring(L, 3, &l); + for (i = 0; i < l; i++) { + if (news[i] != L_ESC) + luaL_addchar(b, news[i]); + else { + i++; /* skip ESC */ + if (!isdigit(uchar(news[i]))) { + if (news[i] != L_ESC) + luaL_error(L, "invalid use of '%c' in replacement string", L_ESC); + luaL_addchar(b, news[i]); + } + else if (news[i] == '0') + luaL_addlstring(b, s, e - s); + else { + push_onecapture(ms, news[i] - '1', s, e); + luaL_tolstring(L, -1, NULL); /* if number, convert it to string */ + lua_remove(L, -2); /* remove original value */ + luaL_addvalue(b); /* add capture to accumulated result */ + } + } + } +} + + +static void add_value (MatchState *ms, luaL_Buffer *b, const char *s, + const char *e, int tr) { + lua_State *L = ms->L; + switch (tr) { + case LUA_TFUNCTION: { + int n; + lua_pushvalue(L, 3); + n = push_captures(ms, s, e); + lua_call(L, n, 1); + break; + } + case LUA_TTABLE: { + push_onecapture(ms, 0, s, e); + lua_gettable(L, 3); + break; + } + default: { /* LUA_TNUMBER or LUA_TSTRING */ + add_s(ms, b, s, e); + return; + } + } + if (!lua_toboolean(L, -1)) { /* nil or false? */ + lua_pop(L, 1); + lua_pushlstring(L, s, e - s); /* keep original text */ + } + else if (!lua_isstring(L, -1)) + luaL_error(L, "invalid replacement value (a %s)", luaL_typename(L, -1)); + luaL_addvalue(b); /* add result to accumulator */ +} + + +static int str_gsub (lua_State *L) { + size_t srcl, lp; + const char *src = luaL_checklstring(L, 1, &srcl); /* subject */ + const char *p = luaL_checklstring(L, 2, &lp); /* pattern */ + const char *lastmatch = NULL; /* end of last match */ + int tr = lua_type(L, 3); /* replacement type */ + lua_Integer max_s = luaL_optinteger(L, 4, srcl + 1); /* max replacements */ + int anchor = (*p == '^'); + lua_Integer n = 0; /* replacement count */ + MatchState ms; + luaL_Buffer b; + luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING || + tr == LUA_TFUNCTION || tr == LUA_TTABLE, 3, + "string/function/table expected"); + luaL_buffinit(L, &b); + if (anchor) { + p++; lp--; /* skip anchor character */ + } + prepstate(&ms, L, src, srcl, p, lp); + while (n < max_s) { + const char *e; + reprepstate(&ms); /* (re)prepare state for new match */ + if ((e = match(&ms, src, p)) != NULL && e != lastmatch) { /* match? */ + n++; + add_value(&ms, &b, src, e, tr); /* add replacement to buffer */ + src = lastmatch = e; + } + else if (src < ms.src_end) /* otherwise, skip one character */ + luaL_addchar(&b, *src++); + else break; /* end of subject */ + if (anchor) break; + } + luaL_addlstring(&b, src, ms.src_end-src); + luaL_pushresult(&b); + lua_pushinteger(L, n); /* number of substitutions */ + return 2; +} + +/* }====================================================== */ + + + +/* +** {====================================================== +** STRING FORMAT +** ======================================================= +*/ + +#if !defined(lua_number2strx) /* { */ + +/* +** Hexadecimal floating-point formatter +*/ + +#include + +#define SIZELENMOD (sizeof(LUA_NUMBER_FRMLEN)/sizeof(char)) + + +/* +** Number of bits that goes into the first digit. It can be any value +** between 1 and 4; the following definition tries to align the number +** to nibble boundaries by making what is left after that first digit a +** multiple of 4. +*/ +#define L_NBFD ((l_mathlim(MANT_DIG) - 1)%4 + 1) + + +/* +** Add integer part of 'x' to buffer and return new 'x' +*/ +static lua_Number adddigit (char *buff, int n, lua_Number x) { + lua_Number dd = l_mathop(floor)(x); /* get integer part from 'x' */ + int d = (int)dd; + buff[n] = (d < 10 ? d + '0' : d - 10 + 'a'); /* add to buffer */ + return x - dd; /* return what is left */ +} + + +static int num2straux (char *buff, int sz, lua_Number x) { + /* if 'inf' or 'NaN', format it like '%g' */ + if (x != x || x == (lua_Number)HUGE_VAL || x == -(lua_Number)HUGE_VAL) + return l_sprintf(buff, sz, LUA_NUMBER_FMT, (LUAI_UACNUMBER)x); + else if (x == 0) { /* can be -0... */ + /* create "0" or "-0" followed by exponent */ + return l_sprintf(buff, sz, LUA_NUMBER_FMT "x0p+0", (LUAI_UACNUMBER)x); + } + else { + int e; + lua_Number m = l_mathop(frexp)(x, &e); /* 'x' fraction and exponent */ + int n = 0; /* character count */ + if (m < 0) { /* is number negative? */ + buff[n++] = '-'; /* add signal */ + m = -m; /* make it positive */ + } + buff[n++] = '0'; buff[n++] = 'x'; /* add "0x" */ + m = adddigit(buff, n++, m * (1 << L_NBFD)); /* add first digit */ + e -= L_NBFD; /* this digit goes before the radix point */ + if (m > 0) { /* more digits? */ + buff[n++] = lua_getlocaledecpoint(); /* add radix point */ + do { /* add as many digits as needed */ + m = adddigit(buff, n++, m * 16); + } while (m > 0); + } + n += l_sprintf(buff + n, sz - n, "p%+d", e); /* add exponent */ + lua_assert(n < sz); + return n; + } +} + + +static int lua_number2strx (lua_State *L, char *buff, int sz, + const char *fmt, lua_Number x) { + int n = num2straux(buff, sz, x); + if (fmt[SIZELENMOD] == 'A') { + int i; + for (i = 0; i < n; i++) + buff[i] = toupper(uchar(buff[i])); + } + else if (fmt[SIZELENMOD] != 'a') + return luaL_error(L, "modifiers for format '%%a'/'%%A' not implemented"); + return n; +} + +#endif /* } */ + + +/* +** Maximum size of each formatted item. This maximum size is produced +** by format('%.99f', -maxfloat), and is equal to 99 + 3 ('-', '.', +** and '\0') + number of decimal digits to represent maxfloat (which +** is maximum exponent + 1). (99+3+1 then rounded to 120 for "extra +** expenses", such as locale-dependent stuff) +*/ +#define MAX_ITEM (120 + l_mathlim(MAX_10_EXP)) + + +/* valid flags in a format specification */ +#define FLAGS "-+ #0" + +/* +** maximum size of each format specification (such as "%-099.99d") +*/ +#define MAX_FORMAT 32 + + +static void addquoted (luaL_Buffer *b, const char *s, size_t len) { + luaL_addchar(b, '"'); + while (len--) { + if (*s == '"' || *s == '\\' || *s == '\n') { + luaL_addchar(b, '\\'); + luaL_addchar(b, *s); + } + else if (iscntrl(uchar(*s))) { + char buff[10]; + if (!isdigit(uchar(*(s+1)))) + l_sprintf(buff, sizeof(buff), "\\%d", (int)uchar(*s)); + else + l_sprintf(buff, sizeof(buff), "\\%03d", (int)uchar(*s)); + luaL_addstring(b, buff); + } + else + luaL_addchar(b, *s); + s++; + } + luaL_addchar(b, '"'); +} + + +/* +** Ensures the 'buff' string uses a dot as the radix character. +*/ +static void checkdp (char *buff, int nb) { + if (memchr(buff, '.', nb) == NULL) { /* no dot? */ + char point = lua_getlocaledecpoint(); /* try locale point */ + char *ppoint = (char *)memchr(buff, point, nb); + if (ppoint) *ppoint = '.'; /* change it to a dot */ + } +} + + +static void addliteral (lua_State *L, luaL_Buffer *b, int arg) { + switch (lua_type(L, arg)) { + case LUA_TSTRING: { + size_t len; + const char *s = lua_tolstring(L, arg, &len); + addquoted(b, s, len); + break; + } + case LUA_TNUMBER: { + char *buff = luaL_prepbuffsize(b, MAX_ITEM); + int nb; + if (!lua_isinteger(L, arg)) { /* float? */ + lua_Number n = lua_tonumber(L, arg); /* write as hexa ('%a') */ + nb = lua_number2strx(L, buff, MAX_ITEM, "%" LUA_NUMBER_FRMLEN "a", n); + checkdp(buff, nb); /* ensure it uses a dot */ + } + else { /* integers */ + lua_Integer n = lua_tointeger(L, arg); + const char *format = (n == LUA_MININTEGER) /* corner case? */ + ? "0x%" LUA_INTEGER_FRMLEN "x" /* use hexa */ + : LUA_INTEGER_FMT; /* else use default format */ + nb = l_sprintf(buff, MAX_ITEM, format, (LUAI_UACINT)n); + } + luaL_addsize(b, nb); + break; + } + case LUA_TNIL: case LUA_TBOOLEAN: { + luaL_tolstring(L, arg, NULL); + luaL_addvalue(b); + break; + } + default: { + luaL_argerror(L, arg, "value has no literal form"); + } + } +} + + +static const char *scanformat (lua_State *L, const char *strfrmt, char *form) { + const char *p = strfrmt; + while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++; /* skip flags */ + if ((size_t)(p - strfrmt) >= sizeof(FLAGS)/sizeof(char)) + luaL_error(L, "invalid format (repeated flags)"); + if (isdigit(uchar(*p))) p++; /* skip width */ + if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ + if (*p == '.') { + p++; + if (isdigit(uchar(*p))) p++; /* skip precision */ + if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ + } + if (isdigit(uchar(*p))) + luaL_error(L, "invalid format (width or precision too long)"); + *(form++) = '%'; + memcpy(form, strfrmt, ((p - strfrmt) + 1) * sizeof(char)); + form += (p - strfrmt) + 1; + *form = '\0'; + return p; +} + + +/* +** add length modifier into formats +*/ +static void addlenmod (char *form, const char *lenmod) { + size_t l = strlen(form); + size_t lm = strlen(lenmod); + char spec = form[l - 1]; + strcpy(form + l - 1, lenmod); + form[l + lm - 1] = spec; + form[l + lm] = '\0'; +} + + +static int str_format (lua_State *L) { + int top = lua_gettop(L); + int arg = 1; + size_t sfl; + const char *strfrmt = luaL_checklstring(L, arg, &sfl); + const char *strfrmt_end = strfrmt+sfl; + luaL_Buffer b; + luaL_buffinit(L, &b); + while (strfrmt < strfrmt_end) { + if (*strfrmt != L_ESC) + luaL_addchar(&b, *strfrmt++); + else if (*++strfrmt == L_ESC) + luaL_addchar(&b, *strfrmt++); /* %% */ + else { /* format item */ + char form[MAX_FORMAT]; /* to store the format ('%...') */ + char *buff = luaL_prepbuffsize(&b, MAX_ITEM); /* to put formatted item */ + int nb = 0; /* number of bytes in added item */ + if (++arg > top) + luaL_argerror(L, arg, "no value"); + strfrmt = scanformat(L, strfrmt, form); + switch (*strfrmt++) { + case 'c': { + nb = l_sprintf(buff, MAX_ITEM, form, (int)luaL_checkinteger(L, arg)); + break; + } + case 'd': case 'i': + case 'o': case 'u': case 'x': case 'X': { + lua_Integer n = luaL_checkinteger(L, arg); + addlenmod(form, LUA_INTEGER_FRMLEN); + nb = l_sprintf(buff, MAX_ITEM, form, (LUAI_UACINT)n); + break; + } + case 'a': case 'A': + addlenmod(form, LUA_NUMBER_FRMLEN); + nb = lua_number2strx(L, buff, MAX_ITEM, form, + luaL_checknumber(L, arg)); + break; + case 'e': case 'E': case 'f': + case 'g': case 'G': { + lua_Number n = luaL_checknumber(L, arg); + addlenmod(form, LUA_NUMBER_FRMLEN); + nb = l_sprintf(buff, MAX_ITEM, form, (LUAI_UACNUMBER)n); + break; + } + case 'q': { + addliteral(L, &b, arg); + break; + } + case 's': { + size_t l; + const char *s = luaL_tolstring(L, arg, &l); + if (form[2] == '\0') /* no modifiers? */ + luaL_addvalue(&b); /* keep entire string */ + else { + luaL_argcheck(L, l == strlen(s), arg, "string contains zeros"); + if (!strchr(form, '.') && l >= 100) { + /* no precision and string is too long to be formatted */ + luaL_addvalue(&b); /* keep entire string */ + } + else { /* format the string into 'buff' */ + nb = l_sprintf(buff, MAX_ITEM, form, s); + lua_pop(L, 1); /* remove result from 'luaL_tolstring' */ + } + } + break; + } + default: { /* also treat cases 'pnLlh' */ + return luaL_error(L, "invalid option '%%%c' to 'format'", + *(strfrmt - 1)); + } + } + lua_assert(nb < MAX_ITEM); + luaL_addsize(&b, nb); + } + } + luaL_pushresult(&b); + return 1; +} + +/* }====================================================== */ + + +/* +** {====================================================== +** PACK/UNPACK +** ======================================================= +*/ + + +/* value used for padding */ +#if !defined(LUAL_PACKPADBYTE) +#define LUAL_PACKPADBYTE 0x00 +#endif + +/* maximum size for the binary representation of an integer */ +#define MAXINTSIZE 16 + +/* number of bits in a character */ +#define NB CHAR_BIT + +/* mask for one character (NB 1's) */ +#define MC ((1 << NB) - 1) + +/* size of a lua_Integer */ +#define SZINT ((int)sizeof(lua_Integer)) + + +/* dummy union to get native endianness */ +static const union { + int dummy; + char little; /* true iff machine is little endian */ +} nativeendian = {1}; + + +/* dummy structure to get native alignment requirements */ +struct cD { + char c; + union { double d; void *p; lua_Integer i; lua_Number n; } u; +}; + +#define MAXALIGN (offsetof(struct cD, u)) + + +/* +** Union for serializing floats +*/ +typedef union Ftypes { + float f; + double d; + lua_Number n; + char buff[5 * sizeof(lua_Number)]; /* enough for any float type */ +} Ftypes; + + +/* +** information to pack/unpack stuff +*/ +typedef struct Header { + lua_State *L; + int islittle; + int maxalign; +} Header; + + +/* +** options for pack/unpack +*/ +typedef enum KOption { + Kint, /* signed integers */ + Kuint, /* unsigned integers */ + Kfloat, /* floating-point numbers */ + Kchar, /* fixed-length strings */ + Kstring, /* strings with prefixed length */ + Kzstr, /* zero-terminated strings */ + Kpadding, /* padding */ + Kpaddalign, /* padding for alignment */ + Knop /* no-op (configuration or spaces) */ +} KOption; + + +/* +** Read an integer numeral from string 'fmt' or return 'df' if +** there is no numeral +*/ +static int digit (int c) { return '0' <= c && c <= '9'; } + +static int getnum (const char **fmt, int df) { + if (!digit(**fmt)) /* no number? */ + return df; /* return default value */ + else { + int a = 0; + do { + a = a*10 + (*((*fmt)++) - '0'); + } while (digit(**fmt) && a <= ((int)MAXSIZE - 9)/10); + return a; + } +} + + +/* +** Read an integer numeral and raises an error if it is larger +** than the maximum size for integers. +*/ +static int getnumlimit (Header *h, const char **fmt, int df) { + int sz = getnum(fmt, df); + if (sz > MAXINTSIZE || sz <= 0) + return luaL_error(h->L, "integral size (%d) out of limits [1,%d]", + sz, MAXINTSIZE); + return sz; +} + + +/* +** Initialize Header +*/ +static void initheader (lua_State *L, Header *h) { + h->L = L; + h->islittle = nativeendian.little; + h->maxalign = 1; +} + + +/* +** Read and classify next option. 'size' is filled with option's size. +*/ +static KOption getoption (Header *h, const char **fmt, int *size) { + int opt = *((*fmt)++); + *size = 0; /* default */ + switch (opt) { + case 'b': *size = sizeof(char); return Kint; + case 'B': *size = sizeof(char); return Kuint; + case 'h': *size = sizeof(short); return Kint; + case 'H': *size = sizeof(short); return Kuint; + case 'l': *size = sizeof(long); return Kint; + case 'L': *size = sizeof(long); return Kuint; + case 'j': *size = sizeof(lua_Integer); return Kint; + case 'J': *size = sizeof(lua_Integer); return Kuint; + case 'T': *size = sizeof(size_t); return Kuint; + case 'f': *size = sizeof(float); return Kfloat; + case 'd': *size = sizeof(double); return Kfloat; + case 'n': *size = sizeof(lua_Number); return Kfloat; + case 'i': *size = getnumlimit(h, fmt, sizeof(int)); return Kint; + case 'I': *size = getnumlimit(h, fmt, sizeof(int)); return Kuint; + case 's': *size = getnumlimit(h, fmt, sizeof(size_t)); return Kstring; + case 'c': + *size = getnum(fmt, -1); + if (*size == -1) + luaL_error(h->L, "missing size for format option 'c'"); + return Kchar; + case 'z': return Kzstr; + case 'x': *size = 1; return Kpadding; + case 'X': return Kpaddalign; + case ' ': break; + case '<': h->islittle = 1; break; + case '>': h->islittle = 0; break; + case '=': h->islittle = nativeendian.little; break; + case '!': h->maxalign = getnumlimit(h, fmt, MAXALIGN); break; + default: luaL_error(h->L, "invalid format option '%c'", opt); + } + return Knop; +} + + +/* +** Read, classify, and fill other details about the next option. +** 'psize' is filled with option's size, 'notoalign' with its +** alignment requirements. +** Local variable 'size' gets the size to be aligned. (Kpadal option +** always gets its full alignment, other options are limited by +** the maximum alignment ('maxalign'). Kchar option needs no alignment +** despite its size. +*/ +static KOption getdetails (Header *h, size_t totalsize, + const char **fmt, int *psize, int *ntoalign) { + KOption opt = getoption(h, fmt, psize); + int align = *psize; /* usually, alignment follows size */ + if (opt == Kpaddalign) { /* 'X' gets alignment from following option */ + if (**fmt == '\0' || getoption(h, fmt, &align) == Kchar || align == 0) + luaL_argerror(h->L, 1, "invalid next option for option 'X'"); + } + if (align <= 1 || opt == Kchar) /* need no alignment? */ + *ntoalign = 0; + else { + if (align > h->maxalign) /* enforce maximum alignment */ + align = h->maxalign; + if ((align & (align - 1)) != 0) /* is 'align' not a power of 2? */ + luaL_argerror(h->L, 1, "format asks for alignment not power of 2"); + *ntoalign = (align - (int)(totalsize & (align - 1))) & (align - 1); + } + return opt; +} + + +/* +** Pack integer 'n' with 'size' bytes and 'islittle' endianness. +** The final 'if' handles the case when 'size' is larger than +** the size of a Lua integer, correcting the extra sign-extension +** bytes if necessary (by default they would be zeros). +*/ +static void packint (luaL_Buffer *b, lua_Unsigned n, + int islittle, int size, int neg) { + char *buff = luaL_prepbuffsize(b, size); + int i; + buff[islittle ? 0 : size - 1] = (char)(n & MC); /* first byte */ + for (i = 1; i < size; i++) { + n >>= NB; + buff[islittle ? i : size - 1 - i] = (char)(n & MC); + } + if (neg && size > SZINT) { /* negative number need sign extension? */ + for (i = SZINT; i < size; i++) /* correct extra bytes */ + buff[islittle ? i : size - 1 - i] = (char)MC; + } + luaL_addsize(b, size); /* add result to buffer */ +} + + +/* +** Copy 'size' bytes from 'src' to 'dest', correcting endianness if +** given 'islittle' is different from native endianness. +*/ +static void copywithendian (volatile char *dest, volatile const char *src, + int size, int islittle) { + if (islittle == nativeendian.little) { + while (size-- != 0) + *(dest++) = *(src++); + } + else { + dest += size - 1; + while (size-- != 0) + *(dest--) = *(src++); + } +} + + +static int str_pack (lua_State *L) { + luaL_Buffer b; + Header h; + const char *fmt = luaL_checkstring(L, 1); /* format string */ + int arg = 1; /* current argument to pack */ + size_t totalsize = 0; /* accumulate total size of result */ + initheader(L, &h); + lua_pushnil(L); /* mark to separate arguments from string buffer */ + luaL_buffinit(L, &b); + while (*fmt != '\0') { + int size, ntoalign; + KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign); + totalsize += ntoalign + size; + while (ntoalign-- > 0) + luaL_addchar(&b, LUAL_PACKPADBYTE); /* fill alignment */ + arg++; + switch (opt) { + case Kint: { /* signed integers */ + lua_Integer n = luaL_checkinteger(L, arg); + if (size < SZINT) { /* need overflow check? */ + lua_Integer lim = (lua_Integer)1 << ((size * NB) - 1); + luaL_argcheck(L, -lim <= n && n < lim, arg, "integer overflow"); + } + packint(&b, (lua_Unsigned)n, h.islittle, size, (n < 0)); + break; + } + case Kuint: { /* unsigned integers */ + lua_Integer n = luaL_checkinteger(L, arg); + if (size < SZINT) /* need overflow check? */ + luaL_argcheck(L, (lua_Unsigned)n < ((lua_Unsigned)1 << (size * NB)), + arg, "unsigned overflow"); + packint(&b, (lua_Unsigned)n, h.islittle, size, 0); + break; + } + case Kfloat: { /* floating-point options */ + volatile Ftypes u; + char *buff = luaL_prepbuffsize(&b, size); + lua_Number n = luaL_checknumber(L, arg); /* get argument */ + if (size == sizeof(u.f)) u.f = (float)n; /* copy it into 'u' */ + else if (size == sizeof(u.d)) u.d = (double)n; + else u.n = n; + /* move 'u' to final result, correcting endianness if needed */ + copywithendian(buff, u.buff, size, h.islittle); + luaL_addsize(&b, size); + break; + } + case Kchar: { /* fixed-size string */ + size_t len; + const char *s = luaL_checklstring(L, arg, &len); + luaL_argcheck(L, len <= (size_t)size, arg, + "string longer than given size"); + luaL_addlstring(&b, s, len); /* add string */ + while (len++ < (size_t)size) /* pad extra space */ + luaL_addchar(&b, LUAL_PACKPADBYTE); + break; + } + case Kstring: { /* strings with length count */ + size_t len; + const char *s = luaL_checklstring(L, arg, &len); + luaL_argcheck(L, size >= (int)sizeof(size_t) || + len < ((size_t)1 << (size * NB)), + arg, "string length does not fit in given size"); + packint(&b, (lua_Unsigned)len, h.islittle, size, 0); /* pack length */ + luaL_addlstring(&b, s, len); + totalsize += len; + break; + } + case Kzstr: { /* zero-terminated string */ + size_t len; + const char *s = luaL_checklstring(L, arg, &len); + luaL_argcheck(L, strlen(s) == len, arg, "string contains zeros"); + luaL_addlstring(&b, s, len); + luaL_addchar(&b, '\0'); /* add zero at the end */ + totalsize += len + 1; + break; + } + case Kpadding: luaL_addchar(&b, LUAL_PACKPADBYTE); /* FALLTHROUGH */ + case Kpaddalign: case Knop: + arg--; /* undo increment */ + break; + } + } + luaL_pushresult(&b); + return 1; +} + + +static int str_packsize (lua_State *L) { + Header h; + const char *fmt = luaL_checkstring(L, 1); /* format string */ + size_t totalsize = 0; /* accumulate total size of result */ + initheader(L, &h); + while (*fmt != '\0') { + int size, ntoalign; + KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign); + size += ntoalign; /* total space used by option */ + luaL_argcheck(L, totalsize <= MAXSIZE - size, 1, + "format result too large"); + totalsize += size; + switch (opt) { + case Kstring: /* strings with length count */ + case Kzstr: /* zero-terminated string */ + luaL_argerror(L, 1, "variable-length format"); + /* call never return, but to avoid warnings: *//* FALLTHROUGH */ + default: break; + } + } + lua_pushinteger(L, (lua_Integer)totalsize); + return 1; +} + + +/* +** Unpack an integer with 'size' bytes and 'islittle' endianness. +** If size is smaller than the size of a Lua integer and integer +** is signed, must do sign extension (propagating the sign to the +** higher bits); if size is larger than the size of a Lua integer, +** it must check the unread bytes to see whether they do not cause an +** overflow. +*/ +static lua_Integer unpackint (lua_State *L, const char *str, + int islittle, int size, int issigned) { + lua_Unsigned res = 0; + int i; + int limit = (size <= SZINT) ? size : SZINT; + for (i = limit - 1; i >= 0; i--) { + res <<= NB; + res |= (lua_Unsigned)(unsigned char)str[islittle ? i : size - 1 - i]; + } + if (size < SZINT) { /* real size smaller than lua_Integer? */ + if (issigned) { /* needs sign extension? */ + lua_Unsigned mask = (lua_Unsigned)1 << (size*NB - 1); + res = ((res ^ mask) - mask); /* do sign extension */ + } + } + else if (size > SZINT) { /* must check unread bytes */ + int mask = (!issigned || (lua_Integer)res >= 0) ? 0 : MC; + for (i = limit; i < size; i++) { + if ((unsigned char)str[islittle ? i : size - 1 - i] != mask) + luaL_error(L, "%d-byte integer does not fit into Lua Integer", size); + } + } + return (lua_Integer)res; +} + + +static int str_unpack (lua_State *L) { + Header h; + const char *fmt = luaL_checkstring(L, 1); + size_t ld; + const char *data = luaL_checklstring(L, 2, &ld); + size_t pos = (size_t)posrelat(luaL_optinteger(L, 3, 1), ld) - 1; + int n = 0; /* number of results */ + luaL_argcheck(L, pos <= ld, 3, "initial position out of string"); + initheader(L, &h); + while (*fmt != '\0') { + int size, ntoalign; + KOption opt = getdetails(&h, pos, &fmt, &size, &ntoalign); + if ((size_t)ntoalign + size > ~pos || pos + ntoalign + size > ld) + luaL_argerror(L, 2, "data string too short"); + pos += ntoalign; /* skip alignment */ + /* stack space for item + next position */ + luaL_checkstack(L, 2, "too many results"); + n++; + switch (opt) { + case Kint: + case Kuint: { + lua_Integer res = unpackint(L, data + pos, h.islittle, size, + (opt == Kint)); + lua_pushinteger(L, res); + break; + } + case Kfloat: { + volatile Ftypes u; + lua_Number num; + copywithendian(u.buff, data + pos, size, h.islittle); + if (size == sizeof(u.f)) num = (lua_Number)u.f; + else if (size == sizeof(u.d)) num = (lua_Number)u.d; + else num = u.n; + lua_pushnumber(L, num); + break; + } + case Kchar: { + lua_pushlstring(L, data + pos, size); + break; + } + case Kstring: { + size_t len = (size_t)unpackint(L, data + pos, h.islittle, size, 0); + luaL_argcheck(L, pos + len + size <= ld, 2, "data string too short"); + lua_pushlstring(L, data + pos + size, len); + pos += len; /* skip string */ + break; + } + case Kzstr: { + size_t len = (int)strlen(data + pos); + lua_pushlstring(L, data + pos, len); + pos += len + 1; /* skip string plus final '\0' */ + break; + } + case Kpaddalign: case Kpadding: case Knop: + n--; /* undo increment */ + break; + } + pos += size; + } + lua_pushinteger(L, pos + 1); /* next position */ + return n + 1; +} + +/* }====================================================== */ + + +static const luaL_Reg strlib[] = { + {"byte", str_byte}, + {"char", str_char}, + {"dump", str_dump}, + {"find", str_find}, + {"format", str_format}, + {"gmatch", gmatch}, + {"gsub", str_gsub}, + {"len", str_len}, + {"lower", str_lower}, + {"match", str_match}, + {"rep", str_rep}, + {"reverse", str_reverse}, + {"sub", str_sub}, + {"upper", str_upper}, + {"pack", str_pack}, + {"packsize", str_packsize}, + {"unpack", str_unpack}, + {NULL, NULL} +}; + + +static void createmetatable (lua_State *L) { + lua_createtable(L, 0, 1); /* table to be metatable for strings */ + lua_pushliteral(L, ""); /* dummy string */ + lua_pushvalue(L, -2); /* copy table */ + lua_setmetatable(L, -2); /* set table as metatable for strings */ + lua_pop(L, 1); /* pop dummy string */ + lua_pushvalue(L, -2); /* get string library */ + lua_setfield(L, -2, "__index"); /* metatable.__index = string */ + lua_pop(L, 1); /* pop metatable */ +} + + +/* +** Open string library +*/ +LUAMOD_API int luaopen_string (lua_State *L) { + luaL_newlib(L, strlib); + createmetatable(L); + return 1; +} + diff --git a/depends/lua/src/ltable.c b/depends/lua/src/ltable.c new file mode 100644 index 0000000000..ea4fe7fcb3 --- /dev/null +++ b/depends/lua/src/ltable.c @@ -0,0 +1,688 @@ +/* +** $Id: ltable.c,v 2.118.1.4 2018/06/08 16:22:51 roberto Exp $ +** Lua tables (hash) +** See Copyright Notice in lua.h +*/ + +#define ltable_c +#define LUA_CORE + +#include "lprefix.h" + + +/* +** Implementation of tables (aka arrays, objects, or hash tables). +** Tables keep its elements in two parts: an array part and a hash part. +** Non-negative integer keys are all candidates to be kept in the array +** part. The actual size of the array is the largest 'n' such that +** more than half the slots between 1 and n are in use. +** Hash uses a mix of chained scatter table with Brent's variation. +** A main invariant of these tables is that, if an element is not +** in its main position (i.e. the 'original' position that its hash gives +** to it), then the colliding element is in its own main position. +** Hence even when the load factor reaches 100%, performance remains good. +*/ + +#include +#include + +#include "lua.h" + +#include "ldebug.h" +#include "ldo.h" +#include "lgc.h" +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "lvm.h" + + +/* +** Maximum size of array part (MAXASIZE) is 2^MAXABITS. MAXABITS is +** the largest integer such that MAXASIZE fits in an unsigned int. +*/ +#define MAXABITS cast_int(sizeof(int) * CHAR_BIT - 1) +#define MAXASIZE (1u << MAXABITS) + +/* +** Maximum size of hash part is 2^MAXHBITS. MAXHBITS is the largest +** integer such that 2^MAXHBITS fits in a signed int. (Note that the +** maximum number of elements in a table, 2^MAXABITS + 2^MAXHBITS, still +** fits comfortably in an unsigned int.) +*/ +#define MAXHBITS (MAXABITS - 1) + + +#define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t)))) + +#define hashstr(t,str) hashpow2(t, (str)->hash) +#define hashboolean(t,p) hashpow2(t, p) +#define hashint(t,i) hashpow2(t, i) + + +/* +** for some types, it is better to avoid modulus by power of 2, as +** they tend to have many 2 factors. +*/ +#define hashmod(t,n) (gnode(t, ((n) % ((sizenode(t)-1)|1)))) + + +#define hashpointer(t,p) hashmod(t, point2uint(p)) + + +#define dummynode (&dummynode_) + +static const Node dummynode_ = { + {NILCONSTANT}, /* value */ + {{NILCONSTANT, 0}} /* key */ +}; + + +/* +** Hash for floating-point numbers. +** The main computation should be just +** n = frexp(n, &i); return (n * INT_MAX) + i +** but there are some numerical subtleties. +** In a two-complement representation, INT_MAX does not has an exact +** representation as a float, but INT_MIN does; because the absolute +** value of 'frexp' is smaller than 1 (unless 'n' is inf/NaN), the +** absolute value of the product 'frexp * -INT_MIN' is smaller or equal +** to INT_MAX. Next, the use of 'unsigned int' avoids overflows when +** adding 'i'; the use of '~u' (instead of '-u') avoids problems with +** INT_MIN. +*/ +#if !defined(l_hashfloat) +static int l_hashfloat (lua_Number n) { + int i; + lua_Integer ni; + n = l_mathop(frexp)(n, &i) * -cast_num(INT_MIN); + if (!lua_numbertointeger(n, &ni)) { /* is 'n' inf/-inf/NaN? */ + lua_assert(luai_numisnan(n) || l_mathop(fabs)(n) == cast_num(HUGE_VAL)); + return 0; + } + else { /* normal case */ + unsigned int u = cast(unsigned int, i) + cast(unsigned int, ni); + return cast_int(u <= cast(unsigned int, INT_MAX) ? u : ~u); + } +} +#endif + + +/* +** returns the 'main' position of an element in a table (that is, the index +** of its hash value) +*/ +static Node *mainposition (const Table *t, const TValue *key) { + switch (ttype(key)) { + case LUA_TNUMINT: + return hashint(t, ivalue(key)); + case LUA_TNUMFLT: + return hashmod(t, l_hashfloat(fltvalue(key))); + case LUA_TSHRSTR: + return hashstr(t, tsvalue(key)); + case LUA_TLNGSTR: + return hashpow2(t, luaS_hashlongstr(tsvalue(key))); + case LUA_TBOOLEAN: + return hashboolean(t, bvalue(key)); + case LUA_TLIGHTUSERDATA: + return hashpointer(t, pvalue(key)); + case LUA_TLCF: + return hashpointer(t, fvalue(key)); + default: + lua_assert(!ttisdeadkey(key)); + return hashpointer(t, gcvalue(key)); + } +} + + +/* +** returns the index for 'key' if 'key' is an appropriate key to live in +** the array part of the table, 0 otherwise. +*/ +static unsigned int arrayindex (const TValue *key) { + if (ttisinteger(key)) { + lua_Integer k = ivalue(key); + if (0 < k && (lua_Unsigned)k <= MAXASIZE) + return cast(unsigned int, k); /* 'key' is an appropriate array index */ + } + return 0; /* 'key' did not match some condition */ +} + + +/* +** returns the index of a 'key' for table traversals. First goes all +** elements in the array part, then elements in the hash part. The +** beginning of a traversal is signaled by 0. +*/ +static unsigned int findindex (lua_State *L, Table *t, StkId key) { + unsigned int i; + if (ttisnil(key)) return 0; /* first iteration */ + i = arrayindex(key); + if (i != 0 && i <= t->sizearray) /* is 'key' inside array part? */ + return i; /* yes; that's the index */ + else { + int nx; + Node *n = mainposition(t, key); + for (;;) { /* check whether 'key' is somewhere in the chain */ + /* key may be dead already, but it is ok to use it in 'next' */ + if (luaV_rawequalobj(gkey(n), key) || + (ttisdeadkey(gkey(n)) && iscollectable(key) && + deadvalue(gkey(n)) == gcvalue(key))) { + i = cast_int(n - gnode(t, 0)); /* key index in hash table */ + /* hash elements are numbered after array ones */ + return (i + 1) + t->sizearray; + } + nx = gnext(n); + if (nx == 0) + luaG_runerror(L, "invalid key to 'next'"); /* key not found */ + else n += nx; + } + } +} + + +int luaH_next (lua_State *L, Table *t, StkId key) { + unsigned int i = findindex(L, t, key); /* find original element */ + for (; i < t->sizearray; i++) { /* try first array part */ + if (!ttisnil(&t->array[i])) { /* a non-nil value? */ + setivalue(key, i + 1); + setobj2s(L, key+1, &t->array[i]); + return 1; + } + } + for (i -= t->sizearray; cast_int(i) < sizenode(t); i++) { /* hash part */ + if (!ttisnil(gval(gnode(t, i)))) { /* a non-nil value? */ + setobj2s(L, key, gkey(gnode(t, i))); + setobj2s(L, key+1, gval(gnode(t, i))); + return 1; + } + } + return 0; /* no more elements */ +} + + +/* +** {============================================================= +** Rehash +** ============================================================== +*/ + +/* +** Compute the optimal size for the array part of table 't'. 'nums' is a +** "count array" where 'nums[i]' is the number of integers in the table +** between 2^(i - 1) + 1 and 2^i. 'pna' enters with the total number of +** integer keys in the table and leaves with the number of keys that +** will go to the array part; return the optimal size. +*/ +static unsigned int computesizes (unsigned int nums[], unsigned int *pna) { + int i; + unsigned int twotoi; /* 2^i (candidate for optimal size) */ + unsigned int a = 0; /* number of elements smaller than 2^i */ + unsigned int na = 0; /* number of elements to go to array part */ + unsigned int optimal = 0; /* optimal size for array part */ + /* loop while keys can fill more than half of total size */ + for (i = 0, twotoi = 1; + twotoi > 0 && *pna > twotoi / 2; + i++, twotoi *= 2) { + if (nums[i] > 0) { + a += nums[i]; + if (a > twotoi/2) { /* more than half elements present? */ + optimal = twotoi; /* optimal size (till now) */ + na = a; /* all elements up to 'optimal' will go to array part */ + } + } + } + lua_assert((optimal == 0 || optimal / 2 < na) && na <= optimal); + *pna = na; + return optimal; +} + + +static int countint (const TValue *key, unsigned int *nums) { + unsigned int k = arrayindex(key); + if (k != 0) { /* is 'key' an appropriate array index? */ + nums[luaO_ceillog2(k)]++; /* count as such */ + return 1; + } + else + return 0; +} + + +/* +** Count keys in array part of table 't': Fill 'nums[i]' with +** number of keys that will go into corresponding slice and return +** total number of non-nil keys. +*/ +static unsigned int numusearray (const Table *t, unsigned int *nums) { + int lg; + unsigned int ttlg; /* 2^lg */ + unsigned int ause = 0; /* summation of 'nums' */ + unsigned int i = 1; /* count to traverse all array keys */ + /* traverse each slice */ + for (lg = 0, ttlg = 1; lg <= MAXABITS; lg++, ttlg *= 2) { + unsigned int lc = 0; /* counter */ + unsigned int lim = ttlg; + if (lim > t->sizearray) { + lim = t->sizearray; /* adjust upper limit */ + if (i > lim) + break; /* no more elements to count */ + } + /* count elements in range (2^(lg - 1), 2^lg] */ + for (; i <= lim; i++) { + if (!ttisnil(&t->array[i-1])) + lc++; + } + nums[lg] += lc; + ause += lc; + } + return ause; +} + + +static int numusehash (const Table *t, unsigned int *nums, unsigned int *pna) { + int totaluse = 0; /* total number of elements */ + int ause = 0; /* elements added to 'nums' (can go to array part) */ + int i = sizenode(t); + while (i--) { + Node *n = &t->node[i]; + if (!ttisnil(gval(n))) { + ause += countint(gkey(n), nums); + totaluse++; + } + } + *pna += ause; + return totaluse; +} + + +static void setarrayvector (lua_State *L, Table *t, unsigned int size) { + unsigned int i; + luaM_reallocvector(L, t->array, t->sizearray, size, TValue); + for (i=t->sizearray; iarray[i]); + t->sizearray = size; +} + + +static void setnodevector (lua_State *L, Table *t, unsigned int size) { + if (size == 0) { /* no elements to hash part? */ + t->node = cast(Node *, dummynode); /* use common 'dummynode' */ + t->lsizenode = 0; + t->lastfree = NULL; /* signal that it is using dummy node */ + } + else { + int i; + int lsize = luaO_ceillog2(size); + if (lsize > MAXHBITS) + luaG_runerror(L, "table overflow"); + size = twoto(lsize); + t->node = luaM_newvector(L, size, Node); + for (i = 0; i < (int)size; i++) { + Node *n = gnode(t, i); + gnext(n) = 0; + setnilvalue(wgkey(n)); + setnilvalue(gval(n)); + } + t->lsizenode = cast_byte(lsize); + t->lastfree = gnode(t, size); /* all positions are free */ + } +} + + +typedef struct { + Table *t; + unsigned int nhsize; +} AuxsetnodeT; + + +static void auxsetnode (lua_State *L, void *ud) { + AuxsetnodeT *asn = cast(AuxsetnodeT *, ud); + setnodevector(L, asn->t, asn->nhsize); +} + + +void luaH_resize (lua_State *L, Table *t, unsigned int nasize, + unsigned int nhsize) { + unsigned int i; + int j; + AuxsetnodeT asn; + unsigned int oldasize = t->sizearray; + int oldhsize = allocsizenode(t); + Node *nold = t->node; /* save old hash ... */ + if (nasize > oldasize) /* array part must grow? */ + setarrayvector(L, t, nasize); + /* create new hash part with appropriate size */ + asn.t = t; asn.nhsize = nhsize; + if (luaD_rawrunprotected(L, auxsetnode, &asn) != LUA_OK) { /* mem. error? */ + setarrayvector(L, t, oldasize); /* array back to its original size */ + luaD_throw(L, LUA_ERRMEM); /* rethrow memory error */ + } + if (nasize < oldasize) { /* array part must shrink? */ + t->sizearray = nasize; + /* re-insert elements from vanishing slice */ + for (i=nasize; iarray[i])) + luaH_setint(L, t, i + 1, &t->array[i]); + } + /* shrink array */ + luaM_reallocvector(L, t->array, oldasize, nasize, TValue); + } + /* re-insert elements from hash part */ + for (j = oldhsize - 1; j >= 0; j--) { + Node *old = nold + j; + if (!ttisnil(gval(old))) { + /* doesn't need barrier/invalidate cache, as entry was + already present in the table */ + setobjt2t(L, luaH_set(L, t, gkey(old)), gval(old)); + } + } + if (oldhsize > 0) /* not the dummy node? */ + luaM_freearray(L, nold, cast(size_t, oldhsize)); /* free old hash */ +} + + +void luaH_resizearray (lua_State *L, Table *t, unsigned int nasize) { + int nsize = allocsizenode(t); + luaH_resize(L, t, nasize, nsize); +} + +/* +** nums[i] = number of keys 'k' where 2^(i - 1) < k <= 2^i +*/ +static void rehash (lua_State *L, Table *t, const TValue *ek) { + unsigned int asize; /* optimal size for array part */ + unsigned int na; /* number of keys in the array part */ + unsigned int nums[MAXABITS + 1]; + int i; + int totaluse; + for (i = 0; i <= MAXABITS; i++) nums[i] = 0; /* reset counts */ + na = numusearray(t, nums); /* count keys in array part */ + totaluse = na; /* all those keys are integer keys */ + totaluse += numusehash(t, nums, &na); /* count keys in hash part */ + /* count extra key */ + na += countint(ek, nums); + totaluse++; + /* compute new size for array part */ + asize = computesizes(nums, &na); + /* resize the table to new computed sizes */ + luaH_resize(L, t, asize, totaluse - na); +} + + + +/* +** }============================================================= +*/ + + +Table *luaH_new (lua_State *L) { + GCObject *o = luaC_newobj(L, LUA_TTABLE, sizeof(Table)); + Table *t = gco2t(o); + t->metatable = NULL; + t->flags = cast_byte(~0); + t->array = NULL; + t->sizearray = 0; + setnodevector(L, t, 0); + return t; +} + + +void luaH_free (lua_State *L, Table *t) { + if (!isdummy(t)) + luaM_freearray(L, t->node, cast(size_t, sizenode(t))); + luaM_freearray(L, t->array, t->sizearray); + luaM_free(L, t); +} + + +static Node *getfreepos (Table *t) { + if (!isdummy(t)) { + while (t->lastfree > t->node) { + t->lastfree--; + if (ttisnil(gkey(t->lastfree))) + return t->lastfree; + } + } + return NULL; /* could not find a free place */ +} + + + +/* +** inserts a new key into a hash table; first, check whether key's main +** position is free. If not, check whether colliding node is in its main +** position or not: if it is not, move colliding node to an empty place and +** put new key in its main position; otherwise (colliding node is in its main +** position), new key goes to an empty position. +*/ +TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) { + Node *mp; + TValue aux; + if (ttisnil(key)) luaG_runerror(L, "table index is nil"); + else if (ttisfloat(key)) { + lua_Integer k; + if (luaV_tointeger(key, &k, 0)) { /* does index fit in an integer? */ + setivalue(&aux, k); + key = &aux; /* insert it as an integer */ + } + else if (luai_numisnan(fltvalue(key))) + luaG_runerror(L, "table index is NaN"); + } + mp = mainposition(t, key); + if (!ttisnil(gval(mp)) || isdummy(t)) { /* main position is taken? */ + Node *othern; + Node *f = getfreepos(t); /* get a free place */ + if (f == NULL) { /* cannot find a free place? */ + rehash(L, t, key); /* grow table */ + /* whatever called 'newkey' takes care of TM cache */ + return luaH_set(L, t, key); /* insert key into grown table */ + } + lua_assert(!isdummy(t)); + othern = mainposition(t, gkey(mp)); + if (othern != mp) { /* is colliding node out of its main position? */ + /* yes; move colliding node into free position */ + while (othern + gnext(othern) != mp) /* find previous */ + othern += gnext(othern); + gnext(othern) = cast_int(f - othern); /* rechain to point to 'f' */ + *f = *mp; /* copy colliding node into free pos. (mp->next also goes) */ + if (gnext(mp) != 0) { + gnext(f) += cast_int(mp - f); /* correct 'next' */ + gnext(mp) = 0; /* now 'mp' is free */ + } + setnilvalue(gval(mp)); + } + else { /* colliding node is in its own main position */ + /* new node will go into free position */ + if (gnext(mp) != 0) + gnext(f) = cast_int((mp + gnext(mp)) - f); /* chain new position */ + else lua_assert(gnext(f) == 0); + gnext(mp) = cast_int(f - mp); + mp = f; + } + } + setnodekey(L, &mp->i_key, key); + luaC_barrierback(L, t, key); + lua_assert(ttisnil(gval(mp))); + return gval(mp); +} + + +/* +** search function for integers +*/ +const TValue *luaH_getint (Table *t, lua_Integer key) { + /* (1 <= key && key <= t->sizearray) */ + if (l_castS2U(key) - 1 < t->sizearray) + return &t->array[key - 1]; + else { + Node *n = hashint(t, key); + for (;;) { /* check whether 'key' is somewhere in the chain */ + if (ttisinteger(gkey(n)) && ivalue(gkey(n)) == key) + return gval(n); /* that's it */ + else { + int nx = gnext(n); + if (nx == 0) break; + n += nx; + } + } + return luaO_nilobject; + } +} + + +/* +** search function for short strings +*/ +const TValue *luaH_getshortstr (Table *t, TString *key) { + Node *n = hashstr(t, key); + lua_assert(key->tt == LUA_TSHRSTR); + for (;;) { /* check whether 'key' is somewhere in the chain */ + const TValue *k = gkey(n); + if (ttisshrstring(k) && eqshrstr(tsvalue(k), key)) + return gval(n); /* that's it */ + else { + int nx = gnext(n); + if (nx == 0) + return luaO_nilobject; /* not found */ + n += nx; + } + } +} + + +/* +** "Generic" get version. (Not that generic: not valid for integers, +** which may be in array part, nor for floats with integral values.) +*/ +static const TValue *getgeneric (Table *t, const TValue *key) { + Node *n = mainposition(t, key); + for (;;) { /* check whether 'key' is somewhere in the chain */ + if (luaV_rawequalobj(gkey(n), key)) + return gval(n); /* that's it */ + else { + int nx = gnext(n); + if (nx == 0) + return luaO_nilobject; /* not found */ + n += nx; + } + } +} + + +const TValue *luaH_getstr (Table *t, TString *key) { + if (key->tt == LUA_TSHRSTR) + return luaH_getshortstr(t, key); + else { /* for long strings, use generic case */ + TValue ko; + setsvalue(cast(lua_State *, NULL), &ko, key); + return getgeneric(t, &ko); + } +} + + +/* +** main search function +*/ +const TValue *luaH_get (Table *t, const TValue *key) { + switch (ttype(key)) { + case LUA_TSHRSTR: return luaH_getshortstr(t, tsvalue(key)); + case LUA_TNUMINT: return luaH_getint(t, ivalue(key)); + case LUA_TNIL: return luaO_nilobject; + case LUA_TNUMFLT: { + lua_Integer k; + if (luaV_tointeger(key, &k, 0)) /* index is int? */ + return luaH_getint(t, k); /* use specialized version */ + /* else... */ + } /* FALLTHROUGH */ + default: + return getgeneric(t, key); + } +} + + +/* +** beware: when using this function you probably need to check a GC +** barrier and invalidate the TM cache. +*/ +TValue *luaH_set (lua_State *L, Table *t, const TValue *key) { + const TValue *p = luaH_get(t, key); + if (p != luaO_nilobject) + return cast(TValue *, p); + else return luaH_newkey(L, t, key); +} + + +void luaH_setint (lua_State *L, Table *t, lua_Integer key, TValue *value) { + const TValue *p = luaH_getint(t, key); + TValue *cell; + if (p != luaO_nilobject) + cell = cast(TValue *, p); + else { + TValue k; + setivalue(&k, key); + cell = luaH_newkey(L, t, &k); + } + setobj2t(L, cell, value); +} + + +static lua_Unsigned unbound_search (Table *t, lua_Unsigned j) { + lua_Unsigned i = j; /* i is zero or a present index */ + j++; + /* find 'i' and 'j' such that i is present and j is not */ + while (!ttisnil(luaH_getint(t, j))) { + i = j; + if (j > l_castS2U(LUA_MAXINTEGER) / 2) { /* overflow? */ + /* table was built with bad purposes: resort to linear search */ + i = 1; + while (!ttisnil(luaH_getint(t, i))) i++; + return i - 1; + } + j *= 2; + } + /* now do a binary search between them */ + while (j - i > 1) { + lua_Unsigned m = (i+j)/2; + if (ttisnil(luaH_getint(t, m))) j = m; + else i = m; + } + return i; +} + + +/* +** Try to find a boundary in table 't'. A 'boundary' is an integer index +** such that t[i] is non-nil and t[i+1] is nil (and 0 if t[1] is nil). +*/ +lua_Unsigned luaH_getn (Table *t) { + unsigned int j = t->sizearray; + if (j > 0 && ttisnil(&t->array[j - 1])) { + /* there is a boundary in the array part: (binary) search for it */ + unsigned int i = 0; + while (j - i > 1) { + unsigned int m = (i+j)/2; + if (ttisnil(&t->array[m - 1])) j = m; + else i = m; + } + return i; + } + /* else must find a boundary in hash part */ + else if (isdummy(t)) /* hash part is empty? */ + return j; /* that is easy... */ + else return unbound_search(t, j); +} + + + +#if defined(LUA_DEBUG) + +Node *luaH_mainposition (const Table *t, const TValue *key) { + return mainposition(t, key); +} + +int luaH_isdummy (const Table *t) { return isdummy(t); } + +#endif diff --git a/depends/lua/src/ltablib.c b/depends/lua/src/ltablib.c new file mode 100644 index 0000000000..c5349578ec --- /dev/null +++ b/depends/lua/src/ltablib.c @@ -0,0 +1,450 @@ +/* +** $Id: ltablib.c,v 1.93.1.1 2017/04/19 17:20:42 roberto Exp $ +** Library for Table Manipulation +** See Copyright Notice in lua.h +*/ + +#define ltablib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include +#include +#include + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +/* +** Operations that an object must define to mimic a table +** (some functions only need some of them) +*/ +#define TAB_R 1 /* read */ +#define TAB_W 2 /* write */ +#define TAB_L 4 /* length */ +#define TAB_RW (TAB_R | TAB_W) /* read/write */ + + +#define aux_getn(L,n,w) (checktab(L, n, (w) | TAB_L), luaL_len(L, n)) + + +static int checkfield (lua_State *L, const char *key, int n) { + lua_pushstring(L, key); + return (lua_rawget(L, -n) != LUA_TNIL); +} + + +/* +** Check that 'arg' either is a table or can behave like one (that is, +** has a metatable with the required metamethods) +*/ +static void checktab (lua_State *L, int arg, int what) { + if (lua_type(L, arg) != LUA_TTABLE) { /* is it not a table? */ + int n = 1; /* number of elements to pop */ + if (lua_getmetatable(L, arg) && /* must have metatable */ + (!(what & TAB_R) || checkfield(L, "__index", ++n)) && + (!(what & TAB_W) || checkfield(L, "__newindex", ++n)) && + (!(what & TAB_L) || checkfield(L, "__len", ++n))) { + lua_pop(L, n); /* pop metatable and tested metamethods */ + } + else + luaL_checktype(L, arg, LUA_TTABLE); /* force an error */ + } +} + + +#if defined(LUA_COMPAT_MAXN) +static int maxn (lua_State *L) { + lua_Number max = 0; + luaL_checktype(L, 1, LUA_TTABLE); + lua_pushnil(L); /* first key */ + while (lua_next(L, 1)) { + lua_pop(L, 1); /* remove value */ + if (lua_type(L, -1) == LUA_TNUMBER) { + lua_Number v = lua_tonumber(L, -1); + if (v > max) max = v; + } + } + lua_pushnumber(L, max); + return 1; +} +#endif + + +static int tinsert (lua_State *L) { + lua_Integer e = aux_getn(L, 1, TAB_RW) + 1; /* first empty element */ + lua_Integer pos; /* where to insert new element */ + switch (lua_gettop(L)) { + case 2: { /* called with only 2 arguments */ + pos = e; /* insert new element at the end */ + break; + } + case 3: { + lua_Integer i; + pos = luaL_checkinteger(L, 2); /* 2nd argument is the position */ + luaL_argcheck(L, 1 <= pos && pos <= e, 2, "position out of bounds"); + for (i = e; i > pos; i--) { /* move up elements */ + lua_geti(L, 1, i - 1); + lua_seti(L, 1, i); /* t[i] = t[i - 1] */ + } + break; + } + default: { + return luaL_error(L, "wrong number of arguments to 'insert'"); + } + } + lua_seti(L, 1, pos); /* t[pos] = v */ + return 0; +} + + +static int tremove (lua_State *L) { + lua_Integer size = aux_getn(L, 1, TAB_RW); + lua_Integer pos = luaL_optinteger(L, 2, size); + if (pos != size) /* validate 'pos' if given */ + luaL_argcheck(L, 1 <= pos && pos <= size + 1, 1, "position out of bounds"); + lua_geti(L, 1, pos); /* result = t[pos] */ + for ( ; pos < size; pos++) { + lua_geti(L, 1, pos + 1); + lua_seti(L, 1, pos); /* t[pos] = t[pos + 1] */ + } + lua_pushnil(L); + lua_seti(L, 1, pos); /* t[pos] = nil */ + return 1; +} + + +/* +** Copy elements (1[f], ..., 1[e]) into (tt[t], tt[t+1], ...). Whenever +** possible, copy in increasing order, which is better for rehashing. +** "possible" means destination after original range, or smaller +** than origin, or copying to another table. +*/ +static int tmove (lua_State *L) { + lua_Integer f = luaL_checkinteger(L, 2); + lua_Integer e = luaL_checkinteger(L, 3); + lua_Integer t = luaL_checkinteger(L, 4); + int tt = !lua_isnoneornil(L, 5) ? 5 : 1; /* destination table */ + checktab(L, 1, TAB_R); + checktab(L, tt, TAB_W); + if (e >= f) { /* otherwise, nothing to move */ + lua_Integer n, i; + luaL_argcheck(L, f > 0 || e < LUA_MAXINTEGER + f, 3, + "too many elements to move"); + n = e - f + 1; /* number of elements to move */ + luaL_argcheck(L, t <= LUA_MAXINTEGER - n + 1, 4, + "destination wrap around"); + if (t > e || t <= f || (tt != 1 && !lua_compare(L, 1, tt, LUA_OPEQ))) { + for (i = 0; i < n; i++) { + lua_geti(L, 1, f + i); + lua_seti(L, tt, t + i); + } + } + else { + for (i = n - 1; i >= 0; i--) { + lua_geti(L, 1, f + i); + lua_seti(L, tt, t + i); + } + } + } + lua_pushvalue(L, tt); /* return destination table */ + return 1; +} + + +static void addfield (lua_State *L, luaL_Buffer *b, lua_Integer i) { + lua_geti(L, 1, i); + if (!lua_isstring(L, -1)) + luaL_error(L, "invalid value (%s) at index %d in table for 'concat'", + luaL_typename(L, -1), i); + luaL_addvalue(b); +} + + +static int tconcat (lua_State *L) { + luaL_Buffer b; + lua_Integer last = aux_getn(L, 1, TAB_R); + size_t lsep; + const char *sep = luaL_optlstring(L, 2, "", &lsep); + lua_Integer i = luaL_optinteger(L, 3, 1); + last = luaL_optinteger(L, 4, last); + luaL_buffinit(L, &b); + for (; i < last; i++) { + addfield(L, &b, i); + luaL_addlstring(&b, sep, lsep); + } + if (i == last) /* add last value (if interval was not empty) */ + addfield(L, &b, i); + luaL_pushresult(&b); + return 1; +} + + +/* +** {====================================================== +** Pack/unpack +** ======================================================= +*/ + +static int pack (lua_State *L) { + int i; + int n = lua_gettop(L); /* number of elements to pack */ + lua_createtable(L, n, 1); /* create result table */ + lua_insert(L, 1); /* put it at index 1 */ + for (i = n; i >= 1; i--) /* assign elements */ + lua_seti(L, 1, i); + lua_pushinteger(L, n); + lua_setfield(L, 1, "n"); /* t.n = number of elements */ + return 1; /* return table */ +} + + +static int unpack (lua_State *L) { + lua_Unsigned n; + lua_Integer i = luaL_optinteger(L, 2, 1); + lua_Integer e = luaL_opt(L, luaL_checkinteger, 3, luaL_len(L, 1)); + if (i > e) return 0; /* empty range */ + n = (lua_Unsigned)e - i; /* number of elements minus 1 (avoid overflows) */ + if (n >= (unsigned int)INT_MAX || !lua_checkstack(L, (int)(++n))) + return luaL_error(L, "too many results to unpack"); + for (; i < e; i++) { /* push arg[i..e - 1] (to avoid overflows) */ + lua_geti(L, 1, i); + } + lua_geti(L, 1, e); /* push last element */ + return (int)n; +} + +/* }====================================================== */ + + + +/* +** {====================================================== +** Quicksort +** (based on 'Algorithms in MODULA-3', Robert Sedgewick; +** Addison-Wesley, 1993.) +** ======================================================= +*/ + + +/* type for array indices */ +typedef unsigned int IdxT; + + +/* +** Produce a "random" 'unsigned int' to randomize pivot choice. This +** macro is used only when 'sort' detects a big imbalance in the result +** of a partition. (If you don't want/need this "randomness", ~0 is a +** good choice.) +*/ +#if !defined(l_randomizePivot) /* { */ + +#include + +/* size of 'e' measured in number of 'unsigned int's */ +#define sof(e) (sizeof(e) / sizeof(unsigned int)) + +/* +** Use 'time' and 'clock' as sources of "randomness". Because we don't +** know the types 'clock_t' and 'time_t', we cannot cast them to +** anything without risking overflows. A safe way to use their values +** is to copy them to an array of a known type and use the array values. +*/ +static unsigned int l_randomizePivot (void) { + clock_t c = clock(); + time_t t = time(NULL); + unsigned int buff[sof(c) + sof(t)]; + unsigned int i, rnd = 0; + memcpy(buff, &c, sof(c) * sizeof(unsigned int)); + memcpy(buff + sof(c), &t, sof(t) * sizeof(unsigned int)); + for (i = 0; i < sof(buff); i++) + rnd += buff[i]; + return rnd; +} + +#endif /* } */ + + +/* arrays larger than 'RANLIMIT' may use randomized pivots */ +#define RANLIMIT 100u + + +static void set2 (lua_State *L, IdxT i, IdxT j) { + lua_seti(L, 1, i); + lua_seti(L, 1, j); +} + + +/* +** Return true iff value at stack index 'a' is less than the value at +** index 'b' (according to the order of the sort). +*/ +static int sort_comp (lua_State *L, int a, int b) { + if (lua_isnil(L, 2)) /* no function? */ + return lua_compare(L, a, b, LUA_OPLT); /* a < b */ + else { /* function */ + int res; + lua_pushvalue(L, 2); /* push function */ + lua_pushvalue(L, a-1); /* -1 to compensate function */ + lua_pushvalue(L, b-2); /* -2 to compensate function and 'a' */ + lua_call(L, 2, 1); /* call function */ + res = lua_toboolean(L, -1); /* get result */ + lua_pop(L, 1); /* pop result */ + return res; + } +} + + +/* +** Does the partition: Pivot P is at the top of the stack. +** precondition: a[lo] <= P == a[up-1] <= a[up], +** so it only needs to do the partition from lo + 1 to up - 2. +** Pos-condition: a[lo .. i - 1] <= a[i] == P <= a[i + 1 .. up] +** returns 'i'. +*/ +static IdxT partition (lua_State *L, IdxT lo, IdxT up) { + IdxT i = lo; /* will be incremented before first use */ + IdxT j = up - 1; /* will be decremented before first use */ + /* loop invariant: a[lo .. i] <= P <= a[j .. up] */ + for (;;) { + /* next loop: repeat ++i while a[i] < P */ + while (lua_geti(L, 1, ++i), sort_comp(L, -1, -2)) { + if (i == up - 1) /* a[i] < P but a[up - 1] == P ?? */ + luaL_error(L, "invalid order function for sorting"); + lua_pop(L, 1); /* remove a[i] */ + } + /* after the loop, a[i] >= P and a[lo .. i - 1] < P */ + /* next loop: repeat --j while P < a[j] */ + while (lua_geti(L, 1, --j), sort_comp(L, -3, -1)) { + if (j < i) /* j < i but a[j] > P ?? */ + luaL_error(L, "invalid order function for sorting"); + lua_pop(L, 1); /* remove a[j] */ + } + /* after the loop, a[j] <= P and a[j + 1 .. up] >= P */ + if (j < i) { /* no elements out of place? */ + /* a[lo .. i - 1] <= P <= a[j + 1 .. i .. up] */ + lua_pop(L, 1); /* pop a[j] */ + /* swap pivot (a[up - 1]) with a[i] to satisfy pos-condition */ + set2(L, up - 1, i); + return i; + } + /* otherwise, swap a[i] - a[j] to restore invariant and repeat */ + set2(L, i, j); + } +} + + +/* +** Choose an element in the middle (2nd-3th quarters) of [lo,up] +** "randomized" by 'rnd' +*/ +static IdxT choosePivot (IdxT lo, IdxT up, unsigned int rnd) { + IdxT r4 = (up - lo) / 4; /* range/4 */ + IdxT p = rnd % (r4 * 2) + (lo + r4); + lua_assert(lo + r4 <= p && p <= up - r4); + return p; +} + + +/* +** QuickSort algorithm (recursive function) +*/ +static void auxsort (lua_State *L, IdxT lo, IdxT up, + unsigned int rnd) { + while (lo < up) { /* loop for tail recursion */ + IdxT p; /* Pivot index */ + IdxT n; /* to be used later */ + /* sort elements 'lo', 'p', and 'up' */ + lua_geti(L, 1, lo); + lua_geti(L, 1, up); + if (sort_comp(L, -1, -2)) /* a[up] < a[lo]? */ + set2(L, lo, up); /* swap a[lo] - a[up] */ + else + lua_pop(L, 2); /* remove both values */ + if (up - lo == 1) /* only 2 elements? */ + return; /* already sorted */ + if (up - lo < RANLIMIT || rnd == 0) /* small interval or no randomize? */ + p = (lo + up)/2; /* middle element is a good pivot */ + else /* for larger intervals, it is worth a random pivot */ + p = choosePivot(lo, up, rnd); + lua_geti(L, 1, p); + lua_geti(L, 1, lo); + if (sort_comp(L, -2, -1)) /* a[p] < a[lo]? */ + set2(L, p, lo); /* swap a[p] - a[lo] */ + else { + lua_pop(L, 1); /* remove a[lo] */ + lua_geti(L, 1, up); + if (sort_comp(L, -1, -2)) /* a[up] < a[p]? */ + set2(L, p, up); /* swap a[up] - a[p] */ + else + lua_pop(L, 2); + } + if (up - lo == 2) /* only 3 elements? */ + return; /* already sorted */ + lua_geti(L, 1, p); /* get middle element (Pivot) */ + lua_pushvalue(L, -1); /* push Pivot */ + lua_geti(L, 1, up - 1); /* push a[up - 1] */ + set2(L, p, up - 1); /* swap Pivot (a[p]) with a[up - 1] */ + p = partition(L, lo, up); + /* a[lo .. p - 1] <= a[p] == P <= a[p + 1 .. up] */ + if (p - lo < up - p) { /* lower interval is smaller? */ + auxsort(L, lo, p - 1, rnd); /* call recursively for lower interval */ + n = p - lo; /* size of smaller interval */ + lo = p + 1; /* tail call for [p + 1 .. up] (upper interval) */ + } + else { + auxsort(L, p + 1, up, rnd); /* call recursively for upper interval */ + n = up - p; /* size of smaller interval */ + up = p - 1; /* tail call for [lo .. p - 1] (lower interval) */ + } + if ((up - lo) / 128 > n) /* partition too imbalanced? */ + rnd = l_randomizePivot(); /* try a new randomization */ + } /* tail call auxsort(L, lo, up, rnd) */ +} + + +static int sort (lua_State *L) { + lua_Integer n = aux_getn(L, 1, TAB_RW); + if (n > 1) { /* non-trivial interval? */ + luaL_argcheck(L, n < INT_MAX, 1, "array too big"); + if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */ + luaL_checktype(L, 2, LUA_TFUNCTION); /* must be a function */ + lua_settop(L, 2); /* make sure there are two arguments */ + auxsort(L, 1, (IdxT)n, 0); + } + return 0; +} + +/* }====================================================== */ + + +static const luaL_Reg tab_funcs[] = { + {"concat", tconcat}, +#if defined(LUA_COMPAT_MAXN) + {"maxn", maxn}, +#endif + {"insert", tinsert}, + {"pack", pack}, + {"unpack", unpack}, + {"remove", tremove}, + {"move", tmove}, + {"sort", sort}, + {NULL, NULL} +}; + + +LUAMOD_API int luaopen_table (lua_State *L) { + luaL_newlib(L, tab_funcs); +#if defined(LUA_COMPAT_UNPACK) + /* _G.unpack = table.unpack */ + lua_getfield(L, -1, "unpack"); + lua_setglobal(L, "unpack"); +#endif + return 1; +} + diff --git a/depends/lua/src/ltm.c b/depends/lua/src/ltm.c new file mode 100644 index 0000000000..0e7c713214 --- /dev/null +++ b/depends/lua/src/ltm.c @@ -0,0 +1,165 @@ +/* +** $Id: ltm.c,v 2.38.1.1 2017/04/19 17:39:34 roberto Exp $ +** Tag methods +** See Copyright Notice in lua.h +*/ + +#define ltm_c +#define LUA_CORE + +#include "lprefix.h" + + +#include + +#include "lua.h" + +#include "ldebug.h" +#include "ldo.h" +#include "lobject.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" +#include "lvm.h" + + +static const char udatatypename[] = "userdata"; + +LUAI_DDEF const char *const luaT_typenames_[LUA_TOTALTAGS] = { + "no value", + "nil", "boolean", udatatypename, "number", + "string", "table", "function", udatatypename, "thread", + "proto" /* this last case is used for tests only */ +}; + + +void luaT_init (lua_State *L) { + static const char *const luaT_eventname[] = { /* ORDER TM */ + "__index", "__newindex", + "__gc", "__mode", "__len", "__eq", + "__add", "__sub", "__mul", "__mod", "__pow", + "__div", "__idiv", + "__band", "__bor", "__bxor", "__shl", "__shr", + "__unm", "__bnot", "__lt", "__le", + "__concat", "__call" + }; + int i; + for (i=0; itmname[i] = luaS_new(L, luaT_eventname[i]); + luaC_fix(L, obj2gco(G(L)->tmname[i])); /* never collect these names */ + } +} + + +/* +** function to be used with macro "fasttm": optimized for absence of +** tag methods +*/ +const TValue *luaT_gettm (Table *events, TMS event, TString *ename) { + const TValue *tm = luaH_getshortstr(events, ename); + lua_assert(event <= TM_EQ); + if (ttisnil(tm)) { /* no tag method? */ + events->flags |= cast_byte(1u<metatable; + break; + case LUA_TUSERDATA: + mt = uvalue(o)->metatable; + break; + default: + mt = G(L)->mt[ttnov(o)]; + } + return (mt ? luaH_getshortstr(mt, G(L)->tmname[event]) : luaO_nilobject); +} + + +/* +** Return the name of the type of an object. For tables and userdata +** with metatable, use their '__name' metafield, if present. +*/ +const char *luaT_objtypename (lua_State *L, const TValue *o) { + Table *mt; + if ((ttistable(o) && (mt = hvalue(o)->metatable) != NULL) || + (ttisfulluserdata(o) && (mt = uvalue(o)->metatable) != NULL)) { + const TValue *name = luaH_getshortstr(mt, luaS_new(L, "__name")); + if (ttisstring(name)) /* is '__name' a string? */ + return getstr(tsvalue(name)); /* use it as type name */ + } + return ttypename(ttnov(o)); /* else use standard type name */ +} + + +void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1, + const TValue *p2, TValue *p3, int hasres) { + ptrdiff_t result = savestack(L, p3); + StkId func = L->top; + setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */ + setobj2s(L, func + 1, p1); /* 1st argument */ + setobj2s(L, func + 2, p2); /* 2nd argument */ + L->top += 3; + if (!hasres) /* no result? 'p3' is third argument */ + setobj2s(L, L->top++, p3); /* 3rd argument */ + /* metamethod may yield only when called from Lua code */ + if (isLua(L->ci)) + luaD_call(L, func, hasres); + else + luaD_callnoyield(L, func, hasres); + if (hasres) { /* if has result, move it to its place */ + p3 = restorestack(L, result); + setobjs2s(L, p3, --L->top); + } +} + + +int luaT_callbinTM (lua_State *L, const TValue *p1, const TValue *p2, + StkId res, TMS event) { + const TValue *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */ + if (ttisnil(tm)) + tm = luaT_gettmbyobj(L, p2, event); /* try second operand */ + if (ttisnil(tm)) return 0; + luaT_callTM(L, tm, p1, p2, res, 1); + return 1; +} + + +void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2, + StkId res, TMS event) { + if (!luaT_callbinTM(L, p1, p2, res, event)) { + switch (event) { + case TM_CONCAT: + luaG_concaterror(L, p1, p2); + /* call never returns, but to avoid warnings: *//* FALLTHROUGH */ + case TM_BAND: case TM_BOR: case TM_BXOR: + case TM_SHL: case TM_SHR: case TM_BNOT: { + lua_Number dummy; + if (tonumber(p1, &dummy) && tonumber(p2, &dummy)) + luaG_tointerror(L, p1, p2); + else + luaG_opinterror(L, p1, p2, "perform bitwise operation on"); + } + /* calls never return, but to avoid warnings: *//* FALLTHROUGH */ + default: + luaG_opinterror(L, p1, p2, "perform arithmetic on"); + } + } +} + + +int luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2, + TMS event) { + if (!luaT_callbinTM(L, p1, p2, L->top, event)) + return -1; /* no metamethod */ + else + return !l_isfalse(L->top); +} + diff --git a/depends/lua/src/lua.c b/depends/lua/src/lua.c new file mode 100644 index 0000000000..ca5b298523 --- /dev/null +++ b/depends/lua/src/lua.c @@ -0,0 +1,612 @@ +/* +** $Id: lua.c,v 1.230.1.1 2017/04/19 17:29:57 roberto Exp $ +** Lua stand-alone interpreter +** See Copyright Notice in lua.h +*/ + +#define lua_c + +#include "lprefix.h" + + +#include +#include +#include +#include + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + + +#if !defined(LUA_PROMPT) +#define LUA_PROMPT "> " +#define LUA_PROMPT2 ">> " +#endif + +#if !defined(LUA_PROGNAME) +#define LUA_PROGNAME "lua" +#endif + +#if !defined(LUA_MAXINPUT) +#define LUA_MAXINPUT 512 +#endif + +#if !defined(LUA_INIT_VAR) +#define LUA_INIT_VAR "LUA_INIT" +#endif + +#define LUA_INITVARVERSION LUA_INIT_VAR LUA_VERSUFFIX + + +/* +** lua_stdin_is_tty detects whether the standard input is a 'tty' (that +** is, whether we're running lua interactively). +*/ +#if !defined(lua_stdin_is_tty) /* { */ + +#if defined(LUA_USE_POSIX) /* { */ + +#include +#define lua_stdin_is_tty() isatty(0) + +#elif defined(LUA_USE_WINDOWS) /* }{ */ + +#include +#include + +#define lua_stdin_is_tty() _isatty(_fileno(stdin)) + +#else /* }{ */ + +/* ISO C definition */ +#define lua_stdin_is_tty() 1 /* assume stdin is a tty */ + +#endif /* } */ + +#endif /* } */ + + +/* +** lua_readline defines how to show a prompt and then read a line from +** the standard input. +** lua_saveline defines how to "save" a read line in a "history". +** lua_freeline defines how to free a line read by lua_readline. +*/ +#if !defined(lua_readline) /* { */ + +#if defined(LUA_USE_READLINE) /* { */ + +#include +#include +#define lua_readline(L,b,p) ((void)L, ((b)=readline(p)) != NULL) +#define lua_saveline(L,line) ((void)L, add_history(line)) +#define lua_freeline(L,b) ((void)L, free(b)) + +#else /* }{ */ + +#define lua_readline(L,b,p) \ + ((void)L, fputs(p, stdout), fflush(stdout), /* show prompt */ \ + fgets(b, LUA_MAXINPUT, stdin) != NULL) /* get line */ +#define lua_saveline(L,line) { (void)L; (void)line; } +#define lua_freeline(L,b) { (void)L; (void)b; } + +#endif /* } */ + +#endif /* } */ + + + + +static lua_State *globalL = NULL; + +static const char *progname = LUA_PROGNAME; + + +/* +** Hook set by signal function to stop the interpreter. +*/ +static void lstop (lua_State *L, lua_Debug *ar) { + (void)ar; /* unused arg. */ + lua_sethook(L, NULL, 0, 0); /* reset hook */ + luaL_error(L, "interrupted!"); +} + + +/* +** Function to be called at a C signal. Because a C signal cannot +** just change a Lua state (as there is no proper synchronization), +** this function only sets a hook that, when called, will stop the +** interpreter. +*/ +static void laction (int i) { + signal(i, SIG_DFL); /* if another SIGINT happens, terminate process */ + lua_sethook(globalL, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1); +} + + +static void print_usage (const char *badoption) { + lua_writestringerror("%s: ", progname); + if (badoption[1] == 'e' || badoption[1] == 'l') + lua_writestringerror("'%s' needs argument\n", badoption); + else + lua_writestringerror("unrecognized option '%s'\n", badoption); + lua_writestringerror( + "usage: %s [options] [script [args]]\n" + "Available options are:\n" + " -e stat execute string 'stat'\n" + " -i enter interactive mode after executing 'script'\n" + " -l name require library 'name' into global 'name'\n" + " -v show version information\n" + " -E ignore environment variables\n" + " -- stop handling options\n" + " - stop handling options and execute stdin\n" + , + progname); +} + + +/* +** Prints an error message, adding the program name in front of it +** (if present) +*/ +static void l_message (const char *pname, const char *msg) { + if (pname) lua_writestringerror("%s: ", pname); + lua_writestringerror("%s\n", msg); +} + + +/* +** Check whether 'status' is not OK and, if so, prints the error +** message on the top of the stack. It assumes that the error object +** is a string, as it was either generated by Lua or by 'msghandler'. +*/ +static int report (lua_State *L, int status) { + if (status != LUA_OK) { + const char *msg = lua_tostring(L, -1); + l_message(progname, msg); + lua_pop(L, 1); /* remove message */ + } + return status; +} + + +/* +** Message handler used to run all chunks +*/ +static int msghandler (lua_State *L) { + const char *msg = lua_tostring(L, 1); + if (msg == NULL) { /* is error object not a string? */ + if (luaL_callmeta(L, 1, "__tostring") && /* does it have a metamethod */ + lua_type(L, -1) == LUA_TSTRING) /* that produces a string? */ + return 1; /* that is the message */ + else + msg = lua_pushfstring(L, "(error object is a %s value)", + luaL_typename(L, 1)); + } + luaL_traceback(L, L, msg, 1); /* append a standard traceback */ + return 1; /* return the traceback */ +} + + +/* +** Interface to 'lua_pcall', which sets appropriate message function +** and C-signal handler. Used to run all chunks. +*/ +static int docall (lua_State *L, int narg, int nres) { + int status; + int base = lua_gettop(L) - narg; /* function index */ + lua_pushcfunction(L, msghandler); /* push message handler */ + lua_insert(L, base); /* put it under function and args */ + globalL = L; /* to be available to 'laction' */ + signal(SIGINT, laction); /* set C-signal handler */ + status = lua_pcall(L, narg, nres, base); + signal(SIGINT, SIG_DFL); /* reset C-signal handler */ + lua_remove(L, base); /* remove message handler from the stack */ + return status; +} + + +static void print_version (void) { + lua_writestring(LUA_COPYRIGHT, strlen(LUA_COPYRIGHT)); + lua_writeline(); +} + + +/* +** Create the 'arg' table, which stores all arguments from the +** command line ('argv'). It should be aligned so that, at index 0, +** it has 'argv[script]', which is the script name. The arguments +** to the script (everything after 'script') go to positive indices; +** other arguments (before the script name) go to negative indices. +** If there is no script name, assume interpreter's name as base. +*/ +static void createargtable (lua_State *L, char **argv, int argc, int script) { + int i, narg; + if (script == argc) script = 0; /* no script name? */ + narg = argc - (script + 1); /* number of positive indices */ + lua_createtable(L, narg, script + 1); + for (i = 0; i < argc; i++) { + lua_pushstring(L, argv[i]); + lua_rawseti(L, -2, i - script); + } + lua_setglobal(L, "arg"); +} + + +static int dochunk (lua_State *L, int status) { + if (status == LUA_OK) status = docall(L, 0, 0); + return report(L, status); +} + + +static int dofile (lua_State *L, const char *name) { + return dochunk(L, luaL_loadfile(L, name)); +} + + +static int dostring (lua_State *L, const char *s, const char *name) { + return dochunk(L, luaL_loadbuffer(L, s, strlen(s), name)); +} + + +/* +** Calls 'require(name)' and stores the result in a global variable +** with the given name. +*/ +static int dolibrary (lua_State *L, const char *name) { + int status; + lua_getglobal(L, "require"); + lua_pushstring(L, name); + status = docall(L, 1, 1); /* call 'require(name)' */ + if (status == LUA_OK) + lua_setglobal(L, name); /* global[name] = require return */ + return report(L, status); +} + + +/* +** Returns the string to be used as a prompt by the interpreter. +*/ +static const char *get_prompt (lua_State *L, int firstline) { + const char *p; + lua_getglobal(L, firstline ? "_PROMPT" : "_PROMPT2"); + p = lua_tostring(L, -1); + if (p == NULL) p = (firstline ? LUA_PROMPT : LUA_PROMPT2); + return p; +} + +/* mark in error messages for incomplete statements */ +#define EOFMARK "" +#define marklen (sizeof(EOFMARK)/sizeof(char) - 1) + + +/* +** Check whether 'status' signals a syntax error and the error +** message at the top of the stack ends with the above mark for +** incomplete statements. +*/ +static int incomplete (lua_State *L, int status) { + if (status == LUA_ERRSYNTAX) { + size_t lmsg; + const char *msg = lua_tolstring(L, -1, &lmsg); + if (lmsg >= marklen && strcmp(msg + lmsg - marklen, EOFMARK) == 0) { + lua_pop(L, 1); + return 1; + } + } + return 0; /* else... */ +} + + +/* +** Prompt the user, read a line, and push it into the Lua stack. +*/ +static int pushline (lua_State *L, int firstline) { + char buffer[LUA_MAXINPUT]; + char *b = buffer; + size_t l; + const char *prmt = get_prompt(L, firstline); + int readstatus = lua_readline(L, b, prmt); + if (readstatus == 0) + return 0; /* no input (prompt will be popped by caller) */ + lua_pop(L, 1); /* remove prompt */ + l = strlen(b); + if (l > 0 && b[l-1] == '\n') /* line ends with newline? */ + b[--l] = '\0'; /* remove it */ + if (firstline && b[0] == '=') /* for compatibility with 5.2, ... */ + lua_pushfstring(L, "return %s", b + 1); /* change '=' to 'return' */ + else + lua_pushlstring(L, b, l); + lua_freeline(L, b); + return 1; +} + + +/* +** Try to compile line on the stack as 'return ;'; on return, stack +** has either compiled chunk or original line (if compilation failed). +*/ +static int addreturn (lua_State *L) { + const char *line = lua_tostring(L, -1); /* original line */ + const char *retline = lua_pushfstring(L, "return %s;", line); + int status = luaL_loadbuffer(L, retline, strlen(retline), "=stdin"); + if (status == LUA_OK) { + lua_remove(L, -2); /* remove modified line */ + if (line[0] != '\0') /* non empty? */ + lua_saveline(L, line); /* keep history */ + } + else + lua_pop(L, 2); /* pop result from 'luaL_loadbuffer' and modified line */ + return status; +} + + +/* +** Read multiple lines until a complete Lua statement +*/ +static int multiline (lua_State *L) { + for (;;) { /* repeat until gets a complete statement */ + size_t len; + const char *line = lua_tolstring(L, 1, &len); /* get what it has */ + int status = luaL_loadbuffer(L, line, len, "=stdin"); /* try it */ + if (!incomplete(L, status) || !pushline(L, 0)) { + lua_saveline(L, line); /* keep history */ + return status; /* cannot or should not try to add continuation line */ + } + lua_pushliteral(L, "\n"); /* add newline... */ + lua_insert(L, -2); /* ...between the two lines */ + lua_concat(L, 3); /* join them */ + } +} + + +/* +** Read a line and try to load (compile) it first as an expression (by +** adding "return " in front of it) and second as a statement. Return +** the final status of load/call with the resulting function (if any) +** in the top of the stack. +*/ +static int loadline (lua_State *L) { + int status; + lua_settop(L, 0); + if (!pushline(L, 1)) + return -1; /* no input */ + if ((status = addreturn(L)) != LUA_OK) /* 'return ...' did not work? */ + status = multiline(L); /* try as command, maybe with continuation lines */ + lua_remove(L, 1); /* remove line from the stack */ + lua_assert(lua_gettop(L) == 1); + return status; +} + + +/* +** Prints (calling the Lua 'print' function) any values on the stack +*/ +static void l_print (lua_State *L) { + int n = lua_gettop(L); + if (n > 0) { /* any result to be printed? */ + luaL_checkstack(L, LUA_MINSTACK, "too many results to print"); + lua_getglobal(L, "print"); + lua_insert(L, 1); + if (lua_pcall(L, n, 0, 0) != LUA_OK) + l_message(progname, lua_pushfstring(L, "error calling 'print' (%s)", + lua_tostring(L, -1))); + } +} + + +/* +** Do the REPL: repeatedly read (load) a line, evaluate (call) it, and +** print any results. +*/ +static void doREPL (lua_State *L) { + int status; + const char *oldprogname = progname; + progname = NULL; /* no 'progname' on errors in interactive mode */ + while ((status = loadline(L)) != -1) { + if (status == LUA_OK) + status = docall(L, 0, LUA_MULTRET); + if (status == LUA_OK) l_print(L); + else report(L, status); + } + lua_settop(L, 0); /* clear stack */ + lua_writeline(); + progname = oldprogname; +} + + +/* +** Push on the stack the contents of table 'arg' from 1 to #arg +*/ +static int pushargs (lua_State *L) { + int i, n; + if (lua_getglobal(L, "arg") != LUA_TTABLE) + luaL_error(L, "'arg' is not a table"); + n = (int)luaL_len(L, -1); + luaL_checkstack(L, n + 3, "too many arguments to script"); + for (i = 1; i <= n; i++) + lua_rawgeti(L, -i, i); + lua_remove(L, -i); /* remove table from the stack */ + return n; +} + + +static int handle_script (lua_State *L, char **argv) { + int status; + const char *fname = argv[0]; + if (strcmp(fname, "-") == 0 && strcmp(argv[-1], "--") != 0) + fname = NULL; /* stdin */ + status = luaL_loadfile(L, fname); + if (status == LUA_OK) { + int n = pushargs(L); /* push arguments to script */ + status = docall(L, n, LUA_MULTRET); + } + return report(L, status); +} + + + +/* bits of various argument indicators in 'args' */ +#define has_error 1 /* bad option */ +#define has_i 2 /* -i */ +#define has_v 4 /* -v */ +#define has_e 8 /* -e */ +#define has_E 16 /* -E */ + +/* +** Traverses all arguments from 'argv', returning a mask with those +** needed before running any Lua code (or an error code if it finds +** any invalid argument). 'first' returns the first not-handled argument +** (either the script name or a bad argument in case of error). +*/ +static int collectargs (char **argv, int *first) { + int args = 0; + int i; + for (i = 1; argv[i] != NULL; i++) { + *first = i; + if (argv[i][0] != '-') /* not an option? */ + return args; /* stop handling options */ + switch (argv[i][1]) { /* else check option */ + case '-': /* '--' */ + if (argv[i][2] != '\0') /* extra characters after '--'? */ + return has_error; /* invalid option */ + *first = i + 1; + return args; + case '\0': /* '-' */ + return args; /* script "name" is '-' */ + case 'E': + if (argv[i][2] != '\0') /* extra characters after 1st? */ + return has_error; /* invalid option */ + args |= has_E; + break; + case 'i': + args |= has_i; /* (-i implies -v) *//* FALLTHROUGH */ + case 'v': + if (argv[i][2] != '\0') /* extra characters after 1st? */ + return has_error; /* invalid option */ + args |= has_v; + break; + case 'e': + args |= has_e; /* FALLTHROUGH */ + case 'l': /* both options need an argument */ + if (argv[i][2] == '\0') { /* no concatenated argument? */ + i++; /* try next 'argv' */ + if (argv[i] == NULL || argv[i][0] == '-') + return has_error; /* no next argument or it is another option */ + } + break; + default: /* invalid option */ + return has_error; + } + } + *first = i; /* no script name */ + return args; +} + + +/* +** Processes options 'e' and 'l', which involve running Lua code. +** Returns 0 if some code raises an error. +*/ +static int runargs (lua_State *L, char **argv, int n) { + int i; + for (i = 1; i < n; i++) { + int option = argv[i][1]; + lua_assert(argv[i][0] == '-'); /* already checked */ + if (option == 'e' || option == 'l') { + int status; + const char *extra = argv[i] + 2; /* both options need an argument */ + if (*extra == '\0') extra = argv[++i]; + lua_assert(extra != NULL); + status = (option == 'e') + ? dostring(L, extra, "=(command line)") + : dolibrary(L, extra); + if (status != LUA_OK) return 0; + } + } + return 1; +} + + + +static int handle_luainit (lua_State *L) { + const char *name = "=" LUA_INITVARVERSION; + const char *init = getenv(name + 1); + if (init == NULL) { + name = "=" LUA_INIT_VAR; + init = getenv(name + 1); /* try alternative name */ + } + if (init == NULL) return LUA_OK; + else if (init[0] == '@') + return dofile(L, init+1); + else + return dostring(L, init, name); +} + + +/* +** Main body of stand-alone interpreter (to be called in protected mode). +** Reads the options and handles them all. +*/ +static int pmain (lua_State *L) { + int argc = (int)lua_tointeger(L, 1); + char **argv = (char **)lua_touserdata(L, 2); + int script; + int args = collectargs(argv, &script); + luaL_checkversion(L); /* check that interpreter has correct version */ + if (argv[0] && argv[0][0]) progname = argv[0]; + if (args == has_error) { /* bad arg? */ + print_usage(argv[script]); /* 'script' has index of bad arg. */ + return 0; + } + if (args & has_v) /* option '-v'? */ + print_version(); + if (args & has_E) { /* option '-E'? */ + lua_pushboolean(L, 1); /* signal for libraries to ignore env. vars. */ + lua_setfield(L, LUA_REGISTRYINDEX, "LUA_NOENV"); + } + luaL_openlibs(L); /* open standard libraries */ + createargtable(L, argv, argc, script); /* create table 'arg' */ + if (!(args & has_E)) { /* no option '-E'? */ + if (handle_luainit(L) != LUA_OK) /* run LUA_INIT */ + return 0; /* error running LUA_INIT */ + } + if (!runargs(L, argv, script)) /* execute arguments -e and -l */ + return 0; /* something failed */ + if (script < argc && /* execute main script (if there is one) */ + handle_script(L, argv + script) != LUA_OK) + return 0; + if (args & has_i) /* -i option? */ + doREPL(L); /* do read-eval-print loop */ + else if (script == argc && !(args & (has_e | has_v))) { /* no arguments? */ + if (lua_stdin_is_tty()) { /* running in interactive mode? */ + print_version(); + doREPL(L); /* do read-eval-print loop */ + } + else dofile(L, NULL); /* executes stdin as a file */ + } + lua_pushboolean(L, 1); /* signal no errors */ + return 1; +} + + +int main (int argc, char **argv) { + int status, result; + lua_State *L = luaL_newstate(); /* create state */ + if (L == NULL) { + l_message(argv[0], "cannot create state: not enough memory"); + return EXIT_FAILURE; + } + lua_pushcfunction(L, &pmain); /* to call 'pmain' in protected mode */ + lua_pushinteger(L, argc); /* 1st argument */ + lua_pushlightuserdata(L, argv); /* 2nd argument */ + status = lua_pcall(L, 2, 1, 0); /* do the call */ + result = lua_toboolean(L, -1); /* get result */ + report(L, status); + lua_close(L); + return (result && status == LUA_OK) ? EXIT_SUCCESS : EXIT_FAILURE; +} + diff --git a/depends/lua/src/luac.c b/depends/lua/src/luac.c new file mode 100644 index 0000000000..549ad39500 --- /dev/null +++ b/depends/lua/src/luac.c @@ -0,0 +1,450 @@ +/* +** $Id: luac.c,v 1.76 2018/06/19 01:32:02 lhf Exp $ +** Lua compiler (saves bytecodes to files; also lists bytecodes) +** See Copyright Notice in lua.h +*/ + +#define luac_c +#define LUA_CORE + +#include "lprefix.h" + +#include +#include +#include +#include +#include + +#include "lua.h" +#include "lauxlib.h" + +#include "lobject.h" +#include "lstate.h" +#include "lundump.h" + +static void PrintFunction(const Proto* f, int full); +#define luaU_print PrintFunction + +#define PROGNAME "luac" /* default program name */ +#define OUTPUT PROGNAME ".out" /* default output file */ + +static int listing=0; /* list bytecodes? */ +static int dumping=1; /* dump bytecodes? */ +static int stripping=0; /* strip debug information? */ +static char Output[]={ OUTPUT }; /* default output file name */ +static const char* output=Output; /* actual output file name */ +static const char* progname=PROGNAME; /* actual program name */ + +static void fatal(const char* message) +{ + fprintf(stderr,"%s: %s\n",progname,message); + exit(EXIT_FAILURE); +} + +static void cannot(const char* what) +{ + fprintf(stderr,"%s: cannot %s %s: %s\n",progname,what,output,strerror(errno)); + exit(EXIT_FAILURE); +} + +static void usage(const char* message) +{ + if (*message=='-') + fprintf(stderr,"%s: unrecognized option '%s'\n",progname,message); + else + fprintf(stderr,"%s: %s\n",progname,message); + fprintf(stderr, + "usage: %s [options] [filenames]\n" + "Available options are:\n" + " -l list (use -l -l for full listing)\n" + " -o name output to file 'name' (default is \"%s\")\n" + " -p parse only\n" + " -s strip debug information\n" + " -v show version information\n" + " -- stop handling options\n" + " - stop handling options and process stdin\n" + ,progname,Output); + exit(EXIT_FAILURE); +} + +#define IS(s) (strcmp(argv[i],s)==0) + +static int doargs(int argc, char* argv[]) +{ + int i; + int version=0; + if (argv[0]!=NULL && *argv[0]!=0) progname=argv[0]; + for (i=1; itop+(i)) + +static const Proto* combine(lua_State* L, int n) +{ + if (n==1) + return toproto(L,-1); + else + { + Proto* f; + int i=n; + if (lua_load(L,reader,&i,"=(" PROGNAME ")",NULL)!=LUA_OK) fatal(lua_tostring(L,-1)); + f=toproto(L,-1); + for (i=0; ip[i]=toproto(L,i-n-1); + if (f->p[i]->sizeupvalues>0) f->p[i]->upvalues[0].instack=0; + } + f->sizelineinfo=0; + return f; + } +} + +static int writer(lua_State* L, const void* p, size_t size, void* u) +{ + UNUSED(L); + return (fwrite(p,size,1,(FILE*)u)!=1) && (size!=0); +} + +static int pmain(lua_State* L) +{ + int argc=(int)lua_tointeger(L,1); + char** argv=(char**)lua_touserdata(L,2); + const Proto* f; + int i; + if (!lua_checkstack(L,argc)) fatal("too many input files"); + for (i=0; i1); + if (dumping) + { + FILE* D= (output==NULL) ? stdout : fopen(output,"wb"); + if (D==NULL) cannot("open"); + lua_lock(L); + luaU_dump(L,f,writer,D,stripping); + lua_unlock(L); + if (ferror(D)) cannot("write"); + if (fclose(D)) cannot("close"); + } + return 0; +} + +int main(int argc, char* argv[]) +{ + lua_State* L; + int i=doargs(argc,argv); + argc-=i; argv+=i; + if (argc<=0) usage("no input files given"); + L=luaL_newstate(); + if (L==NULL) fatal("cannot create state: not enough memory"); + lua_pushcfunction(L,&pmain); + lua_pushinteger(L,argc); + lua_pushlightuserdata(L,argv); + if (lua_pcall(L,2,0,0)!=LUA_OK) fatal(lua_tostring(L,-1)); + lua_close(L); + return EXIT_SUCCESS; +} + +/* +** $Id: luac.c,v 1.76 2018/06/19 01:32:02 lhf Exp $ +** print bytecodes +** See Copyright Notice in lua.h +*/ + +#include +#include + +#define luac_c +#define LUA_CORE + +#include "ldebug.h" +#include "lobject.h" +#include "lopcodes.h" + +#define VOID(p) ((const void*)(p)) + +static void PrintString(const TString* ts) +{ + const char* s=getstr(ts); + size_t i,n=tsslen(ts); + printf("%c",'"'); + for (i=0; ik[i]; + switch (ttype(o)) + { + case LUA_TNIL: + printf("nil"); + break; + case LUA_TBOOLEAN: + printf(bvalue(o) ? "true" : "false"); + break; + case LUA_TNUMFLT: + { + char buff[100]; + sprintf(buff,LUA_NUMBER_FMT,fltvalue(o)); + printf("%s",buff); + if (buff[strspn(buff,"-0123456789")]=='\0') printf(".0"); + break; + } + case LUA_TNUMINT: + printf(LUA_INTEGER_FMT,ivalue(o)); + break; + case LUA_TSHRSTR: case LUA_TLNGSTR: + PrintString(tsvalue(o)); + break; + default: /* cannot happen */ + printf("? type=%d",ttype(o)); + break; + } +} + +#define UPVALNAME(x) ((f->upvalues[x].name) ? getstr(f->upvalues[x].name) : "-") +#define MYK(x) (-1-(x)) + +static void PrintCode(const Proto* f) +{ + const Instruction* code=f->code; + int pc,n=f->sizecode; + for (pc=0; pc0) printf("[%d]\t",line); else printf("[-]\t"); + printf("%-9s\t",luaP_opnames[o]); + switch (getOpMode(o)) + { + case iABC: + printf("%d",a); + if (getBMode(o)!=OpArgN) printf(" %d",ISK(b) ? (MYK(INDEXK(b))) : b); + if (getCMode(o)!=OpArgN) printf(" %d",ISK(c) ? (MYK(INDEXK(c))) : c); + break; + case iABx: + printf("%d",a); + if (getBMode(o)==OpArgK) printf(" %d",MYK(bx)); + if (getBMode(o)==OpArgU) printf(" %d",bx); + break; + case iAsBx: + printf("%d %d",a,sbx); + break; + case iAx: + printf("%d",MYK(ax)); + break; + } + switch (o) + { + case OP_LOADK: + printf("\t; "); PrintConstant(f,bx); + break; + case OP_GETUPVAL: + case OP_SETUPVAL: + printf("\t; %s",UPVALNAME(b)); + break; + case OP_GETTABUP: + printf("\t; %s",UPVALNAME(b)); + if (ISK(c)) { printf(" "); PrintConstant(f,INDEXK(c)); } + break; + case OP_SETTABUP: + printf("\t; %s",UPVALNAME(a)); + if (ISK(b)) { printf(" "); PrintConstant(f,INDEXK(b)); } + if (ISK(c)) { printf(" "); PrintConstant(f,INDEXK(c)); } + break; + case OP_GETTABLE: + case OP_SELF: + if (ISK(c)) { printf("\t; "); PrintConstant(f,INDEXK(c)); } + break; + case OP_SETTABLE: + case OP_ADD: + case OP_SUB: + case OP_MUL: + case OP_MOD: + case OP_POW: + case OP_DIV: + case OP_IDIV: + case OP_BAND: + case OP_BOR: + case OP_BXOR: + case OP_SHL: + case OP_SHR: + case OP_EQ: + case OP_LT: + case OP_LE: + if (ISK(b) || ISK(c)) + { + printf("\t; "); + if (ISK(b)) PrintConstant(f,INDEXK(b)); else printf("-"); + printf(" "); + if (ISK(c)) PrintConstant(f,INDEXK(c)); else printf("-"); + } + break; + case OP_JMP: + case OP_FORLOOP: + case OP_FORPREP: + case OP_TFORLOOP: + printf("\t; to %d",sbx+pc+2); + break; + case OP_CLOSURE: + printf("\t; %p",VOID(f->p[bx])); + break; + case OP_SETLIST: + if (c==0) printf("\t; %d",(int)code[++pc]); else printf("\t; %d",c); + break; + case OP_EXTRAARG: + printf("\t; "); PrintConstant(f,ax); + break; + default: + break; + } + printf("\n"); + } +} + +#define SS(x) ((x==1)?"":"s") +#define S(x) (int)(x),SS(x) + +static void PrintHeader(const Proto* f) +{ + const char* s=f->source ? getstr(f->source) : "=?"; + if (*s=='@' || *s=='=') + s++; + else if (*s==LUA_SIGNATURE[0]) + s="(bstring)"; + else + s="(string)"; + printf("\n%s <%s:%d,%d> (%d instruction%s at %p)\n", + (f->linedefined==0)?"main":"function",s, + f->linedefined,f->lastlinedefined, + S(f->sizecode),VOID(f)); + printf("%d%s param%s, %d slot%s, %d upvalue%s, ", + (int)(f->numparams),f->is_vararg?"+":"",SS(f->numparams), + S(f->maxstacksize),S(f->sizeupvalues)); + printf("%d local%s, %d constant%s, %d function%s\n", + S(f->sizelocvars),S(f->sizek),S(f->sizep)); +} + +static void PrintDebug(const Proto* f) +{ + int i,n; + n=f->sizek; + printf("constants (%d) for %p:\n",n,VOID(f)); + for (i=0; isizelocvars; + printf("locals (%d) for %p:\n",n,VOID(f)); + for (i=0; ilocvars[i].varname),f->locvars[i].startpc+1,f->locvars[i].endpc+1); + } + n=f->sizeupvalues; + printf("upvalues (%d) for %p:\n",n,VOID(f)); + for (i=0; iupvalues[i].instack,f->upvalues[i].idx); + } +} + +static void PrintFunction(const Proto* f, int full) +{ + int i,n=f->sizep; + PrintHeader(f); + PrintCode(f); + if (full) PrintDebug(f); + for (i=0; ip[i],full); +} diff --git a/depends/lua/src/lundump.c b/depends/lua/src/lundump.c new file mode 100644 index 0000000000..edf9eb8d00 --- /dev/null +++ b/depends/lua/src/lundump.c @@ -0,0 +1,287 @@ +/* +** $Id: lundump.c,v 2.44.1.1 2017/04/19 17:20:42 roberto Exp $ +** load precompiled Lua chunks +** See Copyright Notice in lua.h +*/ + +#define lundump_c +#define LUA_CORE + +#include "lprefix.h" + + +#include + +#include "lua.h" + +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "lmem.h" +#include "lobject.h" +#include "lstring.h" +#include "lundump.h" +#include "lzio.h" + + +#if !defined(luai_verifycode) +#define luai_verifycode(L,b,f) /* empty */ +#endif + + +typedef struct { + lua_State *L; + ZIO *Z; + const char *name; +} LoadState; + + +static l_noret error(LoadState *S, const char *why) { + luaO_pushfstring(S->L, "%s: %s precompiled chunk", S->name, why); + luaD_throw(S->L, LUA_ERRSYNTAX); +} + + +/* +** All high-level loads go through LoadVector; you can change it to +** adapt to the endianness of the input +*/ +#define LoadVector(S,b,n) LoadBlock(S,b,(n)*sizeof((b)[0])) + +static void LoadBlock (LoadState *S, void *b, size_t size) { + if (luaZ_read(S->Z, b, size) != 0) + error(S, "truncated"); +} + + +#define LoadVar(S,x) LoadVector(S,&x,1) + + +static lu_byte LoadByte (LoadState *S) { + lu_byte x; + LoadVar(S, x); + return x; +} + + +static int LoadInt (LoadState *S) { + int x; + LoadVar(S, x); + return x; +} + + +static lua_Number LoadNumber (LoadState *S) { + lua_Number x; + LoadVar(S, x); + return x; +} + + +static lua_Integer LoadInteger (LoadState *S) { + lua_Integer x; + LoadVar(S, x); + return x; +} + + +static TString *LoadString (LoadState *S, Proto *p) { + lua_State *L = S->L; + size_t size = LoadByte(S); + TString *ts; + if (size == 0xFF) + LoadVar(S, size); + if (size == 0) + return NULL; + else if (--size <= LUAI_MAXSHORTLEN) { /* short string? */ + char buff[LUAI_MAXSHORTLEN]; + LoadVector(S, buff, size); + ts = luaS_newlstr(L, buff, size); + } + else { /* long string */ + ts = luaS_createlngstrobj(L, size); + setsvalue2s(L, L->top, ts); /* anchor it ('loadVector' can GC) */ + luaD_inctop(L); + LoadVector(S, getstr(ts), size); /* load directly in final place */ + L->top--; /* pop string */ + } + luaC_objbarrier(L, p, ts); + return ts; +} + + +static void LoadCode (LoadState *S, Proto *f) { + int n = LoadInt(S); + f->code = luaM_newvector(S->L, n, Instruction); + f->sizecode = n; + LoadVector(S, f->code, n); +} + + +static void LoadFunction(LoadState *S, Proto *f, TString *psource); + + +static void LoadConstants (LoadState *S, Proto *f) { + int i; + int n = LoadInt(S); + f->k = luaM_newvector(S->L, n, TValue); + f->sizek = n; + for (i = 0; i < n; i++) + setnilvalue(&f->k[i]); + for (i = 0; i < n; i++) { + TValue *o = &f->k[i]; + int t = LoadByte(S); + switch (t) { + case LUA_TNIL: + setnilvalue(o); + break; + case LUA_TBOOLEAN: + setbvalue(o, LoadByte(S)); + break; + case LUA_TNUMFLT: + setfltvalue(o, LoadNumber(S)); + break; + case LUA_TNUMINT: + setivalue(o, LoadInteger(S)); + break; + case LUA_TSHRSTR: + case LUA_TLNGSTR: + setsvalue2n(S->L, o, LoadString(S, f)); + break; + default: + lua_assert(0); + } + } +} + + +static void LoadProtos (LoadState *S, Proto *f) { + int i; + int n = LoadInt(S); + f->p = luaM_newvector(S->L, n, Proto *); + f->sizep = n; + for (i = 0; i < n; i++) + f->p[i] = NULL; + for (i = 0; i < n; i++) { + f->p[i] = luaF_newproto(S->L); + luaC_objbarrier(S->L, f, f->p[i]); + LoadFunction(S, f->p[i], f->source); + } +} + + +static void LoadUpvalues (LoadState *S, Proto *f) { + int i, n; + n = LoadInt(S); + f->upvalues = luaM_newvector(S->L, n, Upvaldesc); + f->sizeupvalues = n; + for (i = 0; i < n; i++) + f->upvalues[i].name = NULL; + for (i = 0; i < n; i++) { + f->upvalues[i].instack = LoadByte(S); + f->upvalues[i].idx = LoadByte(S); + } +} + + +static void LoadDebug (LoadState *S, Proto *f) { + int i, n; + n = LoadInt(S); + f->lineinfo = luaM_newvector(S->L, n, int); + f->sizelineinfo = n; + LoadVector(S, f->lineinfo, n); + n = LoadInt(S); + f->locvars = luaM_newvector(S->L, n, LocVar); + f->sizelocvars = n; + for (i = 0; i < n; i++) + f->locvars[i].varname = NULL; + for (i = 0; i < n; i++) { + f->locvars[i].varname = LoadString(S, f); + f->locvars[i].startpc = LoadInt(S); + f->locvars[i].endpc = LoadInt(S); + } + n = LoadInt(S); + for (i = 0; i < n; i++) + f->upvalues[i].name = LoadString(S, f); +} + + +static void LoadFunction (LoadState *S, Proto *f, TString *psource) { + f->source = LoadString(S, f); + if (f->source == NULL) /* no source in dump? */ + f->source = psource; /* reuse parent's source */ + f->linedefined = LoadInt(S); + f->lastlinedefined = LoadInt(S); + f->numparams = LoadByte(S); + f->is_vararg = LoadByte(S); + f->maxstacksize = LoadByte(S); + LoadCode(S, f); + LoadConstants(S, f); + LoadUpvalues(S, f); + LoadProtos(S, f); + LoadDebug(S, f); +} + + +static void checkliteral (LoadState *S, const char *s, const char *msg) { + char buff[sizeof(LUA_SIGNATURE) + sizeof(LUAC_DATA)]; /* larger than both */ + size_t len = strlen(s); + LoadVector(S, buff, len); + if (memcmp(s, buff, len) != 0) + error(S, msg); +} + + +static void fchecksize (LoadState *S, size_t size, const char *tname) { + if (LoadByte(S) != size) + error(S, luaO_pushfstring(S->L, "%s size mismatch in", tname)); +} + + +#define checksize(S,t) fchecksize(S,sizeof(t),#t) + +static void checkHeader (LoadState *S) { + checkliteral(S, LUA_SIGNATURE + 1, "not a"); /* 1st char already checked */ + if (LoadByte(S) != LUAC_VERSION) + error(S, "version mismatch in"); + if (LoadByte(S) != LUAC_FORMAT) + error(S, "format mismatch in"); + checkliteral(S, LUAC_DATA, "corrupted"); + checksize(S, int); + checksize(S, size_t); + checksize(S, Instruction); + checksize(S, lua_Integer); + checksize(S, lua_Number); + if (LoadInteger(S) != LUAC_INT) + error(S, "endianness mismatch in"); + if (LoadNumber(S) != LUAC_NUM) + error(S, "float format mismatch in"); +} + + +/* +** load precompiled chunk +*/ +LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) { + LoadState S; + LClosure *cl; + if (*name == '@' || *name == '=') + S.name = name + 1; + else if (*name == LUA_SIGNATURE[0]) + S.name = "binary string"; + else + S.name = name; + S.L = L; + S.Z = Z; + checkHeader(&S); + cl = luaF_newLclosure(L, LoadByte(&S)); + setclLvalue(L, L->top, cl); + luaD_inctop(L); + cl->p = luaF_newproto(L); + luaC_objbarrier(L, cl, cl->p); + LoadFunction(&S, cl->p, NULL); + lua_assert(cl->nupvalues == cl->p->sizeupvalues); + luai_verifycode(L, buff, cl->p); + return cl; +} + diff --git a/depends/lua/src/lutf8lib.c b/depends/lua/src/lutf8lib.c new file mode 100644 index 0000000000..10bd238a71 --- /dev/null +++ b/depends/lua/src/lutf8lib.c @@ -0,0 +1,256 @@ +/* +** $Id: lutf8lib.c,v 1.16.1.1 2017/04/19 17:29:57 roberto Exp $ +** Standard library for UTF-8 manipulation +** See Copyright Notice in lua.h +*/ + +#define lutf8lib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include +#include +#include +#include + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + +#define MAXUNICODE 0x10FFFF + +#define iscont(p) ((*(p) & 0xC0) == 0x80) + + +/* from strlib */ +/* translate a relative string position: negative means back from end */ +static lua_Integer u_posrelat (lua_Integer pos, size_t len) { + if (pos >= 0) return pos; + else if (0u - (size_t)pos > len) return 0; + else return (lua_Integer)len + pos + 1; +} + + +/* +** Decode one UTF-8 sequence, returning NULL if byte sequence is invalid. +*/ +static const char *utf8_decode (const char *o, int *val) { + static const unsigned int limits[] = {0xFF, 0x7F, 0x7FF, 0xFFFF}; + const unsigned char *s = (const unsigned char *)o; + unsigned int c = s[0]; + unsigned int res = 0; /* final result */ + if (c < 0x80) /* ascii? */ + res = c; + else { + int count = 0; /* to count number of continuation bytes */ + while (c & 0x40) { /* still have continuation bytes? */ + int cc = s[++count]; /* read next byte */ + if ((cc & 0xC0) != 0x80) /* not a continuation byte? */ + return NULL; /* invalid byte sequence */ + res = (res << 6) | (cc & 0x3F); /* add lower 6 bits from cont. byte */ + c <<= 1; /* to test next bit */ + } + res |= ((c & 0x7F) << (count * 5)); /* add first byte */ + if (count > 3 || res > MAXUNICODE || res <= limits[count]) + return NULL; /* invalid byte sequence */ + s += count; /* skip continuation bytes read */ + } + if (val) *val = res; + return (const char *)s + 1; /* +1 to include first byte */ +} + + +/* +** utf8len(s [, i [, j]]) --> number of characters that start in the +** range [i,j], or nil + current position if 's' is not well formed in +** that interval +*/ +static int utflen (lua_State *L) { + int n = 0; + size_t len; + const char *s = luaL_checklstring(L, 1, &len); + lua_Integer posi = u_posrelat(luaL_optinteger(L, 2, 1), len); + lua_Integer posj = u_posrelat(luaL_optinteger(L, 3, -1), len); + luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 2, + "initial position out of string"); + luaL_argcheck(L, --posj < (lua_Integer)len, 3, + "final position out of string"); + while (posi <= posj) { + const char *s1 = utf8_decode(s + posi, NULL); + if (s1 == NULL) { /* conversion error? */ + lua_pushnil(L); /* return nil ... */ + lua_pushinteger(L, posi + 1); /* ... and current position */ + return 2; + } + posi = s1 - s; + n++; + } + lua_pushinteger(L, n); + return 1; +} + + +/* +** codepoint(s, [i, [j]]) -> returns codepoints for all characters +** that start in the range [i,j] +*/ +static int codepoint (lua_State *L) { + size_t len; + const char *s = luaL_checklstring(L, 1, &len); + lua_Integer posi = u_posrelat(luaL_optinteger(L, 2, 1), len); + lua_Integer pose = u_posrelat(luaL_optinteger(L, 3, posi), len); + int n; + const char *se; + luaL_argcheck(L, posi >= 1, 2, "out of range"); + luaL_argcheck(L, pose <= (lua_Integer)len, 3, "out of range"); + if (posi > pose) return 0; /* empty interval; return no values */ + if (pose - posi >= INT_MAX) /* (lua_Integer -> int) overflow? */ + return luaL_error(L, "string slice too long"); + n = (int)(pose - posi) + 1; + luaL_checkstack(L, n, "string slice too long"); + n = 0; + se = s + pose; + for (s += posi - 1; s < se;) { + int code; + s = utf8_decode(s, &code); + if (s == NULL) + return luaL_error(L, "invalid UTF-8 code"); + lua_pushinteger(L, code); + n++; + } + return n; +} + + +static void pushutfchar (lua_State *L, int arg) { + lua_Integer code = luaL_checkinteger(L, arg); + luaL_argcheck(L, 0 <= code && code <= MAXUNICODE, arg, "value out of range"); + lua_pushfstring(L, "%U", (long)code); +} + + +/* +** utfchar(n1, n2, ...) -> char(n1)..char(n2)... +*/ +static int utfchar (lua_State *L) { + int n = lua_gettop(L); /* number of arguments */ + if (n == 1) /* optimize common case of single char */ + pushutfchar(L, 1); + else { + int i; + luaL_Buffer b; + luaL_buffinit(L, &b); + for (i = 1; i <= n; i++) { + pushutfchar(L, i); + luaL_addvalue(&b); + } + luaL_pushresult(&b); + } + return 1; +} + + +/* +** offset(s, n, [i]) -> index where n-th character counting from +** position 'i' starts; 0 means character at 'i'. +*/ +static int byteoffset (lua_State *L) { + size_t len; + const char *s = luaL_checklstring(L, 1, &len); + lua_Integer n = luaL_checkinteger(L, 2); + lua_Integer posi = (n >= 0) ? 1 : len + 1; + posi = u_posrelat(luaL_optinteger(L, 3, posi), len); + luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 3, + "position out of range"); + if (n == 0) { + /* find beginning of current byte sequence */ + while (posi > 0 && iscont(s + posi)) posi--; + } + else { + if (iscont(s + posi)) + return luaL_error(L, "initial position is a continuation byte"); + if (n < 0) { + while (n < 0 && posi > 0) { /* move back */ + do { /* find beginning of previous character */ + posi--; + } while (posi > 0 && iscont(s + posi)); + n++; + } + } + else { + n--; /* do not move for 1st character */ + while (n > 0 && posi < (lua_Integer)len) { + do { /* find beginning of next character */ + posi++; + } while (iscont(s + posi)); /* (cannot pass final '\0') */ + n--; + } + } + } + if (n == 0) /* did it find given character? */ + lua_pushinteger(L, posi + 1); + else /* no such character */ + lua_pushnil(L); + return 1; +} + + +static int iter_aux (lua_State *L) { + size_t len; + const char *s = luaL_checklstring(L, 1, &len); + lua_Integer n = lua_tointeger(L, 2) - 1; + if (n < 0) /* first iteration? */ + n = 0; /* start from here */ + else if (n < (lua_Integer)len) { + n++; /* skip current byte */ + while (iscont(s + n)) n++; /* and its continuations */ + } + if (n >= (lua_Integer)len) + return 0; /* no more codepoints */ + else { + int code; + const char *next = utf8_decode(s + n, &code); + if (next == NULL || iscont(next)) + return luaL_error(L, "invalid UTF-8 code"); + lua_pushinteger(L, n + 1); + lua_pushinteger(L, code); + return 2; + } +} + + +static int iter_codes (lua_State *L) { + luaL_checkstring(L, 1); + lua_pushcfunction(L, iter_aux); + lua_pushvalue(L, 1); + lua_pushinteger(L, 0); + return 3; +} + + +/* pattern to match a single UTF-8 character */ +#define UTF8PATT "[\0-\x7F\xC2-\xF4][\x80-\xBF]*" + + +static const luaL_Reg funcs[] = { + {"offset", byteoffset}, + {"codepoint", codepoint}, + {"char", utfchar}, + {"len", utflen}, + {"codes", iter_codes}, + /* placeholders */ + {"charpattern", NULL}, + {NULL, NULL} +}; + + +LUAMOD_API int luaopen_utf8 (lua_State *L) { + luaL_newlib(L, funcs); + lua_pushlstring(L, UTF8PATT, sizeof(UTF8PATT)/sizeof(char) - 1); + lua_setfield(L, -2, "charpattern"); + return 1; +} + diff --git a/depends/lua/src/lvm.c b/depends/lua/src/lvm.c new file mode 100644 index 0000000000..cc43d8714d --- /dev/null +++ b/depends/lua/src/lvm.c @@ -0,0 +1,1322 @@ +/* +** $Id: lvm.c,v 2.268.1.1 2017/04/19 17:39:34 roberto Exp $ +** Lua virtual machine +** See Copyright Notice in lua.h +*/ + +#define lvm_c +#define LUA_CORE + +#include "lprefix.h" + +#include +#include +#include +#include +#include +#include + +#include "lua.h" + +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "lgc.h" +#include "lobject.h" +#include "lopcodes.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" +#include "lvm.h" + + +/* limit for table tag-method chains (to avoid loops) */ +#define MAXTAGLOOP 2000 + + + +/* +** 'l_intfitsf' checks whether a given integer can be converted to a +** float without rounding. Used in comparisons. Left undefined if +** all integers fit in a float precisely. +*/ +#if !defined(l_intfitsf) + +/* number of bits in the mantissa of a float */ +#define NBM (l_mathlim(MANT_DIG)) + +/* +** Check whether some integers may not fit in a float, that is, whether +** (maxinteger >> NBM) > 0 (that implies (1 << NBM) <= maxinteger). +** (The shifts are done in parts to avoid shifting by more than the size +** of an integer. In a worst case, NBM == 113 for long double and +** sizeof(integer) == 32.) +*/ +#if ((((LUA_MAXINTEGER >> (NBM / 4)) >> (NBM / 4)) >> (NBM / 4)) \ + >> (NBM - (3 * (NBM / 4)))) > 0 + +#define l_intfitsf(i) \ + (-((lua_Integer)1 << NBM) <= (i) && (i) <= ((lua_Integer)1 << NBM)) + +#endif + +#endif + + + +/* +** Try to convert a value to a float. The float case is already handled +** by the macro 'tonumber'. +*/ +int luaV_tonumber_ (const TValue *obj, lua_Number *n) { + TValue v; + if (ttisinteger(obj)) { + *n = cast_num(ivalue(obj)); + return 1; + } + else if (cvt2num(obj) && /* string convertible to number? */ + luaO_str2num(svalue(obj), &v) == vslen(obj) + 1) { + *n = nvalue(&v); /* convert result of 'luaO_str2num' to a float */ + return 1; + } + else + return 0; /* conversion failed */ +} + + +/* +** try to convert a value to an integer, rounding according to 'mode': +** mode == 0: accepts only integral values +** mode == 1: takes the floor of the number +** mode == 2: takes the ceil of the number +*/ +int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode) { + TValue v; + again: + if (ttisfloat(obj)) { + lua_Number n = fltvalue(obj); + lua_Number f = l_floor(n); + if (n != f) { /* not an integral value? */ + if (mode == 0) return 0; /* fails if mode demands integral value */ + else if (mode > 1) /* needs ceil? */ + f += 1; /* convert floor to ceil (remember: n != f) */ + } + return lua_numbertointeger(f, p); + } + else if (ttisinteger(obj)) { + *p = ivalue(obj); + return 1; + } + else if (cvt2num(obj) && + luaO_str2num(svalue(obj), &v) == vslen(obj) + 1) { + obj = &v; + goto again; /* convert result from 'luaO_str2num' to an integer */ + } + return 0; /* conversion failed */ +} + + +/* +** Try to convert a 'for' limit to an integer, preserving the +** semantics of the loop. +** (The following explanation assumes a non-negative step; it is valid +** for negative steps mutatis mutandis.) +** If the limit can be converted to an integer, rounding down, that is +** it. +** Otherwise, check whether the limit can be converted to a number. If +** the number is too large, it is OK to set the limit as LUA_MAXINTEGER, +** which means no limit. If the number is too negative, the loop +** should not run, because any initial integer value is larger than the +** limit. So, it sets the limit to LUA_MININTEGER. 'stopnow' corrects +** the extreme case when the initial value is LUA_MININTEGER, in which +** case the LUA_MININTEGER limit would still run the loop once. +*/ +static int forlimit (const TValue *obj, lua_Integer *p, lua_Integer step, + int *stopnow) { + *stopnow = 0; /* usually, let loops run */ + if (!luaV_tointeger(obj, p, (step < 0 ? 2 : 1))) { /* not fit in integer? */ + lua_Number n; /* try to convert to float */ + if (!tonumber(obj, &n)) /* cannot convert to float? */ + return 0; /* not a number */ + if (luai_numlt(0, n)) { /* if true, float is larger than max integer */ + *p = LUA_MAXINTEGER; + if (step < 0) *stopnow = 1; + } + else { /* float is smaller than min integer */ + *p = LUA_MININTEGER; + if (step >= 0) *stopnow = 1; + } + } + return 1; +} + + +/* +** Finish the table access 'val = t[key]'. +** if 'slot' is NULL, 't' is not a table; otherwise, 'slot' points to +** t[k] entry (which must be nil). +*/ +void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val, + const TValue *slot) { + int loop; /* counter to avoid infinite loops */ + const TValue *tm; /* metamethod */ + for (loop = 0; loop < MAXTAGLOOP; loop++) { + if (slot == NULL) { /* 't' is not a table? */ + lua_assert(!ttistable(t)); + tm = luaT_gettmbyobj(L, t, TM_INDEX); + if (ttisnil(tm)) + luaG_typeerror(L, t, "index"); /* no metamethod */ + /* else will try the metamethod */ + } + else { /* 't' is a table */ + lua_assert(ttisnil(slot)); + tm = fasttm(L, hvalue(t)->metatable, TM_INDEX); /* table's metamethod */ + if (tm == NULL) { /* no metamethod? */ + setnilvalue(val); /* result is nil */ + return; + } + /* else will try the metamethod */ + } + if (ttisfunction(tm)) { /* is metamethod a function? */ + luaT_callTM(L, tm, t, key, val, 1); /* call it */ + return; + } + t = tm; /* else try to access 'tm[key]' */ + if (luaV_fastget(L,t,key,slot,luaH_get)) { /* fast track? */ + setobj2s(L, val, slot); /* done */ + return; + } + /* else repeat (tail call 'luaV_finishget') */ + } + luaG_runerror(L, "'__index' chain too long; possible loop"); +} + + +/* +** Finish a table assignment 't[key] = val'. +** If 'slot' is NULL, 't' is not a table. Otherwise, 'slot' points +** to the entry 't[key]', or to 'luaO_nilobject' if there is no such +** entry. (The value at 'slot' must be nil, otherwise 'luaV_fastset' +** would have done the job.) +*/ +void luaV_finishset (lua_State *L, const TValue *t, TValue *key, + StkId val, const TValue *slot) { + int loop; /* counter to avoid infinite loops */ + for (loop = 0; loop < MAXTAGLOOP; loop++) { + const TValue *tm; /* '__newindex' metamethod */ + if (slot != NULL) { /* is 't' a table? */ + Table *h = hvalue(t); /* save 't' table */ + lua_assert(ttisnil(slot)); /* old value must be nil */ + tm = fasttm(L, h->metatable, TM_NEWINDEX); /* get metamethod */ + if (tm == NULL) { /* no metamethod? */ + if (slot == luaO_nilobject) /* no previous entry? */ + slot = luaH_newkey(L, h, key); /* create one */ + /* no metamethod and (now) there is an entry with given key */ + setobj2t(L, cast(TValue *, slot), val); /* set its new value */ + invalidateTMcache(h); + luaC_barrierback(L, h, val); + return; + } + /* else will try the metamethod */ + } + else { /* not a table; check metamethod */ + if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) + luaG_typeerror(L, t, "index"); + } + /* try the metamethod */ + if (ttisfunction(tm)) { + luaT_callTM(L, tm, t, key, val, 0); + return; + } + t = tm; /* else repeat assignment over 'tm' */ + if (luaV_fastset(L, t, key, slot, luaH_get, val)) + return; /* done */ + /* else loop */ + } + luaG_runerror(L, "'__newindex' chain too long; possible loop"); +} + + +/* +** Compare two strings 'ls' x 'rs', returning an integer smaller-equal- +** -larger than zero if 'ls' is smaller-equal-larger than 'rs'. +** The code is a little tricky because it allows '\0' in the strings +** and it uses 'strcoll' (to respect locales) for each segments +** of the strings. +*/ +static int l_strcmp (const TString *ls, const TString *rs) { + const char *l = getstr(ls); + size_t ll = tsslen(ls); + const char *r = getstr(rs); + size_t lr = tsslen(rs); + for (;;) { /* for each segment */ + int temp = strcoll(l, r); + if (temp != 0) /* not equal? */ + return temp; /* done */ + else { /* strings are equal up to a '\0' */ + size_t len = strlen(l); /* index of first '\0' in both strings */ + if (len == lr) /* 'rs' is finished? */ + return (len == ll) ? 0 : 1; /* check 'ls' */ + else if (len == ll) /* 'ls' is finished? */ + return -1; /* 'ls' is smaller than 'rs' ('rs' is not finished) */ + /* both strings longer than 'len'; go on comparing after the '\0' */ + len++; + l += len; ll -= len; r += len; lr -= len; + } + } +} + + +/* +** Check whether integer 'i' is less than float 'f'. If 'i' has an +** exact representation as a float ('l_intfitsf'), compare numbers as +** floats. Otherwise, if 'f' is outside the range for integers, result +** is trivial. Otherwise, compare them as integers. (When 'i' has no +** float representation, either 'f' is "far away" from 'i' or 'f' has +** no precision left for a fractional part; either way, how 'f' is +** truncated is irrelevant.) When 'f' is NaN, comparisons must result +** in false. +*/ +static int LTintfloat (lua_Integer i, lua_Number f) { +#if defined(l_intfitsf) + if (!l_intfitsf(i)) { + if (f >= -cast_num(LUA_MININTEGER)) /* -minint == maxint + 1 */ + return 1; /* f >= maxint + 1 > i */ + else if (f > cast_num(LUA_MININTEGER)) /* minint < f <= maxint ? */ + return (i < cast(lua_Integer, f)); /* compare them as integers */ + else /* f <= minint <= i (or 'f' is NaN) --> not(i < f) */ + return 0; + } +#endif + return luai_numlt(cast_num(i), f); /* compare them as floats */ +} + + +/* +** Check whether integer 'i' is less than or equal to float 'f'. +** See comments on previous function. +*/ +static int LEintfloat (lua_Integer i, lua_Number f) { +#if defined(l_intfitsf) + if (!l_intfitsf(i)) { + if (f >= -cast_num(LUA_MININTEGER)) /* -minint == maxint + 1 */ + return 1; /* f >= maxint + 1 > i */ + else if (f >= cast_num(LUA_MININTEGER)) /* minint <= f <= maxint ? */ + return (i <= cast(lua_Integer, f)); /* compare them as integers */ + else /* f < minint <= i (or 'f' is NaN) --> not(i <= f) */ + return 0; + } +#endif + return luai_numle(cast_num(i), f); /* compare them as floats */ +} + + +/* +** Return 'l < r', for numbers. +*/ +static int LTnum (const TValue *l, const TValue *r) { + if (ttisinteger(l)) { + lua_Integer li = ivalue(l); + if (ttisinteger(r)) + return li < ivalue(r); /* both are integers */ + else /* 'l' is int and 'r' is float */ + return LTintfloat(li, fltvalue(r)); /* l < r ? */ + } + else { + lua_Number lf = fltvalue(l); /* 'l' must be float */ + if (ttisfloat(r)) + return luai_numlt(lf, fltvalue(r)); /* both are float */ + else if (luai_numisnan(lf)) /* 'r' is int and 'l' is float */ + return 0; /* NaN < i is always false */ + else /* without NaN, (l < r) <--> not(r <= l) */ + return !LEintfloat(ivalue(r), lf); /* not (r <= l) ? */ + } +} + + +/* +** Return 'l <= r', for numbers. +*/ +static int LEnum (const TValue *l, const TValue *r) { + if (ttisinteger(l)) { + lua_Integer li = ivalue(l); + if (ttisinteger(r)) + return li <= ivalue(r); /* both are integers */ + else /* 'l' is int and 'r' is float */ + return LEintfloat(li, fltvalue(r)); /* l <= r ? */ + } + else { + lua_Number lf = fltvalue(l); /* 'l' must be float */ + if (ttisfloat(r)) + return luai_numle(lf, fltvalue(r)); /* both are float */ + else if (luai_numisnan(lf)) /* 'r' is int and 'l' is float */ + return 0; /* NaN <= i is always false */ + else /* without NaN, (l <= r) <--> not(r < l) */ + return !LTintfloat(ivalue(r), lf); /* not (r < l) ? */ + } +} + + +/* +** Main operation less than; return 'l < r'. +*/ +int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) { + int res; + if (ttisnumber(l) && ttisnumber(r)) /* both operands are numbers? */ + return LTnum(l, r); + else if (ttisstring(l) && ttisstring(r)) /* both are strings? */ + return l_strcmp(tsvalue(l), tsvalue(r)) < 0; + else if ((res = luaT_callorderTM(L, l, r, TM_LT)) < 0) /* no metamethod? */ + luaG_ordererror(L, l, r); /* error */ + return res; +} + + +/* +** Main operation less than or equal to; return 'l <= r'. If it needs +** a metamethod and there is no '__le', try '__lt', based on +** l <= r iff !(r < l) (assuming a total order). If the metamethod +** yields during this substitution, the continuation has to know +** about it (to negate the result of r= 0) /* try 'le' */ + return res; + else { /* try 'lt': */ + L->ci->callstatus |= CIST_LEQ; /* mark it is doing 'lt' for 'le' */ + res = luaT_callorderTM(L, r, l, TM_LT); + L->ci->callstatus ^= CIST_LEQ; /* clear mark */ + if (res < 0) + luaG_ordererror(L, l, r); + return !res; /* result is negated */ + } +} + + +/* +** Main operation for equality of Lua values; return 't1 == t2'. +** L == NULL means raw equality (no metamethods) +*/ +int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) { + const TValue *tm; + if (ttype(t1) != ttype(t2)) { /* not the same variant? */ + if (ttnov(t1) != ttnov(t2) || ttnov(t1) != LUA_TNUMBER) + return 0; /* only numbers can be equal with different variants */ + else { /* two numbers with different variants */ + lua_Integer i1, i2; /* compare them as integers */ + return (tointeger(t1, &i1) && tointeger(t2, &i2) && i1 == i2); + } + } + /* values have same type and same variant */ + switch (ttype(t1)) { + case LUA_TNIL: return 1; + case LUA_TNUMINT: return (ivalue(t1) == ivalue(t2)); + case LUA_TNUMFLT: return luai_numeq(fltvalue(t1), fltvalue(t2)); + case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2); /* true must be 1 !! */ + case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2); + case LUA_TLCF: return fvalue(t1) == fvalue(t2); + case LUA_TSHRSTR: return eqshrstr(tsvalue(t1), tsvalue(t2)); + case LUA_TLNGSTR: return luaS_eqlngstr(tsvalue(t1), tsvalue(t2)); + case LUA_TUSERDATA: { + if (uvalue(t1) == uvalue(t2)) return 1; + else if (L == NULL) return 0; + tm = fasttm(L, uvalue(t1)->metatable, TM_EQ); + if (tm == NULL) + tm = fasttm(L, uvalue(t2)->metatable, TM_EQ); + break; /* will try TM */ + } + case LUA_TTABLE: { + if (hvalue(t1) == hvalue(t2)) return 1; + else if (L == NULL) return 0; + tm = fasttm(L, hvalue(t1)->metatable, TM_EQ); + if (tm == NULL) + tm = fasttm(L, hvalue(t2)->metatable, TM_EQ); + break; /* will try TM */ + } + default: + return gcvalue(t1) == gcvalue(t2); + } + if (tm == NULL) /* no TM? */ + return 0; /* objects are different */ + luaT_callTM(L, tm, t1, t2, L->top, 1); /* call TM */ + return !l_isfalse(L->top); +} + + +/* macro used by 'luaV_concat' to ensure that element at 'o' is a string */ +#define tostring(L,o) \ + (ttisstring(o) || (cvt2str(o) && (luaO_tostring(L, o), 1))) + +#define isemptystr(o) (ttisshrstring(o) && tsvalue(o)->shrlen == 0) + +/* copy strings in stack from top - n up to top - 1 to buffer */ +static void copy2buff (StkId top, int n, char *buff) { + size_t tl = 0; /* size already copied */ + do { + size_t l = vslen(top - n); /* length of string being copied */ + memcpy(buff + tl, svalue(top - n), l * sizeof(char)); + tl += l; + } while (--n > 0); +} + + +/* +** Main operation for concatenation: concat 'total' values in the stack, +** from 'L->top - total' up to 'L->top - 1'. +*/ +void luaV_concat (lua_State *L, int total) { + lua_assert(total >= 2); + do { + StkId top = L->top; + int n = 2; /* number of elements handled in this pass (at least 2) */ + if (!(ttisstring(top-2) || cvt2str(top-2)) || !tostring(L, top-1)) + luaT_trybinTM(L, top-2, top-1, top-2, TM_CONCAT); + else if (isemptystr(top - 1)) /* second operand is empty? */ + cast_void(tostring(L, top - 2)); /* result is first operand */ + else if (isemptystr(top - 2)) { /* first operand is an empty string? */ + setobjs2s(L, top - 2, top - 1); /* result is second op. */ + } + else { + /* at least two non-empty string values; get as many as possible */ + size_t tl = vslen(top - 1); + TString *ts; + /* collect total length and number of strings */ + for (n = 1; n < total && tostring(L, top - n - 1); n++) { + size_t l = vslen(top - n - 1); + if (l >= (MAX_SIZE/sizeof(char)) - tl) + luaG_runerror(L, "string length overflow"); + tl += l; + } + if (tl <= LUAI_MAXSHORTLEN) { /* is result a short string? */ + char buff[LUAI_MAXSHORTLEN]; + copy2buff(top, n, buff); /* copy strings to buffer */ + ts = luaS_newlstr(L, buff, tl); + } + else { /* long string; copy strings directly to final result */ + ts = luaS_createlngstrobj(L, tl); + copy2buff(top, n, getstr(ts)); + } + setsvalue2s(L, top - n, ts); /* create result */ + } + total -= n-1; /* got 'n' strings to create 1 new */ + L->top -= n-1; /* popped 'n' strings and pushed one */ + } while (total > 1); /* repeat until only 1 result left */ +} + + +/* +** Main operation 'ra' = #rb'. +*/ +void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) { + const TValue *tm; + switch (ttype(rb)) { + case LUA_TTABLE: { + Table *h = hvalue(rb); + tm = fasttm(L, h->metatable, TM_LEN); + if (tm) break; /* metamethod? break switch to call it */ + setivalue(ra, luaH_getn(h)); /* else primitive len */ + return; + } + case LUA_TSHRSTR: { + setivalue(ra, tsvalue(rb)->shrlen); + return; + } + case LUA_TLNGSTR: { + setivalue(ra, tsvalue(rb)->u.lnglen); + return; + } + default: { /* try metamethod */ + tm = luaT_gettmbyobj(L, rb, TM_LEN); + if (ttisnil(tm)) /* no metamethod? */ + luaG_typeerror(L, rb, "get length of"); + break; + } + } + luaT_callTM(L, tm, rb, rb, ra, 1); +} + + +/* +** Integer division; return 'm // n', that is, floor(m/n). +** C division truncates its result (rounds towards zero). +** 'floor(q) == trunc(q)' when 'q >= 0' or when 'q' is integer, +** otherwise 'floor(q) == trunc(q) - 1'. +*/ +lua_Integer luaV_div (lua_State *L, lua_Integer m, lua_Integer n) { + if (l_castS2U(n) + 1u <= 1u) { /* special cases: -1 or 0 */ + if (n == 0) + luaG_runerror(L, "attempt to divide by zero"); + return intop(-, 0, m); /* n==-1; avoid overflow with 0x80000...//-1 */ + } + else { + lua_Integer q = m / n; /* perform C division */ + if ((m ^ n) < 0 && m % n != 0) /* 'm/n' would be negative non-integer? */ + q -= 1; /* correct result for different rounding */ + return q; + } +} + + +/* +** Integer modulus; return 'm % n'. (Assume that C '%' with +** negative operands follows C99 behavior. See previous comment +** about luaV_div.) +*/ +lua_Integer luaV_mod (lua_State *L, lua_Integer m, lua_Integer n) { + if (l_castS2U(n) + 1u <= 1u) { /* special cases: -1 or 0 */ + if (n == 0) + luaG_runerror(L, "attempt to perform 'n%%0'"); + return 0; /* m % -1 == 0; avoid overflow with 0x80000...%-1 */ + } + else { + lua_Integer r = m % n; + if (r != 0 && (m ^ n) < 0) /* 'm/n' would be non-integer negative? */ + r += n; /* correct result for different rounding */ + return r; + } +} + + +/* number of bits in an integer */ +#define NBITS cast_int(sizeof(lua_Integer) * CHAR_BIT) + +/* +** Shift left operation. (Shift right just negates 'y'.) +*/ +lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y) { + if (y < 0) { /* shift right? */ + if (y <= -NBITS) return 0; + else return intop(>>, x, -y); + } + else { /* shift left */ + if (y >= NBITS) return 0; + else return intop(<<, x, y); + } +} + + +/* +** check whether cached closure in prototype 'p' may be reused, that is, +** whether there is a cached closure with the same upvalues needed by +** new closure to be created. +*/ +static LClosure *getcached (Proto *p, UpVal **encup, StkId base) { + LClosure *c = p->cache; + if (c != NULL) { /* is there a cached closure? */ + int nup = p->sizeupvalues; + Upvaldesc *uv = p->upvalues; + int i; + for (i = 0; i < nup; i++) { /* check whether it has right upvalues */ + TValue *v = uv[i].instack ? base + uv[i].idx : encup[uv[i].idx]->v; + if (c->upvals[i]->v != v) + return NULL; /* wrong upvalue; cannot reuse closure */ + } + } + return c; /* return cached closure (or NULL if no cached closure) */ +} + + +/* +** create a new Lua closure, push it in the stack, and initialize +** its upvalues. Note that the closure is not cached if prototype is +** already black (which means that 'cache' was already cleared by the +** GC). +*/ +static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base, + StkId ra) { + int nup = p->sizeupvalues; + Upvaldesc *uv = p->upvalues; + int i; + LClosure *ncl = luaF_newLclosure(L, nup); + ncl->p = p; + setclLvalue(L, ra, ncl); /* anchor new closure in stack */ + for (i = 0; i < nup; i++) { /* fill in its upvalues */ + if (uv[i].instack) /* upvalue refers to local variable? */ + ncl->upvals[i] = luaF_findupval(L, base + uv[i].idx); + else /* get upvalue from enclosing function */ + ncl->upvals[i] = encup[uv[i].idx]; + ncl->upvals[i]->refcount++; + /* new closure is white, so we do not need a barrier here */ + } + if (!isblack(p)) /* cache will not break GC invariant? */ + p->cache = ncl; /* save it on cache for reuse */ +} + + +/* +** finish execution of an opcode interrupted by an yield +*/ +void luaV_finishOp (lua_State *L) { + CallInfo *ci = L->ci; + StkId base = ci->u.l.base; + Instruction inst = *(ci->u.l.savedpc - 1); /* interrupted instruction */ + OpCode op = GET_OPCODE(inst); + switch (op) { /* finish its execution */ + case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: case OP_IDIV: + case OP_BAND: case OP_BOR: case OP_BXOR: case OP_SHL: case OP_SHR: + case OP_MOD: case OP_POW: + case OP_UNM: case OP_BNOT: case OP_LEN: + case OP_GETTABUP: case OP_GETTABLE: case OP_SELF: { + setobjs2s(L, base + GETARG_A(inst), --L->top); + break; + } + case OP_LE: case OP_LT: case OP_EQ: { + int res = !l_isfalse(L->top - 1); + L->top--; + if (ci->callstatus & CIST_LEQ) { /* "<=" using "<" instead? */ + lua_assert(op == OP_LE); + ci->callstatus ^= CIST_LEQ; /* clear mark */ + res = !res; /* negate result */ + } + lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_JMP); + if (res != GETARG_A(inst)) /* condition failed? */ + ci->u.l.savedpc++; /* skip jump instruction */ + break; + } + case OP_CONCAT: { + StkId top = L->top - 1; /* top when 'luaT_trybinTM' was called */ + int b = GETARG_B(inst); /* first element to concatenate */ + int total = cast_int(top - 1 - (base + b)); /* yet to concatenate */ + setobj2s(L, top - 2, top); /* put TM result in proper position */ + if (total > 1) { /* are there elements to concat? */ + L->top = top - 1; /* top is one after last element (at top-2) */ + luaV_concat(L, total); /* concat them (may yield again) */ + } + /* move final result to final position */ + setobj2s(L, ci->u.l.base + GETARG_A(inst), L->top - 1); + L->top = ci->top; /* restore top */ + break; + } + case OP_TFORCALL: { + lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_TFORLOOP); + L->top = ci->top; /* correct top */ + break; + } + case OP_CALL: { + if (GETARG_C(inst) - 1 >= 0) /* nresults >= 0? */ + L->top = ci->top; /* adjust results */ + break; + } + case OP_TAILCALL: case OP_SETTABUP: case OP_SETTABLE: + break; + default: lua_assert(0); + } +} + + + + +/* +** {================================================================== +** Function 'luaV_execute': main interpreter loop +** =================================================================== +*/ + + +/* +** some macros for common tasks in 'luaV_execute' +*/ + + +#define RA(i) (base+GETARG_A(i)) +#define RB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgR, base+GETARG_B(i)) +#define RC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgR, base+GETARG_C(i)) +#define RKB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgK, \ + ISK(GETARG_B(i)) ? k+INDEXK(GETARG_B(i)) : base+GETARG_B(i)) +#define RKC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgK, \ + ISK(GETARG_C(i)) ? k+INDEXK(GETARG_C(i)) : base+GETARG_C(i)) + + +/* execute a jump instruction */ +#define dojump(ci,i,e) \ + { int a = GETARG_A(i); \ + if (a != 0) luaF_close(L, ci->u.l.base + a - 1); \ + ci->u.l.savedpc += GETARG_sBx(i) + e; } + +/* for test instructions, execute the jump instruction that follows it */ +#define donextjump(ci) { i = *ci->u.l.savedpc; dojump(ci, i, 1); } + + +#define Protect(x) { {x;}; base = ci->u.l.base; } + +#define checkGC(L,c) \ + { luaC_condGC(L, L->top = (c), /* limit of live values */ \ + Protect(L->top = ci->top)); /* restore top */ \ + luai_threadyield(L); } + + +/* fetch an instruction and prepare its execution */ +#define vmfetch() { \ + i = *(ci->u.l.savedpc++); \ + if (L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) \ + Protect(luaG_traceexec(L)); \ + ra = RA(i); /* WARNING: any stack reallocation invalidates 'ra' */ \ + lua_assert(base == ci->u.l.base); \ + lua_assert(base <= L->top && L->top < L->stack + L->stacksize); \ +} + +#define vmdispatch(o) switch(o) +#define vmcase(l) case l: +#define vmbreak break + + +/* +** copy of 'luaV_gettable', but protecting the call to potential +** metamethod (which can reallocate the stack) +*/ +#define gettableProtected(L,t,k,v) { const TValue *slot; \ + if (luaV_fastget(L,t,k,slot,luaH_get)) { setobj2s(L, v, slot); } \ + else Protect(luaV_finishget(L,t,k,v,slot)); } + + +/* same for 'luaV_settable' */ +#define settableProtected(L,t,k,v) { const TValue *slot; \ + if (!luaV_fastset(L,t,k,slot,luaH_get,v)) \ + Protect(luaV_finishset(L,t,k,v,slot)); } + + + +void luaV_execute (lua_State *L) { + CallInfo *ci = L->ci; + LClosure *cl; + TValue *k; + StkId base; + ci->callstatus |= CIST_FRESH; /* fresh invocation of 'luaV_execute" */ + newframe: /* reentry point when frame changes (call/return) */ + lua_assert(ci == L->ci); + cl = clLvalue(ci->func); /* local reference to function's closure */ + k = cl->p->k; /* local reference to function's constant table */ + base = ci->u.l.base; /* local copy of function's base */ + /* main loop of interpreter */ + for (;;) { + Instruction i; + StkId ra; + vmfetch(); + vmdispatch (GET_OPCODE(i)) { + vmcase(OP_MOVE) { + setobjs2s(L, ra, RB(i)); + vmbreak; + } + vmcase(OP_LOADK) { + TValue *rb = k + GETARG_Bx(i); + setobj2s(L, ra, rb); + vmbreak; + } + vmcase(OP_LOADKX) { + TValue *rb; + lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_EXTRAARG); + rb = k + GETARG_Ax(*ci->u.l.savedpc++); + setobj2s(L, ra, rb); + vmbreak; + } + vmcase(OP_LOADBOOL) { + setbvalue(ra, GETARG_B(i)); + if (GETARG_C(i)) ci->u.l.savedpc++; /* skip next instruction (if C) */ + vmbreak; + } + vmcase(OP_LOADNIL) { + int b = GETARG_B(i); + do { + setnilvalue(ra++); + } while (b--); + vmbreak; + } + vmcase(OP_GETUPVAL) { + int b = GETARG_B(i); + setobj2s(L, ra, cl->upvals[b]->v); + vmbreak; + } + vmcase(OP_GETTABUP) { + TValue *upval = cl->upvals[GETARG_B(i)]->v; + TValue *rc = RKC(i); + gettableProtected(L, upval, rc, ra); + vmbreak; + } + vmcase(OP_GETTABLE) { + StkId rb = RB(i); + TValue *rc = RKC(i); + gettableProtected(L, rb, rc, ra); + vmbreak; + } + vmcase(OP_SETTABUP) { + TValue *upval = cl->upvals[GETARG_A(i)]->v; + TValue *rb = RKB(i); + TValue *rc = RKC(i); + settableProtected(L, upval, rb, rc); + vmbreak; + } + vmcase(OP_SETUPVAL) { + UpVal *uv = cl->upvals[GETARG_B(i)]; + setobj(L, uv->v, ra); + luaC_upvalbarrier(L, uv); + vmbreak; + } + vmcase(OP_SETTABLE) { + TValue *rb = RKB(i); + TValue *rc = RKC(i); + settableProtected(L, ra, rb, rc); + vmbreak; + } + vmcase(OP_NEWTABLE) { + int b = GETARG_B(i); + int c = GETARG_C(i); + Table *t = luaH_new(L); + sethvalue(L, ra, t); + if (b != 0 || c != 0) + luaH_resize(L, t, luaO_fb2int(b), luaO_fb2int(c)); + checkGC(L, ra + 1); + vmbreak; + } + vmcase(OP_SELF) { + const TValue *aux; + StkId rb = RB(i); + TValue *rc = RKC(i); + TString *key = tsvalue(rc); /* key must be a string */ + setobjs2s(L, ra + 1, rb); + if (luaV_fastget(L, rb, key, aux, luaH_getstr)) { + setobj2s(L, ra, aux); + } + else Protect(luaV_finishget(L, rb, rc, ra, aux)); + vmbreak; + } + vmcase(OP_ADD) { + TValue *rb = RKB(i); + TValue *rc = RKC(i); + lua_Number nb; lua_Number nc; + if (ttisinteger(rb) && ttisinteger(rc)) { + lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); + setivalue(ra, intop(+, ib, ic)); + } + else if (tonumber(rb, &nb) && tonumber(rc, &nc)) { + setfltvalue(ra, luai_numadd(L, nb, nc)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_ADD)); } + vmbreak; + } + vmcase(OP_SUB) { + TValue *rb = RKB(i); + TValue *rc = RKC(i); + lua_Number nb; lua_Number nc; + if (ttisinteger(rb) && ttisinteger(rc)) { + lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); + setivalue(ra, intop(-, ib, ic)); + } + else if (tonumber(rb, &nb) && tonumber(rc, &nc)) { + setfltvalue(ra, luai_numsub(L, nb, nc)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_SUB)); } + vmbreak; + } + vmcase(OP_MUL) { + TValue *rb = RKB(i); + TValue *rc = RKC(i); + lua_Number nb; lua_Number nc; + if (ttisinteger(rb) && ttisinteger(rc)) { + lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); + setivalue(ra, intop(*, ib, ic)); + } + else if (tonumber(rb, &nb) && tonumber(rc, &nc)) { + setfltvalue(ra, luai_nummul(L, nb, nc)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_MUL)); } + vmbreak; + } + vmcase(OP_DIV) { /* float division (always with floats) */ + TValue *rb = RKB(i); + TValue *rc = RKC(i); + lua_Number nb; lua_Number nc; + if (tonumber(rb, &nb) && tonumber(rc, &nc)) { + setfltvalue(ra, luai_numdiv(L, nb, nc)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_DIV)); } + vmbreak; + } + vmcase(OP_BAND) { + TValue *rb = RKB(i); + TValue *rc = RKC(i); + lua_Integer ib; lua_Integer ic; + if (tointeger(rb, &ib) && tointeger(rc, &ic)) { + setivalue(ra, intop(&, ib, ic)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_BAND)); } + vmbreak; + } + vmcase(OP_BOR) { + TValue *rb = RKB(i); + TValue *rc = RKC(i); + lua_Integer ib; lua_Integer ic; + if (tointeger(rb, &ib) && tointeger(rc, &ic)) { + setivalue(ra, intop(|, ib, ic)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_BOR)); } + vmbreak; + } + vmcase(OP_BXOR) { + TValue *rb = RKB(i); + TValue *rc = RKC(i); + lua_Integer ib; lua_Integer ic; + if (tointeger(rb, &ib) && tointeger(rc, &ic)) { + setivalue(ra, intop(^, ib, ic)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_BXOR)); } + vmbreak; + } + vmcase(OP_SHL) { + TValue *rb = RKB(i); + TValue *rc = RKC(i); + lua_Integer ib; lua_Integer ic; + if (tointeger(rb, &ib) && tointeger(rc, &ic)) { + setivalue(ra, luaV_shiftl(ib, ic)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_SHL)); } + vmbreak; + } + vmcase(OP_SHR) { + TValue *rb = RKB(i); + TValue *rc = RKC(i); + lua_Integer ib; lua_Integer ic; + if (tointeger(rb, &ib) && tointeger(rc, &ic)) { + setivalue(ra, luaV_shiftl(ib, -ic)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_SHR)); } + vmbreak; + } + vmcase(OP_MOD) { + TValue *rb = RKB(i); + TValue *rc = RKC(i); + lua_Number nb; lua_Number nc; + if (ttisinteger(rb) && ttisinteger(rc)) { + lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); + setivalue(ra, luaV_mod(L, ib, ic)); + } + else if (tonumber(rb, &nb) && tonumber(rc, &nc)) { + lua_Number m; + luai_nummod(L, nb, nc, m); + setfltvalue(ra, m); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_MOD)); } + vmbreak; + } + vmcase(OP_IDIV) { /* floor division */ + TValue *rb = RKB(i); + TValue *rc = RKC(i); + lua_Number nb; lua_Number nc; + if (ttisinteger(rb) && ttisinteger(rc)) { + lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); + setivalue(ra, luaV_div(L, ib, ic)); + } + else if (tonumber(rb, &nb) && tonumber(rc, &nc)) { + setfltvalue(ra, luai_numidiv(L, nb, nc)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_IDIV)); } + vmbreak; + } + vmcase(OP_POW) { + TValue *rb = RKB(i); + TValue *rc = RKC(i); + lua_Number nb; lua_Number nc; + if (tonumber(rb, &nb) && tonumber(rc, &nc)) { + setfltvalue(ra, luai_numpow(L, nb, nc)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_POW)); } + vmbreak; + } + vmcase(OP_UNM) { + TValue *rb = RB(i); + lua_Number nb; + if (ttisinteger(rb)) { + lua_Integer ib = ivalue(rb); + setivalue(ra, intop(-, 0, ib)); + } + else if (tonumber(rb, &nb)) { + setfltvalue(ra, luai_numunm(L, nb)); + } + else { + Protect(luaT_trybinTM(L, rb, rb, ra, TM_UNM)); + } + vmbreak; + } + vmcase(OP_BNOT) { + TValue *rb = RB(i); + lua_Integer ib; + if (tointeger(rb, &ib)) { + setivalue(ra, intop(^, ~l_castS2U(0), ib)); + } + else { + Protect(luaT_trybinTM(L, rb, rb, ra, TM_BNOT)); + } + vmbreak; + } + vmcase(OP_NOT) { + TValue *rb = RB(i); + int res = l_isfalse(rb); /* next assignment may change this value */ + setbvalue(ra, res); + vmbreak; + } + vmcase(OP_LEN) { + Protect(luaV_objlen(L, ra, RB(i))); + vmbreak; + } + vmcase(OP_CONCAT) { + int b = GETARG_B(i); + int c = GETARG_C(i); + StkId rb; + L->top = base + c + 1; /* mark the end of concat operands */ + Protect(luaV_concat(L, c - b + 1)); + ra = RA(i); /* 'luaV_concat' may invoke TMs and move the stack */ + rb = base + b; + setobjs2s(L, ra, rb); + checkGC(L, (ra >= rb ? ra + 1 : rb)); + L->top = ci->top; /* restore top */ + vmbreak; + } + vmcase(OP_JMP) { + dojump(ci, i, 0); + vmbreak; + } + vmcase(OP_EQ) { + TValue *rb = RKB(i); + TValue *rc = RKC(i); + Protect( + if (luaV_equalobj(L, rb, rc) != GETARG_A(i)) + ci->u.l.savedpc++; + else + donextjump(ci); + ) + vmbreak; + } + vmcase(OP_LT) { + Protect( + if (luaV_lessthan(L, RKB(i), RKC(i)) != GETARG_A(i)) + ci->u.l.savedpc++; + else + donextjump(ci); + ) + vmbreak; + } + vmcase(OP_LE) { + Protect( + if (luaV_lessequal(L, RKB(i), RKC(i)) != GETARG_A(i)) + ci->u.l.savedpc++; + else + donextjump(ci); + ) + vmbreak; + } + vmcase(OP_TEST) { + if (GETARG_C(i) ? l_isfalse(ra) : !l_isfalse(ra)) + ci->u.l.savedpc++; + else + donextjump(ci); + vmbreak; + } + vmcase(OP_TESTSET) { + TValue *rb = RB(i); + if (GETARG_C(i) ? l_isfalse(rb) : !l_isfalse(rb)) + ci->u.l.savedpc++; + else { + setobjs2s(L, ra, rb); + donextjump(ci); + } + vmbreak; + } + vmcase(OP_CALL) { + int b = GETARG_B(i); + int nresults = GETARG_C(i) - 1; + if (b != 0) L->top = ra+b; /* else previous instruction set top */ + if (luaD_precall(L, ra, nresults)) { /* C function? */ + if (nresults >= 0) + L->top = ci->top; /* adjust results */ + Protect((void)0); /* update 'base' */ + } + else { /* Lua function */ + ci = L->ci; + goto newframe; /* restart luaV_execute over new Lua function */ + } + vmbreak; + } + vmcase(OP_TAILCALL) { + int b = GETARG_B(i); + if (b != 0) L->top = ra+b; /* else previous instruction set top */ + lua_assert(GETARG_C(i) - 1 == LUA_MULTRET); + if (luaD_precall(L, ra, LUA_MULTRET)) { /* C function? */ + Protect((void)0); /* update 'base' */ + } + else { + /* tail call: put called frame (n) in place of caller one (o) */ + CallInfo *nci = L->ci; /* called frame */ + CallInfo *oci = nci->previous; /* caller frame */ + StkId nfunc = nci->func; /* called function */ + StkId ofunc = oci->func; /* caller function */ + /* last stack slot filled by 'precall' */ + StkId lim = nci->u.l.base + getproto(nfunc)->numparams; + int aux; + /* close all upvalues from previous call */ + if (cl->p->sizep > 0) luaF_close(L, oci->u.l.base); + /* move new frame into old one */ + for (aux = 0; nfunc + aux < lim; aux++) + setobjs2s(L, ofunc + aux, nfunc + aux); + oci->u.l.base = ofunc + (nci->u.l.base - nfunc); /* correct base */ + oci->top = L->top = ofunc + (L->top - nfunc); /* correct top */ + oci->u.l.savedpc = nci->u.l.savedpc; + oci->callstatus |= CIST_TAIL; /* function was tail called */ + ci = L->ci = oci; /* remove new frame */ + lua_assert(L->top == oci->u.l.base + getproto(ofunc)->maxstacksize); + goto newframe; /* restart luaV_execute over new Lua function */ + } + vmbreak; + } + vmcase(OP_RETURN) { + int b = GETARG_B(i); + if (cl->p->sizep > 0) luaF_close(L, base); + b = luaD_poscall(L, ci, ra, (b != 0 ? b - 1 : cast_int(L->top - ra))); + if (ci->callstatus & CIST_FRESH) /* local 'ci' still from callee */ + return; /* external invocation: return */ + else { /* invocation via reentry: continue execution */ + ci = L->ci; + if (b) L->top = ci->top; + lua_assert(isLua(ci)); + lua_assert(GET_OPCODE(*((ci)->u.l.savedpc - 1)) == OP_CALL); + goto newframe; /* restart luaV_execute over new Lua function */ + } + } + vmcase(OP_FORLOOP) { + if (ttisinteger(ra)) { /* integer loop? */ + lua_Integer step = ivalue(ra + 2); + lua_Integer idx = intop(+, ivalue(ra), step); /* increment index */ + lua_Integer limit = ivalue(ra + 1); + if ((0 < step) ? (idx <= limit) : (limit <= idx)) { + ci->u.l.savedpc += GETARG_sBx(i); /* jump back */ + chgivalue(ra, idx); /* update internal index... */ + setivalue(ra + 3, idx); /* ...and external index */ + } + } + else { /* floating loop */ + lua_Number step = fltvalue(ra + 2); + lua_Number idx = luai_numadd(L, fltvalue(ra), step); /* inc. index */ + lua_Number limit = fltvalue(ra + 1); + if (luai_numlt(0, step) ? luai_numle(idx, limit) + : luai_numle(limit, idx)) { + ci->u.l.savedpc += GETARG_sBx(i); /* jump back */ + chgfltvalue(ra, idx); /* update internal index... */ + setfltvalue(ra + 3, idx); /* ...and external index */ + } + } + vmbreak; + } + vmcase(OP_FORPREP) { + TValue *init = ra; + TValue *plimit = ra + 1; + TValue *pstep = ra + 2; + lua_Integer ilimit; + int stopnow; + if (ttisinteger(init) && ttisinteger(pstep) && + forlimit(plimit, &ilimit, ivalue(pstep), &stopnow)) { + /* all values are integer */ + lua_Integer initv = (stopnow ? 0 : ivalue(init)); + setivalue(plimit, ilimit); + setivalue(init, intop(-, initv, ivalue(pstep))); + } + else { /* try making all values floats */ + lua_Number ninit; lua_Number nlimit; lua_Number nstep; + if (!tonumber(plimit, &nlimit)) + luaG_runerror(L, "'for' limit must be a number"); + setfltvalue(plimit, nlimit); + if (!tonumber(pstep, &nstep)) + luaG_runerror(L, "'for' step must be a number"); + setfltvalue(pstep, nstep); + if (!tonumber(init, &ninit)) + luaG_runerror(L, "'for' initial value must be a number"); + setfltvalue(init, luai_numsub(L, ninit, nstep)); + } + ci->u.l.savedpc += GETARG_sBx(i); + vmbreak; + } + vmcase(OP_TFORCALL) { + StkId cb = ra + 3; /* call base */ + setobjs2s(L, cb+2, ra+2); + setobjs2s(L, cb+1, ra+1); + setobjs2s(L, cb, ra); + L->top = cb + 3; /* func. + 2 args (state and index) */ + Protect(luaD_call(L, cb, GETARG_C(i))); + L->top = ci->top; + i = *(ci->u.l.savedpc++); /* go to next instruction */ + ra = RA(i); + lua_assert(GET_OPCODE(i) == OP_TFORLOOP); + goto l_tforloop; + } + vmcase(OP_TFORLOOP) { + l_tforloop: + if (!ttisnil(ra + 1)) { /* continue loop? */ + setobjs2s(L, ra, ra + 1); /* save control variable */ + ci->u.l.savedpc += GETARG_sBx(i); /* jump back */ + } + vmbreak; + } + vmcase(OP_SETLIST) { + int n = GETARG_B(i); + int c = GETARG_C(i); + unsigned int last; + Table *h; + if (n == 0) n = cast_int(L->top - ra) - 1; + if (c == 0) { + lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_EXTRAARG); + c = GETARG_Ax(*ci->u.l.savedpc++); + } + h = hvalue(ra); + last = ((c-1)*LFIELDS_PER_FLUSH) + n; + if (last > h->sizearray) /* needs more space? */ + luaH_resizearray(L, h, last); /* preallocate it at once */ + for (; n > 0; n--) { + TValue *val = ra+n; + luaH_setint(L, h, last--, val); + luaC_barrierback(L, h, val); + } + L->top = ci->top; /* correct top (in case of previous open call) */ + vmbreak; + } + vmcase(OP_CLOSURE) { + Proto *p = cl->p->p[GETARG_Bx(i)]; + LClosure *ncl = getcached(p, cl->upvals, base); /* cached closure */ + if (ncl == NULL) /* no match? */ + pushclosure(L, p, cl->upvals, base, ra); /* create a new one */ + else + setclLvalue(L, ra, ncl); /* push cashed closure */ + checkGC(L, ra + 1); + vmbreak; + } + vmcase(OP_VARARG) { + int b = GETARG_B(i) - 1; /* required results */ + int j; + int n = cast_int(base - ci->func) - cl->p->numparams - 1; + if (n < 0) /* less arguments than parameters? */ + n = 0; /* no vararg arguments */ + if (b < 0) { /* B == 0? */ + b = n; /* get all var. arguments */ + Protect(luaD_checkstack(L, n)); + ra = RA(i); /* previous call may change the stack */ + L->top = ra + n; + } + for (j = 0; j < b && j < n; j++) + setobjs2s(L, ra + j, base - n + j); + for (; j < b; j++) /* complete required results with nil */ + setnilvalue(ra + j); + vmbreak; + } + vmcase(OP_EXTRAARG) { + lua_assert(0); + vmbreak; + } + } + } +} + +/* }================================================================== */ + diff --git a/depends/lua/src/lzio.c b/depends/lua/src/lzio.c new file mode 100644 index 0000000000..6f79094410 --- /dev/null +++ b/depends/lua/src/lzio.c @@ -0,0 +1,68 @@ +/* +** $Id: lzio.c,v 1.37.1.1 2017/04/19 17:20:42 roberto Exp $ +** Buffered streams +** See Copyright Notice in lua.h +*/ + +#define lzio_c +#define LUA_CORE + +#include "lprefix.h" + + +#include + +#include "lua.h" + +#include "llimits.h" +#include "lmem.h" +#include "lstate.h" +#include "lzio.h" + + +int luaZ_fill (ZIO *z) { + size_t size; + lua_State *L = z->L; + const char *buff; + lua_unlock(L); + buff = z->reader(L, z->data, &size); + lua_lock(L); + if (buff == NULL || size == 0) + return EOZ; + z->n = size - 1; /* discount char being returned */ + z->p = buff; + return cast_uchar(*(z->p++)); +} + + +void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, void *data) { + z->L = L; + z->reader = reader; + z->data = data; + z->n = 0; + z->p = NULL; +} + + +/* --------------------------------------------------------------- read --- */ +size_t luaZ_read (ZIO *z, void *b, size_t n) { + while (n) { + size_t m; + if (z->n == 0) { /* no bytes in buffer? */ + if (luaZ_fill(z) == EOZ) /* try to read more */ + return n; /* no more input; return number of missing bytes */ + else { + z->n++; /* luaZ_fill consumed first byte; put it back */ + z->p--; + } + } + m = (n <= z->n) ? n : z->n; /* min. between n and z->n */ + memcpy(b, z->p, m); + z->n -= m; + z->p += m; + b = (char *)b + m; + n -= m; + } + return 0; +} + diff --git a/depends/luacov b/depends/luacov new file mode 160000 index 0000000000..e09ee3fa2e --- /dev/null +++ b/depends/luacov @@ -0,0 +1 @@ +Subproject commit e09ee3fa2e3366d148f94c6a5969c9896126e83a diff --git a/depends/md5/CMakeLists.txt b/depends/md5/CMakeLists.txt new file mode 100644 index 0000000000..55c0bf6c1b --- /dev/null +++ b/depends/md5/CMakeLists.txt @@ -0,0 +1,7 @@ +project(dfhack-md5) +add_library(dfhack-md5 STATIC EXCLUDE_FROM_ALL md5.cpp md5wrapper.cpp) +target_include_directories(dfhack-md5 INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) +ide_folder(dfhack-md5 "Depends") +if(UNIX) + set_target_properties(dfhack-md5 PROPERTIES COMPILE_FLAGS "-Wno-strict-aliasing") +endif() diff --git a/depends/md5/md5.cpp b/depends/md5/md5.cpp new file mode 100644 index 0000000000..8aa9ba38c8 --- /dev/null +++ b/depends/md5/md5.cpp @@ -0,0 +1,240 @@ +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + */ + +#include +#include "md5.h" + +#ifndef HIGHFIRST +#define byteReverse(buf, len) /* Nothing */ +#else +/* + * Note: this code is harmless on little-endian machines. + */ +void byteReverse(unsigned char *buf, unsigned longs) +{ + uint32_t t; + do + { + t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 | + ((unsigned) buf[1] << 8 | buf[0]); + *(uint32_t *) buf = t; + buf += 4; + } while (--longs); +} +#endif + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void MD5Init(MD5Context *ctx) +{ + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bits[0] = 0; + ctx->bits[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void MD5Update( MD5Context *ctx, unsigned char *buf, unsigned len) +{ + uint32_t t; + + /* Update bitcount */ + + t = ctx->bits[0]; + if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t) + ctx->bits[1]++; /* Carry from low to high */ + ctx->bits[1] += len >> 29; + + t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ + + /* Handle any leading odd-sized chunks */ + if (t) + { + unsigned char *p = (unsigned char *) ctx->in + t; + + t = 64 - t; + if (len < t) + { + memcpy(p, buf, len); + return; + } + memcpy(p, buf, t); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (uint32_t *) ctx->in); + buf += t; + len -= t; + } + /* Process data in 64-byte chunks */ + while (len >= 64) + { + memcpy(ctx->in, buf, 64); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (uint32_t *) ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +void MD5Final(unsigned char digest[16], MD5Context *ctx) +{ + unsigned count; + unsigned char *p; + + /* Compute number of bytes mod 64 */ + count = (ctx->bits[0] >> 3) & 0x3F; + + /* Set the first char of padding to 0x80. This is safe since there is + always at least one byte free */ + p = ctx->in + count; + *p++ = 0x80; + + /* Bytes of padding needed to make 64 bytes */ + count = 64 - 1 - count; + + /* Pad out to 56 mod 64 */ + if (count < 8) + { + /* Two lots of padding: Pad the first block to 64 bytes */ + memset(p, 0, count); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (uint32_t *) ctx->in); + + /* Now fill the next block with 56 bytes */ + memset(ctx->in, 0, 56); + } + else + { + /* Pad block to 56 bytes */ + memset(p, 0, count - 8); + } + byteReverse(ctx->in, 14); + + /* Append length in bits and transform */ + ((uint32_t *) ctx->in)[14] = ctx->bits[0]; + ((uint32_t *) ctx->in)[15] = ctx->bits[1]; + + MD5Transform(ctx->buf, (uint32_t *) ctx->in); + byteReverse((unsigned char *) ctx->buf, 4); + memcpy(digest, ctx->buf, 16); + memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */ +} + + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f, w, x, y, z, data, s) \ + ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +void MD5Transform(uint32_t buf[4], uint32_t in[16]) +{ + uint32_t a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} diff --git a/depends/md5/md5.h b/depends/md5/md5.h new file mode 100644 index 0000000000..0a04051bbe --- /dev/null +++ b/depends/md5/md5.h @@ -0,0 +1,36 @@ +#pragma once + +/* The following tests optimise behaviour on little-endian + machines, where there is no need to reverse the byte order + of 32 bit words in the MD5 computation. By default, + HIGHFIRST is defined, which indicates we're running on a + big-endian (most significant byte first) machine, on which + the byteReverse function in md5.c must be invoked. However, + byteReverse is coded in such a way that it is an identity + function when run on a little-endian machine, so calling it + on such a platform causes no harm apart from wasting time. + If the platform is known to be little-endian, we speed + things up by undefining HIGHFIRST, which defines + byteReverse as a null macro. Doing things in this manner + insures we work on new platforms regardless of their byte + order. */ + +#define HIGHFIRST + +#ifdef __i386__ +#undef HIGHFIRST +#endif + +#include + +struct MD5Context +{ + uint32_t buf[4]; + uint32_t bits[2]; + unsigned char in[64]; +}; + +extern void MD5Init( MD5Context *ctx); +extern void MD5Update( MD5Context *ctx, unsigned char *buf, unsigned len); +extern void MD5Final(unsigned char digest[16], MD5Context *ctx); +extern void MD5Transform(uint32_t buf[4], uint32_t in[16]); diff --git a/depends/md5/md5wrapper.cpp b/depends/md5/md5wrapper.cpp new file mode 100644 index 0000000000..7e64f79148 --- /dev/null +++ b/depends/md5/md5wrapper.cpp @@ -0,0 +1,161 @@ +/* + * This is part of my wrapper-class to create + * a MD5 Hash from a string and a file. + * + * This code is completly free, you + * can copy it, modify it, or do + * what ever you want with it. + * + * Feb. 2005 + * Benjamin Grüdelbach + */ + +/* + * Changed unsigned long int types into uint32_t to make this work on 64bit systems. + * Sep. 5. 2009 + * Petr Mrázek + */ + +//---------------------------------------------------------------------- +//basic includes +#include +#include +#include +#include +#include +//my includes +#include "md5wrapper.h" +#include "md5.h" + +//---------privates-------------------------- + +/* + * internal hash function, calling + * the basic methods from md5.h + */ +std::string md5wrapper::hashit(unsigned char *data, size_t length) +{ + MD5Context ctx; + + //init md5 + MD5Init(&ctx); + //update with our string + MD5Update(&ctx, data, length); + + //create the hash + unsigned char buff[16] = ""; + MD5Final((unsigned char*)buff,&ctx); + + //converte the hash to a string and return it + return convToString(buff); +} + +/* + * converts the numeric hash to + * a valid std::string. + * (based on Jim Howard's code; + * http://www.codeproject.com/cpp/cmd5.asp) + */ +std::string md5wrapper::convToString(unsigned char *bytes) +{ + char asciihash[33]; + + int p = 0; + for(int i=0; i<16; i++) + { + ::sprintf(&asciihash[p],"%02x",bytes[i]); + p += 2; + } + asciihash[32] = '\0'; + return std::string(asciihash); +} + +//---------publics-------------------------- + +//constructor +md5wrapper::md5wrapper() +{ +} + + +//destructor +md5wrapper::~md5wrapper() +{ +} + +/* + * creates a MD5 hash from + * "text" and returns it as + * string + */ +std::string md5wrapper::getHashFromString(std::string text) +{ + return this->hashit((unsigned char*)text.data(), text.length()); +} + +/* + * creates a MD5 hash from + * a file specified in "filename" and + * returns it as string + * (based on Ronald L. Rivest's code + * from RFC1321 "The MD5 Message-Digest Algorithm") + */ +std::string md5wrapper::getHashFromFile(std::string filename, uint32_t & length, char * first_kb) +{ + FILE *file; + MD5Context context; + + int len; + int saved = 0; + unsigned char buffer[1024], digest[16]; + + //open file + if ((file = fopen (filename.c_str(), "rb")) == NULL) + { + return "file unreadable."; + } + length = 0; + //init md5 + MD5Init (&context); + + //read the filecontent + while (1) + { + errno = 0; + len = fread (buffer, 1, 1024, file); + if(saved < 1024 && first_kb) + { + memcpy(first_kb + saved, buffer, std::min (len, 1024 - saved)); + saved += len; + } + length += len; + if(len != 1024) + { + int err = ferror(file); + //FIXME: check errno here. + if(err) + { + fclose(file); + return strerror(err); + } + if(feof(file)) + { + MD5Update (&context, buffer, len); + break; + } + } + MD5Update (&context, buffer, len); + } + + /* + generate hash, close the file and return the + hash as std::string + */ + MD5Final (digest, &context); + fclose (file); + return convToString(digest); + } + +/* + * EOF + */ diff --git a/library/depends/md5/md5wrapper.h b/depends/md5/md5wrapper.h similarity index 76% rename from library/depends/md5/md5wrapper.h rename to depends/md5/md5wrapper.h index 65dd2564cd..0b534b61de 100644 --- a/library/depends/md5/md5wrapper.h +++ b/depends/md5/md5wrapper.h @@ -22,20 +22,16 @@ //basic includes #include - -//forwards -class MD5; +#include class md5wrapper { private: - MD5 *md5; - /* * internal hash function, calling * the basic methods from md5.h */ - std::string hashit(std::string text); + std::string hashit(unsigned char *data, size_t length); /* * converts the numeric giets to @@ -56,12 +52,16 @@ class md5wrapper */ std::string getHashFromString(std::string text); + std::string getHashFromBytes(const unsigned char *data, size_t size) { + return hashit(const_cast(data),size); + } + /* * creates a MD5 hash from * a file specified in "filename" and * returns it as string */ - std::string getHashFromFile(std::string filename); + std::string getHashFromFile(const std::string filename, uint32_t & length, char * first_kb = NULL); }; diff --git a/depends/protobuf/.gitignore b/depends/protobuf/.gitignore new file mode 100644 index 0000000000..dd948c3844 --- /dev/null +++ b/depends/protobuf/.gitignore @@ -0,0 +1,2 @@ +config.h +testHashMap.cpp diff --git a/depends/protobuf/CMakeLists.txt b/depends/protobuf/CMakeLists.txt new file mode 100644 index 0000000000..1d1796d1c8 --- /dev/null +++ b/depends/protobuf/CMakeLists.txt @@ -0,0 +1,196 @@ +project(protobuf) + +set(HASH_MAP_H ) +set(HASH_SET_H ) +set(HASH_NAMESPACE std) +set(HASH_MAP_CLASS unordered_map) +set(HASH_SET_CLASS unordered_set) +set(HAVE_HASH_MAP 1) +set(HAVE_HASH_SET 1) + +if(HAVE_HASH_MAP EQUAL 0) + message(SEND_ERROR "Could not find a working hash map implementation. Please install GCC >= 4.4, and all necessary 32-bit C++ development libraries.") +endif() + +if(UNIX) + find_package(Threads REQUIRED) +endif() + +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/config.h.in" "${CMAKE_CURRENT_BINARY_DIR}/config.h") + +set(LIBPROTOBUF_LITE_HDRS + google/protobuf/io/coded_stream.h + google/protobuf/io/coded_stream_inl.h + google/protobuf/stubs/common.h + ${CMAKE_CURRENT_BINARY_DIR}/config.h + google/protobuf/extension_set.h + google/protobuf/generated_message_util.h + google/protobuf/stubs/hash.h + google/protobuf/stubs/map-util.h + google/protobuf/message_lite.h + google/protobuf/stubs/once.h + google/protobuf/repeated_field.h + google/protobuf/stubs/stl_util-inl.h + google/protobuf/wire_format_lite.h + google/protobuf/wire_format_lite_inl.h + google/protobuf/io/zero_copy_stream.h + google/protobuf/io/zero_copy_stream_impl_lite.h + google/protobuf/io/gzip_stream.h + google/protobuf/io/zero_copy_stream_impl.h +) + +set(LIBPROTOBUF_FULL_HDRS + google/protobuf/descriptor.h + google/protobuf/descriptor.pb.h + google/protobuf/descriptor_database.h + google/protobuf/dynamic_message.h + google/protobuf/generated_message_reflection.h + google/protobuf/compiler/importer.h + google/protobuf/message.h + google/protobuf/compiler/parser.h + google/protobuf/io/printer.h + google/protobuf/reflection_ops.h + google/protobuf/service.h + google/protobuf/stubs/strutil.h + google/protobuf/stubs/substitute.h + google/protobuf/text_format.h + google/protobuf/io/tokenizer.h + google/protobuf/unknown_field_set.h + google/protobuf/wire_format.h +) + +list(APPEND LIBPROTOBUF_FULL_HDRS ${LIBPROTOBUF_LITE_HDRS}) + +set(LIBPROTOBUF_LITE_SRCS + google/protobuf/io/coded_stream.cc + google/protobuf/stubs/common.cc + google/protobuf/extension_set.cc + google/protobuf/generated_message_util.cc + google/protobuf/message_lite.cc + google/protobuf/stubs/once.cc + google/protobuf/repeated_field.cc + google/protobuf/wire_format_lite.cc + google/protobuf/io/zero_copy_stream.cc + google/protobuf/io/zero_copy_stream_impl_lite.cc + google/protobuf/io/gzip_stream.cc + google/protobuf/io/zero_copy_stream_impl.cc +) + +set(LIBPROTOBUF_FULL_SRCS + google/protobuf/descriptor.cc + google/protobuf/descriptor.pb.cc + google/protobuf/descriptor_database.cc + google/protobuf/dynamic_message.cc + google/protobuf/extension_set_heavy.cc + google/protobuf/generated_message_reflection.cc + google/protobuf/compiler/importer.cc + google/protobuf/io/gzip_stream.cc + google/protobuf/message.cc + google/protobuf/compiler/parser.cc + google/protobuf/io/printer.cc + google/protobuf/reflection_ops.cc + google/protobuf/service.cc + google/protobuf/stubs/structurally_valid.cc + google/protobuf/stubs/strutil.cc + google/protobuf/stubs/substitute.cc + google/protobuf/text_format.cc + google/protobuf/io/tokenizer.cc + google/protobuf/unknown_field_set.cc + google/protobuf/wire_format.cc + google/protobuf/io/zero_copy_stream_impl.cc +) + +set(LIBPROTOC_HDRS + google/protobuf/compiler/code_generator.h + google/protobuf/compiler/command_line_interface.h + google/protobuf/compiler/cpp/cpp_enum.h + google/protobuf/compiler/cpp/cpp_enum_field.h + google/protobuf/compiler/cpp/cpp_extension.h + google/protobuf/compiler/cpp/cpp_field.h + google/protobuf/compiler/cpp/cpp_file.h + google/protobuf/compiler/cpp/cpp_generator.h + google/protobuf/compiler/cpp/cpp_helpers.h + google/protobuf/compiler/cpp/cpp_message.h + google/protobuf/compiler/cpp/cpp_message_field.h + google/protobuf/compiler/cpp/cpp_primitive_field.h + google/protobuf/compiler/cpp/cpp_service.h + google/protobuf/compiler/cpp/cpp_string_field.h + google/protobuf/compiler/plugin.h + google/protobuf/compiler/plugin.pb.h + google/protobuf/compiler/subprocess.h + google/protobuf/compiler/zip_writer.h +) + +set(LIBPROTOC_SRCS + google/protobuf/compiler/code_generator.cc + google/protobuf/compiler/command_line_interface.cc + google/protobuf/compiler/cpp/cpp_enum.cc + google/protobuf/compiler/cpp/cpp_enum_field.cc + google/protobuf/compiler/cpp/cpp_extension.cc + google/protobuf/compiler/cpp/cpp_field.cc + google/protobuf/compiler/cpp/cpp_file.cc + google/protobuf/compiler/cpp/cpp_generator.cc + google/protobuf/compiler/cpp/cpp_helpers.cc + google/protobuf/compiler/cpp/cpp_message.cc + google/protobuf/compiler/cpp/cpp_message_field.cc + google/protobuf/compiler/cpp/cpp_primitive_field.cc + google/protobuf/compiler/cpp/cpp_service.cc + google/protobuf/compiler/cpp/cpp_string_field.cc + google/protobuf/compiler/plugin.cc + google/protobuf/compiler/plugin.pb.cc + google/protobuf/compiler/subprocess.cc + google/protobuf/compiler/zip_writer.cc +) + +list(APPEND LIBPROTOBUF_FULL_SRCS ${LIBPROTOBUF_LITE_SRCS}) + +if(CMAKE_COMPILER_IS_GNUCC) + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-result -Wno-unused-local-typedefs -Wno-misleading-indentation -Wno-class-memaccess -Wno-sign-compare") +elseif(MSVC) + # Disable warnings for integer conversion to smaller type + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4267 /wd4273") +endif() + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) +set(PROTOBUF_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}) +include_directories(${ZLIB_INCLUDE_DIRS}) +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + +# Protobuf shared libraries + +add_library(protobuf-lite SHARED ${LIBPROTOBUF_LITE_SRCS} ${LIBPROTOBUF_LITE_HDRS}) +ide_folder(protobuf-lite "Depends") + +set_target_properties(protobuf-lite PROPERTIES COMPILE_DEFINITIONS LIBPROTOBUF_EXPORTS) + +target_link_libraries(protobuf-lite ${CMAKE_THREAD_LIBS_INIT} ${ZLIB_LIBRARIES}) + +install(TARGETS protobuf-lite + LIBRARY DESTINATION ${DFHACK_LIBRARY_DESTINATION} + RUNTIME DESTINATION ${DFHACK_LIBRARY_DESTINATION}) + +if(NOT CMAKE_CROSSCOMPILING) + add_library(protobuf SHARED ${LIBPROTOBUF_FULL_SRCS} ${LIBPROTOBUF_FULL_HDRS}) + ide_folder(protobuf "Depends") + set_target_properties(protobuf PROPERTIES COMPILE_DEFINITIONS LIBPROTOBUF_EXPORTS) + target_link_libraries(protobuf ${CMAKE_THREAD_LIBS_INIT} ${ZLIB_LIBRARIES}) + + # Protobuf compiler shared library + + add_library(protoc SHARED ${LIBPROTOC_SRCS} ${LIBPROTOC_HDRS}) + ide_folder(protoc "Depends") + + set_target_properties(protoc PROPERTIES COMPILE_DEFINITIONS LIBPROTOC_EXPORTS) + target_link_libraries(protoc protobuf) + + # Protobuf compiler executable + + add_executable(protoc-bin google/protobuf/compiler/main.cc google/protobuf/compiler/command_line_interface.h google/protobuf/compiler/cpp/cpp_generator.h) + ide_folder(protoc-bin "Depends") + + set_target_properties(protoc-bin PROPERTIES OUTPUT_NAME protoc) + target_link_libraries(protoc-bin protoc) + + export(TARGETS protoc-bin FILE ${CMAKE_BINARY_DIR}/ImportExecutables.cmake ) +endif() diff --git a/depends/protobuf/COPYING.txt b/depends/protobuf/COPYING.txt new file mode 100644 index 0000000000..e1c4f52e7b --- /dev/null +++ b/depends/protobuf/COPYING.txt @@ -0,0 +1,33 @@ +Copyright 2008, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Code generated by the Protocol Buffer compiler is owned by the owner +of the input file used when generating it. This code is not +standalone and requires a support library to be linked with it. This +support library is itself covered by the above license. diff --git a/depends/protobuf/config.h.in b/depends/protobuf/config.h.in new file mode 100644 index 0000000000..7da01520a8 --- /dev/null +++ b/depends/protobuf/config.h.in @@ -0,0 +1,12 @@ +#define HASH_MAP_H @HASH_MAP_H@ +#define HASH_SET_H @HASH_SET_H@ +#define HASH_MAP_CLASS @HASH_MAP_CLASS@ +#define HASH_SET_CLASS @HASH_SET_CLASS@ +#define HASH_NAMESPACE @HASH_NAMESPACE@ +#define HAVE_HASH_MAP @HAVE_HASH_MAP@ +#define HAVE_HASH_SET @HAVE_HASH_SET@ +#define HAVE_PTHREAD @CMAKE_USE_PTHREADS_INIT@ + +/* define if you want to use zlib. See readme.txt for additional + * requirements. */ +#define HAVE_ZLIB 1 diff --git a/depends/protobuf/google/protobuf/compiler/code_generator.cc b/depends/protobuf/google/protobuf/compiler/code_generator.cc new file mode 100644 index 0000000000..455c239a93 --- /dev/null +++ b/depends/protobuf/google/protobuf/compiler/code_generator.cc @@ -0,0 +1,80 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include + +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { + +CodeGenerator::~CodeGenerator() {} +GeneratorContext::~GeneratorContext() {} + +io::ZeroCopyOutputStream* GeneratorContext::OpenForInsert( + const string& filename, const string& insertion_point) { + GOOGLE_LOG(FATAL) << "This GeneratorContext does not support insertion."; + return NULL; // make compiler happy +} + +void GeneratorContext::ListParsedFiles( + vector* output) { + GOOGLE_LOG(FATAL) << "This GeneratorContext does not support ListParsedFiles"; +} + +// Parses a set of comma-delimited name/value pairs. +void ParseGeneratorParameter(const string& text, + vector >* output) { + vector parts; + SplitStringUsing(text, ",", &parts); + + for (int i = 0; i < parts.size(); i++) { + string::size_type equals_pos = parts[i].find_first_of('='); + pair value; + if (equals_pos == string::npos) { + value.first = parts[i]; + value.second = ""; + } else { + value.first = parts[i].substr(0, equals_pos); + value.second = parts[i].substr(equals_pos + 1); + } + output->push_back(value); + } +} + +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/depends/protobuf/google/protobuf/compiler/code_generator.h b/depends/protobuf/google/protobuf/compiler/code_generator.h new file mode 100644 index 0000000000..252f68d1dc --- /dev/null +++ b/depends/protobuf/google/protobuf/compiler/code_generator.h @@ -0,0 +1,142 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// Defines the abstract interface implemented by each of the language-specific +// code generators. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CODE_GENERATOR_H__ +#define GOOGLE_PROTOBUF_COMPILER_CODE_GENERATOR_H__ + +#include +#include +#include +#include + +namespace google { +namespace protobuf { + +namespace io { class ZeroCopyOutputStream; } +class FileDescriptor; + +namespace compiler { + +// Defined in this file. +class CodeGenerator; +class GeneratorContext; + +// The abstract interface to a class which generates code implementing a +// particular proto file in a particular language. A number of these may +// be registered with CommandLineInterface to support various languages. +class LIBPROTOC_EXPORT CodeGenerator { + public: + inline CodeGenerator() {} + virtual ~CodeGenerator(); + + // Generates code for the given proto file, generating one or more files in + // the given output directory. + // + // A parameter to be passed to the generator can be specified on the + // command line. This is intended to be used by Java and similar languages + // to specify which specific class from the proto file is to be generated, + // though it could have other uses as well. It is empty if no parameter was + // given. + // + // Returns true if successful. Otherwise, sets *error to a description of + // the problem (e.g. "invalid parameter") and returns false. + virtual bool Generate(const FileDescriptor* file, + const string& parameter, + GeneratorContext* generator_context, + string* error) const = 0; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CodeGenerator); +}; + +// CodeGenerators generate one or more files in a given directory. This +// abstract interface represents the directory to which the CodeGenerator is +// to write and other information about the context in which the Generator +// runs. +class LIBPROTOC_EXPORT GeneratorContext { + public: + inline GeneratorContext() {} + virtual ~GeneratorContext(); + + // Opens the given file, truncating it if it exists, and returns a + // ZeroCopyOutputStream that writes to the file. The caller takes ownership + // of the returned object. This method never fails (a dummy stream will be + // returned instead). + // + // The filename given should be relative to the root of the source tree. + // E.g. the C++ generator, when generating code for "foo/bar.proto", will + // generate the files "foo/bar.pb.h" and "foo/bar.pb.cc"; note that + // "foo/" is included in these filenames. The filename is not allowed to + // contain "." or ".." components. + virtual io::ZeroCopyOutputStream* Open(const string& filename) = 0; + + // Creates a ZeroCopyOutputStream which will insert code into the given file + // at the given insertion point. See plugin.proto (plugin.pb.h) for more + // information on insertion points. The default implementation + // assert-fails -- it exists only for backwards-compatibility. + // + // WARNING: This feature is currently EXPERIMENTAL and is subject to change. + virtual io::ZeroCopyOutputStream* OpenForInsert( + const string& filename, const string& insertion_point); + + // Returns a vector of FileDescriptors for all the files being compiled + // in this run. Useful for languages, such as Go, that treat files + // differently when compiled as a set rather than individually. + virtual void ListParsedFiles(vector* output); + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(GeneratorContext); +}; + +// The type GeneratorContext was once called OutputDirectory. This typedef +// provides backward compatibility. +typedef GeneratorContext OutputDirectory; + +// Several code generators treat the parameter argument as holding a +// list of options separated by commas. This helper function parses +// a set of comma-delimited name/value pairs: e.g., +// "foo=bar,baz,qux=corge" +// parses to the pairs: +// ("foo", "bar"), ("baz", ""), ("qux", "corge") +extern void ParseGeneratorParameter(const string&, + vector >*); + +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_CODE_GENERATOR_H__ diff --git a/depends/protobuf/google/protobuf/compiler/command_line_interface.cc b/depends/protobuf/google/protobuf/compiler/command_line_interface.cc new file mode 100644 index 0000000000..88850f2cda --- /dev/null +++ b/depends/protobuf/google/protobuf/compiler/command_line_interface.cc @@ -0,0 +1,1357 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include + +#include +#include +#include +#include +#ifdef _MSC_VER +#include +#include +#else +#include +#endif +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace google { +namespace protobuf { +namespace compiler { + +#if defined(_WIN32) +#define mkdir(name, mode) mkdir(name) +#ifndef W_OK +#define W_OK 02 // not defined by MSVC for whatever reason +#endif +#ifndef F_OK +#define F_OK 00 // not defined by MSVC for whatever reason +#endif +#ifndef STDIN_FILENO +#define STDIN_FILENO 0 +#endif +#ifndef STDOUT_FILENO +#define STDOUT_FILENO 1 +#endif +#endif + +#ifndef O_BINARY +#ifdef _O_BINARY +#define O_BINARY _O_BINARY +#else +#define O_BINARY 0 // If this isn't defined, the platform doesn't need it. +#endif +#endif + +namespace { +#if defined(_WIN32) && !defined(__CYGWIN__) +static const char* kPathSeparator = ";"; +#else +static const char* kPathSeparator = ":"; +#endif + +// Returns true if the text looks like a Windows-style absolute path, starting +// with a drive letter. Example: "C:\foo". TODO(kenton): Share this with +// copy in importer.cc? +static bool IsWindowsAbsolutePath(const string& text) { +#if defined(_WIN32) || defined(__CYGWIN__) + return text.size() >= 3 && text[1] == ':' && + isalpha(text[0]) && + (text[2] == '/' || text[2] == '\\') && + text.find_last_of(':') == 1; +#else + return false; +#endif +} + +void SetFdToTextMode(int fd) { +#ifdef _WIN32 + if (_setmode(fd, _O_TEXT) == -1) { + // This should never happen, I think. + GOOGLE_LOG(WARNING) << "_setmode(" << fd << ", _O_TEXT): " << strerror(errno); + } +#endif + // (Text and binary are the same on non-Windows platforms.) +} + +void SetFdToBinaryMode(int fd) { +#ifdef _WIN32 + if (_setmode(fd, _O_BINARY) == -1) { + // This should never happen, I think. + GOOGLE_LOG(WARNING) << "_setmode(" << fd << ", _O_BINARY): " << strerror(errno); + } +#endif + // (Text and binary are the same on non-Windows platforms.) +} + +void AddTrailingSlash(string* path) { + if (!path->empty() && path->at(path->size() - 1) != '/') { + path->push_back('/'); + } +} + +bool VerifyDirectoryExists(const string& path) { + if (path.empty()) return true; + + if (access(path.c_str(), W_OK) == -1) { + cerr << path << ": " << strerror(errno) << endl; + return false; + } else { + return true; + } +} + +// Try to create the parent directory of the given file, creating the parent's +// parent if necessary, and so on. The full file name is actually +// (prefix + filename), but we assume |prefix| already exists and only create +// directories listed in |filename|. +bool TryCreateParentDirectory(const string& prefix, const string& filename) { + // Recursively create parent directories to the output file. + vector parts; + SplitStringUsing(filename, "/", &parts); + string path_so_far = prefix; + for (int i = 0; i < parts.size() - 1; i++) { + path_so_far += parts[i]; + if (mkdir(path_so_far.c_str(), 0777) != 0) { + if (errno != EEXIST) { + cerr << filename << ": while trying to create directory " + << path_so_far << ": " << strerror(errno) << endl; + return false; + } + } + path_so_far += '/'; + } + + return true; +} + +} // namespace + +// A MultiFileErrorCollector that prints errors to stderr. +class CommandLineInterface::ErrorPrinter : public MultiFileErrorCollector, + public io::ErrorCollector { + public: + ErrorPrinter(ErrorFormat format, DiskSourceTree *tree = NULL) + : format_(format), tree_(tree) {} + ~ErrorPrinter() {} + + // implements MultiFileErrorCollector ------------------------------ + void AddError(const string& filename, int line, int column, + const string& message) { + + // Print full path when running under MSVS + string dfile; + if (format_ == CommandLineInterface::ERROR_FORMAT_MSVS && + tree_ != NULL && + tree_->VirtualFileToDiskFile(filename, &dfile)) { + cerr << dfile; + } else { + cerr << filename; + } + + // Users typically expect 1-based line/column numbers, so we add 1 + // to each here. + if (line != -1) { + // Allow for both GCC- and Visual-Studio-compatible output. + switch (format_) { + case CommandLineInterface::ERROR_FORMAT_GCC: + cerr << ":" << (line + 1) << ":" << (column + 1); + break; + case CommandLineInterface::ERROR_FORMAT_MSVS: + cerr << "(" << (line + 1) << ") : error in column=" << (column + 1); + break; + } + } + + cerr << ": " << message << endl; + } + + // implements io::ErrorCollector ----------------------------------- + void AddError(int line, int column, const string& message) { + AddError("input", line, column, message); + } + + private: + const ErrorFormat format_; + DiskSourceTree *tree_; +}; + +// ------------------------------------------------------------------- + +// A GeneratorContext implementation that buffers files in memory, then dumps +// them all to disk on demand. +class CommandLineInterface::GeneratorContextImpl : public GeneratorContext { + public: + GeneratorContextImpl(const vector& parsed_files); + ~GeneratorContextImpl(); + + // Write all files in the directory to disk at the given output location, + // which must end in a '/'. + bool WriteAllToDisk(const string& prefix); + + // Write the contents of this directory to a ZIP-format archive with the + // given name. + bool WriteAllToZip(const string& filename); + + // Add a boilerplate META-INF/MANIFEST.MF file as required by the Java JAR + // format, unless one has already been written. + void AddJarManifest(); + + // implements GeneratorContext -------------------------------------- + io::ZeroCopyOutputStream* Open(const string& filename); + io::ZeroCopyOutputStream* OpenForInsert( + const string& filename, const string& insertion_point); + void ListParsedFiles(vector* output) { + *output = parsed_files_; + } + + private: + friend class MemoryOutputStream; + + // map instead of hash_map so that files are written in order (good when + // writing zips). + map files_; + const vector& parsed_files_; + bool had_error_; +}; + +class CommandLineInterface::MemoryOutputStream + : public io::ZeroCopyOutputStream { + public: + MemoryOutputStream(GeneratorContextImpl* directory, const string& filename); + MemoryOutputStream(GeneratorContextImpl* directory, const string& filename, + const string& insertion_point); + virtual ~MemoryOutputStream(); + + // implements ZeroCopyOutputStream --------------------------------- + virtual bool Next(void** data, int* size) { return inner_->Next(data, size); } + virtual void BackUp(int count) { inner_->BackUp(count); } + virtual int64 ByteCount() const { return inner_->ByteCount(); } + + private: + // Where to insert the string when it's done. + GeneratorContextImpl* directory_; + string filename_; + string insertion_point_; + + // The string we're building. + string data_; + + // StringOutputStream writing to data_. + scoped_ptr inner_; +}; + +// ------------------------------------------------------------------- + +CommandLineInterface::GeneratorContextImpl::GeneratorContextImpl( + const vector& parsed_files) + : parsed_files_(parsed_files), + had_error_(false) { +} + +CommandLineInterface::GeneratorContextImpl::~GeneratorContextImpl() { + STLDeleteValues(&files_); +} + +bool CommandLineInterface::GeneratorContextImpl::WriteAllToDisk( + const string& prefix) { + if (had_error_) { + return false; + } + + if (!VerifyDirectoryExists(prefix)) { + return false; + } + + for (map::const_iterator iter = files_.begin(); + iter != files_.end(); ++iter) { + const string& relative_filename = iter->first; + const char* data = iter->second->data(); + int size = iter->second->size(); + + if (!TryCreateParentDirectory(prefix, relative_filename)) { + return false; + } + string filename = prefix + relative_filename; + + // Create the output file. + int file_descriptor; + do { + file_descriptor = + open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666); + } while (file_descriptor < 0 && errno == EINTR); + + if (file_descriptor < 0) { + int error = errno; + cerr << filename << ": " << strerror(error); + return false; + } + + // Write the file. + while (size > 0) { + int write_result; + do { + write_result = write(file_descriptor, data, size); + } while (write_result < 0 && errno == EINTR); + + if (write_result <= 0) { + // Write error. + + // FIXME(kenton): According to the man page, if write() returns zero, + // there was no error; write() simply did not write anything. It's + // unclear under what circumstances this might happen, but presumably + // errno won't be set in this case. I am confused as to how such an + // event should be handled. For now I'm treating it as an error, + // since retrying seems like it could lead to an infinite loop. I + // suspect this never actually happens anyway. + + if (write_result < 0) { + int error = errno; + cerr << filename << ": write: " << strerror(error); + } else { + cerr << filename << ": write() returned zero?" << endl; + } + return false; + } + + data += write_result; + size -= write_result; + } + + if (close(file_descriptor) != 0) { + int error = errno; + cerr << filename << ": close: " << strerror(error); + return false; + } + } + + return true; +} + +bool CommandLineInterface::GeneratorContextImpl::WriteAllToZip( + const string& filename) { + if (had_error_) { + return false; + } + + // Create the output file. + int file_descriptor; + do { + file_descriptor = + open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666); + } while (file_descriptor < 0 && errno == EINTR); + + if (file_descriptor < 0) { + int error = errno; + cerr << filename << ": " << strerror(error); + return false; + } + + // Create the ZipWriter + io::FileOutputStream stream(file_descriptor); + ZipWriter zip_writer(&stream); + + for (map::const_iterator iter = files_.begin(); + iter != files_.end(); ++iter) { + zip_writer.Write(iter->first, *iter->second); + } + + zip_writer.WriteDirectory(); + + if (stream.GetErrno() != 0) { + cerr << filename << ": " << strerror(stream.GetErrno()) << endl; + } + + if (!stream.Close()) { + cerr << filename << ": " << strerror(stream.GetErrno()) << endl; + } + + return true; +} + +void CommandLineInterface::GeneratorContextImpl::AddJarManifest() { + string** map_slot = &files_["META-INF/MANIFEST.MF"]; + if (*map_slot == NULL) { + *map_slot = new string( + "Manifest-Version: 1.0\n" + "Created-By: 1.6.0 (protoc)\n" + "\n"); + } +} + +io::ZeroCopyOutputStream* CommandLineInterface::GeneratorContextImpl::Open( + const string& filename) { + return new MemoryOutputStream(this, filename); +} + +io::ZeroCopyOutputStream* +CommandLineInterface::GeneratorContextImpl::OpenForInsert( + const string& filename, const string& insertion_point) { + return new MemoryOutputStream(this, filename, insertion_point); +} + +// ------------------------------------------------------------------- + +CommandLineInterface::MemoryOutputStream::MemoryOutputStream( + GeneratorContextImpl* directory, const string& filename) + : directory_(directory), + filename_(filename), + inner_(new io::StringOutputStream(&data_)) { +} + +CommandLineInterface::MemoryOutputStream::MemoryOutputStream( + GeneratorContextImpl* directory, const string& filename, + const string& insertion_point) + : directory_(directory), + filename_(filename), + insertion_point_(insertion_point), + inner_(new io::StringOutputStream(&data_)) { +} + +CommandLineInterface::MemoryOutputStream::~MemoryOutputStream() { + // Make sure all data has been written. + inner_.reset(); + + // Insert into the directory. + string** map_slot = &directory_->files_[filename_]; + + if (insertion_point_.empty()) { + // This was just a regular Open(). + if (*map_slot != NULL) { + cerr << filename_ << ": Tried to write the same file twice." << endl; + directory_->had_error_ = true; + return; + } + + *map_slot = new string; + (*map_slot)->swap(data_); + } else { + // This was an OpenForInsert(). + + // If the data doens't end with a clean line break, add one. + if (!data_.empty() && data_[data_.size() - 1] != '\n') { + data_.push_back('\n'); + } + + // Find the file we are going to insert into. + if (*map_slot == NULL) { + cerr << filename_ << ": Tried to insert into file that doesn't exist." + << endl; + directory_->had_error_ = true; + return; + } + string* target = *map_slot; + + // Find the insertion point. + string magic_string = strings::Substitute( + "@@protoc_insertion_point($0)", insertion_point_); + string::size_type pos = target->find(magic_string); + + if (pos == string::npos) { + cerr << filename_ << ": insertion point \"" << insertion_point_ + << "\" not found." << endl; + directory_->had_error_ = true; + return; + } + + // Seek backwards to the beginning of the line, which is where we will + // insert the data. Note that this has the effect of pushing the insertion + // point down, so the data is inserted before it. This is intentional + // because it means that multiple insertions at the same point will end + // up in the expected order in the final output. + pos = target->find_last_of('\n', pos); + if (pos == string::npos) { + // Insertion point is on the first line. + pos = 0; + } else { + // Advance to character after '\n'. + ++pos; + } + + // Extract indent. + string indent_(*target, pos, target->find_first_not_of(" \t", pos) - pos); + + if (indent_.empty()) { + // No indent. This makes things easier. + target->insert(pos, data_); + } else { + // Calculate how much space we need. + int indent_size = 0; + for (int i = 0; i < data_.size(); i++) { + if (data_[i] == '\n') indent_size += indent_.size(); + } + + // Make a hole for it. + target->insert(pos, data_.size() + indent_size, '\0'); + + // Now copy in the data. + string::size_type data_pos = 0; + char* target_ptr = string_as_array(target) + pos; + while (data_pos < data_.size()) { + // Copy indent. + memcpy(target_ptr, indent_.data(), indent_.size()); + target_ptr += indent_.size(); + + // Copy line from data_. + // We already guaranteed that data_ ends with a newline (above), so this + // search can't fail. + string::size_type line_length = + data_.find_first_of('\n', data_pos) + 1 - data_pos; + memcpy(target_ptr, data_.data() + data_pos, line_length); + target_ptr += line_length; + data_pos += line_length; + } + + GOOGLE_CHECK_EQ(target_ptr, + string_as_array(target) + pos + data_.size() + indent_size); + } + } +} + +// =================================================================== + +CommandLineInterface::CommandLineInterface() + : mode_(MODE_COMPILE), + error_format_(ERROR_FORMAT_GCC), + imports_in_descriptor_set_(false), + disallow_services_(false), + inputs_are_proto_path_relative_(false) {} +CommandLineInterface::~CommandLineInterface() {} + +void CommandLineInterface::RegisterGenerator(const string& flag_name, + CodeGenerator* generator, + const string& help_text) { + GeneratorInfo info; + info.generator = generator; + info.help_text = help_text; + generators_[flag_name] = info; +} + +void CommandLineInterface::AllowPlugins(const string& exe_name_prefix) { + plugin_prefix_ = exe_name_prefix; +} + +int CommandLineInterface::Run(int argc, const char* const argv[]) { + Clear(); + if (!ParseArguments(argc, argv)) return 1; + + // Set up the source tree. + DiskSourceTree source_tree; + for (int i = 0; i < proto_path_.size(); i++) { + source_tree.MapPath(proto_path_[i].first, proto_path_[i].second); + } + + // Map input files to virtual paths if necessary. + if (!inputs_are_proto_path_relative_) { + if (!MakeInputsBeProtoPathRelative(&source_tree)) { + return 1; + } + } + + // Allocate the Importer. + ErrorPrinter error_collector(error_format_, &source_tree); + Importer importer(&source_tree, &error_collector); + + vector parsed_files; + + // Parse each file. + for (int i = 0; i < input_files_.size(); i++) { + // Import the file. + const FileDescriptor* parsed_file = importer.Import(input_files_[i]); + if (parsed_file == NULL) return 1; + parsed_files.push_back(parsed_file); + + // Enforce --disallow_services. + if (disallow_services_ && parsed_file->service_count() > 0) { + cerr << parsed_file->name() << ": This file contains services, but " + "--disallow_services was used." << endl; + return 1; + } + } + + // We construct a separate GeneratorContext for each output location. Note + // that two code generators may output to the same location, in which case + // they should share a single GeneratorContext so that OpenForInsert() works. + typedef hash_map GeneratorContextMap; + GeneratorContextMap output_directories; + + // Generate output. + if (mode_ == MODE_COMPILE) { + for (int i = 0; i < output_directives_.size(); i++) { + string output_location = output_directives_[i].output_location; + if (!HasSuffixString(output_location, ".zip") && + !HasSuffixString(output_location, ".jar")) { + AddTrailingSlash(&output_location); + } + GeneratorContextImpl** map_slot = &output_directories[output_location]; + + if (*map_slot == NULL) { + // First time we've seen this output location. + *map_slot = new GeneratorContextImpl(parsed_files); + } + + if (!GenerateOutput(parsed_files, output_directives_[i], *map_slot)) { + STLDeleteValues(&output_directories); + return 1; + } + } + } + + // Write all output to disk. + for (GeneratorContextMap::iterator iter = output_directories.begin(); + iter != output_directories.end(); ++iter) { + const string& location = iter->first; + GeneratorContextImpl* directory = iter->second; + if (HasSuffixString(location, "/")) { + if (!directory->WriteAllToDisk(location)) { + STLDeleteValues(&output_directories); + return 1; + } + } else { + if (HasSuffixString(location, ".jar")) { + directory->AddJarManifest(); + } + + if (!directory->WriteAllToZip(location)) { + STLDeleteValues(&output_directories); + return 1; + } + } + } + + STLDeleteValues(&output_directories); + + if (!descriptor_set_name_.empty()) { + if (!WriteDescriptorSet(parsed_files)) { + return 1; + } + } + + if (mode_ == MODE_ENCODE || mode_ == MODE_DECODE) { + if (codec_type_.empty()) { + // HACK: Define an EmptyMessage type to use for decoding. + DescriptorPool pool; + FileDescriptorProto file; + file.set_name("empty_message.proto"); + file.add_message_type()->set_name("EmptyMessage"); + GOOGLE_CHECK(pool.BuildFile(file) != NULL); + codec_type_ = "EmptyMessage"; + if (!EncodeOrDecode(&pool)) { + return 1; + } + } else { + if (!EncodeOrDecode(importer.pool())) { + return 1; + } + } + } + + return 0; +} + +void CommandLineInterface::Clear() { + // Clear all members that are set by Run(). Note that we must not clear + // members which are set by other methods before Run() is called. + executable_name_.clear(); + proto_path_.clear(); + input_files_.clear(); + output_directives_.clear(); + codec_type_.clear(); + descriptor_set_name_.clear(); + + mode_ = MODE_COMPILE; + imports_in_descriptor_set_ = false; + disallow_services_ = false; +} + +bool CommandLineInterface::MakeInputsBeProtoPathRelative( + DiskSourceTree* source_tree) { + for (int i = 0; i < input_files_.size(); i++) { + string virtual_file, shadowing_disk_file; + switch (source_tree->DiskFileToVirtualFile( + input_files_[i], &virtual_file, &shadowing_disk_file)) { + case DiskSourceTree::SUCCESS: + input_files_[i] = virtual_file; + break; + case DiskSourceTree::SHADOWED: + cerr << input_files_[i] << ": Input is shadowed in the --proto_path " + "by \"" << shadowing_disk_file << "\". Either use the latter " + "file as your input or reorder the --proto_path so that the " + "former file's location comes first." << endl; + return false; + case DiskSourceTree::CANNOT_OPEN: + cerr << input_files_[i] << ": " << strerror(errno) << endl; + return false; + case DiskSourceTree::NO_MAPPING: + // First check if the file exists at all. + if (access(input_files_[i].c_str(), F_OK) < 0) { + // File does not even exist. + cerr << input_files_[i] << ": " << strerror(ENOENT) << endl; + } else { + cerr << input_files_[i] << ": File does not reside within any path " + "specified using --proto_path (or -I). You must specify a " + "--proto_path which encompasses this file. Note that the " + "proto_path must be an exact prefix of the .proto file " + "names -- protoc is too dumb to figure out when two paths " + "(e.g. absolute and relative) are equivalent (it's harder " + "than you think)." << endl; + } + return false; + } + } + + return true; +} + +bool CommandLineInterface::ParseArguments(int argc, const char* const argv[]) { + executable_name_ = argv[0]; + + // Iterate through all arguments and parse them. + for (int i = 1; i < argc; i++) { + string name, value; + + if (ParseArgument(argv[i], &name, &value)) { + // Returned true => Use the next argument as the flag value. + if (i + 1 == argc || argv[i+1][0] == '-') { + cerr << "Missing value for flag: " << name << endl; + if (name == "--decode") { + cerr << "To decode an unknown message, use --decode_raw." << endl; + } + return false; + } else { + ++i; + value = argv[i]; + } + } + + if (!InterpretArgument(name, value)) return false; + } + + // If no --proto_path was given, use the current working directory. + if (proto_path_.empty()) { + proto_path_.push_back(make_pair("", ".")); + } + + // Check some errror cases. + bool decoding_raw = (mode_ == MODE_DECODE) && codec_type_.empty(); + if (decoding_raw && !input_files_.empty()) { + cerr << "When using --decode_raw, no input files should be given." << endl; + return false; + } else if (!decoding_raw && input_files_.empty()) { + cerr << "Missing input file." << endl; + return false; + } + if (mode_ == MODE_COMPILE && output_directives_.empty() && + descriptor_set_name_.empty()) { + cerr << "Missing output directives." << endl; + return false; + } + if (imports_in_descriptor_set_ && descriptor_set_name_.empty()) { + cerr << "--include_imports only makes sense when combined with " + "--descriptor_set_out." << endl; + } + + return true; +} + +bool CommandLineInterface::ParseArgument(const char* arg, + string* name, string* value) { + bool parsed_value = false; + + if (arg[0] != '-') { + // Not a flag. + name->clear(); + parsed_value = true; + *value = arg; + } else if (arg[1] == '-') { + // Two dashes: Multi-character name, with '=' separating name and + // value. + const char* equals_pos = strchr(arg, '='); + if (equals_pos != NULL) { + *name = string(arg, equals_pos - arg); + *value = equals_pos + 1; + parsed_value = true; + } else { + *name = arg; + } + } else { + // One dash: One-character name, all subsequent characters are the + // value. + if (arg[1] == '\0') { + // arg is just "-". We treat this as an input file, except that at + // present this will just lead to a "file not found" error. + name->clear(); + *value = arg; + parsed_value = true; + } else { + *name = string(arg, 2); + *value = arg + 2; + parsed_value = !value->empty(); + } + } + + // Need to return true iff the next arg should be used as the value for this + // one, false otherwise. + + if (parsed_value) { + // We already parsed a value for this flag. + return false; + } + + if (*name == "-h" || *name == "--help" || + *name == "--disallow_services" || + *name == "--include_imports" || + *name == "--version" || + *name == "--decode_raw") { + // HACK: These are the only flags that don't take a value. + // They probably should not be hard-coded like this but for now it's + // not worth doing better. + return false; + } + + // Next argument is the flag value. + return true; +} + +bool CommandLineInterface::InterpretArgument(const string& name, + const string& value) { + if (name.empty()) { + // Not a flag. Just a filename. + if (value.empty()) { + cerr << "You seem to have passed an empty string as one of the " + "arguments to " << executable_name_ << ". This is actually " + "sort of hard to do. Congrats. Unfortunately it is not valid " + "input so the program is going to die now." << endl; + return false; + } + + input_files_.push_back(value); + + } else if (name == "-I" || name == "--proto_path") { + // Java's -classpath (and some other languages) delimits path components + // with colons. Let's accept that syntax too just to make things more + // intuitive. + vector parts; + SplitStringUsing(value, kPathSeparator, &parts); + + for (int i = 0; i < parts.size(); i++) { + string virtual_path; + string disk_path; + + int equals_pos = parts[i].find_first_of('='); + if (equals_pos == string::npos) { + virtual_path = ""; + disk_path = parts[i]; + } else { + virtual_path = parts[i].substr(0, equals_pos); + disk_path = parts[i].substr(equals_pos + 1); + } + + if (disk_path.empty()) { + cerr << "--proto_path passed empty directory name. (Use \".\" for " + "current directory.)" << endl; + return false; + } + + // Make sure disk path exists, warn otherwise. + if (access(disk_path.c_str(), F_OK) < 0) { + cerr << disk_path << ": warning: directory does not exist." << endl; + } + + proto_path_.push_back(pair(virtual_path, disk_path)); + } + + } else if (name == "-o" || name == "--descriptor_set_out") { + if (!descriptor_set_name_.empty()) { + cerr << name << " may only be passed once." << endl; + return false; + } + if (value.empty()) { + cerr << name << " requires a non-empty value." << endl; + return false; + } + if (mode_ != MODE_COMPILE) { + cerr << "Cannot use --encode or --decode and generate descriptors at the " + "same time." << endl; + return false; + } + descriptor_set_name_ = value; + + } else if (name == "--include_imports") { + if (imports_in_descriptor_set_) { + cerr << name << " may only be passed once." << endl; + return false; + } + imports_in_descriptor_set_ = true; + + } else if (name == "-h" || name == "--help") { + PrintHelpText(); + return false; // Exit without running compiler. + + } else if (name == "--version") { + if (!version_info_.empty()) { + cout << version_info_ << endl; + } + cout << "libprotoc " + << protobuf::internal::VersionString(GOOGLE_PROTOBUF_VERSION) + << endl; + return false; // Exit without running compiler. + + } else if (name == "--disallow_services") { + disallow_services_ = true; + + } else if (name == "--encode" || name == "--decode" || + name == "--decode_raw") { + if (mode_ != MODE_COMPILE) { + cerr << "Only one of --encode and --decode can be specified." << endl; + return false; + } + if (!output_directives_.empty() || !descriptor_set_name_.empty()) { + cerr << "Cannot use " << name + << " and generate code or descriptors at the same time." << endl; + return false; + } + + mode_ = (name == "--encode") ? MODE_ENCODE : MODE_DECODE; + + if (value.empty() && name != "--decode_raw") { + cerr << "Type name for " << name << " cannot be blank." << endl; + if (name == "--decode") { + cerr << "To decode an unknown message, use --decode_raw." << endl; + } + return false; + } else if (!value.empty() && name == "--decode_raw") { + cerr << "--decode_raw does not take a parameter." << endl; + return false; + } + + codec_type_ = value; + + } else if (name == "--error_format") { + if (value == "gcc") { + error_format_ = ERROR_FORMAT_GCC; + } else if (value == "msvs") { + error_format_ = ERROR_FORMAT_MSVS; + } else { + cerr << "Unknown error format: " << value << endl; + return false; + } + + } else if (name == "--plugin") { + if (plugin_prefix_.empty()) { + cerr << "This compiler does not support plugins." << endl; + return false; + } + + string name; + string path; + + string::size_type equals_pos = value.find_first_of('='); + if (equals_pos == string::npos) { + // Use the basename of the file. + string::size_type slash_pos = value.find_last_of('/'); + if (slash_pos == string::npos) { + name = value; + } else { + name = value.substr(slash_pos + 1); + } + path = value; + } else { + name = value.substr(0, equals_pos); + path = value.substr(equals_pos + 1); + } + + plugins_[name] = path; + + } else { + // Some other flag. Look it up in the generators list. + const GeneratorInfo* generator_info = FindOrNull(generators_, name); + if (generator_info == NULL && + (plugin_prefix_.empty() || !HasSuffixString(name, "_out"))) { + cerr << "Unknown flag: " << name << endl; + return false; + } + + // It's an output flag. Add it to the output directives. + if (mode_ != MODE_COMPILE) { + cerr << "Cannot use --encode or --decode and generate code at the " + "same time." << endl; + return false; + } + + OutputDirective directive; + directive.name = name; + if (generator_info == NULL) { + directive.generator = NULL; + } else { + directive.generator = generator_info->generator; + } + + // Split value at ':' to separate the generator parameter from the + // filename. However, avoid doing this if the colon is part of a valid + // Windows-style absolute path. + string::size_type colon_pos = value.find_first_of(':'); + if (colon_pos == string::npos || IsWindowsAbsolutePath(value)) { + directive.output_location = value; + } else { + directive.parameter = value.substr(0, colon_pos); + directive.output_location = value.substr(colon_pos + 1); + } + + output_directives_.push_back(directive); + } + + return true; +} + +void CommandLineInterface::PrintHelpText() { + // Sorry for indentation here; line wrapping would be uglier. + cerr << +"Usage: " << executable_name_ << " [OPTION] PROTO_FILES\n" +"Parse PROTO_FILES and generate output based on the options given:\n" +" -IPATH, --proto_path=PATH Specify the directory in which to search for\n" +" imports. May be specified multiple times;\n" +" directories will be searched in order. If not\n" +" given, the current working directory is used.\n" +" --version Show version info and exit.\n" +" -h, --help Show this text and exit.\n" +" --encode=MESSAGE_TYPE Read a text-format message of the given type\n" +" from standard input and write it in binary\n" +" to standard output. The message type must\n" +" be defined in PROTO_FILES or their imports.\n" +" --decode=MESSAGE_TYPE Read a binary message of the given type from\n" +" standard input and write it in text format\n" +" to standard output. The message type must\n" +" be defined in PROTO_FILES or their imports.\n" +" --decode_raw Read an arbitrary protocol message from\n" +" standard input and write the raw tag/value\n" +" pairs in text format to standard output. No\n" +" PROTO_FILES should be given when using this\n" +" flag.\n" +" -oFILE, Writes a FileDescriptorSet (a protocol buffer,\n" +" --descriptor_set_out=FILE defined in descriptor.proto) containing all of\n" +" the input files to FILE.\n" +" --include_imports When using --descriptor_set_out, also include\n" +" all dependencies of the input files in the\n" +" set, so that the set is self-contained.\n" +" --error_format=FORMAT Set the format in which to print errors.\n" +" FORMAT may be 'gcc' (the default) or 'msvs'\n" +" (Microsoft Visual Studio format)." << endl; + if (!plugin_prefix_.empty()) { + cerr << +" --plugin=EXECUTABLE Specifies a plugin executable to use.\n" +" Normally, protoc searches the PATH for\n" +" plugins, but you may specify additional\n" +" executables not in the path using this flag.\n" +" Additionally, EXECUTABLE may be of the form\n" +" NAME=PATH, in which case the given plugin name\n" +" is mapped to the given executable even if\n" +" the executable's own name differs." << endl; + } + + for (GeneratorMap::iterator iter = generators_.begin(); + iter != generators_.end(); ++iter) { + // FIXME(kenton): If the text is long enough it will wrap, which is ugly, + // but fixing this nicely (e.g. splitting on spaces) is probably more + // trouble than it's worth. + cerr << " " << iter->first << "=OUT_DIR " + << string(19 - iter->first.size(), ' ') // Spaces for alignment. + << iter->second.help_text << endl; + } +} + +bool CommandLineInterface::GenerateOutput( + const vector& parsed_files, + const OutputDirective& output_directive, + GeneratorContext* generator_context) { + // Call the generator. + string error; + if (output_directive.generator == NULL) { + // This is a plugin. + GOOGLE_CHECK(HasPrefixString(output_directive.name, "--") && + HasSuffixString(output_directive.name, "_out")) + << "Bad name for plugin generator: " << output_directive.name; + + // Strip the "--" and "_out" and add the plugin prefix. + string plugin_name = plugin_prefix_ + "gen-" + + output_directive.name.substr(2, output_directive.name.size() - 6); + + if (!GeneratePluginOutput(parsed_files, plugin_name, + output_directive.parameter, + generator_context, &error)) { + cerr << output_directive.name << ": " << error << endl; + return false; + } + } else { + // Regular generator. + for (int i = 0; i < parsed_files.size(); i++) { + if (!output_directive.generator->Generate( + parsed_files[i], output_directive.parameter, + generator_context, &error)) { + // Generator returned an error. + cerr << output_directive.name << ": " << parsed_files[i]->name() << ": " + << error << endl; + return false; + } + } + } + + return true; +} + +bool CommandLineInterface::GeneratePluginOutput( + const vector& parsed_files, + const string& plugin_name, + const string& parameter, + GeneratorContext* generator_context, + string* error) { + CodeGeneratorRequest request; + CodeGeneratorResponse response; + + // Build the request. + if (!parameter.empty()) { + request.set_parameter(parameter); + } + + set already_seen; + for (int i = 0; i < parsed_files.size(); i++) { + request.add_file_to_generate(parsed_files[i]->name()); + GetTransitiveDependencies(parsed_files[i], &already_seen, + request.mutable_proto_file()); + } + + // Invoke the plugin. + Subprocess subprocess; + + if (plugins_.count(plugin_name) > 0) { + subprocess.Start(plugins_[plugin_name], Subprocess::EXACT_NAME); + } else { + subprocess.Start(plugin_name, Subprocess::SEARCH_PATH); + } + + string communicate_error; + if (!subprocess.Communicate(request, &response, &communicate_error)) { + *error = strings::Substitute("$0: $1", plugin_name, communicate_error); + return false; + } + + // Write the files. We do this even if there was a generator error in order + // to match the behavior of a compiled-in generator. + scoped_ptr current_output; + for (int i = 0; i < response.file_size(); i++) { + const CodeGeneratorResponse::File& output_file = response.file(i); + + if (!output_file.insertion_point().empty()) { + // Open a file for insert. + // We reset current_output to NULL first so that the old file is closed + // before the new one is opened. + current_output.reset(); + current_output.reset(generator_context->OpenForInsert( + output_file.name(), output_file.insertion_point())); + } else if (!output_file.name().empty()) { + // Starting a new file. Open it. + // We reset current_output to NULL first so that the old file is closed + // before the new one is opened. + current_output.reset(); + current_output.reset(generator_context->Open(output_file.name())); + } else if (current_output == NULL) { + *error = strings::Substitute( + "$0: First file chunk returned by plugin did not specify a file name.", + plugin_name); + return false; + } + + // Use CodedOutputStream for convenience; otherwise we'd need to provide + // our own buffer-copying loop. + io::CodedOutputStream writer(current_output.get()); + writer.WriteString(output_file.content()); + } + + // Check for errors. + if (!response.error().empty()) { + // Generator returned an error. + *error = response.error(); + return false; + } + + return true; +} + +bool CommandLineInterface::EncodeOrDecode(const DescriptorPool* pool) { + // Look up the type. + const Descriptor* type = pool->FindMessageTypeByName(codec_type_); + if (type == NULL) { + cerr << "Type not defined: " << codec_type_ << endl; + return false; + } + + DynamicMessageFactory dynamic_factory(pool); + scoped_ptr message(dynamic_factory.GetPrototype(type)->New()); + + if (mode_ == MODE_ENCODE) { + SetFdToTextMode(STDIN_FILENO); + SetFdToBinaryMode(STDOUT_FILENO); + } else { + SetFdToBinaryMode(STDIN_FILENO); + SetFdToTextMode(STDOUT_FILENO); + } + + io::FileInputStream in(STDIN_FILENO); + io::FileOutputStream out(STDOUT_FILENO); + + if (mode_ == MODE_ENCODE) { + // Input is text. + ErrorPrinter error_collector(error_format_); + TextFormat::Parser parser; + parser.RecordErrorsTo(&error_collector); + parser.AllowPartialMessage(true); + + if (!parser.Parse(&in, message.get())) { + cerr << "Failed to parse input." << endl; + return false; + } + } else { + // Input is binary. + if (!message->ParsePartialFromZeroCopyStream(&in)) { + cerr << "Failed to parse input." << endl; + return false; + } + } + + if (!message->IsInitialized()) { + cerr << "warning: Input message is missing required fields: " + << message->InitializationErrorString() << endl; + } + + if (mode_ == MODE_ENCODE) { + // Output is binary. + if (!message->SerializePartialToZeroCopyStream(&out)) { + cerr << "output: I/O error." << endl; + return false; + } + } else { + // Output is text. + if (!TextFormat::Print(*message, &out)) { + cerr << "output: I/O error." << endl; + return false; + } + } + + return true; +} + +bool CommandLineInterface::WriteDescriptorSet( + const vector parsed_files) { + FileDescriptorSet file_set; + + if (imports_in_descriptor_set_) { + set already_seen; + for (int i = 0; i < parsed_files.size(); i++) { + GetTransitiveDependencies( + parsed_files[i], &already_seen, file_set.mutable_file()); + } + } else { + for (int i = 0; i < parsed_files.size(); i++) { + parsed_files[i]->CopyTo(file_set.add_file()); + } + } + + int fd; + do { + fd = open(descriptor_set_name_.c_str(), + O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666); + } while (fd < 0 && errno == EINTR); + + if (fd < 0) { + perror(descriptor_set_name_.c_str()); + return false; + } + + io::FileOutputStream out(fd); + if (!file_set.SerializeToZeroCopyStream(&out)) { + cerr << descriptor_set_name_ << ": " << strerror(out.GetErrno()) << endl; + out.Close(); + return false; + } + if (!out.Close()) { + cerr << descriptor_set_name_ << ": " << strerror(out.GetErrno()) << endl; + return false; + } + + return true; +} + +void CommandLineInterface::GetTransitiveDependencies( + const FileDescriptor* file, + set* already_seen, + RepeatedPtrField* output) { + if (!already_seen->insert(file).second) { + // Already saw this file. Skip. + return; + } + + // Add all dependencies. + for (int i = 0; i < file->dependency_count(); i++) { + GetTransitiveDependencies(file->dependency(i), already_seen, output); + } + + // Add this file. + file->CopyTo(output->Add()); +} + + +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/depends/protobuf/google/protobuf/compiler/command_line_interface.h b/depends/protobuf/google/protobuf/compiler/command_line_interface.h new file mode 100644 index 0000000000..0b507d801f --- /dev/null +++ b/depends/protobuf/google/protobuf/compiler/command_line_interface.h @@ -0,0 +1,318 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// Implements the Protocol Compiler front-end such that it may be reused by +// custom compilers written to support other languages. + +#ifndef GOOGLE_PROTOBUF_COMPILER_COMMAND_LINE_INTERFACE_H__ +#define GOOGLE_PROTOBUF_COMPILER_COMMAND_LINE_INTERFACE_H__ + +#include +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { + +class FileDescriptor; // descriptor.h +class DescriptorPool; // descriptor.h +class FileDescriptorProto; // descriptor.pb.h +template class RepeatedPtrField; // repeated_field.h + +namespace compiler { + +class CodeGenerator; // code_generator.h +class GeneratorContext; // code_generator.h +class DiskSourceTree; // importer.h + +// This class implements the command-line interface to the protocol compiler. +// It is designed to make it very easy to create a custom protocol compiler +// supporting the languages of your choice. For example, if you wanted to +// create a custom protocol compiler binary which includes both the regular +// C++ support plus support for your own custom output "Foo", you would +// write a class "FooGenerator" which implements the CodeGenerator interface, +// then write a main() procedure like this: +// +// int main(int argc, char* argv[]) { +// google::protobuf::compiler::CommandLineInterface cli; +// +// // Support generation of C++ source and headers. +// google::protobuf::compiler::cpp::CppGenerator cpp_generator; +// cli.RegisterGenerator("--cpp_out", &cpp_generator, +// "Generate C++ source and header."); +// +// // Support generation of Foo code. +// FooGenerator foo_generator; +// cli.RegisterGenerator("--foo_out", &foo_generator, +// "Generate Foo file."); +// +// return cli.Run(argc, argv); +// } +// +// The compiler is invoked with syntax like: +// protoc --cpp_out=outdir --foo_out=outdir --proto_path=src src/foo.proto +// +// For a full description of the command-line syntax, invoke it with --help. +class LIBPROTOC_EXPORT CommandLineInterface { + public: + CommandLineInterface(); + ~CommandLineInterface(); + + // Register a code generator for a language. + // + // Parameters: + // * flag_name: The command-line flag used to specify an output file of + // this type. The name must start with a '-'. If the name is longer + // than one letter, it must start with two '-'s. + // * generator: The CodeGenerator which will be called to generate files + // of this type. + // * help_text: Text describing this flag in the --help output. + // + // Some generators accept extra parameters. You can specify this parameter + // on the command-line by placing it before the output directory, separated + // by a colon: + // protoc --foo_out=enable_bar:outdir + // The text before the colon is passed to CodeGenerator::Generate() as the + // "parameter". + void RegisterGenerator(const string& flag_name, + CodeGenerator* generator, + const string& help_text); + + // Enables "plugins". In this mode, if a command-line flag ends with "_out" + // but does not match any registered generator, the compiler will attempt to + // find a "plugin" to implement the generator. Plugins are just executables. + // They should live somewhere in the PATH. + // + // The compiler determines the executable name to search for by concatenating + // exe_name_prefix with the unrecognized flag name, removing "_out". So, for + // example, if exe_name_prefix is "protoc-" and you pass the flag --foo_out, + // the compiler will try to run the program "protoc-foo". + // + // The plugin program should implement the following usage: + // plugin [--out=OUTDIR] [--parameter=PARAMETER] PROTO_FILES < DESCRIPTORS + // --out indicates the output directory (as passed to the --foo_out + // parameter); if omitted, the current directory should be used. --parameter + // gives the generator parameter, if any was provided. The PROTO_FILES list + // the .proto files which were given on the compiler command-line; these are + // the files for which the plugin is expected to generate output code. + // Finally, DESCRIPTORS is an encoded FileDescriptorSet (as defined in + // descriptor.proto). This is piped to the plugin's stdin. The set will + // include descriptors for all the files listed in PROTO_FILES as well as + // all files that they import. The plugin MUST NOT attempt to read the + // PROTO_FILES directly -- it must use the FileDescriptorSet. + // + // The plugin should generate whatever files are necessary, as code generators + // normally do. It should write the names of all files it generates to + // stdout. The names should be relative to the output directory, NOT absolute + // names or relative to the current directory. If any errors occur, error + // messages should be written to stderr. If an error is fatal, the plugin + // should exit with a non-zero exit code. + void AllowPlugins(const string& exe_name_prefix); + + // Run the Protocol Compiler with the given command-line parameters. + // Returns the error code which should be returned by main(). + // + // It may not be safe to call Run() in a multi-threaded environment because + // it calls strerror(). I'm not sure why you'd want to do this anyway. + int Run(int argc, const char* const argv[]); + + // Call SetInputsAreCwdRelative(true) if the input files given on the command + // line should be interpreted relative to the proto import path specified + // using --proto_path or -I flags. Otherwise, input file names will be + // interpreted relative to the current working directory (or as absolute + // paths if they start with '/'), though they must still reside inside + // a directory given by --proto_path or the compiler will fail. The latter + // mode is generally more intuitive and easier to use, especially e.g. when + // defining implicit rules in Makefiles. + void SetInputsAreProtoPathRelative(bool enable) { + inputs_are_proto_path_relative_ = enable; + } + + // Provides some text which will be printed when the --version flag is + // used. The version of libprotoc will also be printed on the next line + // after this text. + void SetVersionInfo(const string& text) { + version_info_ = text; + } + + + private: + // ----------------------------------------------------------------- + + class ErrorPrinter; + class GeneratorContextImpl; + class MemoryOutputStream; + + // Clear state from previous Run(). + void Clear(); + + // Remaps each file in input_files_ so that it is relative to one of the + // directories in proto_path_. Returns false if an error occurred. This + // is only used if inputs_are_proto_path_relative_ is false. + bool MakeInputsBeProtoPathRelative( + DiskSourceTree* source_tree); + + // Parse all command-line arguments. + bool ParseArguments(int argc, const char* const argv[]); + + // Parses a command-line argument into a name/value pair. Returns + // true if the next argument in the argv should be used as the value, + // false otherwise. + // + // Exmaples: + // "-Isrc/protos" -> + // name = "-I", value = "src/protos" + // "--cpp_out=src/foo.pb2.cc" -> + // name = "--cpp_out", value = "src/foo.pb2.cc" + // "foo.proto" -> + // name = "", value = "foo.proto" + bool ParseArgument(const char* arg, string* name, string* value); + + // Interprets arguments parsed with ParseArgument. + bool InterpretArgument(const string& name, const string& value); + + // Print the --help text to stderr. + void PrintHelpText(); + + // Generate the given output file from the given input. + struct OutputDirective; // see below + bool GenerateOutput(const vector& parsed_files, + const OutputDirective& output_directive, + GeneratorContext* generator_context); + bool GeneratePluginOutput(const vector& parsed_files, + const string& plugin_name, + const string& parameter, + GeneratorContext* generator_context, + string* error); + + // Implements --encode and --decode. + bool EncodeOrDecode(const DescriptorPool* pool); + + // Implements the --descriptor_set_out option. + bool WriteDescriptorSet(const vector parsed_files); + + // Get all transitive dependencies of the given file (including the file + // itself), adding them to the given list of FileDescriptorProtos. The + // protos will be ordered such that every file is listed before any file that + // depends on it, so that you can call DescriptorPool::BuildFile() on them + // in order. Any files in *already_seen will not be added, and each file + // added will be inserted into *already_seen. + static void GetTransitiveDependencies( + const FileDescriptor* file, + set* already_seen, + RepeatedPtrField* output); + + // ----------------------------------------------------------------- + + // The name of the executable as invoked (i.e. argv[0]). + string executable_name_; + + // Version info set with SetVersionInfo(). + string version_info_; + + // Map from flag names to registered generators. + struct GeneratorInfo { + CodeGenerator* generator; + string help_text; + }; + typedef map GeneratorMap; + GeneratorMap generators_; + + // See AllowPlugins(). If this is empty, plugins aren't allowed. + string plugin_prefix_; + + // Maps specific plugin names to files. When executing a plugin, this map + // is searched first to find the plugin executable. If not found here, the + // PATH (or other OS-specific search strategy) is searched. + map plugins_; + + // Stuff parsed from command line. + enum Mode { + MODE_COMPILE, // Normal mode: parse .proto files and compile them. + MODE_ENCODE, // --encode: read text from stdin, write binary to stdout. + MODE_DECODE // --decode: read binary from stdin, write text to stdout. + }; + + Mode mode_; + + enum ErrorFormat { + ERROR_FORMAT_GCC, // GCC error output format (default). + ERROR_FORMAT_MSVS // Visual Studio output (--error_format=msvs). + }; + + ErrorFormat error_format_; + + vector > proto_path_; // Search path for proto files. + vector input_files_; // Names of the input proto files. + + // output_directives_ lists all the files we are supposed to output and what + // generator to use for each. + struct OutputDirective { + string name; // E.g. "--foo_out" + CodeGenerator* generator; // NULL for plugins + string parameter; + string output_location; + }; + vector output_directives_; + + // When using --encode or --decode, this names the type we are encoding or + // decoding. (Empty string indicates --decode_raw.) + string codec_type_; + + // If --descriptor_set_out was given, this is the filename to which the + // FileDescriptorSet should be written. Otherwise, empty. + string descriptor_set_name_; + + // True if --include_imports was given, meaning that we should + // write all transitive dependencies to the DescriptorSet. Otherwise, only + // the .proto files listed on the command-line are added. + bool imports_in_descriptor_set_; + + // Was the --disallow_services flag used? + bool disallow_services_; + + // See SetInputsAreProtoPathRelative(). + bool inputs_are_proto_path_relative_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CommandLineInterface); +}; + +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_COMMAND_LINE_INTERFACE_H__ diff --git a/depends/protobuf/google/protobuf/compiler/cpp/cpp_enum.cc b/depends/protobuf/google/protobuf/compiler/cpp/cpp_enum.cc new file mode 100644 index 0000000000..76d2b79853 --- /dev/null +++ b/depends/protobuf/google/protobuf/compiler/cpp/cpp_enum.cc @@ -0,0 +1,258 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include +#include + +#include +#include +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor, + const string& dllexport_decl) + : descriptor_(descriptor), + classname_(ClassName(descriptor, false)), + dllexport_decl_(dllexport_decl) { +} + +EnumGenerator::~EnumGenerator() {} + +void EnumGenerator::GenerateDefinition(io::Printer* printer) { + map vars; + vars["classname"] = classname_; + vars["short_name"] = descriptor_->name(); + + printer->Print(vars, "enum $classname$ {\n"); + printer->Indent(); + + const EnumValueDescriptor* min_value = descriptor_->value(0); + const EnumValueDescriptor* max_value = descriptor_->value(0); + + for (int i = 0; i < descriptor_->value_count(); i++) { + vars["name"] = descriptor_->value(i)->name(); + vars["number"] = SimpleItoa(descriptor_->value(i)->number()); + vars["prefix"] = (descriptor_->containing_type() == NULL) ? + "" : classname_ + "_"; + + if (i > 0) printer->Print(",\n"); + printer->Print(vars, "$prefix$$name$ = $number$"); + + if (descriptor_->value(i)->number() < min_value->number()) { + min_value = descriptor_->value(i); + } + if (descriptor_->value(i)->number() > max_value->number()) { + max_value = descriptor_->value(i); + } + } + + printer->Outdent(); + printer->Print("\n};\n"); + + vars["min_name"] = min_value->name(); + vars["max_name"] = max_value->name(); + + if (dllexport_decl_.empty()) { + vars["dllexport"] = ""; + } else { + vars["dllexport"] = dllexport_decl_ + " "; + } + + printer->Print(vars, + "$dllexport$bool $classname$_IsValid(int value);\n" + "const $classname$ $prefix$$short_name$_MIN = $prefix$$min_name$;\n" + "const $classname$ $prefix$$short_name$_MAX = $prefix$$max_name$;\n" + "const int $prefix$$short_name$_ARRAYSIZE = $prefix$$short_name$_MAX + 1;\n" + "\n"); + + if (HasDescriptorMethods(descriptor_->file())) { + printer->Print(vars, + "$dllexport$const ::google::protobuf::EnumDescriptor* $classname$_descriptor();\n"); + // The _Name and _Parse methods + printer->Print(vars, + "inline const ::std::string& $classname$_Name($classname$ value) {\n" + " return ::google::protobuf::internal::NameOfEnum(\n" + " $classname$_descriptor(), value);\n" + "}\n"); + printer->Print(vars, + "inline bool $classname$_Parse(\n" + " const ::std::string& name, $classname$* value) {\n" + " return ::google::protobuf::internal::ParseNamedEnum<$classname$>(\n" + " $classname$_descriptor(), name, value);\n" + "}\n"); + } +} + +void EnumGenerator:: +GenerateGetEnumDescriptorSpecializations(io::Printer* printer) { + if (HasDescriptorMethods(descriptor_->file())) { + printer->Print( + "template <>\n" + "inline const EnumDescriptor* GetEnumDescriptor< $classname$>() {\n" + " return $classname$_descriptor();\n" + "}\n", + "classname", ClassName(descriptor_, true)); + } +} + +void EnumGenerator::GenerateSymbolImports(io::Printer* printer) { + map vars; + vars["nested_name"] = descriptor_->name(); + vars["classname"] = classname_; + printer->Print(vars, "typedef $classname$ $nested_name$;\n"); + + for (int j = 0; j < descriptor_->value_count(); j++) { + vars["tag"] = descriptor_->value(j)->name(); + printer->Print(vars, + "static const $nested_name$ $tag$ = $classname$_$tag$;\n"); + } + + printer->Print(vars, + "static inline bool $nested_name$_IsValid(int value) {\n" + " return $classname$_IsValid(value);\n" + "}\n" + "static const $nested_name$ $nested_name$_MIN =\n" + " $classname$_$nested_name$_MIN;\n" + "static const $nested_name$ $nested_name$_MAX =\n" + " $classname$_$nested_name$_MAX;\n" + "static const int $nested_name$_ARRAYSIZE =\n" + " $classname$_$nested_name$_ARRAYSIZE;\n"); + + if (HasDescriptorMethods(descriptor_->file())) { + printer->Print(vars, + "static inline const ::google::protobuf::EnumDescriptor*\n" + "$nested_name$_descriptor() {\n" + " return $classname$_descriptor();\n" + "}\n"); + printer->Print(vars, + "static inline const ::std::string& $nested_name$_Name($nested_name$ value) {\n" + " return $classname$_Name(value);\n" + "}\n"); + printer->Print(vars, + "static inline bool $nested_name$_Parse(const ::std::string& name,\n" + " $nested_name$* value) {\n" + " return $classname$_Parse(name, value);\n" + "}\n"); + } +} + +void EnumGenerator::GenerateDescriptorInitializer( + io::Printer* printer, int index) { + map vars; + vars["classname"] = classname_; + vars["index"] = SimpleItoa(index); + + if (descriptor_->containing_type() == NULL) { + printer->Print(vars, + "$classname$_descriptor_ = file->enum_type($index$);\n"); + } else { + vars["parent"] = ClassName(descriptor_->containing_type(), false); + printer->Print(vars, + "$classname$_descriptor_ = $parent$_descriptor_->enum_type($index$);\n"); + } +} + +void EnumGenerator::GenerateMethods(io::Printer* printer) { + map vars; + vars["classname"] = classname_; + + if (HasDescriptorMethods(descriptor_->file())) { + printer->Print(vars, + "const ::google::protobuf::EnumDescriptor* $classname$_descriptor() {\n" + " protobuf_AssignDescriptorsOnce();\n" + " return $classname$_descriptor_;\n" + "}\n"); + } + + printer->Print(vars, + "bool $classname$_IsValid(int value) {\n" + " switch(value) {\n"); + + // Multiple values may have the same number. Make sure we only cover + // each number once by first constructing a set containing all valid + // numbers, then printing a case statement for each element. + + set numbers; + for (int j = 0; j < descriptor_->value_count(); j++) { + const EnumValueDescriptor* value = descriptor_->value(j); + numbers.insert(value->number()); + } + + for (set::iterator iter = numbers.begin(); + iter != numbers.end(); ++iter) { + printer->Print( + " case $number$:\n", + "number", SimpleItoa(*iter)); + } + + printer->Print(vars, + " return true;\n" + " default:\n" + " return false;\n" + " }\n" + "}\n" + "\n"); + + if (descriptor_->containing_type() != NULL) { + // We need to "define" the static constants which were declared in the + // header, to give the linker a place to put them. Or at least the C++ + // standard says we have to. MSVC actually insists tha we do _not_ define + // them again in the .cc file. + printer->Print("#ifndef _MSC_VER\n"); + + vars["parent"] = ClassName(descriptor_->containing_type(), false); + vars["nested_name"] = descriptor_->name(); + for (int i = 0; i < descriptor_->value_count(); i++) { + vars["value"] = descriptor_->value(i)->name(); + printer->Print(vars, + "const $classname$ $parent$::$value$;\n"); + } + printer->Print(vars, + "const $classname$ $parent$::$nested_name$_MIN;\n" + "const $classname$ $parent$::$nested_name$_MAX;\n" + "const int $parent$::$nested_name$_ARRAYSIZE;\n"); + + printer->Print("#endif // _MSC_VER\n"); + } +} + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/depends/protobuf/google/protobuf/compiler/cpp/cpp_enum.h b/depends/protobuf/google/protobuf/compiler/cpp/cpp_enum.h new file mode 100644 index 0000000000..58f7721ecd --- /dev/null +++ b/depends/protobuf/google/protobuf/compiler/cpp/cpp_enum.h @@ -0,0 +1,99 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_H__ +#define GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_H__ + +#include +#include + +namespace google { +namespace protobuf { + namespace io { + class Printer; // printer.h + } +} + +namespace protobuf { +namespace compiler { +namespace cpp { + +class EnumGenerator { + public: + // See generator.cc for the meaning of dllexport_decl. + explicit EnumGenerator(const EnumDescriptor* descriptor, + const string& dllexport_decl); + ~EnumGenerator(); + + // Header stuff. + + // Generate header code defining the enum. This code should be placed + // within the enum's package namespace, but NOT within any class, even for + // nested enums. + void GenerateDefinition(io::Printer* printer); + + // Generate specialization of GetEnumDescriptor(). + // Precondition: in ::google::protobuf namespace. + void GenerateGetEnumDescriptorSpecializations(io::Printer* printer); + + // For enums nested within a message, generate code to import all the enum's + // symbols (e.g. the enum type name, all its values, etc.) into the class's + // namespace. This should be placed inside the class definition in the + // header. + void GenerateSymbolImports(io::Printer* printer); + + // Source file stuff. + + // Generate code that initializes the global variable storing the enum's + // descriptor. + void GenerateDescriptorInitializer(io::Printer* printer, int index); + + // Generate non-inline methods related to the enum, such as IsValidValue(). + // Goes in the .cc file. + void GenerateMethods(io::Printer* printer); + + private: + const EnumDescriptor* descriptor_; + string classname_; + string dllexport_decl_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumGenerator); +}; + +} // namespace cpp +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_H__ diff --git a/depends/protobuf/google/protobuf/compiler/cpp/cpp_enum_field.cc b/depends/protobuf/google/protobuf/compiler/cpp/cpp_enum_field.cc new file mode 100644 index 0000000000..a369f41781 --- /dev/null +++ b/depends/protobuf/google/protobuf/compiler/cpp/cpp_enum_field.cc @@ -0,0 +1,361 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +namespace { + +void SetEnumVariables(const FieldDescriptor* descriptor, + map* variables) { + SetCommonFieldVariables(descriptor, variables); + const EnumValueDescriptor* default_value = descriptor->default_value_enum(); + (*variables)["type"] = ClassName(descriptor->enum_type(), true); + (*variables)["default"] = SimpleItoa(default_value->number()); +} + +} // namespace + +// =================================================================== + +EnumFieldGenerator:: +EnumFieldGenerator(const FieldDescriptor* descriptor) + : descriptor_(descriptor) { + SetEnumVariables(descriptor, &variables_); +} + +EnumFieldGenerator::~EnumFieldGenerator() {} + +void EnumFieldGenerator:: +GeneratePrivateMembers(io::Printer* printer) const { + printer->Print(variables_, "int $name$_;\n"); +} + +void EnumFieldGenerator:: +GenerateAccessorDeclarations(io::Printer* printer) const { + printer->Print(variables_, + "inline $type$ $name$() const$deprecation$;\n" + "inline void set_$name$($type$ value)$deprecation$;\n"); +} + +void EnumFieldGenerator:: +GenerateInlineAccessorDefinitions(io::Printer* printer) const { + printer->Print(variables_, + "inline $type$ $classname$::$name$() const {\n" + " return static_cast< $type$ >($name$_);\n" + "}\n" + "inline void $classname$::set_$name$($type$ value) {\n" + " GOOGLE_DCHECK($type$_IsValid(value));\n" + " set_has_$name$();\n" + " $name$_ = value;\n" + "}\n"); +} + +void EnumFieldGenerator:: +GenerateClearingCode(io::Printer* printer) const { + printer->Print(variables_, "$name$_ = $default$;\n"); +} + +void EnumFieldGenerator:: +GenerateMergingCode(io::Printer* printer) const { + printer->Print(variables_, "set_$name$(from.$name$());\n"); +} + +void EnumFieldGenerator:: +GenerateSwappingCode(io::Printer* printer) const { + printer->Print(variables_, "std::swap($name$_, other->$name$_);\n"); +} + +void EnumFieldGenerator:: +GenerateConstructorCode(io::Printer* printer) const { + printer->Print(variables_, "$name$_ = $default$;\n"); +} + +void EnumFieldGenerator:: +GenerateMergeFromCodedStream(io::Printer* printer) const { + printer->Print(variables_, + "int value;\n" + "DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n" + " int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(\n" + " input, &value)));\n" + "if ($type$_IsValid(value)) {\n" + " set_$name$(static_cast< $type$ >(value));\n"); + if (HasUnknownFields(descriptor_->file())) { + printer->Print(variables_, + "} else {\n" + " mutable_unknown_fields()->AddVarint($number$, value);\n"); + } + printer->Print(variables_, + "}\n"); +} + +void EnumFieldGenerator:: +GenerateSerializeWithCachedSizes(io::Printer* printer) const { + printer->Print(variables_, + "::google::protobuf::internal::WireFormatLite::WriteEnum(\n" + " $number$, this->$name$(), output);\n"); +} + +void EnumFieldGenerator:: +GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { + printer->Print(variables_, + "target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(\n" + " $number$, this->$name$(), target);\n"); +} + +void EnumFieldGenerator:: +GenerateByteSize(io::Printer* printer) const { + printer->Print(variables_, + "total_size += $tag_size$ +\n" + " ::google::protobuf::internal::WireFormatLite::EnumSize(this->$name$());\n"); +} + +// =================================================================== + +RepeatedEnumFieldGenerator:: +RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor) + : descriptor_(descriptor) { + SetEnumVariables(descriptor, &variables_); +} + +RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {} + +void RepeatedEnumFieldGenerator:: +GeneratePrivateMembers(io::Printer* printer) const { + printer->Print(variables_, + "::google::protobuf::RepeatedField $name$_;\n"); + if (descriptor_->options().packed() && HasGeneratedMethods(descriptor_->file())) { + printer->Print(variables_, + "mutable int _$name$_cached_byte_size_;\n"); + } +} + +void RepeatedEnumFieldGenerator:: +GenerateAccessorDeclarations(io::Printer* printer) const { + printer->Print(variables_, + "inline $type$ $name$(int index) const$deprecation$;\n" + "inline void set_$name$(int index, $type$ value)$deprecation$;\n" + "inline void add_$name$($type$ value)$deprecation$;\n"); + printer->Print(variables_, + "inline const ::google::protobuf::RepeatedField& $name$() const$deprecation$;\n" + "inline ::google::protobuf::RepeatedField* mutable_$name$()$deprecation$;\n"); +} + +void RepeatedEnumFieldGenerator:: +GenerateInlineAccessorDefinitions(io::Printer* printer) const { + printer->Print(variables_, + "inline $type$ $classname$::$name$(int index) const {\n" + " return static_cast< $type$ >($name$_.Get(index));\n" + "}\n" + "inline void $classname$::set_$name$(int index, $type$ value) {\n" + " GOOGLE_DCHECK($type$_IsValid(value));\n" + " $name$_.Set(index, value);\n" + "}\n" + "inline void $classname$::add_$name$($type$ value) {\n" + " GOOGLE_DCHECK($type$_IsValid(value));\n" + " $name$_.Add(value);\n" + "}\n"); + printer->Print(variables_, + "inline const ::google::protobuf::RepeatedField&\n" + "$classname$::$name$() const {\n" + " return $name$_;\n" + "}\n" + "inline ::google::protobuf::RepeatedField*\n" + "$classname$::mutable_$name$() {\n" + " return &$name$_;\n" + "}\n"); +} + +void RepeatedEnumFieldGenerator:: +GenerateClearingCode(io::Printer* printer) const { + printer->Print(variables_, "$name$_.Clear();\n"); +} + +void RepeatedEnumFieldGenerator:: +GenerateMergingCode(io::Printer* printer) const { + printer->Print(variables_, "$name$_.MergeFrom(from.$name$_);\n"); +} + +void RepeatedEnumFieldGenerator:: +GenerateSwappingCode(io::Printer* printer) const { + printer->Print(variables_, "$name$_.Swap(&other->$name$_);\n"); +} + +void RepeatedEnumFieldGenerator:: +GenerateConstructorCode(io::Printer* printer) const { + // Not needed for repeated fields. +} + +void RepeatedEnumFieldGenerator:: +GenerateMergeFromCodedStream(io::Printer* printer) const { + // Don't use ReadRepeatedPrimitive here so that the enum can be validated. + printer->Print(variables_, + "int value;\n" + "DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n" + " int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(\n" + " input, &value)));\n" + "if ($type$_IsValid(value)) {\n" + " add_$name$(static_cast< $type$ >(value));\n"); + if (HasUnknownFields(descriptor_->file())) { + printer->Print(variables_, + "} else {\n" + " mutable_unknown_fields()->AddVarint($number$, value);\n"); + } + printer->Print("}\n"); +} + +void RepeatedEnumFieldGenerator:: +GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const { + if (!descriptor_->options().packed()) { + // We use a non-inlined implementation in this case, since this path will + // rarely be executed. + printer->Print(variables_, + "DO_((::google::protobuf::internal::WireFormatLite::ReadPackedEnumNoInline(\n" + " input,\n" + " &$type$_IsValid,\n" + " this->mutable_$name$())));\n"); + } else { + printer->Print(variables_, + "::google::protobuf::uint32 length;\n" + "DO_(input->ReadVarint32(&length));\n" + "::google::protobuf::io::CodedInputStream::Limit limit = " + "input->PushLimit(length);\n" + "while (input->BytesUntilLimit() > 0) {\n" + " int value;\n" + " DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n" + " int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(\n" + " input, &value)));\n" + " if ($type$_IsValid(value)) {\n" + " add_$name$(static_cast< $type$ >(value));\n" + " }\n" + "}\n" + "input->PopLimit(limit);\n"); + } +} + +void RepeatedEnumFieldGenerator:: +GenerateSerializeWithCachedSizes(io::Printer* printer) const { + if (descriptor_->options().packed()) { + // Write the tag and the size. + printer->Print(variables_, + "if (this->$name$_size() > 0) {\n" + " ::google::protobuf::internal::WireFormatLite::WriteTag(\n" + " $number$,\n" + " ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,\n" + " output);\n" + " output->WriteVarint32(_$name$_cached_byte_size_);\n" + "}\n"); + } + printer->Print(variables_, + "for (int i = 0; i < this->$name$_size(); i++) {\n"); + if (descriptor_->options().packed()) { + printer->Print(variables_, + " ::google::protobuf::internal::WireFormatLite::WriteEnumNoTag(\n" + " this->$name$(i), output);\n"); + } else { + printer->Print(variables_, + " ::google::protobuf::internal::WireFormatLite::WriteEnum(\n" + " $number$, this->$name$(i), output);\n"); + } + printer->Print("}\n"); +} + +void RepeatedEnumFieldGenerator:: +GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { + if (descriptor_->options().packed()) { + // Write the tag and the size. + printer->Print(variables_, + "if (this->$name$_size() > 0) {\n" + " target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(\n" + " $number$,\n" + " ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,\n" + " target);\n" + " target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(" + " _$name$_cached_byte_size_, target);\n" + "}\n"); + } + printer->Print(variables_, + "for (int i = 0; i < this->$name$_size(); i++) {\n"); + if (descriptor_->options().packed()) { + printer->Print(variables_, + " target = ::google::protobuf::internal::WireFormatLite::WriteEnumNoTagToArray(\n" + " this->$name$(i), target);\n"); + } else { + printer->Print(variables_, + " target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(\n" + " $number$, this->$name$(i), target);\n"); + } + printer->Print("}\n"); +} + +void RepeatedEnumFieldGenerator:: +GenerateByteSize(io::Printer* printer) const { + printer->Print(variables_, + "{\n" + " int data_size = 0;\n"); + printer->Indent(); + printer->Print(variables_, + "for (int i = 0; i < this->$name$_size(); i++) {\n" + " data_size += ::google::protobuf::internal::WireFormatLite::EnumSize(\n" + " this->$name$(i));\n" + "}\n"); + + if (descriptor_->options().packed()) { + printer->Print(variables_, + "if (data_size > 0) {\n" + " total_size += $tag_size$ +\n" + " ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);\n" + "}\n" + "_$name$_cached_byte_size_ = data_size;\n" + "total_size += data_size;\n"); + } else { + printer->Print(variables_, + "total_size += $tag_size$ * this->$name$_size() + data_size;\n"); + } + printer->Outdent(); + printer->Print("}\n"); +} + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/depends/protobuf/google/protobuf/compiler/cpp/cpp_enum_field.h b/depends/protobuf/google/protobuf/compiler/cpp/cpp_enum_field.h new file mode 100644 index 0000000000..0793430c1d --- /dev/null +++ b/depends/protobuf/google/protobuf/compiler/cpp/cpp_enum_field.h @@ -0,0 +1,103 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_FIELD_H__ + +#include +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +class EnumFieldGenerator : public FieldGenerator { + public: + explicit EnumFieldGenerator(const FieldDescriptor* descriptor); + ~EnumFieldGenerator(); + + // implements FieldGenerator --------------------------------------- + void GeneratePrivateMembers(io::Printer* printer) const; + void GenerateAccessorDeclarations(io::Printer* printer) const; + void GenerateInlineAccessorDefinitions(io::Printer* printer) const; + void GenerateClearingCode(io::Printer* printer) const; + void GenerateMergingCode(io::Printer* printer) const; + void GenerateSwappingCode(io::Printer* printer) const; + void GenerateConstructorCode(io::Printer* printer) const; + void GenerateMergeFromCodedStream(io::Printer* printer) const; + void GenerateSerializeWithCachedSizes(io::Printer* printer) const; + void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const; + void GenerateByteSize(io::Printer* printer) const; + + private: + const FieldDescriptor* descriptor_; + map variables_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumFieldGenerator); +}; + +class RepeatedEnumFieldGenerator : public FieldGenerator { + public: + explicit RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor); + ~RepeatedEnumFieldGenerator(); + + // implements FieldGenerator --------------------------------------- + void GeneratePrivateMembers(io::Printer* printer) const; + void GenerateAccessorDeclarations(io::Printer* printer) const; + void GenerateInlineAccessorDefinitions(io::Printer* printer) const; + void GenerateClearingCode(io::Printer* printer) const; + void GenerateMergingCode(io::Printer* printer) const; + void GenerateSwappingCode(io::Printer* printer) const; + void GenerateConstructorCode(io::Printer* printer) const; + void GenerateMergeFromCodedStream(io::Printer* printer) const; + void GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const; + void GenerateSerializeWithCachedSizes(io::Printer* printer) const; + void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const; + void GenerateByteSize(io::Printer* printer) const; + + private: + const FieldDescriptor* descriptor_; + map variables_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedEnumFieldGenerator); +}; + +} // namespace cpp +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_FIELD_H__ diff --git a/depends/protobuf/google/protobuf/compiler/cpp/cpp_extension.cc b/depends/protobuf/google/protobuf/compiler/cpp/cpp_extension.cc new file mode 100644 index 0000000000..658a7077bb --- /dev/null +++ b/depends/protobuf/google/protobuf/compiler/cpp/cpp_extension.cc @@ -0,0 +1,210 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +namespace { + +// Returns the fully-qualified class name of the message that this field +// extends. This function is used in the Google-internal code to handle some +// legacy cases. +string ExtendeeClassName(const FieldDescriptor* descriptor) { + const Descriptor* extendee = descriptor->containing_type(); + return ClassName(extendee, true); +} + +} // anonymous namespace + +ExtensionGenerator::ExtensionGenerator(const FieldDescriptor* descriptor, + const string& dllexport_decl) + : descriptor_(descriptor), + dllexport_decl_(dllexport_decl) { + // Construct type_traits_. + if (descriptor_->is_repeated()) { + type_traits_ = "Repeated"; + } + + switch (descriptor_->cpp_type()) { + case FieldDescriptor::CPPTYPE_ENUM: + type_traits_.append("EnumTypeTraits< "); + type_traits_.append(ClassName(descriptor_->enum_type(), true)); + type_traits_.append(", "); + type_traits_.append(ClassName(descriptor_->enum_type(), true)); + type_traits_.append("_IsValid>"); + break; + case FieldDescriptor::CPPTYPE_STRING: + type_traits_.append("StringTypeTraits"); + break; + case FieldDescriptor::CPPTYPE_MESSAGE: + type_traits_.append("MessageTypeTraits< "); + type_traits_.append(ClassName(descriptor_->message_type(), true)); + type_traits_.append(" >"); + break; + default: + type_traits_.append("PrimitiveTypeTraits< "); + type_traits_.append(PrimitiveTypeName(descriptor_->cpp_type())); + type_traits_.append(" >"); + break; + } +} + +ExtensionGenerator::~ExtensionGenerator() {} + +void ExtensionGenerator::GenerateDeclaration(io::Printer* printer) { + map vars; + vars["extendee" ] = ExtendeeClassName(descriptor_); + vars["number" ] = SimpleItoa(descriptor_->number()); + vars["type_traits" ] = type_traits_; + vars["name" ] = descriptor_->name(); + vars["field_type" ] = SimpleItoa(static_cast(descriptor_->type())); + vars["packed" ] = descriptor_->options().packed() ? "true" : "false"; + vars["constant_name"] = FieldConstantName(descriptor_); + + // If this is a class member, it needs to be declared "static". Otherwise, + // it needs to be "extern". In the latter case, it also needs the DLL + // export/import specifier. + if (descriptor_->extension_scope() == NULL) { + vars["qualifier"] = "extern"; + if (!dllexport_decl_.empty()) { + vars["qualifier"] = dllexport_decl_ + " " + vars["qualifier"]; + } + } else { + vars["qualifier"] = "static"; + } + + printer->Print(vars, + "static const int $constant_name$ = $number$;\n" + "$qualifier$ ::google::protobuf::internal::ExtensionIdentifier< $extendee$,\n" + " ::google::protobuf::internal::$type_traits$, $field_type$, $packed$ >\n" + " $name$;\n" + ); + +} + +void ExtensionGenerator::GenerateDefinition(io::Printer* printer) { + // If this is a class member, it needs to be declared in its class scope. + string scope = (descriptor_->extension_scope() == NULL) ? "" : + ClassName(descriptor_->extension_scope(), false) + "::"; + string name = scope + descriptor_->name(); + + map vars; + vars["extendee" ] = ExtendeeClassName(descriptor_); + vars["type_traits" ] = type_traits_; + vars["name" ] = name; + vars["constant_name"] = FieldConstantName(descriptor_); + vars["default" ] = DefaultValue(descriptor_); + vars["field_type" ] = SimpleItoa(static_cast(descriptor_->type())); + vars["packed" ] = descriptor_->options().packed() ? "true" : "false"; + vars["scope" ] = scope; + + if (descriptor_->cpp_type() == FieldDescriptor::CPPTYPE_STRING) { + // We need to declare a global string which will contain the default value. + // We cannot declare it at class scope because that would require exposing + // it in the header which would be annoying for other reasons. So we + // replace :: with _ in the name and declare it as a global. + string global_name = StringReplace(name, "::", "_", true); + vars["global_name"] = global_name; + printer->Print(vars, + "const ::std::string $global_name$_default($default$);\n"); + + // Update the default to refer to the string global. + vars["default"] = global_name + "_default"; + } + + // Likewise, class members need to declare the field constant variable. + if (descriptor_->extension_scope() != NULL) { + printer->Print(vars, + "#ifndef _MSC_VER\n" + "const int $scope$$constant_name$;\n" + "#endif\n"); + } + + printer->Print(vars, + "::google::protobuf::internal::ExtensionIdentifier< $extendee$,\n" + " ::google::protobuf::internal::$type_traits$, $field_type$, $packed$ >\n" + " $name$($constant_name$, $default$);\n"); +} + +void ExtensionGenerator::GenerateRegistration(io::Printer* printer) { + map vars; + vars["extendee" ] = ExtendeeClassName(descriptor_); + vars["number" ] = SimpleItoa(descriptor_->number()); + vars["field_type" ] = SimpleItoa(static_cast(descriptor_->type())); + vars["is_repeated"] = descriptor_->is_repeated() ? "true" : "false"; + vars["is_packed" ] = (descriptor_->is_repeated() && + descriptor_->options().packed()) + ? "true" : "false"; + + switch (descriptor_->cpp_type()) { + case FieldDescriptor::CPPTYPE_ENUM: + printer->Print(vars, + "::google::protobuf::internal::ExtensionSet::RegisterEnumExtension(\n" + " &$extendee$::default_instance(),\n" + " $number$, $field_type$, $is_repeated$, $is_packed$,\n"); + printer->Print( + " &$type$_IsValid);\n", + "type", ClassName(descriptor_->enum_type(), true)); + break; + case FieldDescriptor::CPPTYPE_MESSAGE: + printer->Print(vars, + "::google::protobuf::internal::ExtensionSet::RegisterMessageExtension(\n" + " &$extendee$::default_instance(),\n" + " $number$, $field_type$, $is_repeated$, $is_packed$,\n"); + printer->Print( + " &$type$::default_instance());\n", + "type", ClassName(descriptor_->message_type(), true)); + break; + default: + printer->Print(vars, + "::google::protobuf::internal::ExtensionSet::RegisterExtension(\n" + " &$extendee$::default_instance(),\n" + " $number$, $field_type$, $is_repeated$, $is_packed$);\n"); + break; + } +} + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/depends/protobuf/google/protobuf/compiler/cpp/cpp_extension.h b/depends/protobuf/google/protobuf/compiler/cpp/cpp_extension.h new file mode 100644 index 0000000000..3068b09148 --- /dev/null +++ b/depends/protobuf/google/protobuf/compiler/cpp/cpp_extension.h @@ -0,0 +1,85 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_EXTENSION_H__ +#define GOOGLE_PROTOBUF_COMPILER_CPP_EXTENSION_H__ + +#include +#include + +namespace google { +namespace protobuf { + class FieldDescriptor; // descriptor.h + namespace io { + class Printer; // printer.h + } +} + +namespace protobuf { +namespace compiler { +namespace cpp { + +// Generates code for an extension, which may be within the scope of some +// message or may be at file scope. This is much simpler than FieldGenerator +// since extensions are just simple identifiers with interesting types. +class ExtensionGenerator { + public: + // See generator.cc for the meaning of dllexport_decl. + explicit ExtensionGenerator(const FieldDescriptor* descriptor, + const string& dllexport_decl); + ~ExtensionGenerator(); + + // Header stuff. + void GenerateDeclaration(io::Printer* printer); + + // Source file stuff. + void GenerateDefinition(io::Printer* printer); + + // Generate code to register the extension. + void GenerateRegistration(io::Printer* printer); + + private: + const FieldDescriptor* descriptor_; + string type_traits_; + string dllexport_decl_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ExtensionGenerator); +}; + +} // namespace cpp +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_H__ diff --git a/depends/protobuf/google/protobuf/compiler/cpp/cpp_field.cc b/depends/protobuf/google/protobuf/compiler/cpp/cpp_field.cc new file mode 100644 index 0000000000..103cac4a9f --- /dev/null +++ b/depends/protobuf/google/protobuf/compiler/cpp/cpp_field.cc @@ -0,0 +1,139 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +using internal::WireFormat; + +void SetCommonFieldVariables(const FieldDescriptor* descriptor, + map* variables) { + (*variables)["name"] = FieldName(descriptor); + (*variables)["index"] = SimpleItoa(descriptor->index()); + (*variables)["number"] = SimpleItoa(descriptor->number()); + (*variables)["classname"] = ClassName(FieldScope(descriptor), false); + (*variables)["declared_type"] = DeclaredTypeMethodName(descriptor->type()); + + (*variables)["tag_size"] = SimpleItoa( + WireFormat::TagSize(descriptor->number(), descriptor->type())); + (*variables)["deprecation"] = descriptor->options().deprecated() + ? " PROTOBUF_DEPRECATED" : ""; + +} + +FieldGenerator::~FieldGenerator() {} + +void FieldGenerator:: +GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const { + // Reaching here indicates a bug. Cases are: + // - This FieldGenerator should support packing, but this method should be + // overridden. + // - This FieldGenerator doesn't support packing, and this method should + // never have been called. + GOOGLE_LOG(FATAL) << "GenerateMergeFromCodedStreamWithPacking() " + << "called on field generator that does not support packing."; + +} + +FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor) + : descriptor_(descriptor), + field_generators_( + new scoped_ptr[descriptor->field_count()]) { + // Construct all the FieldGenerators. + for (int i = 0; i < descriptor->field_count(); i++) { + field_generators_[i].reset(MakeGenerator(descriptor->field(i))); + } +} + +FieldGenerator* FieldGeneratorMap::MakeGenerator(const FieldDescriptor* field) { + if (field->is_repeated()) { + switch (field->cpp_type()) { + case FieldDescriptor::CPPTYPE_MESSAGE: + return new RepeatedMessageFieldGenerator(field); + case FieldDescriptor::CPPTYPE_STRING: + switch (field->options().ctype()) { + default: // RepeatedStringFieldGenerator handles unknown ctypes. + case FieldOptions::STRING: + return new RepeatedStringFieldGenerator(field); + } + case FieldDescriptor::CPPTYPE_ENUM: + return new RepeatedEnumFieldGenerator(field); + default: + return new RepeatedPrimitiveFieldGenerator(field); + } + } else { + switch (field->cpp_type()) { + case FieldDescriptor::CPPTYPE_MESSAGE: + return new MessageFieldGenerator(field); + case FieldDescriptor::CPPTYPE_STRING: + switch (field->options().ctype()) { + default: // StringFieldGenerator handles unknown ctypes. + case FieldOptions::STRING: + return new StringFieldGenerator(field); + } + case FieldDescriptor::CPPTYPE_ENUM: + return new EnumFieldGenerator(field); + default: + return new PrimitiveFieldGenerator(field); + } + } +} + +FieldGeneratorMap::~FieldGeneratorMap() {} + +const FieldGenerator& FieldGeneratorMap::get( + const FieldDescriptor* field) const { + GOOGLE_CHECK_EQ(field->containing_type(), descriptor_); + return *field_generators_[field->index()]; +} + + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/depends/protobuf/google/protobuf/compiler/cpp/cpp_field.h b/depends/protobuf/google/protobuf/compiler/cpp/cpp_field.h new file mode 100644 index 0000000000..c303a3378f --- /dev/null +++ b/depends/protobuf/google/protobuf/compiler/cpp/cpp_field.h @@ -0,0 +1,167 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_CPP_FIELD_H__ + +#include +#include + +#include +#include + +namespace google { +namespace protobuf { + namespace io { + class Printer; // printer.h + } +} + +namespace protobuf { +namespace compiler { +namespace cpp { + +// Helper function: set variables in the map that are the same for all +// field code generators. +// ['name', 'index', 'number', 'classname', 'declared_type', 'tag_size', +// 'deprecation']. +void SetCommonFieldVariables(const FieldDescriptor* descriptor, + map* variables); + +class FieldGenerator { + public: + FieldGenerator() {} + virtual ~FieldGenerator(); + + // Generate lines of code declaring members fields of the message class + // needed to represent this field. These are placed inside the message + // class. + virtual void GeneratePrivateMembers(io::Printer* printer) const = 0; + + // Generate prototypes for all of the accessor functions related to this + // field. These are placed inside the class definition. + virtual void GenerateAccessorDeclarations(io::Printer* printer) const = 0; + + // Generate inline definitions of accessor functions for this field. + // These are placed inside the header after all class definitions. + virtual void GenerateInlineAccessorDefinitions( + io::Printer* printer) const = 0; + + // Generate definitions of accessors that aren't inlined. These are + // placed somewhere in the .cc file. + // Most field types don't need this, so the default implementation is empty. + virtual void GenerateNonInlineAccessorDefinitions( + io::Printer* printer) const {} + + // Generate lines of code (statements, not declarations) which clear the + // field. This is used to define the clear_$name$() method as well as + // the Clear() method for the whole message. + virtual void GenerateClearingCode(io::Printer* printer) const = 0; + + // Generate lines of code (statements, not declarations) which merges the + // contents of the field from the current message to the target message, + // which is stored in the generated code variable "from". + // This is used to fill in the MergeFrom method for the whole message. + // Details of this usage can be found in message.cc under the + // GenerateMergeFrom method. + virtual void GenerateMergingCode(io::Printer* printer) const = 0; + + // Generate lines of code (statements, not declarations) which swaps + // this field and the corresponding field of another message, which + // is stored in the generated code variable "other". This is used to + // define the Swap method. Details of usage can be found in + // message.cc under the GenerateSwap method. + virtual void GenerateSwappingCode(io::Printer* printer) const = 0; + + // Generate initialization code for private members declared by + // GeneratePrivateMembers(). These go into the message class's SharedCtor() + // method, invoked by each of the generated constructors. + virtual void GenerateConstructorCode(io::Printer* printer) const = 0; + + // Generate any code that needs to go in the class's SharedDtor() method, + // invoked by the destructor. + // Most field types don't need this, so the default implementation is empty. + virtual void GenerateDestructorCode(io::Printer* printer) const {} + + // Generate lines to decode this field, which will be placed inside the + // message's MergeFromCodedStream() method. + virtual void GenerateMergeFromCodedStream(io::Printer* printer) const = 0; + + // Generate lines to decode this field from a packed value, which will be + // placed inside the message's MergeFromCodedStream() method. + virtual void GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) + const; + + // Generate lines to serialize this field, which are placed within the + // message's SerializeWithCachedSizes() method. + virtual void GenerateSerializeWithCachedSizes(io::Printer* printer) const = 0; + + // Generate lines to serialize this field directly to the array "target", + // which are placed within the message's SerializeWithCachedSizesToArray() + // method. This must also advance "target" past the written bytes. + virtual void GenerateSerializeWithCachedSizesToArray( + io::Printer* printer) const = 0; + + // Generate lines to compute the serialized size of this field, which + // are placed in the message's ByteSize() method. + virtual void GenerateByteSize(io::Printer* printer) const = 0; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGenerator); +}; + +// Convenience class which constructs FieldGenerators for a Descriptor. +class FieldGeneratorMap { + public: + explicit FieldGeneratorMap(const Descriptor* descriptor); + ~FieldGeneratorMap(); + + const FieldGenerator& get(const FieldDescriptor* field) const; + + private: + const Descriptor* descriptor_; + scoped_array > field_generators_; + + static FieldGenerator* MakeGenerator(const FieldDescriptor* field); + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGeneratorMap); +}; + + +} // namespace cpp +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_CPP_FIELD_H__ diff --git a/depends/protobuf/google/protobuf/compiler/cpp/cpp_file.cc b/depends/protobuf/google/protobuf/compiler/cpp/cpp_file.cc new file mode 100644 index 0000000000..312ebc86d2 --- /dev/null +++ b/depends/protobuf/google/protobuf/compiler/cpp/cpp_file.cc @@ -0,0 +1,611 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +// =================================================================== + +FileGenerator::FileGenerator(const FileDescriptor* file, + const string& dllexport_decl) + : file_(file), + message_generators_( + new scoped_ptr[file->message_type_count()]), + enum_generators_( + new scoped_ptr[file->enum_type_count()]), + service_generators_( + new scoped_ptr[file->service_count()]), + extension_generators_( + new scoped_ptr[file->extension_count()]), + dllexport_decl_(dllexport_decl) { + + for (int i = 0; i < file->message_type_count(); i++) { + message_generators_[i].reset( + new MessageGenerator(file->message_type(i), dllexport_decl)); + } + + for (int i = 0; i < file->enum_type_count(); i++) { + enum_generators_[i].reset( + new EnumGenerator(file->enum_type(i), dllexport_decl)); + } + + for (int i = 0; i < file->service_count(); i++) { + service_generators_[i].reset( + new ServiceGenerator(file->service(i), dllexport_decl)); + } + + for (int i = 0; i < file->extension_count(); i++) { + extension_generators_[i].reset( + new ExtensionGenerator(file->extension(i), dllexport_decl)); + } + + SplitStringUsing(file_->package(), ".", &package_parts_); +} + +FileGenerator::~FileGenerator() {} + +void FileGenerator::GenerateHeader(io::Printer* printer) { + string filename_identifier = FilenameIdentifier(file_->name()); + + // Generate top of header. + printer->Print( + "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" + "// source: $filename$\n" + "\n" + "#ifndef PROTOBUF_$filename_identifier$__INCLUDED\n" + "#define PROTOBUF_$filename_identifier$__INCLUDED\n" + "\n" + "#include \n" + "\n", + "filename", file_->name(), + "filename_identifier", filename_identifier); + + printer->Print( + "#include \n" + "\n"); + + // Verify the protobuf library header version is compatible with the protoc + // version before going any further. + printer->Print( + "#if GOOGLE_PROTOBUF_VERSION < $min_header_version$\n" + "#error This file was generated by a newer version of protoc which is\n" + "#error incompatible with your Protocol Buffer headers. Please update\n" + "#error your headers.\n" + "#endif\n" + "#if $protoc_version$ < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION\n" + "#error This file was generated by an older version of protoc which is\n" + "#error incompatible with your Protocol Buffer headers. Please\n" + "#error regenerate this file with a newer version of protoc.\n" + "#endif\n" + "\n", + "min_header_version", + SimpleItoa(protobuf::internal::kMinHeaderVersionForProtoc), + "protoc_version", SimpleItoa(GOOGLE_PROTOBUF_VERSION)); + + // OK, it's now safe to #include other files. + printer->Print( + "#include \n" + "#include \n" + "#include \n"); + + if (HasDescriptorMethods(file_)) { + printer->Print( + "#include \n"); + } + + if (HasGenericServices(file_)) { + printer->Print( + "#include \n"); + } + + + for (int i = 0; i < file_->dependency_count(); i++) { + printer->Print( + "#include \"$dependency$.pb.h\"\n", + "dependency", StripProto(file_->dependency(i)->name())); + } + + printer->Print( + "// @@protoc_insertion_point(includes)\n"); + + // Open namespace. + GenerateNamespaceOpeners(printer); + + // Forward-declare the AddDescriptors, AssignDescriptors, and ShutdownFile + // functions, so that we can declare them to be friends of each class. + printer->Print( + "\n" + "// Internal implementation detail -- do not call these.\n" + "void $dllexport_decl$ $adddescriptorsname$();\n", + "adddescriptorsname", GlobalAddDescriptorsName(file_->name()), + "dllexport_decl", dllexport_decl_); + + printer->Print( + // Note that we don't put dllexport_decl on these because they are only + // called by the .pb.cc file in which they are defined. + "void $assigndescriptorsname$();\n" + "void $shutdownfilename$();\n" + "\n", + "assigndescriptorsname", GlobalAssignDescriptorsName(file_->name()), + "shutdownfilename", GlobalShutdownFileName(file_->name())); + + // Generate forward declarations of classes. + for (int i = 0; i < file_->message_type_count(); i++) { + message_generators_[i]->GenerateForwardDeclaration(printer); + } + + printer->Print("\n"); + + // Generate enum definitions. + for (int i = 0; i < file_->message_type_count(); i++) { + message_generators_[i]->GenerateEnumDefinitions(printer); + } + for (int i = 0; i < file_->enum_type_count(); i++) { + enum_generators_[i]->GenerateDefinition(printer); + } + + printer->Print(kThickSeparator); + printer->Print("\n"); + + // Generate class definitions. + for (int i = 0; i < file_->message_type_count(); i++) { + if (i > 0) { + printer->Print("\n"); + printer->Print(kThinSeparator); + printer->Print("\n"); + } + message_generators_[i]->GenerateClassDefinition(printer); + } + + printer->Print("\n"); + printer->Print(kThickSeparator); + printer->Print("\n"); + + if (HasGenericServices(file_)) { + // Generate service definitions. + for (int i = 0; i < file_->service_count(); i++) { + if (i > 0) { + printer->Print("\n"); + printer->Print(kThinSeparator); + printer->Print("\n"); + } + service_generators_[i]->GenerateDeclarations(printer); + } + + printer->Print("\n"); + printer->Print(kThickSeparator); + printer->Print("\n"); + } + + // Declare extension identifiers. + for (int i = 0; i < file_->extension_count(); i++) { + extension_generators_[i]->GenerateDeclaration(printer); + } + + printer->Print("\n"); + printer->Print(kThickSeparator); + printer->Print("\n"); + + // Generate class inline methods. + for (int i = 0; i < file_->message_type_count(); i++) { + if (i > 0) { + printer->Print(kThinSeparator); + printer->Print("\n"); + } + message_generators_[i]->GenerateInlineMethods(printer); + } + + printer->Print( + "\n" + "// @@protoc_insertion_point(namespace_scope)\n"); + + // Close up namespace. + GenerateNamespaceClosers(printer); + + // Emit GetEnumDescriptor specializations into google::protobuf namespace: + if (HasDescriptorMethods(file_)) { + // The SWIG conditional is to avoid a null-pointer dereference + // (bug 1984964) in swig-1.3.21 resulting from the following syntax: + // namespace X { void Y(); } + // which appears in GetEnumDescriptor() specializations. + printer->Print( + "\n" + "#ifndef SWIG\n" + "namespace google {\nnamespace protobuf {\n" + "\n"); + for (int i = 0; i < file_->message_type_count(); i++) { + message_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer); + } + for (int i = 0; i < file_->enum_type_count(); i++) { + enum_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer); + } + printer->Print( + "\n" + "} // namespace google\n} // namespace protobuf\n" + "#endif // SWIG\n"); + } + + printer->Print( + "\n" + "// @@protoc_insertion_point(global_scope)\n" + "\n"); + + printer->Print( + "#endif // PROTOBUF_$filename_identifier$__INCLUDED\n", + "filename_identifier", filename_identifier); +} + +void FileGenerator::GenerateSource(io::Printer* printer) { + printer->Print( + "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" + "\n" + + // The generated code calls accessors that might be deprecated. We don't + // want the compiler to warn in generated code. + "#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION\n" + "#include \"$basename$.pb.h\"\n" + "\n" + "#include \n" // for swap() + "\n" + "#include \n" + "#include \n" + "#include \n", + "basename", StripProto(file_->name())); + + if (HasDescriptorMethods(file_)) { + printer->Print( + "#include \n" + "#include \n" + "#include \n"); + } + + printer->Print( + "// @@protoc_insertion_point(includes)\n"); + + GenerateNamespaceOpeners(printer); + + if (HasDescriptorMethods(file_)) { + printer->Print( + "\n" + "namespace {\n" + "\n"); + for (int i = 0; i < file_->message_type_count(); i++) { + message_generators_[i]->GenerateDescriptorDeclarations(printer); + } + for (int i = 0; i < file_->enum_type_count(); i++) { + printer->Print( + "const ::google::protobuf::EnumDescriptor* $name$_descriptor_ = NULL;\n", + "name", ClassName(file_->enum_type(i), false)); + } + + if (HasGenericServices(file_)) { + for (int i = 0; i < file_->service_count(); i++) { + printer->Print( + "const ::google::protobuf::ServiceDescriptor* $name$_descriptor_ = NULL;\n", + "name", file_->service(i)->name()); + } + } + + printer->Print( + "\n" + "} // namespace\n" + "\n"); + } + + // Define our externally-visible BuildDescriptors() function. (For the lite + // library, all this does is initialize default instances.) + GenerateBuildDescriptors(printer); + + // Generate enums. + for (int i = 0; i < file_->enum_type_count(); i++) { + enum_generators_[i]->GenerateMethods(printer); + } + + // Generate classes. + for (int i = 0; i < file_->message_type_count(); i++) { + printer->Print("\n"); + printer->Print(kThickSeparator); + printer->Print("\n"); + message_generators_[i]->GenerateClassMethods(printer); + } + + if (HasGenericServices(file_)) { + // Generate services. + for (int i = 0; i < file_->service_count(); i++) { + if (i == 0) printer->Print("\n"); + printer->Print(kThickSeparator); + printer->Print("\n"); + service_generators_[i]->GenerateImplementation(printer); + } + } + + // Define extensions. + for (int i = 0; i < file_->extension_count(); i++) { + extension_generators_[i]->GenerateDefinition(printer); + } + + printer->Print( + "\n" + "// @@protoc_insertion_point(namespace_scope)\n"); + + GenerateNamespaceClosers(printer); + + printer->Print( + "\n" + "// @@protoc_insertion_point(global_scope)\n"); +} + +void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { + // AddDescriptors() is a file-level procedure which adds the encoded + // FileDescriptorProto for this .proto file to the global DescriptorPool + // for generated files (DescriptorPool::generated_pool()). It always runs + // at static initialization time, so all files will be registered before + // main() starts. This procedure also constructs default instances and + // registers extensions. + // + // Its sibling, AssignDescriptors(), actually pulls the compiled + // FileDescriptor from the DescriptorPool and uses it to populate all of + // the global variables which store pointers to the descriptor objects. + // It also constructs the reflection objects. It is called the first time + // anyone calls descriptor() or GetReflection() on one of the types defined + // in the file. + + // In optimize_for = LITE_RUNTIME mode, we don't generate AssignDescriptors() + // and we only use AddDescriptors() to allocate default instances. + if (HasDescriptorMethods(file_)) { + printer->Print( + "\n" + "void $assigndescriptorsname$() {\n", + "assigndescriptorsname", GlobalAssignDescriptorsName(file_->name())); + printer->Indent(); + + // Make sure the file has found its way into the pool. If a descriptor + // is requested *during* static init then AddDescriptors() may not have + // been called yet, so we call it manually. Note that it's fine if + // AddDescriptors() is called multiple times. + printer->Print( + "$adddescriptorsname$();\n", + "adddescriptorsname", GlobalAddDescriptorsName(file_->name())); + + // Get the file's descriptor from the pool. + printer->Print( + "const ::google::protobuf::FileDescriptor* file =\n" + " ::google::protobuf::DescriptorPool::generated_pool()->FindFileByName(\n" + " \"$filename$\");\n" + // Note that this GOOGLE_CHECK is necessary to prevent a warning about "file" + // being unused when compiling an empty .proto file. + "GOOGLE_CHECK(file != NULL);\n", + "filename", file_->name()); + + // Go through all the stuff defined in this file and generated code to + // assign the global descriptor pointers based on the file descriptor. + for (int i = 0; i < file_->message_type_count(); i++) { + message_generators_[i]->GenerateDescriptorInitializer(printer, i); + } + for (int i = 0; i < file_->enum_type_count(); i++) { + enum_generators_[i]->GenerateDescriptorInitializer(printer, i); + } + if (HasGenericServices(file_)) { + for (int i = 0; i < file_->service_count(); i++) { + service_generators_[i]->GenerateDescriptorInitializer(printer, i); + } + } + + printer->Outdent(); + printer->Print( + "}\n" + "\n"); + + // --------------------------------------------------------------- + + // protobuf_AssignDescriptorsOnce(): The first time it is called, calls + // AssignDescriptors(). All later times, waits for the first call to + // complete and then returns. + printer->Print( + "namespace {\n" + "\n" + "GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_);\n" + "inline void protobuf_AssignDescriptorsOnce() {\n" + " ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_,\n" + " &$assigndescriptorsname$);\n" + "}\n" + "\n", + "assigndescriptorsname", GlobalAssignDescriptorsName(file_->name())); + + // protobuf_RegisterTypes(): Calls + // MessageFactory::InternalRegisterGeneratedType() for each message type. + printer->Print( + "void protobuf_RegisterTypes(const ::std::string&) {\n" + " protobuf_AssignDescriptorsOnce();\n"); + printer->Indent(); + + for (int i = 0; i < file_->message_type_count(); i++) { + message_generators_[i]->GenerateTypeRegistrations(printer); + } + + printer->Outdent(); + printer->Print( + "}\n" + "\n" + "} // namespace\n"); + } + + // ----------------------------------------------------------------- + + // ShutdownFile(): Deletes descriptors, default instances, etc. on shutdown. + printer->Print( + "\n" + "void $shutdownfilename$() {\n", + "shutdownfilename", GlobalShutdownFileName(file_->name())); + printer->Indent(); + + for (int i = 0; i < file_->message_type_count(); i++) { + message_generators_[i]->GenerateShutdownCode(printer); + } + + printer->Outdent(); + printer->Print( + "}\n"); + + // ----------------------------------------------------------------- + + // Now generate the AddDescriptors() function. + printer->Print( + "\n" + "void $adddescriptorsname$() {\n" + // We don't need any special synchronization here because this code is + // called at static init time before any threads exist. + " static bool already_here = false;\n" + " if (already_here) return;\n" + " already_here = true;\n" + " GOOGLE_PROTOBUF_VERIFY_VERSION;\n" + "\n", + "adddescriptorsname", GlobalAddDescriptorsName(file_->name())); + printer->Indent(); + + // Call the AddDescriptors() methods for all of our dependencies, to make + // sure they get added first. + for (int i = 0; i < file_->dependency_count(); i++) { + const FileDescriptor* dependency = file_->dependency(i); + // Print the namespace prefix for the dependency. + vector dependency_package_parts; + SplitStringUsing(dependency->package(), ".", &dependency_package_parts); + printer->Print("::"); + for (int i = 0; i < dependency_package_parts.size(); i++) { + printer->Print("$name$::", + "name", dependency_package_parts[i]); + } + // Call its AddDescriptors function. + printer->Print( + "$name$();\n", + "name", GlobalAddDescriptorsName(dependency->name())); + } + + if (HasDescriptorMethods(file_)) { + // Embed the descriptor. We simply serialize the entire FileDescriptorProto + // and embed it as a string literal, which is parsed and built into real + // descriptors at initialization time. + FileDescriptorProto file_proto; + file_->CopyTo(&file_proto); + string file_data; + file_proto.SerializeToString(&file_data); + + printer->Print( + "::google::protobuf::DescriptorPool::InternalAddGeneratedFile("); + + // Only write 40 bytes per line. + static const int kBytesPerLine = 40; + for (int i = 0; i < file_data.size(); i += kBytesPerLine) { + printer->Print("\n \"$data$\"", + "data", EscapeTrigraphs(CEscape(file_data.substr(i, kBytesPerLine)))); + } + printer->Print( + ", $size$);\n", + "size", SimpleItoa(file_data.size())); + + // Call MessageFactory::InternalRegisterGeneratedFile(). + printer->Print( + "::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(\n" + " \"$filename$\", &protobuf_RegisterTypes);\n", + "filename", file_->name()); + } + + // Allocate and initialize default instances. This can't be done lazily + // since default instances are returned by simple accessors and are used with + // extensions. Speaking of which, we also register extensions at this time. + for (int i = 0; i < file_->message_type_count(); i++) { + message_generators_[i]->GenerateDefaultInstanceAllocator(printer); + } + for (int i = 0; i < file_->extension_count(); i++) { + extension_generators_[i]->GenerateRegistration(printer); + } + for (int i = 0; i < file_->message_type_count(); i++) { + message_generators_[i]->GenerateDefaultInstanceInitializer(printer); + } + + printer->Print( + "::google::protobuf::internal::OnShutdown(&$shutdownfilename$);\n", + "shutdownfilename", GlobalShutdownFileName(file_->name())); + + printer->Outdent(); + + printer->Print( + "}\n" + "\n" + "// Force AddDescriptors() to be called at static initialization time.\n" + "struct StaticDescriptorInitializer_$filename$ {\n" + " StaticDescriptorInitializer_$filename$() {\n" + " $adddescriptorsname$();\n" + " }\n" + "} static_descriptor_initializer_$filename$_;\n" + "\n", + "adddescriptorsname", GlobalAddDescriptorsName(file_->name()), + "filename", FilenameIdentifier(file_->name())); +} + +void FileGenerator::GenerateNamespaceOpeners(io::Printer* printer) { + if (package_parts_.size() > 0) printer->Print("\n"); + + for (int i = 0; i < package_parts_.size(); i++) { + printer->Print("namespace $part$ {\n", + "part", package_parts_[i]); + } +} + +void FileGenerator::GenerateNamespaceClosers(io::Printer* printer) { + if (package_parts_.size() > 0) printer->Print("\n"); + + for (int i = package_parts_.size() - 1; i >= 0; i--) { + printer->Print("} // namespace $part$\n", + "part", package_parts_[i]); + } +} + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/depends/protobuf/google/protobuf/compiler/cpp/cpp_file.h b/depends/protobuf/google/protobuf/compiler/cpp/cpp_file.h new file mode 100644 index 0000000000..b4e012857d --- /dev/null +++ b/depends/protobuf/google/protobuf/compiler/cpp/cpp_file.h @@ -0,0 +1,98 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_FILE_H__ +#define GOOGLE_PROTOBUF_COMPILER_CPP_FILE_H__ + +#include +#include +#include +#include + +namespace google { +namespace protobuf { + class FileDescriptor; // descriptor.h + namespace io { + class Printer; // printer.h + } +} + +namespace protobuf { +namespace compiler { +namespace cpp { + +class EnumGenerator; // enum.h +class MessageGenerator; // message.h +class ServiceGenerator; // service.h +class ExtensionGenerator; // extension.h + +class FileGenerator { + public: + // See generator.cc for the meaning of dllexport_decl. + explicit FileGenerator(const FileDescriptor* file, + const string& dllexport_decl); + ~FileGenerator(); + + void GenerateHeader(io::Printer* printer); + void GenerateSource(io::Printer* printer); + + private: + // Generate the BuildDescriptors() procedure, which builds all descriptors + // for types defined in the file. + void GenerateBuildDescriptors(io::Printer* printer); + + void GenerateNamespaceOpeners(io::Printer* printer); + void GenerateNamespaceClosers(io::Printer* printer); + + const FileDescriptor* file_; + + scoped_array > message_generators_; + scoped_array > enum_generators_; + scoped_array > service_generators_; + scoped_array > extension_generators_; + + // E.g. if the package is foo.bar, package_parts_ is {"foo", "bar"}. + vector package_parts_; + + string dllexport_decl_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileGenerator); +}; + +} // namespace cpp +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_CPP_FILE_H__ diff --git a/depends/protobuf/google/protobuf/compiler/cpp/cpp_generator.cc b/depends/protobuf/google/protobuf/compiler/cpp/cpp_generator.cc new file mode 100644 index 0000000000..bb84e2ab46 --- /dev/null +++ b/depends/protobuf/google/protobuf/compiler/cpp/cpp_generator.cc @@ -0,0 +1,122 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include + +#include +#include + +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +CppGenerator::CppGenerator() {} +CppGenerator::~CppGenerator() {} + +bool CppGenerator::Generate(const FileDescriptor* file, + const string& parameter, + GeneratorContext* generator_context, + string* error) const { + vector > options; + ParseGeneratorParameter(parameter, &options); + + // ----------------------------------------------------------------- + // parse generator options + + // TODO(kenton): If we ever have more options, we may want to create a + // class that encapsulates them which we can pass down to all the + // generator classes. Currently we pass dllexport_decl down to all of + // them via the constructors, but we don't want to have to add another + // constructor parameter for every option. + + // If the dllexport_decl option is passed to the compiler, we need to write + // it in front of every symbol that should be exported if this .proto is + // compiled into a Windows DLL. E.g., if the user invokes the protocol + // compiler as: + // protoc --cpp_out=dllexport_decl=FOO_EXPORT:outdir foo.proto + // then we'll define classes like this: + // class FOO_EXPORT Foo { + // ... + // } + // FOO_EXPORT is a macro which should expand to __declspec(dllexport) or + // __declspec(dllimport) depending on what is being compiled. + string dllexport_decl; + + for (int i = 0; i < options.size(); i++) { + if (options[i].first == "dllexport_decl") { + dllexport_decl = options[i].second; + } else { + *error = "Unknown generator option: " + options[i].first; + return false; + } + } + + // ----------------------------------------------------------------- + + + string basename = StripProto(file->name()); + basename.append(".pb"); + + FileGenerator file_generator(file, dllexport_decl); + + // Generate header. + { + scoped_ptr output( + generator_context->Open(basename + ".h")); + io::Printer printer(output.get(), '$'); + file_generator.GenerateHeader(&printer); + } + + // Generate cc file. + { + scoped_ptr output( + generator_context->Open(basename + ".cc")); + io::Printer printer(output.get(), '$'); + file_generator.GenerateSource(&printer); + } + + return true; +} + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/depends/protobuf/google/protobuf/compiler/cpp/cpp_generator.h b/depends/protobuf/google/protobuf/compiler/cpp/cpp_generator.h new file mode 100644 index 0000000000..a90e84d7b1 --- /dev/null +++ b/depends/protobuf/google/protobuf/compiler/cpp/cpp_generator.h @@ -0,0 +1,72 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// Generates C++ code for a given .proto file. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_GENERATOR_H__ +#define GOOGLE_PROTOBUF_COMPILER_CPP_GENERATOR_H__ + +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +// CodeGenerator implementation which generates a C++ source file and +// header. If you create your own protocol compiler binary and you want +// it to support C++ output, you can do so by registering an instance of this +// CodeGenerator with the CommandLineInterface in your main() function. +class LIBPROTOC_EXPORT CppGenerator : public CodeGenerator { + public: + CppGenerator(); + ~CppGenerator(); + + // implements CodeGenerator ---------------------------------------- + bool Generate(const FileDescriptor* file, + const string& parameter, + GeneratorContext* generator_context, + string* error) const; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CppGenerator); +}; + +} // namespace cpp +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_CPP_GENERATOR_H__ diff --git a/depends/protobuf/google/protobuf/compiler/cpp/cpp_helpers.cc b/depends/protobuf/google/protobuf/compiler/cpp/cpp_helpers.cc new file mode 100644 index 0000000000..25b05a85fd --- /dev/null +++ b/depends/protobuf/google/protobuf/compiler/cpp/cpp_helpers.cc @@ -0,0 +1,347 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include +#include +#include + +#include +#include +#include +#include + + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +namespace { + +string DotsToUnderscores(const string& name) { + return StringReplace(name, ".", "_", true); +} + +string DotsToColons(const string& name) { + return StringReplace(name, ".", "::", true); +} + +const char* const kKeywordList[] = { + "and", "and_eq", "asm", "auto", "bitand", "bitor", "bool", "break", "case", + "catch", "char", "class", "compl", "const", "const_cast", "continue", + "default", "delete", "do", "double", "dynamic_cast", "else", "enum", + "explicit", "extern", "false", "float", "for", "friend", "goto", "if", + "inline", "int", "long", "mutable", "namespace", "new", "not", "not_eq", + "operator", "or", "or_eq", "private", "protected", "public", "register", + "reinterpret_cast", "return", "short", "signed", "sizeof", "static", + "static_cast", "struct", "switch", "template", "this", "throw", "true", "try", + "typedef", "typeid", "typename", "union", "unsigned", "using", "virtual", + "void", "volatile", "wchar_t", "while", "xor", "xor_eq" +}; + +hash_set MakeKeywordsMap() { + hash_set result; + for (int i = 0; i < GOOGLE_ARRAYSIZE(kKeywordList); i++) { + result.insert(kKeywordList[i]); + } + return result; +} + +hash_set kKeywords = MakeKeywordsMap(); + +string UnderscoresToCamelCase(const string& input, bool cap_next_letter) { + string result; + // Note: I distrust ctype.h due to locales. + for (int i = 0; i < input.size(); i++) { + if ('a' <= input[i] && input[i] <= 'z') { + if (cap_next_letter) { + result += input[i] + ('A' - 'a'); + } else { + result += input[i]; + } + cap_next_letter = false; + } else if ('A' <= input[i] && input[i] <= 'Z') { + // Capital letters are left as-is. + result += input[i]; + cap_next_letter = false; + } else if ('0' <= input[i] && input[i] <= '9') { + result += input[i]; + cap_next_letter = true; + } else { + cap_next_letter = true; + } + } + return result; +} + +} // namespace + +const char kThickSeparator[] = + "// ===================================================================\n"; +const char kThinSeparator[] = + "// -------------------------------------------------------------------\n"; + +string ClassName(const Descriptor* descriptor, bool qualified) { + + // Find "outer", the descriptor of the top-level message in which + // "descriptor" is embedded. + const Descriptor* outer = descriptor; + while (outer->containing_type() != NULL) outer = outer->containing_type(); + + const string& outer_name = outer->full_name(); + string inner_name = descriptor->full_name().substr(outer_name.size()); + + if (qualified) { + return "::" + DotsToColons(outer_name) + DotsToUnderscores(inner_name); + } else { + return outer->name() + DotsToUnderscores(inner_name); + } +} + +string ClassName(const EnumDescriptor* enum_descriptor, bool qualified) { + if (enum_descriptor->containing_type() == NULL) { + if (qualified) { + return DotsToColons(enum_descriptor->full_name()); + } else { + return enum_descriptor->name(); + } + } else { + string result = ClassName(enum_descriptor->containing_type(), qualified); + result += '_'; + result += enum_descriptor->name(); + return result; + } +} + + +string SuperClassName(const Descriptor* descriptor) { + return HasDescriptorMethods(descriptor->file()) ? + "::google::protobuf::Message" : "::google::protobuf::MessageLite"; +} + +string FieldName(const FieldDescriptor* field) { + string result = field->name(); + LowerString(&result); + if (kKeywords.count(result) > 0) { + result.append("_"); + } + return result; +} + +string FieldConstantName(const FieldDescriptor *field) { + string field_name = UnderscoresToCamelCase(field->name(), true); + string result = "k" + field_name + "FieldNumber"; + + if (!field->is_extension() && + field->containing_type()->FindFieldByCamelcaseName( + field->camelcase_name()) != field) { + // This field's camelcase name is not unique. As a hack, add the field + // number to the constant name. This makes the constant rather useless, + // but what can we do? + result += "_" + SimpleItoa(field->number()); + } + + return result; +} + +string FieldMessageTypeName(const FieldDescriptor* field) { + // Note: The Google-internal version of Protocol Buffers uses this function + // as a hook point for hacks to support legacy code. + return ClassName(field->message_type(), true); +} + +string StripProto(const string& filename) { + if (HasSuffixString(filename, ".protodevel")) { + return StripSuffixString(filename, ".protodevel"); + } else { + return StripSuffixString(filename, ".proto"); + } +} + +const char* PrimitiveTypeName(FieldDescriptor::CppType type) { + switch (type) { + case FieldDescriptor::CPPTYPE_INT32 : return "::google::protobuf::int32"; + case FieldDescriptor::CPPTYPE_INT64 : return "::google::protobuf::int64"; + case FieldDescriptor::CPPTYPE_UINT32 : return "::google::protobuf::uint32"; + case FieldDescriptor::CPPTYPE_UINT64 : return "::google::protobuf::uint64"; + case FieldDescriptor::CPPTYPE_DOUBLE : return "double"; + case FieldDescriptor::CPPTYPE_FLOAT : return "float"; + case FieldDescriptor::CPPTYPE_BOOL : return "bool"; + case FieldDescriptor::CPPTYPE_ENUM : return "int"; + case FieldDescriptor::CPPTYPE_STRING : return "::std::string"; + case FieldDescriptor::CPPTYPE_MESSAGE: return NULL; + + // No default because we want the compiler to complain if any new + // CppTypes are added. + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return NULL; +} + +const char* DeclaredTypeMethodName(FieldDescriptor::Type type) { + switch (type) { + case FieldDescriptor::TYPE_INT32 : return "Int32"; + case FieldDescriptor::TYPE_INT64 : return "Int64"; + case FieldDescriptor::TYPE_UINT32 : return "UInt32"; + case FieldDescriptor::TYPE_UINT64 : return "UInt64"; + case FieldDescriptor::TYPE_SINT32 : return "SInt32"; + case FieldDescriptor::TYPE_SINT64 : return "SInt64"; + case FieldDescriptor::TYPE_FIXED32 : return "Fixed32"; + case FieldDescriptor::TYPE_FIXED64 : return "Fixed64"; + case FieldDescriptor::TYPE_SFIXED32: return "SFixed32"; + case FieldDescriptor::TYPE_SFIXED64: return "SFixed64"; + case FieldDescriptor::TYPE_FLOAT : return "Float"; + case FieldDescriptor::TYPE_DOUBLE : return "Double"; + + case FieldDescriptor::TYPE_BOOL : return "Bool"; + case FieldDescriptor::TYPE_ENUM : return "Enum"; + + case FieldDescriptor::TYPE_STRING : return "String"; + case FieldDescriptor::TYPE_BYTES : return "Bytes"; + case FieldDescriptor::TYPE_GROUP : return "Group"; + case FieldDescriptor::TYPE_MESSAGE : return "Message"; + + // No default because we want the compiler to complain if any new + // types are added. + } + GOOGLE_LOG(FATAL) << "Can't get here."; + return ""; +} + +string DefaultValue(const FieldDescriptor* field) { + switch (field->cpp_type()) { + case FieldDescriptor::CPPTYPE_INT32: + return SimpleItoa(field->default_value_int32()); + case FieldDescriptor::CPPTYPE_UINT32: + return SimpleItoa(field->default_value_uint32()) + "u"; + case FieldDescriptor::CPPTYPE_INT64: + return "GOOGLE_LONGLONG(" + SimpleItoa(field->default_value_int64()) + ")"; + case FieldDescriptor::CPPTYPE_UINT64: + return "GOOGLE_ULONGLONG(" + SimpleItoa(field->default_value_uint64())+ ")"; + case FieldDescriptor::CPPTYPE_DOUBLE: { + double value = field->default_value_double(); + if (value == numeric_limits::infinity()) { + return "::google::protobuf::internal::Infinity()"; + } else if (value == -numeric_limits::infinity()) { + return "-::google::protobuf::internal::Infinity()"; + } else if (value != value) { + return "::google::protobuf::internal::NaN()"; + } else { + return SimpleDtoa(value); + } + } + case FieldDescriptor::CPPTYPE_FLOAT: + { + float value = field->default_value_float(); + if (value == numeric_limits::infinity()) { + return "static_cast(::google::protobuf::internal::Infinity())"; + } else if (value == -numeric_limits::infinity()) { + return "static_cast(-::google::protobuf::internal::Infinity())"; + } else if (value != value) { + return "static_cast(::google::protobuf::internal::NaN())"; + } else { + string float_value = SimpleFtoa(value); + // If floating point value contains a period (.) or an exponent + // (either E or e), then append suffix 'f' to make it a float + // literal. + if (float_value.find_first_of(".eE") != string::npos) { + float_value.push_back('f'); + } + return float_value; + } + } + case FieldDescriptor::CPPTYPE_BOOL: + return field->default_value_bool() ? "true" : "false"; + case FieldDescriptor::CPPTYPE_ENUM: + // Lazy: Generate a static_cast because we don't have a helper function + // that constructs the full name of an enum value. + return strings::Substitute( + "static_cast< $0 >($1)", + ClassName(field->enum_type(), true), + field->default_value_enum()->number()); + case FieldDescriptor::CPPTYPE_STRING: + return "\"" + EscapeTrigraphs(CEscape(field->default_value_string())) + + "\""; + case FieldDescriptor::CPPTYPE_MESSAGE: + return FieldMessageTypeName(field) + "::default_instance()"; + } + // Can't actually get here; make compiler happy. (We could add a default + // case above but then we wouldn't get the nice compiler warning when a + // new type is added.) + GOOGLE_LOG(FATAL) << "Can't get here."; + return ""; +} + +// Convert a file name into a valid identifier. +string FilenameIdentifier(const string& filename) { + string result; + for (int i = 0; i < filename.size(); i++) { + if (ascii_isalnum(filename[i])) { + result.push_back(filename[i]); + } else { + // Not alphanumeric. To avoid any possibility of name conflicts we + // use the hex code for the character. + result.push_back('_'); + char buffer[kFastToBufferSize]; + result.append(FastHexToBuffer(static_cast(filename[i]), buffer)); + } + } + return result; +} + +// Return the name of the AddDescriptors() function for a given file. +string GlobalAddDescriptorsName(const string& filename) { + return "protobuf_AddDesc_" + FilenameIdentifier(filename); +} + +// Return the name of the AssignDescriptors() function for a given file. +string GlobalAssignDescriptorsName(const string& filename) { + return "protobuf_AssignDesc_" + FilenameIdentifier(filename); +} + +// Return the name of the ShutdownFile() function for a given file. +string GlobalShutdownFileName(const string& filename) { + return "protobuf_ShutdownFile_" + FilenameIdentifier(filename); +} + +// Escape C++ trigraphs by escaping question marks to \? +string EscapeTrigraphs(const string& to_escape) { + return StringReplace(to_escape, "?", "\\?", true); +} + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/depends/protobuf/google/protobuf/compiler/cpp/cpp_helpers.h b/depends/protobuf/google/protobuf/compiler/cpp/cpp_helpers.h new file mode 100644 index 0000000000..b13d53beff --- /dev/null +++ b/depends/protobuf/google/protobuf/compiler/cpp/cpp_helpers.h @@ -0,0 +1,159 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_HELPERS_H__ +#define GOOGLE_PROTOBUF_COMPILER_CPP_HELPERS_H__ + +#include +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +// Commonly-used separator comments. Thick is a line of '=', thin is a line +// of '-'. +extern const char kThickSeparator[]; +extern const char kThinSeparator[]; + +// Returns the non-nested type name for the given type. If "qualified" is +// true, prefix the type with the full namespace. For example, if you had: +// package foo.bar; +// message Baz { message Qux {} } +// Then the qualified ClassName for Qux would be: +// ::foo::bar::Baz_Qux +// While the non-qualified version would be: +// Baz_Qux +string ClassName(const Descriptor* descriptor, bool qualified); +string ClassName(const EnumDescriptor* enum_descriptor, bool qualified); + +string SuperClassName(const Descriptor* descriptor); + +// Get the (unqualified) name that should be used for this field in C++ code. +// The name is coerced to lower-case to emulate proto1 behavior. People +// should be using lowercase-with-underscores style for proto field names +// anyway, so normally this just returns field->name(). +string FieldName(const FieldDescriptor* field); + +// Get the unqualified name that should be used for a field's field +// number constant. +string FieldConstantName(const FieldDescriptor *field); + +// Returns the scope where the field was defined (for extensions, this is +// different from the message type to which the field applies). +inline const Descriptor* FieldScope(const FieldDescriptor* field) { + return field->is_extension() ? + field->extension_scope() : field->containing_type(); +} + +// Returns the fully-qualified type name field->message_type(). Usually this +// is just ClassName(field->message_type(), true); +string FieldMessageTypeName(const FieldDescriptor* field); + +// Strips ".proto" or ".protodevel" from the end of a filename. +string StripProto(const string& filename); + +// Get the C++ type name for a primitive type (e.g. "double", "::google::protobuf::int32", etc.). +// Note: non-built-in type names will be qualified, meaning they will start +// with a ::. If you are using the type as a template parameter, you will +// need to insure there is a space between the < and the ::, because the +// ridiculous C++ standard defines "<:" to be a synonym for "[". +const char* PrimitiveTypeName(FieldDescriptor::CppType type); + +// Get the declared type name in CamelCase format, as is used e.g. for the +// methods of WireFormat. For example, TYPE_INT32 becomes "Int32". +const char* DeclaredTypeMethodName(FieldDescriptor::Type type); + +// Get code that evaluates to the field's default value. +string DefaultValue(const FieldDescriptor* field); + +// Convert a file name into a valid identifier. +string FilenameIdentifier(const string& filename); + +// Return the name of the AddDescriptors() function for a given file. +string GlobalAddDescriptorsName(const string& filename); + +// Return the name of the AssignDescriptors() function for a given file. +string GlobalAssignDescriptorsName(const string& filename); + +// Return the name of the ShutdownFile() function for a given file. +string GlobalShutdownFileName(const string& filename); + +// Escape C++ trigraphs by escaping question marks to \? +string EscapeTrigraphs(const string& to_escape); + +// Do message classes in this file keep track of unknown fields? +inline bool HasUnknownFields(const FileDescriptor *file) { + return file->options().optimize_for() != FileOptions::LITE_RUNTIME; +} + +// Does this file have generated parsing, serialization, and other +// standard methods for which reflection-based fallback implementations exist? +inline bool HasGeneratedMethods(const FileDescriptor *file) { + return file->options().optimize_for() != FileOptions::CODE_SIZE; +} + +// Do message classes in this file have descriptor and refelction methods? +inline bool HasDescriptorMethods(const FileDescriptor *file) { + return file->options().optimize_for() != FileOptions::LITE_RUNTIME; +} + +// Should we generate generic services for this file? +inline bool HasGenericServices(const FileDescriptor *file) { + return file->service_count() > 0 && + file->options().optimize_for() != FileOptions::LITE_RUNTIME && + file->options().cc_generic_services(); +} + +// Should string fields in this file verify that their contents are UTF-8? +inline bool HasUtf8Verification(const FileDescriptor* file) { + return file->options().optimize_for() != FileOptions::LITE_RUNTIME; +} + +// Should we generate a separate, super-optimized code path for serializing to +// flat arrays? We don't do this in Lite mode because we'd rather reduce code +// size. +inline bool HasFastArraySerialization(const FileDescriptor* file) { + return file->options().optimize_for() == FileOptions::SPEED; +} + + +} // namespace cpp +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_CPP_HELPERS_H__ diff --git a/depends/protobuf/google/protobuf/compiler/cpp/cpp_message.cc b/depends/protobuf/google/protobuf/compiler/cpp/cpp_message.cc new file mode 100644 index 0000000000..c4e6fb2c85 --- /dev/null +++ b/depends/protobuf/google/protobuf/compiler/cpp/cpp_message.cc @@ -0,0 +1,1933 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +using internal::WireFormat; +using internal::WireFormatLite; + +namespace { + +void PrintFieldComment(io::Printer* printer, const FieldDescriptor* field) { + // Print the field's proto-syntax definition as a comment. We don't want to + // print group bodies so we cut off after the first line. + string def = field->DebugString(); + printer->Print("// $def$\n", + "def", def.substr(0, def.find_first_of('\n'))); +} + +struct FieldOrderingByNumber { + inline bool operator()(const FieldDescriptor* a, + const FieldDescriptor* b) const { + return a->number() < b->number(); + } +}; + +const char* kWireTypeNames[] = { + "VARINT", + "FIXED64", + "LENGTH_DELIMITED", + "START_GROUP", + "END_GROUP", + "FIXED32", +}; + +// Sort the fields of the given Descriptor by number into a new[]'d array +// and return it. +const FieldDescriptor** SortFieldsByNumber(const Descriptor* descriptor) { + const FieldDescriptor** fields = + new const FieldDescriptor*[descriptor->field_count()]; + for (int i = 0; i < descriptor->field_count(); i++) { + fields[i] = descriptor->field(i); + } + sort(fields, fields + descriptor->field_count(), + FieldOrderingByNumber()); + return fields; +} + +// Functor for sorting extension ranges by their "start" field number. +struct ExtensionRangeSorter { + bool operator()(const Descriptor::ExtensionRange* left, + const Descriptor::ExtensionRange* right) const { + return left->start < right->start; + } +}; + +// Returns true if the message type has any required fields. If it doesn't, +// we can optimize out calls to its IsInitialized() method. +// +// already_seen is used to avoid checking the same type multiple times +// (and also to protect against recursion). +static bool HasRequiredFields( + const Descriptor* type, + hash_set* already_seen) { + if (already_seen->count(type) > 0) { + // Since the first occurrence of a required field causes the whole + // function to return true, we can assume that if the type is already + // in the cache it didn't have any required fields. + return false; + } + already_seen->insert(type); + + // If the type has extensions, an extension with message type could contain + // required fields, so we have to be conservative and assume such an + // extension exists. + if (type->extension_range_count() > 0) return true; + + for (int i = 0; i < type->field_count(); i++) { + const FieldDescriptor* field = type->field(i); + if (field->is_required()) { + return true; + } + if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + if (HasRequiredFields(field->message_type(), already_seen)) { + return true; + } + } + } + + return false; +} + +static bool HasRequiredFields(const Descriptor* type) { + hash_set already_seen; + return HasRequiredFields(type, &already_seen); +} + +// This returns an estimate of the compiler's alignment for the field. This +// can't guarantee to be correct because the generated code could be compiled on +// different systems with different alignment rules. The estimates below assume +// 64-bit pointers. +int EstimateAlignmentSize(const FieldDescriptor* field) { + if (field == NULL) return 0; + if (field->is_repeated()) return 8; + switch (field->cpp_type()) { + case FieldDescriptor::CPPTYPE_BOOL: + return 1; + + case FieldDescriptor::CPPTYPE_INT32: + case FieldDescriptor::CPPTYPE_UINT32: + case FieldDescriptor::CPPTYPE_ENUM: + case FieldDescriptor::CPPTYPE_FLOAT: + return 4; + + case FieldDescriptor::CPPTYPE_INT64: + case FieldDescriptor::CPPTYPE_UINT64: + case FieldDescriptor::CPPTYPE_DOUBLE: + case FieldDescriptor::CPPTYPE_STRING: + case FieldDescriptor::CPPTYPE_MESSAGE: + return 8; + } + GOOGLE_LOG(FATAL) << "Can't get here."; + return -1; // Make compiler happy. +} + +// FieldGroup is just a helper for OptimizePadding below. It holds a vector of +// fields that are grouped together because they have compatible alignment, and +// a preferred location in the final field ordering. +class FieldGroup { + public: + FieldGroup() + : preferred_location_(0) {} + + // A group with a single field. + FieldGroup(float preferred_location, const FieldDescriptor* field) + : preferred_location_(preferred_location), + fields_(1, field) {} + + // Append the fields in 'other' to this group. + void Append(const FieldGroup& other) { + if (other.fields_.empty()) { + return; + } + // Preferred location is the average among all the fields, so we weight by + // the number of fields on each FieldGroup object. + preferred_location_ = + (preferred_location_ * fields_.size() + + (other.preferred_location_ * other.fields_.size())) / + (fields_.size() + other.fields_.size()); + fields_.insert(fields_.end(), other.fields_.begin(), other.fields_.end()); + } + + void SetPreferredLocation(float location) { preferred_location_ = location; } + const vector& fields() const { return fields_; } + + // FieldGroup objects sort by their preferred location. + bool operator<(const FieldGroup& other) const { + return preferred_location_ < other.preferred_location_; + } + + private: + // "preferred_location_" is an estimate of where this group should go in the + // final list of fields. We compute this by taking the average index of each + // field in this group in the original ordering of fields. This is very + // approximate, but should put this group close to where its member fields + // originally went. + float preferred_location_; + vector fields_; + // We rely on the default copy constructor and operator= so this type can be + // used in a vector. +}; + +// Reorder 'fields' so that if the fields are output into a c++ class in the new +// order, the alignment padding is minimized. We try to do this while keeping +// each field as close as possible to its original position so that we don't +// reduce cache locality much for function that access each field in order. +void OptimizePadding(vector* fields) { + // First divide fields into those that align to 1 byte, 4 bytes or 8 bytes. + vector aligned_to_1, aligned_to_4, aligned_to_8; + for (int i = 0; i < fields->size(); ++i) { + switch (EstimateAlignmentSize((*fields)[i])) { + case 1: aligned_to_1.push_back(FieldGroup(i, (*fields)[i])); break; + case 4: aligned_to_4.push_back(FieldGroup(i, (*fields)[i])); break; + case 8: aligned_to_8.push_back(FieldGroup(i, (*fields)[i])); break; + default: + GOOGLE_LOG(FATAL) << "Unknown alignment size."; + } + } + + // Now group fields aligned to 1 byte into sets of 4, and treat those like a + // single field aligned to 4 bytes. + for (int i = 0; i < aligned_to_1.size(); i += 4) { + FieldGroup field_group; + for (int j = i; j < aligned_to_1.size() && j < i + 4; ++j) { + field_group.Append(aligned_to_1[j]); + } + aligned_to_4.push_back(field_group); + } + // Sort by preferred location to keep fields as close to their original + // location as possible. + sort(aligned_to_4.begin(), aligned_to_4.end()); + + // Now group fields aligned to 4 bytes (or the 4-field groups created above) + // into pairs, and treat those like a single field aligned to 8 bytes. + for (int i = 0; i < aligned_to_4.size(); i += 2) { + FieldGroup field_group; + for (int j = i; j < aligned_to_4.size() && j < i + 2; ++j) { + field_group.Append(aligned_to_4[j]); + } + if (i == aligned_to_4.size() - 1) { + // Move incomplete 4-byte block to the end. + field_group.SetPreferredLocation(fields->size() + 1); + } + aligned_to_8.push_back(field_group); + } + // Sort by preferred location to keep fields as close to their original + // location as possible. + sort(aligned_to_8.begin(), aligned_to_8.end()); + + // Now pull out all the FieldDescriptors in order. + fields->clear(); + for (int i = 0; i < aligned_to_8.size(); ++i) { + fields->insert(fields->end(), + aligned_to_8[i].fields().begin(), + aligned_to_8[i].fields().end()); + } +} + +} + +// =================================================================== + +MessageGenerator::MessageGenerator(const Descriptor* descriptor, + const string& dllexport_decl) + : descriptor_(descriptor), + classname_(ClassName(descriptor, false)), + dllexport_decl_(dllexport_decl), + field_generators_(descriptor), + nested_generators_(new scoped_ptr[ + descriptor->nested_type_count()]), + enum_generators_(new scoped_ptr[ + descriptor->enum_type_count()]), + extension_generators_(new scoped_ptr[ + descriptor->extension_count()]) { + + for (int i = 0; i < descriptor->nested_type_count(); i++) { + nested_generators_[i].reset( + new MessageGenerator(descriptor->nested_type(i), dllexport_decl)); + } + + for (int i = 0; i < descriptor->enum_type_count(); i++) { + enum_generators_[i].reset( + new EnumGenerator(descriptor->enum_type(i), dllexport_decl)); + } + + for (int i = 0; i < descriptor->extension_count(); i++) { + extension_generators_[i].reset( + new ExtensionGenerator(descriptor->extension(i), dllexport_decl)); + } +} + +MessageGenerator::~MessageGenerator() {} + +void MessageGenerator:: +GenerateForwardDeclaration(io::Printer* printer) { + printer->Print("class $classname$;\n", + "classname", classname_); + + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + nested_generators_[i]->GenerateForwardDeclaration(printer); + } +} + +void MessageGenerator:: +GenerateEnumDefinitions(io::Printer* printer) { + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + nested_generators_[i]->GenerateEnumDefinitions(printer); + } + + for (int i = 0; i < descriptor_->enum_type_count(); i++) { + enum_generators_[i]->GenerateDefinition(printer); + } +} + +void MessageGenerator:: +GenerateGetEnumDescriptorSpecializations(io::Printer* printer) { + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + nested_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer); + } + for (int i = 0; i < descriptor_->enum_type_count(); i++) { + enum_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer); + } +} + +void MessageGenerator:: +GenerateFieldAccessorDeclarations(io::Printer* printer) { + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + + PrintFieldComment(printer, field); + + map vars; + SetCommonFieldVariables(field, &vars); + vars["constant_name"] = FieldConstantName(field); + + if (field->is_repeated()) { + printer->Print(vars, "inline int $name$_size() const$deprecation$;\n"); + } else { + printer->Print(vars, "inline bool has_$name$() const$deprecation$;\n"); + } + + printer->Print(vars, "inline void clear_$name$()$deprecation$;\n"); + printer->Print(vars, "static const int $constant_name$ = $number$;\n"); + + // Generate type-specific accessor declarations. + field_generators_.get(field).GenerateAccessorDeclarations(printer); + + printer->Print("\n"); + } + + if (descriptor_->extension_range_count() > 0) { + // Generate accessors for extensions. We just call a macro located in + // extension_set.h since the accessors about 80 lines of static code. + printer->Print( + "GOOGLE_PROTOBUF_EXTENSION_ACCESSORS($classname$)\n", + "classname", classname_); + } +} + +void MessageGenerator:: +GenerateFieldAccessorDefinitions(io::Printer* printer) { + printer->Print("// $classname$\n\n", "classname", classname_); + + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + + PrintFieldComment(printer, field); + + map vars; + SetCommonFieldVariables(field, &vars); + + // Generate has_$name$() or $name$_size(). + if (field->is_repeated()) { + printer->Print(vars, + "inline int $classname$::$name$_size() const {\n" + " return $name$_.size();\n" + "}\n"); + } else { + // Singular field. + char buffer[kFastToBufferSize]; + vars["has_array_index"] = SimpleItoa(field->index() / 32); + vars["has_mask"] = FastHex32ToBuffer(1u << (field->index() % 32), buffer); + printer->Print(vars, + "inline bool $classname$::has_$name$() const {\n" + " return (_has_bits_[$has_array_index$] & 0x$has_mask$u) != 0;\n" + "}\n" + "inline void $classname$::set_has_$name$() {\n" + " _has_bits_[$has_array_index$] |= 0x$has_mask$u;\n" + "}\n" + "inline void $classname$::clear_has_$name$() {\n" + " _has_bits_[$has_array_index$] &= ~0x$has_mask$u;\n" + "}\n" + ); + } + + // Generate clear_$name$() + printer->Print(vars, + "inline void $classname$::clear_$name$() {\n"); + + printer->Indent(); + field_generators_.get(field).GenerateClearingCode(printer); + printer->Outdent(); + + if (!field->is_repeated()) { + printer->Print(vars, + " clear_has_$name$();\n"); + } + + printer->Print("}\n"); + + // Generate type-specific accessors. + field_generators_.get(field).GenerateInlineAccessorDefinitions(printer); + + printer->Print("\n"); + } +} + +void MessageGenerator:: +GenerateClassDefinition(io::Printer* printer) { + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + nested_generators_[i]->GenerateClassDefinition(printer); + printer->Print("\n"); + printer->Print(kThinSeparator); + printer->Print("\n"); + } + + map vars; + vars["classname"] = classname_; + vars["field_count"] = SimpleItoa(descriptor_->field_count()); + if (dllexport_decl_.empty()) { + vars["dllexport"] = ""; + } else { + vars["dllexport"] = dllexport_decl_ + " "; + } + vars["superclass"] = SuperClassName(descriptor_); + + printer->Print(vars, + "class $dllexport$$classname$ : public $superclass$ {\n" + " public:\n"); + printer->Indent(); + + printer->Print(vars, + "$classname$();\n" + "virtual ~$classname$();\n" + "\n" + "$classname$(const $classname$& from);\n" + "\n" + "inline $classname$& operator=(const $classname$& from) {\n" + " CopyFrom(from);\n" + " return *this;\n" + "}\n" + "\n"); + + if (HasUnknownFields(descriptor_->file())) { + printer->Print( + "inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {\n" + " return _unknown_fields_;\n" + "}\n" + "\n" + "inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {\n" + " return &_unknown_fields_;\n" + "}\n" + "\n"); + } + + // Only generate this member if it's not disabled. + if (HasDescriptorMethods(descriptor_->file()) && + !descriptor_->options().no_standard_descriptor_accessor()) { + printer->Print(vars, + "static const ::google::protobuf::Descriptor* descriptor();\n"); + } + + printer->Print(vars, + "static const $classname$& default_instance();\n" + "\n"); + + + printer->Print(vars, + "void Swap($classname$* other);\n" + "\n" + "// implements Message ----------------------------------------------\n" + "\n" + "$classname$* New() const;\n"); + + if (HasGeneratedMethods(descriptor_->file())) { + if (HasDescriptorMethods(descriptor_->file())) { + printer->Print(vars, + "void CopyFrom(const ::google::protobuf::Message& from);\n" + "void MergeFrom(const ::google::protobuf::Message& from);\n"); + } else { + printer->Print(vars, + "void CheckTypeAndMergeFrom(const ::google::protobuf::MessageLite& from);\n"); + } + + printer->Print(vars, + "void CopyFrom(const $classname$& from);\n" + "void MergeFrom(const $classname$& from);\n" + "void Clear();\n" + "bool IsInitialized() const;\n" + "\n" + "int ByteSize() const;\n" + "bool MergePartialFromCodedStream(\n" + " ::google::protobuf::io::CodedInputStream* input);\n" + "void SerializeWithCachedSizes(\n" + " ::google::protobuf::io::CodedOutputStream* output) const;\n"); + if (HasFastArraySerialization(descriptor_->file())) { + printer->Print( + "::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;\n"); + } + } + + printer->Print(vars, + "int GetCachedSize() const { return _cached_size_; }\n" + "private:\n" + "void SharedCtor();\n" + "void SharedDtor();\n" + "void SetCachedSize(int size) const;\n" + "public:\n" + "\n"); + + if (HasDescriptorMethods(descriptor_->file())) { + printer->Print( + "::google::protobuf::Metadata GetMetadata() const;\n" + "\n"); + } else { + printer->Print( + "::std::string GetTypeName() const;\n" + "\n"); + } + + printer->Print( + "// nested types ----------------------------------------------------\n" + "\n"); + + // Import all nested message classes into this class's scope with typedefs. + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + const Descriptor* nested_type = descriptor_->nested_type(i); + printer->Print("typedef $nested_full_name$ $nested_name$;\n", + "nested_name", nested_type->name(), + "nested_full_name", ClassName(nested_type, false)); + } + + if (descriptor_->nested_type_count() > 0) { + printer->Print("\n"); + } + + // Import all nested enums and their values into this class's scope with + // typedefs and constants. + for (int i = 0; i < descriptor_->enum_type_count(); i++) { + enum_generators_[i]->GenerateSymbolImports(printer); + printer->Print("\n"); + } + + printer->Print( + "// accessors -------------------------------------------------------\n" + "\n"); + + // Generate accessor methods for all fields. + GenerateFieldAccessorDeclarations(printer); + + // Declare extension identifiers. + for (int i = 0; i < descriptor_->extension_count(); i++) { + extension_generators_[i]->GenerateDeclaration(printer); + } + + + printer->Print( + "// @@protoc_insertion_point(class_scope:$full_name$)\n", + "full_name", descriptor_->full_name()); + + // Generate private members. + printer->Outdent(); + printer->Print(" private:\n"); + printer->Indent(); + + for (int i = 0; i < descriptor_->field_count(); i++) { + if (!descriptor_->field(i)->is_repeated()) { + printer->Print( + "inline void set_has_$name$();\n", + "name", FieldName(descriptor_->field(i))); + printer->Print( + "inline void clear_has_$name$();\n", + "name", FieldName(descriptor_->field(i))); + } + } + printer->Print("\n"); + + // To minimize padding, data members are divided into three sections: + // (1) members assumed to align to 8 bytes + // (2) members corresponding to message fields, re-ordered to optimize + // alignment. + // (3) members assumed to align to 4 bytes. + + // Members assumed to align to 8 bytes: + + if (descriptor_->extension_range_count() > 0) { + printer->Print( + "::google::protobuf::internal::ExtensionSet _extensions_;\n" + "\n"); + } + + if (HasUnknownFields(descriptor_->file())) { + printer->Print( + "::google::protobuf::UnknownFieldSet _unknown_fields_;\n" + "\n"); + } + + // Field members: + + vector fields; + for (int i = 0; i < descriptor_->field_count(); i++) { + fields.push_back(descriptor_->field(i)); + } + OptimizePadding(&fields); + for (int i = 0; i < fields.size(); ++i) { + field_generators_.get(fields[i]).GeneratePrivateMembers(printer); + } + + // Members assumed to align to 4 bytes: + + // TODO(kenton): Make _cached_size_ an atomic when C++ supports it. + printer->Print( + "\n" + "mutable int _cached_size_;\n"); + + // Generate _has_bits_. + if (descriptor_->field_count() > 0) { + printer->Print(vars, + "::google::protobuf::uint32 _has_bits_[($field_count$ + 31) / 32];\n" + "\n"); + } else { + // Zero-size arrays aren't technically allowed, and MSVC in particular + // doesn't like them. We still need to declare these arrays to make + // other code compile. Since this is an uncommon case, we'll just declare + // them with size 1 and waste some space. Oh well. + printer->Print( + "::google::protobuf::uint32 _has_bits_[1];\n" + "\n"); + } + + // Declare AddDescriptors(), BuildDescriptors(), and ShutdownFile() as + // friends so that they can access private static variables like + // default_instance_ and reflection_. + printer->Print( + "friend void $dllexport_decl$ $adddescriptorsname$();\n", + "dllexport_decl", dllexport_decl_, + "adddescriptorsname", + GlobalAddDescriptorsName(descriptor_->file()->name())); + printer->Print( + "friend void $assigndescriptorsname$();\n" + "friend void $shutdownfilename$();\n" + "\n", + "assigndescriptorsname", + GlobalAssignDescriptorsName(descriptor_->file()->name()), + "shutdownfilename", GlobalShutdownFileName(descriptor_->file()->name())); + + printer->Print( + "void InitAsDefaultInstance();\n" + "static $classname$* default_instance_;\n", + "classname", classname_); + + printer->Outdent(); + printer->Print(vars, "};"); +} + +void MessageGenerator:: +GenerateInlineMethods(io::Printer* printer) { + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + nested_generators_[i]->GenerateInlineMethods(printer); + printer->Print(kThinSeparator); + printer->Print("\n"); + } + + GenerateFieldAccessorDefinitions(printer); +} + +void MessageGenerator:: +GenerateDescriptorDeclarations(io::Printer* printer) { + printer->Print( + "const ::google::protobuf::Descriptor* $name$_descriptor_ = NULL;\n" + "const ::google::protobuf::internal::GeneratedMessageReflection*\n" + " $name$_reflection_ = NULL;\n", + "name", classname_); + + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + nested_generators_[i]->GenerateDescriptorDeclarations(printer); + } + + for (int i = 0; i < descriptor_->enum_type_count(); i++) { + printer->Print( + "const ::google::protobuf::EnumDescriptor* $name$_descriptor_ = NULL;\n", + "name", ClassName(descriptor_->enum_type(i), false)); + } +} + +void MessageGenerator:: +GenerateDescriptorInitializer(io::Printer* printer, int index) { + // TODO(kenton): Passing the index to this method is redundant; just use + // descriptor_->index() instead. + map vars; + vars["classname"] = classname_; + vars["index"] = SimpleItoa(index); + + // Obtain the descriptor from the parent's descriptor. + if (descriptor_->containing_type() == NULL) { + printer->Print(vars, + "$classname$_descriptor_ = file->message_type($index$);\n"); + } else { + vars["parent"] = ClassName(descriptor_->containing_type(), false); + printer->Print(vars, + "$classname$_descriptor_ = " + "$parent$_descriptor_->nested_type($index$);\n"); + } + + // Generate the offsets. + GenerateOffsets(printer); + + // Construct the reflection object. + printer->Print(vars, + "$classname$_reflection_ =\n" + " new ::google::protobuf::internal::GeneratedMessageReflection(\n" + " $classname$_descriptor_,\n" + " $classname$::default_instance_,\n" + " $classname$_offsets_,\n" + " GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, _has_bits_[0]),\n" + " GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(" + "$classname$, _unknown_fields_),\n"); + if (descriptor_->extension_range_count() > 0) { + printer->Print(vars, + " GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(" + "$classname$, _extensions_),\n"); + } else { + // No extensions. + printer->Print(vars, + " -1,\n"); + } + printer->Print(vars, + " ::google::protobuf::DescriptorPool::generated_pool(),\n" + " ::google::protobuf::MessageFactory::generated_factory(),\n" + " sizeof($classname$));\n"); + + // Handle nested types. + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + nested_generators_[i]->GenerateDescriptorInitializer(printer, i); + } + + for (int i = 0; i < descriptor_->enum_type_count(); i++) { + enum_generators_[i]->GenerateDescriptorInitializer(printer, i); + } +} + +void MessageGenerator:: +GenerateTypeRegistrations(io::Printer* printer) { + // Register this message type with the message factory. + printer->Print( + "::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(\n" + " $classname$_descriptor_, &$classname$::default_instance());\n", + "classname", classname_); + + // Handle nested types. + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + nested_generators_[i]->GenerateTypeRegistrations(printer); + } +} + +void MessageGenerator:: +GenerateDefaultInstanceAllocator(io::Printer* printer) { + // Construct the default instance. We can't call InitAsDefaultInstance() yet + // because we need to make sure all default instances that this one might + // depend on are constructed first. + printer->Print( + "$classname$::default_instance_ = new $classname$();\n", + "classname", classname_); + + // Handle nested types. + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + nested_generators_[i]->GenerateDefaultInstanceAllocator(printer); + } + +} + +void MessageGenerator:: +GenerateDefaultInstanceInitializer(io::Printer* printer) { + printer->Print( + "$classname$::default_instance_->InitAsDefaultInstance();\n", + "classname", classname_); + + // Register extensions. + for (int i = 0; i < descriptor_->extension_count(); i++) { + extension_generators_[i]->GenerateRegistration(printer); + } + + // Handle nested types. + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + nested_generators_[i]->GenerateDefaultInstanceInitializer(printer); + } +} + +void MessageGenerator:: +GenerateShutdownCode(io::Printer* printer) { + printer->Print( + "delete $classname$::default_instance_;\n", + "classname", classname_); + + if (HasDescriptorMethods(descriptor_->file())) { + printer->Print( + "delete $classname$_reflection_;\n", + "classname", classname_); + } + + // Handle nested types. + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + nested_generators_[i]->GenerateShutdownCode(printer); + } +} + +void MessageGenerator:: +GenerateClassMethods(io::Printer* printer) { + for (int i = 0; i < descriptor_->enum_type_count(); i++) { + enum_generators_[i]->GenerateMethods(printer); + } + + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + nested_generators_[i]->GenerateClassMethods(printer); + printer->Print("\n"); + printer->Print(kThinSeparator); + printer->Print("\n"); + } + + // Generate non-inline field definitions. + for (int i = 0; i < descriptor_->field_count(); i++) { + field_generators_.get(descriptor_->field(i)) + .GenerateNonInlineAccessorDefinitions(printer); + } + + // Generate field number constants. + printer->Print("#ifndef _MSC_VER\n"); + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor *field = descriptor_->field(i); + printer->Print( + "const int $classname$::$constant_name$;\n", + "classname", ClassName(FieldScope(field), false), + "constant_name", FieldConstantName(field)); + } + printer->Print( + "#endif // !_MSC_VER\n" + "\n"); + + // Define extension identifiers. + for (int i = 0; i < descriptor_->extension_count(); i++) { + extension_generators_[i]->GenerateDefinition(printer); + } + + GenerateStructors(printer); + printer->Print("\n"); + + if (HasGeneratedMethods(descriptor_->file())) { + GenerateClear(printer); + printer->Print("\n"); + + GenerateMergeFromCodedStream(printer); + printer->Print("\n"); + + GenerateSerializeWithCachedSizes(printer); + printer->Print("\n"); + + if (HasFastArraySerialization(descriptor_->file())) { + GenerateSerializeWithCachedSizesToArray(printer); + printer->Print("\n"); + } + + GenerateByteSize(printer); + printer->Print("\n"); + + GenerateMergeFrom(printer); + printer->Print("\n"); + + GenerateCopyFrom(printer); + printer->Print("\n"); + + GenerateIsInitialized(printer); + printer->Print("\n"); + } + + GenerateSwap(printer); + printer->Print("\n"); + + if (HasDescriptorMethods(descriptor_->file())) { + printer->Print( + "::google::protobuf::Metadata $classname$::GetMetadata() const {\n" + " protobuf_AssignDescriptorsOnce();\n" + " ::google::protobuf::Metadata metadata;\n" + " metadata.descriptor = $classname$_descriptor_;\n" + " metadata.reflection = $classname$_reflection_;\n" + " return metadata;\n" + "}\n" + "\n", + "classname", classname_); + } else { + printer->Print( + "::std::string $classname$::GetTypeName() const {\n" + " return \"$type_name$\";\n" + "}\n" + "\n", + "classname", classname_, + "type_name", descriptor_->full_name()); + } + +} + +void MessageGenerator:: +GenerateOffsets(io::Printer* printer) { + printer->Print( + "static const int $classname$_offsets_[$field_count$] = {\n", + "classname", classname_, + "field_count", SimpleItoa(max(1, descriptor_->field_count()))); + printer->Indent(); + + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + printer->Print( + "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, $name$_),\n", + "classname", classname_, + "name", FieldName(field)); + } + + printer->Outdent(); + printer->Print("};\n"); +} + +void MessageGenerator:: +GenerateSharedConstructorCode(io::Printer* printer) { + printer->Print( + "void $classname$::SharedCtor() {\n", + "classname", classname_); + printer->Indent(); + + printer->Print( + "_cached_size_ = 0;\n"); + + for (int i = 0; i < descriptor_->field_count(); i++) { + field_generators_.get(descriptor_->field(i)) + .GenerateConstructorCode(printer); + } + + printer->Print( + "::memset(_has_bits_, 0, sizeof(_has_bits_));\n"); + + printer->Outdent(); + printer->Print("}\n\n"); +} + +void MessageGenerator:: +GenerateSharedDestructorCode(io::Printer* printer) { + printer->Print( + "void $classname$::SharedDtor() {\n", + "classname", classname_); + printer->Indent(); + // Write the destructors for each field. + for (int i = 0; i < descriptor_->field_count(); i++) { + field_generators_.get(descriptor_->field(i)) + .GenerateDestructorCode(printer); + } + + printer->Print( + "if (this != default_instance_) {\n"); + + // We need to delete all embedded messages. + // TODO(kenton): If we make unset messages point at default instances + // instead of NULL, then it would make sense to move this code into + // MessageFieldGenerator::GenerateDestructorCode(). + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + + if (!field->is_repeated() && + field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + printer->Print(" delete $name$_;\n", + "name", FieldName(field)); + } + } + + printer->Outdent(); + printer->Print( + " }\n" + "}\n" + "\n"); +} + +void MessageGenerator:: +GenerateStructors(io::Printer* printer) { + string superclass = SuperClassName(descriptor_); + + // Generate the default constructor. + printer->Print( + "$classname$::$classname$()\n" + " : $superclass$() {\n" + " SharedCtor();\n" + "}\n", + "classname", classname_, + "superclass", superclass); + + printer->Print( + "\n" + "void $classname$::InitAsDefaultInstance() {\n", + "classname", classname_); + + // The default instance needs all of its embedded message pointers + // cross-linked to other default instances. We can't do this initialization + // in the constructor because some other default instances may not have been + // constructed yet at that time. + // TODO(kenton): Maybe all message fields (even for non-default messages) + // should be initialized to point at default instances rather than NULL? + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + + if (!field->is_repeated() && + field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + printer->Print( + " $name$_ = const_cast< $type$*>(&$type$::default_instance());\n", + "name", FieldName(field), + "type", FieldMessageTypeName(field)); + } + } + printer->Print( + "}\n" + "\n"); + + // Generate the copy constructor. + printer->Print( + "$classname$::$classname$(const $classname$& from)\n" + " : $superclass$() {\n" + " SharedCtor();\n" + " MergeFrom(from);\n" + "}\n" + "\n", + "classname", classname_, + "superclass", superclass); + + // Generate the shared constructor code. + GenerateSharedConstructorCode(printer); + + // Generate the destructor. + printer->Print( + "$classname$::~$classname$() {\n" + " SharedDtor();\n" + "}\n" + "\n", + "classname", classname_); + + // Generate the shared destructor code. + GenerateSharedDestructorCode(printer); + + // Generate SetCachedSize. + printer->Print( + "void $classname$::SetCachedSize(int size) const {\n" + " GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n" + " _cached_size_ = size;\n" + " GOOGLE_SAFE_CONCURRENT_WRITES_END();\n" + "}\n", + "classname", classname_); + + // Only generate this member if it's not disabled. + if (HasDescriptorMethods(descriptor_->file()) && + !descriptor_->options().no_standard_descriptor_accessor()) { + printer->Print( + "const ::google::protobuf::Descriptor* $classname$::descriptor() {\n" + " protobuf_AssignDescriptorsOnce();\n" + " return $classname$_descriptor_;\n" + "}\n" + "\n", + "classname", classname_, + "adddescriptorsname", + GlobalAddDescriptorsName(descriptor_->file()->name())); + } + + printer->Print( + "const $classname$& $classname$::default_instance() {\n" + " if (default_instance_ == NULL) $adddescriptorsname$();" + " return *default_instance_;\n" + "}\n" + "\n" + "$classname$* $classname$::default_instance_ = NULL;\n" + "\n" + "$classname$* $classname$::New() const {\n" + " return new $classname$;\n" + "}\n", + "classname", classname_, + "adddescriptorsname", + GlobalAddDescriptorsName(descriptor_->file()->name())); + +} + +void MessageGenerator:: +GenerateClear(io::Printer* printer) { + printer->Print("void $classname$::Clear() {\n", + "classname", classname_); + printer->Indent(); + + int last_index = -1; + + if (descriptor_->extension_range_count() > 0) { + printer->Print("_extensions_.Clear();\n"); + } + + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + + if (!field->is_repeated()) { + // We can use the fact that _has_bits_ is a giant bitfield to our + // advantage: We can check up to 32 bits at a time for equality to + // zero, and skip the whole range if so. This can improve the speed + // of Clear() for messages which contain a very large number of + // optional fields of which only a few are used at a time. Here, + // we've chosen to check 8 bits at a time rather than 32. + if (i / 8 != last_index / 8 || last_index < 0) { + if (last_index >= 0) { + printer->Outdent(); + printer->Print("}\n"); + } + printer->Print( + "if (_has_bits_[$index$ / 32] & (0xffu << ($index$ % 32))) {\n", + "index", SimpleItoa(field->index())); + printer->Indent(); + } + last_index = i; + + // It's faster to just overwrite primitive types, but we should + // only clear strings and messages if they were set. + // TODO(kenton): Let the CppFieldGenerator decide this somehow. + bool should_check_bit = + field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE || + field->cpp_type() == FieldDescriptor::CPPTYPE_STRING; + + if (should_check_bit) { + printer->Print( + "if (has_$name$()) {\n", + "name", FieldName(field)); + printer->Indent(); + } + + field_generators_.get(field).GenerateClearingCode(printer); + + if (should_check_bit) { + printer->Outdent(); + printer->Print("}\n"); + } + } + } + + if (last_index >= 0) { + printer->Outdent(); + printer->Print("}\n"); + } + + // Repeated fields don't use _has_bits_ so we clear them in a separate + // pass. + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + + if (field->is_repeated()) { + field_generators_.get(field).GenerateClearingCode(printer); + } + } + + printer->Print( + "::memset(_has_bits_, 0, sizeof(_has_bits_));\n"); + + if (HasUnknownFields(descriptor_->file())) { + printer->Print( + "mutable_unknown_fields()->Clear();\n"); + } + + printer->Outdent(); + printer->Print("}\n"); +} + +void MessageGenerator:: +GenerateSwap(io::Printer* printer) { + // Generate the Swap member function. + printer->Print("void $classname$::Swap($classname$* other) {\n", + "classname", classname_); + printer->Indent(); + printer->Print("if (other != this) {\n"); + printer->Indent(); + + if (HasGeneratedMethods(descriptor_->file())) { + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + field_generators_.get(field).GenerateSwappingCode(printer); + } + + for (int i = 0; i < (descriptor_->field_count() + 31) / 32; ++i) { + printer->Print("std::swap(_has_bits_[$i$], other->_has_bits_[$i$]);\n", + "i", SimpleItoa(i)); + } + + if (HasUnknownFields(descriptor_->file())) { + printer->Print("_unknown_fields_.Swap(&other->_unknown_fields_);\n"); + } + printer->Print("std::swap(_cached_size_, other->_cached_size_);\n"); + if (descriptor_->extension_range_count() > 0) { + printer->Print("_extensions_.Swap(&other->_extensions_);\n"); + } + } else { + printer->Print("GetReflection()->Swap(this, other);"); + } + + printer->Outdent(); + printer->Print("}\n"); + printer->Outdent(); + printer->Print("}\n"); +} + +void MessageGenerator:: +GenerateMergeFrom(io::Printer* printer) { + if (HasDescriptorMethods(descriptor_->file())) { + // Generate the generalized MergeFrom (aka that which takes in the Message + // base class as a parameter). + printer->Print( + "void $classname$::MergeFrom(const ::google::protobuf::Message& from) {\n" + " GOOGLE_CHECK_NE(&from, this);\n", + "classname", classname_); + printer->Indent(); + + // Cast the message to the proper type. If we find that the message is + // *not* of the proper type, we can still call Merge via the reflection + // system, as the GOOGLE_CHECK above ensured that we have the same descriptor + // for each message. + printer->Print( + "const $classname$* source =\n" + " ::google::protobuf::internal::dynamic_cast_if_available(\n" + " &from);\n" + "if (source == NULL) {\n" + " ::google::protobuf::internal::ReflectionOps::Merge(from, this);\n" + "} else {\n" + " MergeFrom(*source);\n" + "}\n", + "classname", classname_); + + printer->Outdent(); + printer->Print("}\n\n"); + } else { + // Generate CheckTypeAndMergeFrom(). + printer->Print( + "void $classname$::CheckTypeAndMergeFrom(\n" + " const ::google::protobuf::MessageLite& from) {\n" + " MergeFrom(*::google::protobuf::down_cast(&from));\n" + "}\n" + "\n", + "classname", classname_); + } + + // Generate the class-specific MergeFrom, which avoids the GOOGLE_CHECK and cast. + printer->Print( + "void $classname$::MergeFrom(const $classname$& from) {\n" + " GOOGLE_CHECK_NE(&from, this);\n", + "classname", classname_); + printer->Indent(); + + // Merge Repeated fields. These fields do not require a + // check as we can simply iterate over them. + for (int i = 0; i < descriptor_->field_count(); ++i) { + const FieldDescriptor* field = descriptor_->field(i); + + if (field->is_repeated()) { + field_generators_.get(field).GenerateMergingCode(printer); + } + } + + // Merge Optional and Required fields (after a _has_bit check). + int last_index = -1; + + for (int i = 0; i < descriptor_->field_count(); ++i) { + const FieldDescriptor* field = descriptor_->field(i); + + if (!field->is_repeated()) { + // See above in GenerateClear for an explanation of this. + if (i / 8 != last_index / 8 || last_index < 0) { + if (last_index >= 0) { + printer->Outdent(); + printer->Print("}\n"); + } + printer->Print( + "if (from._has_bits_[$index$ / 32] & (0xffu << ($index$ % 32))) {\n", + "index", SimpleItoa(field->index())); + printer->Indent(); + } + + last_index = i; + + printer->Print( + "if (from.has_$name$()) {\n", + "name", FieldName(field)); + printer->Indent(); + + field_generators_.get(field).GenerateMergingCode(printer); + + printer->Outdent(); + printer->Print("}\n"); + } + } + + if (last_index >= 0) { + printer->Outdent(); + printer->Print("}\n"); + } + + if (descriptor_->extension_range_count() > 0) { + printer->Print("_extensions_.MergeFrom(from._extensions_);\n"); + } + + if (HasUnknownFields(descriptor_->file())) { + printer->Print( + "mutable_unknown_fields()->MergeFrom(from.unknown_fields());\n"); + } + + printer->Outdent(); + printer->Print("}\n"); +} + +void MessageGenerator:: +GenerateCopyFrom(io::Printer* printer) { + if (HasDescriptorMethods(descriptor_->file())) { + // Generate the generalized CopyFrom (aka that which takes in the Message + // base class as a parameter). + printer->Print( + "void $classname$::CopyFrom(const ::google::protobuf::Message& from) {\n", + "classname", classname_); + printer->Indent(); + + printer->Print( + "if (&from == this) return;\n" + "Clear();\n" + "MergeFrom(from);\n"); + + printer->Outdent(); + printer->Print("}\n\n"); + } + + // Generate the class-specific CopyFrom. + printer->Print( + "void $classname$::CopyFrom(const $classname$& from) {\n", + "classname", classname_); + printer->Indent(); + + printer->Print( + "if (&from == this) return;\n" + "Clear();\n" + "MergeFrom(from);\n"); + + printer->Outdent(); + printer->Print("}\n"); +} + +void MessageGenerator:: +GenerateMergeFromCodedStream(io::Printer* printer) { + if (descriptor_->options().message_set_wire_format()) { + // Special-case MessageSet. + printer->Print( + "bool $classname$::MergePartialFromCodedStream(\n" + " ::google::protobuf::io::CodedInputStream* input) {\n" + " return _extensions_.ParseMessageSet(input, default_instance_,\n" + " mutable_unknown_fields());\n" + "}\n", + "classname", classname_); + return; + } + + printer->Print( + "bool $classname$::MergePartialFromCodedStream(\n" + " ::google::protobuf::io::CodedInputStream* input) {\n" + "#define DO_(EXPRESSION) if (!(EXPRESSION)) return false\n" + " ::google::protobuf::uint32 tag;\n" + " while ((tag = input->ReadTag()) != 0) {\n", + "classname", classname_); + + printer->Indent(); + printer->Indent(); + + if (descriptor_->field_count() > 0) { + // We don't even want to print the switch() if we have no fields because + // MSVC dislikes switch() statements that contain only a default value. + + // Note: If we just switched on the tag rather than the field number, we + // could avoid the need for the if() to check the wire type at the beginning + // of each case. However, this is actually a bit slower in practice as it + // creates a jump table that is 8x larger and sparser, and meanwhile the + // if()s are highly predictable. + printer->Print( + "switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {\n"); + + printer->Indent(); + + scoped_array ordered_fields( + SortFieldsByNumber(descriptor_)); + + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = ordered_fields[i]; + + PrintFieldComment(printer, field); + + printer->Print( + "case $number$: {\n", + "number", SimpleItoa(field->number())); + printer->Indent(); + const FieldGenerator& field_generator = field_generators_.get(field); + + // Emit code to parse the common, expected case. + printer->Print( + "if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==\n" + " ::google::protobuf::internal::WireFormatLite::WIRETYPE_$wiretype$) {\n", + "wiretype", kWireTypeNames[WireFormat::WireTypeForField(field)]); + + if (i > 0 || (field->is_repeated() && !field->options().packed())) { + printer->Print( + " parse_$name$:\n", + "name", field->name()); + } + + printer->Indent(); + if (field->options().packed()) { + field_generator.GenerateMergeFromCodedStreamWithPacking(printer); + } else { + field_generator.GenerateMergeFromCodedStream(printer); + } + printer->Outdent(); + + // Emit code to parse unexpectedly packed or unpacked values. + if (field->is_packable() && field->options().packed()) { + printer->Print( + "} else if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag)\n" + " == ::google::protobuf::internal::WireFormatLite::\n" + " WIRETYPE_$wiretype$) {\n", + "wiretype", + kWireTypeNames[WireFormat::WireTypeForFieldType(field->type())]); + printer->Indent(); + field_generator.GenerateMergeFromCodedStream(printer); + printer->Outdent(); + } else if (field->is_packable() && !field->options().packed()) { + printer->Print( + "} else if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag)\n" + " == ::google::protobuf::internal::WireFormatLite::\n" + " WIRETYPE_LENGTH_DELIMITED) {\n"); + printer->Indent(); + field_generator.GenerateMergeFromCodedStreamWithPacking(printer); + printer->Outdent(); + } + + printer->Print( + "} else {\n" + " goto handle_uninterpreted;\n" + "}\n"); + + // switch() is slow since it can't be predicted well. Insert some if()s + // here that attempt to predict the next tag. + if (field->is_repeated() && !field->options().packed()) { + // Expect repeats of this field. + printer->Print( + "if (input->ExpectTag($tag$)) goto parse_$name$;\n", + "tag", SimpleItoa(WireFormat::MakeTag(field)), + "name", field->name()); + } + + if (i + 1 < descriptor_->field_count()) { + // Expect the next field in order. + const FieldDescriptor* next_field = ordered_fields[i + 1]; + printer->Print( + "if (input->ExpectTag($next_tag$)) goto parse_$next_name$;\n", + "next_tag", SimpleItoa(WireFormat::MakeTag(next_field)), + "next_name", next_field->name()); + } else { + // Expect EOF. + // TODO(kenton): Expect group end-tag? + printer->Print( + "if (input->ExpectAtEnd()) return true;\n"); + } + + printer->Print( + "break;\n"); + + printer->Outdent(); + printer->Print("}\n\n"); + } + + printer->Print( + "default: {\n" + "handle_uninterpreted:\n"); + printer->Indent(); + } + + // Is this an end-group tag? If so, this must be the end of the message. + printer->Print( + "if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==\n" + " ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {\n" + " return true;\n" + "}\n"); + + // Handle extension ranges. + if (descriptor_->extension_range_count() > 0) { + printer->Print( + "if ("); + for (int i = 0; i < descriptor_->extension_range_count(); i++) { + const Descriptor::ExtensionRange* range = + descriptor_->extension_range(i); + if (i > 0) printer->Print(" ||\n "); + + uint32 start_tag = WireFormatLite::MakeTag( + range->start, static_cast(0)); + uint32 end_tag = WireFormatLite::MakeTag( + range->end, static_cast(0)); + + if (range->end > FieldDescriptor::kMaxNumber) { + printer->Print( + "($start$u <= tag)", + "start", SimpleItoa(start_tag)); + } else { + printer->Print( + "($start$u <= tag && tag < $end$u)", + "start", SimpleItoa(start_tag), + "end", SimpleItoa(end_tag)); + } + } + printer->Print(") {\n"); + if (HasUnknownFields(descriptor_->file())) { + printer->Print( + " DO_(_extensions_.ParseField(tag, input, default_instance_,\n" + " mutable_unknown_fields()));\n"); + } else { + printer->Print( + " DO_(_extensions_.ParseField(tag, input, default_instance_));\n"); + } + printer->Print( + " continue;\n" + "}\n"); + } + + // We really don't recognize this tag. Skip it. + if (HasUnknownFields(descriptor_->file())) { + printer->Print( + "DO_(::google::protobuf::internal::WireFormat::SkipField(\n" + " input, tag, mutable_unknown_fields()));\n"); + } else { + printer->Print( + "DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));\n"); + } + + if (descriptor_->field_count() > 0) { + printer->Print("break;\n"); + printer->Outdent(); + printer->Print("}\n"); // default: + printer->Outdent(); + printer->Print("}\n"); // switch + } + + printer->Outdent(); + printer->Outdent(); + printer->Print( + " }\n" // while + " return true;\n" + "#undef DO_\n" + "}\n"); +} + +void MessageGenerator::GenerateSerializeOneField( + io::Printer* printer, const FieldDescriptor* field, bool to_array) { + PrintFieldComment(printer, field); + + if (!field->is_repeated()) { + printer->Print( + "if (has_$name$()) {\n", + "name", FieldName(field)); + printer->Indent(); + } + + if (to_array) { + field_generators_.get(field).GenerateSerializeWithCachedSizesToArray( + printer); + } else { + field_generators_.get(field).GenerateSerializeWithCachedSizes(printer); + } + + if (!field->is_repeated()) { + printer->Outdent(); + printer->Print("}\n"); + } + printer->Print("\n"); +} + +void MessageGenerator::GenerateSerializeOneExtensionRange( + io::Printer* printer, const Descriptor::ExtensionRange* range, + bool to_array) { + map vars; + vars["start"] = SimpleItoa(range->start); + vars["end"] = SimpleItoa(range->end); + printer->Print(vars, + "// Extension range [$start$, $end$)\n"); + if (to_array) { + printer->Print(vars, + "target = _extensions_.SerializeWithCachedSizesToArray(\n" + " $start$, $end$, target);\n\n"); + } else { + printer->Print(vars, + "_extensions_.SerializeWithCachedSizes(\n" + " $start$, $end$, output);\n\n"); + } +} + +void MessageGenerator:: +GenerateSerializeWithCachedSizes(io::Printer* printer) { + if (descriptor_->options().message_set_wire_format()) { + // Special-case MessageSet. + printer->Print( + "void $classname$::SerializeWithCachedSizes(\n" + " ::google::protobuf::io::CodedOutputStream* output) const {\n" + " _extensions_.SerializeMessageSetWithCachedSizes(output);\n", + "classname", classname_); + if (HasUnknownFields(descriptor_->file())) { + printer->Print( + " ::google::protobuf::internal::WireFormat::SerializeUnknownMessageSetItems(\n" + " unknown_fields(), output);\n"); + } + printer->Print( + "}\n"); + return; + } + + printer->Print( + "void $classname$::SerializeWithCachedSizes(\n" + " ::google::protobuf::io::CodedOutputStream* output) const {\n", + "classname", classname_); + printer->Indent(); + + GenerateSerializeWithCachedSizesBody(printer, false); + + printer->Outdent(); + printer->Print( + "}\n"); +} + +void MessageGenerator:: +GenerateSerializeWithCachedSizesToArray(io::Printer* printer) { + if (descriptor_->options().message_set_wire_format()) { + // Special-case MessageSet. + printer->Print( + "::google::protobuf::uint8* $classname$::SerializeWithCachedSizesToArray(\n" + " ::google::protobuf::uint8* target) const {\n" + " target =\n" + " _extensions_.SerializeMessageSetWithCachedSizesToArray(target);\n", + "classname", classname_); + if (HasUnknownFields(descriptor_->file())) { + printer->Print( + " target = ::google::protobuf::internal::WireFormat::\n" + " SerializeUnknownMessageSetItemsToArray(\n" + " unknown_fields(), target);\n"); + } + printer->Print( + " return target;\n" + "}\n"); + return; + } + + printer->Print( + "::google::protobuf::uint8* $classname$::SerializeWithCachedSizesToArray(\n" + " ::google::protobuf::uint8* target) const {\n", + "classname", classname_); + printer->Indent(); + + GenerateSerializeWithCachedSizesBody(printer, true); + + printer->Outdent(); + printer->Print( + " return target;\n" + "}\n"); +} + +void MessageGenerator:: +GenerateSerializeWithCachedSizesBody(io::Printer* printer, bool to_array) { + scoped_array ordered_fields( + SortFieldsByNumber(descriptor_)); + + vector sorted_extensions; + for (int i = 0; i < descriptor_->extension_range_count(); ++i) { + sorted_extensions.push_back(descriptor_->extension_range(i)); + } + sort(sorted_extensions.begin(), sorted_extensions.end(), + ExtensionRangeSorter()); + + // Merge the fields and the extension ranges, both sorted by field number. + int i, j; + for (i = 0, j = 0; + i < descriptor_->field_count() || j < sorted_extensions.size(); + ) { + if (i == descriptor_->field_count()) { + GenerateSerializeOneExtensionRange(printer, + sorted_extensions[j++], + to_array); + } else if (j == sorted_extensions.size()) { + GenerateSerializeOneField(printer, ordered_fields[i++], to_array); + } else if (ordered_fields[i]->number() < sorted_extensions[j]->start) { + GenerateSerializeOneField(printer, ordered_fields[i++], to_array); + } else { + GenerateSerializeOneExtensionRange(printer, + sorted_extensions[j++], + to_array); + } + } + + if (HasUnknownFields(descriptor_->file())) { + printer->Print("if (!unknown_fields().empty()) {\n"); + printer->Indent(); + if (to_array) { + printer->Print( + "target = " + "::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(\n" + " unknown_fields(), target);\n"); + } else { + printer->Print( + "::google::protobuf::internal::WireFormat::SerializeUnknownFields(\n" + " unknown_fields(), output);\n"); + } + printer->Outdent(); + + printer->Print( + "}\n"); + } +} + +void MessageGenerator:: +GenerateByteSize(io::Printer* printer) { + if (descriptor_->options().message_set_wire_format()) { + // Special-case MessageSet. + printer->Print( + "int $classname$::ByteSize() const {\n" + " int total_size = _extensions_.MessageSetByteSize();\n", + "classname", classname_); + if (HasUnknownFields(descriptor_->file())) { + printer->Print( + " total_size += ::google::protobuf::internal::WireFormat::\n" + " ComputeUnknownMessageSetItemsSize(unknown_fields());\n"); + } + printer->Print( + " GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n" + " _cached_size_ = total_size;\n" + " GOOGLE_SAFE_CONCURRENT_WRITES_END();\n" + " return total_size;\n" + "}\n"); + return; + } + + printer->Print( + "int $classname$::ByteSize() const {\n", + "classname", classname_); + printer->Indent(); + printer->Print( + "int total_size = 0;\n" + "\n"); + + int last_index = -1; + + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + + if (!field->is_repeated()) { + // See above in GenerateClear for an explanation of this. + // TODO(kenton): Share code? Unclear how to do so without + // over-engineering. + if ((i / 8) != (last_index / 8) || + last_index < 0) { + if (last_index >= 0) { + printer->Outdent(); + printer->Print("}\n"); + } + printer->Print( + "if (_has_bits_[$index$ / 32] & (0xffu << ($index$ % 32))) {\n", + "index", SimpleItoa(field->index())); + printer->Indent(); + } + last_index = i; + + PrintFieldComment(printer, field); + + printer->Print( + "if (has_$name$()) {\n", + "name", FieldName(field)); + printer->Indent(); + + field_generators_.get(field).GenerateByteSize(printer); + + printer->Outdent(); + printer->Print( + "}\n" + "\n"); + } + } + + if (last_index >= 0) { + printer->Outdent(); + printer->Print("}\n"); + } + + // Repeated fields don't use _has_bits_ so we count them in a separate + // pass. + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + + if (field->is_repeated()) { + PrintFieldComment(printer, field); + field_generators_.get(field).GenerateByteSize(printer); + printer->Print("\n"); + } + } + + if (descriptor_->extension_range_count() > 0) { + printer->Print( + "total_size += _extensions_.ByteSize();\n" + "\n"); + } + + if (HasUnknownFields(descriptor_->file())) { + printer->Print("if (!unknown_fields().empty()) {\n"); + printer->Indent(); + printer->Print( + "total_size +=\n" + " ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(\n" + " unknown_fields());\n"); + printer->Outdent(); + printer->Print("}\n"); + } + + // We update _cached_size_ even though this is a const method. In theory, + // this is not thread-compatible, because concurrent writes have undefined + // results. In practice, since any concurrent writes will be writing the + // exact same value, it works on all common processors. In a future version + // of C++, _cached_size_ should be made into an atomic. + printer->Print( + "GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n" + "_cached_size_ = total_size;\n" + "GOOGLE_SAFE_CONCURRENT_WRITES_END();\n" + "return total_size;\n"); + + printer->Outdent(); + printer->Print("}\n"); +} + +void MessageGenerator:: +GenerateIsInitialized(io::Printer* printer) { + printer->Print( + "bool $classname$::IsInitialized() const {\n", + "classname", classname_); + printer->Indent(); + + // Check that all required fields in this message are set. We can do this + // most efficiently by checking 32 "has bits" at a time. + int has_bits_array_size = (descriptor_->field_count() + 31) / 32; + for (int i = 0; i < has_bits_array_size; i++) { + uint32 mask = 0; + for (int bit = 0; bit < 32; bit++) { + int index = i * 32 + bit; + if (index >= descriptor_->field_count()) break; + const FieldDescriptor* field = descriptor_->field(index); + + if (field->is_required()) { + mask |= 1 << bit; + } + } + + if (mask != 0) { + char buffer[kFastToBufferSize]; + printer->Print( + "if ((_has_bits_[$i$] & 0x$mask$) != 0x$mask$) return false;\n", + "i", SimpleItoa(i), + "mask", FastHex32ToBuffer(mask, buffer)); + } + } + + // Now check that all embedded messages are initialized. + printer->Print("\n"); + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && + HasRequiredFields(field->message_type())) { + if (field->is_repeated()) { + printer->Print( + "for (int i = 0; i < $name$_size(); i++) {\n" + " if (!this->$name$(i).IsInitialized()) return false;\n" + "}\n", + "name", FieldName(field)); + } else { + printer->Print( + "if (has_$name$()) {\n" + " if (!this->$name$().IsInitialized()) return false;\n" + "}\n", + "name", FieldName(field)); + } + } + } + + if (descriptor_->extension_range_count() > 0) { + printer->Print( + "\n" + "if (!_extensions_.IsInitialized()) return false;"); + } + + printer->Outdent(); + printer->Print( + " return true;\n" + "}\n"); +} + + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/depends/protobuf/google/protobuf/compiler/cpp/cpp_message.h b/depends/protobuf/google/protobuf/compiler/cpp/cpp_message.h new file mode 100644 index 0000000000..04778f6d1e --- /dev/null +++ b/depends/protobuf/google/protobuf/compiler/cpp/cpp_message.h @@ -0,0 +1,170 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_H__ +#define GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_H__ + +#include +#include +#include + +namespace google { +namespace protobuf { + namespace io { + class Printer; // printer.h + } +} + +namespace protobuf { +namespace compiler { +namespace cpp { + +class EnumGenerator; // enum.h +class ExtensionGenerator; // extension.h + +class MessageGenerator { + public: + // See generator.cc for the meaning of dllexport_decl. + explicit MessageGenerator(const Descriptor* descriptor, + const string& dllexport_decl); + ~MessageGenerator(); + + // Header stuff. + + // Generate foward declarations for this class and all its nested types. + void GenerateForwardDeclaration(io::Printer* printer); + + // Generate definitions of all nested enums (must come before class + // definitions because those classes use the enums definitions). + void GenerateEnumDefinitions(io::Printer* printer); + + // Generate specializations of GetEnumDescriptor(). + // Precondition: in ::google::protobuf namespace. + void GenerateGetEnumDescriptorSpecializations(io::Printer* printer); + + // Generate definitions for this class and all its nested types. + void GenerateClassDefinition(io::Printer* printer); + + // Generate definitions of inline methods (placed at the end of the header + // file). + void GenerateInlineMethods(io::Printer* printer); + + // Source file stuff. + + // Generate code which declares all the global descriptor pointers which + // will be initialized by the methods below. + void GenerateDescriptorDeclarations(io::Printer* printer); + + // Generate code that initializes the global variable storing the message's + // descriptor. + void GenerateDescriptorInitializer(io::Printer* printer, int index); + + // Generate code that calls MessageFactory::InternalRegisterGeneratedMessage() + // for all types. + void GenerateTypeRegistrations(io::Printer* printer); + + // Generates code that allocates the message's default instance. + void GenerateDefaultInstanceAllocator(io::Printer* printer); + + // Generates code that initializes the message's default instance. This + // is separate from allocating because all default instances must be + // allocated before any can be initialized. + void GenerateDefaultInstanceInitializer(io::Printer* printer); + + // Generates code that should be run when ShutdownProtobufLibrary() is called, + // to delete all dynamically-allocated objects. + void GenerateShutdownCode(io::Printer* printer); + + // Generate all non-inline methods for this class. + void GenerateClassMethods(io::Printer* printer); + + private: + // Generate declarations and definitions of accessors for fields. + void GenerateFieldAccessorDeclarations(io::Printer* printer); + void GenerateFieldAccessorDefinitions(io::Printer* printer); + + // Generate the field offsets array. + void GenerateOffsets(io::Printer* printer); + + // Generate constructors and destructor. + void GenerateStructors(io::Printer* printer); + + // The compiler typically generates multiple copies of each constructor and + // destructor: http://gcc.gnu.org/bugs.html#nonbugs_cxx + // Placing common code in a separate method reduces the generated code size. + // + // Generate the shared constructor code. + void GenerateSharedConstructorCode(io::Printer* printer); + // Generate the shared destructor code. + void GenerateSharedDestructorCode(io::Printer* printer); + + // Generate standard Message methods. + void GenerateClear(io::Printer* printer); + void GenerateMergeFromCodedStream(io::Printer* printer); + void GenerateSerializeWithCachedSizes(io::Printer* printer); + void GenerateSerializeWithCachedSizesToArray(io::Printer* printer); + void GenerateSerializeWithCachedSizesBody(io::Printer* printer, + bool to_array); + void GenerateByteSize(io::Printer* printer); + void GenerateMergeFrom(io::Printer* printer); + void GenerateCopyFrom(io::Printer* printer); + void GenerateSwap(io::Printer* printer); + void GenerateIsInitialized(io::Printer* printer); + + // Helpers for GenerateSerializeWithCachedSizes(). + void GenerateSerializeOneField(io::Printer* printer, + const FieldDescriptor* field, + bool unbounded); + void GenerateSerializeOneExtensionRange( + io::Printer* printer, const Descriptor::ExtensionRange* range, + bool unbounded); + + + const Descriptor* descriptor_; + string classname_; + string dllexport_decl_; + FieldGeneratorMap field_generators_; + scoped_array > nested_generators_; + scoped_array > enum_generators_; + scoped_array > extension_generators_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageGenerator); +}; + +} // namespace cpp +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_H__ diff --git a/depends/protobuf/google/protobuf/compiler/cpp/cpp_message_field.cc b/depends/protobuf/google/protobuf/compiler/cpp/cpp_message_field.cc new file mode 100644 index 0000000000..23e75b87d4 --- /dev/null +++ b/depends/protobuf/google/protobuf/compiler/cpp/cpp_message_field.cc @@ -0,0 +1,277 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include +#include +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +namespace { + +void SetMessageVariables(const FieldDescriptor* descriptor, + map* variables) { + SetCommonFieldVariables(descriptor, variables); + (*variables)["type"] = FieldMessageTypeName(descriptor); + (*variables)["stream_writer"] = (*variables)["declared_type"] + + (HasFastArraySerialization(descriptor->message_type()->file()) ? + "MaybeToArray" : + ""); +} + +} // namespace + +// =================================================================== + +MessageFieldGenerator:: +MessageFieldGenerator(const FieldDescriptor* descriptor) + : descriptor_(descriptor) { + SetMessageVariables(descriptor, &variables_); +} + +MessageFieldGenerator::~MessageFieldGenerator() {} + +void MessageFieldGenerator:: +GeneratePrivateMembers(io::Printer* printer) const { + printer->Print(variables_, "$type$* $name$_;\n"); +} + +void MessageFieldGenerator:: +GenerateAccessorDeclarations(io::Printer* printer) const { + printer->Print(variables_, + "inline const $type$& $name$() const$deprecation$;\n" + "inline $type$* mutable_$name$()$deprecation$;\n" + "inline $type$* release_$name$()$deprecation$;\n"); +} + +void MessageFieldGenerator:: +GenerateInlineAccessorDefinitions(io::Printer* printer) const { + printer->Print(variables_, + "inline const $type$& $classname$::$name$() const {\n" + " return $name$_ != NULL ? *$name$_ : *default_instance_->$name$_;\n" + "}\n" + "inline $type$* $classname$::mutable_$name$() {\n" + " set_has_$name$();\n" + " if ($name$_ == NULL) $name$_ = new $type$;\n" + " return $name$_;\n" + "}\n" + "inline $type$* $classname$::release_$name$() {\n" + " clear_has_$name$();\n" + " $type$* temp = $name$_;\n" + " $name$_ = NULL;\n" + " return temp;\n" + "}\n"); +} + +void MessageFieldGenerator:: +GenerateClearingCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($name$_ != NULL) $name$_->$type$::Clear();\n"); +} + +void MessageFieldGenerator:: +GenerateMergingCode(io::Printer* printer) const { + printer->Print(variables_, + "mutable_$name$()->$type$::MergeFrom(from.$name$());\n"); +} + +void MessageFieldGenerator:: +GenerateSwappingCode(io::Printer* printer) const { + printer->Print(variables_, "std::swap($name$_, other->$name$_);\n"); +} + +void MessageFieldGenerator:: +GenerateConstructorCode(io::Printer* printer) const { + printer->Print(variables_, "$name$_ = NULL;\n"); +} + +void MessageFieldGenerator:: +GenerateMergeFromCodedStream(io::Printer* printer) const { + if (descriptor_->type() == FieldDescriptor::TYPE_MESSAGE) { + printer->Print(variables_, + "DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(\n" + " input, mutable_$name$()));\n"); + } else { + printer->Print(variables_, + "DO_(::google::protobuf::internal::WireFormatLite::ReadGroupNoVirtual(\n" + " $number$, input, mutable_$name$()));\n"); + } +} + +void MessageFieldGenerator:: +GenerateSerializeWithCachedSizes(io::Printer* printer) const { + printer->Print(variables_, + "::google::protobuf::internal::WireFormatLite::Write$stream_writer$(\n" + " $number$, this->$name$(), output);\n"); +} + +void MessageFieldGenerator:: +GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { + printer->Print(variables_, + "target = ::google::protobuf::internal::WireFormatLite::\n" + " Write$declared_type$NoVirtualToArray(\n" + " $number$, this->$name$(), target);\n"); +} + +void MessageFieldGenerator:: +GenerateByteSize(io::Printer* printer) const { + printer->Print(variables_, + "total_size += $tag_size$ +\n" + " ::google::protobuf::internal::WireFormatLite::$declared_type$SizeNoVirtual(\n" + " this->$name$());\n"); +} + +// =================================================================== + +RepeatedMessageFieldGenerator:: +RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor) + : descriptor_(descriptor) { + SetMessageVariables(descriptor, &variables_); +} + +RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() {} + +void RepeatedMessageFieldGenerator:: +GeneratePrivateMembers(io::Printer* printer) const { + printer->Print(variables_, + "::google::protobuf::RepeatedPtrField< $type$ > $name$_;\n"); +} + +void RepeatedMessageFieldGenerator:: +GenerateAccessorDeclarations(io::Printer* printer) const { + printer->Print(variables_, + "inline const $type$& $name$(int index) const$deprecation$;\n" + "inline $type$* mutable_$name$(int index)$deprecation$;\n" + "inline $type$* add_$name$()$deprecation$;\n"); + printer->Print(variables_, + "inline const ::google::protobuf::RepeatedPtrField< $type$ >&\n" + " $name$() const$deprecation$;\n" + "inline ::google::protobuf::RepeatedPtrField< $type$ >*\n" + " mutable_$name$()$deprecation$;\n"); +} + +void RepeatedMessageFieldGenerator:: +GenerateInlineAccessorDefinitions(io::Printer* printer) const { + printer->Print(variables_, + "inline const $type$& $classname$::$name$(int index) const {\n" + " return $name$_.Get(index);\n" + "}\n" + "inline $type$* $classname$::mutable_$name$(int index) {\n" + " return $name$_.Mutable(index);\n" + "}\n" + "inline $type$* $classname$::add_$name$() {\n" + " return $name$_.Add();\n" + "}\n"); + printer->Print(variables_, + "inline const ::google::protobuf::RepeatedPtrField< $type$ >&\n" + "$classname$::$name$() const {\n" + " return $name$_;\n" + "}\n" + "inline ::google::protobuf::RepeatedPtrField< $type$ >*\n" + "$classname$::mutable_$name$() {\n" + " return &$name$_;\n" + "}\n"); +} + +void RepeatedMessageFieldGenerator:: +GenerateClearingCode(io::Printer* printer) const { + printer->Print(variables_, "$name$_.Clear();\n"); +} + +void RepeatedMessageFieldGenerator:: +GenerateMergingCode(io::Printer* printer) const { + printer->Print(variables_, "$name$_.MergeFrom(from.$name$_);\n"); +} + +void RepeatedMessageFieldGenerator:: +GenerateSwappingCode(io::Printer* printer) const { + printer->Print(variables_, "$name$_.Swap(&other->$name$_);\n"); +} + +void RepeatedMessageFieldGenerator:: +GenerateConstructorCode(io::Printer* printer) const { + // Not needed for repeated fields. +} + +void RepeatedMessageFieldGenerator:: +GenerateMergeFromCodedStream(io::Printer* printer) const { + if (descriptor_->type() == FieldDescriptor::TYPE_MESSAGE) { + printer->Print(variables_, + "DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(\n" + " input, add_$name$()));\n"); + } else { + printer->Print(variables_, + "DO_(::google::protobuf::internal::WireFormatLite::ReadGroupNoVirtual(\n" + " $number$, input, add_$name$()));\n"); + } +} + +void RepeatedMessageFieldGenerator:: +GenerateSerializeWithCachedSizes(io::Printer* printer) const { + printer->Print(variables_, + "for (int i = 0; i < this->$name$_size(); i++) {\n" + " ::google::protobuf::internal::WireFormatLite::Write$stream_writer$(\n" + " $number$, this->$name$(i), output);\n" + "}\n"); +} + +void RepeatedMessageFieldGenerator:: +GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { + printer->Print(variables_, + "for (int i = 0; i < this->$name$_size(); i++) {\n" + " target = ::google::protobuf::internal::WireFormatLite::\n" + " Write$declared_type$NoVirtualToArray(\n" + " $number$, this->$name$(i), target);\n" + "}\n"); +} + +void RepeatedMessageFieldGenerator:: +GenerateByteSize(io::Printer* printer) const { + printer->Print(variables_, + "total_size += $tag_size$ * this->$name$_size();\n" + "for (int i = 0; i < this->$name$_size(); i++) {\n" + " total_size +=\n" + " ::google::protobuf::internal::WireFormatLite::$declared_type$SizeNoVirtual(\n" + " this->$name$(i));\n" + "}\n"); +} + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/depends/protobuf/google/protobuf/compiler/cpp/cpp_message_field.h b/depends/protobuf/google/protobuf/compiler/cpp/cpp_message_field.h new file mode 100644 index 0000000000..f5147278b4 --- /dev/null +++ b/depends/protobuf/google/protobuf/compiler/cpp/cpp_message_field.h @@ -0,0 +1,102 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_FIELD_H__ + +#include +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +class MessageFieldGenerator : public FieldGenerator { + public: + explicit MessageFieldGenerator(const FieldDescriptor* descriptor); + ~MessageFieldGenerator(); + + // implements FieldGenerator --------------------------------------- + void GeneratePrivateMembers(io::Printer* printer) const; + void GenerateAccessorDeclarations(io::Printer* printer) const; + void GenerateInlineAccessorDefinitions(io::Printer* printer) const; + void GenerateClearingCode(io::Printer* printer) const; + void GenerateMergingCode(io::Printer* printer) const; + void GenerateSwappingCode(io::Printer* printer) const; + void GenerateConstructorCode(io::Printer* printer) const; + void GenerateMergeFromCodedStream(io::Printer* printer) const; + void GenerateSerializeWithCachedSizes(io::Printer* printer) const; + void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const; + void GenerateByteSize(io::Printer* printer) const; + + private: + const FieldDescriptor* descriptor_; + map variables_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageFieldGenerator); +}; + +class RepeatedMessageFieldGenerator : public FieldGenerator { + public: + explicit RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor); + ~RepeatedMessageFieldGenerator(); + + // implements FieldGenerator --------------------------------------- + void GeneratePrivateMembers(io::Printer* printer) const; + void GenerateAccessorDeclarations(io::Printer* printer) const; + void GenerateInlineAccessorDefinitions(io::Printer* printer) const; + void GenerateClearingCode(io::Printer* printer) const; + void GenerateMergingCode(io::Printer* printer) const; + void GenerateSwappingCode(io::Printer* printer) const; + void GenerateConstructorCode(io::Printer* printer) const; + void GenerateMergeFromCodedStream(io::Printer* printer) const; + void GenerateSerializeWithCachedSizes(io::Printer* printer) const; + void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const; + void GenerateByteSize(io::Printer* printer) const; + + private: + const FieldDescriptor* descriptor_; + map variables_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedMessageFieldGenerator); +}; + +} // namespace cpp +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_FIELD_H__ diff --git a/depends/protobuf/google/protobuf/compiler/cpp/cpp_primitive_field.cc b/depends/protobuf/google/protobuf/compiler/cpp/cpp_primitive_field.cc new file mode 100644 index 0000000000..5e8df0f497 --- /dev/null +++ b/depends/protobuf/google/protobuf/compiler/cpp/cpp_primitive_field.cc @@ -0,0 +1,382 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +using internal::WireFormatLite; + +namespace { + +// For encodings with fixed sizes, returns that size in bytes. Otherwise +// returns -1. +int FixedSize(FieldDescriptor::Type type) { + switch (type) { + case FieldDescriptor::TYPE_INT32 : return -1; + case FieldDescriptor::TYPE_INT64 : return -1; + case FieldDescriptor::TYPE_UINT32 : return -1; + case FieldDescriptor::TYPE_UINT64 : return -1; + case FieldDescriptor::TYPE_SINT32 : return -1; + case FieldDescriptor::TYPE_SINT64 : return -1; + case FieldDescriptor::TYPE_FIXED32 : return WireFormatLite::kFixed32Size; + case FieldDescriptor::TYPE_FIXED64 : return WireFormatLite::kFixed64Size; + case FieldDescriptor::TYPE_SFIXED32: return WireFormatLite::kSFixed32Size; + case FieldDescriptor::TYPE_SFIXED64: return WireFormatLite::kSFixed64Size; + case FieldDescriptor::TYPE_FLOAT : return WireFormatLite::kFloatSize; + case FieldDescriptor::TYPE_DOUBLE : return WireFormatLite::kDoubleSize; + + case FieldDescriptor::TYPE_BOOL : return WireFormatLite::kBoolSize; + case FieldDescriptor::TYPE_ENUM : return -1; + + case FieldDescriptor::TYPE_STRING : return -1; + case FieldDescriptor::TYPE_BYTES : return -1; + case FieldDescriptor::TYPE_GROUP : return -1; + case FieldDescriptor::TYPE_MESSAGE : return -1; + + // No default because we want the compiler to complain if any new + // types are added. + } + GOOGLE_LOG(FATAL) << "Can't get here."; + return -1; +} + +void SetPrimitiveVariables(const FieldDescriptor* descriptor, + map* variables) { + SetCommonFieldVariables(descriptor, variables); + (*variables)["type"] = PrimitiveTypeName(descriptor->cpp_type()); + (*variables)["default"] = DefaultValue(descriptor); + (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor)); + int fixed_size = FixedSize(descriptor->type()); + if (fixed_size != -1) { + (*variables)["fixed_size"] = SimpleItoa(fixed_size); + } + (*variables)["wire_format_field_type"] = + "::google::protobuf::internal::WireFormatLite::" + FieldDescriptorProto_Type_Name( + static_cast(descriptor->type())); +} + +} // namespace + +// =================================================================== + +PrimitiveFieldGenerator:: +PrimitiveFieldGenerator(const FieldDescriptor* descriptor) + : descriptor_(descriptor) { + SetPrimitiveVariables(descriptor, &variables_); +} + +PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {} + +void PrimitiveFieldGenerator:: +GeneratePrivateMembers(io::Printer* printer) const { + printer->Print(variables_, "$type$ $name$_;\n"); +} + +void PrimitiveFieldGenerator:: +GenerateAccessorDeclarations(io::Printer* printer) const { + printer->Print(variables_, + "inline $type$ $name$() const$deprecation$;\n" + "inline void set_$name$($type$ value)$deprecation$;\n"); +} + +void PrimitiveFieldGenerator:: +GenerateInlineAccessorDefinitions(io::Printer* printer) const { + printer->Print(variables_, + "inline $type$ $classname$::$name$() const {\n" + " return $name$_;\n" + "}\n" + "inline void $classname$::set_$name$($type$ value) {\n" + " set_has_$name$();\n" + " $name$_ = value;\n" + "}\n"); +} + +void PrimitiveFieldGenerator:: +GenerateClearingCode(io::Printer* printer) const { + printer->Print(variables_, "$name$_ = $default$;\n"); +} + +void PrimitiveFieldGenerator:: +GenerateMergingCode(io::Printer* printer) const { + printer->Print(variables_, "set_$name$(from.$name$());\n"); +} + +void PrimitiveFieldGenerator:: +GenerateSwappingCode(io::Printer* printer) const { + printer->Print(variables_, "std::swap($name$_, other->$name$_);\n"); +} + +void PrimitiveFieldGenerator:: +GenerateConstructorCode(io::Printer* printer) const { + printer->Print(variables_, "$name$_ = $default$;\n"); +} + +void PrimitiveFieldGenerator:: +GenerateMergeFromCodedStream(io::Printer* printer) const { + printer->Print(variables_, + "DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n" + " $type$, $wire_format_field_type$>(\n" + " input, &$name$_)));\n" + "set_has_$name$();\n"); +} + +void PrimitiveFieldGenerator:: +GenerateSerializeWithCachedSizes(io::Printer* printer) const { + printer->Print(variables_, + "::google::protobuf::internal::WireFormatLite::Write$declared_type$(" + "$number$, this->$name$(), output);\n"); +} + +void PrimitiveFieldGenerator:: +GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { + printer->Print(variables_, + "target = ::google::protobuf::internal::WireFormatLite::Write$declared_type$ToArray(" + "$number$, this->$name$(), target);\n"); +} + +void PrimitiveFieldGenerator:: +GenerateByteSize(io::Printer* printer) const { + int fixed_size = FixedSize(descriptor_->type()); + if (fixed_size == -1) { + printer->Print(variables_, + "total_size += $tag_size$ +\n" + " ::google::protobuf::internal::WireFormatLite::$declared_type$Size(\n" + " this->$name$());\n"); + } else { + printer->Print(variables_, + "total_size += $tag_size$ + $fixed_size$;\n"); + } +} + +// =================================================================== + +RepeatedPrimitiveFieldGenerator:: +RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor) + : descriptor_(descriptor) { + SetPrimitiveVariables(descriptor, &variables_); + + if (descriptor->options().packed()) { + variables_["packed_reader"] = "ReadPackedPrimitive"; + variables_["repeated_reader"] = "ReadRepeatedPrimitiveNoInline"; + } else { + variables_["packed_reader"] = "ReadPackedPrimitiveNoInline"; + variables_["repeated_reader"] = "ReadRepeatedPrimitive"; + } +} + +RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {} + +void RepeatedPrimitiveFieldGenerator:: +GeneratePrivateMembers(io::Printer* printer) const { + printer->Print(variables_, + "::google::protobuf::RepeatedField< $type$ > $name$_;\n"); + if (descriptor_->options().packed() && HasGeneratedMethods(descriptor_->file())) { + printer->Print(variables_, + "mutable int _$name$_cached_byte_size_;\n"); + } +} + +void RepeatedPrimitiveFieldGenerator:: +GenerateAccessorDeclarations(io::Printer* printer) const { + printer->Print(variables_, + "inline $type$ $name$(int index) const$deprecation$;\n" + "inline void set_$name$(int index, $type$ value)$deprecation$;\n" + "inline void add_$name$($type$ value)$deprecation$;\n"); + printer->Print(variables_, + "inline const ::google::protobuf::RepeatedField< $type$ >&\n" + " $name$() const$deprecation$;\n" + "inline ::google::protobuf::RepeatedField< $type$ >*\n" + " mutable_$name$()$deprecation$;\n"); +} + +void RepeatedPrimitiveFieldGenerator:: +GenerateInlineAccessorDefinitions(io::Printer* printer) const { + printer->Print(variables_, + "inline $type$ $classname$::$name$(int index) const {\n" + " return $name$_.Get(index);\n" + "}\n" + "inline void $classname$::set_$name$(int index, $type$ value) {\n" + " $name$_.Set(index, value);\n" + "}\n" + "inline void $classname$::add_$name$($type$ value) {\n" + " $name$_.Add(value);\n" + "}\n"); + printer->Print(variables_, + "inline const ::google::protobuf::RepeatedField< $type$ >&\n" + "$classname$::$name$() const {\n" + " return $name$_;\n" + "}\n" + "inline ::google::protobuf::RepeatedField< $type$ >*\n" + "$classname$::mutable_$name$() {\n" + " return &$name$_;\n" + "}\n"); +} + +void RepeatedPrimitiveFieldGenerator:: +GenerateClearingCode(io::Printer* printer) const { + printer->Print(variables_, "$name$_.Clear();\n"); +} + +void RepeatedPrimitiveFieldGenerator:: +GenerateMergingCode(io::Printer* printer) const { + printer->Print(variables_, "$name$_.MergeFrom(from.$name$_);\n"); +} + +void RepeatedPrimitiveFieldGenerator:: +GenerateSwappingCode(io::Printer* printer) const { + printer->Print(variables_, "$name$_.Swap(&other->$name$_);\n"); +} + +void RepeatedPrimitiveFieldGenerator:: +GenerateConstructorCode(io::Printer* printer) const { + // Not needed for repeated fields. +} + +void RepeatedPrimitiveFieldGenerator:: +GenerateMergeFromCodedStream(io::Printer* printer) const { + printer->Print(variables_, + "DO_((::google::protobuf::internal::WireFormatLite::$repeated_reader$<\n" + " $type$, $wire_format_field_type$>(\n" + " $tag_size$, $tag$, input, this->mutable_$name$())));\n"); +} + +void RepeatedPrimitiveFieldGenerator:: +GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const { + printer->Print(variables_, + "DO_((::google::protobuf::internal::WireFormatLite::$packed_reader$<\n" + " $type$, $wire_format_field_type$>(\n" + " input, this->mutable_$name$())));\n"); +} + +void RepeatedPrimitiveFieldGenerator:: +GenerateSerializeWithCachedSizes(io::Printer* printer) const { + if (descriptor_->options().packed()) { + // Write the tag and the size. + printer->Print(variables_, + "if (this->$name$_size() > 0) {\n" + " ::google::protobuf::internal::WireFormatLite::WriteTag(" + "$number$, " + "::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, " + "output);\n" + " output->WriteVarint32(_$name$_cached_byte_size_);\n" + "}\n"); + } + printer->Print(variables_, + "for (int i = 0; i < this->$name$_size(); i++) {\n"); + if (descriptor_->options().packed()) { + printer->Print(variables_, + " ::google::protobuf::internal::WireFormatLite::Write$declared_type$NoTag(\n" + " this->$name$(i), output);\n"); + } else { + printer->Print(variables_, + " ::google::protobuf::internal::WireFormatLite::Write$declared_type$(\n" + " $number$, this->$name$(i), output);\n"); + } + printer->Print("}\n"); +} + +void RepeatedPrimitiveFieldGenerator:: +GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { + if (descriptor_->options().packed()) { + // Write the tag and the size. + printer->Print(variables_, + "if (this->$name$_size() > 0) {\n" + " target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(\n" + " $number$,\n" + " ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,\n" + " target);\n" + " target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(\n" + " _$name$_cached_byte_size_, target);\n" + "}\n"); + } + printer->Print(variables_, + "for (int i = 0; i < this->$name$_size(); i++) {\n"); + if (descriptor_->options().packed()) { + printer->Print(variables_, + " target = ::google::protobuf::internal::WireFormatLite::\n" + " Write$declared_type$NoTagToArray(this->$name$(i), target);\n"); + } else { + printer->Print(variables_, + " target = ::google::protobuf::internal::WireFormatLite::\n" + " Write$declared_type$ToArray($number$, this->$name$(i), target);\n"); + } + printer->Print("}\n"); +} + +void RepeatedPrimitiveFieldGenerator:: +GenerateByteSize(io::Printer* printer) const { + printer->Print(variables_, + "{\n" + " int data_size = 0;\n"); + printer->Indent(); + int fixed_size = FixedSize(descriptor_->type()); + if (fixed_size == -1) { + printer->Print(variables_, + "for (int i = 0; i < this->$name$_size(); i++) {\n" + " data_size += ::google::protobuf::internal::WireFormatLite::\n" + " $declared_type$Size(this->$name$(i));\n" + "}\n"); + } else { + printer->Print(variables_, + "data_size = $fixed_size$ * this->$name$_size();\n"); + } + + if (descriptor_->options().packed()) { + printer->Print(variables_, + "if (data_size > 0) {\n" + " total_size += $tag_size$ +\n" + " ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);\n" + "}\n" + "_$name$_cached_byte_size_ = data_size;\n" + "total_size += data_size;\n"); + } else { + printer->Print(variables_, + "total_size += $tag_size$ * this->$name$_size() + data_size;\n"); + } + printer->Outdent(); + printer->Print("}\n"); +} + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/depends/protobuf/google/protobuf/compiler/cpp/cpp_primitive_field.h b/depends/protobuf/google/protobuf/compiler/cpp/cpp_primitive_field.h new file mode 100644 index 0000000000..8fcd74ae55 --- /dev/null +++ b/depends/protobuf/google/protobuf/compiler/cpp/cpp_primitive_field.h @@ -0,0 +1,103 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_PRIMITIVE_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_CPP_PRIMITIVE_FIELD_H__ + +#include +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +class PrimitiveFieldGenerator : public FieldGenerator { + public: + explicit PrimitiveFieldGenerator(const FieldDescriptor* descriptor); + ~PrimitiveFieldGenerator(); + + // implements FieldGenerator --------------------------------------- + void GeneratePrivateMembers(io::Printer* printer) const; + void GenerateAccessorDeclarations(io::Printer* printer) const; + void GenerateInlineAccessorDefinitions(io::Printer* printer) const; + void GenerateClearingCode(io::Printer* printer) const; + void GenerateMergingCode(io::Printer* printer) const; + void GenerateSwappingCode(io::Printer* printer) const; + void GenerateConstructorCode(io::Printer* printer) const; + void GenerateMergeFromCodedStream(io::Printer* printer) const; + void GenerateSerializeWithCachedSizes(io::Printer* printer) const; + void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const; + void GenerateByteSize(io::Printer* printer) const; + + private: + const FieldDescriptor* descriptor_; + map variables_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveFieldGenerator); +}; + +class RepeatedPrimitiveFieldGenerator : public FieldGenerator { + public: + explicit RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor); + ~RepeatedPrimitiveFieldGenerator(); + + // implements FieldGenerator --------------------------------------- + void GeneratePrivateMembers(io::Printer* printer) const; + void GenerateAccessorDeclarations(io::Printer* printer) const; + void GenerateInlineAccessorDefinitions(io::Printer* printer) const; + void GenerateClearingCode(io::Printer* printer) const; + void GenerateMergingCode(io::Printer* printer) const; + void GenerateSwappingCode(io::Printer* printer) const; + void GenerateConstructorCode(io::Printer* printer) const; + void GenerateMergeFromCodedStream(io::Printer* printer) const; + void GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const; + void GenerateSerializeWithCachedSizes(io::Printer* printer) const; + void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const; + void GenerateByteSize(io::Printer* printer) const; + + private: + const FieldDescriptor* descriptor_; + map variables_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPrimitiveFieldGenerator); +}; + +} // namespace cpp +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_CPP_PRIMITIVE_FIELD_H__ diff --git a/depends/protobuf/google/protobuf/compiler/cpp/cpp_service.cc b/depends/protobuf/google/protobuf/compiler/cpp/cpp_service.cc new file mode 100644 index 0000000000..c282568354 --- /dev/null +++ b/depends/protobuf/google/protobuf/compiler/cpp/cpp_service.cc @@ -0,0 +1,334 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include +#include +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +ServiceGenerator::ServiceGenerator(const ServiceDescriptor* descriptor, + const string& dllexport_decl) + : descriptor_(descriptor) { + vars_["classname"] = descriptor_->name(); + vars_["full_name"] = descriptor_->full_name(); + if (dllexport_decl.empty()) { + vars_["dllexport"] = ""; + } else { + vars_["dllexport"] = dllexport_decl + " "; + } +} + +ServiceGenerator::~ServiceGenerator() {} + +void ServiceGenerator::GenerateDeclarations(io::Printer* printer) { + // Forward-declare the stub type. + printer->Print(vars_, + "class $classname$_Stub;\n" + "\n"); + + GenerateInterface(printer); + GenerateStubDefinition(printer); +} + +void ServiceGenerator::GenerateInterface(io::Printer* printer) { + printer->Print(vars_, + "class $dllexport$$classname$ : public ::google::protobuf::Service {\n" + " protected:\n" + " // This class should be treated as an abstract interface.\n" + " inline $classname$() {};\n" + " public:\n" + " virtual ~$classname$();\n"); + printer->Indent(); + + printer->Print(vars_, + "\n" + "typedef $classname$_Stub Stub;\n" + "\n" + "static const ::google::protobuf::ServiceDescriptor* descriptor();\n" + "\n"); + + GenerateMethodSignatures(VIRTUAL, printer); + + printer->Print( + "\n" + "// implements Service ----------------------------------------------\n" + "\n" + "const ::google::protobuf::ServiceDescriptor* GetDescriptor();\n" + "void CallMethod(const ::google::protobuf::MethodDescriptor* method,\n" + " ::google::protobuf::RpcController* controller,\n" + " const ::google::protobuf::Message* request,\n" + " ::google::protobuf::Message* response,\n" + " ::google::protobuf::Closure* done);\n" + "const ::google::protobuf::Message& GetRequestPrototype(\n" + " const ::google::protobuf::MethodDescriptor* method) const;\n" + "const ::google::protobuf::Message& GetResponsePrototype(\n" + " const ::google::protobuf::MethodDescriptor* method) const;\n"); + + printer->Outdent(); + printer->Print(vars_, + "\n" + " private:\n" + " GOOGLE_DISALLOW_EVIL_CONSTRUCTORS($classname$);\n" + "};\n" + "\n"); +} + +void ServiceGenerator::GenerateStubDefinition(io::Printer* printer) { + printer->Print(vars_, + "class $dllexport$$classname$_Stub : public $classname$ {\n" + " public:\n"); + + printer->Indent(); + + printer->Print(vars_, + "$classname$_Stub(::google::protobuf::RpcChannel* channel);\n" + "$classname$_Stub(::google::protobuf::RpcChannel* channel,\n" + " ::google::protobuf::Service::ChannelOwnership ownership);\n" + "~$classname$_Stub();\n" + "\n" + "inline ::google::protobuf::RpcChannel* channel() { return channel_; }\n" + "\n" + "// implements $classname$ ------------------------------------------\n" + "\n"); + + GenerateMethodSignatures(NON_VIRTUAL, printer); + + printer->Outdent(); + printer->Print(vars_, + " private:\n" + " ::google::protobuf::RpcChannel* channel_;\n" + " bool owns_channel_;\n" + " GOOGLE_DISALLOW_EVIL_CONSTRUCTORS($classname$_Stub);\n" + "};\n" + "\n"); +} + +void ServiceGenerator::GenerateMethodSignatures( + VirtualOrNon virtual_or_non, io::Printer* printer) { + for (int i = 0; i < descriptor_->method_count(); i++) { + const MethodDescriptor* method = descriptor_->method(i); + map sub_vars; + sub_vars["name"] = method->name(); + sub_vars["input_type"] = ClassName(method->input_type(), true); + sub_vars["output_type"] = ClassName(method->output_type(), true); + sub_vars["virtual"] = virtual_or_non == VIRTUAL ? "virtual " : ""; + + printer->Print(sub_vars, + "$virtual$void $name$(::google::protobuf::RpcController* controller,\n" + " const $input_type$* request,\n" + " $output_type$* response,\n" + " ::google::protobuf::Closure* done);\n"); + } +} + +// =================================================================== + +void ServiceGenerator::GenerateDescriptorInitializer( + io::Printer* printer, int index) { + map vars; + vars["classname"] = descriptor_->name(); + vars["index"] = SimpleItoa(index); + + printer->Print(vars, + "$classname$_descriptor_ = file->service($index$);\n"); +} + +// =================================================================== + +void ServiceGenerator::GenerateImplementation(io::Printer* printer) { + printer->Print(vars_, + "$classname$::~$classname$() {}\n" + "\n" + "const ::google::protobuf::ServiceDescriptor* $classname$::descriptor() {\n" + " protobuf_AssignDescriptorsOnce();\n" + " return $classname$_descriptor_;\n" + "}\n" + "\n" + "const ::google::protobuf::ServiceDescriptor* $classname$::GetDescriptor() {\n" + " protobuf_AssignDescriptorsOnce();\n" + " return $classname$_descriptor_;\n" + "}\n" + "\n"); + + // Generate methods of the interface. + GenerateNotImplementedMethods(printer); + GenerateCallMethod(printer); + GenerateGetPrototype(REQUEST, printer); + GenerateGetPrototype(RESPONSE, printer); + + // Generate stub implementation. + printer->Print(vars_, + "$classname$_Stub::$classname$_Stub(::google::protobuf::RpcChannel* channel)\n" + " : channel_(channel), owns_channel_(false) {}\n" + "$classname$_Stub::$classname$_Stub(\n" + " ::google::protobuf::RpcChannel* channel,\n" + " ::google::protobuf::Service::ChannelOwnership ownership)\n" + " : channel_(channel),\n" + " owns_channel_(ownership == ::google::protobuf::Service::STUB_OWNS_CHANNEL) {}\n" + "$classname$_Stub::~$classname$_Stub() {\n" + " if (owns_channel_) delete channel_;\n" + "}\n" + "\n"); + + GenerateStubMethods(printer); +} + +void ServiceGenerator::GenerateNotImplementedMethods(io::Printer* printer) { + for (int i = 0; i < descriptor_->method_count(); i++) { + const MethodDescriptor* method = descriptor_->method(i); + map sub_vars; + sub_vars["classname"] = descriptor_->name(); + sub_vars["name"] = method->name(); + sub_vars["index"] = SimpleItoa(i); + sub_vars["input_type"] = ClassName(method->input_type(), true); + sub_vars["output_type"] = ClassName(method->output_type(), true); + + printer->Print(sub_vars, + "void $classname$::$name$(::google::protobuf::RpcController* controller,\n" + " const $input_type$*,\n" + " $output_type$*,\n" + " ::google::protobuf::Closure* done) {\n" + " controller->SetFailed(\"Method $name$() not implemented.\");\n" + " done->Run();\n" + "}\n" + "\n"); + } +} + +void ServiceGenerator::GenerateCallMethod(io::Printer* printer) { + printer->Print(vars_, + "void $classname$::CallMethod(const ::google::protobuf::MethodDescriptor* method,\n" + " ::google::protobuf::RpcController* controller,\n" + " const ::google::protobuf::Message* request,\n" + " ::google::protobuf::Message* response,\n" + " ::google::protobuf::Closure* done) {\n" + " GOOGLE_DCHECK_EQ(method->service(), $classname$_descriptor_);\n" + " switch(method->index()) {\n"); + + for (int i = 0; i < descriptor_->method_count(); i++) { + const MethodDescriptor* method = descriptor_->method(i); + map sub_vars; + sub_vars["name"] = method->name(); + sub_vars["index"] = SimpleItoa(i); + sub_vars["input_type"] = ClassName(method->input_type(), true); + sub_vars["output_type"] = ClassName(method->output_type(), true); + + // Note: down_cast does not work here because it only works on pointers, + // not references. + printer->Print(sub_vars, + " case $index$:\n" + " $name$(controller,\n" + " ::google::protobuf::down_cast(request),\n" + " ::google::protobuf::down_cast< $output_type$*>(response),\n" + " done);\n" + " break;\n"); + } + + printer->Print(vars_, + " default:\n" + " GOOGLE_LOG(FATAL) << \"Bad method index; this should never happen.\";\n" + " break;\n" + " }\n" + "}\n" + "\n"); +} + +void ServiceGenerator::GenerateGetPrototype(RequestOrResponse which, + io::Printer* printer) { + if (which == REQUEST) { + printer->Print(vars_, + "const ::google::protobuf::Message& $classname$::GetRequestPrototype(\n"); + } else { + printer->Print(vars_, + "const ::google::protobuf::Message& $classname$::GetResponsePrototype(\n"); + } + + printer->Print(vars_, + " const ::google::protobuf::MethodDescriptor* method) const {\n" + " GOOGLE_DCHECK_EQ(method->service(), descriptor());\n" + " switch(method->index()) {\n"); + + for (int i = 0; i < descriptor_->method_count(); i++) { + const MethodDescriptor* method = descriptor_->method(i); + const Descriptor* type = + (which == REQUEST) ? method->input_type() : method->output_type(); + + map sub_vars; + sub_vars["index"] = SimpleItoa(i); + sub_vars["type"] = ClassName(type, true); + + printer->Print(sub_vars, + " case $index$:\n" + " return $type$::default_instance();\n"); + } + + printer->Print(vars_, + " default:\n" + " GOOGLE_LOG(FATAL) << \"Bad method index; this should never happen.\";\n" + " return *reinterpret_cast< ::google::protobuf::Message*>(NULL);\n" + " }\n" + "}\n" + "\n"); +} + +void ServiceGenerator::GenerateStubMethods(io::Printer* printer) { + for (int i = 0; i < descriptor_->method_count(); i++) { + const MethodDescriptor* method = descriptor_->method(i); + map sub_vars; + sub_vars["classname"] = descriptor_->name(); + sub_vars["name"] = method->name(); + sub_vars["index"] = SimpleItoa(i); + sub_vars["input_type"] = ClassName(method->input_type(), true); + sub_vars["output_type"] = ClassName(method->output_type(), true); + + printer->Print(sub_vars, + "void $classname$_Stub::$name$(::google::protobuf::RpcController* controller,\n" + " const $input_type$* request,\n" + " $output_type$* response,\n" + " ::google::protobuf::Closure* done) {\n" + " channel_->CallMethod(descriptor()->method($index$),\n" + " controller, request, response, done);\n" + "}\n"); + } +} + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/depends/protobuf/google/protobuf/compiler/cpp/cpp_service.h b/depends/protobuf/google/protobuf/compiler/cpp/cpp_service.h new file mode 100644 index 0000000000..10e9dd3cd2 --- /dev/null +++ b/depends/protobuf/google/protobuf/compiler/cpp/cpp_service.h @@ -0,0 +1,118 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_SERVICE_H__ +#define GOOGLE_PROTOBUF_COMPILER_CPP_SERVICE_H__ + +#include +#include +#include +#include + +namespace google { +namespace protobuf { + namespace io { + class Printer; // printer.h + } +} + +namespace protobuf { +namespace compiler { +namespace cpp { + +class ServiceGenerator { + public: + // See generator.cc for the meaning of dllexport_decl. + explicit ServiceGenerator(const ServiceDescriptor* descriptor, + const string& dllexport_decl); + ~ServiceGenerator(); + + // Header stuff. + + // Generate the class definitions for the service's interface and the + // stub implementation. + void GenerateDeclarations(io::Printer* printer); + + // Source file stuff. + + // Generate code that initializes the global variable storing the service's + // descriptor. + void GenerateDescriptorInitializer(io::Printer* printer, int index); + + // Generate implementations of everything declared by GenerateDeclarations(). + void GenerateImplementation(io::Printer* printer); + + private: + enum RequestOrResponse { REQUEST, RESPONSE }; + enum VirtualOrNon { VIRTUAL, NON_VIRTUAL }; + + // Header stuff. + + // Generate the service abstract interface. + void GenerateInterface(io::Printer* printer); + + // Generate the stub class definition. + void GenerateStubDefinition(io::Printer* printer); + + // Prints signatures for all methods in the + void GenerateMethodSignatures(VirtualOrNon virtual_or_non, + io::Printer* printer); + + // Source file stuff. + + // Generate the default implementations of the service methods, which + // produce a "not implemented" error. + void GenerateNotImplementedMethods(io::Printer* printer); + + // Generate the CallMethod() method of the service. + void GenerateCallMethod(io::Printer* printer); + + // Generate the Get{Request,Response}Prototype() methods. + void GenerateGetPrototype(RequestOrResponse which, io::Printer* printer); + + // Generate the stub's implementations of the service methods. + void GenerateStubMethods(io::Printer* printer); + + const ServiceDescriptor* descriptor_; + map vars_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ServiceGenerator); +}; + +} // namespace cpp +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_CPP_SERVICE_H__ diff --git a/depends/protobuf/google/protobuf/compiler/cpp/cpp_string_field.cc b/depends/protobuf/google/protobuf/compiler/cpp/cpp_string_field.cc new file mode 100644 index 0000000000..8d611b690b --- /dev/null +++ b/depends/protobuf/google/protobuf/compiler/cpp/cpp_string_field.cc @@ -0,0 +1,453 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +namespace { + +void SetStringVariables(const FieldDescriptor* descriptor, + map* variables) { + SetCommonFieldVariables(descriptor, variables); + (*variables)["default"] = DefaultValue(descriptor); + (*variables)["default_variable"] = descriptor->default_value_string().empty() + ? "::google::protobuf::internal::kEmptyString" + : "_default_" + FieldName(descriptor) + "_"; + (*variables)["pointer_type"] = + descriptor->type() == FieldDescriptor::TYPE_BYTES ? "void" : "char"; +} + +} // namespace + +// =================================================================== + +StringFieldGenerator:: +StringFieldGenerator(const FieldDescriptor* descriptor) + : descriptor_(descriptor) { + SetStringVariables(descriptor, &variables_); +} + +StringFieldGenerator::~StringFieldGenerator() {} + +void StringFieldGenerator:: +GeneratePrivateMembers(io::Printer* printer) const { + printer->Print(variables_, "::std::string* $name$_;\n"); + if (!descriptor_->default_value_string().empty()) { + printer->Print(variables_, "static const ::std::string $default_variable$;\n"); + } +} + +void StringFieldGenerator:: +GenerateAccessorDeclarations(io::Printer* printer) const { + // If we're using StringFieldGenerator for a field with a ctype, it's + // because that ctype isn't actually implemented. In particular, this is + // true of ctype=CORD and ctype=STRING_PIECE in the open source release. + // We aren't releasing Cord because it has too many Google-specific + // dependencies and we aren't releasing StringPiece because it's hardly + // useful outside of Google and because it would get confusing to have + // multiple instances of the StringPiece class in different libraries (PCRE + // already includes it for their C++ bindings, which came from Google). + // + // In any case, we make all the accessors private while still actually + // using a string to represent the field internally. This way, we can + // guarantee that if we do ever implement the ctype, it won't break any + // existing users who might be -- for whatever reason -- already using .proto + // files that applied the ctype. The field can still be accessed via the + // reflection interface since the reflection interface is independent of + // the string's underlying representation. + if (descriptor_->options().ctype() != FieldOptions::STRING) { + printer->Outdent(); + printer->Print( + " private:\n" + " // Hidden due to unknown ctype option.\n"); + printer->Indent(); + } + + printer->Print(variables_, + "inline const ::std::string& $name$() const$deprecation$;\n" + "inline void set_$name$(const ::std::string& value)$deprecation$;\n" + "inline void set_$name$(const char* value)$deprecation$;\n" + "inline void set_$name$(const $pointer_type$* value, size_t size)" + "$deprecation$;\n" + "inline ::std::string* mutable_$name$()$deprecation$;\n" + "inline ::std::string* release_$name$()$deprecation$;\n"); + + if (descriptor_->options().ctype() != FieldOptions::STRING) { + printer->Outdent(); + printer->Print(" public:\n"); + printer->Indent(); + } +} + +void StringFieldGenerator:: +GenerateInlineAccessorDefinitions(io::Printer* printer) const { + printer->Print(variables_, + "inline const ::std::string& $classname$::$name$() const {\n" + " return *$name$_;\n" + "}\n" + "inline void $classname$::set_$name$(const ::std::string& value) {\n" + " set_has_$name$();\n" + " if ($name$_ == &$default_variable$) {\n" + " $name$_ = new ::std::string;\n" + " }\n" + " $name$_->assign(value);\n" + "}\n" + "inline void $classname$::set_$name$(const char* value) {\n" + " set_has_$name$();\n" + " if ($name$_ == &$default_variable$) {\n" + " $name$_ = new ::std::string;\n" + " }\n" + " $name$_->assign(value);\n" + "}\n" + "inline " + "void $classname$::set_$name$(const $pointer_type$* value, size_t size) {\n" + " set_has_$name$();\n" + " if ($name$_ == &$default_variable$) {\n" + " $name$_ = new ::std::string;\n" + " }\n" + " $name$_->assign(reinterpret_cast(value), size);\n" + "}\n" + "inline ::std::string* $classname$::mutable_$name$() {\n" + " set_has_$name$();\n" + " if ($name$_ == &$default_variable$) {\n"); + if (descriptor_->default_value_string().empty()) { + printer->Print(variables_, + " $name$_ = new ::std::string;\n"); + } else { + printer->Print(variables_, + " $name$_ = new ::std::string($default_variable$);\n"); + } + printer->Print(variables_, + " }\n" + " return $name$_;\n" + "}\n" + "inline ::std::string* $classname$::release_$name$() {\n" + " clear_has_$name$();\n" + " if ($name$_ == &$default_variable$) {\n" + " return NULL;\n" + " } else {\n" + " ::std::string* temp = $name$_;\n" + " $name$_ = const_cast< ::std::string*>(&$default_variable$);\n" + " return temp;\n" + " }\n" + "}\n"); +} + +void StringFieldGenerator:: +GenerateNonInlineAccessorDefinitions(io::Printer* printer) const { + if (!descriptor_->default_value_string().empty()) { + printer->Print(variables_, + "const ::std::string $classname$::$default_variable$($default$);\n"); + } +} + +void StringFieldGenerator:: +GenerateClearingCode(io::Printer* printer) const { + if (descriptor_->default_value_string().empty()) { + printer->Print(variables_, + "if ($name$_ != &$default_variable$) {\n" + " $name$_->clear();\n" + "}\n"); + } else { + printer->Print(variables_, + "if ($name$_ != &$default_variable$) {\n" + " $name$_->assign($default_variable$);\n" + "}\n"); + } +} + +void StringFieldGenerator:: +GenerateMergingCode(io::Printer* printer) const { + printer->Print(variables_, "set_$name$(from.$name$());\n"); +} + +void StringFieldGenerator:: +GenerateSwappingCode(io::Printer* printer) const { + printer->Print(variables_, "std::swap($name$_, other->$name$_);\n"); +} + +void StringFieldGenerator:: +GenerateConstructorCode(io::Printer* printer) const { + printer->Print(variables_, + "$name$_ = const_cast< ::std::string*>(&$default_variable$);\n"); +} + +void StringFieldGenerator:: +GenerateDestructorCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($name$_ != &$default_variable$) {\n" + " delete $name$_;\n" + "}\n"); +} + +void StringFieldGenerator:: +GenerateMergeFromCodedStream(io::Printer* printer) const { + printer->Print(variables_, + "DO_(::google::protobuf::internal::WireFormatLite::Read$declared_type$(\n" + " input, this->mutable_$name$()));\n"); + if (HasUtf8Verification(descriptor_->file()) && + descriptor_->type() == FieldDescriptor::TYPE_STRING) { + printer->Print(variables_, + "::google::protobuf::internal::WireFormat::VerifyUTF8String(\n" + " this->$name$().data(), this->$name$().length(),\n" + " ::google::protobuf::internal::WireFormat::PARSE);\n"); + } +} + +void StringFieldGenerator:: +GenerateSerializeWithCachedSizes(io::Printer* printer) const { + if (HasUtf8Verification(descriptor_->file()) && + descriptor_->type() == FieldDescriptor::TYPE_STRING) { + printer->Print(variables_, + "::google::protobuf::internal::WireFormat::VerifyUTF8String(\n" + " this->$name$().data(), this->$name$().length(),\n" + " ::google::protobuf::internal::WireFormat::SERIALIZE);\n"); + } + printer->Print(variables_, + "::google::protobuf::internal::WireFormatLite::Write$declared_type$(\n" + " $number$, this->$name$(), output);\n"); +} + +void StringFieldGenerator:: +GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { + if (HasUtf8Verification(descriptor_->file()) && + descriptor_->type() == FieldDescriptor::TYPE_STRING) { + printer->Print(variables_, + "::google::protobuf::internal::WireFormat::VerifyUTF8String(\n" + " this->$name$().data(), this->$name$().length(),\n" + " ::google::protobuf::internal::WireFormat::SERIALIZE);\n"); + } + printer->Print(variables_, + "target =\n" + " ::google::protobuf::internal::WireFormatLite::Write$declared_type$ToArray(\n" + " $number$, this->$name$(), target);\n"); +} + +void StringFieldGenerator:: +GenerateByteSize(io::Printer* printer) const { + printer->Print(variables_, + "total_size += $tag_size$ +\n" + " ::google::protobuf::internal::WireFormatLite::$declared_type$Size(\n" + " this->$name$());\n"); +} + +// =================================================================== + +RepeatedStringFieldGenerator:: +RepeatedStringFieldGenerator(const FieldDescriptor* descriptor) + : descriptor_(descriptor) { + SetStringVariables(descriptor, &variables_); +} + +RepeatedStringFieldGenerator::~RepeatedStringFieldGenerator() {} + +void RepeatedStringFieldGenerator:: +GeneratePrivateMembers(io::Printer* printer) const { + printer->Print(variables_, + "::google::protobuf::RepeatedPtrField< ::std::string> $name$_;\n"); +} + +void RepeatedStringFieldGenerator:: +GenerateAccessorDeclarations(io::Printer* printer) const { + // See comment above about unknown ctypes. + if (descriptor_->options().ctype() != FieldOptions::STRING) { + printer->Outdent(); + printer->Print( + " private:\n" + " // Hidden due to unknown ctype option.\n"); + printer->Indent(); + } + + printer->Print(variables_, + "inline const ::std::string& $name$(int index) const$deprecation$;\n" + "inline ::std::string* mutable_$name$(int index)$deprecation$;\n" + "inline void set_$name$(int index, const ::std::string& value)$deprecation$;\n" + "inline void set_$name$(int index, const char* value)$deprecation$;\n" + "inline " + "void set_$name$(int index, const $pointer_type$* value, size_t size)" + "$deprecation$;\n" + "inline ::std::string* add_$name$()$deprecation$;\n" + "inline void add_$name$(const ::std::string& value)$deprecation$;\n" + "inline void add_$name$(const char* value)$deprecation$;\n" + "inline void add_$name$(const $pointer_type$* value, size_t size)" + "$deprecation$;\n"); + + printer->Print(variables_, + "inline const ::google::protobuf::RepeatedPtrField< ::std::string>& $name$() const" + "$deprecation$;\n" + "inline ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_$name$()" + "$deprecation$;\n"); + + if (descriptor_->options().ctype() != FieldOptions::STRING) { + printer->Outdent(); + printer->Print(" public:\n"); + printer->Indent(); + } +} + +void RepeatedStringFieldGenerator:: +GenerateInlineAccessorDefinitions(io::Printer* printer) const { + printer->Print(variables_, + "inline const ::std::string& $classname$::$name$(int index) const {\n" + " return $name$_.Get(index);\n" + "}\n" + "inline ::std::string* $classname$::mutable_$name$(int index) {\n" + " return $name$_.Mutable(index);\n" + "}\n" + "inline void $classname$::set_$name$(int index, const ::std::string& value) {\n" + " $name$_.Mutable(index)->assign(value);\n" + "}\n" + "inline void $classname$::set_$name$(int index, const char* value) {\n" + " $name$_.Mutable(index)->assign(value);\n" + "}\n" + "inline void " + "$classname$::set_$name$" + "(int index, const $pointer_type$* value, size_t size) {\n" + " $name$_.Mutable(index)->assign(\n" + " reinterpret_cast(value), size);\n" + "}\n" + "inline ::std::string* $classname$::add_$name$() {\n" + " return $name$_.Add();\n" + "}\n" + "inline void $classname$::add_$name$(const ::std::string& value) {\n" + " $name$_.Add()->assign(value);\n" + "}\n" + "inline void $classname$::add_$name$(const char* value) {\n" + " $name$_.Add()->assign(value);\n" + "}\n" + "inline void " + "$classname$::add_$name$(const $pointer_type$* value, size_t size) {\n" + " $name$_.Add()->assign(reinterpret_cast(value), size);\n" + "}\n"); + printer->Print(variables_, + "inline const ::google::protobuf::RepeatedPtrField< ::std::string>&\n" + "$classname$::$name$() const {\n" + " return $name$_;\n" + "}\n" + "inline ::google::protobuf::RepeatedPtrField< ::std::string>*\n" + "$classname$::mutable_$name$() {\n" + " return &$name$_;\n" + "}\n"); +} + +void RepeatedStringFieldGenerator:: +GenerateClearingCode(io::Printer* printer) const { + printer->Print(variables_, "$name$_.Clear();\n"); +} + +void RepeatedStringFieldGenerator:: +GenerateMergingCode(io::Printer* printer) const { + printer->Print(variables_, "$name$_.MergeFrom(from.$name$_);\n"); +} + +void RepeatedStringFieldGenerator:: +GenerateSwappingCode(io::Printer* printer) const { + printer->Print(variables_, "$name$_.Swap(&other->$name$_);\n"); +} + +void RepeatedStringFieldGenerator:: +GenerateConstructorCode(io::Printer* printer) const { + // Not needed for repeated fields. +} + +void RepeatedStringFieldGenerator:: +GenerateMergeFromCodedStream(io::Printer* printer) const { + printer->Print(variables_, + "DO_(::google::protobuf::internal::WireFormatLite::Read$declared_type$(\n" + " input, this->add_$name$()));\n"); + if (HasUtf8Verification(descriptor_->file()) && + descriptor_->type() == FieldDescriptor::TYPE_STRING) { + printer->Print(variables_, + "::google::protobuf::internal::WireFormat::VerifyUTF8String(\n" + " this->$name$(0).data(), this->$name$(0).length(),\n" + " ::google::protobuf::internal::WireFormat::PARSE);\n"); + } +} + +void RepeatedStringFieldGenerator:: +GenerateSerializeWithCachedSizes(io::Printer* printer) const { + printer->Print(variables_, + "for (int i = 0; i < this->$name$_size(); i++) {\n"); + if (HasUtf8Verification(descriptor_->file()) && + descriptor_->type() == FieldDescriptor::TYPE_STRING) { + printer->Print(variables_, + "::google::protobuf::internal::WireFormat::VerifyUTF8String(\n" + " this->$name$(i).data(), this->$name$(i).length(),\n" + " ::google::protobuf::internal::WireFormat::SERIALIZE);\n"); + } + printer->Print(variables_, + " ::google::protobuf::internal::WireFormatLite::Write$declared_type$(\n" + " $number$, this->$name$(i), output);\n" + "}\n"); +} + +void RepeatedStringFieldGenerator:: +GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { + printer->Print(variables_, + "for (int i = 0; i < this->$name$_size(); i++) {\n"); + if (HasUtf8Verification(descriptor_->file()) && + descriptor_->type() == FieldDescriptor::TYPE_STRING) { + printer->Print(variables_, + " ::google::protobuf::internal::WireFormat::VerifyUTF8String(\n" + " this->$name$(i).data(), this->$name$(i).length(),\n" + " ::google::protobuf::internal::WireFormat::SERIALIZE);\n"); + } + printer->Print(variables_, + " target = ::google::protobuf::internal::WireFormatLite::\n" + " Write$declared_type$ToArray($number$, this->$name$(i), target);\n" + "}\n"); +} + +void RepeatedStringFieldGenerator:: +GenerateByteSize(io::Printer* printer) const { + printer->Print(variables_, + "total_size += $tag_size$ * this->$name$_size();\n" + "for (int i = 0; i < this->$name$_size(); i++) {\n" + " total_size += ::google::protobuf::internal::WireFormatLite::$declared_type$Size(\n" + " this->$name$(i));\n" + "}\n"); +} + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/depends/protobuf/google/protobuf/compiler/cpp/cpp_string_field.h b/depends/protobuf/google/protobuf/compiler/cpp/cpp_string_field.h new file mode 100644 index 0000000000..7f45107de6 --- /dev/null +++ b/depends/protobuf/google/protobuf/compiler/cpp/cpp_string_field.h @@ -0,0 +1,104 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_STRING_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_CPP_STRING_FIELD_H__ + +#include +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +class StringFieldGenerator : public FieldGenerator { + public: + explicit StringFieldGenerator(const FieldDescriptor* descriptor); + ~StringFieldGenerator(); + + // implements FieldGenerator --------------------------------------- + void GeneratePrivateMembers(io::Printer* printer) const; + void GenerateAccessorDeclarations(io::Printer* printer) const; + void GenerateInlineAccessorDefinitions(io::Printer* printer) const; + void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const; + void GenerateClearingCode(io::Printer* printer) const; + void GenerateMergingCode(io::Printer* printer) const; + void GenerateSwappingCode(io::Printer* printer) const; + void GenerateConstructorCode(io::Printer* printer) const; + void GenerateDestructorCode(io::Printer* printer) const; + void GenerateMergeFromCodedStream(io::Printer* printer) const; + void GenerateSerializeWithCachedSizes(io::Printer* printer) const; + void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const; + void GenerateByteSize(io::Printer* printer) const; + + private: + const FieldDescriptor* descriptor_; + map variables_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringFieldGenerator); +}; + +class RepeatedStringFieldGenerator : public FieldGenerator { + public: + explicit RepeatedStringFieldGenerator(const FieldDescriptor* descriptor); + ~RepeatedStringFieldGenerator(); + + // implements FieldGenerator --------------------------------------- + void GeneratePrivateMembers(io::Printer* printer) const; + void GenerateAccessorDeclarations(io::Printer* printer) const; + void GenerateInlineAccessorDefinitions(io::Printer* printer) const; + void GenerateClearingCode(io::Printer* printer) const; + void GenerateMergingCode(io::Printer* printer) const; + void GenerateSwappingCode(io::Printer* printer) const; + void GenerateConstructorCode(io::Printer* printer) const; + void GenerateMergeFromCodedStream(io::Printer* printer) const; + void GenerateSerializeWithCachedSizes(io::Printer* printer) const; + void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const; + void GenerateByteSize(io::Printer* printer) const; + + private: + const FieldDescriptor* descriptor_; + map variables_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedStringFieldGenerator); +}; + +} // namespace cpp +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_CPP_STRING_FIELD_H__ diff --git a/depends/protobuf/google/protobuf/compiler/cpp/cpp_unittest.cc b/depends/protobuf/google/protobuf/compiler/cpp/cpp_unittest.cc new file mode 100644 index 0000000000..301a7ce677 --- /dev/null +++ b/depends/protobuf/google/protobuf/compiler/cpp/cpp_unittest.cc @@ -0,0 +1,1281 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// To test the code generator, we actually use it to generate code for +// google/protobuf/unittest.proto, then test that. This means that we +// are actually testing the parser and other parts of the system at the same +// time, and that problems in the generator may show up as compile-time errors +// rather than unittest failures, which may be surprising. However, testing +// the output of the C++ generator directly would be very hard. We can't very +// well just check it against golden files since those files would have to be +// updated for any small change; such a test would be very brittle and probably +// not very helpful. What we really want to test is that the code compiles +// correctly and produces the interfaces we expect, which is why this test +// is written this way. + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +// Can't use an anonymous namespace here due to brokenness of Tru64 compiler. +namespace cpp_unittest { + + +class MockErrorCollector : public MultiFileErrorCollector { + public: + MockErrorCollector() {} + ~MockErrorCollector() {} + + string text_; + + // implements ErrorCollector --------------------------------------- + void AddError(const string& filename, int line, int column, + const string& message) { + strings::SubstituteAndAppend(&text_, "$0:$1:$2: $3\n", + filename, line, column, message); + } +}; + +#ifndef PROTOBUF_TEST_NO_DESCRIPTORS + +// Test that generated code has proper descriptors: +// Parse a descriptor directly (using google::protobuf::compiler::Importer) and +// compare it to the one that was produced by generated code. +TEST(GeneratedDescriptorTest, IdenticalDescriptors) { + const FileDescriptor* generated_descriptor = + unittest::TestAllTypes::descriptor()->file(); + + // Set up the Importer. + MockErrorCollector error_collector; + DiskSourceTree source_tree; + source_tree.MapPath("", TestSourceDir()); + Importer importer(&source_tree, &error_collector); + + // Import (parse) unittest.proto. + const FileDescriptor* parsed_descriptor = + importer.Import("google/protobuf/unittest.proto"); + EXPECT_EQ("", error_collector.text_); + ASSERT_TRUE(parsed_descriptor != NULL); + + // Test that descriptors are generated correctly by converting them to + // FileDescriptorProtos and comparing. + FileDescriptorProto generated_decsriptor_proto, parsed_descriptor_proto; + generated_descriptor->CopyTo(&generated_decsriptor_proto); + parsed_descriptor->CopyTo(&parsed_descriptor_proto); + + EXPECT_EQ(parsed_descriptor_proto.DebugString(), + generated_decsriptor_proto.DebugString()); +} + +#endif // !PROTOBUF_TEST_NO_DESCRIPTORS + +// =================================================================== + +TEST(GeneratedMessageTest, Defaults) { + // Check that all default values are set correctly in the initial message. + unittest::TestAllTypes message; + + TestUtil::ExpectClear(message); + + // Messages should return pointers to default instances until first use. + // (This is not checked by ExpectClear() since it is not actually true after + // the fields have been set and then cleared.) + EXPECT_EQ(&unittest::TestAllTypes::OptionalGroup::default_instance(), + &message.optionalgroup()); + EXPECT_EQ(&unittest::TestAllTypes::NestedMessage::default_instance(), + &message.optional_nested_message()); + EXPECT_EQ(&unittest::ForeignMessage::default_instance(), + &message.optional_foreign_message()); + EXPECT_EQ(&unittest_import::ImportMessage::default_instance(), + &message.optional_import_message()); +} + +TEST(GeneratedMessageTest, FloatingPointDefaults) { + const unittest::TestExtremeDefaultValues& extreme_default = + unittest::TestExtremeDefaultValues::default_instance(); + + EXPECT_EQ(0.0f, extreme_default.zero_float()); + EXPECT_EQ(1.0f, extreme_default.one_float()); + EXPECT_EQ(1.5f, extreme_default.small_float()); + EXPECT_EQ(-1.0f, extreme_default.negative_one_float()); + EXPECT_EQ(-1.5f, extreme_default.negative_float()); + EXPECT_EQ(2.0e8f, extreme_default.large_float()); + EXPECT_EQ(-8e-28f, extreme_default.small_negative_float()); + EXPECT_EQ(numeric_limits::infinity(), + extreme_default.inf_double()); + EXPECT_EQ(-numeric_limits::infinity(), + extreme_default.neg_inf_double()); + EXPECT_TRUE(extreme_default.nan_double() != extreme_default.nan_double()); + EXPECT_EQ(numeric_limits::infinity(), + extreme_default.inf_float()); + EXPECT_EQ(-numeric_limits::infinity(), + extreme_default.neg_inf_float()); + EXPECT_TRUE(extreme_default.nan_float() != extreme_default.nan_float()); +} + +TEST(GeneratedMessageTest, Trigraph) { + const unittest::TestExtremeDefaultValues& extreme_default = + unittest::TestExtremeDefaultValues::default_instance(); + + EXPECT_EQ("? ? ?? ?? ??? ?\?/ ?\?-", extreme_default.cpp_trigraph()); +} + +TEST(GeneratedMessageTest, Accessors) { + // Set every field to a unique value then go back and check all those + // values. + unittest::TestAllTypes message; + + TestUtil::SetAllFields(&message); + TestUtil::ExpectAllFieldsSet(message); + + TestUtil::ModifyRepeatedFields(&message); + TestUtil::ExpectRepeatedFieldsModified(message); +} + +TEST(GeneratedMessageTest, MutableStringDefault) { + // mutable_foo() for a string should return a string initialized to its + // default value. + unittest::TestAllTypes message; + + EXPECT_EQ("hello", *message.mutable_default_string()); + + // Note that the first time we call mutable_foo(), we get a newly-allocated + // string, but if we clear it and call it again, we get the same object again. + // We should verify that it has its default value in both cases. + message.set_default_string("blah"); + message.Clear(); + + EXPECT_EQ("hello", *message.mutable_default_string()); +} + +TEST(GeneratedMessageTest, ReleaseString) { + // Check that release_foo() starts out NULL, and gives us a value + // that we can delete after it's been set. + unittest::TestAllTypes message; + + EXPECT_EQ(NULL, message.release_default_string()); + EXPECT_FALSE(message.has_default_string()); + EXPECT_EQ("hello", message.default_string()); + + message.set_default_string("blah"); + EXPECT_TRUE(message.has_default_string()); + string* str = message.release_default_string(); + EXPECT_FALSE(message.has_default_string()); + ASSERT_TRUE(str != NULL); + EXPECT_EQ("blah", *str); + delete str; + + EXPECT_EQ(NULL, message.release_default_string()); + EXPECT_FALSE(message.has_default_string()); + EXPECT_EQ("hello", message.default_string()); +} + +TEST(GeneratedMessageTest, ReleaseMessage) { + // Check that release_foo() starts out NULL, and gives us a value + // that we can delete after it's been set. + unittest::TestAllTypes message; + + EXPECT_EQ(NULL, message.release_optional_nested_message()); + EXPECT_FALSE(message.has_optional_nested_message()); + + message.mutable_optional_nested_message()->set_bb(1); + unittest::TestAllTypes::NestedMessage* nest = + message.release_optional_nested_message(); + EXPECT_FALSE(message.has_optional_nested_message()); + ASSERT_TRUE(nest != NULL); + EXPECT_EQ(1, nest->bb()); + delete nest; + + EXPECT_EQ(NULL, message.release_optional_nested_message()); + EXPECT_FALSE(message.has_optional_nested_message()); +} + +TEST(GeneratedMessageTest, Clear) { + // Set every field to a unique value, clear the message, then check that + // it is cleared. + unittest::TestAllTypes message; + + TestUtil::SetAllFields(&message); + message.Clear(); + TestUtil::ExpectClear(message); + + // Unlike with the defaults test, we do NOT expect that requesting embedded + // messages will return a pointer to the default instance. Instead, they + // should return the objects that were created when mutable_blah() was + // called. + EXPECT_NE(&unittest::TestAllTypes::OptionalGroup::default_instance(), + &message.optionalgroup()); + EXPECT_NE(&unittest::TestAllTypes::NestedMessage::default_instance(), + &message.optional_nested_message()); + EXPECT_NE(&unittest::ForeignMessage::default_instance(), + &message.optional_foreign_message()); + EXPECT_NE(&unittest_import::ImportMessage::default_instance(), + &message.optional_import_message()); +} + +TEST(GeneratedMessageTest, EmbeddedNullsInBytesCharStar) { + unittest::TestAllTypes message; + + const char* value = "\0lalala\0\0"; + message.set_optional_bytes(value, 9); + ASSERT_EQ(9, message.optional_bytes().size()); + EXPECT_EQ(0, memcmp(value, message.optional_bytes().data(), 9)); + + message.add_repeated_bytes(value, 9); + ASSERT_EQ(9, message.repeated_bytes(0).size()); + EXPECT_EQ(0, memcmp(value, message.repeated_bytes(0).data(), 9)); +} + +TEST(GeneratedMessageTest, ClearOneField) { + // Set every field to a unique value, then clear one value and insure that + // only that one value is cleared. + unittest::TestAllTypes message; + + TestUtil::SetAllFields(&message); + int64 original_value = message.optional_int64(); + + // Clear the field and make sure it shows up as cleared. + message.clear_optional_int64(); + EXPECT_FALSE(message.has_optional_int64()); + EXPECT_EQ(0, message.optional_int64()); + + // Other adjacent fields should not be cleared. + EXPECT_TRUE(message.has_optional_int32()); + EXPECT_TRUE(message.has_optional_uint32()); + + // Make sure if we set it again, then all fields are set. + message.set_optional_int64(original_value); + TestUtil::ExpectAllFieldsSet(message); +} + +TEST(GeneratedMessageTest, StringCharStarLength) { + // Verify that we can use a char*,length to set one of the string fields. + unittest::TestAllTypes message; + message.set_optional_string("abcdef", 3); + EXPECT_EQ("abc", message.optional_string()); + + // Verify that we can use a char*,length to add to a repeated string field. + message.add_repeated_string("abcdef", 3); + EXPECT_EQ(1, message.repeated_string_size()); + EXPECT_EQ("abc", message.repeated_string(0)); + + // Verify that we can use a char*,length to set a repeated string field. + message.set_repeated_string(0, "wxyz", 2); + EXPECT_EQ("wx", message.repeated_string(0)); +} + + +TEST(GeneratedMessageTest, CopyFrom) { + unittest::TestAllTypes message1, message2; + + TestUtil::SetAllFields(&message1); + message2.CopyFrom(message1); + TestUtil::ExpectAllFieldsSet(message2); + + // Copying from self should be a no-op. + message2.CopyFrom(message2); + TestUtil::ExpectAllFieldsSet(message2); +} + + +TEST(GeneratedMessageTest, SwapWithEmpty) { + unittest::TestAllTypes message1, message2; + TestUtil::SetAllFields(&message1); + + TestUtil::ExpectAllFieldsSet(message1); + TestUtil::ExpectClear(message2); + message1.Swap(&message2); + TestUtil::ExpectAllFieldsSet(message2); + TestUtil::ExpectClear(message1); +} + +TEST(GeneratedMessageTest, SwapWithSelf) { + unittest::TestAllTypes message; + TestUtil::SetAllFields(&message); + TestUtil::ExpectAllFieldsSet(message); + message.Swap(&message); + TestUtil::ExpectAllFieldsSet(message); +} + +TEST(GeneratedMessageTest, SwapWithOther) { + unittest::TestAllTypes message1, message2; + + message1.set_optional_int32(123); + message1.set_optional_string("abc"); + message1.mutable_optional_nested_message()->set_bb(1); + message1.set_optional_nested_enum(unittest::TestAllTypes::FOO); + message1.add_repeated_int32(1); + message1.add_repeated_int32(2); + message1.add_repeated_string("a"); + message1.add_repeated_string("b"); + message1.add_repeated_nested_message()->set_bb(7); + message1.add_repeated_nested_message()->set_bb(8); + message1.add_repeated_nested_enum(unittest::TestAllTypes::FOO); + message1.add_repeated_nested_enum(unittest::TestAllTypes::BAR); + + message2.set_optional_int32(456); + message2.set_optional_string("def"); + message2.mutable_optional_nested_message()->set_bb(2); + message2.set_optional_nested_enum(unittest::TestAllTypes::BAR); + message2.add_repeated_int32(3); + message2.add_repeated_string("c"); + message2.add_repeated_nested_message()->set_bb(9); + message2.add_repeated_nested_enum(unittest::TestAllTypes::BAZ); + + message1.Swap(&message2); + + EXPECT_EQ(456, message1.optional_int32()); + EXPECT_EQ("def", message1.optional_string()); + EXPECT_EQ(2, message1.optional_nested_message().bb()); + EXPECT_EQ(unittest::TestAllTypes::BAR, message1.optional_nested_enum()); + ASSERT_EQ(1, message1.repeated_int32_size()); + EXPECT_EQ(3, message1.repeated_int32(0)); + ASSERT_EQ(1, message1.repeated_string_size()); + EXPECT_EQ("c", message1.repeated_string(0)); + ASSERT_EQ(1, message1.repeated_nested_message_size()); + EXPECT_EQ(9, message1.repeated_nested_message(0).bb()); + ASSERT_EQ(1, message1.repeated_nested_enum_size()); + EXPECT_EQ(unittest::TestAllTypes::BAZ, message1.repeated_nested_enum(0)); + + EXPECT_EQ(123, message2.optional_int32()); + EXPECT_EQ("abc", message2.optional_string()); + EXPECT_EQ(1, message2.optional_nested_message().bb()); + EXPECT_EQ(unittest::TestAllTypes::FOO, message2.optional_nested_enum()); + ASSERT_EQ(2, message2.repeated_int32_size()); + EXPECT_EQ(1, message2.repeated_int32(0)); + EXPECT_EQ(2, message2.repeated_int32(1)); + ASSERT_EQ(2, message2.repeated_string_size()); + EXPECT_EQ("a", message2.repeated_string(0)); + EXPECT_EQ("b", message2.repeated_string(1)); + ASSERT_EQ(2, message2.repeated_nested_message_size()); + EXPECT_EQ(7, message2.repeated_nested_message(0).bb()); + EXPECT_EQ(8, message2.repeated_nested_message(1).bb()); + ASSERT_EQ(2, message2.repeated_nested_enum_size()); + EXPECT_EQ(unittest::TestAllTypes::FOO, message2.repeated_nested_enum(0)); + EXPECT_EQ(unittest::TestAllTypes::BAR, message2.repeated_nested_enum(1)); +} + +TEST(GeneratedMessageTest, CopyConstructor) { + unittest::TestAllTypes message1; + TestUtil::SetAllFields(&message1); + + unittest::TestAllTypes message2(message1); + TestUtil::ExpectAllFieldsSet(message2); +} + +TEST(GeneratedMessageTest, CopyAssignmentOperator) { + unittest::TestAllTypes message1; + TestUtil::SetAllFields(&message1); + + unittest::TestAllTypes message2; + message2 = message1; + TestUtil::ExpectAllFieldsSet(message2); + + // Make sure that self-assignment does something sane. + message2.operator=(message2); + TestUtil::ExpectAllFieldsSet(message2); +} + +TEST(GeneratedMessageTest, UpcastCopyFrom) { + // Test the CopyFrom method that takes in the generic const Message& + // parameter. + unittest::TestAllTypes message1, message2; + + TestUtil::SetAllFields(&message1); + + const Message* source = implicit_cast(&message1); + message2.CopyFrom(*source); + + TestUtil::ExpectAllFieldsSet(message2); +} + +#ifndef PROTOBUF_TEST_NO_DESCRIPTORS + +TEST(GeneratedMessageTest, DynamicMessageCopyFrom) { + // Test copying from a DynamicMessage, which must fall back to using + // reflection. + unittest::TestAllTypes message2; + + // Construct a new version of the dynamic message via the factory. + DynamicMessageFactory factory; + scoped_ptr message1; + message1.reset(factory.GetPrototype( + unittest::TestAllTypes::descriptor())->New()); + + TestUtil::ReflectionTester reflection_tester( + unittest::TestAllTypes::descriptor()); + reflection_tester.SetAllFieldsViaReflection(message1.get()); + + message2.CopyFrom(*message1); + + TestUtil::ExpectAllFieldsSet(message2); +} + +#endif // !PROTOBUF_TEST_NO_DESCRIPTORS + +TEST(GeneratedMessageTest, NonEmptyMergeFrom) { + // Test merging with a non-empty message. Code is a modified form + // of that found in google/protobuf/reflection_ops_unittest.cc. + unittest::TestAllTypes message1, message2; + + TestUtil::SetAllFields(&message1); + + // This field will test merging into an empty spot. + message2.set_optional_int32(message1.optional_int32()); + message1.clear_optional_int32(); + + // This tests overwriting. + message2.set_optional_string(message1.optional_string()); + message1.set_optional_string("something else"); + + // This tests concatenating. + message2.add_repeated_int32(message1.repeated_int32(1)); + int32 i = message1.repeated_int32(0); + message1.clear_repeated_int32(); + message1.add_repeated_int32(i); + + message1.MergeFrom(message2); + + TestUtil::ExpectAllFieldsSet(message1); +} + +#ifdef GTEST_HAS_DEATH_TEST + +TEST(GeneratedMessageTest, MergeFromSelf) { + unittest::TestAllTypes message; + EXPECT_DEATH(message.MergeFrom(message), "&from"); + EXPECT_DEATH(message.MergeFrom(implicit_cast(message)), + "&from"); +} + +#endif // GTEST_HAS_DEATH_TEST + +// Test the generated SerializeWithCachedSizesToArray(), +TEST(GeneratedMessageTest, SerializationToArray) { + unittest::TestAllTypes message1, message2; + string data; + TestUtil::SetAllFields(&message1); + int size = message1.ByteSize(); + data.resize(size); + uint8* start = reinterpret_cast(string_as_array(&data)); + uint8* end = message1.SerializeWithCachedSizesToArray(start); + EXPECT_EQ(size, end - start); + EXPECT_TRUE(message2.ParseFromString(data)); + TestUtil::ExpectAllFieldsSet(message2); + +} + +TEST(GeneratedMessageTest, PackedFieldsSerializationToArray) { + unittest::TestPackedTypes packed_message1, packed_message2; + string packed_data; + TestUtil::SetPackedFields(&packed_message1); + int packed_size = packed_message1.ByteSize(); + packed_data.resize(packed_size); + uint8* start = reinterpret_cast(string_as_array(&packed_data)); + uint8* end = packed_message1.SerializeWithCachedSizesToArray(start); + EXPECT_EQ(packed_size, end - start); + EXPECT_TRUE(packed_message2.ParseFromString(packed_data)); + TestUtil::ExpectPackedFieldsSet(packed_message2); +} + +// Test the generated SerializeWithCachedSizes() by forcing the buffer to write +// one byte at a time. +TEST(GeneratedMessageTest, SerializationToStream) { + unittest::TestAllTypes message1, message2; + TestUtil::SetAllFields(&message1); + int size = message1.ByteSize(); + string data; + data.resize(size); + { + // Allow the output stream to buffer only one byte at a time. + io::ArrayOutputStream array_stream(string_as_array(&data), size, 1); + io::CodedOutputStream output_stream(&array_stream); + message1.SerializeWithCachedSizes(&output_stream); + EXPECT_FALSE(output_stream.HadError()); + EXPECT_EQ(size, output_stream.ByteCount()); + } + EXPECT_TRUE(message2.ParseFromString(data)); + TestUtil::ExpectAllFieldsSet(message2); + +} + +TEST(GeneratedMessageTest, PackedFieldsSerializationToStream) { + unittest::TestPackedTypes message1, message2; + TestUtil::SetPackedFields(&message1); + int size = message1.ByteSize(); + string data; + data.resize(size); + { + // Allow the output stream to buffer only one byte at a time. + io::ArrayOutputStream array_stream(string_as_array(&data), size, 1); + io::CodedOutputStream output_stream(&array_stream); + message1.SerializeWithCachedSizes(&output_stream); + EXPECT_FALSE(output_stream.HadError()); + EXPECT_EQ(size, output_stream.ByteCount()); + } + EXPECT_TRUE(message2.ParseFromString(data)); + TestUtil::ExpectPackedFieldsSet(message2); +} + + +TEST(GeneratedMessageTest, Required) { + // Test that IsInitialized() returns false if required fields are missing. + unittest::TestRequired message; + + EXPECT_FALSE(message.IsInitialized()); + message.set_a(1); + EXPECT_FALSE(message.IsInitialized()); + message.set_b(2); + EXPECT_FALSE(message.IsInitialized()); + message.set_c(3); + EXPECT_TRUE(message.IsInitialized()); +} + +TEST(GeneratedMessageTest, RequiredForeign) { + // Test that IsInitialized() returns false if required fields in nested + // messages are missing. + unittest::TestRequiredForeign message; + + EXPECT_TRUE(message.IsInitialized()); + + message.mutable_optional_message(); + EXPECT_FALSE(message.IsInitialized()); + + message.mutable_optional_message()->set_a(1); + message.mutable_optional_message()->set_b(2); + message.mutable_optional_message()->set_c(3); + EXPECT_TRUE(message.IsInitialized()); + + message.add_repeated_message(); + EXPECT_FALSE(message.IsInitialized()); + + message.mutable_repeated_message(0)->set_a(1); + message.mutable_repeated_message(0)->set_b(2); + message.mutable_repeated_message(0)->set_c(3); + EXPECT_TRUE(message.IsInitialized()); +} + +TEST(GeneratedMessageTest, ForeignNested) { + // Test that TestAllTypes::NestedMessage can be embedded directly into + // another message. + unittest::TestForeignNested message; + + // If this compiles and runs without crashing, it must work. We have + // nothing more to test. + unittest::TestAllTypes::NestedMessage* nested = + message.mutable_foreign_nested(); + nested->set_bb(1); +} + +TEST(GeneratedMessageTest, ReallyLargeTagNumber) { + // Test that really large tag numbers don't break anything. + unittest::TestReallyLargeTagNumber message1, message2; + string data; + + // For the most part, if this compiles and runs then we're probably good. + // (The most likely cause for failure would be if something were attempting + // to allocate a lookup table of some sort using tag numbers as the index.) + // We'll try serializing just for fun. + message1.set_a(1234); + message1.set_bb(5678); + message1.SerializeToString(&data); + EXPECT_TRUE(message2.ParseFromString(data)); + EXPECT_EQ(1234, message2.a()); + EXPECT_EQ(5678, message2.bb()); +} + +TEST(GeneratedMessageTest, MutualRecursion) { + // Test that mutually-recursive message types work. + unittest::TestMutualRecursionA message; + unittest::TestMutualRecursionA* nested = message.mutable_bb()->mutable_a(); + unittest::TestMutualRecursionA* nested2 = nested->mutable_bb()->mutable_a(); + + // Again, if the above compiles and runs, that's all we really have to + // test, but just for run we'll check that the system didn't somehow come + // up with a pointer loop... + EXPECT_NE(&message, nested); + EXPECT_NE(&message, nested2); + EXPECT_NE(nested, nested2); +} + +TEST(GeneratedMessageTest, CamelCaseFieldNames) { + // This test is mainly checking that the following compiles, which verifies + // that the field names were coerced to lower-case. + // + // Protocol buffers standard style is to use lowercase-with-underscores for + // field names. Some old proto1 .protos unfortunately used camel-case field + // names. In proto1, these names were forced to lower-case. So, we do the + // same thing in proto2. + + unittest::TestCamelCaseFieldNames message; + + message.set_primitivefield(2); + message.set_stringfield("foo"); + message.set_enumfield(unittest::FOREIGN_FOO); + message.mutable_messagefield()->set_c(6); + + message.add_repeatedprimitivefield(8); + message.add_repeatedstringfield("qux"); + message.add_repeatedenumfield(unittest::FOREIGN_BAR); + message.add_repeatedmessagefield()->set_c(15); + + EXPECT_EQ(2, message.primitivefield()); + EXPECT_EQ("foo", message.stringfield()); + EXPECT_EQ(unittest::FOREIGN_FOO, message.enumfield()); + EXPECT_EQ(6, message.messagefield().c()); + + EXPECT_EQ(8, message.repeatedprimitivefield(0)); + EXPECT_EQ("qux", message.repeatedstringfield(0)); + EXPECT_EQ(unittest::FOREIGN_BAR, message.repeatedenumfield(0)); + EXPECT_EQ(15, message.repeatedmessagefield(0).c()); +} + +TEST(GeneratedMessageTest, TestConflictingSymbolNames) { + // test_bad_identifiers.proto successfully compiled, then it works. The + // following is just a token usage to insure that the code is, in fact, + // being compiled and linked. + + protobuf_unittest::TestConflictingSymbolNames message; + message.set_uint32(1); + EXPECT_EQ(3, message.ByteSize()); + + message.set_friend_(5); + EXPECT_EQ(5, message.friend_()); +} + +#ifndef PROTOBUF_TEST_NO_DESCRIPTORS + +TEST(GeneratedMessageTest, TestOptimizedForSize) { + // We rely on the tests in reflection_ops_unittest and wire_format_unittest + // to really test that reflection-based methods work. Here we are mostly + // just making sure that TestOptimizedForSize actually builds and seems to + // function. + + protobuf_unittest::TestOptimizedForSize message, message2; + message.set_i(1); + message.mutable_msg()->set_c(2); + message2.CopyFrom(message); + EXPECT_EQ(1, message2.i()); + EXPECT_EQ(2, message2.msg().c()); +} + +TEST(GeneratedMessageTest, TestEmbedOptimizedForSize) { + // Verifies that something optimized for speed can contain something optimized + // for size. + + protobuf_unittest::TestEmbedOptimizedForSize message, message2; + message.mutable_optional_message()->set_i(1); + message.add_repeated_message()->mutable_msg()->set_c(2); + string data; + message.SerializeToString(&data); + ASSERT_TRUE(message2.ParseFromString(data)); + EXPECT_EQ(1, message2.optional_message().i()); + EXPECT_EQ(2, message2.repeated_message(0).msg().c()); +} + +TEST(GeneratedMessageTest, TestSpaceUsed) { + unittest::TestAllTypes message1; + // sizeof provides a lower bound on SpaceUsed(). + EXPECT_LE(sizeof(unittest::TestAllTypes), message1.SpaceUsed()); + const int empty_message_size = message1.SpaceUsed(); + + // Setting primitive types shouldn't affect the space used. + message1.set_optional_int32(123); + message1.set_optional_int64(12345); + message1.set_optional_uint32(123); + message1.set_optional_uint64(12345); + EXPECT_EQ(empty_message_size, message1.SpaceUsed()); + + // On some STL implementations, setting the string to a small value should + // only increase SpaceUsed() by the size of a string object, though this is + // not true everywhere. + message1.set_optional_string("abc"); + EXPECT_LE(empty_message_size + sizeof(string), message1.SpaceUsed()); + + // Setting a string to a value larger than the string object itself should + // increase SpaceUsed(), because it cannot store the value internally. + message1.set_optional_string(string(sizeof(string) + 1, 'x')); + int min_expected_increase = message1.optional_string().capacity() + + sizeof(string); + EXPECT_LE(empty_message_size + min_expected_increase, + message1.SpaceUsed()); + + int previous_size = message1.SpaceUsed(); + // Adding an optional message should increase the size by the size of the + // nested message type. NestedMessage is simple enough (1 int field) that it + // is equal to sizeof(NestedMessage) + message1.mutable_optional_nested_message(); + ASSERT_EQ(sizeof(unittest::TestAllTypes::NestedMessage), + message1.optional_nested_message().SpaceUsed()); + EXPECT_EQ(previous_size + + sizeof(unittest::TestAllTypes::NestedMessage), + message1.SpaceUsed()); +} + +#endif // !PROTOBUF_TEST_NO_DESCRIPTORS + + +TEST(GeneratedMessageTest, FieldConstantValues) { + unittest::TestRequired message; + EXPECT_EQ(unittest::TestAllTypes_NestedMessage::kBbFieldNumber, 1); + EXPECT_EQ(unittest::TestAllTypes::kOptionalInt32FieldNumber, 1); + EXPECT_EQ(unittest::TestAllTypes::kOptionalgroupFieldNumber, 16); + EXPECT_EQ(unittest::TestAllTypes::kOptionalNestedMessageFieldNumber, 18); + EXPECT_EQ(unittest::TestAllTypes::kOptionalNestedEnumFieldNumber, 21); + EXPECT_EQ(unittest::TestAllTypes::kRepeatedInt32FieldNumber, 31); + EXPECT_EQ(unittest::TestAllTypes::kRepeatedgroupFieldNumber, 46); + EXPECT_EQ(unittest::TestAllTypes::kRepeatedNestedMessageFieldNumber, 48); + EXPECT_EQ(unittest::TestAllTypes::kRepeatedNestedEnumFieldNumber, 51); +} + +TEST(GeneratedMessageTest, ExtensionConstantValues) { + EXPECT_EQ(unittest::TestRequired::kSingleFieldNumber, 1000); + EXPECT_EQ(unittest::TestRequired::kMultiFieldNumber, 1001); + EXPECT_EQ(unittest::kOptionalInt32ExtensionFieldNumber, 1); + EXPECT_EQ(unittest::kOptionalgroupExtensionFieldNumber, 16); + EXPECT_EQ(unittest::kOptionalNestedMessageExtensionFieldNumber, 18); + EXPECT_EQ(unittest::kOptionalNestedEnumExtensionFieldNumber, 21); + EXPECT_EQ(unittest::kRepeatedInt32ExtensionFieldNumber, 31); + EXPECT_EQ(unittest::kRepeatedgroupExtensionFieldNumber, 46); + EXPECT_EQ(unittest::kRepeatedNestedMessageExtensionFieldNumber, 48); + EXPECT_EQ(unittest::kRepeatedNestedEnumExtensionFieldNumber, 51); +} + +// =================================================================== + +TEST(GeneratedEnumTest, EnumValuesAsSwitchCases) { + // Test that our nested enum values can be used as switch cases. This test + // doesn't actually do anything, the proof that it works is that it + // compiles. + int i =0; + unittest::TestAllTypes::NestedEnum a = unittest::TestAllTypes::BAR; + switch (a) { + case unittest::TestAllTypes::FOO: + i = 1; + break; + case unittest::TestAllTypes::BAR: + i = 2; + break; + case unittest::TestAllTypes::BAZ: + i = 3; + break; + // no default case: We want to make sure the compiler recognizes that + // all cases are covered. (GCC warns if you do not cover all cases of + // an enum in a switch.) + } + + // Token check just for fun. + EXPECT_EQ(2, i); +} + +TEST(GeneratedEnumTest, IsValidValue) { + // Test enum IsValidValue. + EXPECT_TRUE(unittest::TestAllTypes::NestedEnum_IsValid(1)); + EXPECT_TRUE(unittest::TestAllTypes::NestedEnum_IsValid(2)); + EXPECT_TRUE(unittest::TestAllTypes::NestedEnum_IsValid(3)); + + EXPECT_FALSE(unittest::TestAllTypes::NestedEnum_IsValid(0)); + EXPECT_FALSE(unittest::TestAllTypes::NestedEnum_IsValid(4)); + + // Make sure it also works when there are dups. + EXPECT_TRUE(unittest::TestEnumWithDupValue_IsValid(1)); + EXPECT_TRUE(unittest::TestEnumWithDupValue_IsValid(2)); + EXPECT_TRUE(unittest::TestEnumWithDupValue_IsValid(3)); + + EXPECT_FALSE(unittest::TestEnumWithDupValue_IsValid(0)); + EXPECT_FALSE(unittest::TestEnumWithDupValue_IsValid(4)); +} + +TEST(GeneratedEnumTest, MinAndMax) { + EXPECT_EQ(unittest::TestAllTypes::FOO, + unittest::TestAllTypes::NestedEnum_MIN); + EXPECT_EQ(unittest::TestAllTypes::BAZ, + unittest::TestAllTypes::NestedEnum_MAX); + EXPECT_EQ(4, unittest::TestAllTypes::NestedEnum_ARRAYSIZE); + + EXPECT_EQ(unittest::FOREIGN_FOO, unittest::ForeignEnum_MIN); + EXPECT_EQ(unittest::FOREIGN_BAZ, unittest::ForeignEnum_MAX); + EXPECT_EQ(7, unittest::ForeignEnum_ARRAYSIZE); + + EXPECT_EQ(1, unittest::TestEnumWithDupValue_MIN); + EXPECT_EQ(3, unittest::TestEnumWithDupValue_MAX); + EXPECT_EQ(4, unittest::TestEnumWithDupValue_ARRAYSIZE); + + EXPECT_EQ(unittest::SPARSE_E, unittest::TestSparseEnum_MIN); + EXPECT_EQ(unittest::SPARSE_C, unittest::TestSparseEnum_MAX); + EXPECT_EQ(12589235, unittest::TestSparseEnum_ARRAYSIZE); + + // Make sure we can take the address of _MIN, _MAX and _ARRAYSIZE. + void* null_pointer = 0; // NULL may be integer-type, not pointer-type. + EXPECT_NE(null_pointer, &unittest::TestAllTypes::NestedEnum_MIN); + EXPECT_NE(null_pointer, &unittest::TestAllTypes::NestedEnum_MAX); + EXPECT_NE(null_pointer, &unittest::TestAllTypes::NestedEnum_ARRAYSIZE); + + EXPECT_NE(null_pointer, &unittest::ForeignEnum_MIN); + EXPECT_NE(null_pointer, &unittest::ForeignEnum_MAX); + EXPECT_NE(null_pointer, &unittest::ForeignEnum_ARRAYSIZE); + + // Make sure we can use _MIN, _MAX and _ARRAYSIZE as switch cases. + switch (unittest::SPARSE_A) { + case unittest::TestSparseEnum_MIN: + case unittest::TestSparseEnum_MAX: + case unittest::TestSparseEnum_ARRAYSIZE: + break; + default: + break; + } +} + +#ifndef PROTOBUF_TEST_NO_DESCRIPTORS + +TEST(GeneratedEnumTest, Name) { + // "Names" in the presence of dup values are a bit arbitrary. + EXPECT_EQ("FOO1", unittest::TestEnumWithDupValue_Name(unittest::FOO1)); + EXPECT_EQ("FOO1", unittest::TestEnumWithDupValue_Name(unittest::FOO2)); + + EXPECT_EQ("SPARSE_A", unittest::TestSparseEnum_Name(unittest::SPARSE_A)); + EXPECT_EQ("SPARSE_B", unittest::TestSparseEnum_Name(unittest::SPARSE_B)); + EXPECT_EQ("SPARSE_C", unittest::TestSparseEnum_Name(unittest::SPARSE_C)); + EXPECT_EQ("SPARSE_D", unittest::TestSparseEnum_Name(unittest::SPARSE_D)); + EXPECT_EQ("SPARSE_E", unittest::TestSparseEnum_Name(unittest::SPARSE_E)); + EXPECT_EQ("SPARSE_F", unittest::TestSparseEnum_Name(unittest::SPARSE_F)); + EXPECT_EQ("SPARSE_G", unittest::TestSparseEnum_Name(unittest::SPARSE_G)); +} + +TEST(GeneratedEnumTest, Parse) { + unittest::TestEnumWithDupValue dup_value = unittest::FOO1; + EXPECT_TRUE(unittest::TestEnumWithDupValue_Parse("FOO1", &dup_value)); + EXPECT_EQ(unittest::FOO1, dup_value); + EXPECT_TRUE(unittest::TestEnumWithDupValue_Parse("FOO2", &dup_value)); + EXPECT_EQ(unittest::FOO2, dup_value); + EXPECT_FALSE(unittest::TestEnumWithDupValue_Parse("FOO", &dup_value)); +} + +TEST(GeneratedEnumTest, GetEnumDescriptor) { + EXPECT_EQ(unittest::TestAllTypes::NestedEnum_descriptor(), + GetEnumDescriptor()); + EXPECT_EQ(unittest::ForeignEnum_descriptor(), + GetEnumDescriptor()); + EXPECT_EQ(unittest::TestEnumWithDupValue_descriptor(), + GetEnumDescriptor()); + EXPECT_EQ(unittest::TestSparseEnum_descriptor(), + GetEnumDescriptor()); +} + +#endif // PROTOBUF_TEST_NO_DESCRIPTORS + +// =================================================================== + +#ifndef PROTOBUF_TEST_NO_DESCRIPTORS + +// Support code for testing services. +class GeneratedServiceTest : public testing::Test { + protected: + class MockTestService : public unittest::TestService { + public: + MockTestService() + : called_(false), + method_(""), + controller_(NULL), + request_(NULL), + response_(NULL), + done_(NULL) {} + + ~MockTestService() {} + + void Reset() { called_ = false; } + + // implements TestService ---------------------------------------- + + void Foo(RpcController* controller, + const unittest::FooRequest* request, + unittest::FooResponse* response, + Closure* done) { + ASSERT_FALSE(called_); + called_ = true; + method_ = "Foo"; + controller_ = controller; + request_ = request; + response_ = response; + done_ = done; + } + + void Bar(RpcController* controller, + const unittest::BarRequest* request, + unittest::BarResponse* response, + Closure* done) { + ASSERT_FALSE(called_); + called_ = true; + method_ = "Bar"; + controller_ = controller; + request_ = request; + response_ = response; + done_ = done; + } + + // --------------------------------------------------------------- + + bool called_; + string method_; + RpcController* controller_; + const Message* request_; + Message* response_; + Closure* done_; + }; + + class MockRpcChannel : public RpcChannel { + public: + MockRpcChannel() + : called_(false), + method_(NULL), + controller_(NULL), + request_(NULL), + response_(NULL), + done_(NULL), + destroyed_(NULL) {} + + ~MockRpcChannel() { + if (destroyed_ != NULL) *destroyed_ = true; + } + + void Reset() { called_ = false; } + + // implements TestService ---------------------------------------- + + void CallMethod(const MethodDescriptor* method, + RpcController* controller, + const Message* request, + Message* response, + Closure* done) { + ASSERT_FALSE(called_); + called_ = true; + method_ = method; + controller_ = controller; + request_ = request; + response_ = response; + done_ = done; + } + + // --------------------------------------------------------------- + + bool called_; + const MethodDescriptor* method_; + RpcController* controller_; + const Message* request_; + Message* response_; + Closure* done_; + bool* destroyed_; + }; + + class MockController : public RpcController { + public: + void Reset() { + ADD_FAILURE() << "Reset() not expected during this test."; + } + bool Failed() const { + ADD_FAILURE() << "Failed() not expected during this test."; + return false; + } + string ErrorText() const { + ADD_FAILURE() << "ErrorText() not expected during this test."; + return ""; + } + void StartCancel() { + ADD_FAILURE() << "StartCancel() not expected during this test."; + } + void SetFailed(const string& reason) { + ADD_FAILURE() << "SetFailed() not expected during this test."; + } + bool IsCanceled() const { + ADD_FAILURE() << "IsCanceled() not expected during this test."; + return false; + } + void NotifyOnCancel(Closure* callback) { + ADD_FAILURE() << "NotifyOnCancel() not expected during this test."; + } + }; + + GeneratedServiceTest() + : descriptor_(unittest::TestService::descriptor()), + foo_(descriptor_->FindMethodByName("Foo")), + bar_(descriptor_->FindMethodByName("Bar")), + stub_(&mock_channel_), + done_(NewPermanentCallback(&DoNothing)) {} + + virtual void SetUp() { + ASSERT_TRUE(foo_ != NULL); + ASSERT_TRUE(bar_ != NULL); + } + + const ServiceDescriptor* descriptor_; + const MethodDescriptor* foo_; + const MethodDescriptor* bar_; + + MockTestService mock_service_; + MockController mock_controller_; + + MockRpcChannel mock_channel_; + unittest::TestService::Stub stub_; + + // Just so we don't have to re-define these with every test. + unittest::FooRequest foo_request_; + unittest::FooResponse foo_response_; + unittest::BarRequest bar_request_; + unittest::BarResponse bar_response_; + scoped_ptr done_; +}; + +TEST_F(GeneratedServiceTest, GetDescriptor) { + // Test that GetDescriptor() works. + + EXPECT_EQ(descriptor_, mock_service_.GetDescriptor()); +} + +TEST_F(GeneratedServiceTest, GetChannel) { + EXPECT_EQ(&mock_channel_, stub_.channel()); +} + +TEST_F(GeneratedServiceTest, OwnsChannel) { + MockRpcChannel* channel = new MockRpcChannel; + bool destroyed = false; + channel->destroyed_ = &destroyed; + + { + unittest::TestService::Stub owning_stub(channel, + Service::STUB_OWNS_CHANNEL); + EXPECT_FALSE(destroyed); + } + + EXPECT_TRUE(destroyed); +} + +TEST_F(GeneratedServiceTest, CallMethod) { + // Test that CallMethod() works. + + // Call Foo() via CallMethod(). + mock_service_.CallMethod(foo_, &mock_controller_, + &foo_request_, &foo_response_, done_.get()); + + ASSERT_TRUE(mock_service_.called_); + + EXPECT_EQ("Foo" , mock_service_.method_ ); + EXPECT_EQ(&mock_controller_, mock_service_.controller_); + EXPECT_EQ(&foo_request_ , mock_service_.request_ ); + EXPECT_EQ(&foo_response_ , mock_service_.response_ ); + EXPECT_EQ(done_.get() , mock_service_.done_ ); + + // Try again, but call Bar() instead. + mock_service_.Reset(); + mock_service_.CallMethod(bar_, &mock_controller_, + &bar_request_, &bar_response_, done_.get()); + + ASSERT_TRUE(mock_service_.called_); + EXPECT_EQ("Bar", mock_service_.method_); +} + +TEST_F(GeneratedServiceTest, CallMethodTypeFailure) { + // Verify death if we call Foo() with Bar's message types. + +#ifdef GTEST_HAS_DEATH_TEST // death tests do not work on Windows yet + EXPECT_DEBUG_DEATH( + mock_service_.CallMethod(foo_, &mock_controller_, + &foo_request_, &bar_response_, done_.get()), + "dynamic_cast"); + + mock_service_.Reset(); + EXPECT_DEBUG_DEATH( + mock_service_.CallMethod(foo_, &mock_controller_, + &bar_request_, &foo_response_, done_.get()), + "dynamic_cast"); +#endif // GTEST_HAS_DEATH_TEST +} + +TEST_F(GeneratedServiceTest, GetPrototypes) { + // Test Get{Request,Response}Prototype() methods. + + EXPECT_EQ(&unittest::FooRequest::default_instance(), + &mock_service_.GetRequestPrototype(foo_)); + EXPECT_EQ(&unittest::BarRequest::default_instance(), + &mock_service_.GetRequestPrototype(bar_)); + + EXPECT_EQ(&unittest::FooResponse::default_instance(), + &mock_service_.GetResponsePrototype(foo_)); + EXPECT_EQ(&unittest::BarResponse::default_instance(), + &mock_service_.GetResponsePrototype(bar_)); +} + +TEST_F(GeneratedServiceTest, Stub) { + // Test that the stub class works. + + // Call Foo() via the stub. + stub_.Foo(&mock_controller_, &foo_request_, &foo_response_, done_.get()); + + ASSERT_TRUE(mock_channel_.called_); + + EXPECT_EQ(foo_ , mock_channel_.method_ ); + EXPECT_EQ(&mock_controller_, mock_channel_.controller_); + EXPECT_EQ(&foo_request_ , mock_channel_.request_ ); + EXPECT_EQ(&foo_response_ , mock_channel_.response_ ); + EXPECT_EQ(done_.get() , mock_channel_.done_ ); + + // Call Bar() via the stub. + mock_channel_.Reset(); + stub_.Bar(&mock_controller_, &bar_request_, &bar_response_, done_.get()); + + ASSERT_TRUE(mock_channel_.called_); + EXPECT_EQ(bar_, mock_channel_.method_); +} + +TEST_F(GeneratedServiceTest, NotImplemented) { + // Test that failing to implement a method of a service causes it to fail + // with a "not implemented" error message. + + // A service which doesn't implement any methods. + class UnimplementedService : public unittest::TestService { + public: + UnimplementedService() {} + }; + + UnimplementedService unimplemented_service; + + // And a controller which expects to get a "not implemented" error. + class ExpectUnimplementedController : public MockController { + public: + ExpectUnimplementedController() : called_(false) {} + + void SetFailed(const string& reason) { + EXPECT_FALSE(called_); + called_ = true; + EXPECT_EQ("Method Foo() not implemented.", reason); + } + + bool called_; + }; + + ExpectUnimplementedController controller; + + // Call Foo. + unimplemented_service.Foo(&controller, &foo_request_, &foo_response_, + done_.get()); + + EXPECT_TRUE(controller.called_); +} + +} // namespace cpp_unittest +} // namespace cpp +} // namespace compiler + +namespace no_generic_services_test { + // Verify that no class called "TestService" was defined in + // unittest_no_generic_services.pb.h by defining a different type by the same + // name. If such a service was generated, this will not compile. + struct TestService { + int i; + }; +} + +namespace compiler { +namespace cpp { +namespace cpp_unittest { + +TEST_F(GeneratedServiceTest, NoGenericServices) { + // Verify that non-services in unittest_no_generic_services.proto were + // generated. + no_generic_services_test::TestMessage message; + message.set_a(1); + message.SetExtension(no_generic_services_test::test_extension, 123); + no_generic_services_test::TestEnum e = no_generic_services_test::FOO; + EXPECT_EQ(e, 1); + + // Verify that a ServiceDescriptor is generated for the service even if the + // class itself is not. + const FileDescriptor* file = + no_generic_services_test::TestMessage::descriptor()->file(); + + ASSERT_EQ(1, file->service_count()); + EXPECT_EQ("TestService", file->service(0)->name()); + ASSERT_EQ(1, file->service(0)->method_count()); + EXPECT_EQ("Foo", file->service(0)->method(0)->name()); +} + +#endif // !PROTOBUF_TEST_NO_DESCRIPTORS + +// =================================================================== + +// This test must run last. It verifies that descriptors were or were not +// initialized depending on whether PROTOBUF_TEST_NO_DESCRIPTORS was defined. +// When this is defined, we skip all tests which are expected to trigger +// descriptor initialization. This verifies that everything else still works +// if descriptors are not initialized. +TEST(DescriptorInitializationTest, Initialized) { +#ifdef PROTOBUF_TEST_NO_DESCRIPTORS + bool should_have_descriptors = false; +#else + bool should_have_descriptors = true; +#endif + + EXPECT_EQ(should_have_descriptors, + DescriptorPool::generated_pool()->InternalIsFileLoaded( + "google/protobuf/unittest.proto")); +} + +} // namespace cpp_unittest + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/depends/protobuf/google/protobuf/compiler/importer.cc b/depends/protobuf/google/protobuf/compiler/importer.cc new file mode 100644 index 0000000000..422f759f2b --- /dev/null +++ b/depends/protobuf/google/protobuf/compiler/importer.cc @@ -0,0 +1,459 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifdef _MSC_VER +#include +#else +#include +#endif +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { + +#ifdef _WIN32 +#ifndef F_OK +#define F_OK 00 // not defined by MSVC for whatever reason +#endif +#include +#endif + +// Returns true if the text looks like a Windows-style absolute path, starting +// with a drive letter. Example: "C:\foo". TODO(kenton): Share this with +// copy in command_line_interface.cc? +static bool IsWindowsAbsolutePath(const string& text) { +#if defined(_WIN32) || defined(__CYGWIN__) + return text.size() >= 3 && text[1] == ':' && + isalpha(text[0]) && + (text[2] == '/' || text[2] == '\\') && + text.find_last_of(':') == 1; +#else + return false; +#endif +} + +MultiFileErrorCollector::~MultiFileErrorCollector() {} + +// This class serves two purposes: +// - It implements the ErrorCollector interface (used by Tokenizer and Parser) +// in terms of MultiFileErrorCollector, using a particular filename. +// - It lets us check if any errors have occurred. +class SourceTreeDescriptorDatabase::SingleFileErrorCollector + : public io::ErrorCollector { + public: + SingleFileErrorCollector(const string& filename, + MultiFileErrorCollector* multi_file_error_collector) + : filename_(filename), + multi_file_error_collector_(multi_file_error_collector), + had_errors_(false) {} + ~SingleFileErrorCollector() {} + + bool had_errors() { return had_errors_; } + + // implements ErrorCollector --------------------------------------- + void AddError(int line, int column, const string& message) { + if (multi_file_error_collector_ != NULL) { + multi_file_error_collector_->AddError(filename_, line, column, message); + } + had_errors_ = true; + } + + private: + string filename_; + MultiFileErrorCollector* multi_file_error_collector_; + bool had_errors_; +}; + +// =================================================================== + +SourceTreeDescriptorDatabase::SourceTreeDescriptorDatabase( + SourceTree* source_tree) + : source_tree_(source_tree), + error_collector_(NULL), + using_validation_error_collector_(false), + validation_error_collector_(this) {} + +SourceTreeDescriptorDatabase::~SourceTreeDescriptorDatabase() {} + +bool SourceTreeDescriptorDatabase::FindFileByName( + const string& filename, FileDescriptorProto* output) { + scoped_ptr input(source_tree_->Open(filename)); + if (input == NULL) { + if (error_collector_ != NULL) { + error_collector_->AddError(filename, -1, 0, "File not found."); + } + return false; + } + + // Set up the tokenizer and parser. + SingleFileErrorCollector file_error_collector(filename, error_collector_); + io::Tokenizer tokenizer(input.get(), &file_error_collector); + + Parser parser; + if (error_collector_ != NULL) { + parser.RecordErrorsTo(&file_error_collector); + } + if (using_validation_error_collector_) { + parser.RecordSourceLocationsTo(&source_locations_); + } + + // Parse it. + output->set_name(filename); + return parser.Parse(&tokenizer, output) && + !file_error_collector.had_errors(); +} + +bool SourceTreeDescriptorDatabase::FindFileContainingSymbol( + const string& symbol_name, FileDescriptorProto* output) { + return false; +} + +bool SourceTreeDescriptorDatabase::FindFileContainingExtension( + const string& containing_type, int field_number, + FileDescriptorProto* output) { + return false; +} + +// ------------------------------------------------------------------- + +SourceTreeDescriptorDatabase::ValidationErrorCollector:: +ValidationErrorCollector(SourceTreeDescriptorDatabase* owner) + : owner_(owner) {} + +SourceTreeDescriptorDatabase::ValidationErrorCollector:: +~ValidationErrorCollector() {} + +void SourceTreeDescriptorDatabase::ValidationErrorCollector::AddError( + const string& filename, + const string& element_name, + const Message* descriptor, + ErrorLocation location, + const string& message) { + if (owner_->error_collector_ == NULL) return; + + int line, column; + owner_->source_locations_.Find(descriptor, location, &line, &column); + owner_->error_collector_->AddError(filename, line, column, message); +} + +// =================================================================== + +Importer::Importer(SourceTree* source_tree, + MultiFileErrorCollector* error_collector) + : database_(source_tree), + pool_(&database_, database_.GetValidationErrorCollector()) { + database_.RecordErrorsTo(error_collector); +} + +Importer::~Importer() {} + +const FileDescriptor* Importer::Import(const string& filename) { + return pool_.FindFileByName(filename); +} + +// =================================================================== + +SourceTree::~SourceTree() {} + +DiskSourceTree::DiskSourceTree() {} + +DiskSourceTree::~DiskSourceTree() {} + +static inline char LastChar(const string& str) { + return str[str.size() - 1]; +} + +// Given a path, returns an equivalent path with these changes: +// - On Windows, any backslashes are replaced with forward slashes. +// - Any instances of the directory "." are removed. +// - Any consecutive '/'s are collapsed into a single slash. +// Note that the resulting string may be empty. +// +// TODO(kenton): It would be nice to handle "..", e.g. so that we can figure +// out that "foo/bar.proto" is inside "baz/../foo". However, if baz is a +// symlink or doesn't exist, then things get complicated, and we can't +// actually determine this without investigating the filesystem, probably +// in non-portable ways. So, we punt. +// +// TODO(kenton): It would be nice to use realpath() here except that it +// resolves symbolic links. This could cause problems if people place +// symbolic links in their source tree. For example, if you executed: +// protoc --proto_path=foo foo/bar/baz.proto +// then if foo/bar is a symbolic link, foo/bar/baz.proto will canonicalize +// to a path which does not appear to be under foo, and thus the compiler +// will complain that baz.proto is not inside the --proto_path. +static string CanonicalizePath(string path) { +#ifdef _WIN32 + // The Win32 API accepts forward slashes as a path delimiter even though + // backslashes are standard. Let's avoid confusion and use only forward + // slashes. + if (HasPrefixString(path, "\\\\")) { + // Avoid converting two leading backslashes. + path = "\\\\" + StringReplace(path.substr(2), "\\", "/", true); + } else { + path = StringReplace(path, "\\", "/", true); + } +#endif + + vector parts; + vector canonical_parts; + SplitStringUsing(path, "/", &parts); // Note: Removes empty parts. + for (int i = 0; i < parts.size(); i++) { + if (parts[i] == ".") { + // Ignore. + } else { + canonical_parts.push_back(parts[i]); + } + } + string result = JoinStrings(canonical_parts, "/"); + if (!path.empty() && path[0] == '/') { + // Restore leading slash. + result = '/' + result; + } + if (!path.empty() && LastChar(path) == '/' && + !result.empty() && LastChar(result) != '/') { + // Restore trailing slash. + result += '/'; + } + return result; +} + +static inline bool ContainsParentReference(const string& path) { + return path == ".." || + HasPrefixString(path, "../") || + HasSuffixString(path, "/..") || + path.find("/../") != string::npos; +} + +// Maps a file from an old location to a new one. Typically, old_prefix is +// a virtual path and new_prefix is its corresponding disk path. Returns +// false if the filename did not start with old_prefix, otherwise replaces +// old_prefix with new_prefix and stores the result in *result. Examples: +// string result; +// assert(ApplyMapping("foo/bar", "", "baz", &result)); +// assert(result == "baz/foo/bar"); +// +// assert(ApplyMapping("foo/bar", "foo", "baz", &result)); +// assert(result == "baz/bar"); +// +// assert(ApplyMapping("foo", "foo", "bar", &result)); +// assert(result == "bar"); +// +// assert(!ApplyMapping("foo/bar", "baz", "qux", &result)); +// assert(!ApplyMapping("foo/bar", "baz", "qux", &result)); +// assert(!ApplyMapping("foobar", "foo", "baz", &result)); +static bool ApplyMapping(const string& filename, + const string& old_prefix, + const string& new_prefix, + string* result) { + if (old_prefix.empty()) { + // old_prefix matches any relative path. + if (ContainsParentReference(filename)) { + // We do not allow the file name to use "..". + return false; + } + if (HasPrefixString(filename, "/") || + IsWindowsAbsolutePath(filename)) { + // This is an absolute path, so it isn't matched by the empty string. + return false; + } + result->assign(new_prefix); + if (!result->empty()) result->push_back('/'); + result->append(filename); + return true; + } else if (HasPrefixString(filename, old_prefix)) { + // old_prefix is a prefix of the filename. Is it the whole filename? + if (filename.size() == old_prefix.size()) { + // Yep, it's an exact match. + *result = new_prefix; + return true; + } else { + // Not an exact match. Is the next character a '/'? Otherwise, + // this isn't actually a match at all. E.g. the prefix "foo/bar" + // does not match the filename "foo/barbaz". + int after_prefix_start = -1; + if (filename[old_prefix.size()] == '/') { + after_prefix_start = old_prefix.size() + 1; + } else if (filename[old_prefix.size() - 1] == '/') { + // old_prefix is never empty, and canonicalized paths never have + // consecutive '/' characters. + after_prefix_start = old_prefix.size(); + } + if (after_prefix_start != -1) { + // Yep. So the prefixes are directories and the filename is a file + // inside them. + string after_prefix = filename.substr(after_prefix_start); + if (ContainsParentReference(after_prefix)) { + // We do not allow the file name to use "..". + return false; + } + result->assign(new_prefix); + if (!result->empty()) result->push_back('/'); + result->append(after_prefix); + return true; + } + } + } + + return false; +} + +void DiskSourceTree::MapPath(const string& virtual_path, + const string& disk_path) { + mappings_.push_back(Mapping(virtual_path, CanonicalizePath(disk_path))); +} + +DiskSourceTree::DiskFileToVirtualFileResult +DiskSourceTree::DiskFileToVirtualFile( + const string& disk_file, + string* virtual_file, + string* shadowing_disk_file) { + int mapping_index = -1; + string canonical_disk_file = CanonicalizePath(disk_file); + + for (int i = 0; i < mappings_.size(); i++) { + // Apply the mapping in reverse. + if (ApplyMapping(canonical_disk_file, mappings_[i].disk_path, + mappings_[i].virtual_path, virtual_file)) { + // Success. + mapping_index = i; + break; + } + } + + if (mapping_index == -1) { + return NO_MAPPING; + } + + // Iterate through all mappings with higher precedence and verify that none + // of them map this file to some other existing file. + for (int i = 0; i < mapping_index; i++) { + if (ApplyMapping(*virtual_file, mappings_[i].virtual_path, + mappings_[i].disk_path, shadowing_disk_file)) { + if (access(shadowing_disk_file->c_str(), F_OK) >= 0) { + // File exists. + return SHADOWED; + } + } + } + shadowing_disk_file->clear(); + + // Verify that we can open the file. Note that this also has the side-effect + // of verifying that we are not canonicalizing away any non-existent + // directories. + scoped_ptr stream(OpenDiskFile(disk_file)); + if (stream == NULL) { + return CANNOT_OPEN; + } + + return SUCCESS; +} + +bool DiskSourceTree::VirtualFileToDiskFile(const string& virtual_file, + string* disk_file) { + scoped_ptr stream(OpenVirtualFile(virtual_file, + disk_file)); + return stream != NULL; +} + +io::ZeroCopyInputStream* DiskSourceTree::Open(const string& filename) { + return OpenVirtualFile(filename, NULL); +} + +io::ZeroCopyInputStream* DiskSourceTree::OpenVirtualFile( + const string& virtual_file, + string* disk_file) { + if (virtual_file != CanonicalizePath(virtual_file) || + ContainsParentReference(virtual_file)) { + // We do not allow importing of paths containing things like ".." or + // consecutive slashes since the compiler expects files to be uniquely + // identified by file name. + return NULL; + } + + for (int i = 0; i < mappings_.size(); i++) { + string temp_disk_file; + if (ApplyMapping(virtual_file, mappings_[i].virtual_path, + mappings_[i].disk_path, &temp_disk_file)) { + io::ZeroCopyInputStream* stream = OpenDiskFile(temp_disk_file); + if (stream != NULL) { + if (disk_file != NULL) { + *disk_file = temp_disk_file; + } + return stream; + } + + if (errno == EACCES) { + // The file exists but is not readable. + // TODO(kenton): Find a way to report this more nicely. + GOOGLE_LOG(WARNING) << "Read access is denied for file: " << temp_disk_file; + return NULL; + } + } + } + + return NULL; +} + +io::ZeroCopyInputStream* DiskSourceTree::OpenDiskFile( + const string& filename) { + int file_descriptor; + do { + file_descriptor = open(filename.c_str(), O_RDONLY); + } while (file_descriptor < 0 && errno == EINTR); + if (file_descriptor >= 0) { + io::FileInputStream* result = new io::FileInputStream(file_descriptor); + result->SetCloseOnDelete(true); + return result; + } else { + return NULL; + } +} + +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/depends/protobuf/google/protobuf/compiler/importer.h b/depends/protobuf/google/protobuf/compiler/importer.h new file mode 100644 index 0000000000..7a2efc2976 --- /dev/null +++ b/depends/protobuf/google/protobuf/compiler/importer.h @@ -0,0 +1,303 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// This file is the public interface to the .proto file parser. + +#ifndef GOOGLE_PROTOBUF_COMPILER_IMPORTER_H__ +#define GOOGLE_PROTOBUF_COMPILER_IMPORTER_H__ + +#include +#include +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { + +namespace io { class ZeroCopyInputStream; } + +namespace compiler { + +// Defined in this file. +class Importer; +class MultiFileErrorCollector; +class SourceTree; +class DiskSourceTree; + +// TODO(kenton): Move all SourceTree stuff to a separate file? + +// An implementation of DescriptorDatabase which loads files from a SourceTree +// and parses them. +// +// Note: This class is not thread-safe since it maintains a table of source +// code locations for error reporting. However, when a DescriptorPool wraps +// a DescriptorDatabase, it uses mutex locking to make sure only one method +// of the database is called at a time, even if the DescriptorPool is used +// from multiple threads. Therefore, there is only a problem if you create +// multiple DescriptorPools wrapping the same SourceTreeDescriptorDatabase +// and use them from multiple threads. +// +// Note: This class does not implement FindFileContainingSymbol() or +// FindFileContainingExtension(); these will always return false. +class LIBPROTOBUF_EXPORT SourceTreeDescriptorDatabase : public DescriptorDatabase { + public: + SourceTreeDescriptorDatabase(SourceTree* source_tree); + ~SourceTreeDescriptorDatabase(); + + // Instructs the SourceTreeDescriptorDatabase to report any parse errors + // to the given MultiFileErrorCollector. This should be called before + // parsing. error_collector must remain valid until either this method + // is called again or the SourceTreeDescriptorDatabase is destroyed. + void RecordErrorsTo(MultiFileErrorCollector* error_collector) { + error_collector_ = error_collector; + } + + // Gets a DescriptorPool::ErrorCollector which records errors to the + // MultiFileErrorCollector specified with RecordErrorsTo(). This collector + // has the ability to determine exact line and column numbers of errors + // from the information given to it by the DescriptorPool. + DescriptorPool::ErrorCollector* GetValidationErrorCollector() { + using_validation_error_collector_ = true; + return &validation_error_collector_; + } + + // implements DescriptorDatabase ----------------------------------- + bool FindFileByName(const string& filename, FileDescriptorProto* output); + bool FindFileContainingSymbol(const string& symbol_name, + FileDescriptorProto* output); + bool FindFileContainingExtension(const string& containing_type, + int field_number, + FileDescriptorProto* output); + + private: + class SingleFileErrorCollector; + + SourceTree* source_tree_; + MultiFileErrorCollector* error_collector_; + + class LIBPROTOBUF_EXPORT ValidationErrorCollector : public DescriptorPool::ErrorCollector { + public: + ValidationErrorCollector(SourceTreeDescriptorDatabase* owner); + ~ValidationErrorCollector(); + + // implements ErrorCollector --------------------------------------- + void AddError(const string& filename, + const string& element_name, + const Message* descriptor, + ErrorLocation location, + const string& message); + + private: + SourceTreeDescriptorDatabase* owner_; + }; + friend class ValidationErrorCollector; + + bool using_validation_error_collector_; + SourceLocationTable source_locations_; + ValidationErrorCollector validation_error_collector_; +}; + +// Simple interface for parsing .proto files. This wraps the process +// of opening the file, parsing it with a Parser, recursively parsing all its +// imports, and then cross-linking the results to produce a FileDescriptor. +// +// This is really just a thin wrapper around SourceTreeDescriptorDatabase. +// You may find that SourceTreeDescriptorDatabase is more flexible. +// +// TODO(kenton): I feel like this class is not well-named. +class LIBPROTOBUF_EXPORT Importer { + public: + Importer(SourceTree* source_tree, + MultiFileErrorCollector* error_collector); + ~Importer(); + + // Import the given file and build a FileDescriptor representing it. If + // the file is already in the DescriptorPool, the existing FileDescriptor + // will be returned. The FileDescriptor is property of the DescriptorPool, + // and will remain valid until it is destroyed. If any errors occur, they + // will be reported using the error collector and Import() will return NULL. + // + // A particular Importer object will only report errors for a particular + // file once. All future attempts to import the same file will return NULL + // without reporting any errors. The idea is that you might want to import + // a lot of files without seeing the same errors over and over again. If + // you want to see errors for the same files repeatedly, you can use a + // separate Importer object to import each one (but use the same + // DescriptorPool so that they can be cross-linked). + const FileDescriptor* Import(const string& filename); + + // The DescriptorPool in which all imported FileDescriptors and their + // contents are stored. + inline const DescriptorPool* pool() const { + return &pool_; + } + + private: + SourceTreeDescriptorDatabase database_; + DescriptorPool pool_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Importer); +}; + +// If the importer encounters problems while trying to import the proto files, +// it reports them to a MultiFileErrorCollector. +class LIBPROTOBUF_EXPORT MultiFileErrorCollector { + public: + inline MultiFileErrorCollector() {} + virtual ~MultiFileErrorCollector(); + + // Line and column numbers are zero-based. A line number of -1 indicates + // an error with the entire file (e.g. "not found"). + virtual void AddError(const string& filename, int line, int column, + const string& message) = 0; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MultiFileErrorCollector); +}; + +// Abstract interface which represents a directory tree containing proto files. +// Used by the default implementation of Importer to resolve import statements +// Most users will probably want to use the DiskSourceTree implementation, +// below. +class LIBPROTOBUF_EXPORT SourceTree { + public: + inline SourceTree() {} + virtual ~SourceTree(); + + // Open the given file and return a stream that reads it, or NULL if not + // found. The caller takes ownership of the returned object. The filename + // must be a path relative to the root of the source tree and must not + // contain "." or ".." components. + virtual io::ZeroCopyInputStream* Open(const string& filename) = 0; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SourceTree); +}; + +// An implementation of SourceTree which loads files from locations on disk. +// Multiple mappings can be set up to map locations in the DiskSourceTree to +// locations in the physical filesystem. +class LIBPROTOBUF_EXPORT DiskSourceTree : public SourceTree { + public: + DiskSourceTree(); + ~DiskSourceTree(); + + // Map a path on disk to a location in the SourceTree. The path may be + // either a file or a directory. If it is a directory, the entire tree + // under it will be mapped to the given virtual location. To map a directory + // to the root of the source tree, pass an empty string for virtual_path. + // + // If multiple mapped paths apply when opening a file, they will be searched + // in order. For example, if you do: + // MapPath("bar", "foo/bar"); + // MapPath("", "baz"); + // and then you do: + // Open("bar/qux"); + // the DiskSourceTree will first try to open foo/bar/qux, then baz/bar/qux, + // returning the first one that opens successfuly. + // + // disk_path may be an absolute path or relative to the current directory, + // just like a path you'd pass to open(). + void MapPath(const string& virtual_path, const string& disk_path); + + // Return type for DiskFileToVirtualFile(). + enum DiskFileToVirtualFileResult { + SUCCESS, + SHADOWED, + CANNOT_OPEN, + NO_MAPPING + }; + + // Given a path to a file on disk, find a virtual path mapping to that + // file. The first mapping created with MapPath() whose disk_path contains + // the filename is used. However, that virtual path may not actually be + // usable to open the given file. Possible return values are: + // * SUCCESS: The mapping was found. *virtual_file is filled in so that + // calling Open(*virtual_file) will open the file named by disk_file. + // * SHADOWED: A mapping was found, but using Open() to open this virtual + // path will end up returning some different file. This is because some + // other mapping with a higher precedence also matches this virtual path + // and maps it to a different file that exists on disk. *virtual_file + // is filled in as it would be in the SUCCESS case. *shadowing_disk_file + // is filled in with the disk path of the file which would be opened if + // you were to call Open(*virtual_file). + // * CANNOT_OPEN: The mapping was found and was not shadowed, but the + // file specified cannot be opened. When this value is returned, + // errno will indicate the reason the file cannot be opened. *virtual_file + // will be set to the virtual path as in the SUCCESS case, even though + // it is not useful. + // * NO_MAPPING: Indicates that no mapping was found which contains this + // file. + DiskFileToVirtualFileResult + DiskFileToVirtualFile(const string& disk_file, + string* virtual_file, + string* shadowing_disk_file); + + // Given a virtual path, find the path to the file on disk. + // Return true and update disk_file with the on-disk path if the file exists. + // Return false and leave disk_file untouched if the file doesn't exist. + bool VirtualFileToDiskFile(const string& virtual_file, string* disk_file); + + // implements SourceTree ------------------------------------------- + io::ZeroCopyInputStream* Open(const string& filename); + + private: + struct Mapping { + string virtual_path; + string disk_path; + + inline Mapping(const string& virtual_path, const string& disk_path) + : virtual_path(virtual_path), disk_path(disk_path) {} + }; + vector mappings_; + + // Like Open(), but returns the on-disk path in disk_file if disk_file is + // non-NULL and the file could be successfully opened. + io::ZeroCopyInputStream* OpenVirtualFile(const string& virtual_file, + string* disk_file); + + // Like Open() but given the actual on-disk path. + io::ZeroCopyInputStream* OpenDiskFile(const string& filename); + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DiskSourceTree); +}; + +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_IMPORTER_H__ diff --git a/depends/protobuf/google/protobuf/compiler/main.cc b/depends/protobuf/google/protobuf/compiler/main.cc new file mode 100644 index 0000000000..4a17b87d95 --- /dev/null +++ b/depends/protobuf/google/protobuf/compiler/main.cc @@ -0,0 +1,61 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) + +#include +#include +//#include +//#include + + +int main(int argc, char* argv[]) { + + google::protobuf::compiler::CommandLineInterface cli; + cli.AllowPlugins("protoc-"); + + // Proto2 C++ + google::protobuf::compiler::cpp::CppGenerator cpp_generator; + cli.RegisterGenerator("--cpp_out", &cpp_generator, + "Generate C++ header and source."); + + // Proto2 Java + //google::protobuf::compiler::java::JavaGenerator java_generator; + //cli.RegisterGenerator("--java_out", &java_generator, + // "Generate Java source file."); + + + // Proto2 Python + //google::protobuf::compiler::python::Generator py_generator; + //cli.RegisterGenerator("--python_out", &py_generator, + // "Generate Python source file."); + + return cli.Run(argc, argv); +} diff --git a/depends/protobuf/google/protobuf/compiler/mock_code_generator.cc b/depends/protobuf/google/protobuf/compiler/mock_code_generator.cc new file mode 100644 index 0000000000..5b76af2577 --- /dev/null +++ b/depends/protobuf/google/protobuf/compiler/mock_code_generator.cc @@ -0,0 +1,231 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { + +// Returns the list of the names of files in all_files in the form of a +// comma-separated string. +string CommaSeparatedList(const vector all_files) { + vector names; + for (int i = 0; i < all_files.size(); i++) { + names.push_back(all_files[i]->name()); + } + return JoinStrings(names, ","); +} + +static const char* kFirstInsertionPointName = "first_mock_insertion_point"; +static const char* kSecondInsertionPointName = "second_mock_insertion_point"; +static const char* kFirstInsertionPoint = + "# @@protoc_insertion_point(first_mock_insertion_point) is here\n"; +static const char* kSecondInsertionPoint = + " # @@protoc_insertion_point(second_mock_insertion_point) is here\n"; + +MockCodeGenerator::MockCodeGenerator(const string& name) + : name_(name) {} + +MockCodeGenerator::~MockCodeGenerator() {} + +void MockCodeGenerator::ExpectGenerated( + const string& name, + const string& parameter, + const string& insertions, + const string& file, + const string& first_message_name, + const string& first_parsed_file_name, + const string& output_directory) { + string content; + ASSERT_TRUE(File::ReadFileToString( + output_directory + "/" + GetOutputFileName(name, file), &content)); + + vector lines; + SplitStringUsing(content, "\n", &lines); + + while (!lines.empty() && lines.back().empty()) { + lines.pop_back(); + } + for (int i = 0; i < lines.size(); i++) { + lines[i] += "\n"; + } + + vector insertion_list; + if (!insertions.empty()) { + SplitStringUsing(insertions, ",", &insertion_list); + } + + ASSERT_EQ(lines.size(), 3 + insertion_list.size() * 2); + EXPECT_EQ(GetOutputFileContent(name, parameter, file, + first_parsed_file_name, first_message_name), + lines[0]); + + EXPECT_EQ(kFirstInsertionPoint, lines[1 + insertion_list.size()]); + EXPECT_EQ(kSecondInsertionPoint, lines[2 + insertion_list.size() * 2]); + + for (int i = 0; i < insertion_list.size(); i++) { + EXPECT_EQ(GetOutputFileContent(insertion_list[i], "first_insert", + file, file, first_message_name), + lines[1 + i]); + // Second insertion point is indented, so the inserted text should + // automatically be indented too. + EXPECT_EQ(" " + GetOutputFileContent(insertion_list[i], "second_insert", + file, file, first_message_name), + lines[2 + insertion_list.size() + i]); + } +} + +bool MockCodeGenerator::Generate( + const FileDescriptor* file, + const string& parameter, + GeneratorContext* context, + string* error) const { + for (int i = 0; i < file->message_type_count(); i++) { + if (HasPrefixString(file->message_type(i)->name(), "MockCodeGenerator_")) { + string command = StripPrefixString(file->message_type(i)->name(), + "MockCodeGenerator_"); + if (command == "Error") { + *error = "Saw message type MockCodeGenerator_Error."; + return false; + } else if (command == "Exit") { + cerr << "Saw message type MockCodeGenerator_Exit." << endl; + exit(123); + } else if (command == "Abort") { + cerr << "Saw message type MockCodeGenerator_Abort." << endl; + abort(); + } else { + GOOGLE_LOG(FATAL) << "Unknown MockCodeGenerator command: " << command; + } + } + } + + if (HasPrefixString(parameter, "insert=")) { + vector insert_into; + SplitStringUsing(StripPrefixString(parameter, "insert="), + ",", &insert_into); + + for (int i = 0; i < insert_into.size(); i++) { + { + scoped_ptr output( + context->OpenForInsert( + GetOutputFileName(insert_into[i], file), + kFirstInsertionPointName)); + io::Printer printer(output.get(), '$'); + printer.PrintRaw(GetOutputFileContent(name_, "first_insert", + file, context)); + if (printer.failed()) { + *error = "MockCodeGenerator detected write error."; + return false; + } + } + + { + scoped_ptr output( + context->OpenForInsert( + GetOutputFileName(insert_into[i], file), + kSecondInsertionPointName)); + io::Printer printer(output.get(), '$'); + printer.PrintRaw(GetOutputFileContent(name_, "second_insert", + file, context)); + if (printer.failed()) { + *error = "MockCodeGenerator detected write error."; + return false; + } + } + } + } else { + scoped_ptr output( + context->Open(GetOutputFileName(name_, file))); + + io::Printer printer(output.get(), '$'); + printer.PrintRaw(GetOutputFileContent(name_, parameter, + file, context)); + printer.PrintRaw(kFirstInsertionPoint); + printer.PrintRaw(kSecondInsertionPoint); + + if (printer.failed()) { + *error = "MockCodeGenerator detected write error."; + return false; + } + } + + return true; +} + +string MockCodeGenerator::GetOutputFileName(const string& generator_name, + const FileDescriptor* file) { + return GetOutputFileName(generator_name, file->name()); +} + +string MockCodeGenerator::GetOutputFileName(const string& generator_name, + const string& file) { + return file + ".MockCodeGenerator." + generator_name; +} + +string MockCodeGenerator::GetOutputFileContent( + const string& generator_name, + const string& parameter, + const FileDescriptor* file, + GeneratorContext *context) { + vector all_files; + context->ListParsedFiles(&all_files); + return GetOutputFileContent( + generator_name, parameter, file->name(), + CommaSeparatedList(all_files), + file->message_type_count() > 0 ? + file->message_type(0)->name() : "(none)"); +} + +string MockCodeGenerator::GetOutputFileContent( + const string& generator_name, + const string& parameter, + const string& file, + const string& parsed_file_list, + const string& first_message_name) { + return strings::Substitute("$0: $1, $2, $3, $4\n", + generator_name, parameter, file, + first_message_name, parsed_file_list); +} + +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/depends/protobuf/google/protobuf/compiler/mock_code_generator.h b/depends/protobuf/google/protobuf/compiler/mock_code_generator.h new file mode 100644 index 0000000000..5c7942bda6 --- /dev/null +++ b/depends/protobuf/google/protobuf/compiler/mock_code_generator.h @@ -0,0 +1,113 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) + +#ifndef GOOGLE_PROTOBUF_COMPILER_MOCK_CODE_GENERATOR_H__ +#define GOOGLE_PROTOBUF_COMPILER_MOCK_CODE_GENERATOR_H__ + +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { + +// A mock CodeGenerator, used by command_line_interface_unittest. This is in +// its own file so that it can be used both directly and as a plugin. +// +// Generate() produces some output which can be checked by ExpectCalled(). The +// generator can run in a different process (e.g. a plugin). +// +// If the parameter is "insert=NAMES", the MockCodeGenerator will insert lines +// into the files generated by other MockCodeGenerators instead of creating +// its own file. NAMES is a comma-separated list of the names of those other +// MockCodeGenerators. +// +// MockCodeGenerator will also modify its behavior slightly if the input file +// contains a message type with one of the following names: +// MockCodeGenerator_Error: Causes Generate() to return false and set the +// error message to "Saw message type MockCodeGenerator_Error." +// MockCodeGenerator_Exit: Generate() prints "Saw message type +// MockCodeGenerator_Exit." to stderr and then calls exit(123). +// MockCodeGenerator_Abort: Generate() prints "Saw message type +// MockCodeGenerator_Abort." to stderr and then calls abort(). +class MockCodeGenerator : public CodeGenerator { + public: + MockCodeGenerator(const string& name); + virtual ~MockCodeGenerator(); + + // Expect (via gTest) that a MockCodeGenerator with the given name was called + // with the given parameters by inspecting the output location. + // + // |insertions| is a comma-separated list of names of MockCodeGenerators which + // should have inserted lines into this file. + // |parsed_file_list| is a comma-separated list of names of the files + // that are being compiled together in this run. + static void ExpectGenerated(const string& name, + const string& parameter, + const string& insertions, + const string& file, + const string& first_message_name, + const string& parsed_file_list, + const string& output_directory); + + // Get the name of the file which would be written by the given generator. + static string GetOutputFileName(const string& generator_name, + const FileDescriptor* file); + static string GetOutputFileName(const string& generator_name, + const string& file); + + // implements CodeGenerator ---------------------------------------- + + virtual bool Generate(const FileDescriptor* file, + const string& parameter, + GeneratorContext* context, + string* error) const; + + private: + string name_; + + static string GetOutputFileContent(const string& generator_name, + const string& parameter, + const FileDescriptor* file, + GeneratorContext *context); + static string GetOutputFileContent(const string& generator_name, + const string& parameter, + const string& file, + const string& parsed_file_list, + const string& first_message_name); +}; + +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_MOCK_CODE_GENERATOR_H__ diff --git a/depends/protobuf/google/protobuf/compiler/package_info.h b/depends/protobuf/google/protobuf/compiler/package_info.h new file mode 100644 index 0000000000..b897126742 --- /dev/null +++ b/depends/protobuf/google/protobuf/compiler/package_info.h @@ -0,0 +1,64 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// This file exists solely to document the google::protobuf::compiler namespace. +// It is not compiled into anything, but it may be read by an automated +// documentation generator. + +namespace google { + +namespace protobuf { + +// Implementation of the Protocol Buffer compiler. +// +// This package contains code for parsing .proto files and generating code +// based on them. There are two reasons you might be interested in this +// package: +// - You want to parse .proto files at runtime. In this case, you should +// look at importer.h. Since this functionality is widely useful, it is +// included in the libprotobuf base library; you do not have to link against +// libprotoc. +// - You want to write a custom protocol compiler which generates different +// kinds of code, e.g. code in a different language which is not supported +// by the official compiler. For this purpose, command_line_interface.h +// provides you with a complete compiler front-end, so all you need to do +// is write a custom implementation of CodeGenerator and a trivial main() +// function. You can even make your compiler support the official languages +// in addition to your own. Since this functionality is only useful to those +// writing custom compilers, it is in a separate library called "libprotoc" +// which you will have to link against. +namespace compiler {} + +} // namespace protobuf +} // namespace google diff --git a/depends/protobuf/google/protobuf/compiler/parser.cc b/depends/protobuf/google/protobuf/compiler/parser.cc new file mode 100644 index 0000000000..34317b1fd9 --- /dev/null +++ b/depends/protobuf/google/protobuf/compiler/parser.cc @@ -0,0 +1,1473 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// Recursive descent FTW. + +#include +#include +#include + + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { + +using internal::WireFormat; + +namespace { + +typedef hash_map TypeNameMap; + +TypeNameMap MakeTypeNameTable() { + TypeNameMap result; + + result["double" ] = FieldDescriptorProto::TYPE_DOUBLE; + result["float" ] = FieldDescriptorProto::TYPE_FLOAT; + result["uint64" ] = FieldDescriptorProto::TYPE_UINT64; + result["fixed64" ] = FieldDescriptorProto::TYPE_FIXED64; + result["fixed32" ] = FieldDescriptorProto::TYPE_FIXED32; + result["bool" ] = FieldDescriptorProto::TYPE_BOOL; + result["string" ] = FieldDescriptorProto::TYPE_STRING; + result["group" ] = FieldDescriptorProto::TYPE_GROUP; + + result["bytes" ] = FieldDescriptorProto::TYPE_BYTES; + result["uint32" ] = FieldDescriptorProto::TYPE_UINT32; + result["sfixed32"] = FieldDescriptorProto::TYPE_SFIXED32; + result["sfixed64"] = FieldDescriptorProto::TYPE_SFIXED64; + result["int32" ] = FieldDescriptorProto::TYPE_INT32; + result["int64" ] = FieldDescriptorProto::TYPE_INT64; + result["sint32" ] = FieldDescriptorProto::TYPE_SINT32; + result["sint64" ] = FieldDescriptorProto::TYPE_SINT64; + + return result; +} + +const TypeNameMap kTypeNames = MakeTypeNameTable(); + +} // anonymous namespace + +// Makes code slightly more readable. The meaning of "DO(foo)" is +// "Execute foo and fail if it fails.", where failure is indicated by +// returning false. +#define DO(STATEMENT) if (STATEMENT) {} else return false + +// =================================================================== + +Parser::Parser() + : input_(NULL), + error_collector_(NULL), + source_location_table_(NULL), + had_errors_(false), + require_syntax_identifier_(false), + stop_after_syntax_identifier_(false) { +} + +Parser::~Parser() { +} + +// =================================================================== + +inline bool Parser::LookingAt(const char* text) { + return input_->current().text == text; +} + +inline bool Parser::LookingAtType(io::Tokenizer::TokenType token_type) { + return input_->current().type == token_type; +} + +inline bool Parser::AtEnd() { + return LookingAtType(io::Tokenizer::TYPE_END); +} + +bool Parser::TryConsume(const char* text) { + if (LookingAt(text)) { + input_->Next(); + return true; + } else { + return false; + } +} + +bool Parser::Consume(const char* text, const char* error) { + if (TryConsume(text)) { + return true; + } else { + AddError(error); + return false; + } +} + +bool Parser::Consume(const char* text) { + if (TryConsume(text)) { + return true; + } else { + AddError("Expected \"" + string(text) + "\"."); + return false; + } +} + +bool Parser::ConsumeIdentifier(string* output, const char* error) { + if (LookingAtType(io::Tokenizer::TYPE_IDENTIFIER)) { + *output = input_->current().text; + input_->Next(); + return true; + } else { + AddError(error); + return false; + } +} + +bool Parser::ConsumeInteger(int* output, const char* error) { + if (LookingAtType(io::Tokenizer::TYPE_INTEGER)) { + uint64 value = 0; + if (!io::Tokenizer::ParseInteger(input_->current().text, + kint32max, &value)) { + AddError("Integer out of range."); + // We still return true because we did, in fact, parse an integer. + } + *output = value; + input_->Next(); + return true; + } else { + AddError(error); + return false; + } +} + +bool Parser::ConsumeInteger64(uint64 max_value, uint64* output, + const char* error) { + if (LookingAtType(io::Tokenizer::TYPE_INTEGER)) { + if (!io::Tokenizer::ParseInteger(input_->current().text, max_value, + output)) { + AddError("Integer out of range."); + // We still return true because we did, in fact, parse an integer. + *output = 0; + } + input_->Next(); + return true; + } else { + AddError(error); + return false; + } +} + +bool Parser::ConsumeNumber(double* output, const char* error) { + if (LookingAtType(io::Tokenizer::TYPE_FLOAT)) { + *output = io::Tokenizer::ParseFloat(input_->current().text); + input_->Next(); + return true; + } else if (LookingAtType(io::Tokenizer::TYPE_INTEGER)) { + // Also accept integers. + uint64 value = 0; + if (!io::Tokenizer::ParseInteger(input_->current().text, + kuint64max, &value)) { + AddError("Integer out of range."); + // We still return true because we did, in fact, parse a number. + } + *output = value; + input_->Next(); + return true; + } else if (LookingAt("inf")) { + *output = numeric_limits::infinity(); + input_->Next(); + return true; + } else if (LookingAt("nan")) { + *output = numeric_limits::quiet_NaN(); + input_->Next(); + return true; + } else { + AddError(error); + return false; + } +} + +bool Parser::ConsumeString(string* output, const char* error) { + if (LookingAtType(io::Tokenizer::TYPE_STRING)) { + io::Tokenizer::ParseString(input_->current().text, output); + input_->Next(); + // Allow C++ like concatenation of adjacent string tokens. + while (LookingAtType(io::Tokenizer::TYPE_STRING)) { + io::Tokenizer::ParseStringAppend(input_->current().text, output); + input_->Next(); + } + return true; + } else { + AddError(error); + return false; + } +} + +// ------------------------------------------------------------------- + +void Parser::AddError(int line, int column, const string& error) { + if (error_collector_ != NULL) { + error_collector_->AddError(line, column, error); + } + had_errors_ = true; +} + +void Parser::AddError(const string& error) { + AddError(input_->current().line, input_->current().column, error); +} + +// ------------------------------------------------------------------- + +Parser::LocationRecorder::LocationRecorder(Parser* parser) + : parser_(parser), + location_(parser_->source_code_info_->add_location()) { + location_->add_span(parser_->input_->current().line); + location_->add_span(parser_->input_->current().column); +} + +Parser::LocationRecorder::LocationRecorder(const LocationRecorder& parent) { + Init(parent); +} + +Parser::LocationRecorder::LocationRecorder(const LocationRecorder& parent, + int path1) { + Init(parent); + AddPath(path1); +} + +Parser::LocationRecorder::LocationRecorder(const LocationRecorder& parent, + int path1, int path2) { + Init(parent); + AddPath(path1); + AddPath(path2); +} + +void Parser::LocationRecorder::Init(const LocationRecorder& parent) { + parser_ = parent.parser_; + location_ = parser_->source_code_info_->add_location(); + location_->mutable_path()->CopyFrom(parent.location_->path()); + + location_->add_span(parser_->input_->current().line); + location_->add_span(parser_->input_->current().column); +} + +Parser::LocationRecorder::~LocationRecorder() { + if (location_->span_size() <= 2) { + EndAt(parser_->input_->previous()); + } +} + +void Parser::LocationRecorder::AddPath(int path_component) { + location_->add_path(path_component); +} + +void Parser::LocationRecorder::StartAt(const io::Tokenizer::Token& token) { + location_->set_span(0, token.line); + location_->set_span(1, token.column); +} + +void Parser::LocationRecorder::EndAt(const io::Tokenizer::Token& token) { + if (token.line != location_->span(0)) { + location_->add_span(token.line); + } + location_->add_span(token.end_column); +} + +void Parser::LocationRecorder::RecordLegacyLocation(const Message* descriptor, + DescriptorPool::ErrorCollector::ErrorLocation location) { + if (parser_->source_location_table_ != NULL) { + parser_->source_location_table_->Add( + descriptor, location, location_->span(0), location_->span(1)); + } +} + +// ------------------------------------------------------------------- + +void Parser::SkipStatement() { + while (true) { + if (AtEnd()) { + return; + } else if (LookingAtType(io::Tokenizer::TYPE_SYMBOL)) { + if (TryConsume(";")) { + return; + } else if (TryConsume("{")) { + SkipRestOfBlock(); + return; + } else if (LookingAt("}")) { + return; + } + } + input_->Next(); + } +} + +void Parser::SkipRestOfBlock() { + while (true) { + if (AtEnd()) { + return; + } else if (LookingAtType(io::Tokenizer::TYPE_SYMBOL)) { + if (TryConsume("}")) { + return; + } else if (TryConsume("{")) { + SkipRestOfBlock(); + } + } + input_->Next(); + } +} + +// =================================================================== + +bool Parser::Parse(io::Tokenizer* input, FileDescriptorProto* file) { + input_ = input; + had_errors_ = false; + syntax_identifier_.clear(); + + // Note that |file| could be NULL at this point if + // stop_after_syntax_identifier_ is true. So, we conservatively allocate + // SourceCodeInfo on the stack, then swap it into the FileDescriptorProto + // later on. + SourceCodeInfo source_code_info; + source_code_info_ = &source_code_info; + + if (LookingAtType(io::Tokenizer::TYPE_START)) { + // Advance to first token. + input_->Next(); + } + + { + LocationRecorder root_location(this); + + if (require_syntax_identifier_ || LookingAt("syntax")) { + if (!ParseSyntaxIdentifier()) { + // Don't attempt to parse the file if we didn't recognize the syntax + // identifier. + return false; + } + } else if (!stop_after_syntax_identifier_) { + syntax_identifier_ = "proto2"; + } + + if (stop_after_syntax_identifier_) return !had_errors_; + + // Repeatedly parse statements until we reach the end of the file. + while (!AtEnd()) { + if (!ParseTopLevelStatement(file, root_location)) { + // This statement failed to parse. Skip it, but keep looping to parse + // other statements. + SkipStatement(); + + if (LookingAt("}")) { + AddError("Unmatched \"}\"."); + input_->Next(); + } + } + } + } + + input_ = NULL; + source_code_info_ = NULL; + source_code_info.Swap(file->mutable_source_code_info()); + return !had_errors_; +} + +bool Parser::ParseSyntaxIdentifier() { + DO(Consume("syntax", "File must begin with 'syntax = \"proto2\";'.")); + DO(Consume("=")); + io::Tokenizer::Token syntax_token = input_->current(); + string syntax; + DO(ConsumeString(&syntax, "Expected syntax identifier.")); + DO(Consume(";")); + + syntax_identifier_ = syntax; + + if (syntax != "proto2" && !stop_after_syntax_identifier_) { + AddError(syntax_token.line, syntax_token.column, + "Unrecognized syntax identifier \"" + syntax + "\". This parser " + "only recognizes \"proto2\"."); + return false; + } + + return true; +} + +bool Parser::ParseTopLevelStatement(FileDescriptorProto* file, + const LocationRecorder& root_location) { + if (TryConsume(";")) { + // empty statement; ignore + return true; + } else if (LookingAt("message")) { + LocationRecorder location(root_location, + FileDescriptorProto::kMessageTypeFieldNumber, file->message_type_size()); + return ParseMessageDefinition(file->add_message_type(), location); + } else if (LookingAt("enum")) { + LocationRecorder location(root_location, + FileDescriptorProto::kEnumTypeFieldNumber, file->enum_type_size()); + return ParseEnumDefinition(file->add_enum_type(), location); + } else if (LookingAt("service")) { + LocationRecorder location(root_location, + FileDescriptorProto::kServiceFieldNumber, file->service_size()); + return ParseServiceDefinition(file->add_service(), location); + } else if (LookingAt("extend")) { + LocationRecorder location(root_location, + FileDescriptorProto::kExtensionFieldNumber); + return ParseExtend(file->mutable_extension(), + file->mutable_message_type(), + root_location, + FileDescriptorProto::kMessageTypeFieldNumber, + location); + } else if (LookingAt("import")) { + int index = file->dependency_size(); + return ParseImport(file->add_dependency(), root_location, index); + } else if (LookingAt("package")) { + return ParsePackage(file, root_location); + } else if (LookingAt("option")) { + LocationRecorder location(root_location, + FileDescriptorProto::kOptionsFieldNumber); + return ParseOption(file->mutable_options(), location); + } else { + AddError("Expected top-level statement (e.g. \"message\")."); + return false; + } +} + +// ------------------------------------------------------------------- +// Messages + +bool Parser::ParseMessageDefinition(DescriptorProto* message, + const LocationRecorder& message_location) { + DO(Consume("message")); + { + LocationRecorder location(message_location, + DescriptorProto::kNameFieldNumber); + location.RecordLegacyLocation( + message, DescriptorPool::ErrorCollector::NAME); + DO(ConsumeIdentifier(message->mutable_name(), "Expected message name.")); + } + DO(ParseMessageBlock(message, message_location)); + return true; +} + +bool Parser::ParseMessageBlock(DescriptorProto* message, + const LocationRecorder& message_location) { + DO(Consume("{")); + + while (!TryConsume("}")) { + if (AtEnd()) { + AddError("Reached end of input in message definition (missing '}')."); + return false; + } + + if (!ParseMessageStatement(message, message_location)) { + // This statement failed to parse. Skip it, but keep looping to parse + // other statements. + SkipStatement(); + } + } + + return true; +} + +bool Parser::ParseMessageStatement(DescriptorProto* message, + const LocationRecorder& message_location) { + if (TryConsume(";")) { + // empty statement; ignore + return true; + } else if (LookingAt("message")) { + LocationRecorder location(message_location, + DescriptorProto::kNestedTypeFieldNumber, + message->nested_type_size()); + return ParseMessageDefinition(message->add_nested_type(), location); + } else if (LookingAt("enum")) { + LocationRecorder location(message_location, + DescriptorProto::kEnumTypeFieldNumber, + message->enum_type_size()); + return ParseEnumDefinition(message->add_enum_type(), location); + } else if (LookingAt("extensions")) { + LocationRecorder location(message_location, + DescriptorProto::kExtensionRangeFieldNumber); + return ParseExtensions(message, location); + } else if (LookingAt("extend")) { + LocationRecorder location(message_location, + DescriptorProto::kExtensionFieldNumber); + return ParseExtend(message->mutable_extension(), + message->mutable_nested_type(), + message_location, + DescriptorProto::kNestedTypeFieldNumber, + location); + } else if (LookingAt("option")) { + LocationRecorder location(message_location, + DescriptorProto::kOptionsFieldNumber); + return ParseOption(message->mutable_options(), location); + } else { + LocationRecorder location(message_location, + DescriptorProto::kFieldFieldNumber, + message->field_size()); + return ParseMessageField(message->add_field(), + message->mutable_nested_type(), + message_location, + DescriptorProto::kNestedTypeFieldNumber, + location); + } +} + +bool Parser::ParseMessageField(FieldDescriptorProto* field, + RepeatedPtrField* messages, + const LocationRecorder& parent_location, + int location_field_number_for_nested_type, + const LocationRecorder& field_location) { + // Parse label and type. + io::Tokenizer::Token label_token = input_->current(); + { + LocationRecorder location(field_location, + FieldDescriptorProto::kLabelFieldNumber); + FieldDescriptorProto::Label label; + DO(ParseLabel(&label)); + field->set_label(label); + } + + { + LocationRecorder location(field_location); // add path later + location.RecordLegacyLocation(field, DescriptorPool::ErrorCollector::TYPE); + + FieldDescriptorProto::Type type = FieldDescriptorProto::TYPE_INT32; + string type_name; + DO(ParseType(&type, &type_name)); + if (type_name.empty()) { + location.AddPath(FieldDescriptorProto::kTypeFieldNumber); + field->set_type(type); + } else { + location.AddPath(FieldDescriptorProto::kTypeNameFieldNumber); + field->set_type_name(type_name); + } + } + + // Parse name and '='. + io::Tokenizer::Token name_token = input_->current(); + { + LocationRecorder location(field_location, + FieldDescriptorProto::kNameFieldNumber); + location.RecordLegacyLocation(field, DescriptorPool::ErrorCollector::NAME); + DO(ConsumeIdentifier(field->mutable_name(), "Expected field name.")); + } + DO(Consume("=", "Missing field number.")); + + // Parse field number. + { + LocationRecorder location(field_location, + FieldDescriptorProto::kNumberFieldNumber); + location.RecordLegacyLocation( + field, DescriptorPool::ErrorCollector::NUMBER); + int number; + DO(ConsumeInteger(&number, "Expected field number.")); + field->set_number(number); + } + + // Parse options. + DO(ParseFieldOptions(field, field_location)); + + // Deal with groups. + if (field->has_type() && field->type() == FieldDescriptorProto::TYPE_GROUP) { + // Awkward: Since a group declares both a message type and a field, we + // have to create overlapping locations. + LocationRecorder group_location(parent_location); + group_location.StartAt(label_token); + group_location.AddPath(location_field_number_for_nested_type); + group_location.AddPath(messages->size()); + + DescriptorProto* group = messages->Add(); + group->set_name(field->name()); + + // Record name location to match the field name's location. + { + LocationRecorder location(group_location, + DescriptorProto::kNameFieldNumber); + location.StartAt(name_token); + location.EndAt(name_token); + location.RecordLegacyLocation( + group, DescriptorPool::ErrorCollector::NAME); + } + + // The field's type_name also comes from the name. Confusing! + { + LocationRecorder location(field_location, + FieldDescriptorProto::kTypeNameFieldNumber); + location.StartAt(name_token); + location.EndAt(name_token); + } + + // As a hack for backwards-compatibility, we force the group name to start + // with a capital letter and lower-case the field name. New code should + // not use groups; it should use nested messages. + if (group->name()[0] < 'A' || 'Z' < group->name()[0]) { + AddError(name_token.line, name_token.column, + "Group names must start with a capital letter."); + } + LowerString(field->mutable_name()); + + field->set_type_name(group->name()); + if (LookingAt("{")) { + DO(ParseMessageBlock(group, group_location)); + } else { + AddError("Missing group body."); + return false; + } + } else { + DO(Consume(";")); + } + + return true; +} + +bool Parser::ParseFieldOptions(FieldDescriptorProto* field, + const LocationRecorder& field_location) { + if (!LookingAt("[")) return true; + + LocationRecorder location(field_location, + FieldDescriptorProto::kOptionsFieldNumber); + + DO(Consume("[")); + + // Parse field options. + do { + if (LookingAt("default")) { + // We intentionally pass field_location rather than location here, since + // the default value is not actually an option. + DO(ParseDefaultAssignment(field, field_location)); + } else { + DO(ParseOptionAssignment(field->mutable_options(), location)); + } + } while (TryConsume(",")); + + DO(Consume("]")); + return true; +} + +bool Parser::ParseDefaultAssignment(FieldDescriptorProto* field, + const LocationRecorder& field_location) { + if (field->has_default_value()) { + AddError("Already set option \"default\"."); + field->clear_default_value(); + } + + DO(Consume("default")); + DO(Consume("=")); + + LocationRecorder location(field_location, + FieldDescriptorProto::kDefaultValueFieldNumber); + location.RecordLegacyLocation( + field, DescriptorPool::ErrorCollector::DEFAULT_VALUE); + string* default_value = field->mutable_default_value(); + + if (!field->has_type()) { + // The field has a type name, but we don't know if it is a message or an + // enum yet. Assume an enum for now. + DO(ConsumeIdentifier(default_value, "Expected identifier.")); + return true; + } + + switch (field->type()) { + case FieldDescriptorProto::TYPE_INT32: + case FieldDescriptorProto::TYPE_INT64: + case FieldDescriptorProto::TYPE_SINT32: + case FieldDescriptorProto::TYPE_SINT64: + case FieldDescriptorProto::TYPE_SFIXED32: + case FieldDescriptorProto::TYPE_SFIXED64: { + uint64 max_value = kint64max; + if (field->type() == FieldDescriptorProto::TYPE_INT32 || + field->type() == FieldDescriptorProto::TYPE_SINT32 || + field->type() == FieldDescriptorProto::TYPE_SFIXED32) { + max_value = kint32max; + } + + // These types can be negative. + if (TryConsume("-")) { + default_value->append("-"); + // Two's complement always has one more negative value than positive. + ++max_value; + } + // Parse the integer to verify that it is not out-of-range. + uint64 value; + DO(ConsumeInteger64(max_value, &value, "Expected integer.")); + // And stringify it again. + default_value->append(SimpleItoa(value)); + break; + } + + case FieldDescriptorProto::TYPE_UINT32: + case FieldDescriptorProto::TYPE_UINT64: + case FieldDescriptorProto::TYPE_FIXED32: + case FieldDescriptorProto::TYPE_FIXED64: { + uint64 max_value = kuint64max; + if (field->type() == FieldDescriptorProto::TYPE_UINT32 || + field->type() == FieldDescriptorProto::TYPE_FIXED32) { + max_value = kuint32max; + } + + // Numeric, not negative. + if (TryConsume("-")) { + AddError("Unsigned field can't have negative default value."); + } + // Parse the integer to verify that it is not out-of-range. + uint64 value; + DO(ConsumeInteger64(max_value, &value, "Expected integer.")); + // And stringify it again. + default_value->append(SimpleItoa(value)); + break; + } + + case FieldDescriptorProto::TYPE_FLOAT: + case FieldDescriptorProto::TYPE_DOUBLE: + // These types can be negative. + if (TryConsume("-")) { + default_value->append("-"); + } + // Parse the integer because we have to convert hex integers to decimal + // floats. + double value; + DO(ConsumeNumber(&value, "Expected number.")); + // And stringify it again. + default_value->append(SimpleDtoa(value)); + break; + + case FieldDescriptorProto::TYPE_BOOL: + if (TryConsume("true")) { + default_value->assign("true"); + } else if (TryConsume("false")) { + default_value->assign("false"); + } else { + AddError("Expected \"true\" or \"false\"."); + return false; + } + break; + + case FieldDescriptorProto::TYPE_STRING: + DO(ConsumeString(default_value, "Expected string.")); + break; + + case FieldDescriptorProto::TYPE_BYTES: + DO(ConsumeString(default_value, "Expected string.")); + *default_value = CEscape(*default_value); + break; + + case FieldDescriptorProto::TYPE_ENUM: + DO(ConsumeIdentifier(default_value, "Expected identifier.")); + break; + + case FieldDescriptorProto::TYPE_MESSAGE: + case FieldDescriptorProto::TYPE_GROUP: + AddError("Messages can't have default values."); + return false; + } + + return true; +} + +bool Parser::ParseOptionNamePart(UninterpretedOption* uninterpreted_option, + const LocationRecorder& part_location) { + UninterpretedOption::NamePart* name = uninterpreted_option->add_name(); + string identifier; // We parse identifiers into this string. + if (LookingAt("(")) { // This is an extension. + DO(Consume("(")); + + { + LocationRecorder location( + part_location, UninterpretedOption::NamePart::kNamePartFieldNumber); + // An extension name consists of dot-separated identifiers, and may begin + // with a dot. + if (LookingAtType(io::Tokenizer::TYPE_IDENTIFIER)) { + DO(ConsumeIdentifier(&identifier, "Expected identifier.")); + name->mutable_name_part()->append(identifier); + } + while (LookingAt(".")) { + DO(Consume(".")); + name->mutable_name_part()->append("."); + DO(ConsumeIdentifier(&identifier, "Expected identifier.")); + name->mutable_name_part()->append(identifier); + } + } + + DO(Consume(")")); + name->set_is_extension(true); + } else { // This is a regular field. + LocationRecorder location( + part_location, UninterpretedOption::NamePart::kNamePartFieldNumber); + DO(ConsumeIdentifier(&identifier, "Expected identifier.")); + name->mutable_name_part()->append(identifier); + name->set_is_extension(false); + } + return true; +} + +bool Parser::ParseUninterpretedBlock(string* value) { + // Note that enclosing braces are not added to *value. + DO(Consume("{")); + int brace_depth = 1; + while (!AtEnd()) { + if (LookingAt("{")) { + brace_depth++; + } else if (LookingAt("}")) { + brace_depth--; + if (brace_depth == 0) { + input_->Next(); + return true; + } + } + // TODO(sanjay): Interpret line/column numbers to preserve formatting + if (!value->empty()) value->push_back(' '); + value->append(input_->current().text); + input_->Next(); + } + AddError("Unexpected end of stream while parsing aggregate value."); + return false; +} + +// We don't interpret the option here. Instead we store it in an +// UninterpretedOption, to be interpreted later. +bool Parser::ParseOptionAssignment(Message* options, + const LocationRecorder& options_location) { + // Create an entry in the uninterpreted_option field. + const FieldDescriptor* uninterpreted_option_field = options->GetDescriptor()-> + FindFieldByName("uninterpreted_option"); + GOOGLE_CHECK(uninterpreted_option_field != NULL) + << "No field named \"uninterpreted_option\" in the Options proto."; + + const Reflection* reflection = options->GetReflection(); + + LocationRecorder location( + options_location, uninterpreted_option_field->number(), + reflection->FieldSize(*options, uninterpreted_option_field)); + + UninterpretedOption* uninterpreted_option = down_cast( + options->GetReflection()->AddMessage(options, + uninterpreted_option_field)); + + // Parse dot-separated name. + { + LocationRecorder name_location(location, + UninterpretedOption::kNameFieldNumber); + name_location.RecordLegacyLocation( + uninterpreted_option, DescriptorPool::ErrorCollector::OPTION_NAME); + + { + LocationRecorder part_location(name_location, + uninterpreted_option->name_size()); + DO(ParseOptionNamePart(uninterpreted_option, part_location)); + } + + while (LookingAt(".")) { + DO(Consume(".")); + LocationRecorder part_location(name_location, + uninterpreted_option->name_size()); + DO(ParseOptionNamePart(uninterpreted_option, part_location)); + } + } + + DO(Consume("=")); + + LocationRecorder value_location(location); + value_location.RecordLegacyLocation( + uninterpreted_option, DescriptorPool::ErrorCollector::OPTION_VALUE); + + // All values are a single token, except for negative numbers, which consist + // of a single '-' symbol, followed by a positive number. + bool is_negative = TryConsume("-"); + + switch (input_->current().type) { + case io::Tokenizer::TYPE_START: + GOOGLE_LOG(FATAL) << "Trying to read value before any tokens have been read."; + return false; + + case io::Tokenizer::TYPE_END: + AddError("Unexpected end of stream while parsing option value."); + return false; + + case io::Tokenizer::TYPE_IDENTIFIER: { + value_location.AddPath(UninterpretedOption::kIdentifierValueFieldNumber); + if (is_negative) { + AddError("Invalid '-' symbol before identifier."); + return false; + } + string value; + DO(ConsumeIdentifier(&value, "Expected identifier.")); + uninterpreted_option->set_identifier_value(value); + break; + } + + case io::Tokenizer::TYPE_INTEGER: { + uint64 value; + uint64 max_value = + is_negative ? static_cast(kint64max) + 1 : kuint64max; + DO(ConsumeInteger64(max_value, &value, "Expected integer.")); + if (is_negative) { + value_location.AddPath( + UninterpretedOption::kNegativeIntValueFieldNumber); + uninterpreted_option->set_negative_int_value(-static_cast(value)); + } else { + value_location.AddPath( + UninterpretedOption::kPositiveIntValueFieldNumber); + uninterpreted_option->set_positive_int_value(value); + } + break; + } + + case io::Tokenizer::TYPE_FLOAT: { + value_location.AddPath(UninterpretedOption::kDoubleValueFieldNumber); + double value; + DO(ConsumeNumber(&value, "Expected number.")); + uninterpreted_option->set_double_value(is_negative ? -value : value); + break; + } + + case io::Tokenizer::TYPE_STRING: { + value_location.AddPath(UninterpretedOption::kStringValueFieldNumber); + if (is_negative) { + AddError("Invalid '-' symbol before string."); + return false; + } + string value; + DO(ConsumeString(&value, "Expected string.")); + uninterpreted_option->set_string_value(value); + break; + } + + case io::Tokenizer::TYPE_SYMBOL: + if (LookingAt("{")) { + value_location.AddPath(UninterpretedOption::kAggregateValueFieldNumber); + DO(ParseUninterpretedBlock( + uninterpreted_option->mutable_aggregate_value())); + } else { + AddError("Expected option value."); + return false; + } + break; + } + + return true; +} + +bool Parser::ParseExtensions(DescriptorProto* message, + const LocationRecorder& extensions_location) { + // Parse the declaration. + DO(Consume("extensions")); + + do { + // Note that kExtensionRangeFieldNumber was already pushed by the parent. + LocationRecorder location(extensions_location, + message->extension_range_size()); + + DescriptorProto::ExtensionRange* range = message->add_extension_range(); + location.RecordLegacyLocation( + range, DescriptorPool::ErrorCollector::NUMBER); + + int start, end; + io::Tokenizer::Token start_token; + + { + LocationRecorder start_location( + location, DescriptorProto::ExtensionRange::kStartFieldNumber); + start_token = input_->current(); + DO(ConsumeInteger(&start, "Expected field number range.")); + } + + if (TryConsume("to")) { + LocationRecorder end_location( + location, DescriptorProto::ExtensionRange::kEndFieldNumber); + if (TryConsume("max")) { + end = FieldDescriptor::kMaxNumber; + } else { + DO(ConsumeInteger(&end, "Expected integer.")); + } + } else { + LocationRecorder end_location( + location, DescriptorProto::ExtensionRange::kEndFieldNumber); + end_location.StartAt(start_token); + end_location.EndAt(start_token); + end = start; + } + + // Users like to specify inclusive ranges, but in code we like the end + // number to be exclusive. + ++end; + + range->set_start(start); + range->set_end(end); + } while (TryConsume(",")); + + DO(Consume(";")); + return true; +} + +bool Parser::ParseExtend(RepeatedPtrField* extensions, + RepeatedPtrField* messages, + const LocationRecorder& parent_location, + int location_field_number_for_nested_type, + const LocationRecorder& extend_location) { + DO(Consume("extend")); + + // Parse the extendee type. + io::Tokenizer::Token extendee_start = input_->current(); + string extendee; + DO(ParseUserDefinedType(&extendee)); + io::Tokenizer::Token extendee_end = input_->previous(); + + // Parse the block. + DO(Consume("{")); + + bool is_first = true; + + do { + if (AtEnd()) { + AddError("Reached end of input in extend definition (missing '}')."); + return false; + } + + // Note that kExtensionFieldNumber was already pushed by the parent. + LocationRecorder location(extend_location, extensions->size()); + + FieldDescriptorProto* field = extensions->Add(); + + { + LocationRecorder extendee_location( + location, FieldDescriptorProto::kExtendeeFieldNumber); + extendee_location.StartAt(extendee_start); + extendee_location.EndAt(extendee_end); + + if (is_first) { + extendee_location.RecordLegacyLocation( + field, DescriptorPool::ErrorCollector::EXTENDEE); + is_first = false; + } + } + + field->set_extendee(extendee); + + if (!ParseMessageField(field, messages, parent_location, + location_field_number_for_nested_type, + location)) { + // This statement failed to parse. Skip it, but keep looping to parse + // other statements. + SkipStatement(); + } + } while(!TryConsume("}")); + + return true; +} + +// ------------------------------------------------------------------- +// Enums + +bool Parser::ParseEnumDefinition(EnumDescriptorProto* enum_type, + const LocationRecorder& enum_location) { + DO(Consume("enum")); + + { + LocationRecorder location(enum_location, + EnumDescriptorProto::kNameFieldNumber); + location.RecordLegacyLocation( + enum_type, DescriptorPool::ErrorCollector::NAME); + DO(ConsumeIdentifier(enum_type->mutable_name(), "Expected enum name.")); + } + + DO(ParseEnumBlock(enum_type, enum_location)); + return true; +} + +bool Parser::ParseEnumBlock(EnumDescriptorProto* enum_type, + const LocationRecorder& enum_location) { + DO(Consume("{")); + + while (!TryConsume("}")) { + if (AtEnd()) { + AddError("Reached end of input in enum definition (missing '}')."); + return false; + } + + if (!ParseEnumStatement(enum_type, enum_location)) { + // This statement failed to parse. Skip it, but keep looping to parse + // other statements. + SkipStatement(); + } + } + + return true; +} + +bool Parser::ParseEnumStatement(EnumDescriptorProto* enum_type, + const LocationRecorder& enum_location) { + if (TryConsume(";")) { + // empty statement; ignore + return true; + } else if (LookingAt("option")) { + LocationRecorder location(enum_location, + EnumDescriptorProto::kOptionsFieldNumber); + return ParseOption(enum_type->mutable_options(), location); + } else { + LocationRecorder location(enum_location, + EnumDescriptorProto::kValueFieldNumber, enum_type->value_size()); + return ParseEnumConstant(enum_type->add_value(), location); + } +} + +bool Parser::ParseEnumConstant(EnumValueDescriptorProto* enum_value, + const LocationRecorder& enum_value_location) { + // Parse name. + { + LocationRecorder location(enum_value_location, + EnumValueDescriptorProto::kNameFieldNumber); + location.RecordLegacyLocation( + enum_value, DescriptorPool::ErrorCollector::NAME); + DO(ConsumeIdentifier(enum_value->mutable_name(), + "Expected enum constant name.")); + } + + DO(Consume("=", "Missing numeric value for enum constant.")); + + // Parse value. + { + LocationRecorder location( + enum_value_location, EnumValueDescriptorProto::kNumberFieldNumber); + location.RecordLegacyLocation( + enum_value, DescriptorPool::ErrorCollector::NUMBER); + + bool is_negative = TryConsume("-"); + int number; + DO(ConsumeInteger(&number, "Expected integer.")); + if (is_negative) number *= -1; + enum_value->set_number(number); + } + + DO(ParseEnumConstantOptions(enum_value, enum_value_location)); + + DO(Consume(";")); + + return true; +} + +bool Parser::ParseEnumConstantOptions( + EnumValueDescriptorProto* value, + const LocationRecorder& enum_value_location) { + if (!LookingAt("[")) return true; + + LocationRecorder location( + enum_value_location, EnumValueDescriptorProto::kOptionsFieldNumber); + + DO(Consume("[")); + + do { + DO(ParseOptionAssignment(value->mutable_options(), location)); + } while (TryConsume(",")); + + DO(Consume("]")); + return true; +} + +// ------------------------------------------------------------------- +// Services + +bool Parser::ParseServiceDefinition(ServiceDescriptorProto* service, + const LocationRecorder& service_location) { + DO(Consume("service")); + + { + LocationRecorder location(service_location, + ServiceDescriptorProto::kNameFieldNumber); + location.RecordLegacyLocation( + service, DescriptorPool::ErrorCollector::NAME); + DO(ConsumeIdentifier(service->mutable_name(), "Expected service name.")); + } + + DO(ParseServiceBlock(service, service_location)); + return true; +} + +bool Parser::ParseServiceBlock(ServiceDescriptorProto* service, + const LocationRecorder& service_location) { + DO(Consume("{")); + + while (!TryConsume("}")) { + if (AtEnd()) { + AddError("Reached end of input in service definition (missing '}')."); + return false; + } + + if (!ParseServiceStatement(service, service_location)) { + // This statement failed to parse. Skip it, but keep looping to parse + // other statements. + SkipStatement(); + } + } + + return true; +} + +bool Parser::ParseServiceStatement(ServiceDescriptorProto* service, + const LocationRecorder& service_location) { + if (TryConsume(";")) { + // empty statement; ignore + return true; + } else if (LookingAt("option")) { + LocationRecorder location( + service_location, ServiceDescriptorProto::kOptionsFieldNumber); + return ParseOption(service->mutable_options(), location); + } else { + LocationRecorder location(service_location, + ServiceDescriptorProto::kMethodFieldNumber, service->method_size()); + return ParseServiceMethod(service->add_method(), location); + } +} + +bool Parser::ParseServiceMethod(MethodDescriptorProto* method, + const LocationRecorder& method_location) { + DO(Consume("rpc")); + + { + LocationRecorder location(method_location, + MethodDescriptorProto::kNameFieldNumber); + location.RecordLegacyLocation( + method, DescriptorPool::ErrorCollector::NAME); + DO(ConsumeIdentifier(method->mutable_name(), "Expected method name.")); + } + + // Parse input type. + DO(Consume("(")); + { + LocationRecorder location(method_location, + MethodDescriptorProto::kInputTypeFieldNumber); + location.RecordLegacyLocation( + method, DescriptorPool::ErrorCollector::INPUT_TYPE); + DO(ParseUserDefinedType(method->mutable_input_type())); + } + DO(Consume(")")); + + // Parse output type. + DO(Consume("returns")); + DO(Consume("(")); + { + LocationRecorder location(method_location, + MethodDescriptorProto::kOutputTypeFieldNumber); + location.RecordLegacyLocation( + method, DescriptorPool::ErrorCollector::OUTPUT_TYPE); + DO(ParseUserDefinedType(method->mutable_output_type())); + } + DO(Consume(")")); + + if (TryConsume("{")) { + // Options! + while (!TryConsume("}")) { + if (AtEnd()) { + AddError("Reached end of input in method options (missing '}')."); + return false; + } + + if (TryConsume(";")) { + // empty statement; ignore + } else { + LocationRecorder location(method_location, + MethodDescriptorProto::kOptionsFieldNumber); + if (!ParseOption(method->mutable_options(), location)) { + // This statement failed to parse. Skip it, but keep looping to + // parse other statements. + SkipStatement(); + } + } + } + } else { + DO(Consume(";")); + } + + return true; +} + +// ------------------------------------------------------------------- + +bool Parser::ParseLabel(FieldDescriptorProto::Label* label) { + if (TryConsume("optional")) { + *label = FieldDescriptorProto::LABEL_OPTIONAL; + return true; + } else if (TryConsume("repeated")) { + *label = FieldDescriptorProto::LABEL_REPEATED; + return true; + } else if (TryConsume("required")) { + *label = FieldDescriptorProto::LABEL_REQUIRED; + return true; + } else { + AddError("Expected \"required\", \"optional\", or \"repeated\"."); + // We can actually reasonably recover here by just assuming the user + // forgot the label altogether. + *label = FieldDescriptorProto::LABEL_OPTIONAL; + return true; + } +} + +bool Parser::ParseType(FieldDescriptorProto::Type* type, + string* type_name) { + TypeNameMap::const_iterator iter = kTypeNames.find(input_->current().text); + if (iter != kTypeNames.end()) { + *type = iter->second; + input_->Next(); + } else { + DO(ParseUserDefinedType(type_name)); + } + return true; +} + +bool Parser::ParseUserDefinedType(string* type_name) { + type_name->clear(); + + TypeNameMap::const_iterator iter = kTypeNames.find(input_->current().text); + if (iter != kTypeNames.end()) { + // Note: The only place enum types are allowed is for field types, but + // if we are parsing a field type then we would not get here because + // primitives are allowed there as well. So this error message doesn't + // need to account for enums. + AddError("Expected message type."); + + // Pretend to accept this type so that we can go on parsing. + *type_name = input_->current().text; + input_->Next(); + return true; + } + + // A leading "." means the name is fully-qualified. + if (TryConsume(".")) type_name->append("."); + + // Consume the first part of the name. + string identifier; + DO(ConsumeIdentifier(&identifier, "Expected type name.")); + type_name->append(identifier); + + // Consume more parts. + while (TryConsume(".")) { + type_name->append("."); + DO(ConsumeIdentifier(&identifier, "Expected identifier.")); + type_name->append(identifier); + } + + return true; +} + +// =================================================================== + +bool Parser::ParsePackage(FileDescriptorProto* file, + const LocationRecorder& root_location) { + if (file->has_package()) { + AddError("Multiple package definitions."); + // Don't append the new package to the old one. Just replace it. Not + // that it really matters since this is an error anyway. + file->clear_package(); + } + + DO(Consume("package")); + + { + LocationRecorder location(root_location, + FileDescriptorProto::kPackageFieldNumber); + location.RecordLegacyLocation(file, DescriptorPool::ErrorCollector::NAME); + + while (true) { + string identifier; + DO(ConsumeIdentifier(&identifier, "Expected identifier.")); + file->mutable_package()->append(identifier); + if (!TryConsume(".")) break; + file->mutable_package()->append("."); + } + } + + DO(Consume(";")); + return true; +} + +bool Parser::ParseImport(string* import_filename, + const LocationRecorder& root_location, + int index) { + DO(Consume("import")); + { + LocationRecorder location(root_location, + FileDescriptorProto::kDependencyFieldNumber, + index); + DO(ConsumeString(import_filename, + "Expected a string naming the file to import.")); + } + DO(Consume(";")); + return true; +} + +bool Parser::ParseOption(Message* options, + const LocationRecorder& options_location) { + DO(Consume("option")); + DO(ParseOptionAssignment(options, options_location)); + DO(Consume(";")); + return true; +} + +// =================================================================== + +SourceLocationTable::SourceLocationTable() {} +SourceLocationTable::~SourceLocationTable() {} + +bool SourceLocationTable::Find( + const Message* descriptor, + DescriptorPool::ErrorCollector::ErrorLocation location, + int* line, int* column) const { + const pair* result = + FindOrNull(location_map_, make_pair(descriptor, location)); + if (result == NULL) { + *line = -1; + *column = 0; + return false; + } else { + *line = result->first; + *column = result->second; + return true; + } +} + +void SourceLocationTable::Add( + const Message* descriptor, + DescriptorPool::ErrorCollector::ErrorLocation location, + int line, int column) { + location_map_[make_pair(descriptor, location)] = make_pair(line, column); +} + +void SourceLocationTable::Clear() { + location_map_.clear(); +} + +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/depends/protobuf/google/protobuf/compiler/parser.h b/depends/protobuf/google/protobuf/compiler/parser.h new file mode 100644 index 0000000000..4cc90a29af --- /dev/null +++ b/depends/protobuf/google/protobuf/compiler/parser.h @@ -0,0 +1,434 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// Implements parsing of .proto files to FileDescriptorProtos. + +#ifndef GOOGLE_PROTOBUF_COMPILER_PARSER_H__ +#define GOOGLE_PROTOBUF_COMPILER_PARSER_H__ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { class Message; } + +namespace protobuf { +namespace compiler { + +// Defined in this file. +class Parser; +class SourceLocationTable; + +// Implements parsing of protocol definitions (such as .proto files). +// +// Note that most users will be more interested in the Importer class. +// Parser is a lower-level class which simply converts a single .proto file +// to a FileDescriptorProto. It does not resolve import directives or perform +// many other kinds of validation needed to construct a complete +// FileDescriptor. +class LIBPROTOBUF_EXPORT Parser { + public: + Parser(); + ~Parser(); + + // Parse the entire input and construct a FileDescriptorProto representing + // it. Returns true if no errors occurred, false otherwise. + bool Parse(io::Tokenizer* input, FileDescriptorProto* file); + + // Optional fetaures: + + // DEPRECATED: New code should use the SourceCodeInfo embedded in the + // FileDescriptorProto. + // + // Requests that locations of certain definitions be recorded to the given + // SourceLocationTable while parsing. This can be used to look up exact line + // and column numbers for errors reported by DescriptorPool during validation. + // Set to NULL (the default) to discard source location information. + void RecordSourceLocationsTo(SourceLocationTable* location_table) { + source_location_table_ = location_table; + } + + // Requests that errors be recorded to the given ErrorCollector while + // parsing. Set to NULL (the default) to discard error messages. + void RecordErrorsTo(io::ErrorCollector* error_collector) { + error_collector_ = error_collector; + } + + // Returns the identifier used in the "syntax = " declaration, if one was + // seen during the last call to Parse(), or the empty string otherwise. + const string& GetSyntaxIdentifier() { return syntax_identifier_; } + + // If set true, input files will be required to begin with a syntax + // identifier. Otherwise, files may omit this. If a syntax identifier + // is provided, it must be 'syntax = "proto2";' and must appear at the + // top of this file regardless of whether or not it was required. + void SetRequireSyntaxIdentifier(bool value) { + require_syntax_identifier_ = value; + } + + // Call SetStopAfterSyntaxIdentifier(true) to tell the parser to stop + // parsing as soon as it has seen the syntax identifier, or lack thereof. + // This is useful for quickly identifying the syntax of the file without + // parsing the whole thing. If this is enabled, no error will be recorded + // if the syntax identifier is something other than "proto2" (since + // presumably the caller intends to deal with that), but other kinds of + // errors (e.g. parse errors) will still be reported. When this is enabled, + // you may pass a NULL FileDescriptorProto to Parse(). + void SetStopAfterSyntaxIdentifier(bool value) { + stop_after_syntax_identifier_ = value; + } + + private: + // ================================================================= + // Error recovery helpers + + // Consume the rest of the current statement. This consumes tokens + // until it sees one of: + // ';' Consumes the token and returns. + // '{' Consumes the brace then calls SkipRestOfBlock(). + // '}' Returns without consuming. + // EOF Returns (can't consume). + // The Parser often calls SkipStatement() after encountering a syntax + // error. This allows it to go on parsing the following lines, allowing + // it to report more than just one error in the file. + void SkipStatement(); + + // Consume the rest of the current block, including nested blocks, + // ending after the closing '}' is encountered and consumed, or at EOF. + void SkipRestOfBlock(); + + // ----------------------------------------------------------------- + // Single-token consuming helpers + // + // These make parsing code more readable. + + // True if the current token is TYPE_END. + inline bool AtEnd(); + + // True if the next token matches the given text. + inline bool LookingAt(const char* text); + // True if the next token is of the given type. + inline bool LookingAtType(io::Tokenizer::TokenType token_type); + + // If the next token exactly matches the text given, consume it and return + // true. Otherwise, return false without logging an error. + bool TryConsume(const char* text); + + // These attempt to read some kind of token from the input. If successful, + // they return true. Otherwise they return false and add the given error + // to the error list. + + // Consume a token with the exact text given. + bool Consume(const char* text, const char* error); + // Same as above, but automatically generates the error "Expected \"text\".", + // where "text" is the expected token text. + bool Consume(const char* text); + // Consume a token of type IDENTIFIER and store its text in "output". + bool ConsumeIdentifier(string* output, const char* error); + // Consume an integer and store its value in "output". + bool ConsumeInteger(int* output, const char* error); + // Consume a 64-bit integer and store its value in "output". If the value + // is greater than max_value, an error will be reported. + bool ConsumeInteger64(uint64 max_value, uint64* output, const char* error); + // Consume a number and store its value in "output". This will accept + // tokens of either INTEGER or FLOAT type. + bool ConsumeNumber(double* output, const char* error); + // Consume a string literal and store its (unescaped) value in "output". + bool ConsumeString(string* output, const char* error); + + // ----------------------------------------------------------------- + // Error logging helpers + + // Invokes error_collector_->AddError(), if error_collector_ is not NULL. + void AddError(int line, int column, const string& error); + + // Invokes error_collector_->AddError() with the line and column number + // of the current token. + void AddError(const string& error); + + // Records a location in the SourceCodeInfo.location table (see + // descriptor.proto). We use RAII to ensure that the start and end locations + // are recorded -- the constructor records the start location and the + // destructor records the end location. Since the parser is + // recursive-descent, this works out beautifully. + class LIBPROTOBUF_EXPORT LocationRecorder { + public: + // Construct the file's "root" location. + LocationRecorder(Parser* parser); + + // Construct a location that represents a declaration nested within the + // given parent. E.g. a field's location is nested within the location + // for a message type. The parent's path will be copied, so you should + // call AddPath() only to add the path components leading from the parent + // to the child (as opposed to leading from the root to the child). + LocationRecorder(const LocationRecorder& parent); + + // Convenience constructors that call AddPath() one or two times. + LocationRecorder(const LocationRecorder& parent, int path1); + LocationRecorder(const LocationRecorder& parent, int path1, int path2); + + ~LocationRecorder(); + + // Add a path component. See SourceCodeInfo.Location.path in + // descriptor.proto. + void AddPath(int path_component); + + // By default the location is considered to start at the current token at + // the time the LocationRecorder is created. StartAt() sets the start + // location to the given token instead. + void StartAt(const io::Tokenizer::Token& token); + + // By default the location is considered to end at the previous token at + // the time the LocationRecorder is destroyed. EndAt() sets the end + // location to the given token instead. + void EndAt(const io::Tokenizer::Token& token); + + // Records the start point of this location to the SourceLocationTable that + // was passed to RecordSourceLocationsTo(), if any. SourceLocationTable + // is an older way of keeping track of source locations which is still + // used in some places. + void RecordLegacyLocation(const Message* descriptor, + DescriptorPool::ErrorCollector::ErrorLocation location); + + private: + Parser* parser_; + SourceCodeInfo::Location* location_; + + void Init(const LocationRecorder& parent); + }; + + // ================================================================= + // Parsers for various language constructs + + // Parses the "syntax = \"proto2\";" line at the top of the file. Returns + // false if it failed to parse or if the syntax identifier was not + // recognized. + bool ParseSyntaxIdentifier(); + + // These methods parse various individual bits of code. They return + // false if they completely fail to parse the construct. In this case, + // it is probably necessary to skip the rest of the statement to recover. + // However, if these methods return true, it does NOT mean that there + // were no errors; only that there were no *syntax* errors. For instance, + // if a service method is defined using proper syntax but uses a primitive + // type as its input or output, ParseMethodField() still returns true + // and only reports the error by calling AddError(). In practice, this + // makes logic much simpler for the caller. + + // Parse a top-level message, enum, service, etc. + bool ParseTopLevelStatement(FileDescriptorProto* file, + const LocationRecorder& root_location); + + // Parse various language high-level language construrcts. + bool ParseMessageDefinition(DescriptorProto* message, + const LocationRecorder& message_location); + bool ParseEnumDefinition(EnumDescriptorProto* enum_type, + const LocationRecorder& enum_location); + bool ParseServiceDefinition(ServiceDescriptorProto* service, + const LocationRecorder& service_location); + bool ParsePackage(FileDescriptorProto* file, + const LocationRecorder& root_location); + bool ParseImport(string* import_filename, + const LocationRecorder& root_location, + int index); + bool ParseOption(Message* options, + const LocationRecorder& options_location); + + // These methods parse the contents of a message, enum, or service type and + // add them to the given object. They consume the entire block including + // the beginning and ending brace. + bool ParseMessageBlock(DescriptorProto* message, + const LocationRecorder& message_location); + bool ParseEnumBlock(EnumDescriptorProto* enum_type, + const LocationRecorder& enum_location); + bool ParseServiceBlock(ServiceDescriptorProto* service, + const LocationRecorder& service_location); + + // Parse one statement within a message, enum, or service block, inclunding + // final semicolon. + bool ParseMessageStatement(DescriptorProto* message, + const LocationRecorder& message_location); + bool ParseEnumStatement(EnumDescriptorProto* message, + const LocationRecorder& enum_location); + bool ParseServiceStatement(ServiceDescriptorProto* message, + const LocationRecorder& service_location); + + // Parse a field of a message. If the field is a group, its type will be + // added to "messages". + // + // parent_location and location_field_number_for_nested_type are needed when + // parsing groups -- we need to generate a nested message type within the + // parent and record its location accordingly. Since the parent could be + // either a FileDescriptorProto or a DescriptorProto, we must pass in the + // correct field number to use. + bool ParseMessageField(FieldDescriptorProto* field, + RepeatedPtrField* messages, + const LocationRecorder& parent_location, + int location_field_number_for_nested_type, + const LocationRecorder& field_location); + + // Parse an "extensions" declaration. + bool ParseExtensions(DescriptorProto* message, + const LocationRecorder& extensions_location); + + // Parse an "extend" declaration. (See also comments for + // ParseMessageField().) + bool ParseExtend(RepeatedPtrField* extensions, + RepeatedPtrField* messages, + const LocationRecorder& parent_location, + int location_field_number_for_nested_type, + const LocationRecorder& extend_location); + + // Parse a single enum value within an enum block. + bool ParseEnumConstant(EnumValueDescriptorProto* enum_value, + const LocationRecorder& enum_value_location); + + // Parse enum constant options, i.e. the list in square brackets at the end + // of the enum constant value definition. + bool ParseEnumConstantOptions(EnumValueDescriptorProto* value, + const LocationRecorder& enum_value_location); + + // Parse a single method within a service definition. + bool ParseServiceMethod(MethodDescriptorProto* method, + const LocationRecorder& method_location); + + // Parse "required", "optional", or "repeated" and fill in "label" + // with the value. + bool ParseLabel(FieldDescriptorProto::Label* label); + + // Parse a type name and fill in "type" (if it is a primitive) or + // "type_name" (if it is not) with the type parsed. + bool ParseType(FieldDescriptorProto::Type* type, + string* type_name); + // Parse a user-defined type and fill in "type_name" with the name. + // If a primitive type is named, it is treated as an error. + bool ParseUserDefinedType(string* type_name); + + // Parses field options, i.e. the stuff in square brackets at the end + // of a field definition. Also parses default value. + bool ParseFieldOptions(FieldDescriptorProto* field, + const LocationRecorder& field_location); + + // Parse the "default" option. This needs special handling because its + // type is the field's type. + bool ParseDefaultAssignment(FieldDescriptorProto* field, + const LocationRecorder& field_location); + + // Parse a single option name/value pair, e.g. "ctype = CORD". The name + // identifies a field of the given Message, and the value of that field + // is set to the parsed value. + bool ParseOptionAssignment(Message* options, + const LocationRecorder& options_location); + + // Parses a single part of a multipart option name. A multipart name consists + // of names separated by dots. Each name is either an identifier or a series + // of identifiers separated by dots and enclosed in parentheses. E.g., + // "foo.(bar.baz).qux". + bool ParseOptionNamePart(UninterpretedOption* uninterpreted_option, + const LocationRecorder& part_location); + + // Parses a string surrounded by balanced braces. Strips off the outer + // braces and stores the enclosed string in *value. + // E.g., + // { foo } *value gets 'foo' + // { foo { bar: box } } *value gets 'foo { bar: box }' + // {} *value gets '' + // + // REQUIRES: LookingAt("{") + // When finished successfully, we are looking at the first token past + // the ending brace. + bool ParseUninterpretedBlock(string* value); + + // ================================================================= + + io::Tokenizer* input_; + io::ErrorCollector* error_collector_; + SourceCodeInfo* source_code_info_; + SourceLocationTable* source_location_table_; // legacy + bool had_errors_; + bool require_syntax_identifier_; + bool stop_after_syntax_identifier_; + string syntax_identifier_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Parser); +}; + +// A table mapping (descriptor, ErrorLocation) pairs -- as reported by +// DescriptorPool when validating descriptors -- to line and column numbers +// within the original source code. +// +// This is semi-obsolete: FileDescriptorProto.source_code_info now contains +// far more complete information about source locations. However, as of this +// writing you still need to use SourceLocationTable when integrating with +// DescriptorPool. +class LIBPROTOBUF_EXPORT SourceLocationTable { + public: + SourceLocationTable(); + ~SourceLocationTable(); + + // Finds the precise location of the given error and fills in *line and + // *column with the line and column numbers. If not found, sets *line to + // -1 and *column to 0 (since line = -1 is used to mean "error has no exact + // location" in the ErrorCollector interface). Returns true if found, false + // otherwise. + bool Find(const Message* descriptor, + DescriptorPool::ErrorCollector::ErrorLocation location, + int* line, int* column) const; + + // Adds a location to the table. + void Add(const Message* descriptor, + DescriptorPool::ErrorCollector::ErrorLocation location, + int line, int column); + + // Clears the contents of the table. + void Clear(); + + private: + typedef map< + pair, + pair > LocationMap; + LocationMap location_map_; +}; + +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_PARSER_H__ diff --git a/depends/protobuf/google/protobuf/compiler/plugin.cc b/depends/protobuf/google/protobuf/compiler/plugin.cc new file mode 100644 index 0000000000..727f942166 --- /dev/null +++ b/depends/protobuf/google/protobuf/compiler/plugin.cc @@ -0,0 +1,163 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) + +#include + +#include +#include + +#ifdef _WIN32 +#include +#include +#ifndef STDIN_FILENO +#define STDIN_FILENO 0 +#endif +#ifndef STDOUT_FILENO +#define STDOUT_FILENO 1 +#endif +#else +#include +#endif + +#include +#include +#include +#include +#include + + +namespace google { +namespace protobuf { +namespace compiler { + +class GeneratorResponseContext : public GeneratorContext { + public: + GeneratorResponseContext(CodeGeneratorResponse* response, + const vector& parsed_files) + : response_(response), + parsed_files_(parsed_files) {} + virtual ~GeneratorResponseContext() {} + + // implements GeneratorContext -------------------------------------- + + virtual io::ZeroCopyOutputStream* Open(const string& filename) { + CodeGeneratorResponse::File* file = response_->add_file(); + file->set_name(filename); + return new io::StringOutputStream(file->mutable_content()); + } + + virtual io::ZeroCopyOutputStream* OpenForInsert( + const string& filename, const string& insertion_point) { + CodeGeneratorResponse::File* file = response_->add_file(); + file->set_name(filename); + file->set_insertion_point(insertion_point); + return new io::StringOutputStream(file->mutable_content()); + } + + void ListParsedFiles(vector* output) { + *output = parsed_files_; + } + + private: + CodeGeneratorResponse* response_; + const vector& parsed_files_; +}; + +int PluginMain(int argc, char* argv[], const CodeGenerator* generator) { + + if (argc > 1) { + cerr << argv[0] << ": Unknown option: " << argv[1] << endl; + return 1; + } + +#ifdef _WIN32 + _setmode(STDIN_FILENO, _O_BINARY); + _setmode(STDOUT_FILENO, _O_BINARY); +#endif + + CodeGeneratorRequest request; + if (!request.ParseFromFileDescriptor(STDIN_FILENO)) { + cerr << argv[0] << ": protoc sent unparseable request to plugin." << endl; + return 1; + } + + DescriptorPool pool; + for (int i = 0; i < request.proto_file_size(); i++) { + const FileDescriptor* file = pool.BuildFile(request.proto_file(i)); + if (file == NULL) { + // BuildFile() already wrote an error message. + return 1; + } + } + + vector parsed_files; + for (int i = 0; i < request.file_to_generate_size(); i++) { + parsed_files.push_back(pool.FindFileByName(request.file_to_generate(i))); + if (parsed_files.back() == NULL) { + cerr << argv[0] << ": protoc asked plugin to generate a file but " + "did not provide a descriptor for the file: " + << request.file_to_generate(i) << endl; + return 1; + } + } + + CodeGeneratorResponse response; + GeneratorResponseContext context(&response, parsed_files); + + for (int i = 0; i < parsed_files.size(); i++) { + const FileDescriptor* file = parsed_files[i]; + + string error; + bool succeeded = generator->Generate( + file, request.parameter(), &context, &error); + + if (!succeeded && error.empty()) { + error = "Code generator returned false but provided no error " + "description."; + } + if (!error.empty()) { + response.set_error(file->name() + ": " + error); + break; + } + } + + if (!response.SerializeToFileDescriptor(STDOUT_FILENO)) { + cerr << argv[0] << ": Error writing to stdout." << endl; + return 1; + } + + return 0; +} + +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/depends/protobuf/google/protobuf/compiler/plugin.h b/depends/protobuf/google/protobuf/compiler/plugin.h new file mode 100644 index 0000000000..64dfb1d2cf --- /dev/null +++ b/depends/protobuf/google/protobuf/compiler/plugin.h @@ -0,0 +1,73 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// +// Front-end for protoc code generator plugins written in C++. +// +// To implement a protoc plugin in C++, simply write an implementation of +// CodeGenerator, then create a main() function like: +// int main(int argc, char* argv[]) { +// MyCodeGenerator generator; +// return google::protobuf::compiler::PluginMain(argc, argv, &generator); +// } +// You must link your plugin against libprotobuf and libprotoc. +// +// To get protoc to use the plugin, do one of the following: +// * Place the plugin binary somewhere in the PATH and give it the name +// "protoc-gen-NAME" (replacing "NAME" with the name of your plugin). If you +// then invoke protoc with the parameter --NAME_out=OUT_DIR (again, replace +// "NAME" with your plugin's name), protoc will invoke your plugin to generate +// the output, which will be placed in OUT_DIR. +// * Place the plugin binary anywhere, with any name, and pass the --plugin +// parameter to protoc to direct it to your plugin like so: +// protoc --plugin=protoc-gen-NAME=path/to/mybinary --NAME_out=OUT_DIR +// On Windows, make sure to include the .exe suffix: +// protoc --plugin=protoc-gen-NAME=path/to/mybinary.exe --NAME_out=OUT_DIR + +#ifndef GOOGLE_PROTOBUF_COMPILER_PLUGIN_H__ +#define GOOGLE_PROTOBUF_COMPILER_PLUGIN_H__ + +#include + +namespace google { +namespace protobuf { +namespace compiler { + +class CodeGenerator; // code_generator.h + +// Implements main() for a protoc plugin exposing the given code generator. +int PluginMain(int argc, char* argv[], const CodeGenerator* generator); + +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_PLUGIN_H__ diff --git a/depends/protobuf/google/protobuf/compiler/plugin.pb.cc b/depends/protobuf/google/protobuf/compiler/plugin.pb.cc new file mode 100644 index 0000000000..ad4b4deb0e --- /dev/null +++ b/depends/protobuf/google/protobuf/compiler/plugin.pb.cc @@ -0,0 +1,1082 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! + +#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION +#include "google/protobuf/compiler/plugin.pb.h" + +#include + +#include +#include +#include +#include +#include +#include +// @@protoc_insertion_point(includes) + +namespace google { +namespace protobuf { +namespace compiler { + +namespace { + +const ::google::protobuf::Descriptor* CodeGeneratorRequest_descriptor_ = NULL; +const ::google::protobuf::internal::GeneratedMessageReflection* + CodeGeneratorRequest_reflection_ = NULL; +const ::google::protobuf::Descriptor* CodeGeneratorResponse_descriptor_ = NULL; +const ::google::protobuf::internal::GeneratedMessageReflection* + CodeGeneratorResponse_reflection_ = NULL; +const ::google::protobuf::Descriptor* CodeGeneratorResponse_File_descriptor_ = NULL; +const ::google::protobuf::internal::GeneratedMessageReflection* + CodeGeneratorResponse_File_reflection_ = NULL; + +} // namespace + + +void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto() { + protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); + const ::google::protobuf::FileDescriptor* file = + ::google::protobuf::DescriptorPool::generated_pool()->FindFileByName( + "google/protobuf/compiler/plugin.proto"); + GOOGLE_CHECK(file != NULL); + CodeGeneratorRequest_descriptor_ = file->message_type(0); + static const int CodeGeneratorRequest_offsets_[3] = { + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorRequest, file_to_generate_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorRequest, parameter_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorRequest, proto_file_), + }; + CodeGeneratorRequest_reflection_ = + new ::google::protobuf::internal::GeneratedMessageReflection( + CodeGeneratorRequest_descriptor_, + CodeGeneratorRequest::default_instance_, + CodeGeneratorRequest_offsets_, + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorRequest, _has_bits_[0]), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorRequest, _unknown_fields_), + -1, + ::google::protobuf::DescriptorPool::generated_pool(), + ::google::protobuf::MessageFactory::generated_factory(), + sizeof(CodeGeneratorRequest)); + CodeGeneratorResponse_descriptor_ = file->message_type(1); + static const int CodeGeneratorResponse_offsets_[2] = { + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse, error_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse, file_), + }; + CodeGeneratorResponse_reflection_ = + new ::google::protobuf::internal::GeneratedMessageReflection( + CodeGeneratorResponse_descriptor_, + CodeGeneratorResponse::default_instance_, + CodeGeneratorResponse_offsets_, + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse, _has_bits_[0]), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse, _unknown_fields_), + -1, + ::google::protobuf::DescriptorPool::generated_pool(), + ::google::protobuf::MessageFactory::generated_factory(), + sizeof(CodeGeneratorResponse)); + CodeGeneratorResponse_File_descriptor_ = CodeGeneratorResponse_descriptor_->nested_type(0); + static const int CodeGeneratorResponse_File_offsets_[3] = { + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse_File, name_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse_File, insertion_point_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse_File, content_), + }; + CodeGeneratorResponse_File_reflection_ = + new ::google::protobuf::internal::GeneratedMessageReflection( + CodeGeneratorResponse_File_descriptor_, + CodeGeneratorResponse_File::default_instance_, + CodeGeneratorResponse_File_offsets_, + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse_File, _has_bits_[0]), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse_File, _unknown_fields_), + -1, + ::google::protobuf::DescriptorPool::generated_pool(), + ::google::protobuf::MessageFactory::generated_factory(), + sizeof(CodeGeneratorResponse_File)); +} + +namespace { + +GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_); +inline void protobuf_AssignDescriptorsOnce() { + ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_, + &protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto); +} + +void protobuf_RegisterTypes(const ::std::string&) { + protobuf_AssignDescriptorsOnce(); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( + CodeGeneratorRequest_descriptor_, &CodeGeneratorRequest::default_instance()); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( + CodeGeneratorResponse_descriptor_, &CodeGeneratorResponse::default_instance()); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( + CodeGeneratorResponse_File_descriptor_, &CodeGeneratorResponse_File::default_instance()); +} + +} // namespace + +void protobuf_ShutdownFile_google_2fprotobuf_2fcompiler_2fplugin_2eproto() { + delete CodeGeneratorRequest::default_instance_; + delete CodeGeneratorRequest_reflection_; + delete CodeGeneratorResponse::default_instance_; + delete CodeGeneratorResponse_reflection_; + delete CodeGeneratorResponse_File::default_instance_; + delete CodeGeneratorResponse_File_reflection_; +} + +void protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto() { + static bool already_here = false; + if (already_here) return; + already_here = true; + GOOGLE_PROTOBUF_VERIFY_VERSION; + + ::google::protobuf::protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + ::google::protobuf::DescriptorPool::InternalAddGeneratedFile( + "\n%google/protobuf/compiler/plugin.proto\022" + "\030google.protobuf.compiler\032 google/protob" + "uf/descriptor.proto\"}\n\024CodeGeneratorRequ" + "est\022\030\n\020file_to_generate\030\001 \003(\t\022\021\n\tparamet" + "er\030\002 \001(\t\0228\n\nproto_file\030\017 \003(\0132$.google.pr" + "otobuf.FileDescriptorProto\"\252\001\n\025CodeGener" + "atorResponse\022\r\n\005error\030\001 \001(\t\022B\n\004file\030\017 \003(" + "\01324.google.protobuf.compiler.CodeGenerat" + "orResponse.File\032>\n\004File\022\014\n\004name\030\001 \001(\t\022\027\n" + "\017insertion_point\030\002 \001(\t\022\017\n\007content\030\017 \001(\t", 399); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( + "google/protobuf/compiler/plugin.proto", &protobuf_RegisterTypes); + CodeGeneratorRequest::default_instance_ = new CodeGeneratorRequest(); + CodeGeneratorResponse::default_instance_ = new CodeGeneratorResponse(); + CodeGeneratorResponse_File::default_instance_ = new CodeGeneratorResponse_File(); + CodeGeneratorRequest::default_instance_->InitAsDefaultInstance(); + CodeGeneratorResponse::default_instance_->InitAsDefaultInstance(); + CodeGeneratorResponse_File::default_instance_->InitAsDefaultInstance(); + ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_google_2fprotobuf_2fcompiler_2fplugin_2eproto); +} + +// Force AddDescriptors() to be called at static initialization time. +struct StaticDescriptorInitializer_google_2fprotobuf_2fcompiler_2fplugin_2eproto { + StaticDescriptorInitializer_google_2fprotobuf_2fcompiler_2fplugin_2eproto() { + protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); + } +} static_descriptor_initializer_google_2fprotobuf_2fcompiler_2fplugin_2eproto_; + + +// =================================================================== + +#ifndef _MSC_VER +const int CodeGeneratorRequest::kFileToGenerateFieldNumber; +const int CodeGeneratorRequest::kParameterFieldNumber; +const int CodeGeneratorRequest::kProtoFileFieldNumber; +#endif // !_MSC_VER + +CodeGeneratorRequest::CodeGeneratorRequest() + : ::google::protobuf::Message() { + SharedCtor(); +} + +void CodeGeneratorRequest::InitAsDefaultInstance() { +} + +CodeGeneratorRequest::CodeGeneratorRequest(const CodeGeneratorRequest& from) + : ::google::protobuf::Message() { + SharedCtor(); + MergeFrom(from); +} + +void CodeGeneratorRequest::SharedCtor() { + _cached_size_ = 0; + parameter_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + +CodeGeneratorRequest::~CodeGeneratorRequest() { + SharedDtor(); +} + +void CodeGeneratorRequest::SharedDtor() { + if (parameter_ != &::google::protobuf::internal::kEmptyString) { + delete parameter_; + } + if (this != default_instance_) { + } +} + +void CodeGeneratorRequest::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} +const ::google::protobuf::Descriptor* CodeGeneratorRequest::descriptor() { + protobuf_AssignDescriptorsOnce(); + return CodeGeneratorRequest_descriptor_; +} + +const CodeGeneratorRequest& CodeGeneratorRequest::default_instance() { + if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); return *default_instance_; +} + +CodeGeneratorRequest* CodeGeneratorRequest::default_instance_ = NULL; + +CodeGeneratorRequest* CodeGeneratorRequest::New() const { + return new CodeGeneratorRequest; +} + +void CodeGeneratorRequest::Clear() { + if (_has_bits_[1 / 32] & (0xffu << (1 % 32))) { + if (has_parameter()) { + if (parameter_ != &::google::protobuf::internal::kEmptyString) { + parameter_->clear(); + } + } + } + file_to_generate_.Clear(); + proto_file_.Clear(); + ::memset(_has_bits_, 0, sizeof(_has_bits_)); + mutable_unknown_fields()->Clear(); +} + +bool CodeGeneratorRequest::MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input) { +#define DO_(EXPRESSION) if (!(EXPRESSION)) return false + ::google::protobuf::uint32 tag; + while ((tag = input->ReadTag()) != 0) { + switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { + // repeated string file_to_generate = 1; + case 1: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_file_to_generate: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->add_file_to_generate())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->file_to_generate(0).data(), this->file_to_generate(0).length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(10)) goto parse_file_to_generate; + if (input->ExpectTag(18)) goto parse_parameter; + break; + } + + // optional string parameter = 2; + case 2: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_parameter: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_parameter())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->parameter().data(), this->parameter().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(122)) goto parse_proto_file; + break; + } + + // repeated .google.protobuf.FileDescriptorProto proto_file = 15; + case 15: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_proto_file: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_proto_file())); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(122)) goto parse_proto_file; + if (input->ExpectAtEnd()) return true; + break; + } + + default: { + handle_uninterpreted: + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { + return true; + } + DO_(::google::protobuf::internal::WireFormat::SkipField( + input, tag, mutable_unknown_fields())); + break; + } + } + } + return true; +#undef DO_ +} + +void CodeGeneratorRequest::SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const { + // repeated string file_to_generate = 1; + for (int i = 0; i < this->file_to_generate_size(); i++) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->file_to_generate(i).data(), this->file_to_generate(i).length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + ::google::protobuf::internal::WireFormatLite::WriteString( + 1, this->file_to_generate(i), output); + } + + // optional string parameter = 2; + if (has_parameter()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->parameter().data(), this->parameter().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + ::google::protobuf::internal::WireFormatLite::WriteString( + 2, this->parameter(), output); + } + + // repeated .google.protobuf.FileDescriptorProto proto_file = 15; + for (int i = 0; i < this->proto_file_size(); i++) { + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( + 15, this->proto_file(i), output); + } + + if (!unknown_fields().empty()) { + ::google::protobuf::internal::WireFormat::SerializeUnknownFields( + unknown_fields(), output); + } +} + +::google::protobuf::uint8* CodeGeneratorRequest::SerializeWithCachedSizesToArray( + ::google::protobuf::uint8* target) const { + // repeated string file_to_generate = 1; + for (int i = 0; i < this->file_to_generate_size(); i++) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->file_to_generate(i).data(), this->file_to_generate(i).length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + target = ::google::protobuf::internal::WireFormatLite:: + WriteStringToArray(1, this->file_to_generate(i), target); + } + + // optional string parameter = 2; + if (has_parameter()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->parameter().data(), this->parameter().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + target = + ::google::protobuf::internal::WireFormatLite::WriteStringToArray( + 2, this->parameter(), target); + } + + // repeated .google.protobuf.FileDescriptorProto proto_file = 15; + for (int i = 0; i < this->proto_file_size(); i++) { + target = ::google::protobuf::internal::WireFormatLite:: + WriteMessageNoVirtualToArray( + 15, this->proto_file(i), target); + } + + if (!unknown_fields().empty()) { + target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( + unknown_fields(), target); + } + return target; +} + +int CodeGeneratorRequest::ByteSize() const { + int total_size = 0; + + if (_has_bits_[1 / 32] & (0xffu << (1 % 32))) { + // optional string parameter = 2; + if (has_parameter()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::StringSize( + this->parameter()); + } + + } + // repeated string file_to_generate = 1; + total_size += 1 * this->file_to_generate_size(); + for (int i = 0; i < this->file_to_generate_size(); i++) { + total_size += ::google::protobuf::internal::WireFormatLite::StringSize( + this->file_to_generate(i)); + } + + // repeated .google.protobuf.FileDescriptorProto proto_file = 15; + total_size += 1 * this->proto_file_size(); + for (int i = 0; i < this->proto_file_size(); i++) { + total_size += + ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( + this->proto_file(i)); + } + + if (!unknown_fields().empty()) { + total_size += + ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( + unknown_fields()); + } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); + return total_size; +} + +void CodeGeneratorRequest::MergeFrom(const ::google::protobuf::Message& from) { + GOOGLE_CHECK_NE(&from, this); + const CodeGeneratorRequest* source = + ::google::protobuf::internal::dynamic_cast_if_available( + &from); + if (source == NULL) { + ::google::protobuf::internal::ReflectionOps::Merge(from, this); + } else { + MergeFrom(*source); + } +} + +void CodeGeneratorRequest::MergeFrom(const CodeGeneratorRequest& from) { + GOOGLE_CHECK_NE(&from, this); + file_to_generate_.MergeFrom(from.file_to_generate_); + proto_file_.MergeFrom(from.proto_file_); + if (from._has_bits_[1 / 32] & (0xffu << (1 % 32))) { + if (from.has_parameter()) { + set_parameter(from.parameter()); + } + } + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); +} + +void CodeGeneratorRequest::CopyFrom(const ::google::protobuf::Message& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +void CodeGeneratorRequest::CopyFrom(const CodeGeneratorRequest& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool CodeGeneratorRequest::IsInitialized() const { + + for (int i = 0; i < proto_file_size(); i++) { + if (!this->proto_file(i).IsInitialized()) return false; + } + return true; +} + +void CodeGeneratorRequest::Swap(CodeGeneratorRequest* other) { + if (other != this) { + file_to_generate_.Swap(&other->file_to_generate_); + std::swap(parameter_, other->parameter_); + proto_file_.Swap(&other->proto_file_); + std::swap(_has_bits_[0], other->_has_bits_[0]); + _unknown_fields_.Swap(&other->_unknown_fields_); + std::swap(_cached_size_, other->_cached_size_); + } +} + +::google::protobuf::Metadata CodeGeneratorRequest::GetMetadata() const { + protobuf_AssignDescriptorsOnce(); + ::google::protobuf::Metadata metadata; + metadata.descriptor = CodeGeneratorRequest_descriptor_; + metadata.reflection = CodeGeneratorRequest_reflection_; + return metadata; +} + + +// =================================================================== + +#ifndef _MSC_VER +const int CodeGeneratorResponse_File::kNameFieldNumber; +const int CodeGeneratorResponse_File::kInsertionPointFieldNumber; +const int CodeGeneratorResponse_File::kContentFieldNumber; +#endif // !_MSC_VER + +CodeGeneratorResponse_File::CodeGeneratorResponse_File() + : ::google::protobuf::Message() { + SharedCtor(); +} + +void CodeGeneratorResponse_File::InitAsDefaultInstance() { +} + +CodeGeneratorResponse_File::CodeGeneratorResponse_File(const CodeGeneratorResponse_File& from) + : ::google::protobuf::Message() { + SharedCtor(); + MergeFrom(from); +} + +void CodeGeneratorResponse_File::SharedCtor() { + _cached_size_ = 0; + name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + insertion_point_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + content_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + +CodeGeneratorResponse_File::~CodeGeneratorResponse_File() { + SharedDtor(); +} + +void CodeGeneratorResponse_File::SharedDtor() { + if (name_ != &::google::protobuf::internal::kEmptyString) { + delete name_; + } + if (insertion_point_ != &::google::protobuf::internal::kEmptyString) { + delete insertion_point_; + } + if (content_ != &::google::protobuf::internal::kEmptyString) { + delete content_; + } + if (this != default_instance_) { + } +} + +void CodeGeneratorResponse_File::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} +const ::google::protobuf::Descriptor* CodeGeneratorResponse_File::descriptor() { + protobuf_AssignDescriptorsOnce(); + return CodeGeneratorResponse_File_descriptor_; +} + +const CodeGeneratorResponse_File& CodeGeneratorResponse_File::default_instance() { + if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); return *default_instance_; +} + +CodeGeneratorResponse_File* CodeGeneratorResponse_File::default_instance_ = NULL; + +CodeGeneratorResponse_File* CodeGeneratorResponse_File::New() const { + return new CodeGeneratorResponse_File; +} + +void CodeGeneratorResponse_File::Clear() { + if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + if (has_name()) { + if (name_ != &::google::protobuf::internal::kEmptyString) { + name_->clear(); + } + } + if (has_insertion_point()) { + if (insertion_point_ != &::google::protobuf::internal::kEmptyString) { + insertion_point_->clear(); + } + } + if (has_content()) { + if (content_ != &::google::protobuf::internal::kEmptyString) { + content_->clear(); + } + } + } + ::memset(_has_bits_, 0, sizeof(_has_bits_)); + mutable_unknown_fields()->Clear(); +} + +bool CodeGeneratorResponse_File::MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input) { +#define DO_(EXPRESSION) if (!(EXPRESSION)) return false + ::google::protobuf::uint32 tag; + while ((tag = input->ReadTag()) != 0) { + switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { + // optional string name = 1; + case 1: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_name())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(18)) goto parse_insertion_point; + break; + } + + // optional string insertion_point = 2; + case 2: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_insertion_point: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_insertion_point())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->insertion_point().data(), this->insertion_point().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(122)) goto parse_content; + break; + } + + // optional string content = 15; + case 15: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_content: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_content())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->content().data(), this->content().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { + goto handle_uninterpreted; + } + if (input->ExpectAtEnd()) return true; + break; + } + + default: { + handle_uninterpreted: + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { + return true; + } + DO_(::google::protobuf::internal::WireFormat::SkipField( + input, tag, mutable_unknown_fields())); + break; + } + } + } + return true; +#undef DO_ +} + +void CodeGeneratorResponse_File::SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const { + // optional string name = 1; + if (has_name()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + ::google::protobuf::internal::WireFormatLite::WriteString( + 1, this->name(), output); + } + + // optional string insertion_point = 2; + if (has_insertion_point()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->insertion_point().data(), this->insertion_point().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + ::google::protobuf::internal::WireFormatLite::WriteString( + 2, this->insertion_point(), output); + } + + // optional string content = 15; + if (has_content()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->content().data(), this->content().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + ::google::protobuf::internal::WireFormatLite::WriteString( + 15, this->content(), output); + } + + if (!unknown_fields().empty()) { + ::google::protobuf::internal::WireFormat::SerializeUnknownFields( + unknown_fields(), output); + } +} + +::google::protobuf::uint8* CodeGeneratorResponse_File::SerializeWithCachedSizesToArray( + ::google::protobuf::uint8* target) const { + // optional string name = 1; + if (has_name()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + target = + ::google::protobuf::internal::WireFormatLite::WriteStringToArray( + 1, this->name(), target); + } + + // optional string insertion_point = 2; + if (has_insertion_point()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->insertion_point().data(), this->insertion_point().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + target = + ::google::protobuf::internal::WireFormatLite::WriteStringToArray( + 2, this->insertion_point(), target); + } + + // optional string content = 15; + if (has_content()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->content().data(), this->content().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + target = + ::google::protobuf::internal::WireFormatLite::WriteStringToArray( + 15, this->content(), target); + } + + if (!unknown_fields().empty()) { + target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( + unknown_fields(), target); + } + return target; +} + +int CodeGeneratorResponse_File::ByteSize() const { + int total_size = 0; + + if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + // optional string name = 1; + if (has_name()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::StringSize( + this->name()); + } + + // optional string insertion_point = 2; + if (has_insertion_point()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::StringSize( + this->insertion_point()); + } + + // optional string content = 15; + if (has_content()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::StringSize( + this->content()); + } + + } + if (!unknown_fields().empty()) { + total_size += + ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( + unknown_fields()); + } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); + return total_size; +} + +void CodeGeneratorResponse_File::MergeFrom(const ::google::protobuf::Message& from) { + GOOGLE_CHECK_NE(&from, this); + const CodeGeneratorResponse_File* source = + ::google::protobuf::internal::dynamic_cast_if_available( + &from); + if (source == NULL) { + ::google::protobuf::internal::ReflectionOps::Merge(from, this); + } else { + MergeFrom(*source); + } +} + +void CodeGeneratorResponse_File::MergeFrom(const CodeGeneratorResponse_File& from) { + GOOGLE_CHECK_NE(&from, this); + if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { + if (from.has_name()) { + set_name(from.name()); + } + if (from.has_insertion_point()) { + set_insertion_point(from.insertion_point()); + } + if (from.has_content()) { + set_content(from.content()); + } + } + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); +} + +void CodeGeneratorResponse_File::CopyFrom(const ::google::protobuf::Message& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +void CodeGeneratorResponse_File::CopyFrom(const CodeGeneratorResponse_File& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool CodeGeneratorResponse_File::IsInitialized() const { + + return true; +} + +void CodeGeneratorResponse_File::Swap(CodeGeneratorResponse_File* other) { + if (other != this) { + std::swap(name_, other->name_); + std::swap(insertion_point_, other->insertion_point_); + std::swap(content_, other->content_); + std::swap(_has_bits_[0], other->_has_bits_[0]); + _unknown_fields_.Swap(&other->_unknown_fields_); + std::swap(_cached_size_, other->_cached_size_); + } +} + +::google::protobuf::Metadata CodeGeneratorResponse_File::GetMetadata() const { + protobuf_AssignDescriptorsOnce(); + ::google::protobuf::Metadata metadata; + metadata.descriptor = CodeGeneratorResponse_File_descriptor_; + metadata.reflection = CodeGeneratorResponse_File_reflection_; + return metadata; +} + + +// ------------------------------------------------------------------- + +#ifndef _MSC_VER +const int CodeGeneratorResponse::kErrorFieldNumber; +const int CodeGeneratorResponse::kFileFieldNumber; +#endif // !_MSC_VER + +CodeGeneratorResponse::CodeGeneratorResponse() + : ::google::protobuf::Message() { + SharedCtor(); +} + +void CodeGeneratorResponse::InitAsDefaultInstance() { +} + +CodeGeneratorResponse::CodeGeneratorResponse(const CodeGeneratorResponse& from) + : ::google::protobuf::Message() { + SharedCtor(); + MergeFrom(from); +} + +void CodeGeneratorResponse::SharedCtor() { + _cached_size_ = 0; + error_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + +CodeGeneratorResponse::~CodeGeneratorResponse() { + SharedDtor(); +} + +void CodeGeneratorResponse::SharedDtor() { + if (error_ != &::google::protobuf::internal::kEmptyString) { + delete error_; + } + if (this != default_instance_) { + } +} + +void CodeGeneratorResponse::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} +const ::google::protobuf::Descriptor* CodeGeneratorResponse::descriptor() { + protobuf_AssignDescriptorsOnce(); + return CodeGeneratorResponse_descriptor_; +} + +const CodeGeneratorResponse& CodeGeneratorResponse::default_instance() { + if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); return *default_instance_; +} + +CodeGeneratorResponse* CodeGeneratorResponse::default_instance_ = NULL; + +CodeGeneratorResponse* CodeGeneratorResponse::New() const { + return new CodeGeneratorResponse; +} + +void CodeGeneratorResponse::Clear() { + if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + if (has_error()) { + if (error_ != &::google::protobuf::internal::kEmptyString) { + error_->clear(); + } + } + } + file_.Clear(); + ::memset(_has_bits_, 0, sizeof(_has_bits_)); + mutable_unknown_fields()->Clear(); +} + +bool CodeGeneratorResponse::MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input) { +#define DO_(EXPRESSION) if (!(EXPRESSION)) return false + ::google::protobuf::uint32 tag; + while ((tag = input->ReadTag()) != 0) { + switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { + // optional string error = 1; + case 1: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_error())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->error().data(), this->error().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(122)) goto parse_file; + break; + } + + // repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15; + case 15: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_file: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_file())); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(122)) goto parse_file; + if (input->ExpectAtEnd()) return true; + break; + } + + default: { + handle_uninterpreted: + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { + return true; + } + DO_(::google::protobuf::internal::WireFormat::SkipField( + input, tag, mutable_unknown_fields())); + break; + } + } + } + return true; +#undef DO_ +} + +void CodeGeneratorResponse::SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const { + // optional string error = 1; + if (has_error()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->error().data(), this->error().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + ::google::protobuf::internal::WireFormatLite::WriteString( + 1, this->error(), output); + } + + // repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15; + for (int i = 0; i < this->file_size(); i++) { + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( + 15, this->file(i), output); + } + + if (!unknown_fields().empty()) { + ::google::protobuf::internal::WireFormat::SerializeUnknownFields( + unknown_fields(), output); + } +} + +::google::protobuf::uint8* CodeGeneratorResponse::SerializeWithCachedSizesToArray( + ::google::protobuf::uint8* target) const { + // optional string error = 1; + if (has_error()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->error().data(), this->error().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + target = + ::google::protobuf::internal::WireFormatLite::WriteStringToArray( + 1, this->error(), target); + } + + // repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15; + for (int i = 0; i < this->file_size(); i++) { + target = ::google::protobuf::internal::WireFormatLite:: + WriteMessageNoVirtualToArray( + 15, this->file(i), target); + } + + if (!unknown_fields().empty()) { + target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( + unknown_fields(), target); + } + return target; +} + +int CodeGeneratorResponse::ByteSize() const { + int total_size = 0; + + if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + // optional string error = 1; + if (has_error()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::StringSize( + this->error()); + } + + } + // repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15; + total_size += 1 * this->file_size(); + for (int i = 0; i < this->file_size(); i++) { + total_size += + ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( + this->file(i)); + } + + if (!unknown_fields().empty()) { + total_size += + ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( + unknown_fields()); + } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); + return total_size; +} + +void CodeGeneratorResponse::MergeFrom(const ::google::protobuf::Message& from) { + GOOGLE_CHECK_NE(&from, this); + const CodeGeneratorResponse* source = + ::google::protobuf::internal::dynamic_cast_if_available( + &from); + if (source == NULL) { + ::google::protobuf::internal::ReflectionOps::Merge(from, this); + } else { + MergeFrom(*source); + } +} + +void CodeGeneratorResponse::MergeFrom(const CodeGeneratorResponse& from) { + GOOGLE_CHECK_NE(&from, this); + file_.MergeFrom(from.file_); + if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { + if (from.has_error()) { + set_error(from.error()); + } + } + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); +} + +void CodeGeneratorResponse::CopyFrom(const ::google::protobuf::Message& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +void CodeGeneratorResponse::CopyFrom(const CodeGeneratorResponse& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool CodeGeneratorResponse::IsInitialized() const { + + return true; +} + +void CodeGeneratorResponse::Swap(CodeGeneratorResponse* other) { + if (other != this) { + std::swap(error_, other->error_); + file_.Swap(&other->file_); + std::swap(_has_bits_[0], other->_has_bits_[0]); + _unknown_fields_.Swap(&other->_unknown_fields_); + std::swap(_cached_size_, other->_cached_size_); + } +} + +::google::protobuf::Metadata CodeGeneratorResponse::GetMetadata() const { + protobuf_AssignDescriptorsOnce(); + ::google::protobuf::Metadata metadata; + metadata.descriptor = CodeGeneratorResponse_descriptor_; + metadata.reflection = CodeGeneratorResponse_reflection_; + return metadata; +} + + +// @@protoc_insertion_point(namespace_scope) + +} // namespace compiler +} // namespace protobuf +} // namespace google + +// @@protoc_insertion_point(global_scope) diff --git a/depends/protobuf/google/protobuf/compiler/plugin.pb.h b/depends/protobuf/google/protobuf/compiler/plugin.pb.h new file mode 100644 index 0000000000..14216c2a16 --- /dev/null +++ b/depends/protobuf/google/protobuf/compiler/plugin.pb.h @@ -0,0 +1,790 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: google/protobuf/compiler/plugin.proto + +#ifndef PROTOBUF_google_2fprotobuf_2fcompiler_2fplugin_2eproto__INCLUDED +#define PROTOBUF_google_2fprotobuf_2fcompiler_2fplugin_2eproto__INCLUDED + +#include + +#include + +#if GOOGLE_PROTOBUF_VERSION < 2004000 +#error This file was generated by a newer version of protoc which is +#error incompatible with your Protocol Buffer headers. Please update +#error your headers. +#endif +#if 2004001 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION +#error This file was generated by an older version of protoc which is +#error incompatible with your Protocol Buffer headers. Please +#error regenerate this file with a newer version of protoc. +#endif + +#include +#include +#include +#include +#include "google/protobuf/descriptor.pb.h" +// @@protoc_insertion_point(includes) + +namespace google { +namespace protobuf { +namespace compiler { + +// Internal implementation detail -- do not call these. +void LIBPROTOC_EXPORT protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); +void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); +void protobuf_ShutdownFile_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); + +class CodeGeneratorRequest; +class CodeGeneratorResponse; +class CodeGeneratorResponse_File; + +// =================================================================== + +class LIBPROTOC_EXPORT CodeGeneratorRequest : public ::google::protobuf::Message { + public: + CodeGeneratorRequest(); + virtual ~CodeGeneratorRequest(); + + CodeGeneratorRequest(const CodeGeneratorRequest& from); + + inline CodeGeneratorRequest& operator=(const CodeGeneratorRequest& from) { + CopyFrom(from); + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { + return _unknown_fields_; + } + + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { + return &_unknown_fields_; + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const CodeGeneratorRequest& default_instance(); + + void Swap(CodeGeneratorRequest* other); + + // implements Message ---------------------------------------------- + + CodeGeneratorRequest* New() const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const CodeGeneratorRequest& from); + void MergeFrom(const CodeGeneratorRequest& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + // repeated string file_to_generate = 1; + inline int file_to_generate_size() const; + inline void clear_file_to_generate(); + static const int kFileToGenerateFieldNumber = 1; + inline const ::std::string& file_to_generate(int index) const; + inline ::std::string* mutable_file_to_generate(int index); + inline void set_file_to_generate(int index, const ::std::string& value); + inline void set_file_to_generate(int index, const char* value); + inline void set_file_to_generate(int index, const char* value, size_t size); + inline ::std::string* add_file_to_generate(); + inline void add_file_to_generate(const ::std::string& value); + inline void add_file_to_generate(const char* value); + inline void add_file_to_generate(const char* value, size_t size); + inline const ::google::protobuf::RepeatedPtrField< ::std::string>& file_to_generate() const; + inline ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_file_to_generate(); + + // optional string parameter = 2; + inline bool has_parameter() const; + inline void clear_parameter(); + static const int kParameterFieldNumber = 2; + inline const ::std::string& parameter() const; + inline void set_parameter(const ::std::string& value); + inline void set_parameter(const char* value); + inline void set_parameter(const char* value, size_t size); + inline ::std::string* mutable_parameter(); + inline ::std::string* release_parameter(); + + // repeated .google.protobuf.FileDescriptorProto proto_file = 15; + inline int proto_file_size() const; + inline void clear_proto_file(); + static const int kProtoFileFieldNumber = 15; + inline const ::google::protobuf::FileDescriptorProto& proto_file(int index) const; + inline ::google::protobuf::FileDescriptorProto* mutable_proto_file(int index); + inline ::google::protobuf::FileDescriptorProto* add_proto_file(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >& + proto_file() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >* + mutable_proto_file(); + + // @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorRequest) + private: + inline void set_has_parameter(); + inline void clear_has_parameter(); + + ::google::protobuf::UnknownFieldSet _unknown_fields_; + + ::google::protobuf::RepeatedPtrField< ::std::string> file_to_generate_; + ::std::string* parameter_; + ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto > proto_file_; + + mutable int _cached_size_; + ::google::protobuf::uint32 _has_bits_[(3 + 31) / 32]; + + friend void LIBPROTOC_EXPORT protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); + friend void protobuf_ShutdownFile_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); + + void InitAsDefaultInstance(); + static CodeGeneratorRequest* default_instance_; +}; +// ------------------------------------------------------------------- + +class LIBPROTOC_EXPORT CodeGeneratorResponse_File : public ::google::protobuf::Message { + public: + CodeGeneratorResponse_File(); + virtual ~CodeGeneratorResponse_File(); + + CodeGeneratorResponse_File(const CodeGeneratorResponse_File& from); + + inline CodeGeneratorResponse_File& operator=(const CodeGeneratorResponse_File& from) { + CopyFrom(from); + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { + return _unknown_fields_; + } + + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { + return &_unknown_fields_; + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const CodeGeneratorResponse_File& default_instance(); + + void Swap(CodeGeneratorResponse_File* other); + + // implements Message ---------------------------------------------- + + CodeGeneratorResponse_File* New() const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const CodeGeneratorResponse_File& from); + void MergeFrom(const CodeGeneratorResponse_File& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + // optional string name = 1; + inline bool has_name() const; + inline void clear_name(); + static const int kNameFieldNumber = 1; + inline const ::std::string& name() const; + inline void set_name(const ::std::string& value); + inline void set_name(const char* value); + inline void set_name(const char* value, size_t size); + inline ::std::string* mutable_name(); + inline ::std::string* release_name(); + + // optional string insertion_point = 2; + inline bool has_insertion_point() const; + inline void clear_insertion_point(); + static const int kInsertionPointFieldNumber = 2; + inline const ::std::string& insertion_point() const; + inline void set_insertion_point(const ::std::string& value); + inline void set_insertion_point(const char* value); + inline void set_insertion_point(const char* value, size_t size); + inline ::std::string* mutable_insertion_point(); + inline ::std::string* release_insertion_point(); + + // optional string content = 15; + inline bool has_content() const; + inline void clear_content(); + static const int kContentFieldNumber = 15; + inline const ::std::string& content() const; + inline void set_content(const ::std::string& value); + inline void set_content(const char* value); + inline void set_content(const char* value, size_t size); + inline ::std::string* mutable_content(); + inline ::std::string* release_content(); + + // @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorResponse.File) + private: + inline void set_has_name(); + inline void clear_has_name(); + inline void set_has_insertion_point(); + inline void clear_has_insertion_point(); + inline void set_has_content(); + inline void clear_has_content(); + + ::google::protobuf::UnknownFieldSet _unknown_fields_; + + ::std::string* name_; + ::std::string* insertion_point_; + ::std::string* content_; + + mutable int _cached_size_; + ::google::protobuf::uint32 _has_bits_[(3 + 31) / 32]; + + friend void LIBPROTOC_EXPORT protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); + friend void protobuf_ShutdownFile_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); + + void InitAsDefaultInstance(); + static CodeGeneratorResponse_File* default_instance_; +}; +// ------------------------------------------------------------------- + +class LIBPROTOC_EXPORT CodeGeneratorResponse : public ::google::protobuf::Message { + public: + CodeGeneratorResponse(); + virtual ~CodeGeneratorResponse(); + + CodeGeneratorResponse(const CodeGeneratorResponse& from); + + inline CodeGeneratorResponse& operator=(const CodeGeneratorResponse& from) { + CopyFrom(from); + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { + return _unknown_fields_; + } + + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { + return &_unknown_fields_; + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const CodeGeneratorResponse& default_instance(); + + void Swap(CodeGeneratorResponse* other); + + // implements Message ---------------------------------------------- + + CodeGeneratorResponse* New() const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const CodeGeneratorResponse& from); + void MergeFrom(const CodeGeneratorResponse& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + typedef CodeGeneratorResponse_File File; + + // accessors ------------------------------------------------------- + + // optional string error = 1; + inline bool has_error() const; + inline void clear_error(); + static const int kErrorFieldNumber = 1; + inline const ::std::string& error() const; + inline void set_error(const ::std::string& value); + inline void set_error(const char* value); + inline void set_error(const char* value, size_t size); + inline ::std::string* mutable_error(); + inline ::std::string* release_error(); + + // repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15; + inline int file_size() const; + inline void clear_file(); + static const int kFileFieldNumber = 15; + inline const ::google::protobuf::compiler::CodeGeneratorResponse_File& file(int index) const; + inline ::google::protobuf::compiler::CodeGeneratorResponse_File* mutable_file(int index); + inline ::google::protobuf::compiler::CodeGeneratorResponse_File* add_file(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >& + file() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >* + mutable_file(); + + // @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorResponse) + private: + inline void set_has_error(); + inline void clear_has_error(); + + ::google::protobuf::UnknownFieldSet _unknown_fields_; + + ::std::string* error_; + ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File > file_; + + mutable int _cached_size_; + ::google::protobuf::uint32 _has_bits_[(2 + 31) / 32]; + + friend void LIBPROTOC_EXPORT protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); + friend void protobuf_ShutdownFile_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); + + void InitAsDefaultInstance(); + static CodeGeneratorResponse* default_instance_; +}; +// =================================================================== + + +// =================================================================== + +// CodeGeneratorRequest + +// repeated string file_to_generate = 1; +inline int CodeGeneratorRequest::file_to_generate_size() const { + return file_to_generate_.size(); +} +inline void CodeGeneratorRequest::clear_file_to_generate() { + file_to_generate_.Clear(); +} +inline const ::std::string& CodeGeneratorRequest::file_to_generate(int index) const { + return file_to_generate_.Get(index); +} +inline ::std::string* CodeGeneratorRequest::mutable_file_to_generate(int index) { + return file_to_generate_.Mutable(index); +} +inline void CodeGeneratorRequest::set_file_to_generate(int index, const ::std::string& value) { + file_to_generate_.Mutable(index)->assign(value); +} +inline void CodeGeneratorRequest::set_file_to_generate(int index, const char* value) { + file_to_generate_.Mutable(index)->assign(value); +} +inline void CodeGeneratorRequest::set_file_to_generate(int index, const char* value, size_t size) { + file_to_generate_.Mutable(index)->assign( + reinterpret_cast(value), size); +} +inline ::std::string* CodeGeneratorRequest::add_file_to_generate() { + return file_to_generate_.Add(); +} +inline void CodeGeneratorRequest::add_file_to_generate(const ::std::string& value) { + file_to_generate_.Add()->assign(value); +} +inline void CodeGeneratorRequest::add_file_to_generate(const char* value) { + file_to_generate_.Add()->assign(value); +} +inline void CodeGeneratorRequest::add_file_to_generate(const char* value, size_t size) { + file_to_generate_.Add()->assign(reinterpret_cast(value), size); +} +inline const ::google::protobuf::RepeatedPtrField< ::std::string>& +CodeGeneratorRequest::file_to_generate() const { + return file_to_generate_; +} +inline ::google::protobuf::RepeatedPtrField< ::std::string>* +CodeGeneratorRequest::mutable_file_to_generate() { + return &file_to_generate_; +} + +// optional string parameter = 2; +inline bool CodeGeneratorRequest::has_parameter() const { + return (_has_bits_[0] & 0x00000002u) != 0; +} +inline void CodeGeneratorRequest::set_has_parameter() { + _has_bits_[0] |= 0x00000002u; +} +inline void CodeGeneratorRequest::clear_has_parameter() { + _has_bits_[0] &= ~0x00000002u; +} +inline void CodeGeneratorRequest::clear_parameter() { + if (parameter_ != &::google::protobuf::internal::kEmptyString) { + parameter_->clear(); + } + clear_has_parameter(); +} +inline const ::std::string& CodeGeneratorRequest::parameter() const { + return *parameter_; +} +inline void CodeGeneratorRequest::set_parameter(const ::std::string& value) { + set_has_parameter(); + if (parameter_ == &::google::protobuf::internal::kEmptyString) { + parameter_ = new ::std::string; + } + parameter_->assign(value); +} +inline void CodeGeneratorRequest::set_parameter(const char* value) { + set_has_parameter(); + if (parameter_ == &::google::protobuf::internal::kEmptyString) { + parameter_ = new ::std::string; + } + parameter_->assign(value); +} +inline void CodeGeneratorRequest::set_parameter(const char* value, size_t size) { + set_has_parameter(); + if (parameter_ == &::google::protobuf::internal::kEmptyString) { + parameter_ = new ::std::string; + } + parameter_->assign(reinterpret_cast(value), size); +} +inline ::std::string* CodeGeneratorRequest::mutable_parameter() { + set_has_parameter(); + if (parameter_ == &::google::protobuf::internal::kEmptyString) { + parameter_ = new ::std::string; + } + return parameter_; +} +inline ::std::string* CodeGeneratorRequest::release_parameter() { + clear_has_parameter(); + if (parameter_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = parameter_; + parameter_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} + +// repeated .google.protobuf.FileDescriptorProto proto_file = 15; +inline int CodeGeneratorRequest::proto_file_size() const { + return proto_file_.size(); +} +inline void CodeGeneratorRequest::clear_proto_file() { + proto_file_.Clear(); +} +inline const ::google::protobuf::FileDescriptorProto& CodeGeneratorRequest::proto_file(int index) const { + return proto_file_.Get(index); +} +inline ::google::protobuf::FileDescriptorProto* CodeGeneratorRequest::mutable_proto_file(int index) { + return proto_file_.Mutable(index); +} +inline ::google::protobuf::FileDescriptorProto* CodeGeneratorRequest::add_proto_file() { + return proto_file_.Add(); +} +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >& +CodeGeneratorRequest::proto_file() const { + return proto_file_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >* +CodeGeneratorRequest::mutable_proto_file() { + return &proto_file_; +} + +// ------------------------------------------------------------------- + +// CodeGeneratorResponse_File + +// optional string name = 1; +inline bool CodeGeneratorResponse_File::has_name() const { + return (_has_bits_[0] & 0x00000001u) != 0; +} +inline void CodeGeneratorResponse_File::set_has_name() { + _has_bits_[0] |= 0x00000001u; +} +inline void CodeGeneratorResponse_File::clear_has_name() { + _has_bits_[0] &= ~0x00000001u; +} +inline void CodeGeneratorResponse_File::clear_name() { + if (name_ != &::google::protobuf::internal::kEmptyString) { + name_->clear(); + } + clear_has_name(); +} +inline const ::std::string& CodeGeneratorResponse_File::name() const { + return *name_; +} +inline void CodeGeneratorResponse_File::set_name(const ::std::string& value) { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + name_->assign(value); +} +inline void CodeGeneratorResponse_File::set_name(const char* value) { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + name_->assign(value); +} +inline void CodeGeneratorResponse_File::set_name(const char* value, size_t size) { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + name_->assign(reinterpret_cast(value), size); +} +inline ::std::string* CodeGeneratorResponse_File::mutable_name() { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + return name_; +} +inline ::std::string* CodeGeneratorResponse_File::release_name() { + clear_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = name_; + name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} + +// optional string insertion_point = 2; +inline bool CodeGeneratorResponse_File::has_insertion_point() const { + return (_has_bits_[0] & 0x00000002u) != 0; +} +inline void CodeGeneratorResponse_File::set_has_insertion_point() { + _has_bits_[0] |= 0x00000002u; +} +inline void CodeGeneratorResponse_File::clear_has_insertion_point() { + _has_bits_[0] &= ~0x00000002u; +} +inline void CodeGeneratorResponse_File::clear_insertion_point() { + if (insertion_point_ != &::google::protobuf::internal::kEmptyString) { + insertion_point_->clear(); + } + clear_has_insertion_point(); +} +inline const ::std::string& CodeGeneratorResponse_File::insertion_point() const { + return *insertion_point_; +} +inline void CodeGeneratorResponse_File::set_insertion_point(const ::std::string& value) { + set_has_insertion_point(); + if (insertion_point_ == &::google::protobuf::internal::kEmptyString) { + insertion_point_ = new ::std::string; + } + insertion_point_->assign(value); +} +inline void CodeGeneratorResponse_File::set_insertion_point(const char* value) { + set_has_insertion_point(); + if (insertion_point_ == &::google::protobuf::internal::kEmptyString) { + insertion_point_ = new ::std::string; + } + insertion_point_->assign(value); +} +inline void CodeGeneratorResponse_File::set_insertion_point(const char* value, size_t size) { + set_has_insertion_point(); + if (insertion_point_ == &::google::protobuf::internal::kEmptyString) { + insertion_point_ = new ::std::string; + } + insertion_point_->assign(reinterpret_cast(value), size); +} +inline ::std::string* CodeGeneratorResponse_File::mutable_insertion_point() { + set_has_insertion_point(); + if (insertion_point_ == &::google::protobuf::internal::kEmptyString) { + insertion_point_ = new ::std::string; + } + return insertion_point_; +} +inline ::std::string* CodeGeneratorResponse_File::release_insertion_point() { + clear_has_insertion_point(); + if (insertion_point_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = insertion_point_; + insertion_point_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} + +// optional string content = 15; +inline bool CodeGeneratorResponse_File::has_content() const { + return (_has_bits_[0] & 0x00000004u) != 0; +} +inline void CodeGeneratorResponse_File::set_has_content() { + _has_bits_[0] |= 0x00000004u; +} +inline void CodeGeneratorResponse_File::clear_has_content() { + _has_bits_[0] &= ~0x00000004u; +} +inline void CodeGeneratorResponse_File::clear_content() { + if (content_ != &::google::protobuf::internal::kEmptyString) { + content_->clear(); + } + clear_has_content(); +} +inline const ::std::string& CodeGeneratorResponse_File::content() const { + return *content_; +} +inline void CodeGeneratorResponse_File::set_content(const ::std::string& value) { + set_has_content(); + if (content_ == &::google::protobuf::internal::kEmptyString) { + content_ = new ::std::string; + } + content_->assign(value); +} +inline void CodeGeneratorResponse_File::set_content(const char* value) { + set_has_content(); + if (content_ == &::google::protobuf::internal::kEmptyString) { + content_ = new ::std::string; + } + content_->assign(value); +} +inline void CodeGeneratorResponse_File::set_content(const char* value, size_t size) { + set_has_content(); + if (content_ == &::google::protobuf::internal::kEmptyString) { + content_ = new ::std::string; + } + content_->assign(reinterpret_cast(value), size); +} +inline ::std::string* CodeGeneratorResponse_File::mutable_content() { + set_has_content(); + if (content_ == &::google::protobuf::internal::kEmptyString) { + content_ = new ::std::string; + } + return content_; +} +inline ::std::string* CodeGeneratorResponse_File::release_content() { + clear_has_content(); + if (content_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = content_; + content_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} + +// ------------------------------------------------------------------- + +// CodeGeneratorResponse + +// optional string error = 1; +inline bool CodeGeneratorResponse::has_error() const { + return (_has_bits_[0] & 0x00000001u) != 0; +} +inline void CodeGeneratorResponse::set_has_error() { + _has_bits_[0] |= 0x00000001u; +} +inline void CodeGeneratorResponse::clear_has_error() { + _has_bits_[0] &= ~0x00000001u; +} +inline void CodeGeneratorResponse::clear_error() { + if (error_ != &::google::protobuf::internal::kEmptyString) { + error_->clear(); + } + clear_has_error(); +} +inline const ::std::string& CodeGeneratorResponse::error() const { + return *error_; +} +inline void CodeGeneratorResponse::set_error(const ::std::string& value) { + set_has_error(); + if (error_ == &::google::protobuf::internal::kEmptyString) { + error_ = new ::std::string; + } + error_->assign(value); +} +inline void CodeGeneratorResponse::set_error(const char* value) { + set_has_error(); + if (error_ == &::google::protobuf::internal::kEmptyString) { + error_ = new ::std::string; + } + error_->assign(value); +} +inline void CodeGeneratorResponse::set_error(const char* value, size_t size) { + set_has_error(); + if (error_ == &::google::protobuf::internal::kEmptyString) { + error_ = new ::std::string; + } + error_->assign(reinterpret_cast(value), size); +} +inline ::std::string* CodeGeneratorResponse::mutable_error() { + set_has_error(); + if (error_ == &::google::protobuf::internal::kEmptyString) { + error_ = new ::std::string; + } + return error_; +} +inline ::std::string* CodeGeneratorResponse::release_error() { + clear_has_error(); + if (error_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = error_; + error_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} + +// repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15; +inline int CodeGeneratorResponse::file_size() const { + return file_.size(); +} +inline void CodeGeneratorResponse::clear_file() { + file_.Clear(); +} +inline const ::google::protobuf::compiler::CodeGeneratorResponse_File& CodeGeneratorResponse::file(int index) const { + return file_.Get(index); +} +inline ::google::protobuf::compiler::CodeGeneratorResponse_File* CodeGeneratorResponse::mutable_file(int index) { + return file_.Mutable(index); +} +inline ::google::protobuf::compiler::CodeGeneratorResponse_File* CodeGeneratorResponse::add_file() { + return file_.Add(); +} +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >& +CodeGeneratorResponse::file() const { + return file_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >* +CodeGeneratorResponse::mutable_file() { + return &file_; +} + + +// @@protoc_insertion_point(namespace_scope) + +} // namespace compiler +} // namespace protobuf +} // namespace google + +#ifndef SWIG +namespace google { +namespace protobuf { + + +} // namespace google +} // namespace protobuf +#endif // SWIG + +// @@protoc_insertion_point(global_scope) + +#endif // PROTOBUF_google_2fprotobuf_2fcompiler_2fplugin_2eproto__INCLUDED diff --git a/depends/protobuf/google/protobuf/compiler/subprocess.cc b/depends/protobuf/google/protobuf/compiler/subprocess.cc new file mode 100644 index 0000000000..5fb5d5cb7d --- /dev/null +++ b/depends/protobuf/google/protobuf/compiler/subprocess.cc @@ -0,0 +1,460 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) + +#include + +#include + +#ifndef _WIN32 +#include +#include +#include +#include +#endif + +#include +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { + +#ifdef _WIN32 + +static void CloseHandleOrDie(HANDLE handle) { + if (!CloseHandle(handle)) { + GOOGLE_LOG(FATAL) << "CloseHandle: " + << Subprocess::Win32ErrorMessage(GetLastError()); + } +} + +Subprocess::Subprocess() + : process_start_error_(ERROR_SUCCESS), + child_handle_(NULL), child_stdin_(NULL), child_stdout_(NULL) {} + +Subprocess::~Subprocess() { + if (child_stdin_ != NULL) { + CloseHandleOrDie(child_stdin_); + } + if (child_stdout_ != NULL) { + CloseHandleOrDie(child_stdout_); + } +} + +void Subprocess::Start(const string& program, SearchMode search_mode) { + // Create the pipes. + HANDLE stdin_pipe_read; + HANDLE stdin_pipe_write; + HANDLE stdout_pipe_read; + HANDLE stdout_pipe_write; + + if (!CreatePipe(&stdin_pipe_read, &stdin_pipe_write, NULL, 0)) { + GOOGLE_LOG(FATAL) << "CreatePipe: " << Win32ErrorMessage(GetLastError()); + } + if (!CreatePipe(&stdout_pipe_read, &stdout_pipe_write, NULL, 0)) { + GOOGLE_LOG(FATAL) << "CreatePipe: " << Win32ErrorMessage(GetLastError()); + } + + // Make child side of the pipes inheritable. + if (!SetHandleInformation(stdin_pipe_read, + HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT)) { + GOOGLE_LOG(FATAL) << "SetHandleInformation: " + << Win32ErrorMessage(GetLastError()); + } + if (!SetHandleInformation(stdout_pipe_write, + HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT)) { + GOOGLE_LOG(FATAL) << "SetHandleInformation: " + << Win32ErrorMessage(GetLastError()); + } + + // Setup STARTUPINFO to redirect handles. + STARTUPINFOA startup_info; + ZeroMemory(&startup_info, sizeof(startup_info)); + startup_info.cb = sizeof(startup_info); + startup_info.dwFlags = STARTF_USESTDHANDLES; + startup_info.hStdInput = stdin_pipe_read; + startup_info.hStdOutput = stdout_pipe_write; + startup_info.hStdError = GetStdHandle(STD_ERROR_HANDLE); + + if (startup_info.hStdError == INVALID_HANDLE_VALUE) { + GOOGLE_LOG(FATAL) << "GetStdHandle: " + << Win32ErrorMessage(GetLastError()); + } + + // CreateProcess() mutates its second parameter. WTF? + char* name_copy = strdup(program.c_str()); + + // Create the process. + PROCESS_INFORMATION process_info; + + if (CreateProcessA((search_mode == SEARCH_PATH) ? NULL : program.c_str(), + (search_mode == SEARCH_PATH) ? name_copy : NULL, + NULL, // process security attributes + NULL, // thread security attributes + TRUE, // inherit handles? + 0, // obscure creation flags + NULL, // environment (inherit from parent) + NULL, // current directory (inherit from parent) + &startup_info, + &process_info)) { + child_handle_ = process_info.hProcess; + CloseHandleOrDie(process_info.hThread); + child_stdin_ = stdin_pipe_write; + child_stdout_ = stdout_pipe_read; + } else { + process_start_error_ = GetLastError(); + CloseHandleOrDie(stdin_pipe_write); + CloseHandleOrDie(stdout_pipe_read); + } + + CloseHandleOrDie(stdin_pipe_read); + CloseHandleOrDie(stdout_pipe_write); + free(name_copy); +} + +bool Subprocess::Communicate(const Message& input, Message* output, + string* error) { + if (process_start_error_ != ERROR_SUCCESS) { + *error = Win32ErrorMessage(process_start_error_); + return false; + } + + GOOGLE_CHECK(child_handle_ != NULL) << "Must call Start() first."; + + string input_data = input.SerializeAsString(); + string output_data; + + int input_pos = 0; + + while (child_stdout_ != NULL) { + HANDLE handles[2]; + int handle_count = 0; + + if (child_stdin_ != NULL) { + handles[handle_count++] = child_stdin_; + } + if (child_stdout_ != NULL) { + handles[handle_count++] = child_stdout_; + } + + DWORD wait_result = + WaitForMultipleObjects(handle_count, handles, FALSE, INFINITE); + + HANDLE signaled_handle; + if (wait_result >= WAIT_OBJECT_0 && + wait_result < WAIT_OBJECT_0 + handle_count) { + signaled_handle = handles[wait_result - WAIT_OBJECT_0]; + } else if (wait_result == WAIT_FAILED) { + GOOGLE_LOG(FATAL) << "WaitForMultipleObjects: " + << Win32ErrorMessage(GetLastError()); + } else { + GOOGLE_LOG(FATAL) << "WaitForMultipleObjects: Unexpected return code: " + << wait_result; + } + + if (signaled_handle == child_stdin_) { + DWORD n; + if (!WriteFile(child_stdin_, + input_data.data() + input_pos, + input_data.size() - input_pos, + &n, NULL)) { + // Child closed pipe. Presumably it will report an error later. + // Pretend we're done for now. + input_pos = input_data.size(); + } else { + input_pos += n; + } + + if (input_pos == input_data.size()) { + // We're done writing. Close. + CloseHandleOrDie(child_stdin_); + child_stdin_ = NULL; + } + } else if (signaled_handle == child_stdout_) { + char buffer[4096]; + DWORD n; + + if (!ReadFile(child_stdout_, buffer, sizeof(buffer), &n, NULL)) { + // We're done reading. Close. + CloseHandleOrDie(child_stdout_); + child_stdout_ = NULL; + } else { + output_data.append(buffer, n); + } + } + } + + if (child_stdin_ != NULL) { + // Child did not finish reading input before it closed the output. + // Presumably it exited with an error. + CloseHandleOrDie(child_stdin_); + child_stdin_ = NULL; + } + + DWORD wait_result = WaitForSingleObject(child_handle_, INFINITE); + + if (wait_result == WAIT_FAILED) { + GOOGLE_LOG(FATAL) << "WaitForSingleObject: " + << Win32ErrorMessage(GetLastError()); + } else if (wait_result != WAIT_OBJECT_0) { + GOOGLE_LOG(FATAL) << "WaitForSingleObject: Unexpected return code: " + << wait_result; + } + + DWORD exit_code; + if (!GetExitCodeProcess(child_handle_, &exit_code)) { + GOOGLE_LOG(FATAL) << "GetExitCodeProcess: " + << Win32ErrorMessage(GetLastError()); + } + + CloseHandleOrDie(child_handle_); + child_handle_ = NULL; + + if (exit_code != 0) { + *error = strings::Substitute( + "Plugin failed with status code $0.", exit_code); + return false; + } + + if (!output->ParseFromString(output_data)) { + *error = "Plugin output is unparseable: " + CEscape(output_data); + return false; + } + + return true; +} + +string Subprocess::Win32ErrorMessage(DWORD error_code) { + char* message; + + // WTF? + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, error_code, 0, + (LPTSTR)&message, // NOT A BUG! + 0, NULL); + + string result = message; + LocalFree(message); + return result; +} + +// =================================================================== + +#else // _WIN32 + +Subprocess::Subprocess() + : child_pid_(-1), child_stdin_(-1), child_stdout_(-1) {} + +Subprocess::~Subprocess() { + if (child_stdin_ != -1) { + close(child_stdin_); + } + if (child_stdout_ != -1) { + close(child_stdout_); + } +} + +void Subprocess::Start(const string& program, SearchMode search_mode) { + // Note that we assume that there are no other threads, thus we don't have to + // do crazy stuff like using socket pairs or avoiding libc locks. + + // [0] is read end, [1] is write end. + int stdin_pipe[2]; + int stdout_pipe[2]; + + pipe(stdin_pipe); + pipe(stdout_pipe); + + char* argv[2] = { strdup(program.c_str()), NULL }; + + child_pid_ = fork(); + if (child_pid_ == -1) { + GOOGLE_LOG(FATAL) << "fork: " << strerror(errno); + } else if (child_pid_ == 0) { + // We are the child. + dup2(stdin_pipe[0], STDIN_FILENO); + dup2(stdout_pipe[1], STDOUT_FILENO); + + close(stdin_pipe[0]); + close(stdin_pipe[1]); + close(stdout_pipe[0]); + close(stdout_pipe[1]); + + switch (search_mode) { + case SEARCH_PATH: + execvp(argv[0], argv); + break; + case EXACT_NAME: + execv(argv[0], argv); + break; + } + + // Write directly to STDERR_FILENO to avoid stdio code paths that may do + // stuff that is unsafe here. + write(STDERR_FILENO, argv[0], strlen(argv[0])); + const char* message = ": program not found or is not executable\n"; + write(STDERR_FILENO, message, strlen(message)); + + // Must use _exit() rather than exit() to avoid flushing output buffers + // that will also be flushed by the parent. + _exit(1); + } else { + free(argv[0]); + + close(stdin_pipe[0]); + close(stdout_pipe[1]); + + child_stdin_ = stdin_pipe[1]; + child_stdout_ = stdout_pipe[0]; + } +} + +bool Subprocess::Communicate(const Message& input, Message* output, + string* error) { + + GOOGLE_CHECK_NE(child_stdin_, -1) << "Must call Start() first."; + + // The "sighandler_t" typedef is GNU-specific, so define our own. + typedef void SignalHandler(int); + + // Make sure SIGPIPE is disabled so that if the child dies it doesn't kill us. + SignalHandler* old_pipe_handler = signal(SIGPIPE, SIG_IGN); + + string input_data = input.SerializeAsString(); + string output_data; + + int input_pos = 0; + int max_fd = max(child_stdin_, child_stdout_); + + while (child_stdout_ != -1) { + fd_set read_fds; + fd_set write_fds; + FD_ZERO(&read_fds); + FD_ZERO(&write_fds); + if (child_stdout_ != -1) { + FD_SET(child_stdout_, &read_fds); + } + if (child_stdin_ != -1) { + FD_SET(child_stdin_, &write_fds); + } + + if (select(max_fd + 1, &read_fds, &write_fds, NULL, NULL) < 0) { + if (errno == EINTR) { + // Interrupted by signal. Try again. + continue; + } else { + GOOGLE_LOG(FATAL) << "select: " << strerror(errno); + } + } + + if (child_stdin_ != -1 && FD_ISSET(child_stdin_, &write_fds)) { + int n = write(child_stdin_, input_data.data() + input_pos, + input_data.size() - input_pos); + if (n < 0) { + // Child closed pipe. Presumably it will report an error later. + // Pretend we're done for now. + input_pos = input_data.size(); + } else { + input_pos += n; + } + + if (input_pos == input_data.size()) { + // We're done writing. Close. + close(child_stdin_); + child_stdin_ = -1; + } + } + + if (child_stdout_ != -1 && FD_ISSET(child_stdout_, &read_fds)) { + char buffer[4096]; + int n = read(child_stdout_, buffer, sizeof(buffer)); + + if (n > 0) { + output_data.append(buffer, n); + } else { + // We're done reading. Close. + close(child_stdout_); + child_stdout_ = -1; + } + } + } + + if (child_stdin_ != -1) { + // Child did not finish reading input before it closed the output. + // Presumably it exited with an error. + close(child_stdin_); + child_stdin_ = -1; + } + + int status; + while (waitpid(child_pid_, &status, 0) == -1) { + if (errno != EINTR) { + GOOGLE_LOG(FATAL) << "waitpid: " << strerror(errno); + } + } + + // Restore SIGPIPE handling. + signal(SIGPIPE, old_pipe_handler); + + if (WIFEXITED(status)) { + if (WEXITSTATUS(status) != 0) { + int error_code = WEXITSTATUS(status); + *error = strings::Substitute( + "Plugin failed with status code $0.", error_code); + return false; + } + } else if (WIFSIGNALED(status)) { + int signal = WTERMSIG(status); + *error = strings::Substitute( + "Plugin killed by signal $0.", signal); + return false; + } else { + *error = "Neither WEXITSTATUS nor WTERMSIG is true?"; + return false; + } + + if (!output->ParseFromString(output_data)) { + *error = "Plugin output is unparseable."; + return false; + } + + return true; +} + +#endif // !_WIN32 + +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/depends/protobuf/google/protobuf/compiler/subprocess.h b/depends/protobuf/google/protobuf/compiler/subprocess.h new file mode 100644 index 0000000000..de9fce9ec9 --- /dev/null +++ b/depends/protobuf/google/protobuf/compiler/subprocess.h @@ -0,0 +1,108 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) + +#ifndef GOOGLE_PROTOBUF_COMPILER_SUBPROCESS_H__ +#define GOOGLE_PROTOBUF_COMPILER_SUBPROCESS_H__ + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN // right... +#include +#else // _WIN32 +#include +#include +#endif // !_WIN32 +#include + +#include + + +namespace google { +namespace protobuf { + +class Message; + +namespace compiler { + +// Utility class for launching sub-processes. +class Subprocess { + public: + Subprocess(); + ~Subprocess(); + + enum SearchMode { + SEARCH_PATH, // Use PATH environment variable. + EXACT_NAME // Program is an exact file name; don't use the PATH. + }; + + // Start the subprocess. Currently we don't provide a way to specify + // arguments as protoc plugins don't have any. + void Start(const string& program, SearchMode search_mode); + + // Serialize the input message and pipe it to the subprocess's stdin, then + // close the pipe. Meanwhile, read from the subprocess's stdout and parse + // the data into *output. All this is done carefully to avoid deadlocks. + // Returns true if successful. On any sort of error, returns false and sets + // *error to a description of the problem. + bool Communicate(const Message& input, Message* output, string* error); + +#ifdef _WIN32 + // Given an error code, returns a human-readable error message. This is + // defined here so that CommandLineInterface can share it. + static string Win32ErrorMessage(DWORD error_code); +#endif + + private: +#ifdef _WIN32 + DWORD process_start_error_; + HANDLE child_handle_; + + // The file handles for our end of the child's pipes. We close each and + // set it to NULL when no longer needed. + HANDLE child_stdin_; + HANDLE child_stdout_; + +#else // _WIN32 + pid_t child_pid_; + + // The file descriptors for our end of the child's pipes. We close each and + // set it to -1 when no longer needed. + int child_stdin_; + int child_stdout_; + +#endif // !_WIN32 +}; + +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_SUBPROCESS_H__ diff --git a/depends/protobuf/google/protobuf/compiler/test_plugin.cc b/depends/protobuf/google/protobuf/compiler/test_plugin.cc new file mode 100644 index 0000000000..5cbbf3d9df --- /dev/null +++ b/depends/protobuf/google/protobuf/compiler/test_plugin.cc @@ -0,0 +1,51 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// +// This is a dummy code generator plugin used by +// command_line_interface_unittest. + +#include +#include +#include +#include +#include + +int main(int argc, char* argv[]) { +#ifdef _MSC_VER + // Don't print a silly message or stick a modal dialog box in my face, + // please. + _set_abort_behavior(0, ~0); +#endif // !_MSC_VER + + google::protobuf::compiler::MockCodeGenerator generator("test_plugin"); + return google::protobuf::compiler::PluginMain(argc, argv, &generator); +} diff --git a/depends/protobuf/google/protobuf/compiler/zip_writer.cc b/depends/protobuf/google/protobuf/compiler/zip_writer.cc new file mode 100644 index 0000000000..65d7352705 --- /dev/null +++ b/depends/protobuf/google/protobuf/compiler/zip_writer.cc @@ -0,0 +1,218 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: ambrose@google.com (Ambrose Feinstein), +// kenton@google.com (Kenton Varda) +// +// Based on http://www.pkware.com/documents/casestudies/APPNOTE.TXT + +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { + +static const uint32 kCRC32Table[256] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + +static uint32 ComputeCRC32(const string &buf) { + uint32 x = ~0U; + for (int i = 0; i < buf.size(); ++i) { + unsigned char c = buf[i]; + x = kCRC32Table[(x ^ c) & 0xff] ^ (x >> 8); + } + return ~x; +} + +static void WriteShort(io::CodedOutputStream *out, uint16 val) { + uint8 p[2]; + p[0] = static_cast(val); + p[1] = static_cast(val >> 8); + out->WriteRaw(p, 2); +} + +ZipWriter::ZipWriter(io::ZeroCopyOutputStream* raw_output) + : raw_output_(raw_output) {} +ZipWriter::~ZipWriter() {} + +bool ZipWriter::Write(const string& filename, const string& contents) { + FileInfo info; + + info.name = filename; + uint16 filename_size = filename.size(); + info.offset = raw_output_->ByteCount(); + info.size = contents.size(); + info.crc32 = ComputeCRC32(contents); + + files_.push_back(info); + + // write file header + io::CodedOutputStream output(raw_output_); + output.WriteLittleEndian32(0x04034b50); // magic + WriteShort(&output, 10); // version needed to extract + WriteShort(&output, 0); // flags + WriteShort(&output, 0); // compression method: stored + WriteShort(&output, 0); // last modified time + WriteShort(&output, 0); // last modified date + output.WriteLittleEndian32(info.crc32); // crc-32 + output.WriteLittleEndian32(info.size); // compressed size + output.WriteLittleEndian32(info.size); // uncompressed size + WriteShort(&output, filename_size); // file name length + WriteShort(&output, 0); // extra field length + output.WriteString(filename); // file name + output.WriteString(contents); // file data + + return !output.HadError(); +} + +bool ZipWriter::WriteDirectory() { + uint16 num_entries = files_.size(); + uint32 dir_ofs = raw_output_->ByteCount(); + + // write central directory + io::CodedOutputStream output(raw_output_); + for (int i = 0; i < num_entries; ++i) { + const string &filename = files_[i].name; + uint16 filename_size = filename.size(); + uint32 crc32 = files_[i].crc32; + uint32 size = files_[i].size; + uint32 offset = files_[i].offset; + + output.WriteLittleEndian32(0x02014b50); // magic + WriteShort(&output, 10); // version made by + WriteShort(&output, 10); // version needed to extract + WriteShort(&output, 0); // flags + WriteShort(&output, 0); // compression method: stored + WriteShort(&output, 0); // last modified time + WriteShort(&output, 0); // last modified date + output.WriteLittleEndian32(crc32); // crc-32 + output.WriteLittleEndian32(size); // compressed size + output.WriteLittleEndian32(size); // uncompressed size + WriteShort(&output, filename_size); // file name length + WriteShort(&output, 0); // extra field length + WriteShort(&output, 0); // file comment length + WriteShort(&output, 0); // starting disk number + WriteShort(&output, 0); // internal file attributes + output.WriteLittleEndian32(0); // external file attributes + output.WriteLittleEndian32(offset); // local header offset + output.WriteString(filename); // file name + } + uint32 dir_len = output.ByteCount(); + + // write end of central directory marker + output.WriteLittleEndian32(0x06054b50); // magic + WriteShort(&output, 0); // disk number + WriteShort(&output, 0); // disk with start of central directory + WriteShort(&output, num_entries); // central directory entries (this disk) + WriteShort(&output, num_entries); // central directory entries (total) + output.WriteLittleEndian32(dir_len); // central directory byte size + output.WriteLittleEndian32(dir_ofs); // central directory offset + WriteShort(&output, 0); // comment length + + return output.HadError(); +} + +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/depends/protobuf/google/protobuf/compiler/zip_writer.h b/depends/protobuf/google/protobuf/compiler/zip_writer.h new file mode 100644 index 0000000000..be73972a6d --- /dev/null +++ b/depends/protobuf/google/protobuf/compiler/zip_writer.h @@ -0,0 +1,93 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) + +#include +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { + +class ZipWriter { + public: + ZipWriter(io::ZeroCopyOutputStream* raw_output); + ~ZipWriter(); + + bool Write(const string& filename, const string& contents); + bool WriteDirectory(); + + private: + struct FileInfo { + string name; + uint32 offset; + uint32 size; + uint32 crc32; + }; + + io::ZeroCopyOutputStream* raw_output_; + vector files_; +}; + +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/depends/protobuf/google/protobuf/descriptor.cc b/depends/protobuf/google/protobuf/descriptor.cc new file mode 100644 index 0000000000..754b56283e --- /dev/null +++ b/depends/protobuf/google/protobuf/descriptor.cc @@ -0,0 +1,4497 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef PACKAGE // autoheader #defines this. :( + +namespace google { +namespace protobuf { + +const FieldDescriptor::CppType +FieldDescriptor::kTypeToCppTypeMap[MAX_TYPE + 1] = { + static_cast(0), // 0 is reserved for errors + + CPPTYPE_DOUBLE, // TYPE_DOUBLE + CPPTYPE_FLOAT, // TYPE_FLOAT + CPPTYPE_INT64, // TYPE_INT64 + CPPTYPE_UINT64, // TYPE_UINT64 + CPPTYPE_INT32, // TYPE_INT32 + CPPTYPE_UINT64, // TYPE_FIXED64 + CPPTYPE_UINT32, // TYPE_FIXED32 + CPPTYPE_BOOL, // TYPE_BOOL + CPPTYPE_STRING, // TYPE_STRING + CPPTYPE_MESSAGE, // TYPE_GROUP + CPPTYPE_MESSAGE, // TYPE_MESSAGE + CPPTYPE_STRING, // TYPE_BYTES + CPPTYPE_UINT32, // TYPE_UINT32 + CPPTYPE_ENUM, // TYPE_ENUM + CPPTYPE_INT32, // TYPE_SFIXED32 + CPPTYPE_INT64, // TYPE_SFIXED64 + CPPTYPE_INT32, // TYPE_SINT32 + CPPTYPE_INT64, // TYPE_SINT64 +}; + +const char * const FieldDescriptor::kTypeToName[MAX_TYPE + 1] = { + "ERROR", // 0 is reserved for errors + + "double", // TYPE_DOUBLE + "float", // TYPE_FLOAT + "int64", // TYPE_INT64 + "uint64", // TYPE_UINT64 + "int32", // TYPE_INT32 + "fixed64", // TYPE_FIXED64 + "fixed32", // TYPE_FIXED32 + "bool", // TYPE_BOOL + "string", // TYPE_STRING + "group", // TYPE_GROUP + "message", // TYPE_MESSAGE + "bytes", // TYPE_BYTES + "uint32", // TYPE_UINT32 + "enum", // TYPE_ENUM + "sfixed32", // TYPE_SFIXED32 + "sfixed64", // TYPE_SFIXED64 + "sint32", // TYPE_SINT32 + "sint64", // TYPE_SINT64 +}; + +const char * const FieldDescriptor::kLabelToName[MAX_LABEL + 1] = { + "ERROR", // 0 is reserved for errors + + "optional", // LABEL_OPTIONAL + "required", // LABEL_REQUIRED + "repeated", // LABEL_REPEATED +}; + +#ifndef _MSC_VER // MSVC doesn't need these and won't even accept them. +const int FieldDescriptor::kMaxNumber; +const int FieldDescriptor::kFirstReservedNumber; +const int FieldDescriptor::kLastReservedNumber; +#endif + +namespace { + +const string kEmptyString; + +string ToCamelCase(const string& input) { + bool capitalize_next = false; + string result; + result.reserve(input.size()); + + for (int i = 0; i < input.size(); i++) { + if (input[i] == '_') { + capitalize_next = true; + } else if (capitalize_next) { + // Note: I distrust ctype.h due to locales. + if ('a' <= input[i] && input[i] <= 'z') { + result.push_back(input[i] - 'a' + 'A'); + } else { + result.push_back(input[i]); + } + capitalize_next = false; + } else { + result.push_back(input[i]); + } + } + + // Lower-case the first letter. + if (!result.empty() && 'A' <= result[0] && result[0] <= 'Z') { + result[0] = result[0] - 'A' + 'a'; + } + + return result; +} + +// A DescriptorPool contains a bunch of hash_maps to implement the +// various Find*By*() methods. Since hashtable lookups are O(1), it's +// most efficient to construct a fixed set of large hash_maps used by +// all objects in the pool rather than construct one or more small +// hash_maps for each object. +// +// The keys to these hash_maps are (parent, name) or (parent, number) +// pairs. Unfortunately STL doesn't provide hash functions for pair<>, +// so we must invent our own. +// +// TODO(kenton): Use StringPiece rather than const char* in keys? It would +// be a lot cleaner but we'd just have to convert it back to const char* +// for the open source release. + +typedef pair PointerStringPair; + +struct PointerStringPairEqual { + inline bool operator()(const PointerStringPair& a, + const PointerStringPair& b) const { + return a.first == b.first && strcmp(a.second, b.second) == 0; + } +}; + +template +struct PointerIntegerPairHash { + size_t operator()(const PairType& p) const { + // FIXME(kenton): What is the best way to compute this hash? I have + // no idea! This seems a bit better than an XOR. + return reinterpret_cast(p.first) * ((1 << 16) - 1) + p.second; + } + + // Used only by MSVC and platforms where hash_map is not available. + static const size_t bucket_size = 4; + static const size_t min_buckets = 8; + inline bool operator()(const PairType& a, const PairType& b) const { + return a.first < b.first || + (a.first == b.first && a.second < b.second); + } +}; + +typedef pair DescriptorIntPair; +typedef pair EnumIntPair; + +struct PointerStringPairHash { + size_t operator()(const PointerStringPair& p) const { + // FIXME(kenton): What is the best way to compute this hash? I have + // no idea! This seems a bit better than an XOR. + hash cstring_hash; + return reinterpret_cast(p.first) * ((1 << 16) - 1) + + cstring_hash(p.second); + } + + // Used only by MSVC and platforms where hash_map is not available. + static const size_t bucket_size = 4; + static const size_t min_buckets = 8; + inline bool operator()(const PointerStringPair& a, + const PointerStringPair& b) const { + if (a.first < b.first) return true; + if (a.first > b.first) return false; + return strcmp(a.second, b.second) < 0; + } +}; + + +struct Symbol { + enum Type { + NULL_SYMBOL, MESSAGE, FIELD, ENUM, ENUM_VALUE, SERVICE, METHOD, PACKAGE + }; + Type type; + union { + const Descriptor* descriptor; + const FieldDescriptor* field_descriptor; + const EnumDescriptor* enum_descriptor; + const EnumValueDescriptor* enum_value_descriptor; + const ServiceDescriptor* service_descriptor; + const MethodDescriptor* method_descriptor; + const FileDescriptor* package_file_descriptor; + }; + + inline Symbol() : type(NULL_SYMBOL) { descriptor = NULL; } + inline bool IsNull() const { return type == NULL_SYMBOL; } + inline bool IsType() const { + return type == MESSAGE || type == ENUM; + } + inline bool IsAggregate() const { + return type == MESSAGE || type == PACKAGE + || type == ENUM || type == SERVICE; + } + +#define CONSTRUCTOR(TYPE, TYPE_CONSTANT, FIELD) \ + inline explicit Symbol(const TYPE* value) { \ + type = TYPE_CONSTANT; \ + this->FIELD = value; \ + } + + CONSTRUCTOR(Descriptor , MESSAGE , descriptor ) + CONSTRUCTOR(FieldDescriptor , FIELD , field_descriptor ) + CONSTRUCTOR(EnumDescriptor , ENUM , enum_descriptor ) + CONSTRUCTOR(EnumValueDescriptor, ENUM_VALUE, enum_value_descriptor ) + CONSTRUCTOR(ServiceDescriptor , SERVICE , service_descriptor ) + CONSTRUCTOR(MethodDescriptor , METHOD , method_descriptor ) + CONSTRUCTOR(FileDescriptor , PACKAGE , package_file_descriptor) +#undef CONSTRUCTOR + + const FileDescriptor* GetFile() const { + switch (type) { + case NULL_SYMBOL: return NULL; + case MESSAGE : return descriptor ->file(); + case FIELD : return field_descriptor ->file(); + case ENUM : return enum_descriptor ->file(); + case ENUM_VALUE : return enum_value_descriptor->type()->file(); + case SERVICE : return service_descriptor ->file(); + case METHOD : return method_descriptor ->service()->file(); + case PACKAGE : return package_file_descriptor; + } + return NULL; + } +}; + +const Symbol kNullSymbol; + +typedef hash_map, streq> + SymbolsByNameMap; +typedef hash_map + SymbolsByParentMap; +typedef hash_map, streq> + FilesByNameMap; +typedef hash_map + FieldsByNameMap; +typedef hash_map > + FieldsByNumberMap; +typedef hash_map > + EnumValuesByNumberMap; +// This is a map rather than a hash_map, since we use it to iterate +// through all the extensions that extend a given Descriptor, and an +// ordered data structure that implements lower_bound is convenient +// for that. +typedef map + ExtensionsGroupedByDescriptorMap; + +} // anonymous namespace + +// =================================================================== +// DescriptorPool::Tables + +class DescriptorPool::Tables { + public: + Tables(); + ~Tables(); + + // Checkpoint the state of the tables. Future calls to Rollback() will + // return the Tables to this state. This is used when building files, since + // some kinds of validation errors cannot be detected until the file's + // descriptors have already been added to the tables. BuildFile() calls + // Checkpoint() before it starts building and Rollback() if it encounters + // an error. + void Checkpoint(); + + // Roll back the Tables to the state of the last Checkpoint(), removing + // everything that was added after that point. + void Rollback(); + + // The stack of files which are currently being built. Used to detect + // cyclic dependencies when loading files from a DescriptorDatabase. Not + // used when fallback_database_ == NULL. + vector pending_files_; + + // A set of files which we have tried to load from the fallback database + // and encountered errors. We will not attempt to load them again. + // Not used when fallback_database_ == NULL. + hash_set known_bad_files_; + + // The set of descriptors for which we've already loaded the full + // set of extensions numbers from fallback_database_. + hash_set extensions_loaded_from_db_; + + // ----------------------------------------------------------------- + // Finding items. + + // Find symbols. This returns a null Symbol (symbol.IsNull() is true) + // if not found. + inline Symbol FindSymbol(const string& key) const; + + // This implements the body of DescriptorPool::Find*ByName(). It should + // really be a private method of DescriptorPool, but that would require + // declaring Symbol in descriptor.h, which would drag all kinds of other + // stuff into the header. Yay C++. + Symbol FindByNameHelper( + const DescriptorPool* pool, const string& name) const; + + // These return NULL if not found. + inline const FileDescriptor* FindFile(const string& key) const; + inline const FieldDescriptor* FindExtension(const Descriptor* extendee, + int number); + inline void FindAllExtensions(const Descriptor* extendee, + vector* out) const; + + // ----------------------------------------------------------------- + // Adding items. + + // These add items to the corresponding tables. They return false if + // the key already exists in the table. For AddSymbol(), the string passed + // in must be one that was constructed using AllocateString(), as it will + // be used as a key in the symbols_by_name_ map without copying. + bool AddSymbol(const string& full_name, Symbol symbol); + bool AddFile(const FileDescriptor* file); + bool AddExtension(const FieldDescriptor* field); + + // ----------------------------------------------------------------- + // Allocating memory. + + // Allocate an object which will be reclaimed when the pool is + // destroyed. Note that the object's destructor will never be called, + // so its fields must be plain old data (primitive data types and + // pointers). All of the descriptor types are such objects. + template Type* Allocate(); + + // Allocate an array of objects which will be reclaimed when the + // pool in destroyed. Again, destructors are never called. + template Type* AllocateArray(int count); + + // Allocate a string which will be destroyed when the pool is destroyed. + // The string is initialized to the given value for convenience. + string* AllocateString(const string& value); + + // Allocate a protocol message object. Some older versions of GCC have + // trouble understanding explicit template instantiations in some cases, so + // in those cases we have to pass a dummy pointer of the right type as the + // parameter instead of specifying the type explicitly. + template Type* AllocateMessage(Type* dummy = NULL); + + // Allocate a FileDescriptorTables object. + FileDescriptorTables* AllocateFileTables(); + + private: + vector strings_; // All strings in the pool. + vector messages_; // All messages in the pool. + vector file_tables_; // All file tables in the pool. + vector allocations_; // All other memory allocated in the pool. + + SymbolsByNameMap symbols_by_name_; + FilesByNameMap files_by_name_; + ExtensionsGroupedByDescriptorMap extensions_; + + int strings_before_checkpoint_; + int messages_before_checkpoint_; + int file_tables_before_checkpoint_; + int allocations_before_checkpoint_; + vector symbols_after_checkpoint_; + vector files_after_checkpoint_; + vector extensions_after_checkpoint_; + + // Allocate some bytes which will be reclaimed when the pool is + // destroyed. + void* AllocateBytes(int size); +}; + +// Contains tables specific to a particular file. These tables are not +// modified once the file has been constructed, so they need not be +// protected by a mutex. This makes operations that depend only on the +// contents of a single file -- e.g. Descriptor::FindFieldByName() -- +// lock-free. +// +// For historical reasons, the definitions of the methods of +// FileDescriptorTables and DescriptorPool::Tables are interleaved below. +// These used to be a single class. +class FileDescriptorTables { + public: + FileDescriptorTables(); + ~FileDescriptorTables(); + + // Empty table, used with placeholder files. + static const FileDescriptorTables kEmpty; + + // ----------------------------------------------------------------- + // Finding items. + + // Find symbols. These return a null Symbol (symbol.IsNull() is true) + // if not found. + inline Symbol FindNestedSymbol(const void* parent, + const string& name) const; + inline Symbol FindNestedSymbolOfType(const void* parent, + const string& name, + const Symbol::Type type) const; + + // These return NULL if not found. + inline const FieldDescriptor* FindFieldByNumber( + const Descriptor* parent, int number) const; + inline const FieldDescriptor* FindFieldByLowercaseName( + const void* parent, const string& lowercase_name) const; + inline const FieldDescriptor* FindFieldByCamelcaseName( + const void* parent, const string& camelcase_name) const; + inline const EnumValueDescriptor* FindEnumValueByNumber( + const EnumDescriptor* parent, int number) const; + + // ----------------------------------------------------------------- + // Adding items. + + // These add items to the corresponding tables. They return false if + // the key already exists in the table. For AddAliasUnderParent(), the + // string passed in must be one that was constructed using AllocateString(), + // as it will be used as a key in the symbols_by_parent_ map without copying. + bool AddAliasUnderParent(const void* parent, const string& name, + Symbol symbol); + bool AddFieldByNumber(const FieldDescriptor* field); + bool AddEnumValueByNumber(const EnumValueDescriptor* value); + + // Adds the field to the lowercase_name and camelcase_name maps. Never + // fails because we allow duplicates; the first field by the name wins. + void AddFieldByStylizedNames(const FieldDescriptor* field); + + private: + SymbolsByParentMap symbols_by_parent_; + FieldsByNameMap fields_by_lowercase_name_; + FieldsByNameMap fields_by_camelcase_name_; + FieldsByNumberMap fields_by_number_; // Not including extensions. + EnumValuesByNumberMap enum_values_by_number_; +}; + +DescriptorPool::Tables::Tables() + : strings_before_checkpoint_(0), + messages_before_checkpoint_(0), + allocations_before_checkpoint_(0) {} + +DescriptorPool::Tables::~Tables() { + // Note that the deletion order is important, since the destructors of some + // messages may refer to objects in allocations_. + STLDeleteElements(&messages_); + for (int i = 0; i < allocations_.size(); i++) { + operator delete(allocations_[i]); + } + STLDeleteElements(&strings_); + STLDeleteElements(&file_tables_); +} + +FileDescriptorTables::FileDescriptorTables() {} +FileDescriptorTables::~FileDescriptorTables() {} + +const FileDescriptorTables FileDescriptorTables::kEmpty; + +void DescriptorPool::Tables::Checkpoint() { + strings_before_checkpoint_ = strings_.size(); + messages_before_checkpoint_ = messages_.size(); + file_tables_before_checkpoint_ = file_tables_.size(); + allocations_before_checkpoint_ = allocations_.size(); + + symbols_after_checkpoint_.clear(); + files_after_checkpoint_.clear(); + extensions_after_checkpoint_.clear(); +} + +void DescriptorPool::Tables::Rollback() { + for (int i = 0; i < symbols_after_checkpoint_.size(); i++) { + symbols_by_name_.erase(symbols_after_checkpoint_[i]); + } + for (int i = 0; i < files_after_checkpoint_.size(); i++) { + files_by_name_.erase(files_after_checkpoint_[i]); + } + for (int i = 0; i < extensions_after_checkpoint_.size(); i++) { + extensions_.erase(extensions_after_checkpoint_[i]); + } + + symbols_after_checkpoint_.clear(); + files_after_checkpoint_.clear(); + extensions_after_checkpoint_.clear(); + + STLDeleteContainerPointers( + strings_.begin() + strings_before_checkpoint_, strings_.end()); + STLDeleteContainerPointers( + messages_.begin() + messages_before_checkpoint_, messages_.end()); + STLDeleteContainerPointers( + file_tables_.begin() + file_tables_before_checkpoint_, file_tables_.end()); + for (int i = allocations_before_checkpoint_; i < allocations_.size(); i++) { + operator delete(allocations_[i]); + } + + strings_.resize(strings_before_checkpoint_); + messages_.resize(messages_before_checkpoint_); + file_tables_.resize(file_tables_before_checkpoint_); + allocations_.resize(allocations_before_checkpoint_); +} + +// ------------------------------------------------------------------- + +inline Symbol DescriptorPool::Tables::FindSymbol(const string& key) const { + const Symbol* result = FindOrNull(symbols_by_name_, key.c_str()); + if (result == NULL) { + return kNullSymbol; + } else { + return *result; + } +} + +inline Symbol FileDescriptorTables::FindNestedSymbol( + const void* parent, const string& name) const { + const Symbol* result = + FindOrNull(symbols_by_parent_, PointerStringPair(parent, name.c_str())); + if (result == NULL) { + return kNullSymbol; + } else { + return *result; + } +} + +inline Symbol FileDescriptorTables::FindNestedSymbolOfType( + const void* parent, const string& name, const Symbol::Type type) const { + Symbol result = FindNestedSymbol(parent, name); + if (result.type != type) return kNullSymbol; + return result; +} + +Symbol DescriptorPool::Tables::FindByNameHelper( + const DescriptorPool* pool, const string& name) const { + MutexLockMaybe lock(pool->mutex_); + Symbol result = FindSymbol(name); + + if (result.IsNull() && pool->underlay_ != NULL) { + // Symbol not found; check the underlay. + result = + pool->underlay_->tables_->FindByNameHelper(pool->underlay_, name); + } + + if (result.IsNull()) { + // Symbol still not found, so check fallback database. + if (pool->TryFindSymbolInFallbackDatabase(name)) { + result = FindSymbol(name); + } + } + + return result; +} + +inline const FileDescriptor* DescriptorPool::Tables::FindFile( + const string& key) const { + return FindPtrOrNull(files_by_name_, key.c_str()); +} + +inline const FieldDescriptor* FileDescriptorTables::FindFieldByNumber( + const Descriptor* parent, int number) const { + return FindPtrOrNull(fields_by_number_, make_pair(parent, number)); +} + +inline const FieldDescriptor* FileDescriptorTables::FindFieldByLowercaseName( + const void* parent, const string& lowercase_name) const { + return FindPtrOrNull(fields_by_lowercase_name_, + PointerStringPair(parent, lowercase_name.c_str())); +} + +inline const FieldDescriptor* FileDescriptorTables::FindFieldByCamelcaseName( + const void* parent, const string& camelcase_name) const { + return FindPtrOrNull(fields_by_camelcase_name_, + PointerStringPair(parent, camelcase_name.c_str())); +} + +inline const EnumValueDescriptor* FileDescriptorTables::FindEnumValueByNumber( + const EnumDescriptor* parent, int number) const { + return FindPtrOrNull(enum_values_by_number_, make_pair(parent, number)); +} + +inline const FieldDescriptor* DescriptorPool::Tables::FindExtension( + const Descriptor* extendee, int number) { + return FindPtrOrNull(extensions_, make_pair(extendee, number)); +} + +inline void DescriptorPool::Tables::FindAllExtensions( + const Descriptor* extendee, vector* out) const { + ExtensionsGroupedByDescriptorMap::const_iterator it = + extensions_.lower_bound(make_pair(extendee, 0)); + for (; it != extensions_.end() && it->first.first == extendee; ++it) { + out->push_back(it->second); + } +} + +// ------------------------------------------------------------------- + +bool DescriptorPool::Tables::AddSymbol( + const string& full_name, Symbol symbol) { + if (InsertIfNotPresent(&symbols_by_name_, full_name.c_str(), symbol)) { + symbols_after_checkpoint_.push_back(full_name.c_str()); + return true; + } else { + return false; + } +} + +bool FileDescriptorTables::AddAliasUnderParent( + const void* parent, const string& name, Symbol symbol) { + PointerStringPair by_parent_key(parent, name.c_str()); + return InsertIfNotPresent(&symbols_by_parent_, by_parent_key, symbol); +} + +bool DescriptorPool::Tables::AddFile(const FileDescriptor* file) { + if (InsertIfNotPresent(&files_by_name_, file->name().c_str(), file)) { + files_after_checkpoint_.push_back(file->name().c_str()); + return true; + } else { + return false; + } +} + +void FileDescriptorTables::AddFieldByStylizedNames( + const FieldDescriptor* field) { + const void* parent; + if (field->is_extension()) { + if (field->extension_scope() == NULL) { + parent = field->file(); + } else { + parent = field->extension_scope(); + } + } else { + parent = field->containing_type(); + } + + PointerStringPair lowercase_key(parent, field->lowercase_name().c_str()); + InsertIfNotPresent(&fields_by_lowercase_name_, lowercase_key, field); + + PointerStringPair camelcase_key(parent, field->camelcase_name().c_str()); + InsertIfNotPresent(&fields_by_camelcase_name_, camelcase_key, field); +} + +bool FileDescriptorTables::AddFieldByNumber(const FieldDescriptor* field) { + DescriptorIntPair key(field->containing_type(), field->number()); + return InsertIfNotPresent(&fields_by_number_, key, field); +} + +bool FileDescriptorTables::AddEnumValueByNumber( + const EnumValueDescriptor* value) { + EnumIntPair key(value->type(), value->number()); + return InsertIfNotPresent(&enum_values_by_number_, key, value); +} + +bool DescriptorPool::Tables::AddExtension(const FieldDescriptor* field) { + DescriptorIntPair key(field->containing_type(), field->number()); + if (InsertIfNotPresent(&extensions_, key, field)) { + extensions_after_checkpoint_.push_back(key); + return true; + } else { + return false; + } +} + +// ------------------------------------------------------------------- + +template +Type* DescriptorPool::Tables::Allocate() { + return reinterpret_cast(AllocateBytes(sizeof(Type))); +} + +template +Type* DescriptorPool::Tables::AllocateArray(int count) { + return reinterpret_cast(AllocateBytes(sizeof(Type) * count)); +} + +string* DescriptorPool::Tables::AllocateString(const string& value) { + string* result = new string(value); + strings_.push_back(result); + return result; +} + +template +Type* DescriptorPool::Tables::AllocateMessage(Type* dummy) { + Type* result = new Type; + messages_.push_back(result); + return result; +} + +FileDescriptorTables* DescriptorPool::Tables::AllocateFileTables() { + FileDescriptorTables* result = new FileDescriptorTables; + file_tables_.push_back(result); + return result; +} + +void* DescriptorPool::Tables::AllocateBytes(int size) { + // TODO(kenton): Would it be worthwhile to implement this in some more + // sophisticated way? Probably not for the open source release, but for + // internal use we could easily plug in one of our existing memory pool + // allocators... + if (size == 0) return NULL; + + void* result = operator new(size); + allocations_.push_back(result); + return result; +} + +// =================================================================== +// DescriptorPool + +DescriptorPool::ErrorCollector::~ErrorCollector() {} + +DescriptorPool::DescriptorPool() + : mutex_(NULL), + fallback_database_(NULL), + default_error_collector_(NULL), + underlay_(NULL), + tables_(new Tables), + enforce_dependencies_(true), + allow_unknown_(false) {} + +DescriptorPool::DescriptorPool(DescriptorDatabase* fallback_database, + ErrorCollector* error_collector) + : mutex_(new Mutex), + fallback_database_(fallback_database), + default_error_collector_(error_collector), + underlay_(NULL), + tables_(new Tables), + enforce_dependencies_(true), + allow_unknown_(false) { +} + +DescriptorPool::DescriptorPool(const DescriptorPool* underlay) + : mutex_(NULL), + fallback_database_(NULL), + default_error_collector_(NULL), + underlay_(underlay), + tables_(new Tables), + enforce_dependencies_(true), + allow_unknown_(false) {} + +DescriptorPool::~DescriptorPool() { + if (mutex_ != NULL) delete mutex_; +} + +// DescriptorPool::BuildFile() defined later. +// DescriptorPool::BuildFileCollectingErrors() defined later. + +void DescriptorPool::InternalDontEnforceDependencies() { + enforce_dependencies_ = false; +} + +bool DescriptorPool::InternalIsFileLoaded(const string& filename) const { + MutexLockMaybe lock(mutex_); + return tables_->FindFile(filename) != NULL; +} + +// generated_pool ==================================================== + +namespace { + + +EncodedDescriptorDatabase* generated_database_ = NULL; +DescriptorPool* generated_pool_ = NULL; +GOOGLE_PROTOBUF_DECLARE_ONCE(generated_pool_init_); + +void DeleteGeneratedPool() { + delete generated_database_; + generated_database_ = NULL; + delete generated_pool_; + generated_pool_ = NULL; +} + +void InitGeneratedPool() { + generated_database_ = new EncodedDescriptorDatabase; + generated_pool_ = new DescriptorPool(generated_database_); + + internal::OnShutdown(&DeleteGeneratedPool); +} + +inline void InitGeneratedPoolOnce() { + ::google::protobuf::GoogleOnceInit(&generated_pool_init_, &InitGeneratedPool); +} + +} // anonymous namespace + +const DescriptorPool* DescriptorPool::generated_pool() { + InitGeneratedPoolOnce(); + return generated_pool_; +} + +DescriptorPool* DescriptorPool::internal_generated_pool() { + InitGeneratedPoolOnce(); + return generated_pool_; +} + +void DescriptorPool::InternalAddGeneratedFile( + const void* encoded_file_descriptor, int size) { + // So, this function is called in the process of initializing the + // descriptors for generated proto classes. Each generated .pb.cc file + // has an internal procedure called AddDescriptors() which is called at + // process startup, and that function calls this one in order to register + // the raw bytes of the FileDescriptorProto representing the file. + // + // We do not actually construct the descriptor objects right away. We just + // hang on to the bytes until they are actually needed. We actually construct + // the descriptor the first time one of the following things happens: + // * Someone calls a method like descriptor(), GetDescriptor(), or + // GetReflection() on the generated types, which requires returning the + // descriptor or an object based on it. + // * Someone looks up the descriptor in DescriptorPool::generated_pool(). + // + // Once one of these happens, the DescriptorPool actually parses the + // FileDescriptorProto and generates a FileDescriptor (and all its children) + // based on it. + // + // Note that FileDescriptorProto is itself a generated protocol message. + // Therefore, when we parse one, we have to be very careful to avoid using + // any descriptor-based operations, since this might cause infinite recursion + // or deadlock. + InitGeneratedPoolOnce(); + GOOGLE_CHECK(generated_database_->Add(encoded_file_descriptor, size)); +} + + +// Find*By* methods ================================================== + +// TODO(kenton): There's a lot of repeated code here, but I'm not sure if +// there's any good way to factor it out. Think about this some time when +// there's nothing more important to do (read: never). + +const FileDescriptor* DescriptorPool::FindFileByName(const string& name) const { + MutexLockMaybe lock(mutex_); + const FileDescriptor* result = tables_->FindFile(name); + if (result != NULL) return result; + if (underlay_ != NULL) { + const FileDescriptor* result = underlay_->FindFileByName(name); + if (result != NULL) return result; + } + if (TryFindFileInFallbackDatabase(name)) { + const FileDescriptor* result = tables_->FindFile(name); + if (result != NULL) return result; + } + return NULL; +} + +const FileDescriptor* DescriptorPool::FindFileContainingSymbol( + const string& symbol_name) const { + MutexLockMaybe lock(mutex_); + Symbol result = tables_->FindSymbol(symbol_name); + if (!result.IsNull()) return result.GetFile(); + if (underlay_ != NULL) { + const FileDescriptor* result = + underlay_->FindFileContainingSymbol(symbol_name); + if (result != NULL) return result; + } + if (TryFindSymbolInFallbackDatabase(symbol_name)) { + Symbol result = tables_->FindSymbol(symbol_name); + if (!result.IsNull()) return result.GetFile(); + } + return NULL; +} + +const Descriptor* DescriptorPool::FindMessageTypeByName( + const string& name) const { + Symbol result = tables_->FindByNameHelper(this, name); + return (result.type == Symbol::MESSAGE) ? result.descriptor : NULL; +} + +const FieldDescriptor* DescriptorPool::FindFieldByName( + const string& name) const { + Symbol result = tables_->FindByNameHelper(this, name); + if (result.type == Symbol::FIELD && + !result.field_descriptor->is_extension()) { + return result.field_descriptor; + } else { + return NULL; + } +} + +const FieldDescriptor* DescriptorPool::FindExtensionByName( + const string& name) const { + Symbol result = tables_->FindByNameHelper(this, name); + if (result.type == Symbol::FIELD && + result.field_descriptor->is_extension()) { + return result.field_descriptor; + } else { + return NULL; + } +} + +const EnumDescriptor* DescriptorPool::FindEnumTypeByName( + const string& name) const { + Symbol result = tables_->FindByNameHelper(this, name); + return (result.type == Symbol::ENUM) ? result.enum_descriptor : NULL; +} + +const EnumValueDescriptor* DescriptorPool::FindEnumValueByName( + const string& name) const { + Symbol result = tables_->FindByNameHelper(this, name); + return (result.type == Symbol::ENUM_VALUE) ? + result.enum_value_descriptor : NULL; +} + +const ServiceDescriptor* DescriptorPool::FindServiceByName( + const string& name) const { + Symbol result = tables_->FindByNameHelper(this, name); + return (result.type == Symbol::SERVICE) ? result.service_descriptor : NULL; +} + +const MethodDescriptor* DescriptorPool::FindMethodByName( + const string& name) const { + Symbol result = tables_->FindByNameHelper(this, name); + return (result.type == Symbol::METHOD) ? result.method_descriptor : NULL; +} + +const FieldDescriptor* DescriptorPool::FindExtensionByNumber( + const Descriptor* extendee, int number) const { + MutexLockMaybe lock(mutex_); + const FieldDescriptor* result = tables_->FindExtension(extendee, number); + if (result != NULL) { + return result; + } + if (underlay_ != NULL) { + const FieldDescriptor* result = + underlay_->FindExtensionByNumber(extendee, number); + if (result != NULL) return result; + } + if (TryFindExtensionInFallbackDatabase(extendee, number)) { + const FieldDescriptor* result = tables_->FindExtension(extendee, number); + if (result != NULL) { + return result; + } + } + return NULL; +} + +void DescriptorPool::FindAllExtensions( + const Descriptor* extendee, vector* out) const { + MutexLockMaybe lock(mutex_); + + // Initialize tables_->extensions_ from the fallback database first + // (but do this only once per descriptor). + if (fallback_database_ != NULL && + tables_->extensions_loaded_from_db_.count(extendee) == 0) { + vector numbers; + if (fallback_database_->FindAllExtensionNumbers(extendee->full_name(), + &numbers)) { + for (int i = 0; i < numbers.size(); ++i) { + int number = numbers[i]; + if (tables_->FindExtension(extendee, number) == NULL) { + TryFindExtensionInFallbackDatabase(extendee, number); + } + } + tables_->extensions_loaded_from_db_.insert(extendee); + } + } + + tables_->FindAllExtensions(extendee, out); + if (underlay_ != NULL) { + underlay_->FindAllExtensions(extendee, out); + } +} + +// ------------------------------------------------------------------- + +const FieldDescriptor* +Descriptor::FindFieldByNumber(int key) const { + const FieldDescriptor* result = + file()->tables_->FindFieldByNumber(this, key); + if (result == NULL || result->is_extension()) { + return NULL; + } else { + return result; + } +} + +const FieldDescriptor* +Descriptor::FindFieldByLowercaseName(const string& key) const { + const FieldDescriptor* result = + file()->tables_->FindFieldByLowercaseName(this, key); + if (result == NULL || result->is_extension()) { + return NULL; + } else { + return result; + } +} + +const FieldDescriptor* +Descriptor::FindFieldByCamelcaseName(const string& key) const { + const FieldDescriptor* result = + file()->tables_->FindFieldByCamelcaseName(this, key); + if (result == NULL || result->is_extension()) { + return NULL; + } else { + return result; + } +} + +const FieldDescriptor* +Descriptor::FindFieldByName(const string& key) const { + Symbol result = + file()->tables_->FindNestedSymbolOfType(this, key, Symbol::FIELD); + if (!result.IsNull() && !result.field_descriptor->is_extension()) { + return result.field_descriptor; + } else { + return NULL; + } +} + +const FieldDescriptor* +Descriptor::FindExtensionByName(const string& key) const { + Symbol result = + file()->tables_->FindNestedSymbolOfType(this, key, Symbol::FIELD); + if (!result.IsNull() && result.field_descriptor->is_extension()) { + return result.field_descriptor; + } else { + return NULL; + } +} + +const FieldDescriptor* +Descriptor::FindExtensionByLowercaseName(const string& key) const { + const FieldDescriptor* result = + file()->tables_->FindFieldByLowercaseName(this, key); + if (result == NULL || !result->is_extension()) { + return NULL; + } else { + return result; + } +} + +const FieldDescriptor* +Descriptor::FindExtensionByCamelcaseName(const string& key) const { + const FieldDescriptor* result = + file()->tables_->FindFieldByCamelcaseName(this, key); + if (result == NULL || !result->is_extension()) { + return NULL; + } else { + return result; + } +} + +const Descriptor* +Descriptor::FindNestedTypeByName(const string& key) const { + Symbol result = + file()->tables_->FindNestedSymbolOfType(this, key, Symbol::MESSAGE); + if (!result.IsNull()) { + return result.descriptor; + } else { + return NULL; + } +} + +const EnumDescriptor* +Descriptor::FindEnumTypeByName(const string& key) const { + Symbol result = + file()->tables_->FindNestedSymbolOfType(this, key, Symbol::ENUM); + if (!result.IsNull()) { + return result.enum_descriptor; + } else { + return NULL; + } +} + +const EnumValueDescriptor* +Descriptor::FindEnumValueByName(const string& key) const { + Symbol result = + file()->tables_->FindNestedSymbolOfType(this, key, Symbol::ENUM_VALUE); + if (!result.IsNull()) { + return result.enum_value_descriptor; + } else { + return NULL; + } +} + +const EnumValueDescriptor* +EnumDescriptor::FindValueByName(const string& key) const { + Symbol result = + file()->tables_->FindNestedSymbolOfType(this, key, Symbol::ENUM_VALUE); + if (!result.IsNull()) { + return result.enum_value_descriptor; + } else { + return NULL; + } +} + +const EnumValueDescriptor* +EnumDescriptor::FindValueByNumber(int key) const { + return file()->tables_->FindEnumValueByNumber(this, key); +} + +const MethodDescriptor* +ServiceDescriptor::FindMethodByName(const string& key) const { + Symbol result = + file()->tables_->FindNestedSymbolOfType(this, key, Symbol::METHOD); + if (!result.IsNull()) { + return result.method_descriptor; + } else { + return NULL; + } +} + +const Descriptor* +FileDescriptor::FindMessageTypeByName(const string& key) const { + Symbol result = tables_->FindNestedSymbolOfType(this, key, Symbol::MESSAGE); + if (!result.IsNull()) { + return result.descriptor; + } else { + return NULL; + } +} + +const EnumDescriptor* +FileDescriptor::FindEnumTypeByName(const string& key) const { + Symbol result = tables_->FindNestedSymbolOfType(this, key, Symbol::ENUM); + if (!result.IsNull()) { + return result.enum_descriptor; + } else { + return NULL; + } +} + +const EnumValueDescriptor* +FileDescriptor::FindEnumValueByName(const string& key) const { + Symbol result = + tables_->FindNestedSymbolOfType(this, key, Symbol::ENUM_VALUE); + if (!result.IsNull()) { + return result.enum_value_descriptor; + } else { + return NULL; + } +} + +const ServiceDescriptor* +FileDescriptor::FindServiceByName(const string& key) const { + Symbol result = tables_->FindNestedSymbolOfType(this, key, Symbol::SERVICE); + if (!result.IsNull()) { + return result.service_descriptor; + } else { + return NULL; + } +} + +const FieldDescriptor* +FileDescriptor::FindExtensionByName(const string& key) const { + Symbol result = tables_->FindNestedSymbolOfType(this, key, Symbol::FIELD); + if (!result.IsNull() && result.field_descriptor->is_extension()) { + return result.field_descriptor; + } else { + return NULL; + } +} + +const FieldDescriptor* +FileDescriptor::FindExtensionByLowercaseName(const string& key) const { + const FieldDescriptor* result = tables_->FindFieldByLowercaseName(this, key); + if (result == NULL || !result->is_extension()) { + return NULL; + } else { + return result; + } +} + +const FieldDescriptor* +FileDescriptor::FindExtensionByCamelcaseName(const string& key) const { + const FieldDescriptor* result = tables_->FindFieldByCamelcaseName(this, key); + if (result == NULL || !result->is_extension()) { + return NULL; + } else { + return result; + } +} + +bool Descriptor::IsExtensionNumber(int number) const { + // Linear search should be fine because we don't expect a message to have + // more than a couple extension ranges. + for (int i = 0; i < extension_range_count(); i++) { + if (number >= extension_range(i)->start && + number < extension_range(i)->end) { + return true; + } + } + return false; +} + +// ------------------------------------------------------------------- + +bool DescriptorPool::TryFindFileInFallbackDatabase(const string& name) const { + if (fallback_database_ == NULL) return false; + + if (tables_->known_bad_files_.count(name) > 0) return false; + + FileDescriptorProto file_proto; + if (!fallback_database_->FindFileByName(name, &file_proto) || + BuildFileFromDatabase(file_proto) == NULL) { + tables_->known_bad_files_.insert(name); + return false; + } + + return true; +} + +bool DescriptorPool::TryFindSymbolInFallbackDatabase(const string& name) const { + if (fallback_database_ == NULL) return false; + + FileDescriptorProto file_proto; + if (!fallback_database_->FindFileContainingSymbol(name, &file_proto)) { + return false; + } + + if (tables_->FindFile(file_proto.name()) != NULL) { + // We've already loaded this file, and it apparently doesn't contain the + // symbol we're looking for. Some DescriptorDatabases return false + // positives. + return false; + } + + if (BuildFileFromDatabase(file_proto) == NULL) { + return false; + } + + return true; +} + +bool DescriptorPool::TryFindExtensionInFallbackDatabase( + const Descriptor* containing_type, int field_number) const { + if (fallback_database_ == NULL) return false; + + FileDescriptorProto file_proto; + if (!fallback_database_->FindFileContainingExtension( + containing_type->full_name(), field_number, &file_proto)) { + return false; + } + + if (tables_->FindFile(file_proto.name()) != NULL) { + // We've already loaded this file, and it apparently doesn't contain the + // extension we're looking for. Some DescriptorDatabases return false + // positives. + return false; + } + + if (BuildFileFromDatabase(file_proto) == NULL) { + return false; + } + + return true; +} + +// =================================================================== + +string FieldDescriptor::DefaultValueAsString(bool quote_string_type) const { + GOOGLE_CHECK(has_default_value()) << "No default value"; + switch (cpp_type()) { + case CPPTYPE_INT32: + return SimpleItoa(default_value_int32()); + break; + case CPPTYPE_INT64: + return SimpleItoa(default_value_int64()); + break; + case CPPTYPE_UINT32: + return SimpleItoa(default_value_uint32()); + break; + case CPPTYPE_UINT64: + return SimpleItoa(default_value_uint64()); + break; + case CPPTYPE_FLOAT: + return SimpleFtoa(default_value_float()); + break; + case CPPTYPE_DOUBLE: + return SimpleDtoa(default_value_double()); + break; + case CPPTYPE_BOOL: + return default_value_bool() ? "true" : "false"; + break; + case CPPTYPE_STRING: + if (quote_string_type) { + return "\"" + CEscape(default_value_string()) + "\""; + } else { + if (type() == TYPE_BYTES) { + return CEscape(default_value_string()); + } else { + return default_value_string(); + } + } + break; + case CPPTYPE_ENUM: + return default_value_enum()->name(); + break; + case CPPTYPE_MESSAGE: + GOOGLE_LOG(DFATAL) << "Messages can't have default values!"; + break; + } + GOOGLE_LOG(FATAL) << "Can't get here: failed to get default value as string"; + return ""; +} + +// CopyTo methods ==================================================== + +void FileDescriptor::CopyTo(FileDescriptorProto* proto) const { + proto->set_name(name()); + if (!package().empty()) proto->set_package(package()); + + for (int i = 0; i < dependency_count(); i++) { + proto->add_dependency(dependency(i)->name()); + } + + for (int i = 0; i < message_type_count(); i++) { + message_type(i)->CopyTo(proto->add_message_type()); + } + for (int i = 0; i < enum_type_count(); i++) { + enum_type(i)->CopyTo(proto->add_enum_type()); + } + for (int i = 0; i < service_count(); i++) { + service(i)->CopyTo(proto->add_service()); + } + for (int i = 0; i < extension_count(); i++) { + extension(i)->CopyTo(proto->add_extension()); + } + + if (&options() != &FileOptions::default_instance()) { + proto->mutable_options()->CopyFrom(options()); + } +} + +void Descriptor::CopyTo(DescriptorProto* proto) const { + proto->set_name(name()); + + for (int i = 0; i < field_count(); i++) { + field(i)->CopyTo(proto->add_field()); + } + for (int i = 0; i < nested_type_count(); i++) { + nested_type(i)->CopyTo(proto->add_nested_type()); + } + for (int i = 0; i < enum_type_count(); i++) { + enum_type(i)->CopyTo(proto->add_enum_type()); + } + for (int i = 0; i < extension_range_count(); i++) { + DescriptorProto::ExtensionRange* range = proto->add_extension_range(); + range->set_start(extension_range(i)->start); + range->set_end(extension_range(i)->end); + } + for (int i = 0; i < extension_count(); i++) { + extension(i)->CopyTo(proto->add_extension()); + } + + if (&options() != &MessageOptions::default_instance()) { + proto->mutable_options()->CopyFrom(options()); + } +} + +void FieldDescriptor::CopyTo(FieldDescriptorProto* proto) const { + proto->set_name(name()); + proto->set_number(number()); + + // Some compilers do not allow static_cast directly between two enum types, + // so we must cast to int first. + proto->set_label(static_cast( + implicit_cast(label()))); + proto->set_type(static_cast( + implicit_cast(type()))); + + if (is_extension()) { + if (!containing_type()->is_unqualified_placeholder_) { + proto->set_extendee("."); + } + proto->mutable_extendee()->append(containing_type()->full_name()); + } + + if (cpp_type() == CPPTYPE_MESSAGE) { + if (message_type()->is_placeholder_) { + // We don't actually know if the type is a message type. It could be + // an enum. + proto->clear_type(); + } + + if (!message_type()->is_unqualified_placeholder_) { + proto->set_type_name("."); + } + proto->mutable_type_name()->append(message_type()->full_name()); + } else if (cpp_type() == CPPTYPE_ENUM) { + if (!enum_type()->is_unqualified_placeholder_) { + proto->set_type_name("."); + } + proto->mutable_type_name()->append(enum_type()->full_name()); + } + + if (has_default_value()) { + proto->set_default_value(DefaultValueAsString(false)); + } + + if (&options() != &FieldOptions::default_instance()) { + proto->mutable_options()->CopyFrom(options()); + } +} + +void EnumDescriptor::CopyTo(EnumDescriptorProto* proto) const { + proto->set_name(name()); + + for (int i = 0; i < value_count(); i++) { + value(i)->CopyTo(proto->add_value()); + } + + if (&options() != &EnumOptions::default_instance()) { + proto->mutable_options()->CopyFrom(options()); + } +} + +void EnumValueDescriptor::CopyTo(EnumValueDescriptorProto* proto) const { + proto->set_name(name()); + proto->set_number(number()); + + if (&options() != &EnumValueOptions::default_instance()) { + proto->mutable_options()->CopyFrom(options()); + } +} + +void ServiceDescriptor::CopyTo(ServiceDescriptorProto* proto) const { + proto->set_name(name()); + + for (int i = 0; i < method_count(); i++) { + method(i)->CopyTo(proto->add_method()); + } + + if (&options() != &ServiceOptions::default_instance()) { + proto->mutable_options()->CopyFrom(options()); + } +} + +void MethodDescriptor::CopyTo(MethodDescriptorProto* proto) const { + proto->set_name(name()); + + if (!input_type()->is_unqualified_placeholder_) { + proto->set_input_type("."); + } + proto->mutable_input_type()->append(input_type()->full_name()); + + if (!output_type()->is_unqualified_placeholder_) { + proto->set_output_type("."); + } + proto->mutable_output_type()->append(output_type()->full_name()); + + if (&options() != &MethodOptions::default_instance()) { + proto->mutable_options()->CopyFrom(options()); + } +} + +// DebugString methods =============================================== + +namespace { + +// Used by each of the option formatters. +bool RetrieveOptions(const Message &options, vector *option_entries) { + option_entries->clear(); + const Reflection* reflection = options.GetReflection(); + vector fields; + reflection->ListFields(options, &fields); + for (int i = 0; i < fields.size(); i++) { + // Doesn't make sense to have message type fields here + if (fields[i]->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + continue; + } + int count = 1; + bool repeated = false; + if (fields[i]->is_repeated()) { + count = reflection->FieldSize(options, fields[i]); + repeated = true; + } + for (int j = 0; j < count; j++) { + string fieldval; + TextFormat::PrintFieldValueToString(options, fields[i], + repeated ? count : -1, &fieldval); + option_entries->push_back(fields[i]->name() + " = " + fieldval); + } + } + return !option_entries->empty(); +} + +// Formats options that all appear together in brackets. Does not include +// brackets. +bool FormatBracketedOptions(const Message &options, string *output) { + vector all_options; + if (RetrieveOptions(options, &all_options)) { + output->append(JoinStrings(all_options, ", ")); + } + return !all_options.empty(); +} + +// Formats options one per line +bool FormatLineOptions(int depth, const Message &options, string *output) { + string prefix(depth * 2, ' '); + vector all_options; + if (RetrieveOptions(options, &all_options)) { + for (int i = 0; i < all_options.size(); i++) { + strings::SubstituteAndAppend(output, "$0option $1;\n", + prefix, all_options[i]); + } + } + return !all_options.empty(); +} + +} // anonymous namespace + +string FileDescriptor::DebugString() const { + string contents = "syntax = \"proto2\";\n\n"; + + for (int i = 0; i < dependency_count(); i++) { + strings::SubstituteAndAppend(&contents, "import \"$0\";\n", + dependency(i)->name()); + } + + if (!package().empty()) { + strings::SubstituteAndAppend(&contents, "package $0;\n\n", package()); + } + + if (FormatLineOptions(0, options(), &contents)) { + contents.append("\n"); // add some space if we had options + } + + for (int i = 0; i < enum_type_count(); i++) { + enum_type(i)->DebugString(0, &contents); + contents.append("\n"); + } + + // Find all the 'group' type extensions; we will not output their nested + // definitions (those will be done with their group field descriptor). + set groups; + for (int i = 0; i < extension_count(); i++) { + if (extension(i)->type() == FieldDescriptor::TYPE_GROUP) { + groups.insert(extension(i)->message_type()); + } + } + + for (int i = 0; i < message_type_count(); i++) { + if (groups.count(message_type(i)) == 0) { + strings::SubstituteAndAppend(&contents, "message $0", + message_type(i)->name()); + message_type(i)->DebugString(0, &contents); + contents.append("\n"); + } + } + + for (int i = 0; i < service_count(); i++) { + service(i)->DebugString(&contents); + contents.append("\n"); + } + + const Descriptor* containing_type = NULL; + for (int i = 0; i < extension_count(); i++) { + if (extension(i)->containing_type() != containing_type) { + if (i > 0) contents.append("}\n\n"); + containing_type = extension(i)->containing_type(); + strings::SubstituteAndAppend(&contents, "extend .$0 {\n", + containing_type->full_name()); + } + extension(i)->DebugString(1, &contents); + } + if (extension_count() > 0) contents.append("}\n\n"); + + return contents; +} + +string Descriptor::DebugString() const { + string contents; + strings::SubstituteAndAppend(&contents, "message $0", name()); + DebugString(0, &contents); + return contents; +} + +void Descriptor::DebugString(int depth, string *contents) const { + string prefix(depth * 2, ' '); + ++depth; + contents->append(" {\n"); + + FormatLineOptions(depth, options(), contents); + + // Find all the 'group' types for fields and extensions; we will not output + // their nested definitions (those will be done with their group field + // descriptor). + set groups; + for (int i = 0; i < field_count(); i++) { + if (field(i)->type() == FieldDescriptor::TYPE_GROUP) { + groups.insert(field(i)->message_type()); + } + } + for (int i = 0; i < extension_count(); i++) { + if (extension(i)->type() == FieldDescriptor::TYPE_GROUP) { + groups.insert(extension(i)->message_type()); + } + } + + for (int i = 0; i < nested_type_count(); i++) { + if (groups.count(nested_type(i)) == 0) { + strings::SubstituteAndAppend(contents, "$0 message $1", + prefix, nested_type(i)->name()); + nested_type(i)->DebugString(depth, contents); + } + } + for (int i = 0; i < enum_type_count(); i++) { + enum_type(i)->DebugString(depth, contents); + } + for (int i = 0; i < field_count(); i++) { + field(i)->DebugString(depth, contents); + } + + for (int i = 0; i < extension_range_count(); i++) { + strings::SubstituteAndAppend(contents, "$0 extensions $1 to $2;\n", + prefix, + extension_range(i)->start, + extension_range(i)->end - 1); + } + + // Group extensions by what they extend, so they can be printed out together. + const Descriptor* containing_type = NULL; + for (int i = 0; i < extension_count(); i++) { + if (extension(i)->containing_type() != containing_type) { + if (i > 0) strings::SubstituteAndAppend(contents, "$0 }\n", prefix); + containing_type = extension(i)->containing_type(); + strings::SubstituteAndAppend(contents, "$0 extend .$1 {\n", + prefix, containing_type->full_name()); + } + extension(i)->DebugString(depth + 1, contents); + } + if (extension_count() > 0) + strings::SubstituteAndAppend(contents, "$0 }\n", prefix); + + strings::SubstituteAndAppend(contents, "$0}\n", prefix); +} + +string FieldDescriptor::DebugString() const { + string contents; + int depth = 0; + if (is_extension()) { + strings::SubstituteAndAppend(&contents, "extend .$0 {\n", + containing_type()->full_name()); + depth = 1; + } + DebugString(depth, &contents); + if (is_extension()) { + contents.append("}\n"); + } + return contents; +} + +void FieldDescriptor::DebugString(int depth, string *contents) const { + string prefix(depth * 2, ' '); + string field_type; + switch (type()) { + case TYPE_MESSAGE: + field_type = "." + message_type()->full_name(); + break; + case TYPE_ENUM: + field_type = "." + enum_type()->full_name(); + break; + default: + field_type = kTypeToName[type()]; + } + + strings::SubstituteAndAppend(contents, "$0$1 $2 $3 = $4", + prefix, + kLabelToName[label()], + field_type, + type() == TYPE_GROUP ? message_type()->name() : + name(), + number()); + + bool bracketed = false; + if (has_default_value()) { + bracketed = true; + strings::SubstituteAndAppend(contents, " [default = $0", + DefaultValueAsString(true)); + } + + string formatted_options; + if (FormatBracketedOptions(options(), &formatted_options)) { + contents->append(bracketed ? ", " : " ["); + bracketed = true; + contents->append(formatted_options); + } + + if (bracketed) { + contents->append("]"); + } + + if (type() == TYPE_GROUP) { + message_type()->DebugString(depth, contents); + } else { + contents->append(";\n"); + } +} + +string EnumDescriptor::DebugString() const { + string contents; + DebugString(0, &contents); + return contents; +} + +void EnumDescriptor::DebugString(int depth, string *contents) const { + string prefix(depth * 2, ' '); + ++depth; + strings::SubstituteAndAppend(contents, "$0enum $1 {\n", + prefix, name()); + + FormatLineOptions(depth, options(), contents); + + for (int i = 0; i < value_count(); i++) { + value(i)->DebugString(depth, contents); + } + strings::SubstituteAndAppend(contents, "$0}\n", prefix); +} + +string EnumValueDescriptor::DebugString() const { + string contents; + DebugString(0, &contents); + return contents; +} + +void EnumValueDescriptor::DebugString(int depth, string *contents) const { + string prefix(depth * 2, ' '); + strings::SubstituteAndAppend(contents, "$0$1 = $2", + prefix, name(), number()); + + string formatted_options; + if (FormatBracketedOptions(options(), &formatted_options)) { + strings::SubstituteAndAppend(contents, " [$0]", formatted_options); + } + contents->append(";\n"); +} + +string ServiceDescriptor::DebugString() const { + string contents; + DebugString(&contents); + return contents; +} + +void ServiceDescriptor::DebugString(string *contents) const { + strings::SubstituteAndAppend(contents, "service $0 {\n", name()); + + FormatLineOptions(1, options(), contents); + + for (int i = 0; i < method_count(); i++) { + method(i)->DebugString(1, contents); + } + + contents->append("}\n"); +} + +string MethodDescriptor::DebugString() const { + string contents; + DebugString(0, &contents); + return contents; +} + +void MethodDescriptor::DebugString(int depth, string *contents) const { + string prefix(depth * 2, ' '); + ++depth; + strings::SubstituteAndAppend(contents, "$0rpc $1(.$2) returns (.$3)", + prefix, name(), + input_type()->full_name(), + output_type()->full_name()); + + string formatted_options; + if (FormatLineOptions(depth, options(), &formatted_options)) { + strings::SubstituteAndAppend(contents, " {\n$0$1}\n", + formatted_options, prefix); + } else { + contents->append(";\n"); + } +} +// =================================================================== + +namespace { + +// Represents an options message to interpret. Extension names in the option +// name are respolved relative to name_scope. element_name and orig_opt are +// used only for error reporting (since the parser records locations against +// pointers in the original options, not the mutable copy). The Message must be +// one of the Options messages in descriptor.proto. +struct OptionsToInterpret { + OptionsToInterpret(const string& ns, + const string& el, + const Message* orig_opt, + Message* opt) + : name_scope(ns), + element_name(el), + original_options(orig_opt), + options(opt) { + } + string name_scope; + string element_name; + const Message* original_options; + Message* options; +}; + +} // namespace + +class DescriptorBuilder { + public: + DescriptorBuilder(const DescriptorPool* pool, + DescriptorPool::Tables* tables, + DescriptorPool::ErrorCollector* error_collector); + ~DescriptorBuilder(); + + const FileDescriptor* BuildFile(const FileDescriptorProto& proto); + + private: + friend class OptionInterpreter; + + const DescriptorPool* pool_; + DescriptorPool::Tables* tables_; // for convenience + DescriptorPool::ErrorCollector* error_collector_; + + // As we build descriptors we store copies of the options messages in + // them. We put pointers to those copies in this vector, as we build, so we + // can later (after cross-linking) interpret those options. + vector options_to_interpret_; + + bool had_errors_; + string filename_; + FileDescriptor* file_; + FileDescriptorTables* file_tables_; + + // If LookupSymbol() finds a symbol that is in a file which is not a declared + // dependency of this file, it will fail, but will set + // possible_undeclared_dependency_ to point at that file. This is only used + // by AddNotDefinedError() to report a more useful error message. + // possible_undeclared_dependency_name_ is the name of the symbol that was + // actually found in possible_undeclared_dependency_, which may be a parent + // of the symbol actually looked for. + const FileDescriptor* possible_undeclared_dependency_; + string possible_undeclared_dependency_name_; + + void AddError(const string& element_name, + const Message& descriptor, + DescriptorPool::ErrorCollector::ErrorLocation location, + const string& error); + + // Adds an error indicating that undefined_symbol was not defined. Must + // only be called after LookupSymbol() fails. + void AddNotDefinedError( + const string& element_name, + const Message& descriptor, + DescriptorPool::ErrorCollector::ErrorLocation location, + const string& undefined_symbol); + + // Silly helper which determines if the given file is in the given package. + // I.e., either file->package() == package_name or file->package() is a + // nested package within package_name. + bool IsInPackage(const FileDescriptor* file, const string& package_name); + + // Like tables_->FindSymbol(), but additionally: + // - Search the pool's underlay if not found in tables_. + // - Insure that the resulting Symbol is from one of the file's declared + // dependencies. + Symbol FindSymbol(const string& name); + + // Like FindSymbol() but does not require that the symbol is in one of the + // file's declared dependencies. + Symbol FindSymbolNotEnforcingDeps(const string& name); + + // Like FindSymbol(), but looks up the name relative to some other symbol + // name. This first searches siblings of relative_to, then siblings of its + // parents, etc. For example, LookupSymbol("foo.bar", "baz.qux.corge") makes + // the following calls, returning the first non-null result: + // FindSymbol("baz.qux.foo.bar"), FindSymbol("baz.foo.bar"), + // FindSymbol("foo.bar"). If AllowUnknownDependencies() has been called + // on the DescriptorPool, this will generate a placeholder type if + // the name is not found (unless the name itself is malformed). The + // placeholder_type parameter indicates what kind of placeholder should be + // constructed in this case. The resolve_mode parameter determines whether + // any symbol is returned, or only symbols that are types. Note, however, + // that LookupSymbol may still return a non-type symbol in LOOKUP_TYPES mode, + // if it believes that's all it could refer to. The caller should always + // check that it receives the type of symbol it was expecting. + enum PlaceholderType { + PLACEHOLDER_MESSAGE, + PLACEHOLDER_ENUM, + PLACEHOLDER_EXTENDABLE_MESSAGE + }; + enum ResolveMode { + LOOKUP_ALL, LOOKUP_TYPES + }; + Symbol LookupSymbol(const string& name, const string& relative_to, + PlaceholderType placeholder_type = PLACEHOLDER_MESSAGE, + ResolveMode resolve_mode = LOOKUP_ALL); + + // Like LookupSymbol() but will not return a placeholder even if + // AllowUnknownDependencies() has been used. + Symbol LookupSymbolNoPlaceholder(const string& name, + const string& relative_to, + ResolveMode resolve_mode = LOOKUP_ALL); + + // Creates a placeholder type suitable for return from LookupSymbol(). May + // return kNullSymbol if the name is not a valid type name. + Symbol NewPlaceholder(const string& name, PlaceholderType placeholder_type); + + // Creates a placeholder file. Never returns NULL. This is used when an + // import is not found and AllowUnknownDependencies() is enabled. + const FileDescriptor* NewPlaceholderFile(const string& name); + + // Calls tables_->AddSymbol() and records an error if it fails. Returns + // true if successful or false if failed, though most callers can ignore + // the return value since an error has already been recorded. + bool AddSymbol(const string& full_name, + const void* parent, const string& name, + const Message& proto, Symbol symbol); + + // Like AddSymbol(), but succeeds if the symbol is already defined as long + // as the existing definition is also a package (because it's OK to define + // the same package in two different files). Also adds all parents of the + // packgae to the symbol table (e.g. AddPackage("foo.bar", ...) will add + // "foo.bar" and "foo" to the table). + void AddPackage(const string& name, const Message& proto, + const FileDescriptor* file); + + // Checks that the symbol name contains only alphanumeric characters and + // underscores. Records an error otherwise. + void ValidateSymbolName(const string& name, const string& full_name, + const Message& proto); + + // Like ValidateSymbolName(), but the name is allowed to contain periods and + // an error is indicated by returning false (not recording the error). + bool ValidateQualifiedName(const string& name); + + // Used by BUILD_ARRAY macro (below) to avoid having to have the type + // specified as a macro parameter. + template + inline void AllocateArray(int size, Type** output) { + *output = tables_->AllocateArray(size); + } + + // Allocates a copy of orig_options in tables_ and stores it in the + // descriptor. Remembers its uninterpreted options, to be interpreted + // later. DescriptorT must be one of the Descriptor messages from + // descriptor.proto. + template void AllocateOptions( + const typename DescriptorT::OptionsType& orig_options, + DescriptorT* descriptor); + // Specialization for FileOptions. + void AllocateOptions(const FileOptions& orig_options, + FileDescriptor* descriptor); + + // Implementation for AllocateOptions(). Don't call this directly. + template void AllocateOptionsImpl( + const string& name_scope, + const string& element_name, + const typename DescriptorT::OptionsType& orig_options, + DescriptorT* descriptor); + + // These methods all have the same signature for the sake of the BUILD_ARRAY + // macro, below. + void BuildMessage(const DescriptorProto& proto, + const Descriptor* parent, + Descriptor* result); + void BuildFieldOrExtension(const FieldDescriptorProto& proto, + const Descriptor* parent, + FieldDescriptor* result, + bool is_extension); + void BuildField(const FieldDescriptorProto& proto, + const Descriptor* parent, + FieldDescriptor* result) { + BuildFieldOrExtension(proto, parent, result, false); + } + void BuildExtension(const FieldDescriptorProto& proto, + const Descriptor* parent, + FieldDescriptor* result) { + BuildFieldOrExtension(proto, parent, result, true); + } + void BuildExtensionRange(const DescriptorProto::ExtensionRange& proto, + const Descriptor* parent, + Descriptor::ExtensionRange* result); + void BuildEnum(const EnumDescriptorProto& proto, + const Descriptor* parent, + EnumDescriptor* result); + void BuildEnumValue(const EnumValueDescriptorProto& proto, + const EnumDescriptor* parent, + EnumValueDescriptor* result); + void BuildService(const ServiceDescriptorProto& proto, + const void* dummy, + ServiceDescriptor* result); + void BuildMethod(const MethodDescriptorProto& proto, + const ServiceDescriptor* parent, + MethodDescriptor* result); + + // Must be run only after building. + // + // NOTE: Options will not be available during cross-linking, as they + // have not yet been interpreted. Defer any handling of options to the + // Validate*Options methods. + void CrossLinkFile(FileDescriptor* file, const FileDescriptorProto& proto); + void CrossLinkMessage(Descriptor* message, const DescriptorProto& proto); + void CrossLinkField(FieldDescriptor* field, + const FieldDescriptorProto& proto); + void CrossLinkEnum(EnumDescriptor* enum_type, + const EnumDescriptorProto& proto); + void CrossLinkEnumValue(EnumValueDescriptor* enum_value, + const EnumValueDescriptorProto& proto); + void CrossLinkService(ServiceDescriptor* service, + const ServiceDescriptorProto& proto); + void CrossLinkMethod(MethodDescriptor* method, + const MethodDescriptorProto& proto); + + // Must be run only after cross-linking. + void InterpretOptions(); + + // A helper class for interpreting options. + class OptionInterpreter { + public: + // Creates an interpreter that operates in the context of the pool of the + // specified builder, which must not be NULL. We don't take ownership of the + // builder. + explicit OptionInterpreter(DescriptorBuilder* builder); + + ~OptionInterpreter(); + + // Interprets the uninterpreted options in the specified Options message. + // On error, calls AddError() on the underlying builder and returns false. + // Otherwise returns true. + bool InterpretOptions(OptionsToInterpret* options_to_interpret); + + class AggregateOptionFinder; + + private: + // Interprets uninterpreted_option_ on the specified message, which + // must be the mutable copy of the original options message to which + // uninterpreted_option_ belongs. + bool InterpretSingleOption(Message* options); + + // Adds the uninterpreted_option to the given options message verbatim. + // Used when AllowUnknownDependencies() is in effect and we can't find + // the option's definition. + void AddWithoutInterpreting(const UninterpretedOption& uninterpreted_option, + Message* options); + + // A recursive helper function that drills into the intermediate fields + // in unknown_fields to check if field innermost_field is set on the + // innermost message. Returns false and sets an error if so. + bool ExamineIfOptionIsSet( + vector::const_iterator intermediate_fields_iter, + vector::const_iterator intermediate_fields_end, + const FieldDescriptor* innermost_field, const string& debug_msg_name, + const UnknownFieldSet& unknown_fields); + + // Validates the value for the option field of the currently interpreted + // option and then sets it on the unknown_field. + bool SetOptionValue(const FieldDescriptor* option_field, + UnknownFieldSet* unknown_fields); + + // Parses an aggregate value for a CPPTYPE_MESSAGE option and + // saves it into *unknown_fields. + bool SetAggregateOption(const FieldDescriptor* option_field, + UnknownFieldSet* unknown_fields); + + // Convenience functions to set an int field the right way, depending on + // its wire type (a single int CppType can represent multiple wire types). + void SetInt32(int number, int32 value, FieldDescriptor::Type type, + UnknownFieldSet* unknown_fields); + void SetInt64(int number, int64 value, FieldDescriptor::Type type, + UnknownFieldSet* unknown_fields); + void SetUInt32(int number, uint32 value, FieldDescriptor::Type type, + UnknownFieldSet* unknown_fields); + void SetUInt64(int number, uint64 value, FieldDescriptor::Type type, + UnknownFieldSet* unknown_fields); + + // A helper function that adds an error at the specified location of the + // option we're currently interpreting, and returns false. + bool AddOptionError(DescriptorPool::ErrorCollector::ErrorLocation location, + const string& msg) { + builder_->AddError(options_to_interpret_->element_name, + *uninterpreted_option_, location, msg); + return false; + } + + // A helper function that adds an error at the location of the option name + // and returns false. + bool AddNameError(const string& msg) { + return AddOptionError(DescriptorPool::ErrorCollector::OPTION_NAME, msg); + } + + // A helper function that adds an error at the location of the option name + // and returns false. + bool AddValueError(const string& msg) { + return AddOptionError(DescriptorPool::ErrorCollector::OPTION_VALUE, msg); + } + + // We interpret against this builder's pool. Is never NULL. We don't own + // this pointer. + DescriptorBuilder* builder_; + + // The options we're currently interpreting, or NULL if we're not in a call + // to InterpretOptions. + const OptionsToInterpret* options_to_interpret_; + + // The option we're currently interpreting within options_to_interpret_, or + // NULL if we're not in a call to InterpretOptions(). This points to a + // submessage of the original option, not the mutable copy. Therefore we + // can use it to find locations recorded by the parser. + const UninterpretedOption* uninterpreted_option_; + + // Factory used to create the dynamic messages we need to parse + // any aggregate option values we encounter. + DynamicMessageFactory dynamic_factory_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(OptionInterpreter); + }; + + // Work-around for broken compilers: According to the C++ standard, + // OptionInterpreter should have access to the private members of any class + // which has declared DescriptorBuilder as a friend. Unfortunately some old + // versions of GCC and other compilers do not implement this correctly. So, + // we have to have these intermediate methods to provide access. We also + // redundantly declare OptionInterpreter a friend just to make things extra + // clear for these bad compilers. + friend class OptionInterpreter; + friend class OptionInterpreter::AggregateOptionFinder; + + static inline bool get_allow_unknown(const DescriptorPool* pool) { + return pool->allow_unknown_; + } + static inline bool get_is_placeholder(const Descriptor* descriptor) { + return descriptor->is_placeholder_; + } + static inline void assert_mutex_held(const DescriptorPool* pool) { + if (pool->mutex_ != NULL) { + pool->mutex_->AssertHeld(); + } + } + + // Must be run only after options have been interpreted. + // + // NOTE: Validation code must only reference the options in the mutable + // descriptors, which are the ones that have been interpreted. The const + // proto references are passed in only so they can be provided to calls to + // AddError(). Do not look at their options, which have not been interpreted. + void ValidateFileOptions(FileDescriptor* file, + const FileDescriptorProto& proto); + void ValidateMessageOptions(Descriptor* message, + const DescriptorProto& proto); + void ValidateFieldOptions(FieldDescriptor* field, + const FieldDescriptorProto& proto); + void ValidateEnumOptions(EnumDescriptor* enm, + const EnumDescriptorProto& proto); + void ValidateEnumValueOptions(EnumValueDescriptor* enum_value, + const EnumValueDescriptorProto& proto); + void ValidateServiceOptions(ServiceDescriptor* service, + const ServiceDescriptorProto& proto); + void ValidateMethodOptions(MethodDescriptor* method, + const MethodDescriptorProto& proto); + + void ValidateMapKey(FieldDescriptor* field, + const FieldDescriptorProto& proto); +}; + +const FileDescriptor* DescriptorPool::BuildFile( + const FileDescriptorProto& proto) { + GOOGLE_CHECK(fallback_database_ == NULL) + << "Cannot call BuildFile on a DescriptorPool that uses a " + "DescriptorDatabase. You must instead find a way to get your file " + "into the underlying database."; + GOOGLE_CHECK(mutex_ == NULL); // Implied by the above GOOGLE_CHECK. + return DescriptorBuilder(this, tables_.get(), NULL).BuildFile(proto); +} + +const FileDescriptor* DescriptorPool::BuildFileCollectingErrors( + const FileDescriptorProto& proto, + ErrorCollector* error_collector) { + GOOGLE_CHECK(fallback_database_ == NULL) + << "Cannot call BuildFile on a DescriptorPool that uses a " + "DescriptorDatabase. You must instead find a way to get your file " + "into the underlying database."; + GOOGLE_CHECK(mutex_ == NULL); // Implied by the above GOOGLE_CHECK. + return DescriptorBuilder(this, tables_.get(), + error_collector).BuildFile(proto); +} + +const FileDescriptor* DescriptorPool::BuildFileFromDatabase( + const FileDescriptorProto& proto) const { + mutex_->AssertHeld(); + return DescriptorBuilder(this, tables_.get(), + default_error_collector_).BuildFile(proto); +} + +DescriptorBuilder::DescriptorBuilder( + const DescriptorPool* pool, + DescriptorPool::Tables* tables, + DescriptorPool::ErrorCollector* error_collector) + : pool_(pool), + tables_(tables), + error_collector_(error_collector), + had_errors_(false), + possible_undeclared_dependency_(NULL) {} + +DescriptorBuilder::~DescriptorBuilder() {} + +void DescriptorBuilder::AddError( + const string& element_name, + const Message& descriptor, + DescriptorPool::ErrorCollector::ErrorLocation location, + const string& error) { + if (error_collector_ == NULL) { + if (!had_errors_) { + GOOGLE_LOG(ERROR) << "Invalid proto descriptor for file \"" << filename_ + << "\":"; + } + GOOGLE_LOG(ERROR) << " " << element_name << ": " << error; + } else { + error_collector_->AddError(filename_, element_name, + &descriptor, location, error); + } + had_errors_ = true; +} + +void DescriptorBuilder::AddNotDefinedError( + const string& element_name, + const Message& descriptor, + DescriptorPool::ErrorCollector::ErrorLocation location, + const string& undefined_symbol) { + if (possible_undeclared_dependency_ == NULL) { + AddError(element_name, descriptor, location, + "\"" + undefined_symbol + "\" is not defined."); + } else { + AddError(element_name, descriptor, location, + "\"" + possible_undeclared_dependency_name_ + + "\" seems to be defined in \"" + + possible_undeclared_dependency_->name() + "\", which is not " + "imported by \"" + filename_ + "\". To use it here, please " + "add the necessary import."); + } +} + +bool DescriptorBuilder::IsInPackage(const FileDescriptor* file, + const string& package_name) { + return HasPrefixString(file->package(), package_name) && + (file->package().size() == package_name.size() || + file->package()[package_name.size()] == '.'); +} + +Symbol DescriptorBuilder::FindSymbolNotEnforcingDeps(const string& name) { + Symbol result; + + // We need to search our pool and all its underlays. + const DescriptorPool* pool = pool_; + while (true) { + // If we are looking at an underlay, we must lock its mutex_, since we are + // accessing the underlay's tables_ dircetly. + MutexLockMaybe lock((pool == pool_) ? NULL : pool->mutex_); + + // Note that we don't have to check fallback_database_ here because the + // symbol has to be in one of its file's direct dependencies, and we have + // already loaded those by the time we get here. + result = pool->tables_->FindSymbol(name); + if (!result.IsNull()) break; + if (pool->underlay_ == NULL) return kNullSymbol; + pool = pool->underlay_; + } + + return result; +} + +Symbol DescriptorBuilder::FindSymbol(const string& name) { + Symbol result = FindSymbolNotEnforcingDeps(name); + + if (!pool_->enforce_dependencies_) { + // Hack for CompilerUpgrader. + return result; + } + + // Only find symbols which were defined in this file or one of its + // dependencies. + const FileDescriptor* file = result.GetFile(); + if (file == file_) return result; + for (int i = 0; i < file_->dependency_count(); i++) { + if (file == file_->dependency(i)) return result; + } + + if (result.type == Symbol::PACKAGE) { + // Arg, this is overcomplicated. The symbol is a package name. It could + // be that the package was defined in multiple files. result.GetFile() + // returns the first file we saw that used this package. We've determined + // that that file is not a direct dependency of the file we are currently + // building, but it could be that some other file which *is* a direct + // dependency also defines the same package. We can't really rule out this + // symbol unless none of the dependencies define it. + if (IsInPackage(file_, name)) return result; + for (int i = 0; i < file_->dependency_count(); i++) { + // Note: A dependency may be NULL if it was not found or had errors. + if (file_->dependency(i) != NULL && + IsInPackage(file_->dependency(i), name)) { + return result; + } + } + } + + possible_undeclared_dependency_ = file; + possible_undeclared_dependency_name_ = name; + return kNullSymbol; +} + +Symbol DescriptorBuilder::LookupSymbolNoPlaceholder( + const string& name, const string& relative_to, ResolveMode resolve_mode) { + possible_undeclared_dependency_ = NULL; + + if (name.size() > 0 && name[0] == '.') { + // Fully-qualified name. + return FindSymbol(name.substr(1)); + } + + // If name is something like "Foo.Bar.baz", and symbols named "Foo" are + // defined in multiple parent scopes, we only want to find "Bar.baz" in the + // innermost one. E.g., the following should produce an error: + // message Bar { message Baz {} } + // message Foo { + // message Bar { + // } + // optional Bar.Baz baz = 1; + // } + // So, we look for just "Foo" first, then look for "Bar.baz" within it if + // found. + int name_dot_pos = name.find_first_of('.'); + string first_part_of_name; + if (name_dot_pos == string::npos) { + first_part_of_name = name; + } else { + first_part_of_name = name.substr(0, name_dot_pos); + } + + string scope_to_try(relative_to); + + while (true) { + // Chop off the last component of the scope. + string::size_type dot_pos = scope_to_try.find_last_of('.'); + if (dot_pos == string::npos) { + return FindSymbol(name); + } else { + scope_to_try.erase(dot_pos); + } + + // Append ".first_part_of_name" and try to find. + string::size_type old_size = scope_to_try.size(); + scope_to_try.append(1, '.'); + scope_to_try.append(first_part_of_name); + Symbol result = FindSymbol(scope_to_try); + if (!result.IsNull()) { + if (first_part_of_name.size() < name.size()) { + // name is a compound symbol, of which we only found the first part. + // Now try to look up the rest of it. + if (result.IsAggregate()) { + scope_to_try.append(name, first_part_of_name.size(), + name.size() - first_part_of_name.size()); + return FindSymbol(scope_to_try); + } else { + // We found a symbol but it's not an aggregate. Continue the loop. + } + } else { + if (resolve_mode == LOOKUP_TYPES && !result.IsType()) { + // We found a symbol but it's not a type. Continue the loop. + } else { + return result; + } + } + } + + // Not found. Remove the name so we can try again. + scope_to_try.erase(old_size); + } +} + +Symbol DescriptorBuilder::LookupSymbol( + const string& name, const string& relative_to, + PlaceholderType placeholder_type, ResolveMode resolve_mode) { + Symbol result = LookupSymbolNoPlaceholder( + name, relative_to, resolve_mode); + if (result.IsNull() && pool_->allow_unknown_) { + // Not found, but AllowUnknownDependencies() is enabled. Return a + // placeholder instead. + result = NewPlaceholder(name, placeholder_type); + } + return result; +} + +Symbol DescriptorBuilder::NewPlaceholder(const string& name, + PlaceholderType placeholder_type) { + // Compute names. + const string* placeholder_full_name; + const string* placeholder_name; + const string* placeholder_package; + + if (!ValidateQualifiedName(name)) return kNullSymbol; + if (name[0] == '.') { + // Fully-qualified. + placeholder_full_name = tables_->AllocateString(name.substr(1)); + } else { + placeholder_full_name = tables_->AllocateString(name); + } + + string::size_type dotpos = placeholder_full_name->find_last_of('.'); + if (dotpos != string::npos) { + placeholder_package = tables_->AllocateString( + placeholder_full_name->substr(0, dotpos)); + placeholder_name = tables_->AllocateString( + placeholder_full_name->substr(dotpos + 1)); + } else { + placeholder_package = &kEmptyString; + placeholder_name = placeholder_full_name; + } + + // Create the placeholders. + FileDescriptor* placeholder_file = tables_->Allocate(); + memset(placeholder_file, 0, sizeof(*placeholder_file)); + + placeholder_file->name_ = + tables_->AllocateString(*placeholder_full_name + ".placeholder.proto"); + placeholder_file->package_ = placeholder_package; + placeholder_file->pool_ = pool_; + placeholder_file->options_ = &FileOptions::default_instance(); + placeholder_file->tables_ = &FileDescriptorTables::kEmpty; + // All other fields are zero or NULL. + + if (placeholder_type == PLACEHOLDER_ENUM) { + placeholder_file->enum_type_count_ = 1; + placeholder_file->enum_types_ = + tables_->AllocateArray(1); + + EnumDescriptor* placeholder_enum = &placeholder_file->enum_types_[0]; + memset(placeholder_enum, 0, sizeof(*placeholder_enum)); + + placeholder_enum->full_name_ = placeholder_full_name; + placeholder_enum->name_ = placeholder_name; + placeholder_enum->file_ = placeholder_file; + placeholder_enum->options_ = &EnumOptions::default_instance(); + placeholder_enum->is_placeholder_ = true; + placeholder_enum->is_unqualified_placeholder_ = (name[0] != '.'); + + // Enums must have at least one value. + placeholder_enum->value_count_ = 1; + placeholder_enum->values_ = tables_->AllocateArray(1); + + EnumValueDescriptor* placeholder_value = &placeholder_enum->values_[0]; + memset(placeholder_value, 0, sizeof(*placeholder_value)); + + placeholder_value->name_ = tables_->AllocateString("PLACEHOLDER_VALUE"); + // Note that enum value names are siblings of their type, not children. + placeholder_value->full_name_ = + placeholder_package->empty() ? placeholder_value->name_ : + tables_->AllocateString(*placeholder_package + ".PLACEHOLDER_VALUE"); + + placeholder_value->number_ = 0; + placeholder_value->type_ = placeholder_enum; + placeholder_value->options_ = &EnumValueOptions::default_instance(); + + return Symbol(placeholder_enum); + } else { + placeholder_file->message_type_count_ = 1; + placeholder_file->message_types_ = + tables_->AllocateArray(1); + + Descriptor* placeholder_message = &placeholder_file->message_types_[0]; + memset(placeholder_message, 0, sizeof(*placeholder_message)); + + placeholder_message->full_name_ = placeholder_full_name; + placeholder_message->name_ = placeholder_name; + placeholder_message->file_ = placeholder_file; + placeholder_message->options_ = &MessageOptions::default_instance(); + placeholder_message->is_placeholder_ = true; + placeholder_message->is_unqualified_placeholder_ = (name[0] != '.'); + + if (placeholder_type == PLACEHOLDER_EXTENDABLE_MESSAGE) { + placeholder_message->extension_range_count_ = 1; + placeholder_message->extension_ranges_ = + tables_->AllocateArray(1); + placeholder_message->extension_ranges_->start = 1; + // kMaxNumber + 1 because ExtensionRange::end is exclusive. + placeholder_message->extension_ranges_->end = + FieldDescriptor::kMaxNumber + 1; + } + + return Symbol(placeholder_message); + } +} + +const FileDescriptor* DescriptorBuilder::NewPlaceholderFile( + const string& name) { + FileDescriptor* placeholder = tables_->Allocate(); + memset(placeholder, 0, sizeof(*placeholder)); + + placeholder->name_ = tables_->AllocateString(name); + placeholder->package_ = &kEmptyString; + placeholder->pool_ = pool_; + placeholder->options_ = &FileOptions::default_instance(); + placeholder->tables_ = &FileDescriptorTables::kEmpty; + // All other fields are zero or NULL. + + return placeholder; +} + +bool DescriptorBuilder::AddSymbol( + const string& full_name, const void* parent, const string& name, + const Message& proto, Symbol symbol) { + // If the caller passed NULL for the parent, the symbol is at file scope. + // Use its file as the parent instead. + if (parent == NULL) parent = file_; + + if (tables_->AddSymbol(full_name, symbol)) { + if (!file_tables_->AddAliasUnderParent(parent, name, symbol)) { + GOOGLE_LOG(DFATAL) << "\"" << full_name << "\" not previously defined in " + "symbols_by_name_, but was defined in symbols_by_parent_; " + "this shouldn't be possible."; + return false; + } + return true; + } else { + const FileDescriptor* other_file = tables_->FindSymbol(full_name).GetFile(); + if (other_file == file_) { + string::size_type dot_pos = full_name.find_last_of('.'); + if (dot_pos == string::npos) { + AddError(full_name, proto, DescriptorPool::ErrorCollector::NAME, + "\"" + full_name + "\" is already defined."); + } else { + AddError(full_name, proto, DescriptorPool::ErrorCollector::NAME, + "\"" + full_name.substr(dot_pos + 1) + + "\" is already defined in \"" + + full_name.substr(0, dot_pos) + "\"."); + } + } else { + // Symbol seems to have been defined in a different file. + AddError(full_name, proto, DescriptorPool::ErrorCollector::NAME, + "\"" + full_name + "\" is already defined in file \"" + + other_file->name() + "\"."); + } + return false; + } +} + +void DescriptorBuilder::AddPackage( + const string& name, const Message& proto, const FileDescriptor* file) { + if (tables_->AddSymbol(name, Symbol(file))) { + // Success. Also add parent package, if any. + string::size_type dot_pos = name.find_last_of('.'); + if (dot_pos == string::npos) { + // No parents. + ValidateSymbolName(name, name, proto); + } else { + // Has parent. + string* parent_name = tables_->AllocateString(name.substr(0, dot_pos)); + AddPackage(*parent_name, proto, file); + ValidateSymbolName(name.substr(dot_pos + 1), name, proto); + } + } else { + Symbol existing_symbol = tables_->FindSymbol(name); + // It's OK to redefine a package. + if (existing_symbol.type != Symbol::PACKAGE) { + // Symbol seems to have been defined in a different file. + AddError(name, proto, DescriptorPool::ErrorCollector::NAME, + "\"" + name + "\" is already defined (as something other than " + "a package) in file \"" + existing_symbol.GetFile()->name() + + "\"."); + } + } +} + +void DescriptorBuilder::ValidateSymbolName( + const string& name, const string& full_name, const Message& proto) { + if (name.empty()) { + AddError(full_name, proto, DescriptorPool::ErrorCollector::NAME, + "Missing name."); + } else { + for (int i = 0; i < name.size(); i++) { + // I don't trust isalnum() due to locales. :( + if ((name[i] < 'a' || 'z' < name[i]) && + (name[i] < 'A' || 'Z' < name[i]) && + (name[i] < '0' || '9' < name[i]) && + (name[i] != '_')) { + AddError(full_name, proto, DescriptorPool::ErrorCollector::NAME, + "\"" + name + "\" is not a valid identifier."); + } + } + } +} + +bool DescriptorBuilder::ValidateQualifiedName(const string& name) { + bool last_was_period = false; + + for (int i = 0; i < name.size(); i++) { + // I don't trust isalnum() due to locales. :( + if (('a' <= name[i] && name[i] <= 'z') || + ('A' <= name[i] && name[i] <= 'Z') || + ('0' <= name[i] && name[i] <= '9') || + (name[i] == '_')) { + last_was_period = false; + } else if (name[i] == '.') { + if (last_was_period) return false; + last_was_period = true; + } else { + return false; + } + } + + return !name.empty() && !last_was_period; +} + +// ------------------------------------------------------------------- + +// This generic implementation is good for all descriptors except +// FileDescriptor. +template void DescriptorBuilder::AllocateOptions( + const typename DescriptorT::OptionsType& orig_options, + DescriptorT* descriptor) { + AllocateOptionsImpl(descriptor->full_name(), descriptor->full_name(), + orig_options, descriptor); +} + +// We specialize for FileDescriptor. +void DescriptorBuilder::AllocateOptions(const FileOptions& orig_options, + FileDescriptor* descriptor) { + // We add the dummy token so that LookupSymbol does the right thing. + AllocateOptionsImpl(descriptor->package() + ".dummy", descriptor->name(), + orig_options, descriptor); +} + +template void DescriptorBuilder::AllocateOptionsImpl( + const string& name_scope, + const string& element_name, + const typename DescriptorT::OptionsType& orig_options, + DescriptorT* descriptor) { + // We need to use a dummy pointer to work around a bug in older versions of + // GCC. Otherwise, the following two lines could be replaced with: + // typename DescriptorT::OptionsType* options = + // tables_->AllocateMessage(); + typename DescriptorT::OptionsType* const dummy = NULL; + typename DescriptorT::OptionsType* options = tables_->AllocateMessage(dummy); + options->CopyFrom(orig_options); + descriptor->options_ = options; + + // Don't add to options_to_interpret_ unless there were uninterpreted + // options. This not only avoids unnecessary work, but prevents a + // bootstrapping problem when building descriptors for descriptor.proto. + // descriptor.proto does not contain any uninterpreted options, but + // attempting to interpret options anyway will cause + // OptionsType::GetDescriptor() to be called which may then deadlock since + // we're still trying to build it. + if (options->uninterpreted_option_size() > 0) { + options_to_interpret_.push_back( + OptionsToInterpret(name_scope, element_name, &orig_options, options)); + } +} + + +// A common pattern: We want to convert a repeated field in the descriptor +// to an array of values, calling some method to build each value. +#define BUILD_ARRAY(INPUT, OUTPUT, NAME, METHOD, PARENT) \ + OUTPUT->NAME##_count_ = INPUT.NAME##_size(); \ + AllocateArray(INPUT.NAME##_size(), &OUTPUT->NAME##s_); \ + for (int i = 0; i < INPUT.NAME##_size(); i++) { \ + METHOD(INPUT.NAME(i), PARENT, OUTPUT->NAME##s_ + i); \ + } + +const FileDescriptor* DescriptorBuilder::BuildFile( + const FileDescriptorProto& proto) { + filename_ = proto.name(); + + // Check if the file already exists and is identical to the one being built. + // Note: This only works if the input is canonical -- that is, it + // fully-qualifies all type names, has no UninterpretedOptions, etc. + // This is fine, because this idempotency "feature" really only exists to + // accomodate one hack in the proto1->proto2 migration layer. + const FileDescriptor* existing_file = tables_->FindFile(filename_); + if (existing_file != NULL) { + // File already in pool. Compare the existing one to the input. + FileDescriptorProto existing_proto; + existing_file->CopyTo(&existing_proto); + if (existing_proto.SerializeAsString() == proto.SerializeAsString()) { + // They're identical. Return the existing descriptor. + return existing_file; + } + + // Not a match. The error will be detected and handled later. + } + + // Check to see if this file is already on the pending files list. + // TODO(kenton): Allow recursive imports? It may not work with some + // (most?) programming languages. E.g., in C++, a forward declaration + // of a type is not sufficient to allow it to be used even in a + // generated header file due to inlining. This could perhaps be + // worked around using tricks involving inserting #include statements + // mid-file, but that's pretty ugly, and I'm pretty sure there are + // some languages out there that do not allow recursive dependencies + // at all. + for (int i = 0; i < tables_->pending_files_.size(); i++) { + if (tables_->pending_files_[i] == proto.name()) { + string error_message("File recursively imports itself: "); + for (; i < tables_->pending_files_.size(); i++) { + error_message.append(tables_->pending_files_[i]); + error_message.append(" -> "); + } + error_message.append(proto.name()); + + AddError(proto.name(), proto, DescriptorPool::ErrorCollector::OTHER, + error_message); + return NULL; + } + } + + // If we have a fallback_database_, attempt to load all dependencies now, + // before checkpointing tables_. This avoids confusion with recursive + // checkpoints. + if (pool_->fallback_database_ != NULL) { + tables_->pending_files_.push_back(proto.name()); + for (int i = 0; i < proto.dependency_size(); i++) { + if (tables_->FindFile(proto.dependency(i)) == NULL && + (pool_->underlay_ == NULL || + pool_->underlay_->FindFileByName(proto.dependency(i)) == NULL)) { + // We don't care what this returns since we'll find out below anyway. + pool_->TryFindFileInFallbackDatabase(proto.dependency(i)); + } + } + tables_->pending_files_.pop_back(); + } + + // Checkpoint the tables so that we can roll back if something goes wrong. + tables_->Checkpoint(); + + FileDescriptor* result = tables_->Allocate(); + file_ = result; + + file_tables_ = tables_->AllocateFileTables(); + file_->tables_ = file_tables_; + + if (!proto.has_name()) { + AddError("", proto, DescriptorPool::ErrorCollector::OTHER, + "Missing field: FileDescriptorProto.name."); + } + + result->name_ = tables_->AllocateString(proto.name()); + if (proto.has_package()) { + result->package_ = tables_->AllocateString(proto.package()); + } else { + // We cannot rely on proto.package() returning a valid string if + // proto.has_package() is false, because we might be running at static + // initialization time, in which case default values have not yet been + // initialized. + result->package_ = tables_->AllocateString(""); + } + result->pool_ = pool_; + + // Add to tables. + if (!tables_->AddFile(result)) { + AddError(proto.name(), proto, DescriptorPool::ErrorCollector::OTHER, + "A file with this name is already in the pool."); + // Bail out early so that if this is actually the exact same file, we + // don't end up reporting that every single symbol is already defined. + tables_->Rollback(); + return NULL; + } + if (!result->package().empty()) { + AddPackage(result->package(), proto, result); + } + + // Make sure all dependencies are loaded. + set seen_dependencies; + result->dependency_count_ = proto.dependency_size(); + result->dependencies_ = + tables_->AllocateArray(proto.dependency_size()); + for (int i = 0; i < proto.dependency_size(); i++) { + if (!seen_dependencies.insert(proto.dependency(i)).second) { + AddError(proto.name(), proto, + DescriptorPool::ErrorCollector::OTHER, + "Import \"" + proto.dependency(i) + "\" was listed twice."); + } + + const FileDescriptor* dependency = tables_->FindFile(proto.dependency(i)); + if (dependency == NULL && pool_->underlay_ != NULL) { + dependency = pool_->underlay_->FindFileByName(proto.dependency(i)); + } + + if (dependency == NULL) { + if (pool_->allow_unknown_) { + dependency = NewPlaceholderFile(proto.dependency(i)); + } else { + string message; + if (pool_->fallback_database_ == NULL) { + message = "Import \"" + proto.dependency(i) + + "\" has not been loaded."; + } else { + message = "Import \"" + proto.dependency(i) + + "\" was not found or had errors."; + } + AddError(proto.name(), proto, + DescriptorPool::ErrorCollector::OTHER, + message); + } + } + + result->dependencies_[i] = dependency; + } + + // Convert children. + BUILD_ARRAY(proto, result, message_type, BuildMessage , NULL); + BUILD_ARRAY(proto, result, enum_type , BuildEnum , NULL); + BUILD_ARRAY(proto, result, service , BuildService , NULL); + BUILD_ARRAY(proto, result, extension , BuildExtension, NULL); + + // Copy options. + if (!proto.has_options()) { + result->options_ = NULL; // Will set to default_instance later. + } else { + AllocateOptions(proto.options(), result); + } + + // Note that the following steps must occur in exactly the specified order. + + // Cross-link. + CrossLinkFile(result, proto); + + // Interpret any remaining uninterpreted options gathered into + // options_to_interpret_ during descriptor building. Cross-linking has made + // extension options known, so all interpretations should now succeed. + if (!had_errors_) { + OptionInterpreter option_interpreter(this); + for (vector::iterator iter = + options_to_interpret_.begin(); + iter != options_to_interpret_.end(); ++iter) { + option_interpreter.InterpretOptions(&(*iter)); + } + options_to_interpret_.clear(); + } + + // Validate options. + if (!had_errors_) { + ValidateFileOptions(result, proto); + } + + if (had_errors_) { + tables_->Rollback(); + return NULL; + } else { + tables_->Checkpoint(); + return result; + } +} + +void DescriptorBuilder::BuildMessage(const DescriptorProto& proto, + const Descriptor* parent, + Descriptor* result) { + const string& scope = (parent == NULL) ? + file_->package() : parent->full_name(); + string* full_name = tables_->AllocateString(scope); + if (!full_name->empty()) full_name->append(1, '.'); + full_name->append(proto.name()); + + ValidateSymbolName(proto.name(), *full_name, proto); + + result->name_ = tables_->AllocateString(proto.name()); + result->full_name_ = full_name; + result->file_ = file_; + result->containing_type_ = parent; + result->is_placeholder_ = false; + result->is_unqualified_placeholder_ = false; + + BUILD_ARRAY(proto, result, field , BuildField , result); + BUILD_ARRAY(proto, result, nested_type , BuildMessage , result); + BUILD_ARRAY(proto, result, enum_type , BuildEnum , result); + BUILD_ARRAY(proto, result, extension_range, BuildExtensionRange, result); + BUILD_ARRAY(proto, result, extension , BuildExtension , result); + + // Copy options. + if (!proto.has_options()) { + result->options_ = NULL; // Will set to default_instance later. + } else { + AllocateOptions(proto.options(), result); + } + + AddSymbol(result->full_name(), parent, result->name(), + proto, Symbol(result)); + + // Check that no fields have numbers in extension ranges. + for (int i = 0; i < result->field_count(); i++) { + const FieldDescriptor* field = result->field(i); + for (int j = 0; j < result->extension_range_count(); j++) { + const Descriptor::ExtensionRange* range = result->extension_range(j); + if (range->start <= field->number() && field->number() < range->end) { + AddError(field->full_name(), proto.extension_range(j), + DescriptorPool::ErrorCollector::NUMBER, + strings::Substitute( + "Extension range $0 to $1 includes field \"$2\" ($3).", + range->start, range->end - 1, + field->name(), field->number())); + } + } + } + + // Check that extension ranges don't overlap. + for (int i = 0; i < result->extension_range_count(); i++) { + const Descriptor::ExtensionRange* range1 = result->extension_range(i); + for (int j = i + 1; j < result->extension_range_count(); j++) { + const Descriptor::ExtensionRange* range2 = result->extension_range(j); + if (range1->end > range2->start && range2->end > range1->start) { + AddError(result->full_name(), proto.extension_range(j), + DescriptorPool::ErrorCollector::NUMBER, + strings::Substitute("Extension range $0 to $1 overlaps with " + "already-defined range $2 to $3.", + range2->start, range2->end - 1, + range1->start, range1->end - 1)); + } + } + } +} + +void DescriptorBuilder::BuildFieldOrExtension(const FieldDescriptorProto& proto, + const Descriptor* parent, + FieldDescriptor* result, + bool is_extension) { + const string& scope = (parent == NULL) ? + file_->package() : parent->full_name(); + string* full_name = tables_->AllocateString(scope); + if (!full_name->empty()) full_name->append(1, '.'); + full_name->append(proto.name()); + + ValidateSymbolName(proto.name(), *full_name, proto); + + result->name_ = tables_->AllocateString(proto.name()); + result->full_name_ = full_name; + result->file_ = file_; + result->number_ = proto.number(); + result->is_extension_ = is_extension; + + // If .proto files follow the style guide then the name should already be + // lower-cased. If that's the case we can just reuse the string we already + // allocated rather than allocate a new one. + string lowercase_name(proto.name()); + LowerString(&lowercase_name); + if (lowercase_name == proto.name()) { + result->lowercase_name_ = result->name_; + } else { + result->lowercase_name_ = tables_->AllocateString(lowercase_name); + } + + // Don't bother with the above optimization for camel-case names since + // .proto files that follow the guide shouldn't be using names in this + // format, so the optimization wouldn't help much. + result->camelcase_name_ = tables_->AllocateString(ToCamelCase(proto.name())); + + // Some compilers do not allow static_cast directly between two enum types, + // so we must cast to int first. + result->type_ = static_cast( + implicit_cast(proto.type())); + result->label_ = static_cast( + implicit_cast(proto.label())); + + // Some of these may be filled in when cross-linking. + result->containing_type_ = NULL; + result->extension_scope_ = NULL; + result->experimental_map_key_ = NULL; + result->message_type_ = NULL; + result->enum_type_ = NULL; + + result->has_default_value_ = proto.has_default_value(); + if (proto.has_default_value() && result->is_repeated()) { + AddError(result->full_name(), proto, + DescriptorPool::ErrorCollector::DEFAULT_VALUE, + "Repeated fields can't have default values."); + } + + if (proto.has_type()) { + if (proto.has_default_value()) { + char* end_pos = NULL; + switch (result->cpp_type()) { + case FieldDescriptor::CPPTYPE_INT32: + result->default_value_int32_ = + strtol(proto.default_value().c_str(), &end_pos, 0); + break; + case FieldDescriptor::CPPTYPE_INT64: + result->default_value_int64_ = + strto64(proto.default_value().c_str(), &end_pos, 0); + break; + case FieldDescriptor::CPPTYPE_UINT32: + result->default_value_uint32_ = + strtoul(proto.default_value().c_str(), &end_pos, 0); + break; + case FieldDescriptor::CPPTYPE_UINT64: + result->default_value_uint64_ = + strtou64(proto.default_value().c_str(), &end_pos, 0); + break; + case FieldDescriptor::CPPTYPE_FLOAT: + if (proto.default_value() == "inf") { + result->default_value_float_ = numeric_limits::infinity(); + } else if (proto.default_value() == "-inf") { + result->default_value_float_ = -numeric_limits::infinity(); + } else if (proto.default_value() == "nan") { + result->default_value_float_ = numeric_limits::quiet_NaN(); + } else { + result->default_value_float_ = + NoLocaleStrtod(proto.default_value().c_str(), &end_pos); + } + break; + case FieldDescriptor::CPPTYPE_DOUBLE: + if (proto.default_value() == "inf") { + result->default_value_double_ = numeric_limits::infinity(); + } else if (proto.default_value() == "-inf") { + result->default_value_double_ = -numeric_limits::infinity(); + } else if (proto.default_value() == "nan") { + result->default_value_double_ = numeric_limits::quiet_NaN(); + } else { + result->default_value_double_ = + NoLocaleStrtod(proto.default_value().c_str(), &end_pos); + } + break; + case FieldDescriptor::CPPTYPE_BOOL: + if (proto.default_value() == "true") { + result->default_value_bool_ = true; + } else if (proto.default_value() == "false") { + result->default_value_bool_ = false; + } else { + AddError(result->full_name(), proto, + DescriptorPool::ErrorCollector::DEFAULT_VALUE, + "Boolean default must be true or false."); + } + break; + case FieldDescriptor::CPPTYPE_ENUM: + // This will be filled in when cross-linking. + result->default_value_enum_ = NULL; + break; + case FieldDescriptor::CPPTYPE_STRING: + if (result->type() == FieldDescriptor::TYPE_BYTES) { + result->default_value_string_ = tables_->AllocateString( + UnescapeCEscapeString(proto.default_value())); + } else { + result->default_value_string_ = + tables_->AllocateString(proto.default_value()); + } + break; + case FieldDescriptor::CPPTYPE_MESSAGE: + AddError(result->full_name(), proto, + DescriptorPool::ErrorCollector::DEFAULT_VALUE, + "Messages can't have default values."); + result->has_default_value_ = false; + break; + } + + if (end_pos != NULL) { + // end_pos is only set non-NULL by the parsers for numeric types, above. + // This checks that the default was non-empty and had no extra junk + // after the end of the number. + if (proto.default_value().empty() || *end_pos != '\0') { + AddError(result->full_name(), proto, + DescriptorPool::ErrorCollector::DEFAULT_VALUE, + "Couldn't parse default value."); + } + } + } else { + // No explicit default value + switch (result->cpp_type()) { + case FieldDescriptor::CPPTYPE_INT32: + result->default_value_int32_ = 0; + break; + case FieldDescriptor::CPPTYPE_INT64: + result->default_value_int64_ = 0; + break; + case FieldDescriptor::CPPTYPE_UINT32: + result->default_value_uint32_ = 0; + break; + case FieldDescriptor::CPPTYPE_UINT64: + result->default_value_uint64_ = 0; + break; + case FieldDescriptor::CPPTYPE_FLOAT: + result->default_value_float_ = 0.0f; + break; + case FieldDescriptor::CPPTYPE_DOUBLE: + result->default_value_double_ = 0.0; + break; + case FieldDescriptor::CPPTYPE_BOOL: + result->default_value_bool_ = false; + break; + case FieldDescriptor::CPPTYPE_ENUM: + // This will be filled in when cross-linking. + result->default_value_enum_ = NULL; + break; + case FieldDescriptor::CPPTYPE_STRING: + result->default_value_string_ = &kEmptyString; + break; + case FieldDescriptor::CPPTYPE_MESSAGE: + break; + } + } + } + + if (result->number() <= 0) { + AddError(result->full_name(), proto, DescriptorPool::ErrorCollector::NUMBER, + "Field numbers must be positive integers."); + } else if (result->number() > FieldDescriptor::kMaxNumber) { + AddError(result->full_name(), proto, DescriptorPool::ErrorCollector::NUMBER, + strings::Substitute("Field numbers cannot be greater than $0.", + FieldDescriptor::kMaxNumber)); + } else if (result->number() >= FieldDescriptor::kFirstReservedNumber && + result->number() <= FieldDescriptor::kLastReservedNumber) { + AddError(result->full_name(), proto, DescriptorPool::ErrorCollector::NUMBER, + strings::Substitute( + "Field numbers $0 through $1 are reserved for the protocol " + "buffer library implementation.", + FieldDescriptor::kFirstReservedNumber, + FieldDescriptor::kLastReservedNumber)); + } + + if (is_extension) { + if (!proto.has_extendee()) { + AddError(result->full_name(), proto, + DescriptorPool::ErrorCollector::EXTENDEE, + "FieldDescriptorProto.extendee not set for extension field."); + } + + result->extension_scope_ = parent; + } else { + if (proto.has_extendee()) { + AddError(result->full_name(), proto, + DescriptorPool::ErrorCollector::EXTENDEE, + "FieldDescriptorProto.extendee set for non-extension field."); + } + + result->containing_type_ = parent; + } + + // Copy options. + if (!proto.has_options()) { + result->options_ = NULL; // Will set to default_instance later. + } else { + AllocateOptions(proto.options(), result); + } + + AddSymbol(result->full_name(), parent, result->name(), + proto, Symbol(result)); +} + +void DescriptorBuilder::BuildExtensionRange( + const DescriptorProto::ExtensionRange& proto, + const Descriptor* parent, + Descriptor::ExtensionRange* result) { + result->start = proto.start(); + result->end = proto.end(); + if (result->start <= 0) { + AddError(parent->full_name(), proto, + DescriptorPool::ErrorCollector::NUMBER, + "Extension numbers must be positive integers."); + } + + if (result->end > FieldDescriptor::kMaxNumber + 1) { + AddError(parent->full_name(), proto, + DescriptorPool::ErrorCollector::NUMBER, + strings::Substitute("Extension numbers cannot be greater than $0.", + FieldDescriptor::kMaxNumber)); + } + + if (result->start >= result->end) { + AddError(parent->full_name(), proto, + DescriptorPool::ErrorCollector::NUMBER, + "Extension range end number must be greater than start number."); + } +} + +void DescriptorBuilder::BuildEnum(const EnumDescriptorProto& proto, + const Descriptor* parent, + EnumDescriptor* result) { + const string& scope = (parent == NULL) ? + file_->package() : parent->full_name(); + string* full_name = tables_->AllocateString(scope); + if (!full_name->empty()) full_name->append(1, '.'); + full_name->append(proto.name()); + + ValidateSymbolName(proto.name(), *full_name, proto); + + result->name_ = tables_->AllocateString(proto.name()); + result->full_name_ = full_name; + result->file_ = file_; + result->containing_type_ = parent; + result->is_placeholder_ = false; + result->is_unqualified_placeholder_ = false; + + if (proto.value_size() == 0) { + // We cannot allow enums with no values because this would mean there + // would be no valid default value for fields of this type. + AddError(result->full_name(), proto, + DescriptorPool::ErrorCollector::NAME, + "Enums must contain at least one value."); + } + + BUILD_ARRAY(proto, result, value, BuildEnumValue, result); + + // Copy options. + if (!proto.has_options()) { + result->options_ = NULL; // Will set to default_instance later. + } else { + AllocateOptions(proto.options(), result); + } + + AddSymbol(result->full_name(), parent, result->name(), + proto, Symbol(result)); +} + +void DescriptorBuilder::BuildEnumValue(const EnumValueDescriptorProto& proto, + const EnumDescriptor* parent, + EnumValueDescriptor* result) { + result->name_ = tables_->AllocateString(proto.name()); + result->number_ = proto.number(); + result->type_ = parent; + + // Note: full_name for enum values is a sibling to the parent's name, not a + // child of it. + string* full_name = tables_->AllocateString(*parent->full_name_); + full_name->resize(full_name->size() - parent->name_->size()); + full_name->append(*result->name_); + result->full_name_ = full_name; + + ValidateSymbolName(proto.name(), *full_name, proto); + + // Copy options. + if (!proto.has_options()) { + result->options_ = NULL; // Will set to default_instance later. + } else { + AllocateOptions(proto.options(), result); + } + + // Again, enum values are weird because we makes them appear as siblings + // of the enum type instead of children of it. So, we use + // parent->containing_type() as the value's parent. + bool added_to_outer_scope = + AddSymbol(result->full_name(), parent->containing_type(), result->name(), + proto, Symbol(result)); + + // However, we also want to be able to search for values within a single + // enum type, so we add it as a child of the enum type itself, too. + // Note: This could fail, but if it does, the error has already been + // reported by the above AddSymbol() call, so we ignore the return code. + bool added_to_inner_scope = + file_tables_->AddAliasUnderParent(parent, result->name(), Symbol(result)); + + if (added_to_inner_scope && !added_to_outer_scope) { + // This value did not conflict with any values defined in the same enum, + // but it did conflict with some other symbol defined in the enum type's + // scope. Let's print an additional error to explain this. + string outer_scope; + if (parent->containing_type() == NULL) { + outer_scope = file_->package(); + } else { + outer_scope = parent->containing_type()->full_name(); + } + + if (outer_scope.empty()) { + outer_scope = "the global scope"; + } else { + outer_scope = "\"" + outer_scope + "\""; + } + + AddError(result->full_name(), proto, + DescriptorPool::ErrorCollector::NAME, + "Note that enum values use C++ scoping rules, meaning that " + "enum values are siblings of their type, not children of it. " + "Therefore, \"" + result->name() + "\" must be unique within " + + outer_scope + ", not just within \"" + parent->name() + "\"."); + } + + // An enum is allowed to define two numbers that refer to the same value. + // FindValueByNumber() should return the first such value, so we simply + // ignore AddEnumValueByNumber()'s return code. + file_tables_->AddEnumValueByNumber(result); +} + +void DescriptorBuilder::BuildService(const ServiceDescriptorProto& proto, + const void* dummy, + ServiceDescriptor* result) { + string* full_name = tables_->AllocateString(file_->package()); + if (!full_name->empty()) full_name->append(1, '.'); + full_name->append(proto.name()); + + ValidateSymbolName(proto.name(), *full_name, proto); + + result->name_ = tables_->AllocateString(proto.name()); + result->full_name_ = full_name; + result->file_ = file_; + + BUILD_ARRAY(proto, result, method, BuildMethod, result); + + // Copy options. + if (!proto.has_options()) { + result->options_ = NULL; // Will set to default_instance later. + } else { + AllocateOptions(proto.options(), result); + } + + AddSymbol(result->full_name(), NULL, result->name(), + proto, Symbol(result)); +} + +void DescriptorBuilder::BuildMethod(const MethodDescriptorProto& proto, + const ServiceDescriptor* parent, + MethodDescriptor* result) { + result->name_ = tables_->AllocateString(proto.name()); + result->service_ = parent; + + string* full_name = tables_->AllocateString(parent->full_name()); + full_name->append(1, '.'); + full_name->append(*result->name_); + result->full_name_ = full_name; + + ValidateSymbolName(proto.name(), *full_name, proto); + + // These will be filled in when cross-linking. + result->input_type_ = NULL; + result->output_type_ = NULL; + + // Copy options. + if (!proto.has_options()) { + result->options_ = NULL; // Will set to default_instance later. + } else { + AllocateOptions(proto.options(), result); + } + + AddSymbol(result->full_name(), parent, result->name(), + proto, Symbol(result)); +} + +#undef BUILD_ARRAY + +// ------------------------------------------------------------------- + +void DescriptorBuilder::CrossLinkFile( + FileDescriptor* file, const FileDescriptorProto& proto) { + if (file->options_ == NULL) { + file->options_ = &FileOptions::default_instance(); + } + + for (int i = 0; i < file->message_type_count(); i++) { + CrossLinkMessage(&file->message_types_[i], proto.message_type(i)); + } + + for (int i = 0; i < file->extension_count(); i++) { + CrossLinkField(&file->extensions_[i], proto.extension(i)); + } + + for (int i = 0; i < file->enum_type_count(); i++) { + CrossLinkEnum(&file->enum_types_[i], proto.enum_type(i)); + } + + for (int i = 0; i < file->service_count(); i++) { + CrossLinkService(&file->services_[i], proto.service(i)); + } +} + +void DescriptorBuilder::CrossLinkMessage( + Descriptor* message, const DescriptorProto& proto) { + if (message->options_ == NULL) { + message->options_ = &MessageOptions::default_instance(); + } + + for (int i = 0; i < message->nested_type_count(); i++) { + CrossLinkMessage(&message->nested_types_[i], proto.nested_type(i)); + } + + for (int i = 0; i < message->enum_type_count(); i++) { + CrossLinkEnum(&message->enum_types_[i], proto.enum_type(i)); + } + + for (int i = 0; i < message->field_count(); i++) { + CrossLinkField(&message->fields_[i], proto.field(i)); + } + + for (int i = 0; i < message->extension_count(); i++) { + CrossLinkField(&message->extensions_[i], proto.extension(i)); + } +} + +void DescriptorBuilder::CrossLinkField( + FieldDescriptor* field, const FieldDescriptorProto& proto) { + if (field->options_ == NULL) { + field->options_ = &FieldOptions::default_instance(); + } + + if (proto.has_extendee()) { + Symbol extendee = LookupSymbol(proto.extendee(), field->full_name(), + PLACEHOLDER_EXTENDABLE_MESSAGE); + if (extendee.IsNull()) { + AddNotDefinedError(field->full_name(), proto, + DescriptorPool::ErrorCollector::EXTENDEE, + proto.extendee()); + return; + } else if (extendee.type != Symbol::MESSAGE) { + AddError(field->full_name(), proto, + DescriptorPool::ErrorCollector::EXTENDEE, + "\"" + proto.extendee() + "\" is not a message type."); + return; + } + field->containing_type_ = extendee.descriptor; + + if (!field->containing_type()->IsExtensionNumber(field->number())) { + AddError(field->full_name(), proto, + DescriptorPool::ErrorCollector::NUMBER, + strings::Substitute("\"$0\" does not declare $1 as an " + "extension number.", + field->containing_type()->full_name(), + field->number())); + } + } + + if (proto.has_type_name()) { + // Assume we are expecting a message type unless the proto contains some + // evidence that it expects an enum type. This only makes a difference if + // we end up creating a placeholder. + bool expecting_enum = (proto.type() == FieldDescriptorProto::TYPE_ENUM) || + proto.has_default_value(); + + Symbol type = + LookupSymbol(proto.type_name(), field->full_name(), + expecting_enum ? PLACEHOLDER_ENUM : PLACEHOLDER_MESSAGE, + LOOKUP_TYPES); + + if (type.IsNull()) { + AddNotDefinedError(field->full_name(), proto, + DescriptorPool::ErrorCollector::TYPE, + proto.type_name()); + return; + } + + if (!proto.has_type()) { + // Choose field type based on symbol. + if (type.type == Symbol::MESSAGE) { + field->type_ = FieldDescriptor::TYPE_MESSAGE; + } else if (type.type == Symbol::ENUM) { + field->type_ = FieldDescriptor::TYPE_ENUM; + } else { + AddError(field->full_name(), proto, + DescriptorPool::ErrorCollector::TYPE, + "\"" + proto.type_name() + "\" is not a type."); + return; + } + } + + if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + if (type.type != Symbol::MESSAGE) { + AddError(field->full_name(), proto, + DescriptorPool::ErrorCollector::TYPE, + "\"" + proto.type_name() + "\" is not a message type."); + return; + } + field->message_type_ = type.descriptor; + + if (field->has_default_value()) { + AddError(field->full_name(), proto, + DescriptorPool::ErrorCollector::DEFAULT_VALUE, + "Messages can't have default values."); + } + } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) { + if (type.type != Symbol::ENUM) { + AddError(field->full_name(), proto, + DescriptorPool::ErrorCollector::TYPE, + "\"" + proto.type_name() + "\" is not an enum type."); + return; + } + field->enum_type_ = type.enum_descriptor; + + if (field->enum_type()->is_placeholder_) { + // We can't look up default values for placeholder types. We'll have + // to just drop them. + field->has_default_value_ = false; + } + + if (field->has_default_value()) { + // We can't just use field->enum_type()->FindValueByName() here + // because that locks the pool's mutex, which we have already locked + // at this point. + Symbol default_value = + LookupSymbolNoPlaceholder(proto.default_value(), + field->enum_type()->full_name()); + + if (default_value.type == Symbol::ENUM_VALUE && + default_value.enum_value_descriptor->type() == field->enum_type()) { + field->default_value_enum_ = default_value.enum_value_descriptor; + } else { + AddError(field->full_name(), proto, + DescriptorPool::ErrorCollector::DEFAULT_VALUE, + "Enum type \"" + field->enum_type()->full_name() + + "\" has no value named \"" + proto.default_value() + "\"."); + } + } else if (field->enum_type()->value_count() > 0) { + // All enums must have at least one value, or we would have reported + // an error elsewhere. We use the first defined value as the default + // if a default is not explicitly defined. + field->default_value_enum_ = field->enum_type()->value(0); + } + } else { + AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE, + "Field with primitive type has type_name."); + } + } else { + if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE || + field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) { + AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE, + "Field with message or enum type missing type_name."); + } + } + + // Add the field to the fields-by-number table. + // Note: We have to do this *after* cross-linking because extensions do not + // know their containing type until now. + if (!file_tables_->AddFieldByNumber(field)) { + const FieldDescriptor* conflicting_field = + file_tables_->FindFieldByNumber(field->containing_type(), + field->number()); + if (field->is_extension()) { + AddError(field->full_name(), proto, + DescriptorPool::ErrorCollector::NUMBER, + strings::Substitute("Extension number $0 has already been used " + "in \"$1\" by extension \"$2\".", + field->number(), + field->containing_type()->full_name(), + conflicting_field->full_name())); + } else { + AddError(field->full_name(), proto, + DescriptorPool::ErrorCollector::NUMBER, + strings::Substitute("Field number $0 has already been used in " + "\"$1\" by field \"$2\".", + field->number(), + field->containing_type()->full_name(), + conflicting_field->name())); + } + } + + if (field->is_extension()) { + // No need for error checking: if the extension number collided, + // we've already been informed of it by the if() above. + tables_->AddExtension(field); + } + + // Add the field to the lowercase-name and camelcase-name tables. + file_tables_->AddFieldByStylizedNames(field); +} + +void DescriptorBuilder::CrossLinkEnum( + EnumDescriptor* enum_type, const EnumDescriptorProto& proto) { + if (enum_type->options_ == NULL) { + enum_type->options_ = &EnumOptions::default_instance(); + } + + for (int i = 0; i < enum_type->value_count(); i++) { + CrossLinkEnumValue(&enum_type->values_[i], proto.value(i)); + } +} + +void DescriptorBuilder::CrossLinkEnumValue( + EnumValueDescriptor* enum_value, const EnumValueDescriptorProto& proto) { + if (enum_value->options_ == NULL) { + enum_value->options_ = &EnumValueOptions::default_instance(); + } +} + +void DescriptorBuilder::CrossLinkService( + ServiceDescriptor* service, const ServiceDescriptorProto& proto) { + if (service->options_ == NULL) { + service->options_ = &ServiceOptions::default_instance(); + } + + for (int i = 0; i < service->method_count(); i++) { + CrossLinkMethod(&service->methods_[i], proto.method(i)); + } +} + +void DescriptorBuilder::CrossLinkMethod( + MethodDescriptor* method, const MethodDescriptorProto& proto) { + if (method->options_ == NULL) { + method->options_ = &MethodOptions::default_instance(); + } + + Symbol input_type = LookupSymbol(proto.input_type(), method->full_name()); + if (input_type.IsNull()) { + AddNotDefinedError(method->full_name(), proto, + DescriptorPool::ErrorCollector::INPUT_TYPE, + proto.input_type()); + } else if (input_type.type != Symbol::MESSAGE) { + AddError(method->full_name(), proto, + DescriptorPool::ErrorCollector::INPUT_TYPE, + "\"" + proto.input_type() + "\" is not a message type."); + } else { + method->input_type_ = input_type.descriptor; + } + + Symbol output_type = LookupSymbol(proto.output_type(), method->full_name()); + if (output_type.IsNull()) { + AddNotDefinedError(method->full_name(), proto, + DescriptorPool::ErrorCollector::OUTPUT_TYPE, + proto.output_type()); + } else if (output_type.type != Symbol::MESSAGE) { + AddError(method->full_name(), proto, + DescriptorPool::ErrorCollector::OUTPUT_TYPE, + "\"" + proto.output_type() + "\" is not a message type."); + } else { + method->output_type_ = output_type.descriptor; + } +} + +// ------------------------------------------------------------------- + +#define VALIDATE_OPTIONS_FROM_ARRAY(descriptor, array_name, type) \ + for (int i = 0; i < descriptor->array_name##_count(); ++i) { \ + Validate##type##Options(descriptor->array_name##s_ + i, \ + proto.array_name(i)); \ + } + +// Determine if the file uses optimize_for = LITE_RUNTIME, being careful to +// avoid problems that exist at init time. +static bool IsLite(const FileDescriptor* file) { + // TODO(kenton): I don't even remember how many of these conditions are + // actually possible. I'm just being super-safe. + return file != NULL && + &file->options() != NULL && + &file->options() != &FileOptions::default_instance() && + file->options().optimize_for() == FileOptions::LITE_RUNTIME; +} + +void DescriptorBuilder::ValidateFileOptions(FileDescriptor* file, + const FileDescriptorProto& proto) { + VALIDATE_OPTIONS_FROM_ARRAY(file, message_type, Message); + VALIDATE_OPTIONS_FROM_ARRAY(file, enum_type, Enum); + VALIDATE_OPTIONS_FROM_ARRAY(file, service, Service); + VALIDATE_OPTIONS_FROM_ARRAY(file, extension, Field); + + // Lite files can only be imported by other Lite files. + if (!IsLite(file)) { + for (int i = 0; i < file->dependency_count(); i++) { + if (IsLite(file->dependency(i))) { + AddError( + file->name(), proto, + DescriptorPool::ErrorCollector::OTHER, + "Files that do not use optimize_for = LITE_RUNTIME cannot import " + "files which do use this option. This file is not lite, but it " + "imports \"" + file->dependency(i)->name() + "\" which is."); + break; + } + } + } +} + +void DescriptorBuilder::ValidateMessageOptions(Descriptor* message, + const DescriptorProto& proto) { + VALIDATE_OPTIONS_FROM_ARRAY(message, field, Field); + VALIDATE_OPTIONS_FROM_ARRAY(message, nested_type, Message); + VALIDATE_OPTIONS_FROM_ARRAY(message, enum_type, Enum); + VALIDATE_OPTIONS_FROM_ARRAY(message, extension, Field); +} + +void DescriptorBuilder::ValidateFieldOptions(FieldDescriptor* field, + const FieldDescriptorProto& proto) { + if (field->options().has_experimental_map_key()) { + ValidateMapKey(field, proto); + } + + // Only repeated primitive fields may be packed. + if (field->options().packed() && !field->is_packable()) { + AddError( + field->full_name(), proto, + DescriptorPool::ErrorCollector::TYPE, + "[packed = true] can only be specified for repeated primitive fields."); + } + + // Note: Default instance may not yet be initialized here, so we have to + // avoid reading from it. + if (field->containing_type_ != NULL && + &field->containing_type()->options() != + &MessageOptions::default_instance() && + field->containing_type()->options().message_set_wire_format()) { + if (field->is_extension()) { + if (!field->is_optional() || + field->type() != FieldDescriptor::TYPE_MESSAGE) { + AddError(field->full_name(), proto, + DescriptorPool::ErrorCollector::TYPE, + "Extensions of MessageSets must be optional messages."); + } + } else { + AddError(field->full_name(), proto, + DescriptorPool::ErrorCollector::NAME, + "MessageSets cannot have fields, only extensions."); + } + } + + // Lite extensions can only be of Lite types. + if (IsLite(field->file()) && + field->containing_type_ != NULL && + !IsLite(field->containing_type()->file())) { + AddError(field->full_name(), proto, + DescriptorPool::ErrorCollector::EXTENDEE, + "Extensions to non-lite types can only be declared in non-lite " + "files. Note that you cannot extend a non-lite type to contain " + "a lite type, but the reverse is allowed."); + } +} + +void DescriptorBuilder::ValidateEnumOptions(EnumDescriptor* enm, + const EnumDescriptorProto& proto) { + VALIDATE_OPTIONS_FROM_ARRAY(enm, value, EnumValue); +} + +void DescriptorBuilder::ValidateEnumValueOptions( + EnumValueDescriptor* enum_value, const EnumValueDescriptorProto& proto) { + // Nothing to do so far. +} +void DescriptorBuilder::ValidateServiceOptions(ServiceDescriptor* service, + const ServiceDescriptorProto& proto) { + if (IsLite(service->file()) && + (service->file()->options().cc_generic_services() || + service->file()->options().java_generic_services())) { + AddError(service->full_name(), proto, + DescriptorPool::ErrorCollector::NAME, + "Files with optimize_for = LITE_RUNTIME cannot define services " + "unless you set both options cc_generic_services and " + "java_generic_sevices to false."); + } + + VALIDATE_OPTIONS_FROM_ARRAY(service, method, Method); +} + +void DescriptorBuilder::ValidateMethodOptions(MethodDescriptor* method, + const MethodDescriptorProto& proto) { + // Nothing to do so far. +} + +void DescriptorBuilder::ValidateMapKey(FieldDescriptor* field, + const FieldDescriptorProto& proto) { + if (!field->is_repeated()) { + AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE, + "map type is only allowed for repeated fields."); + return; + } + + if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) { + AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE, + "map type is only allowed for fields with a message type."); + return; + } + + const Descriptor* item_type = field->message_type(); + if (item_type == NULL) { + AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE, + "Could not find field type."); + return; + } + + // Find the field in item_type named by "experimental_map_key" + const string& key_name = field->options().experimental_map_key(); + const Symbol key_symbol = LookupSymbol( + key_name, + // We append ".key_name" to the containing type's name since + // LookupSymbol() searches for peers of the supplied name, not + // children of the supplied name. + item_type->full_name() + "." + key_name); + + if (key_symbol.IsNull() || key_symbol.field_descriptor->is_extension()) { + AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE, + "Could not find field named \"" + key_name + "\" in type \"" + + item_type->full_name() + "\"."); + return; + } + const FieldDescriptor* key_field = key_symbol.field_descriptor; + + if (key_field->is_repeated()) { + AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE, + "map_key must not name a repeated field."); + return; + } + + if (key_field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE, + "map key must name a scalar or string field."); + return; + } + + field->experimental_map_key_ = key_field; +} + +#undef VALIDATE_OPTIONS_FROM_ARRAY + +// ------------------------------------------------------------------- + +DescriptorBuilder::OptionInterpreter::OptionInterpreter( + DescriptorBuilder* builder) : builder_(builder) { + GOOGLE_CHECK(builder_); +} + +DescriptorBuilder::OptionInterpreter::~OptionInterpreter() { +} + +bool DescriptorBuilder::OptionInterpreter::InterpretOptions( + OptionsToInterpret* options_to_interpret) { + // Note that these may be in different pools, so we can't use the same + // descriptor and reflection objects on both. + Message* options = options_to_interpret->options; + const Message* original_options = options_to_interpret->original_options; + + bool failed = false; + options_to_interpret_ = options_to_interpret; + + // Find the uninterpreted_option field in the mutable copy of the options + // and clear them, since we're about to interpret them. + const FieldDescriptor* uninterpreted_options_field = + options->GetDescriptor()->FindFieldByName("uninterpreted_option"); + GOOGLE_CHECK(uninterpreted_options_field != NULL) + << "No field named \"uninterpreted_option\" in the Options proto."; + options->GetReflection()->ClearField(options, uninterpreted_options_field); + + // Find the uninterpreted_option field in the original options. + const FieldDescriptor* original_uninterpreted_options_field = + original_options->GetDescriptor()-> + FindFieldByName("uninterpreted_option"); + GOOGLE_CHECK(original_uninterpreted_options_field != NULL) + << "No field named \"uninterpreted_option\" in the Options proto."; + + const int num_uninterpreted_options = original_options->GetReflection()-> + FieldSize(*original_options, original_uninterpreted_options_field); + for (int i = 0; i < num_uninterpreted_options; ++i) { + uninterpreted_option_ = down_cast( + &original_options->GetReflection()->GetRepeatedMessage( + *original_options, original_uninterpreted_options_field, i)); + if (!InterpretSingleOption(options)) { + // Error already added by InterpretSingleOption(). + failed = true; + break; + } + } + // Reset these, so we don't have any dangling pointers. + uninterpreted_option_ = NULL; + options_to_interpret_ = NULL; + + if (!failed) { + // InterpretSingleOption() added the interpreted options in the + // UnknownFieldSet, in case the option isn't yet known to us. Now we + // serialize the options message and deserialize it back. That way, any + // option fields that we do happen to know about will get moved from the + // UnknownFieldSet into the real fields, and thus be available right away. + // If they are not known, that's OK too. They will get reparsed into the + // UnknownFieldSet and wait there until the message is parsed by something + // that does know about the options. + string buf; + options->AppendToString(&buf); + GOOGLE_CHECK(options->ParseFromString(buf)) + << "Protocol message serialized itself in invalid fashion."; + } + + return !failed; +} + +bool DescriptorBuilder::OptionInterpreter::InterpretSingleOption( + Message* options) { + // First do some basic validation. + if (uninterpreted_option_->name_size() == 0) { + // This should never happen unless the parser has gone seriously awry or + // someone has manually created the uninterpreted option badly. + return AddNameError("Option must have a name."); + } + if (uninterpreted_option_->name(0).name_part() == "uninterpreted_option") { + return AddNameError("Option must not use reserved name " + "\"uninterpreted_option\"."); + } + + const Descriptor* options_descriptor = NULL; + // Get the options message's descriptor from the builder's pool, so that we + // get the version that knows about any extension options declared in the + // file we're currently building. The descriptor should be there as long as + // the file we're building imported "google/protobuf/descriptors.proto". + + // Note that we use DescriptorBuilder::FindSymbol(), not + // DescriptorPool::FindMessageTypeByName() because we're already holding the + // pool's mutex, and the latter method locks it again. + Symbol symbol = builder_->FindSymbolNotEnforcingDeps( + options->GetDescriptor()->full_name()); + if (!symbol.IsNull() && symbol.type == Symbol::MESSAGE) { + options_descriptor = symbol.descriptor; + } else { + // The options message's descriptor was not in the builder's pool, so use + // the standard version from the generated pool. We're not holding the + // generated pool's mutex, so we can search it the straightforward way. + options_descriptor = options->GetDescriptor(); + } + GOOGLE_CHECK(options_descriptor); + + // We iterate over the name parts to drill into the submessages until we find + // the leaf field for the option. As we drill down we remember the current + // submessage's descriptor in |descriptor| and the next field in that + // submessage in |field|. We also track the fields we're drilling down + // through in |intermediate_fields|. As we go, we reconstruct the full option + // name in |debug_msg_name|, for use in error messages. + const Descriptor* descriptor = options_descriptor; + const FieldDescriptor* field = NULL; + vector intermediate_fields; + string debug_msg_name = ""; + + for (int i = 0; i < uninterpreted_option_->name_size(); ++i) { + const string& name_part = uninterpreted_option_->name(i).name_part(); + if (debug_msg_name.size() > 0) { + debug_msg_name += "."; + } + if (uninterpreted_option_->name(i).is_extension()) { + debug_msg_name += "(" + name_part + ")"; + // Search for the extension's descriptor as an extension in the builder's + // pool. Note that we use DescriptorBuilder::LookupSymbol(), not + // DescriptorPool::FindExtensionByName(), for two reasons: 1) It allows + // relative lookups, and 2) because we're already holding the pool's + // mutex, and the latter method locks it again. + Symbol symbol = builder_->LookupSymbol(name_part, + options_to_interpret_->name_scope); + if (!symbol.IsNull() && symbol.type == Symbol::FIELD) { + field = symbol.field_descriptor; + } + // If we don't find the field then the field's descriptor was not in the + // builder's pool, but there's no point in looking in the generated + // pool. We require that you import the file that defines any extensions + // you use, so they must be present in the builder's pool. + } else { + debug_msg_name += name_part; + // Search for the field's descriptor as a regular field. + field = descriptor->FindFieldByName(name_part); + } + + if (field == NULL) { + if (get_allow_unknown(builder_->pool_)) { + // We can't find the option, but AllowUnknownDependencies() is enabled, + // so we will just leave it as uninterpreted. + AddWithoutInterpreting(*uninterpreted_option_, options); + return true; + } else { + return AddNameError("Option \"" + debug_msg_name + "\" unknown."); + } + } else if (field->containing_type() != descriptor) { + if (get_is_placeholder(field->containing_type())) { + // The field is an extension of a placeholder type, so we can't + // reliably verify whether it is a valid extension to use here (e.g. + // we don't know if it is an extension of the correct *Options message, + // or if it has a valid field number, etc.). Just leave it as + // uninterpreted instead. + AddWithoutInterpreting(*uninterpreted_option_, options); + return true; + } else { + // This can only happen if, due to some insane misconfiguration of the + // pools, we find the options message in one pool but the field in + // another. This would probably imply a hefty bug somewhere. + return AddNameError("Option field \"" + debug_msg_name + + "\" is not a field or extension of message \"" + + descriptor->name() + "\"."); + } + } else if (field->is_repeated()) { + return AddNameError("Option field \"" + debug_msg_name + + "\" is repeated. Repeated options are not " + "supported."); + } else if (i < uninterpreted_option_->name_size() - 1) { + if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) { + return AddNameError("Option \"" + debug_msg_name + + "\" is an atomic type, not a message."); + } else { + // Drill down into the submessage. + intermediate_fields.push_back(field); + descriptor = field->message_type(); + } + } + } + + // We've found the leaf field. Now we use UnknownFieldSets to set its value + // on the options message. We do so because the message may not yet know + // about its extension fields, so we may not be able to set the fields + // directly. But the UnknownFieldSets will serialize to the same wire-format + // message, so reading that message back in once the extension fields are + // known will populate them correctly. + + // First see if the option is already set. + if (!ExamineIfOptionIsSet( + intermediate_fields.begin(), + intermediate_fields.end(), + field, debug_msg_name, + options->GetReflection()->GetUnknownFields(*options))) { + return false; // ExamineIfOptionIsSet() already added the error. + } + + + // First set the value on the UnknownFieldSet corresponding to the + // innermost message. + scoped_ptr unknown_fields(new UnknownFieldSet()); + if (!SetOptionValue(field, unknown_fields.get())) { + return false; // SetOptionValue() already added the error. + } + + // Now wrap the UnknownFieldSet with UnknownFieldSets corresponding to all + // the intermediate messages. + for (vector::reverse_iterator iter = + intermediate_fields.rbegin(); + iter != intermediate_fields.rend(); ++iter) { + scoped_ptr parent_unknown_fields(new UnknownFieldSet()); + switch ((*iter)->type()) { + case FieldDescriptor::TYPE_MESSAGE: { + io::StringOutputStream outstr( + parent_unknown_fields->AddLengthDelimited((*iter)->number())); + io::CodedOutputStream out(&outstr); + internal::WireFormat::SerializeUnknownFields(*unknown_fields, &out); + GOOGLE_CHECK(!out.HadError()) + << "Unexpected failure while serializing option submessage " + << debug_msg_name << "\"."; + break; + } + + case FieldDescriptor::TYPE_GROUP: { + parent_unknown_fields->AddGroup((*iter)->number()) + ->MergeFrom(*unknown_fields); + break; + } + + default: + GOOGLE_LOG(FATAL) << "Invalid wire type for CPPTYPE_MESSAGE: " + << (*iter)->type(); + return false; + } + unknown_fields.reset(parent_unknown_fields.release()); + } + + // Now merge the UnknownFieldSet corresponding to the top-level message into + // the options message. + options->GetReflection()->MutableUnknownFields(options)->MergeFrom( + *unknown_fields); + + return true; +} + +void DescriptorBuilder::OptionInterpreter::AddWithoutInterpreting( + const UninterpretedOption& uninterpreted_option, Message* options) { + const FieldDescriptor* field = + options->GetDescriptor()->FindFieldByName("uninterpreted_option"); + GOOGLE_CHECK(field != NULL); + + options->GetReflection()->AddMessage(options, field) + ->CopyFrom(uninterpreted_option); +} + +bool DescriptorBuilder::OptionInterpreter::ExamineIfOptionIsSet( + vector::const_iterator intermediate_fields_iter, + vector::const_iterator intermediate_fields_end, + const FieldDescriptor* innermost_field, const string& debug_msg_name, + const UnknownFieldSet& unknown_fields) { + // We do linear searches of the UnknownFieldSet and its sub-groups. This + // should be fine since it's unlikely that any one options structure will + // contain more than a handful of options. + + if (intermediate_fields_iter == intermediate_fields_end) { + // We're at the innermost submessage. + for (int i = 0; i < unknown_fields.field_count(); i++) { + if (unknown_fields.field(i).number() == innermost_field->number()) { + return AddNameError("Option \"" + debug_msg_name + + "\" was already set."); + } + } + return true; + } + + for (int i = 0; i < unknown_fields.field_count(); i++) { + if (unknown_fields.field(i).number() == + (*intermediate_fields_iter)->number()) { + const UnknownField* unknown_field = &unknown_fields.field(i); + FieldDescriptor::Type type = (*intermediate_fields_iter)->type(); + // Recurse into the next submessage. + switch (type) { + case FieldDescriptor::TYPE_MESSAGE: + if (unknown_field->type() == UnknownField::TYPE_LENGTH_DELIMITED) { + UnknownFieldSet intermediate_unknown_fields; + if (intermediate_unknown_fields.ParseFromString( + unknown_field->length_delimited()) && + !ExamineIfOptionIsSet(intermediate_fields_iter + 1, + intermediate_fields_end, + innermost_field, debug_msg_name, + intermediate_unknown_fields)) { + return false; // Error already added. + } + } + break; + + case FieldDescriptor::TYPE_GROUP: + if (unknown_field->type() == UnknownField::TYPE_GROUP) { + if (!ExamineIfOptionIsSet(intermediate_fields_iter + 1, + intermediate_fields_end, + innermost_field, debug_msg_name, + unknown_field->group())) { + return false; // Error already added. + } + } + break; + + default: + GOOGLE_LOG(FATAL) << "Invalid wire type for CPPTYPE_MESSAGE: " << type; + return false; + } + } + } + return true; +} + +bool DescriptorBuilder::OptionInterpreter::SetOptionValue( + const FieldDescriptor* option_field, + UnknownFieldSet* unknown_fields) { + // We switch on the CppType to validate. + switch (option_field->cpp_type()) { + + case FieldDescriptor::CPPTYPE_INT32: + if (uninterpreted_option_->has_positive_int_value()) { + if (uninterpreted_option_->positive_int_value() > + static_cast(kint32max)) { + return AddValueError("Value out of range for int32 option \"" + + option_field->full_name() + "\"."); + } else { + SetInt32(option_field->number(), + uninterpreted_option_->positive_int_value(), + option_field->type(), unknown_fields); + } + } else if (uninterpreted_option_->has_negative_int_value()) { + if (uninterpreted_option_->negative_int_value() < + static_cast(kint32min)) { + return AddValueError("Value out of range for int32 option \"" + + option_field->full_name() + "\"."); + } else { + SetInt32(option_field->number(), + uninterpreted_option_->negative_int_value(), + option_field->type(), unknown_fields); + } + } else { + return AddValueError("Value must be integer for int32 option \"" + + option_field->full_name() + "\"."); + } + break; + + case FieldDescriptor::CPPTYPE_INT64: + if (uninterpreted_option_->has_positive_int_value()) { + if (uninterpreted_option_->positive_int_value() > + static_cast(kint64max)) { + return AddValueError("Value out of range for int64 option \"" + + option_field->full_name() + "\"."); + } else { + SetInt64(option_field->number(), + uninterpreted_option_->positive_int_value(), + option_field->type(), unknown_fields); + } + } else if (uninterpreted_option_->has_negative_int_value()) { + SetInt64(option_field->number(), + uninterpreted_option_->negative_int_value(), + option_field->type(), unknown_fields); + } else { + return AddValueError("Value must be integer for int64 option \"" + + option_field->full_name() + "\"."); + } + break; + + case FieldDescriptor::CPPTYPE_UINT32: + if (uninterpreted_option_->has_positive_int_value()) { + if (uninterpreted_option_->positive_int_value() > kuint32max) { + return AddValueError("Value out of range for uint32 option \"" + + option_field->name() + "\"."); + } else { + SetUInt32(option_field->number(), + uninterpreted_option_->positive_int_value(), + option_field->type(), unknown_fields); + } + } else { + return AddValueError("Value must be non-negative integer for uint32 " + "option \"" + option_field->full_name() + "\"."); + } + break; + + case FieldDescriptor::CPPTYPE_UINT64: + if (uninterpreted_option_->has_positive_int_value()) { + SetUInt64(option_field->number(), + uninterpreted_option_->positive_int_value(), + option_field->type(), unknown_fields); + } else { + return AddValueError("Value must be non-negative integer for uint64 " + "option \"" + option_field->full_name() + "\"."); + } + break; + + case FieldDescriptor::CPPTYPE_FLOAT: { + float value; + if (uninterpreted_option_->has_double_value()) { + value = uninterpreted_option_->double_value(); + } else if (uninterpreted_option_->has_positive_int_value()) { + value = uninterpreted_option_->positive_int_value(); + } else if (uninterpreted_option_->has_negative_int_value()) { + value = uninterpreted_option_->negative_int_value(); + } else { + return AddValueError("Value must be number for float option \"" + + option_field->full_name() + "\"."); + } + unknown_fields->AddFixed32(option_field->number(), + google::protobuf::internal::WireFormatLite::EncodeFloat(value)); + break; + } + + case FieldDescriptor::CPPTYPE_DOUBLE: { + double value; + if (uninterpreted_option_->has_double_value()) { + value = uninterpreted_option_->double_value(); + } else if (uninterpreted_option_->has_positive_int_value()) { + value = uninterpreted_option_->positive_int_value(); + } else if (uninterpreted_option_->has_negative_int_value()) { + value = uninterpreted_option_->negative_int_value(); + } else { + return AddValueError("Value must be number for double option \"" + + option_field->full_name() + "\"."); + } + unknown_fields->AddFixed64(option_field->number(), + google::protobuf::internal::WireFormatLite::EncodeDouble(value)); + break; + } + + case FieldDescriptor::CPPTYPE_BOOL: + uint64 value; + if (!uninterpreted_option_->has_identifier_value()) { + return AddValueError("Value must be identifier for boolean option " + "\"" + option_field->full_name() + "\"."); + } + if (uninterpreted_option_->identifier_value() == "true") { + value = 1; + } else if (uninterpreted_option_->identifier_value() == "false") { + value = 0; + } else { + return AddValueError("Value must be \"true\" or \"false\" for boolean " + "option \"" + option_field->full_name() + "\"."); + } + unknown_fields->AddVarint(option_field->number(), value); + break; + + case FieldDescriptor::CPPTYPE_ENUM: { + if (!uninterpreted_option_->has_identifier_value()) { + return AddValueError("Value must be identifier for enum-valued option " + "\"" + option_field->full_name() + "\"."); + } + const EnumDescriptor* enum_type = option_field->enum_type(); + const string& value_name = uninterpreted_option_->identifier_value(); + const EnumValueDescriptor* enum_value = NULL; + + if (enum_type->file()->pool() != DescriptorPool::generated_pool()) { + // Note that the enum value's fully-qualified name is a sibling of the + // enum's name, not a child of it. + string fully_qualified_name = enum_type->full_name(); + fully_qualified_name.resize(fully_qualified_name.size() - + enum_type->name().size()); + fully_qualified_name += value_name; + + // Search for the enum value's descriptor in the builder's pool. Note + // that we use DescriptorBuilder::FindSymbolNotEnforcingDeps(), not + // DescriptorPool::FindEnumValueByName() because we're already holding + // the pool's mutex, and the latter method locks it again. + Symbol symbol = + builder_->FindSymbolNotEnforcingDeps(fully_qualified_name); + if (!symbol.IsNull() && symbol.type == Symbol::ENUM_VALUE) { + if (symbol.enum_value_descriptor->type() != enum_type) { + return AddValueError("Enum type \"" + enum_type->full_name() + + "\" has no value named \"" + value_name + "\" for option \"" + + option_field->full_name() + + "\". This appears to be a value from a sibling type."); + } else { + enum_value = symbol.enum_value_descriptor; + } + } + } else { + // The enum type is in the generated pool, so we can search for the + // value there. + enum_value = enum_type->FindValueByName(value_name); + } + + if (enum_value == NULL) { + return AddValueError("Enum type \"" + + option_field->enum_type()->full_name() + + "\" has no value named \"" + value_name + "\" for " + "option \"" + option_field->full_name() + "\"."); + } else { + // Sign-extension is not a problem, since we cast directly from int32 to + // uint64, without first going through uint32. + unknown_fields->AddVarint(option_field->number(), + static_cast(static_cast(enum_value->number()))); + } + break; + } + + case FieldDescriptor::CPPTYPE_STRING: + if (!uninterpreted_option_->has_string_value()) { + return AddValueError("Value must be quoted string for string option " + "\"" + option_field->full_name() + "\"."); + } + // The string has already been unquoted and unescaped by the parser. + unknown_fields->AddLengthDelimited(option_field->number(), + uninterpreted_option_->string_value()); + break; + + case FieldDescriptor::CPPTYPE_MESSAGE: + if (!SetAggregateOption(option_field, unknown_fields)) { + return false; + } + break; + } + + return true; +} + +class DescriptorBuilder::OptionInterpreter::AggregateOptionFinder + : public TextFormat::Finder { + public: + DescriptorBuilder* builder_; + + virtual const FieldDescriptor* FindExtension( + Message* message, const string& name) const { + assert_mutex_held(builder_->pool_); + Symbol result = builder_->LookupSymbolNoPlaceholder( + name, message->GetDescriptor()->full_name()); + if (result.type == Symbol::FIELD && + result.field_descriptor->is_extension()) { + return result.field_descriptor; + } else { + return NULL; + } + } +}; + +// A custom error collector to record any text-format parsing errors +namespace { +class AggregateErrorCollector : public io::ErrorCollector { + public: + string error_; + + virtual void AddError(int line, int column, const string& message) { + if (!error_.empty()) { + error_ += "; "; + } + error_ += message; + } + + virtual void AddWarning(int line, int column, const string& message) { + // Ignore warnings + } +}; +} + +// We construct a dynamic message of the type corresponding to +// option_field, parse the supplied text-format string into this +// message, and serialize the resulting message to produce the value. +bool DescriptorBuilder::OptionInterpreter::SetAggregateOption( + const FieldDescriptor* option_field, + UnknownFieldSet* unknown_fields) { + if (!uninterpreted_option_->has_aggregate_value()) { + return AddValueError("Option \"" + option_field->full_name() + + "\" is a message. To set the entire message, use " + "syntax like \"" + option_field->name() + + " = { }\". " + "To set fields within it, use " + "syntax like \"" + option_field->name() + + ".foo = value\"."); + } + + const Descriptor* type = option_field->message_type(); + scoped_ptr dynamic(dynamic_factory_.GetPrototype(type)->New()); + GOOGLE_CHECK(dynamic.get() != NULL) + << "Could not create an instance of " << option_field->DebugString(); + + AggregateErrorCollector collector; + AggregateOptionFinder finder; + finder.builder_ = builder_; + TextFormat::Parser parser; + parser.RecordErrorsTo(&collector); + parser.SetFinder(&finder); + if (!parser.ParseFromString(uninterpreted_option_->aggregate_value(), + dynamic.get())) { + AddValueError("Error while parsing option value for \"" + + option_field->name() + "\": " + collector.error_); + return false; + } else { + string serial; + dynamic->SerializeToString(&serial); // Never fails + unknown_fields->AddLengthDelimited(option_field->number(), serial); + return true; + } +} + +void DescriptorBuilder::OptionInterpreter::SetInt32(int number, int32 value, + FieldDescriptor::Type type, UnknownFieldSet* unknown_fields) { + switch (type) { + case FieldDescriptor::TYPE_INT32: + unknown_fields->AddVarint(number, + static_cast(static_cast(value))); + break; + + case FieldDescriptor::TYPE_SFIXED32: + unknown_fields->AddFixed32(number, static_cast(value)); + break; + + case FieldDescriptor::TYPE_SINT32: + unknown_fields->AddVarint(number, + google::protobuf::internal::WireFormatLite::ZigZagEncode32(value)); + break; + + default: + GOOGLE_LOG(FATAL) << "Invalid wire type for CPPTYPE_INT32: " << type; + break; + } +} + +void DescriptorBuilder::OptionInterpreter::SetInt64(int number, int64 value, + FieldDescriptor::Type type, UnknownFieldSet* unknown_fields) { + switch (type) { + case FieldDescriptor::TYPE_INT64: + unknown_fields->AddVarint(number, static_cast(value)); + break; + + case FieldDescriptor::TYPE_SFIXED64: + unknown_fields->AddFixed64(number, static_cast(value)); + break; + + case FieldDescriptor::TYPE_SINT64: + unknown_fields->AddVarint(number, + google::protobuf::internal::WireFormatLite::ZigZagEncode64(value)); + break; + + default: + GOOGLE_LOG(FATAL) << "Invalid wire type for CPPTYPE_INT64: " << type; + break; + } +} + +void DescriptorBuilder::OptionInterpreter::SetUInt32(int number, uint32 value, + FieldDescriptor::Type type, UnknownFieldSet* unknown_fields) { + switch (type) { + case FieldDescriptor::TYPE_UINT32: + unknown_fields->AddVarint(number, static_cast(value)); + break; + + case FieldDescriptor::TYPE_FIXED32: + unknown_fields->AddFixed32(number, static_cast(value)); + break; + + default: + GOOGLE_LOG(FATAL) << "Invalid wire type for CPPTYPE_UINT32: " << type; + break; + } +} + +void DescriptorBuilder::OptionInterpreter::SetUInt64(int number, uint64 value, + FieldDescriptor::Type type, UnknownFieldSet* unknown_fields) { + switch (type) { + case FieldDescriptor::TYPE_UINT64: + unknown_fields->AddVarint(number, value); + break; + + case FieldDescriptor::TYPE_FIXED64: + unknown_fields->AddFixed64(number, value); + break; + + default: + GOOGLE_LOG(FATAL) << "Invalid wire type for CPPTYPE_UINT64: " << type; + break; + } +} + +} // namespace protobuf +} // namespace google diff --git a/depends/protobuf/google/protobuf/descriptor.h b/depends/protobuf/google/protobuf/descriptor.h new file mode 100644 index 0000000000..7f87dd809c --- /dev/null +++ b/depends/protobuf/google/protobuf/descriptor.h @@ -0,0 +1,1367 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// This file contains classes which describe a type of protocol message. +// You can use a message's descriptor to learn at runtime what fields +// it contains and what the types of those fields are. The Message +// interface also allows you to dynamically access and modify individual +// fields by passing the FieldDescriptor of the field you are interested +// in. +// +// Most users will not care about descriptors, because they will write +// code specific to certain protocol types and will simply use the classes +// generated by the protocol compiler directly. Advanced users who want +// to operate on arbitrary types (not known at compile time) may want to +// read descriptors in order to learn about the contents of a message. +// A very small number of users will want to construct their own +// Descriptors, either because they are implementing Message manually or +// because they are writing something like the protocol compiler. +// +// For an example of how you might use descriptors, see the code example +// at the top of message.h. + +#ifndef GOOGLE_PROTOBUF_DESCRIPTOR_H__ +#define GOOGLE_PROTOBUF_DESCRIPTOR_H__ + +#include +#include +#include + + +namespace google { +namespace protobuf { + +// Defined in this file. +class Descriptor; +class FieldDescriptor; +class EnumDescriptor; +class EnumValueDescriptor; +class ServiceDescriptor; +class MethodDescriptor; +class FileDescriptor; +class DescriptorDatabase; +class DescriptorPool; + +// Defined in descriptor.proto +class DescriptorProto; +class FieldDescriptorProto; +class EnumDescriptorProto; +class EnumValueDescriptorProto; +class ServiceDescriptorProto; +class MethodDescriptorProto; +class FileDescriptorProto; +class MessageOptions; +class FieldOptions; +class EnumOptions; +class EnumValueOptions; +class ServiceOptions; +class MethodOptions; +class FileOptions; +class UninterpretedOption; + +// Defined in message.h +class Message; + +// Defined in descriptor.cc +class DescriptorBuilder; +class FileDescriptorTables; + +// Defined in unknown_field_set.h. +class UnknownField; + +// Describes a type of protocol message, or a particular group within a +// message. To obtain the Descriptor for a given message object, call +// Message::GetDescriptor(). Generated message classes also have a +// static method called descriptor() which returns the type's descriptor. +// Use DescriptorPool to construct your own descriptors. +class LIBPROTOBUF_EXPORT Descriptor { + public: + // The name of the message type, not including its scope. + const string& name() const; + + // The fully-qualified name of the message type, scope delimited by + // periods. For example, message type "Foo" which is declared in package + // "bar" has full name "bar.Foo". If a type "Baz" is nested within + // Foo, Baz's full_name is "bar.Foo.Baz". To get only the part that + // comes after the last '.', use name(). + const string& full_name() const; + + // Index of this descriptor within the file or containing type's message + // type array. + int index() const; + + // The .proto file in which this message type was defined. Never NULL. + const FileDescriptor* file() const; + + // If this Descriptor describes a nested type, this returns the type + // in which it is nested. Otherwise, returns NULL. + const Descriptor* containing_type() const; + + // Get options for this message type. These are specified in the .proto file + // by placing lines like "option foo = 1234;" in the message definition. + // Allowed options are defined by MessageOptions in + // google/protobuf/descriptor.proto, and any available extensions of that + // message. + const MessageOptions& options() const; + + // Write the contents of this Descriptor into the given DescriptorProto. + // The target DescriptorProto must be clear before calling this; if it + // isn't, the result may be garbage. + void CopyTo(DescriptorProto* proto) const; + + // Write the contents of this decriptor in a human-readable form. Output + // will be suitable for re-parsing. + string DebugString() const; + + // Field stuff ----------------------------------------------------- + + // The number of fields in this message type. + int field_count() const; + // Gets a field by index, where 0 <= index < field_count(). + // These are returned in the order they were defined in the .proto file. + const FieldDescriptor* field(int index) const; + + // Looks up a field by declared tag number. Returns NULL if no such field + // exists. + const FieldDescriptor* FindFieldByNumber(int number) const; + // Looks up a field by name. Returns NULL if no such field exists. + const FieldDescriptor* FindFieldByName(const string& name) const; + + // Looks up a field by lowercased name (as returned by lowercase_name()). + // This lookup may be ambiguous if multiple field names differ only by case, + // in which case the field returned is chosen arbitrarily from the matches. + const FieldDescriptor* FindFieldByLowercaseName( + const string& lowercase_name) const; + + // Looks up a field by camel-case name (as returned by camelcase_name()). + // This lookup may be ambiguous if multiple field names differ in a way that + // leads them to have identical camel-case names, in which case the field + // returned is chosen arbitrarily from the matches. + const FieldDescriptor* FindFieldByCamelcaseName( + const string& camelcase_name) const; + + // Nested type stuff ----------------------------------------------- + + // The number of nested types in this message type. + int nested_type_count() const; + // Gets a nested type by index, where 0 <= index < nested_type_count(). + // These are returned in the order they were defined in the .proto file. + const Descriptor* nested_type(int index) const; + + // Looks up a nested type by name. Returns NULL if no such nested type + // exists. + const Descriptor* FindNestedTypeByName(const string& name) const; + + // Enum stuff ------------------------------------------------------ + + // The number of enum types in this message type. + int enum_type_count() const; + // Gets an enum type by index, where 0 <= index < enum_type_count(). + // These are returned in the order they were defined in the .proto file. + const EnumDescriptor* enum_type(int index) const; + + // Looks up an enum type by name. Returns NULL if no such enum type exists. + const EnumDescriptor* FindEnumTypeByName(const string& name) const; + + // Looks up an enum value by name, among all enum types in this message. + // Returns NULL if no such value exists. + const EnumValueDescriptor* FindEnumValueByName(const string& name) const; + + // Extensions ------------------------------------------------------ + + // A range of field numbers which are designated for third-party + // extensions. + struct ExtensionRange { + int start; // inclusive + int end; // exclusive + }; + + // The number of extension ranges in this message type. + int extension_range_count() const; + // Gets an extension range by index, where 0 <= index < + // extension_range_count(). These are returned in the order they were defined + // in the .proto file. + const ExtensionRange* extension_range(int index) const; + + // Returns true if the number is in one of the extension ranges. + bool IsExtensionNumber(int number) const; + + // The number of extensions -- extending *other* messages -- that were + // defined nested within this message type's scope. + int extension_count() const; + // Get an extension by index, where 0 <= index < extension_count(). + // These are returned in the order they were defined in the .proto file. + const FieldDescriptor* extension(int index) const; + + // Looks up a named extension (which extends some *other* message type) + // defined within this message type's scope. + const FieldDescriptor* FindExtensionByName(const string& name) const; + + // Similar to FindFieldByLowercaseName(), but finds extensions defined within + // this message type's scope. + const FieldDescriptor* FindExtensionByLowercaseName(const string& name) const; + + // Similar to FindFieldByCamelcaseName(), but finds extensions defined within + // this message type's scope. + const FieldDescriptor* FindExtensionByCamelcaseName(const string& name) const; + + private: + typedef MessageOptions OptionsType; + + // Internal version of DebugString; controls the level of indenting for + // correct depth + void DebugString(int depth, string *contents) const; + + const string* name_; + const string* full_name_; + const FileDescriptor* file_; + const Descriptor* containing_type_; + const MessageOptions* options_; + + // True if this is a placeholder for an unknown type. + bool is_placeholder_; + // True if this is a placeholder and the type name wasn't fully-qualified. + bool is_unqualified_placeholder_; + + int field_count_; + FieldDescriptor* fields_; + int nested_type_count_; + Descriptor* nested_types_; + int enum_type_count_; + EnumDescriptor* enum_types_; + int extension_range_count_; + ExtensionRange* extension_ranges_; + int extension_count_; + FieldDescriptor* extensions_; + // IMPORTANT: If you add a new field, make sure to search for all instances + // of Allocate() and AllocateArray() in descriptor.cc + // and update them to initialize the field. + + // Must be constructed using DescriptorPool. + Descriptor() {} + friend class DescriptorBuilder; + friend class EnumDescriptor; + friend class FieldDescriptor; + friend class MethodDescriptor; + friend class FileDescriptor; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Descriptor); +}; + +// Describes a single field of a message. To get the descriptor for a given +// field, first get the Descriptor for the message in which it is defined, +// then call Descriptor::FindFieldByName(). To get a FieldDescriptor for +// an extension, do one of the following: +// - Get the Descriptor or FileDescriptor for its containing scope, then +// call Descriptor::FindExtensionByName() or +// FileDescriptor::FindExtensionByName(). +// - Given a DescriptorPool, call DescriptorPool::FindExtensionByNumber(). +// - Given a Reflection for a message object, call +// Reflection::FindKnownExtensionByName() or +// Reflection::FindKnownExtensionByNumber(). +// Use DescriptorPool to construct your own descriptors. +class LIBPROTOBUF_EXPORT FieldDescriptor { + public: + // Identifies a field type. 0 is reserved for errors. The order is weird + // for historical reasons. Types 12 and up are new in proto2. + enum Type { + TYPE_DOUBLE = 1, // double, exactly eight bytes on the wire. + TYPE_FLOAT = 2, // float, exactly four bytes on the wire. + TYPE_INT64 = 3, // int64, varint on the wire. Negative numbers + // take 10 bytes. Use TYPE_SINT64 if negative + // values are likely. + TYPE_UINT64 = 4, // uint64, varint on the wire. + TYPE_INT32 = 5, // int32, varint on the wire. Negative numbers + // take 10 bytes. Use TYPE_SINT32 if negative + // values are likely. + TYPE_FIXED64 = 6, // uint64, exactly eight bytes on the wire. + TYPE_FIXED32 = 7, // uint32, exactly four bytes on the wire. + TYPE_BOOL = 8, // bool, varint on the wire. + TYPE_STRING = 9, // UTF-8 text. + TYPE_GROUP = 10, // Tag-delimited message. Deprecated. + TYPE_MESSAGE = 11, // Length-delimited message. + + TYPE_BYTES = 12, // Arbitrary byte array. + TYPE_UINT32 = 13, // uint32, varint on the wire + TYPE_ENUM = 14, // Enum, varint on the wire + TYPE_SFIXED32 = 15, // int32, exactly four bytes on the wire + TYPE_SFIXED64 = 16, // int64, exactly eight bytes on the wire + TYPE_SINT32 = 17, // int32, ZigZag-encoded varint on the wire + TYPE_SINT64 = 18, // int64, ZigZag-encoded varint on the wire + + MAX_TYPE = 18, // Constant useful for defining lookup tables + // indexed by Type. + }; + + // Specifies the C++ data type used to represent the field. There is a + // fixed mapping from Type to CppType where each Type maps to exactly one + // CppType. 0 is reserved for errors. + enum CppType { + CPPTYPE_INT32 = 1, // TYPE_INT32, TYPE_SINT32, TYPE_SFIXED32 + CPPTYPE_INT64 = 2, // TYPE_INT64, TYPE_SINT64, TYPE_SFIXED64 + CPPTYPE_UINT32 = 3, // TYPE_UINT32, TYPE_FIXED32 + CPPTYPE_UINT64 = 4, // TYPE_UINT64, TYPE_FIXED64 + CPPTYPE_DOUBLE = 5, // TYPE_DOUBLE + CPPTYPE_FLOAT = 6, // TYPE_FLOAT + CPPTYPE_BOOL = 7, // TYPE_BOOL + CPPTYPE_ENUM = 8, // TYPE_ENUM + CPPTYPE_STRING = 9, // TYPE_STRING, TYPE_BYTES + CPPTYPE_MESSAGE = 10, // TYPE_MESSAGE, TYPE_GROUP + + MAX_CPPTYPE = 10, // Constant useful for defining lookup tables + // indexed by CppType. + }; + + // Identifies whether the field is optional, required, or repeated. 0 is + // reserved for errors. + enum Label { + LABEL_OPTIONAL = 1, // optional + LABEL_REQUIRED = 2, // required + LABEL_REPEATED = 3, // repeated + + MAX_LABEL = 3, // Constant useful for defining lookup tables + // indexed by Label. + }; + + // Valid field numbers are positive integers up to kMaxNumber. + static const int kMaxNumber = (1 << 29) - 1; + + // First field number reserved for the protocol buffer library implementation. + // Users may not declare fields that use reserved numbers. + static const int kFirstReservedNumber = 19000; + // Last field number reserved for the protocol buffer library implementation. + // Users may not declare fields that use reserved numbers. + static const int kLastReservedNumber = 19999; + + const string& name() const; // Name of this field within the message. + const string& full_name() const; // Fully-qualified name of the field. + const FileDescriptor* file() const;// File in which this field was defined. + bool is_extension() const; // Is this an extension field? + int number() const; // Declared tag number. + + // Same as name() except converted to lower-case. This (and especially the + // FindFieldByLowercaseName() method) can be useful when parsing formats + // which prefer to use lowercase naming style. (Although, technically + // field names should be lowercased anyway according to the protobuf style + // guide, so this only makes a difference when dealing with old .proto files + // which do not follow the guide.) + const string& lowercase_name() const; + + // Same as name() except converted to camel-case. In this conversion, any + // time an underscore appears in the name, it is removed and the next + // letter is capitalized. Furthermore, the first letter of the name is + // lower-cased. Examples: + // FooBar -> fooBar + // foo_bar -> fooBar + // fooBar -> fooBar + // This (and especially the FindFieldByCamelcaseName() method) can be useful + // when parsing formats which prefer to use camel-case naming style. + const string& camelcase_name() const; + + Type type() const; // Declared type of this field. + CppType cpp_type() const; // C++ type of this field. + Label label() const; // optional/required/repeated + + bool is_required() const; // shorthand for label() == LABEL_REQUIRED + bool is_optional() const; // shorthand for label() == LABEL_OPTIONAL + bool is_repeated() const; // shorthand for label() == LABEL_REPEATED + bool is_packable() const; // shorthand for is_repeated() && + // IsTypePackable(type()) + + // Index of this field within the message's field array, or the file or + // extension scope's extensions array. + int index() const; + + // Does this field have an explicitly-declared default value? + bool has_default_value() const; + + // Get the field default value if cpp_type() == CPPTYPE_INT32. If no + // explicit default was defined, the default is 0. + int32 default_value_int32() const; + // Get the field default value if cpp_type() == CPPTYPE_INT64. If no + // explicit default was defined, the default is 0. + int64 default_value_int64() const; + // Get the field default value if cpp_type() == CPPTYPE_UINT32. If no + // explicit default was defined, the default is 0. + uint32 default_value_uint32() const; + // Get the field default value if cpp_type() == CPPTYPE_UINT64. If no + // explicit default was defined, the default is 0. + uint64 default_value_uint64() const; + // Get the field default value if cpp_type() == CPPTYPE_FLOAT. If no + // explicit default was defined, the default is 0.0. + float default_value_float() const; + // Get the field default value if cpp_type() == CPPTYPE_DOUBLE. If no + // explicit default was defined, the default is 0.0. + double default_value_double() const; + // Get the field default value if cpp_type() == CPPTYPE_BOOL. If no + // explicit default was defined, the default is false. + bool default_value_bool() const; + // Get the field default value if cpp_type() == CPPTYPE_ENUM. If no + // explicit default was defined, the default is the first value defined + // in the enum type (all enum types are required to have at least one value). + // This never returns NULL. + const EnumValueDescriptor* default_value_enum() const; + // Get the field default value if cpp_type() == CPPTYPE_STRING. If no + // explicit default was defined, the default is the empty string. + const string& default_value_string() const; + + // The Descriptor for the message of which this is a field. For extensions, + // this is the extended type. Never NULL. + const Descriptor* containing_type() const; + + // An extension may be declared within the scope of another message. If this + // field is an extension (is_extension() is true), then extension_scope() + // returns that message, or NULL if the extension was declared at global + // scope. If this is not an extension, extension_scope() is undefined (may + // assert-fail). + const Descriptor* extension_scope() const; + + // If type is TYPE_MESSAGE or TYPE_GROUP, returns a descriptor for the + // message or the group type. Otherwise, undefined. + const Descriptor* message_type() const; + // If type is TYPE_ENUM, returns a descriptor for the enum. Otherwise, + // undefined. + const EnumDescriptor* enum_type() const; + + // EXPERIMENTAL; DO NOT USE. + // If this field is a map field, experimental_map_key() is the field + // that is the key for this map. + // experimental_map_key()->containing_type() is the same as message_type(). + const FieldDescriptor* experimental_map_key() const; + + // Get the FieldOptions for this field. This includes things listed in + // square brackets after the field definition. E.g., the field: + // optional string text = 1 [ctype=CORD]; + // has the "ctype" option set. Allowed options are defined by FieldOptions + // in google/protobuf/descriptor.proto, and any available extensions of that + // message. + const FieldOptions& options() const; + + // See Descriptor::CopyTo(). + void CopyTo(FieldDescriptorProto* proto) const; + + // See Descriptor::DebugString(). + string DebugString() const; + + // Helper method to get the CppType for a particular Type. + static CppType TypeToCppType(Type type); + + // Return true iff [packed = true] is valid for fields of this type. + static inline bool IsTypePackable(Type field_type); + + private: + typedef FieldOptions OptionsType; + + // See Descriptor::DebugString(). + void DebugString(int depth, string *contents) const; + + // formats the default value appropriately and returns it as a string. + // Must have a default value to call this. If quote_string_type is true, then + // types of CPPTYPE_STRING whill be surrounded by quotes and CEscaped. + string DefaultValueAsString(bool quote_string_type) const; + + const string* name_; + const string* full_name_; + const string* lowercase_name_; + const string* camelcase_name_; + const FileDescriptor* file_; + int number_; + Type type_; + Label label_; + bool is_extension_; + const Descriptor* containing_type_; + const Descriptor* extension_scope_; + const Descriptor* message_type_; + const EnumDescriptor* enum_type_; + const FieldDescriptor* experimental_map_key_; + const FieldOptions* options_; + // IMPORTANT: If you add a new field, make sure to search for all instances + // of Allocate() and AllocateArray() in + // descriptor.cc and update them to initialize the field. + + bool has_default_value_; + union { + int32 default_value_int32_; + int64 default_value_int64_; + uint32 default_value_uint32_; + uint64 default_value_uint64_; + float default_value_float_; + double default_value_double_; + bool default_value_bool_; + + const EnumValueDescriptor* default_value_enum_; + const string* default_value_string_; + }; + + static const CppType kTypeToCppTypeMap[MAX_TYPE + 1]; + + static const char * const kTypeToName[MAX_TYPE + 1]; + + static const char * const kLabelToName[MAX_LABEL + 1]; + + // Must be constructed using DescriptorPool. + FieldDescriptor() {} + friend class DescriptorBuilder; + friend class FileDescriptor; + friend class Descriptor; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldDescriptor); +}; + +// Describes an enum type defined in a .proto file. To get the EnumDescriptor +// for a generated enum type, call TypeName_descriptor(). Use DescriptorPool +// to construct your own descriptors. +class LIBPROTOBUF_EXPORT EnumDescriptor { + public: + // The name of this enum type in the containing scope. + const string& name() const; + + // The fully-qualified name of the enum type, scope delimited by periods. + const string& full_name() const; + + // Index of this enum within the file or containing message's enum array. + int index() const; + + // The .proto file in which this enum type was defined. Never NULL. + const FileDescriptor* file() const; + + // The number of values for this EnumDescriptor. Guaranteed to be greater + // than zero. + int value_count() const; + // Gets a value by index, where 0 <= index < value_count(). + // These are returned in the order they were defined in the .proto file. + const EnumValueDescriptor* value(int index) const; + + // Looks up a value by name. Returns NULL if no such value exists. + const EnumValueDescriptor* FindValueByName(const string& name) const; + // Looks up a value by number. Returns NULL if no such value exists. If + // multiple values have this number, the first one defined is returned. + const EnumValueDescriptor* FindValueByNumber(int number) const; + + // If this enum type is nested in a message type, this is that message type. + // Otherwise, NULL. + const Descriptor* containing_type() const; + + // Get options for this enum type. These are specified in the .proto file by + // placing lines like "option foo = 1234;" in the enum definition. Allowed + // options are defined by EnumOptions in google/protobuf/descriptor.proto, + // and any available extensions of that message. + const EnumOptions& options() const; + + // See Descriptor::CopyTo(). + void CopyTo(EnumDescriptorProto* proto) const; + + // See Descriptor::DebugString(). + string DebugString() const; + + private: + typedef EnumOptions OptionsType; + + // See Descriptor::DebugString(). + void DebugString(int depth, string *contents) const; + + const string* name_; + const string* full_name_; + const FileDescriptor* file_; + const Descriptor* containing_type_; + const EnumOptions* options_; + + // True if this is a placeholder for an unknown type. + bool is_placeholder_; + // True if this is a placeholder and the type name wasn't fully-qualified. + bool is_unqualified_placeholder_; + + int value_count_; + EnumValueDescriptor* values_; + // IMPORTANT: If you add a new field, make sure to search for all instances + // of Allocate() and AllocateArray() in + // descriptor.cc and update them to initialize the field. + + // Must be constructed using DescriptorPool. + EnumDescriptor() {} + friend class DescriptorBuilder; + friend class Descriptor; + friend class FieldDescriptor; + friend class EnumValueDescriptor; + friend class FileDescriptor; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumDescriptor); +}; + +// Describes an individual enum constant of a particular type. To get the +// EnumValueDescriptor for a given enum value, first get the EnumDescriptor +// for its type, then use EnumDescriptor::FindValueByName() or +// EnumDescriptor::FindValueByNumber(). Use DescriptorPool to construct +// your own descriptors. +class LIBPROTOBUF_EXPORT EnumValueDescriptor { + public: + const string& name() const; // Name of this enum constant. + int index() const; // Index within the enums's Descriptor. + int number() const; // Numeric value of this enum constant. + + // The full_name of an enum value is a sibling symbol of the enum type. + // e.g. the full name of FieldDescriptorProto::TYPE_INT32 is actually + // "google.protobuf.FieldDescriptorProto.TYPE_INT32", NOT + // "google.protobuf.FieldDescriptorProto.Type.TYPE_INT32". This is to conform + // with C++ scoping rules for enums. + const string& full_name() const; + + // The type of this value. Never NULL. + const EnumDescriptor* type() const; + + // Get options for this enum value. These are specified in the .proto file + // by adding text like "[foo = 1234]" after an enum value definition. + // Allowed options are defined by EnumValueOptions in + // google/protobuf/descriptor.proto, and any available extensions of that + // message. + const EnumValueOptions& options() const; + + // See Descriptor::CopyTo(). + void CopyTo(EnumValueDescriptorProto* proto) const; + + // See Descriptor::DebugString(). + string DebugString() const; + + private: + typedef EnumValueOptions OptionsType; + + // See Descriptor::DebugString(). + void DebugString(int depth, string *contents) const; + + const string* name_; + const string* full_name_; + int number_; + const EnumDescriptor* type_; + const EnumValueOptions* options_; + // IMPORTANT: If you add a new field, make sure to search for all instances + // of Allocate() and AllocateArray() + // in descriptor.cc and update them to initialize the field. + + // Must be constructed using DescriptorPool. + EnumValueDescriptor() {} + friend class DescriptorBuilder; + friend class EnumDescriptor; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumValueDescriptor); +}; + +// Describes an RPC service. To get the ServiceDescriptor for a service, +// call Service::GetDescriptor(). Generated service classes also have a +// static method called descriptor() which returns the type's +// ServiceDescriptor. Use DescriptorPool to construct your own descriptors. +class LIBPROTOBUF_EXPORT ServiceDescriptor { + public: + // The name of the service, not including its containing scope. + const string& name() const; + // The fully-qualified name of the service, scope delimited by periods. + const string& full_name() const; + // Index of this service within the file's services array. + int index() const; + + // The .proto file in which this service was defined. Never NULL. + const FileDescriptor* file() const; + + // Get options for this service type. These are specified in the .proto file + // by placing lines like "option foo = 1234;" in the service definition. + // Allowed options are defined by ServiceOptions in + // google/protobuf/descriptor.proto, and any available extensions of that + // message. + const ServiceOptions& options() const; + + // The number of methods this service defines. + int method_count() const; + // Gets a MethodDescriptor by index, where 0 <= index < method_count(). + // These are returned in the order they were defined in the .proto file. + const MethodDescriptor* method(int index) const; + + // Look up a MethodDescriptor by name. + const MethodDescriptor* FindMethodByName(const string& name) const; + + // See Descriptor::CopyTo(). + void CopyTo(ServiceDescriptorProto* proto) const; + + // See Descriptor::DebugString(). + string DebugString() const; + + private: + typedef ServiceOptions OptionsType; + + // See Descriptor::DebugString(). + void DebugString(string *contents) const; + + const string* name_; + const string* full_name_; + const FileDescriptor* file_; + const ServiceOptions* options_; + int method_count_; + MethodDescriptor* methods_; + // IMPORTANT: If you add a new field, make sure to search for all instances + // of Allocate() and AllocateArray() in + // descriptor.cc and update them to initialize the field. + + // Must be constructed using DescriptorPool. + ServiceDescriptor() {} + friend class DescriptorBuilder; + friend class FileDescriptor; + friend class MethodDescriptor; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ServiceDescriptor); +}; + +// Describes an individual service method. To obtain a MethodDescriptor given +// a service, first get its ServiceDescriptor, then call +// ServiceDescriptor::FindMethodByName(). Use DescriptorPool to construct your +// own descriptors. +class LIBPROTOBUF_EXPORT MethodDescriptor { + public: + // Name of this method, not including containing scope. + const string& name() const; + // The fully-qualified name of the method, scope delimited by periods. + const string& full_name() const; + // Index within the service's Descriptor. + int index() const; + + // Gets the service to which this method belongs. Never NULL. + const ServiceDescriptor* service() const; + + // Gets the type of protocol message which this method accepts as input. + const Descriptor* input_type() const; + // Gets the type of protocol message which this message produces as output. + const Descriptor* output_type() const; + + // Get options for this method. These are specified in the .proto file by + // placing lines like "option foo = 1234;" in curly-braces after a method + // declaration. Allowed options are defined by MethodOptions in + // google/protobuf/descriptor.proto, and any available extensions of that + // message. + const MethodOptions& options() const; + + // See Descriptor::CopyTo(). + void CopyTo(MethodDescriptorProto* proto) const; + + // See Descriptor::DebugString(). + string DebugString() const; + + private: + typedef MethodOptions OptionsType; + + // See Descriptor::DebugString(). + void DebugString(int depth, string *contents) const; + + const string* name_; + const string* full_name_; + const ServiceDescriptor* service_; + const Descriptor* input_type_; + const Descriptor* output_type_; + const MethodOptions* options_; + // IMPORTANT: If you add a new field, make sure to search for all instances + // of Allocate() and AllocateArray() in + // descriptor.cc and update them to initialize the field. + + // Must be constructed using DescriptorPool. + MethodDescriptor() {} + friend class DescriptorBuilder; + friend class ServiceDescriptor; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MethodDescriptor); +}; + +// Describes a whole .proto file. To get the FileDescriptor for a compiled-in +// file, get the descriptor for something defined in that file and call +// descriptor->file(). Use DescriptorPool to construct your own descriptors. +class LIBPROTOBUF_EXPORT FileDescriptor { + public: + // The filename, relative to the source tree. + // e.g. "google/protobuf/descriptor.proto" + const string& name() const; + + // The package, e.g. "google.protobuf.compiler". + const string& package() const; + + // The DescriptorPool in which this FileDescriptor and all its contents were + // allocated. Never NULL. + const DescriptorPool* pool() const; + + // The number of files imported by this one. + int dependency_count() const; + // Gets an imported file by index, where 0 <= index < dependency_count(). + // These are returned in the order they were defined in the .proto file. + const FileDescriptor* dependency(int index) const; + + // Number of top-level message types defined in this file. (This does not + // include nested types.) + int message_type_count() const; + // Gets a top-level message type, where 0 <= index < message_type_count(). + // These are returned in the order they were defined in the .proto file. + const Descriptor* message_type(int index) const; + + // Number of top-level enum types defined in this file. (This does not + // include nested types.) + int enum_type_count() const; + // Gets a top-level enum type, where 0 <= index < enum_type_count(). + // These are returned in the order they were defined in the .proto file. + const EnumDescriptor* enum_type(int index) const; + + // Number of services defined in this file. + int service_count() const; + // Gets a service, where 0 <= index < service_count(). + // These are returned in the order they were defined in the .proto file. + const ServiceDescriptor* service(int index) const; + + // Number of extensions defined at file scope. (This does not include + // extensions nested within message types.) + int extension_count() const; + // Gets an extension's descriptor, where 0 <= index < extension_count(). + // These are returned in the order they were defined in the .proto file. + const FieldDescriptor* extension(int index) const; + + // Get options for this file. These are specified in the .proto file by + // placing lines like "option foo = 1234;" at the top level, outside of any + // other definitions. Allowed options are defined by FileOptions in + // google/protobuf/descriptor.proto, and any available extensions of that + // message. + const FileOptions& options() const; + + // Find a top-level message type by name. Returns NULL if not found. + const Descriptor* FindMessageTypeByName(const string& name) const; + // Find a top-level enum type by name. Returns NULL if not found. + const EnumDescriptor* FindEnumTypeByName(const string& name) const; + // Find an enum value defined in any top-level enum by name. Returns NULL if + // not found. + const EnumValueDescriptor* FindEnumValueByName(const string& name) const; + // Find a service definition by name. Returns NULL if not found. + const ServiceDescriptor* FindServiceByName(const string& name) const; + // Find a top-level extension definition by name. Returns NULL if not found. + const FieldDescriptor* FindExtensionByName(const string& name) const; + // Similar to FindExtensionByName(), but searches by lowercased-name. See + // Descriptor::FindFieldByLowercaseName(). + const FieldDescriptor* FindExtensionByLowercaseName(const string& name) const; + // Similar to FindExtensionByName(), but searches by camelcased-name. See + // Descriptor::FindFieldByCamelcaseName(). + const FieldDescriptor* FindExtensionByCamelcaseName(const string& name) const; + + // See Descriptor::CopyTo(). + void CopyTo(FileDescriptorProto* proto) const; + + // See Descriptor::DebugString(). + string DebugString() const; + + private: + typedef FileOptions OptionsType; + + const string* name_; + const string* package_; + const DescriptorPool* pool_; + int dependency_count_; + const FileDescriptor** dependencies_; + int message_type_count_; + Descriptor* message_types_; + int enum_type_count_; + EnumDescriptor* enum_types_; + int service_count_; + ServiceDescriptor* services_; + int extension_count_; + FieldDescriptor* extensions_; + const FileOptions* options_; + + const FileDescriptorTables* tables_; + // IMPORTANT: If you add a new field, make sure to search for all instances + // of Allocate() and AllocateArray() in + // descriptor.cc and update them to initialize the field. + + FileDescriptor() {} + friend class DescriptorBuilder; + friend class Descriptor; + friend class FieldDescriptor; + friend class EnumDescriptor; + friend class ServiceDescriptor; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileDescriptor); +}; + +// =================================================================== + +// Used to construct descriptors. +// +// Normally you won't want to build your own descriptors. Message classes +// constructed by the protocol compiler will provide them for you. However, +// if you are implementing Message on your own, or if you are writing a +// program which can operate on totally arbitrary types and needs to load +// them from some sort of database, you might need to. +// +// Since Descriptors are composed of a whole lot of cross-linked bits of +// data that would be a pain to put together manually, the +// DescriptorPool class is provided to make the process easier. It can +// take a FileDescriptorProto (defined in descriptor.proto), validate it, +// and convert it to a set of nicely cross-linked Descriptors. +// +// DescriptorPool also helps with memory management. Descriptors are +// composed of many objects containing static data and pointers to each +// other. In all likelihood, when it comes time to delete this data, +// you'll want to delete it all at once. In fact, it is not uncommon to +// have a whole pool of descriptors all cross-linked with each other which +// you wish to delete all at once. This class represents such a pool, and +// handles the memory management for you. +// +// You can also search for descriptors within a DescriptorPool by name, and +// extensions by number. +class LIBPROTOBUF_EXPORT DescriptorPool { + public: + // Create a normal, empty DescriptorPool. + DescriptorPool(); + + // Constructs a DescriptorPool that, when it can't find something among the + // descriptors already in the pool, looks for it in the given + // DescriptorDatabase. + // Notes: + // - If a DescriptorPool is constructed this way, its BuildFile*() methods + // must not be called (they will assert-fail). The only way to populate + // the pool with descriptors is to call the Find*By*() methods. + // - The Find*By*() methods may block the calling thread if the + // DescriptorDatabase blocks. This in turn means that parsing messages + // may block if they need to look up extensions. + // - The Find*By*() methods will use mutexes for thread-safety, thus making + // them slower even when they don't have to fall back to the database. + // In fact, even the Find*By*() methods of descriptor objects owned by + // this pool will be slower, since they will have to obtain locks too. + // - An ErrorCollector may optionally be given to collect validation errors + // in files loaded from the database. If not given, errors will be printed + // to GOOGLE_LOG(ERROR). Remember that files are built on-demand, so this + // ErrorCollector may be called from any thread that calls one of the + // Find*By*() methods. + class ErrorCollector; + explicit DescriptorPool(DescriptorDatabase* fallback_database, + ErrorCollector* error_collector = NULL); + + ~DescriptorPool(); + + // Get a pointer to the generated pool. Generated protocol message classes + // which are compiled into the binary will allocate their descriptors in + // this pool. Do not add your own descriptors to this pool. + static const DescriptorPool* generated_pool(); + + // Find a FileDescriptor in the pool by file name. Returns NULL if not + // found. + const FileDescriptor* FindFileByName(const string& name) const; + + // Find the FileDescriptor in the pool which defines the given symbol. + // If any of the Find*ByName() methods below would succeed, then this is + // equivalent to calling that method and calling the result's file() method. + // Otherwise this returns NULL. + const FileDescriptor* FindFileContainingSymbol( + const string& symbol_name) const; + + // Looking up descriptors ------------------------------------------ + // These find descriptors by fully-qualified name. These will find both + // top-level descriptors and nested descriptors. They return NULL if not + // found. + + const Descriptor* FindMessageTypeByName(const string& name) const; + const FieldDescriptor* FindFieldByName(const string& name) const; + const FieldDescriptor* FindExtensionByName(const string& name) const; + const EnumDescriptor* FindEnumTypeByName(const string& name) const; + const EnumValueDescriptor* FindEnumValueByName(const string& name) const; + const ServiceDescriptor* FindServiceByName(const string& name) const; + const MethodDescriptor* FindMethodByName(const string& name) const; + + // Finds an extension of the given type by number. The extendee must be + // a member of this DescriptorPool or one of its underlays. + const FieldDescriptor* FindExtensionByNumber(const Descriptor* extendee, + int number) const; + + // Finds extensions of extendee. The extensions will be appended to + // out in an undefined order. Only extensions defined directly in + // this DescriptorPool or one of its underlays are guaranteed to be + // found: extensions defined in the fallback database might not be found + // depending on the database implementation. + void FindAllExtensions(const Descriptor* extendee, + vector* out) const; + + // Building descriptors -------------------------------------------- + + // When converting a FileDescriptorProto to a FileDescriptor, various + // errors might be detected in the input. The caller may handle these + // programmatically by implementing an ErrorCollector. + class LIBPROTOBUF_EXPORT ErrorCollector { + public: + inline ErrorCollector() {} + virtual ~ErrorCollector(); + + // These constants specify what exact part of the construct is broken. + // This is useful e.g. for mapping the error back to an exact location + // in a .proto file. + enum ErrorLocation { + NAME, // the symbol name, or the package name for files + NUMBER, // field or extension range number + TYPE, // field type + EXTENDEE, // field extendee + DEFAULT_VALUE, // field default value + INPUT_TYPE, // method input type + OUTPUT_TYPE, // method output type + OPTION_NAME, // name in assignment + OPTION_VALUE, // value in option assignment + OTHER // some other problem + }; + + // Reports an error in the FileDescriptorProto. + virtual void AddError( + const string& filename, // File name in which the error occurred. + const string& element_name, // Full name of the erroneous element. + const Message* descriptor, // Descriptor of the erroneous element. + ErrorLocation location, // One of the location constants, above. + const string& message // Human-readable error message. + ) = 0; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ErrorCollector); + }; + + // Convert the FileDescriptorProto to real descriptors and place them in + // this DescriptorPool. All dependencies of the file must already be in + // the pool. Returns the resulting FileDescriptor, or NULL if there were + // problems with the input (e.g. the message was invalid, or dependencies + // were missing). Details about the errors are written to GOOGLE_LOG(ERROR). + const FileDescriptor* BuildFile(const FileDescriptorProto& proto); + + // Same as BuildFile() except errors are sent to the given ErrorCollector. + const FileDescriptor* BuildFileCollectingErrors( + const FileDescriptorProto& proto, + ErrorCollector* error_collector); + + // By default, it is an error if a FileDescriptorProto contains references + // to types or other files that are not found in the DescriptorPool (or its + // backing DescriptorDatabase, if any). If you call + // AllowUnknownDependencies(), however, then unknown types and files + // will be replaced by placeholder descriptors. This can allow you to + // perform some useful operations with a .proto file even if you do not + // have access to other .proto files on which it depends. However, some + // heuristics must be used to fill in the gaps in information, and these + // can lead to descriptors which are inaccurate. For example, the + // DescriptorPool may be forced to guess whether an unknown type is a message + // or an enum, as well as what package it resides in. Furthermore, + // placeholder types will not be discoverable via FindMessageTypeByName() + // and similar methods, which could confuse some descriptor-based algorithms. + // Generally, the results of this option should only be relied upon for + // debugging purposes. + void AllowUnknownDependencies() { allow_unknown_ = true; } + + // Internal stuff -------------------------------------------------- + // These methods MUST NOT be called from outside the proto2 library. + // These methods may contain hidden pitfalls and may be removed in a + // future library version. + + // Create a DescriptorPool which is overlaid on top of some other pool. + // If you search for a descriptor in the overlay and it is not found, the + // underlay will be searched as a backup. If the underlay has its own + // underlay, that will be searched next, and so on. This also means that + // files built in the overlay will be cross-linked with the underlay's + // descriptors if necessary. The underlay remains property of the caller; + // it must remain valid for the lifetime of the newly-constructed pool. + // + // Example: Say you want to parse a .proto file at runtime in order to use + // its type with a DynamicMessage. Say this .proto file has dependencies, + // but you know that all the dependencies will be things that are already + // compiled into the binary. For ease of use, you'd like to load the types + // right out of generated_pool() rather than have to parse redundant copies + // of all these .protos and runtime. But, you don't want to add the parsed + // types directly into generated_pool(): this is not allowed, and would be + // bad design anyway. So, instead, you could use generated_pool() as an + // underlay for a new DescriptorPool in which you add only the new file. + // + // WARNING: Use of underlays can lead to many subtle gotchas. Instead, + // try to formulate what you want to do in terms of DescriptorDatabases. + explicit DescriptorPool(const DescriptorPool* underlay); + + // Called by generated classes at init time to add their descriptors to + // generated_pool. Do NOT call this in your own code! filename must be a + // permanent string (e.g. a string literal). + static void InternalAddGeneratedFile( + const void* encoded_file_descriptor, int size); + + + // For internal use only: Gets a non-const pointer to the generated pool. + // This is called at static-initialization time only, so thread-safety is + // not a concern. If both an underlay and a fallback database are present, + // the fallback database takes precedence. + static DescriptorPool* internal_generated_pool(); + + // For internal use only: Changes the behavior of BuildFile() such that it + // allows the file to make reference to message types declared in other files + // which it did not officially declare as dependencies. + void InternalDontEnforceDependencies(); + + // For internal use only. + void internal_set_underlay(const DescriptorPool* underlay) { + underlay_ = underlay; + } + + // For internal (unit test) use only: Returns true if a FileDescriptor has + // been constructed for the given file, false otherwise. Useful for testing + // lazy descriptor initialization behavior. + bool InternalIsFileLoaded(const string& filename) const; + + private: + friend class Descriptor; + friend class FieldDescriptor; + friend class EnumDescriptor; + friend class ServiceDescriptor; + friend class FileDescriptor; + friend class DescriptorBuilder; + + // Tries to find something in the fallback database and link in the + // corresponding proto file. Returns true if successful, in which case + // the caller should search for the thing again. These are declared + // const because they are called by (semantically) const methods. + bool TryFindFileInFallbackDatabase(const string& name) const; + bool TryFindSymbolInFallbackDatabase(const string& name) const; + bool TryFindExtensionInFallbackDatabase(const Descriptor* containing_type, + int field_number) const; + + // Like BuildFile() but called internally when the file has been loaded from + // fallback_database_. Declared const because it is called by (semantically) + // const methods. + const FileDescriptor* BuildFileFromDatabase( + const FileDescriptorProto& proto) const; + + // If fallback_database_ is NULL, this is NULL. Otherwise, this is a mutex + // which must be locked while accessing tables_. + Mutex* mutex_; + + // See constructor. + DescriptorDatabase* fallback_database_; + ErrorCollector* default_error_collector_; + const DescriptorPool* underlay_; + + // This class contains a lot of hash maps with complicated types that + // we'd like to keep out of the header. + class Tables; + scoped_ptr tables_; + + bool enforce_dependencies_; + bool allow_unknown_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DescriptorPool); +}; + +// inline methods ==================================================== + +// These macros makes this repetitive code more readable. +#define PROTOBUF_DEFINE_ACCESSOR(CLASS, FIELD, TYPE) \ + inline TYPE CLASS::FIELD() const { return FIELD##_; } + +// Strings fields are stored as pointers but returned as const references. +#define PROTOBUF_DEFINE_STRING_ACCESSOR(CLASS, FIELD) \ + inline const string& CLASS::FIELD() const { return *FIELD##_; } + +// Arrays take an index parameter, obviously. +#define PROTOBUF_DEFINE_ARRAY_ACCESSOR(CLASS, FIELD, TYPE) \ + inline TYPE CLASS::FIELD(int index) const { return FIELD##s_ + index; } + +#define PROTOBUF_DEFINE_OPTIONS_ACCESSOR(CLASS, TYPE) \ + inline const TYPE& CLASS::options() const { return *options_; } + +PROTOBUF_DEFINE_STRING_ACCESSOR(Descriptor, name) +PROTOBUF_DEFINE_STRING_ACCESSOR(Descriptor, full_name) +PROTOBUF_DEFINE_ACCESSOR(Descriptor, file, const FileDescriptor*) +PROTOBUF_DEFINE_ACCESSOR(Descriptor, containing_type, const Descriptor*) + +PROTOBUF_DEFINE_ACCESSOR(Descriptor, field_count, int) +PROTOBUF_DEFINE_ACCESSOR(Descriptor, nested_type_count, int) +PROTOBUF_DEFINE_ACCESSOR(Descriptor, enum_type_count, int) + +PROTOBUF_DEFINE_ARRAY_ACCESSOR(Descriptor, field, const FieldDescriptor*) +PROTOBUF_DEFINE_ARRAY_ACCESSOR(Descriptor, nested_type, const Descriptor*) +PROTOBUF_DEFINE_ARRAY_ACCESSOR(Descriptor, enum_type, const EnumDescriptor*) + +PROTOBUF_DEFINE_ACCESSOR(Descriptor, extension_range_count, int) +PROTOBUF_DEFINE_ACCESSOR(Descriptor, extension_count, int) +PROTOBUF_DEFINE_ARRAY_ACCESSOR(Descriptor, extension_range, + const Descriptor::ExtensionRange*) +PROTOBUF_DEFINE_ARRAY_ACCESSOR(Descriptor, extension, + const FieldDescriptor*) +PROTOBUF_DEFINE_OPTIONS_ACCESSOR(Descriptor, MessageOptions); + +PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, name) +PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, full_name) +PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, lowercase_name) +PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, camelcase_name) +PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, file, const FileDescriptor*) +PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, number, int) +PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, is_extension, bool) +PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, type, FieldDescriptor::Type) +PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, label, FieldDescriptor::Label) +PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, containing_type, const Descriptor*) +PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, extension_scope, const Descriptor*) +PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, message_type, const Descriptor*) +PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, enum_type, const EnumDescriptor*) +PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, experimental_map_key, + const FieldDescriptor*) +PROTOBUF_DEFINE_OPTIONS_ACCESSOR(FieldDescriptor, FieldOptions); +PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, has_default_value, bool) +PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_int32 , int32 ) +PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_int64 , int64 ) +PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_uint32, uint32) +PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_uint64, uint64) +PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_float , float ) +PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_double, double) +PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_bool , bool ) +PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_enum, + const EnumValueDescriptor*) +PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, default_value_string) + +PROTOBUF_DEFINE_STRING_ACCESSOR(EnumDescriptor, name) +PROTOBUF_DEFINE_STRING_ACCESSOR(EnumDescriptor, full_name) +PROTOBUF_DEFINE_ACCESSOR(EnumDescriptor, file, const FileDescriptor*) +PROTOBUF_DEFINE_ACCESSOR(EnumDescriptor, containing_type, const Descriptor*) +PROTOBUF_DEFINE_ACCESSOR(EnumDescriptor, value_count, int) +PROTOBUF_DEFINE_ARRAY_ACCESSOR(EnumDescriptor, value, + const EnumValueDescriptor*) +PROTOBUF_DEFINE_OPTIONS_ACCESSOR(EnumDescriptor, EnumOptions); + +PROTOBUF_DEFINE_STRING_ACCESSOR(EnumValueDescriptor, name) +PROTOBUF_DEFINE_STRING_ACCESSOR(EnumValueDescriptor, full_name) +PROTOBUF_DEFINE_ACCESSOR(EnumValueDescriptor, number, int) +PROTOBUF_DEFINE_ACCESSOR(EnumValueDescriptor, type, const EnumDescriptor*) +PROTOBUF_DEFINE_OPTIONS_ACCESSOR(EnumValueDescriptor, EnumValueOptions); + +PROTOBUF_DEFINE_STRING_ACCESSOR(ServiceDescriptor, name) +PROTOBUF_DEFINE_STRING_ACCESSOR(ServiceDescriptor, full_name) +PROTOBUF_DEFINE_ACCESSOR(ServiceDescriptor, file, const FileDescriptor*) +PROTOBUF_DEFINE_ACCESSOR(ServiceDescriptor, method_count, int) +PROTOBUF_DEFINE_ARRAY_ACCESSOR(ServiceDescriptor, method, + const MethodDescriptor*) +PROTOBUF_DEFINE_OPTIONS_ACCESSOR(ServiceDescriptor, ServiceOptions); + +PROTOBUF_DEFINE_STRING_ACCESSOR(MethodDescriptor, name) +PROTOBUF_DEFINE_STRING_ACCESSOR(MethodDescriptor, full_name) +PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, service, const ServiceDescriptor*) +PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, input_type, const Descriptor*) +PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, output_type, const Descriptor*) +PROTOBUF_DEFINE_OPTIONS_ACCESSOR(MethodDescriptor, MethodOptions); + +PROTOBUF_DEFINE_STRING_ACCESSOR(FileDescriptor, name) +PROTOBUF_DEFINE_STRING_ACCESSOR(FileDescriptor, package) +PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, pool, const DescriptorPool*) +PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, dependency_count, int) +PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, message_type_count, int) +PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, enum_type_count, int) +PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, service_count, int) +PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, extension_count, int) +PROTOBUF_DEFINE_OPTIONS_ACCESSOR(FileDescriptor, FileOptions); + +PROTOBUF_DEFINE_ARRAY_ACCESSOR(FileDescriptor, message_type, const Descriptor*) +PROTOBUF_DEFINE_ARRAY_ACCESSOR(FileDescriptor, enum_type, const EnumDescriptor*) +PROTOBUF_DEFINE_ARRAY_ACCESSOR(FileDescriptor, service, + const ServiceDescriptor*) +PROTOBUF_DEFINE_ARRAY_ACCESSOR(FileDescriptor, extension, + const FieldDescriptor*) + +#undef PROTOBUF_DEFINE_ACCESSOR +#undef PROTOBUF_DEFINE_STRING_ACCESSOR +#undef PROTOBUF_DEFINE_ARRAY_ACCESSOR + +// A few accessors differ from the macros... + +inline bool FieldDescriptor::is_required() const { + return label() == LABEL_REQUIRED; +} + +inline bool FieldDescriptor::is_optional() const { + return label() == LABEL_OPTIONAL; +} + +inline bool FieldDescriptor::is_repeated() const { + return label() == LABEL_REPEATED; +} + +inline bool FieldDescriptor::is_packable() const { + return is_repeated() && IsTypePackable(type()); +} + +// To save space, index() is computed by looking at the descriptor's position +// in the parent's array of children. +inline int FieldDescriptor::index() const { + if (!is_extension_) { + return this - containing_type_->fields_; + } else if (extension_scope_ != NULL) { + return this - extension_scope_->extensions_; + } else { + return this - file_->extensions_; + } +} + +inline int Descriptor::index() const { + if (containing_type_ == NULL) { + return this - file_->message_types_; + } else { + return this - containing_type_->nested_types_; + } +} + +inline int EnumDescriptor::index() const { + if (containing_type_ == NULL) { + return this - file_->enum_types_; + } else { + return this - containing_type_->enum_types_; + } +} + +inline int EnumValueDescriptor::index() const { + return this - type_->values_; +} + +inline int ServiceDescriptor::index() const { + return this - file_->services_; +} + +inline int MethodDescriptor::index() const { + return this - service_->methods_; +} + +inline FieldDescriptor::CppType FieldDescriptor::cpp_type() const { + return kTypeToCppTypeMap[type_]; +} + +inline FieldDescriptor::CppType FieldDescriptor::TypeToCppType(Type type) { + return kTypeToCppTypeMap[type]; +} + +inline bool FieldDescriptor::IsTypePackable(Type field_type) { + return (field_type != FieldDescriptor::TYPE_STRING && + field_type != FieldDescriptor::TYPE_GROUP && + field_type != FieldDescriptor::TYPE_MESSAGE && + field_type != FieldDescriptor::TYPE_BYTES); +} + +inline const FileDescriptor* FileDescriptor::dependency(int index) const { + return dependencies_[index]; +} + +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_DESCRIPTOR_H__ diff --git a/depends/protobuf/google/protobuf/descriptor.pb.cc b/depends/protobuf/google/protobuf/descriptor.pb.cc new file mode 100644 index 0000000000..87303ef87b --- /dev/null +++ b/depends/protobuf/google/protobuf/descriptor.pb.cc @@ -0,0 +1,7708 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! + +#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION +#include "google/protobuf/descriptor.pb.h" + +#include + +#include +#include +#include +#include +#include +#include +// @@protoc_insertion_point(includes) + +namespace google { +namespace protobuf { + +namespace { + +const ::google::protobuf::Descriptor* FileDescriptorSet_descriptor_ = NULL; +const ::google::protobuf::internal::GeneratedMessageReflection* + FileDescriptorSet_reflection_ = NULL; +const ::google::protobuf::Descriptor* FileDescriptorProto_descriptor_ = NULL; +const ::google::protobuf::internal::GeneratedMessageReflection* + FileDescriptorProto_reflection_ = NULL; +const ::google::protobuf::Descriptor* DescriptorProto_descriptor_ = NULL; +const ::google::protobuf::internal::GeneratedMessageReflection* + DescriptorProto_reflection_ = NULL; +const ::google::protobuf::Descriptor* DescriptorProto_ExtensionRange_descriptor_ = NULL; +const ::google::protobuf::internal::GeneratedMessageReflection* + DescriptorProto_ExtensionRange_reflection_ = NULL; +const ::google::protobuf::Descriptor* FieldDescriptorProto_descriptor_ = NULL; +const ::google::protobuf::internal::GeneratedMessageReflection* + FieldDescriptorProto_reflection_ = NULL; +const ::google::protobuf::EnumDescriptor* FieldDescriptorProto_Type_descriptor_ = NULL; +const ::google::protobuf::EnumDescriptor* FieldDescriptorProto_Label_descriptor_ = NULL; +const ::google::protobuf::Descriptor* EnumDescriptorProto_descriptor_ = NULL; +const ::google::protobuf::internal::GeneratedMessageReflection* + EnumDescriptorProto_reflection_ = NULL; +const ::google::protobuf::Descriptor* EnumValueDescriptorProto_descriptor_ = NULL; +const ::google::protobuf::internal::GeneratedMessageReflection* + EnumValueDescriptorProto_reflection_ = NULL; +const ::google::protobuf::Descriptor* ServiceDescriptorProto_descriptor_ = NULL; +const ::google::protobuf::internal::GeneratedMessageReflection* + ServiceDescriptorProto_reflection_ = NULL; +const ::google::protobuf::Descriptor* MethodDescriptorProto_descriptor_ = NULL; +const ::google::protobuf::internal::GeneratedMessageReflection* + MethodDescriptorProto_reflection_ = NULL; +const ::google::protobuf::Descriptor* FileOptions_descriptor_ = NULL; +const ::google::protobuf::internal::GeneratedMessageReflection* + FileOptions_reflection_ = NULL; +const ::google::protobuf::EnumDescriptor* FileOptions_OptimizeMode_descriptor_ = NULL; +const ::google::protobuf::Descriptor* MessageOptions_descriptor_ = NULL; +const ::google::protobuf::internal::GeneratedMessageReflection* + MessageOptions_reflection_ = NULL; +const ::google::protobuf::Descriptor* FieldOptions_descriptor_ = NULL; +const ::google::protobuf::internal::GeneratedMessageReflection* + FieldOptions_reflection_ = NULL; +const ::google::protobuf::EnumDescriptor* FieldOptions_CType_descriptor_ = NULL; +const ::google::protobuf::Descriptor* EnumOptions_descriptor_ = NULL; +const ::google::protobuf::internal::GeneratedMessageReflection* + EnumOptions_reflection_ = NULL; +const ::google::protobuf::Descriptor* EnumValueOptions_descriptor_ = NULL; +const ::google::protobuf::internal::GeneratedMessageReflection* + EnumValueOptions_reflection_ = NULL; +const ::google::protobuf::Descriptor* ServiceOptions_descriptor_ = NULL; +const ::google::protobuf::internal::GeneratedMessageReflection* + ServiceOptions_reflection_ = NULL; +const ::google::protobuf::Descriptor* MethodOptions_descriptor_ = NULL; +const ::google::protobuf::internal::GeneratedMessageReflection* + MethodOptions_reflection_ = NULL; +const ::google::protobuf::Descriptor* UninterpretedOption_descriptor_ = NULL; +const ::google::protobuf::internal::GeneratedMessageReflection* + UninterpretedOption_reflection_ = NULL; +const ::google::protobuf::Descriptor* UninterpretedOption_NamePart_descriptor_ = NULL; +const ::google::protobuf::internal::GeneratedMessageReflection* + UninterpretedOption_NamePart_reflection_ = NULL; +const ::google::protobuf::Descriptor* SourceCodeInfo_descriptor_ = NULL; +const ::google::protobuf::internal::GeneratedMessageReflection* + SourceCodeInfo_reflection_ = NULL; +const ::google::protobuf::Descriptor* SourceCodeInfo_Location_descriptor_ = NULL; +const ::google::protobuf::internal::GeneratedMessageReflection* + SourceCodeInfo_Location_reflection_ = NULL; + +} // namespace + + +void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { + protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + const ::google::protobuf::FileDescriptor* file = + ::google::protobuf::DescriptorPool::generated_pool()->FindFileByName( + "google/protobuf/descriptor.proto"); + GOOGLE_CHECK(file != NULL); + FileDescriptorSet_descriptor_ = file->message_type(0); + static const int FileDescriptorSet_offsets_[1] = { + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorSet, file_), + }; + FileDescriptorSet_reflection_ = + new ::google::protobuf::internal::GeneratedMessageReflection( + FileDescriptorSet_descriptor_, + FileDescriptorSet::default_instance_, + FileDescriptorSet_offsets_, + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorSet, _has_bits_[0]), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorSet, _unknown_fields_), + -1, + ::google::protobuf::DescriptorPool::generated_pool(), + ::google::protobuf::MessageFactory::generated_factory(), + sizeof(FileDescriptorSet)); + FileDescriptorProto_descriptor_ = file->message_type(1); + static const int FileDescriptorProto_offsets_[9] = { + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, name_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, package_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, dependency_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, message_type_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, enum_type_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, service_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, extension_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, options_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, source_code_info_), + }; + FileDescriptorProto_reflection_ = + new ::google::protobuf::internal::GeneratedMessageReflection( + FileDescriptorProto_descriptor_, + FileDescriptorProto::default_instance_, + FileDescriptorProto_offsets_, + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, _has_bits_[0]), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, _unknown_fields_), + -1, + ::google::protobuf::DescriptorPool::generated_pool(), + ::google::protobuf::MessageFactory::generated_factory(), + sizeof(FileDescriptorProto)); + DescriptorProto_descriptor_ = file->message_type(2); + static const int DescriptorProto_offsets_[7] = { + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, name_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, field_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, extension_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, nested_type_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, enum_type_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, extension_range_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, options_), + }; + DescriptorProto_reflection_ = + new ::google::protobuf::internal::GeneratedMessageReflection( + DescriptorProto_descriptor_, + DescriptorProto::default_instance_, + DescriptorProto_offsets_, + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, _has_bits_[0]), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, _unknown_fields_), + -1, + ::google::protobuf::DescriptorPool::generated_pool(), + ::google::protobuf::MessageFactory::generated_factory(), + sizeof(DescriptorProto)); + DescriptorProto_ExtensionRange_descriptor_ = DescriptorProto_descriptor_->nested_type(0); + static const int DescriptorProto_ExtensionRange_offsets_[2] = { + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto_ExtensionRange, start_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto_ExtensionRange, end_), + }; + DescriptorProto_ExtensionRange_reflection_ = + new ::google::protobuf::internal::GeneratedMessageReflection( + DescriptorProto_ExtensionRange_descriptor_, + DescriptorProto_ExtensionRange::default_instance_, + DescriptorProto_ExtensionRange_offsets_, + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto_ExtensionRange, _has_bits_[0]), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto_ExtensionRange, _unknown_fields_), + -1, + ::google::protobuf::DescriptorPool::generated_pool(), + ::google::protobuf::MessageFactory::generated_factory(), + sizeof(DescriptorProto_ExtensionRange)); + FieldDescriptorProto_descriptor_ = file->message_type(3); + static const int FieldDescriptorProto_offsets_[8] = { + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, name_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, number_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, label_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, type_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, type_name_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, extendee_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, default_value_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, options_), + }; + FieldDescriptorProto_reflection_ = + new ::google::protobuf::internal::GeneratedMessageReflection( + FieldDescriptorProto_descriptor_, + FieldDescriptorProto::default_instance_, + FieldDescriptorProto_offsets_, + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, _has_bits_[0]), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, _unknown_fields_), + -1, + ::google::protobuf::DescriptorPool::generated_pool(), + ::google::protobuf::MessageFactory::generated_factory(), + sizeof(FieldDescriptorProto)); + FieldDescriptorProto_Type_descriptor_ = FieldDescriptorProto_descriptor_->enum_type(0); + FieldDescriptorProto_Label_descriptor_ = FieldDescriptorProto_descriptor_->enum_type(1); + EnumDescriptorProto_descriptor_ = file->message_type(4); + static const int EnumDescriptorProto_offsets_[3] = { + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumDescriptorProto, name_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumDescriptorProto, value_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumDescriptorProto, options_), + }; + EnumDescriptorProto_reflection_ = + new ::google::protobuf::internal::GeneratedMessageReflection( + EnumDescriptorProto_descriptor_, + EnumDescriptorProto::default_instance_, + EnumDescriptorProto_offsets_, + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumDescriptorProto, _has_bits_[0]), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumDescriptorProto, _unknown_fields_), + -1, + ::google::protobuf::DescriptorPool::generated_pool(), + ::google::protobuf::MessageFactory::generated_factory(), + sizeof(EnumDescriptorProto)); + EnumValueDescriptorProto_descriptor_ = file->message_type(5); + static const int EnumValueDescriptorProto_offsets_[3] = { + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueDescriptorProto, name_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueDescriptorProto, number_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueDescriptorProto, options_), + }; + EnumValueDescriptorProto_reflection_ = + new ::google::protobuf::internal::GeneratedMessageReflection( + EnumValueDescriptorProto_descriptor_, + EnumValueDescriptorProto::default_instance_, + EnumValueDescriptorProto_offsets_, + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueDescriptorProto, _has_bits_[0]), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueDescriptorProto, _unknown_fields_), + -1, + ::google::protobuf::DescriptorPool::generated_pool(), + ::google::protobuf::MessageFactory::generated_factory(), + sizeof(EnumValueDescriptorProto)); + ServiceDescriptorProto_descriptor_ = file->message_type(6); + static const int ServiceDescriptorProto_offsets_[3] = { + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceDescriptorProto, name_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceDescriptorProto, method_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceDescriptorProto, options_), + }; + ServiceDescriptorProto_reflection_ = + new ::google::protobuf::internal::GeneratedMessageReflection( + ServiceDescriptorProto_descriptor_, + ServiceDescriptorProto::default_instance_, + ServiceDescriptorProto_offsets_, + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceDescriptorProto, _has_bits_[0]), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceDescriptorProto, _unknown_fields_), + -1, + ::google::protobuf::DescriptorPool::generated_pool(), + ::google::protobuf::MessageFactory::generated_factory(), + sizeof(ServiceDescriptorProto)); + MethodDescriptorProto_descriptor_ = file->message_type(7); + static const int MethodDescriptorProto_offsets_[4] = { + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodDescriptorProto, name_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodDescriptorProto, input_type_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodDescriptorProto, output_type_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodDescriptorProto, options_), + }; + MethodDescriptorProto_reflection_ = + new ::google::protobuf::internal::GeneratedMessageReflection( + MethodDescriptorProto_descriptor_, + MethodDescriptorProto::default_instance_, + MethodDescriptorProto_offsets_, + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodDescriptorProto, _has_bits_[0]), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodDescriptorProto, _unknown_fields_), + -1, + ::google::protobuf::DescriptorPool::generated_pool(), + ::google::protobuf::MessageFactory::generated_factory(), + sizeof(MethodDescriptorProto)); + FileOptions_descriptor_ = file->message_type(8); + static const int FileOptions_offsets_[9] = { + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, java_package_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, java_outer_classname_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, java_multiple_files_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, java_generate_equals_and_hash_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, optimize_for_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, cc_generic_services_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, java_generic_services_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, py_generic_services_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, uninterpreted_option_), + }; + FileOptions_reflection_ = + new ::google::protobuf::internal::GeneratedMessageReflection( + FileOptions_descriptor_, + FileOptions::default_instance_, + FileOptions_offsets_, + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, _has_bits_[0]), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, _unknown_fields_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, _extensions_), + ::google::protobuf::DescriptorPool::generated_pool(), + ::google::protobuf::MessageFactory::generated_factory(), + sizeof(FileOptions)); + FileOptions_OptimizeMode_descriptor_ = FileOptions_descriptor_->enum_type(0); + MessageOptions_descriptor_ = file->message_type(9); + static const int MessageOptions_offsets_[3] = { + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageOptions, message_set_wire_format_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageOptions, no_standard_descriptor_accessor_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageOptions, uninterpreted_option_), + }; + MessageOptions_reflection_ = + new ::google::protobuf::internal::GeneratedMessageReflection( + MessageOptions_descriptor_, + MessageOptions::default_instance_, + MessageOptions_offsets_, + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageOptions, _has_bits_[0]), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageOptions, _unknown_fields_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageOptions, _extensions_), + ::google::protobuf::DescriptorPool::generated_pool(), + ::google::protobuf::MessageFactory::generated_factory(), + sizeof(MessageOptions)); + FieldOptions_descriptor_ = file->message_type(10); + static const int FieldOptions_offsets_[5] = { + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, ctype_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, packed_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, deprecated_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, experimental_map_key_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, uninterpreted_option_), + }; + FieldOptions_reflection_ = + new ::google::protobuf::internal::GeneratedMessageReflection( + FieldOptions_descriptor_, + FieldOptions::default_instance_, + FieldOptions_offsets_, + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, _has_bits_[0]), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, _unknown_fields_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, _extensions_), + ::google::protobuf::DescriptorPool::generated_pool(), + ::google::protobuf::MessageFactory::generated_factory(), + sizeof(FieldOptions)); + FieldOptions_CType_descriptor_ = FieldOptions_descriptor_->enum_type(0); + EnumOptions_descriptor_ = file->message_type(11); + static const int EnumOptions_offsets_[1] = { + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumOptions, uninterpreted_option_), + }; + EnumOptions_reflection_ = + new ::google::protobuf::internal::GeneratedMessageReflection( + EnumOptions_descriptor_, + EnumOptions::default_instance_, + EnumOptions_offsets_, + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumOptions, _has_bits_[0]), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumOptions, _unknown_fields_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumOptions, _extensions_), + ::google::protobuf::DescriptorPool::generated_pool(), + ::google::protobuf::MessageFactory::generated_factory(), + sizeof(EnumOptions)); + EnumValueOptions_descriptor_ = file->message_type(12); + static const int EnumValueOptions_offsets_[1] = { + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueOptions, uninterpreted_option_), + }; + EnumValueOptions_reflection_ = + new ::google::protobuf::internal::GeneratedMessageReflection( + EnumValueOptions_descriptor_, + EnumValueOptions::default_instance_, + EnumValueOptions_offsets_, + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueOptions, _has_bits_[0]), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueOptions, _unknown_fields_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueOptions, _extensions_), + ::google::protobuf::DescriptorPool::generated_pool(), + ::google::protobuf::MessageFactory::generated_factory(), + sizeof(EnumValueOptions)); + ServiceOptions_descriptor_ = file->message_type(13); + static const int ServiceOptions_offsets_[1] = { + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceOptions, uninterpreted_option_), + }; + ServiceOptions_reflection_ = + new ::google::protobuf::internal::GeneratedMessageReflection( + ServiceOptions_descriptor_, + ServiceOptions::default_instance_, + ServiceOptions_offsets_, + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceOptions, _has_bits_[0]), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceOptions, _unknown_fields_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceOptions, _extensions_), + ::google::protobuf::DescriptorPool::generated_pool(), + ::google::protobuf::MessageFactory::generated_factory(), + sizeof(ServiceOptions)); + MethodOptions_descriptor_ = file->message_type(14); + static const int MethodOptions_offsets_[1] = { + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodOptions, uninterpreted_option_), + }; + MethodOptions_reflection_ = + new ::google::protobuf::internal::GeneratedMessageReflection( + MethodOptions_descriptor_, + MethodOptions::default_instance_, + MethodOptions_offsets_, + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodOptions, _has_bits_[0]), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodOptions, _unknown_fields_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodOptions, _extensions_), + ::google::protobuf::DescriptorPool::generated_pool(), + ::google::protobuf::MessageFactory::generated_factory(), + sizeof(MethodOptions)); + UninterpretedOption_descriptor_ = file->message_type(15); + static const int UninterpretedOption_offsets_[7] = { + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption, name_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption, identifier_value_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption, positive_int_value_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption, negative_int_value_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption, double_value_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption, string_value_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption, aggregate_value_), + }; + UninterpretedOption_reflection_ = + new ::google::protobuf::internal::GeneratedMessageReflection( + UninterpretedOption_descriptor_, + UninterpretedOption::default_instance_, + UninterpretedOption_offsets_, + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption, _has_bits_[0]), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption, _unknown_fields_), + -1, + ::google::protobuf::DescriptorPool::generated_pool(), + ::google::protobuf::MessageFactory::generated_factory(), + sizeof(UninterpretedOption)); + UninterpretedOption_NamePart_descriptor_ = UninterpretedOption_descriptor_->nested_type(0); + static const int UninterpretedOption_NamePart_offsets_[2] = { + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption_NamePart, name_part_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption_NamePart, is_extension_), + }; + UninterpretedOption_NamePart_reflection_ = + new ::google::protobuf::internal::GeneratedMessageReflection( + UninterpretedOption_NamePart_descriptor_, + UninterpretedOption_NamePart::default_instance_, + UninterpretedOption_NamePart_offsets_, + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption_NamePart, _has_bits_[0]), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption_NamePart, _unknown_fields_), + -1, + ::google::protobuf::DescriptorPool::generated_pool(), + ::google::protobuf::MessageFactory::generated_factory(), + sizeof(UninterpretedOption_NamePart)); + SourceCodeInfo_descriptor_ = file->message_type(16); + static const int SourceCodeInfo_offsets_[1] = { + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo, location_), + }; + SourceCodeInfo_reflection_ = + new ::google::protobuf::internal::GeneratedMessageReflection( + SourceCodeInfo_descriptor_, + SourceCodeInfo::default_instance_, + SourceCodeInfo_offsets_, + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo, _has_bits_[0]), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo, _unknown_fields_), + -1, + ::google::protobuf::DescriptorPool::generated_pool(), + ::google::protobuf::MessageFactory::generated_factory(), + sizeof(SourceCodeInfo)); + SourceCodeInfo_Location_descriptor_ = SourceCodeInfo_descriptor_->nested_type(0); + static const int SourceCodeInfo_Location_offsets_[2] = { + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo_Location, path_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo_Location, span_), + }; + SourceCodeInfo_Location_reflection_ = + new ::google::protobuf::internal::GeneratedMessageReflection( + SourceCodeInfo_Location_descriptor_, + SourceCodeInfo_Location::default_instance_, + SourceCodeInfo_Location_offsets_, + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo_Location, _has_bits_[0]), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo_Location, _unknown_fields_), + -1, + ::google::protobuf::DescriptorPool::generated_pool(), + ::google::protobuf::MessageFactory::generated_factory(), + sizeof(SourceCodeInfo_Location)); +} + +namespace { + +GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_); +inline void protobuf_AssignDescriptorsOnce() { + ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_, + &protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto); +} + +void protobuf_RegisterTypes(const ::std::string&) { + protobuf_AssignDescriptorsOnce(); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( + FileDescriptorSet_descriptor_, &FileDescriptorSet::default_instance()); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( + FileDescriptorProto_descriptor_, &FileDescriptorProto::default_instance()); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( + DescriptorProto_descriptor_, &DescriptorProto::default_instance()); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( + DescriptorProto_ExtensionRange_descriptor_, &DescriptorProto_ExtensionRange::default_instance()); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( + FieldDescriptorProto_descriptor_, &FieldDescriptorProto::default_instance()); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( + EnumDescriptorProto_descriptor_, &EnumDescriptorProto::default_instance()); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( + EnumValueDescriptorProto_descriptor_, &EnumValueDescriptorProto::default_instance()); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( + ServiceDescriptorProto_descriptor_, &ServiceDescriptorProto::default_instance()); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( + MethodDescriptorProto_descriptor_, &MethodDescriptorProto::default_instance()); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( + FileOptions_descriptor_, &FileOptions::default_instance()); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( + MessageOptions_descriptor_, &MessageOptions::default_instance()); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( + FieldOptions_descriptor_, &FieldOptions::default_instance()); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( + EnumOptions_descriptor_, &EnumOptions::default_instance()); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( + EnumValueOptions_descriptor_, &EnumValueOptions::default_instance()); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( + ServiceOptions_descriptor_, &ServiceOptions::default_instance()); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( + MethodOptions_descriptor_, &MethodOptions::default_instance()); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( + UninterpretedOption_descriptor_, &UninterpretedOption::default_instance()); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( + UninterpretedOption_NamePart_descriptor_, &UninterpretedOption_NamePart::default_instance()); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( + SourceCodeInfo_descriptor_, &SourceCodeInfo::default_instance()); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( + SourceCodeInfo_Location_descriptor_, &SourceCodeInfo_Location::default_instance()); +} + +} // namespace + +void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto() { + delete FileDescriptorSet::default_instance_; + delete FileDescriptorSet_reflection_; + delete FileDescriptorProto::default_instance_; + delete FileDescriptorProto_reflection_; + delete DescriptorProto::default_instance_; + delete DescriptorProto_reflection_; + delete DescriptorProto_ExtensionRange::default_instance_; + delete DescriptorProto_ExtensionRange_reflection_; + delete FieldDescriptorProto::default_instance_; + delete FieldDescriptorProto_reflection_; + delete EnumDescriptorProto::default_instance_; + delete EnumDescriptorProto_reflection_; + delete EnumValueDescriptorProto::default_instance_; + delete EnumValueDescriptorProto_reflection_; + delete ServiceDescriptorProto::default_instance_; + delete ServiceDescriptorProto_reflection_; + delete MethodDescriptorProto::default_instance_; + delete MethodDescriptorProto_reflection_; + delete FileOptions::default_instance_; + delete FileOptions_reflection_; + delete MessageOptions::default_instance_; + delete MessageOptions_reflection_; + delete FieldOptions::default_instance_; + delete FieldOptions_reflection_; + delete EnumOptions::default_instance_; + delete EnumOptions_reflection_; + delete EnumValueOptions::default_instance_; + delete EnumValueOptions_reflection_; + delete ServiceOptions::default_instance_; + delete ServiceOptions_reflection_; + delete MethodOptions::default_instance_; + delete MethodOptions_reflection_; + delete UninterpretedOption::default_instance_; + delete UninterpretedOption_reflection_; + delete UninterpretedOption_NamePart::default_instance_; + delete UninterpretedOption_NamePart_reflection_; + delete SourceCodeInfo::default_instance_; + delete SourceCodeInfo_reflection_; + delete SourceCodeInfo_Location::default_instance_; + delete SourceCodeInfo_Location_reflection_; +} + +void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto() { + static bool already_here = false; + if (already_here) return; + already_here = true; + GOOGLE_PROTOBUF_VERIFY_VERSION; + + ::google::protobuf::DescriptorPool::InternalAddGeneratedFile( + "\n google/protobuf/descriptor.proto\022\017goog" + "le.protobuf\"G\n\021FileDescriptorSet\0222\n\004file" + "\030\001 \003(\0132$.google.protobuf.FileDescriptorP" + "roto\"\227\003\n\023FileDescriptorProto\022\014\n\004name\030\001 \001" + "(\t\022\017\n\007package\030\002 \001(\t\022\022\n\ndependency\030\003 \003(\t\022" + "6\n\014message_type\030\004 \003(\0132 .google.protobuf." + "DescriptorProto\0227\n\tenum_type\030\005 \003(\0132$.goo" + "gle.protobuf.EnumDescriptorProto\0228\n\007serv" + "ice\030\006 \003(\0132\'.google.protobuf.ServiceDescr" + "iptorProto\0228\n\textension\030\007 \003(\0132%.google.p" + "rotobuf.FieldDescriptorProto\022-\n\007options\030" + "\010 \001(\0132\034.google.protobuf.FileOptions\0229\n\020s" + "ource_code_info\030\t \001(\0132\037.google.protobuf." + "SourceCodeInfo\"\251\003\n\017DescriptorProto\022\014\n\004na" + "me\030\001 \001(\t\0224\n\005field\030\002 \003(\0132%.google.protobu" + "f.FieldDescriptorProto\0228\n\textension\030\006 \003(" + "\0132%.google.protobuf.FieldDescriptorProto" + "\0225\n\013nested_type\030\003 \003(\0132 .google.protobuf." + "DescriptorProto\0227\n\tenum_type\030\004 \003(\0132$.goo" + "gle.protobuf.EnumDescriptorProto\022H\n\017exte" + "nsion_range\030\005 \003(\0132/.google.protobuf.Desc" + "riptorProto.ExtensionRange\0220\n\007options\030\007 " + "\001(\0132\037.google.protobuf.MessageOptions\032,\n\016" + "ExtensionRange\022\r\n\005start\030\001 \001(\005\022\013\n\003end\030\002 \001" + "(\005\"\224\005\n\024FieldDescriptorProto\022\014\n\004name\030\001 \001(" + "\t\022\016\n\006number\030\003 \001(\005\022:\n\005label\030\004 \001(\0162+.googl" + "e.protobuf.FieldDescriptorProto.Label\0228\n" + "\004type\030\005 \001(\0162*.google.protobuf.FieldDescr" + "iptorProto.Type\022\021\n\ttype_name\030\006 \001(\t\022\020\n\010ex" + "tendee\030\002 \001(\t\022\025\n\rdefault_value\030\007 \001(\t\022.\n\007o" + "ptions\030\010 \001(\0132\035.google.protobuf.FieldOpti" + "ons\"\266\002\n\004Type\022\017\n\013TYPE_DOUBLE\020\001\022\016\n\nTYPE_FL" + "OAT\020\002\022\016\n\nTYPE_INT64\020\003\022\017\n\013TYPE_UINT64\020\004\022\016" + "\n\nTYPE_INT32\020\005\022\020\n\014TYPE_FIXED64\020\006\022\020\n\014TYPE" + "_FIXED32\020\007\022\r\n\tTYPE_BOOL\020\010\022\017\n\013TYPE_STRING" + "\020\t\022\016\n\nTYPE_GROUP\020\n\022\020\n\014TYPE_MESSAGE\020\013\022\016\n\n" + "TYPE_BYTES\020\014\022\017\n\013TYPE_UINT32\020\r\022\r\n\tTYPE_EN" + "UM\020\016\022\021\n\rTYPE_SFIXED32\020\017\022\021\n\rTYPE_SFIXED64" + "\020\020\022\017\n\013TYPE_SINT32\020\021\022\017\n\013TYPE_SINT64\020\022\"C\n\005" + "Label\022\022\n\016LABEL_OPTIONAL\020\001\022\022\n\016LABEL_REQUI" + "RED\020\002\022\022\n\016LABEL_REPEATED\020\003\"\214\001\n\023EnumDescri" + "ptorProto\022\014\n\004name\030\001 \001(\t\0228\n\005value\030\002 \003(\0132)" + ".google.protobuf.EnumValueDescriptorProt" + "o\022-\n\007options\030\003 \001(\0132\034.google.protobuf.Enu" + "mOptions\"l\n\030EnumValueDescriptorProto\022\014\n\004" + "name\030\001 \001(\t\022\016\n\006number\030\002 \001(\005\0222\n\007options\030\003 " + "\001(\0132!.google.protobuf.EnumValueOptions\"\220" + "\001\n\026ServiceDescriptorProto\022\014\n\004name\030\001 \001(\t\022" + "6\n\006method\030\002 \003(\0132&.google.protobuf.Method" + "DescriptorProto\0220\n\007options\030\003 \001(\0132\037.googl" + "e.protobuf.ServiceOptions\"\177\n\025MethodDescr" + "iptorProto\022\014\n\004name\030\001 \001(\t\022\022\n\ninput_type\030\002" + " \001(\t\022\023\n\013output_type\030\003 \001(\t\022/\n\007options\030\004 \001" + "(\0132\036.google.protobuf.MethodOptions\"\325\003\n\013F" + "ileOptions\022\024\n\014java_package\030\001 \001(\t\022\034\n\024java" + "_outer_classname\030\010 \001(\t\022\"\n\023java_multiple_" + "files\030\n \001(\010:\005false\022,\n\035java_generate_equa" + "ls_and_hash\030\024 \001(\010:\005false\022F\n\014optimize_for" + "\030\t \001(\0162).google.protobuf.FileOptions.Opt" + "imizeMode:\005SPEED\022\"\n\023cc_generic_services\030" + "\020 \001(\010:\005false\022$\n\025java_generic_services\030\021 " + "\001(\010:\005false\022\"\n\023py_generic_services\030\022 \001(\010:" + "\005false\022C\n\024uninterpreted_option\030\347\007 \003(\0132$." + "google.protobuf.UninterpretedOption\":\n\014O" + "ptimizeMode\022\t\n\005SPEED\020\001\022\r\n\tCODE_SIZE\020\002\022\020\n" + "\014LITE_RUNTIME\020\003*\t\010\350\007\020\200\200\200\200\002\"\270\001\n\016MessageOp" + "tions\022&\n\027message_set_wire_format\030\001 \001(\010:\005" + "false\022.\n\037no_standard_descriptor_accessor" + "\030\002 \001(\010:\005false\022C\n\024uninterpreted_option\030\347\007" + " \003(\0132$.google.protobuf.UninterpretedOpti" + "on*\t\010\350\007\020\200\200\200\200\002\"\224\002\n\014FieldOptions\022:\n\005ctype\030" + "\001 \001(\0162#.google.protobuf.FieldOptions.CTy" + "pe:\006STRING\022\016\n\006packed\030\002 \001(\010\022\031\n\ndeprecated" + "\030\003 \001(\010:\005false\022\034\n\024experimental_map_key\030\t " + "\001(\t\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.goo" + "gle.protobuf.UninterpretedOption\"/\n\005CTyp" + "e\022\n\n\006STRING\020\000\022\010\n\004CORD\020\001\022\020\n\014STRING_PIECE\020" + "\002*\t\010\350\007\020\200\200\200\200\002\"]\n\013EnumOptions\022C\n\024uninterpr" + "eted_option\030\347\007 \003(\0132$.google.protobuf.Uni" + "nterpretedOption*\t\010\350\007\020\200\200\200\200\002\"b\n\020EnumValue" + "Options\022C\n\024uninterpreted_option\030\347\007 \003(\0132$" + ".google.protobuf.UninterpretedOption*\t\010\350" + "\007\020\200\200\200\200\002\"`\n\016ServiceOptions\022C\n\024uninterpret" + "ed_option\030\347\007 \003(\0132$.google.protobuf.Unint" + "erpretedOption*\t\010\350\007\020\200\200\200\200\002\"_\n\rMethodOptio" + "ns\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.goog" + "le.protobuf.UninterpretedOption*\t\010\350\007\020\200\200\200" + "\200\002\"\236\002\n\023UninterpretedOption\022;\n\004name\030\002 \003(\013" + "2-.google.protobuf.UninterpretedOption.N" + "amePart\022\030\n\020identifier_value\030\003 \001(\t\022\032\n\022pos" + "itive_int_value\030\004 \001(\004\022\032\n\022negative_int_va" + "lue\030\005 \001(\003\022\024\n\014double_value\030\006 \001(\001\022\024\n\014strin" + "g_value\030\007 \001(\014\022\027\n\017aggregate_value\030\010 \001(\t\0323" + "\n\010NamePart\022\021\n\tname_part\030\001 \002(\t\022\024\n\014is_exte" + "nsion\030\002 \002(\010\"|\n\016SourceCodeInfo\022:\n\010locatio" + "n\030\001 \003(\0132(.google.protobuf.SourceCodeInfo" + ".Location\032.\n\010Location\022\020\n\004path\030\001 \003(\005B\002\020\001\022" + "\020\n\004span\030\002 \003(\005B\002\020\001B)\n\023com.google.protobuf" + "B\020DescriptorProtosH\001", 3940); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( + "google/protobuf/descriptor.proto", &protobuf_RegisterTypes); + FileDescriptorSet::default_instance_ = new FileDescriptorSet(); + FileDescriptorProto::default_instance_ = new FileDescriptorProto(); + DescriptorProto::default_instance_ = new DescriptorProto(); + DescriptorProto_ExtensionRange::default_instance_ = new DescriptorProto_ExtensionRange(); + FieldDescriptorProto::default_instance_ = new FieldDescriptorProto(); + EnumDescriptorProto::default_instance_ = new EnumDescriptorProto(); + EnumValueDescriptorProto::default_instance_ = new EnumValueDescriptorProto(); + ServiceDescriptorProto::default_instance_ = new ServiceDescriptorProto(); + MethodDescriptorProto::default_instance_ = new MethodDescriptorProto(); + FileOptions::default_instance_ = new FileOptions(); + MessageOptions::default_instance_ = new MessageOptions(); + FieldOptions::default_instance_ = new FieldOptions(); + EnumOptions::default_instance_ = new EnumOptions(); + EnumValueOptions::default_instance_ = new EnumValueOptions(); + ServiceOptions::default_instance_ = new ServiceOptions(); + MethodOptions::default_instance_ = new MethodOptions(); + UninterpretedOption::default_instance_ = new UninterpretedOption(); + UninterpretedOption_NamePart::default_instance_ = new UninterpretedOption_NamePart(); + SourceCodeInfo::default_instance_ = new SourceCodeInfo(); + SourceCodeInfo_Location::default_instance_ = new SourceCodeInfo_Location(); + FileDescriptorSet::default_instance_->InitAsDefaultInstance(); + FileDescriptorProto::default_instance_->InitAsDefaultInstance(); + DescriptorProto::default_instance_->InitAsDefaultInstance(); + DescriptorProto_ExtensionRange::default_instance_->InitAsDefaultInstance(); + FieldDescriptorProto::default_instance_->InitAsDefaultInstance(); + EnumDescriptorProto::default_instance_->InitAsDefaultInstance(); + EnumValueDescriptorProto::default_instance_->InitAsDefaultInstance(); + ServiceDescriptorProto::default_instance_->InitAsDefaultInstance(); + MethodDescriptorProto::default_instance_->InitAsDefaultInstance(); + FileOptions::default_instance_->InitAsDefaultInstance(); + MessageOptions::default_instance_->InitAsDefaultInstance(); + FieldOptions::default_instance_->InitAsDefaultInstance(); + EnumOptions::default_instance_->InitAsDefaultInstance(); + EnumValueOptions::default_instance_->InitAsDefaultInstance(); + ServiceOptions::default_instance_->InitAsDefaultInstance(); + MethodOptions::default_instance_->InitAsDefaultInstance(); + UninterpretedOption::default_instance_->InitAsDefaultInstance(); + UninterpretedOption_NamePart::default_instance_->InitAsDefaultInstance(); + SourceCodeInfo::default_instance_->InitAsDefaultInstance(); + SourceCodeInfo_Location::default_instance_->InitAsDefaultInstance(); + ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto); +} + +// Force AddDescriptors() to be called at static initialization time. +struct StaticDescriptorInitializer_google_2fprotobuf_2fdescriptor_2eproto { + StaticDescriptorInitializer_google_2fprotobuf_2fdescriptor_2eproto() { + protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + } +} static_descriptor_initializer_google_2fprotobuf_2fdescriptor_2eproto_; + + +// =================================================================== + +#ifndef _MSC_VER +const int FileDescriptorSet::kFileFieldNumber; +#endif // !_MSC_VER + +FileDescriptorSet::FileDescriptorSet() + : ::google::protobuf::Message() { + SharedCtor(); +} + +void FileDescriptorSet::InitAsDefaultInstance() { +} + +FileDescriptorSet::FileDescriptorSet(const FileDescriptorSet& from) + : ::google::protobuf::Message() { + SharedCtor(); + MergeFrom(from); +} + +void FileDescriptorSet::SharedCtor() { + _cached_size_ = 0; + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + +FileDescriptorSet::~FileDescriptorSet() { + SharedDtor(); +} + +void FileDescriptorSet::SharedDtor() { + if (this != default_instance_) { + } +} + +void FileDescriptorSet::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} +const ::google::protobuf::Descriptor* FileDescriptorSet::descriptor() { + protobuf_AssignDescriptorsOnce(); + return FileDescriptorSet_descriptor_; +} + +const FileDescriptorSet& FileDescriptorSet::default_instance() { + if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_; +} + +FileDescriptorSet* FileDescriptorSet::default_instance_ = NULL; + +FileDescriptorSet* FileDescriptorSet::New() const { + return new FileDescriptorSet; +} + +void FileDescriptorSet::Clear() { + file_.Clear(); + ::memset(_has_bits_, 0, sizeof(_has_bits_)); + mutable_unknown_fields()->Clear(); +} + +bool FileDescriptorSet::MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input) { +#define DO_(EXPRESSION) if (!(EXPRESSION)) return false + ::google::protobuf::uint32 tag; + while ((tag = input->ReadTag()) != 0) { + switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { + // repeated .google.protobuf.FileDescriptorProto file = 1; + case 1: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_file: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_file())); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(10)) goto parse_file; + if (input->ExpectAtEnd()) return true; + break; + } + + default: { + handle_uninterpreted: + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { + return true; + } + DO_(::google::protobuf::internal::WireFormat::SkipField( + input, tag, mutable_unknown_fields())); + break; + } + } + } + return true; +#undef DO_ +} + +void FileDescriptorSet::SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const { + // repeated .google.protobuf.FileDescriptorProto file = 1; + for (int i = 0; i < this->file_size(); i++) { + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( + 1, this->file(i), output); + } + + if (!unknown_fields().empty()) { + ::google::protobuf::internal::WireFormat::SerializeUnknownFields( + unknown_fields(), output); + } +} + +::google::protobuf::uint8* FileDescriptorSet::SerializeWithCachedSizesToArray( + ::google::protobuf::uint8* target) const { + // repeated .google.protobuf.FileDescriptorProto file = 1; + for (int i = 0; i < this->file_size(); i++) { + target = ::google::protobuf::internal::WireFormatLite:: + WriteMessageNoVirtualToArray( + 1, this->file(i), target); + } + + if (!unknown_fields().empty()) { + target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( + unknown_fields(), target); + } + return target; +} + +int FileDescriptorSet::ByteSize() const { + int total_size = 0; + + // repeated .google.protobuf.FileDescriptorProto file = 1; + total_size += 1 * this->file_size(); + for (int i = 0; i < this->file_size(); i++) { + total_size += + ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( + this->file(i)); + } + + if (!unknown_fields().empty()) { + total_size += + ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( + unknown_fields()); + } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); + return total_size; +} + +void FileDescriptorSet::MergeFrom(const ::google::protobuf::Message& from) { + GOOGLE_CHECK_NE(&from, this); + const FileDescriptorSet* source = + ::google::protobuf::internal::dynamic_cast_if_available( + &from); + if (source == NULL) { + ::google::protobuf::internal::ReflectionOps::Merge(from, this); + } else { + MergeFrom(*source); + } +} + +void FileDescriptorSet::MergeFrom(const FileDescriptorSet& from) { + GOOGLE_CHECK_NE(&from, this); + file_.MergeFrom(from.file_); + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); +} + +void FileDescriptorSet::CopyFrom(const ::google::protobuf::Message& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +void FileDescriptorSet::CopyFrom(const FileDescriptorSet& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool FileDescriptorSet::IsInitialized() const { + + for (int i = 0; i < file_size(); i++) { + if (!this->file(i).IsInitialized()) return false; + } + return true; +} + +void FileDescriptorSet::Swap(FileDescriptorSet* other) { + if (other != this) { + file_.Swap(&other->file_); + std::swap(_has_bits_[0], other->_has_bits_[0]); + _unknown_fields_.Swap(&other->_unknown_fields_); + std::swap(_cached_size_, other->_cached_size_); + } +} + +::google::protobuf::Metadata FileDescriptorSet::GetMetadata() const { + protobuf_AssignDescriptorsOnce(); + ::google::protobuf::Metadata metadata; + metadata.descriptor = FileDescriptorSet_descriptor_; + metadata.reflection = FileDescriptorSet_reflection_; + return metadata; +} + + +// =================================================================== + +#ifndef _MSC_VER +const int FileDescriptorProto::kNameFieldNumber; +const int FileDescriptorProto::kPackageFieldNumber; +const int FileDescriptorProto::kDependencyFieldNumber; +const int FileDescriptorProto::kMessageTypeFieldNumber; +const int FileDescriptorProto::kEnumTypeFieldNumber; +const int FileDescriptorProto::kServiceFieldNumber; +const int FileDescriptorProto::kExtensionFieldNumber; +const int FileDescriptorProto::kOptionsFieldNumber; +const int FileDescriptorProto::kSourceCodeInfoFieldNumber; +#endif // !_MSC_VER + +FileDescriptorProto::FileDescriptorProto() + : ::google::protobuf::Message() { + SharedCtor(); +} + +void FileDescriptorProto::InitAsDefaultInstance() { + options_ = const_cast< ::google::protobuf::FileOptions*>(&::google::protobuf::FileOptions::default_instance()); + source_code_info_ = const_cast< ::google::protobuf::SourceCodeInfo*>(&::google::protobuf::SourceCodeInfo::default_instance()); +} + +FileDescriptorProto::FileDescriptorProto(const FileDescriptorProto& from) + : ::google::protobuf::Message() { + SharedCtor(); + MergeFrom(from); +} + +void FileDescriptorProto::SharedCtor() { + _cached_size_ = 0; + name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + package_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + options_ = NULL; + source_code_info_ = NULL; + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + +FileDescriptorProto::~FileDescriptorProto() { + SharedDtor(); +} + +void FileDescriptorProto::SharedDtor() { + if (name_ != &::google::protobuf::internal::kEmptyString) { + delete name_; + } + if (package_ != &::google::protobuf::internal::kEmptyString) { + delete package_; + } + if (this != default_instance_) { + delete options_; + delete source_code_info_; + } +} + +void FileDescriptorProto::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} +const ::google::protobuf::Descriptor* FileDescriptorProto::descriptor() { + protobuf_AssignDescriptorsOnce(); + return FileDescriptorProto_descriptor_; +} + +const FileDescriptorProto& FileDescriptorProto::default_instance() { + if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_; +} + +FileDescriptorProto* FileDescriptorProto::default_instance_ = NULL; + +FileDescriptorProto* FileDescriptorProto::New() const { + return new FileDescriptorProto; +} + +void FileDescriptorProto::Clear() { + if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + if (has_name()) { + if (name_ != &::google::protobuf::internal::kEmptyString) { + name_->clear(); + } + } + if (has_package()) { + if (package_ != &::google::protobuf::internal::kEmptyString) { + package_->clear(); + } + } + if (has_options()) { + if (options_ != NULL) options_->::google::protobuf::FileOptions::Clear(); + } + } + if (_has_bits_[8 / 32] & (0xffu << (8 % 32))) { + if (has_source_code_info()) { + if (source_code_info_ != NULL) source_code_info_->::google::protobuf::SourceCodeInfo::Clear(); + } + } + dependency_.Clear(); + message_type_.Clear(); + enum_type_.Clear(); + service_.Clear(); + extension_.Clear(); + ::memset(_has_bits_, 0, sizeof(_has_bits_)); + mutable_unknown_fields()->Clear(); +} + +bool FileDescriptorProto::MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input) { +#define DO_(EXPRESSION) if (!(EXPRESSION)) return false + ::google::protobuf::uint32 tag; + while ((tag = input->ReadTag()) != 0) { + switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { + // optional string name = 1; + case 1: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_name())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(18)) goto parse_package; + break; + } + + // optional string package = 2; + case 2: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_package: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_package())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->package().data(), this->package().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(26)) goto parse_dependency; + break; + } + + // repeated string dependency = 3; + case 3: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_dependency: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->add_dependency())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->dependency(0).data(), this->dependency(0).length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(26)) goto parse_dependency; + if (input->ExpectTag(34)) goto parse_message_type; + break; + } + + // repeated .google.protobuf.DescriptorProto message_type = 4; + case 4: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_message_type: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_message_type())); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(34)) goto parse_message_type; + if (input->ExpectTag(42)) goto parse_enum_type; + break; + } + + // repeated .google.protobuf.EnumDescriptorProto enum_type = 5; + case 5: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_enum_type: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_enum_type())); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(42)) goto parse_enum_type; + if (input->ExpectTag(50)) goto parse_service; + break; + } + + // repeated .google.protobuf.ServiceDescriptorProto service = 6; + case 6: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_service: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_service())); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(50)) goto parse_service; + if (input->ExpectTag(58)) goto parse_extension; + break; + } + + // repeated .google.protobuf.FieldDescriptorProto extension = 7; + case 7: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_extension: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_extension())); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(58)) goto parse_extension; + if (input->ExpectTag(66)) goto parse_options; + break; + } + + // optional .google.protobuf.FileOptions options = 8; + case 8: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_options: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, mutable_options())); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(74)) goto parse_source_code_info; + break; + } + + // optional .google.protobuf.SourceCodeInfo source_code_info = 9; + case 9: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_source_code_info: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, mutable_source_code_info())); + } else { + goto handle_uninterpreted; + } + if (input->ExpectAtEnd()) return true; + break; + } + + default: { + handle_uninterpreted: + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { + return true; + } + DO_(::google::protobuf::internal::WireFormat::SkipField( + input, tag, mutable_unknown_fields())); + break; + } + } + } + return true; +#undef DO_ +} + +void FileDescriptorProto::SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const { + // optional string name = 1; + if (has_name()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + ::google::protobuf::internal::WireFormatLite::WriteString( + 1, this->name(), output); + } + + // optional string package = 2; + if (has_package()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->package().data(), this->package().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + ::google::protobuf::internal::WireFormatLite::WriteString( + 2, this->package(), output); + } + + // repeated string dependency = 3; + for (int i = 0; i < this->dependency_size(); i++) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->dependency(i).data(), this->dependency(i).length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + ::google::protobuf::internal::WireFormatLite::WriteString( + 3, this->dependency(i), output); + } + + // repeated .google.protobuf.DescriptorProto message_type = 4; + for (int i = 0; i < this->message_type_size(); i++) { + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( + 4, this->message_type(i), output); + } + + // repeated .google.protobuf.EnumDescriptorProto enum_type = 5; + for (int i = 0; i < this->enum_type_size(); i++) { + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( + 5, this->enum_type(i), output); + } + + // repeated .google.protobuf.ServiceDescriptorProto service = 6; + for (int i = 0; i < this->service_size(); i++) { + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( + 6, this->service(i), output); + } + + // repeated .google.protobuf.FieldDescriptorProto extension = 7; + for (int i = 0; i < this->extension_size(); i++) { + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( + 7, this->extension(i), output); + } + + // optional .google.protobuf.FileOptions options = 8; + if (has_options()) { + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( + 8, this->options(), output); + } + + // optional .google.protobuf.SourceCodeInfo source_code_info = 9; + if (has_source_code_info()) { + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( + 9, this->source_code_info(), output); + } + + if (!unknown_fields().empty()) { + ::google::protobuf::internal::WireFormat::SerializeUnknownFields( + unknown_fields(), output); + } +} + +::google::protobuf::uint8* FileDescriptorProto::SerializeWithCachedSizesToArray( + ::google::protobuf::uint8* target) const { + // optional string name = 1; + if (has_name()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + target = + ::google::protobuf::internal::WireFormatLite::WriteStringToArray( + 1, this->name(), target); + } + + // optional string package = 2; + if (has_package()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->package().data(), this->package().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + target = + ::google::protobuf::internal::WireFormatLite::WriteStringToArray( + 2, this->package(), target); + } + + // repeated string dependency = 3; + for (int i = 0; i < this->dependency_size(); i++) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->dependency(i).data(), this->dependency(i).length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + target = ::google::protobuf::internal::WireFormatLite:: + WriteStringToArray(3, this->dependency(i), target); + } + + // repeated .google.protobuf.DescriptorProto message_type = 4; + for (int i = 0; i < this->message_type_size(); i++) { + target = ::google::protobuf::internal::WireFormatLite:: + WriteMessageNoVirtualToArray( + 4, this->message_type(i), target); + } + + // repeated .google.protobuf.EnumDescriptorProto enum_type = 5; + for (int i = 0; i < this->enum_type_size(); i++) { + target = ::google::protobuf::internal::WireFormatLite:: + WriteMessageNoVirtualToArray( + 5, this->enum_type(i), target); + } + + // repeated .google.protobuf.ServiceDescriptorProto service = 6; + for (int i = 0; i < this->service_size(); i++) { + target = ::google::protobuf::internal::WireFormatLite:: + WriteMessageNoVirtualToArray( + 6, this->service(i), target); + } + + // repeated .google.protobuf.FieldDescriptorProto extension = 7; + for (int i = 0; i < this->extension_size(); i++) { + target = ::google::protobuf::internal::WireFormatLite:: + WriteMessageNoVirtualToArray( + 7, this->extension(i), target); + } + + // optional .google.protobuf.FileOptions options = 8; + if (has_options()) { + target = ::google::protobuf::internal::WireFormatLite:: + WriteMessageNoVirtualToArray( + 8, this->options(), target); + } + + // optional .google.protobuf.SourceCodeInfo source_code_info = 9; + if (has_source_code_info()) { + target = ::google::protobuf::internal::WireFormatLite:: + WriteMessageNoVirtualToArray( + 9, this->source_code_info(), target); + } + + if (!unknown_fields().empty()) { + target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( + unknown_fields(), target); + } + return target; +} + +int FileDescriptorProto::ByteSize() const { + int total_size = 0; + + if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + // optional string name = 1; + if (has_name()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::StringSize( + this->name()); + } + + // optional string package = 2; + if (has_package()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::StringSize( + this->package()); + } + + // optional .google.protobuf.FileOptions options = 8; + if (has_options()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( + this->options()); + } + + } + if (_has_bits_[8 / 32] & (0xffu << (8 % 32))) { + // optional .google.protobuf.SourceCodeInfo source_code_info = 9; + if (has_source_code_info()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( + this->source_code_info()); + } + + } + // repeated string dependency = 3; + total_size += 1 * this->dependency_size(); + for (int i = 0; i < this->dependency_size(); i++) { + total_size += ::google::protobuf::internal::WireFormatLite::StringSize( + this->dependency(i)); + } + + // repeated .google.protobuf.DescriptorProto message_type = 4; + total_size += 1 * this->message_type_size(); + for (int i = 0; i < this->message_type_size(); i++) { + total_size += + ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( + this->message_type(i)); + } + + // repeated .google.protobuf.EnumDescriptorProto enum_type = 5; + total_size += 1 * this->enum_type_size(); + for (int i = 0; i < this->enum_type_size(); i++) { + total_size += + ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( + this->enum_type(i)); + } + + // repeated .google.protobuf.ServiceDescriptorProto service = 6; + total_size += 1 * this->service_size(); + for (int i = 0; i < this->service_size(); i++) { + total_size += + ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( + this->service(i)); + } + + // repeated .google.protobuf.FieldDescriptorProto extension = 7; + total_size += 1 * this->extension_size(); + for (int i = 0; i < this->extension_size(); i++) { + total_size += + ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( + this->extension(i)); + } + + if (!unknown_fields().empty()) { + total_size += + ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( + unknown_fields()); + } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); + return total_size; +} + +void FileDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) { + GOOGLE_CHECK_NE(&from, this); + const FileDescriptorProto* source = + ::google::protobuf::internal::dynamic_cast_if_available( + &from); + if (source == NULL) { + ::google::protobuf::internal::ReflectionOps::Merge(from, this); + } else { + MergeFrom(*source); + } +} + +void FileDescriptorProto::MergeFrom(const FileDescriptorProto& from) { + GOOGLE_CHECK_NE(&from, this); + dependency_.MergeFrom(from.dependency_); + message_type_.MergeFrom(from.message_type_); + enum_type_.MergeFrom(from.enum_type_); + service_.MergeFrom(from.service_); + extension_.MergeFrom(from.extension_); + if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { + if (from.has_name()) { + set_name(from.name()); + } + if (from.has_package()) { + set_package(from.package()); + } + if (from.has_options()) { + mutable_options()->::google::protobuf::FileOptions::MergeFrom(from.options()); + } + } + if (from._has_bits_[8 / 32] & (0xffu << (8 % 32))) { + if (from.has_source_code_info()) { + mutable_source_code_info()->::google::protobuf::SourceCodeInfo::MergeFrom(from.source_code_info()); + } + } + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); +} + +void FileDescriptorProto::CopyFrom(const ::google::protobuf::Message& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +void FileDescriptorProto::CopyFrom(const FileDescriptorProto& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool FileDescriptorProto::IsInitialized() const { + + for (int i = 0; i < message_type_size(); i++) { + if (!this->message_type(i).IsInitialized()) return false; + } + for (int i = 0; i < enum_type_size(); i++) { + if (!this->enum_type(i).IsInitialized()) return false; + } + for (int i = 0; i < service_size(); i++) { + if (!this->service(i).IsInitialized()) return false; + } + for (int i = 0; i < extension_size(); i++) { + if (!this->extension(i).IsInitialized()) return false; + } + if (has_options()) { + if (!this->options().IsInitialized()) return false; + } + return true; +} + +void FileDescriptorProto::Swap(FileDescriptorProto* other) { + if (other != this) { + std::swap(name_, other->name_); + std::swap(package_, other->package_); + dependency_.Swap(&other->dependency_); + message_type_.Swap(&other->message_type_); + enum_type_.Swap(&other->enum_type_); + service_.Swap(&other->service_); + extension_.Swap(&other->extension_); + std::swap(options_, other->options_); + std::swap(source_code_info_, other->source_code_info_); + std::swap(_has_bits_[0], other->_has_bits_[0]); + _unknown_fields_.Swap(&other->_unknown_fields_); + std::swap(_cached_size_, other->_cached_size_); + } +} + +::google::protobuf::Metadata FileDescriptorProto::GetMetadata() const { + protobuf_AssignDescriptorsOnce(); + ::google::protobuf::Metadata metadata; + metadata.descriptor = FileDescriptorProto_descriptor_; + metadata.reflection = FileDescriptorProto_reflection_; + return metadata; +} + + +// =================================================================== + +#ifndef _MSC_VER +const int DescriptorProto_ExtensionRange::kStartFieldNumber; +const int DescriptorProto_ExtensionRange::kEndFieldNumber; +#endif // !_MSC_VER + +DescriptorProto_ExtensionRange::DescriptorProto_ExtensionRange() + : ::google::protobuf::Message() { + SharedCtor(); +} + +void DescriptorProto_ExtensionRange::InitAsDefaultInstance() { +} + +DescriptorProto_ExtensionRange::DescriptorProto_ExtensionRange(const DescriptorProto_ExtensionRange& from) + : ::google::protobuf::Message() { + SharedCtor(); + MergeFrom(from); +} + +void DescriptorProto_ExtensionRange::SharedCtor() { + _cached_size_ = 0; + start_ = 0; + end_ = 0; + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + +DescriptorProto_ExtensionRange::~DescriptorProto_ExtensionRange() { + SharedDtor(); +} + +void DescriptorProto_ExtensionRange::SharedDtor() { + if (this != default_instance_) { + } +} + +void DescriptorProto_ExtensionRange::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} +const ::google::protobuf::Descriptor* DescriptorProto_ExtensionRange::descriptor() { + protobuf_AssignDescriptorsOnce(); + return DescriptorProto_ExtensionRange_descriptor_; +} + +const DescriptorProto_ExtensionRange& DescriptorProto_ExtensionRange::default_instance() { + if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_; +} + +DescriptorProto_ExtensionRange* DescriptorProto_ExtensionRange::default_instance_ = NULL; + +DescriptorProto_ExtensionRange* DescriptorProto_ExtensionRange::New() const { + return new DescriptorProto_ExtensionRange; +} + +void DescriptorProto_ExtensionRange::Clear() { + if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + start_ = 0; + end_ = 0; + } + ::memset(_has_bits_, 0, sizeof(_has_bits_)); + mutable_unknown_fields()->Clear(); +} + +bool DescriptorProto_ExtensionRange::MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input) { +#define DO_(EXPRESSION) if (!(EXPRESSION)) return false + ::google::protobuf::uint32 tag; + while ((tag = input->ReadTag()) != 0) { + switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { + // optional int32 start = 1; + case 1: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( + input, &start_))); + set_has_start(); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(16)) goto parse_end; + break; + } + + // optional int32 end = 2; + case 2: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_end: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( + input, &end_))); + set_has_end(); + } else { + goto handle_uninterpreted; + } + if (input->ExpectAtEnd()) return true; + break; + } + + default: { + handle_uninterpreted: + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { + return true; + } + DO_(::google::protobuf::internal::WireFormat::SkipField( + input, tag, mutable_unknown_fields())); + break; + } + } + } + return true; +#undef DO_ +} + +void DescriptorProto_ExtensionRange::SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const { + // optional int32 start = 1; + if (has_start()) { + ::google::protobuf::internal::WireFormatLite::WriteInt32(1, this->start(), output); + } + + // optional int32 end = 2; + if (has_end()) { + ::google::protobuf::internal::WireFormatLite::WriteInt32(2, this->end(), output); + } + + if (!unknown_fields().empty()) { + ::google::protobuf::internal::WireFormat::SerializeUnknownFields( + unknown_fields(), output); + } +} + +::google::protobuf::uint8* DescriptorProto_ExtensionRange::SerializeWithCachedSizesToArray( + ::google::protobuf::uint8* target) const { + // optional int32 start = 1; + if (has_start()) { + target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(1, this->start(), target); + } + + // optional int32 end = 2; + if (has_end()) { + target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(2, this->end(), target); + } + + if (!unknown_fields().empty()) { + target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( + unknown_fields(), target); + } + return target; +} + +int DescriptorProto_ExtensionRange::ByteSize() const { + int total_size = 0; + + if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + // optional int32 start = 1; + if (has_start()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::Int32Size( + this->start()); + } + + // optional int32 end = 2; + if (has_end()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::Int32Size( + this->end()); + } + + } + if (!unknown_fields().empty()) { + total_size += + ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( + unknown_fields()); + } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); + return total_size; +} + +void DescriptorProto_ExtensionRange::MergeFrom(const ::google::protobuf::Message& from) { + GOOGLE_CHECK_NE(&from, this); + const DescriptorProto_ExtensionRange* source = + ::google::protobuf::internal::dynamic_cast_if_available( + &from); + if (source == NULL) { + ::google::protobuf::internal::ReflectionOps::Merge(from, this); + } else { + MergeFrom(*source); + } +} + +void DescriptorProto_ExtensionRange::MergeFrom(const DescriptorProto_ExtensionRange& from) { + GOOGLE_CHECK_NE(&from, this); + if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { + if (from.has_start()) { + set_start(from.start()); + } + if (from.has_end()) { + set_end(from.end()); + } + } + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); +} + +void DescriptorProto_ExtensionRange::CopyFrom(const ::google::protobuf::Message& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +void DescriptorProto_ExtensionRange::CopyFrom(const DescriptorProto_ExtensionRange& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool DescriptorProto_ExtensionRange::IsInitialized() const { + + return true; +} + +void DescriptorProto_ExtensionRange::Swap(DescriptorProto_ExtensionRange* other) { + if (other != this) { + std::swap(start_, other->start_); + std::swap(end_, other->end_); + std::swap(_has_bits_[0], other->_has_bits_[0]); + _unknown_fields_.Swap(&other->_unknown_fields_); + std::swap(_cached_size_, other->_cached_size_); + } +} + +::google::protobuf::Metadata DescriptorProto_ExtensionRange::GetMetadata() const { + protobuf_AssignDescriptorsOnce(); + ::google::protobuf::Metadata metadata; + metadata.descriptor = DescriptorProto_ExtensionRange_descriptor_; + metadata.reflection = DescriptorProto_ExtensionRange_reflection_; + return metadata; +} + + +// ------------------------------------------------------------------- + +#ifndef _MSC_VER +const int DescriptorProto::kNameFieldNumber; +const int DescriptorProto::kFieldFieldNumber; +const int DescriptorProto::kExtensionFieldNumber; +const int DescriptorProto::kNestedTypeFieldNumber; +const int DescriptorProto::kEnumTypeFieldNumber; +const int DescriptorProto::kExtensionRangeFieldNumber; +const int DescriptorProto::kOptionsFieldNumber; +#endif // !_MSC_VER + +DescriptorProto::DescriptorProto() + : ::google::protobuf::Message() { + SharedCtor(); +} + +void DescriptorProto::InitAsDefaultInstance() { + options_ = const_cast< ::google::protobuf::MessageOptions*>(&::google::protobuf::MessageOptions::default_instance()); +} + +DescriptorProto::DescriptorProto(const DescriptorProto& from) + : ::google::protobuf::Message() { + SharedCtor(); + MergeFrom(from); +} + +void DescriptorProto::SharedCtor() { + _cached_size_ = 0; + name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + options_ = NULL; + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + +DescriptorProto::~DescriptorProto() { + SharedDtor(); +} + +void DescriptorProto::SharedDtor() { + if (name_ != &::google::protobuf::internal::kEmptyString) { + delete name_; + } + if (this != default_instance_) { + delete options_; + } +} + +void DescriptorProto::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} +const ::google::protobuf::Descriptor* DescriptorProto::descriptor() { + protobuf_AssignDescriptorsOnce(); + return DescriptorProto_descriptor_; +} + +const DescriptorProto& DescriptorProto::default_instance() { + if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_; +} + +DescriptorProto* DescriptorProto::default_instance_ = NULL; + +DescriptorProto* DescriptorProto::New() const { + return new DescriptorProto; +} + +void DescriptorProto::Clear() { + if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + if (has_name()) { + if (name_ != &::google::protobuf::internal::kEmptyString) { + name_->clear(); + } + } + if (has_options()) { + if (options_ != NULL) options_->::google::protobuf::MessageOptions::Clear(); + } + } + field_.Clear(); + extension_.Clear(); + nested_type_.Clear(); + enum_type_.Clear(); + extension_range_.Clear(); + ::memset(_has_bits_, 0, sizeof(_has_bits_)); + mutable_unknown_fields()->Clear(); +} + +bool DescriptorProto::MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input) { +#define DO_(EXPRESSION) if (!(EXPRESSION)) return false + ::google::protobuf::uint32 tag; + while ((tag = input->ReadTag()) != 0) { + switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { + // optional string name = 1; + case 1: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_name())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(18)) goto parse_field; + break; + } + + // repeated .google.protobuf.FieldDescriptorProto field = 2; + case 2: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_field: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_field())); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(18)) goto parse_field; + if (input->ExpectTag(26)) goto parse_nested_type; + break; + } + + // repeated .google.protobuf.DescriptorProto nested_type = 3; + case 3: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_nested_type: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_nested_type())); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(26)) goto parse_nested_type; + if (input->ExpectTag(34)) goto parse_enum_type; + break; + } + + // repeated .google.protobuf.EnumDescriptorProto enum_type = 4; + case 4: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_enum_type: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_enum_type())); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(34)) goto parse_enum_type; + if (input->ExpectTag(42)) goto parse_extension_range; + break; + } + + // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5; + case 5: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_extension_range: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_extension_range())); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(42)) goto parse_extension_range; + if (input->ExpectTag(50)) goto parse_extension; + break; + } + + // repeated .google.protobuf.FieldDescriptorProto extension = 6; + case 6: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_extension: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_extension())); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(50)) goto parse_extension; + if (input->ExpectTag(58)) goto parse_options; + break; + } + + // optional .google.protobuf.MessageOptions options = 7; + case 7: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_options: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, mutable_options())); + } else { + goto handle_uninterpreted; + } + if (input->ExpectAtEnd()) return true; + break; + } + + default: { + handle_uninterpreted: + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { + return true; + } + DO_(::google::protobuf::internal::WireFormat::SkipField( + input, tag, mutable_unknown_fields())); + break; + } + } + } + return true; +#undef DO_ +} + +void DescriptorProto::SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const { + // optional string name = 1; + if (has_name()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + ::google::protobuf::internal::WireFormatLite::WriteString( + 1, this->name(), output); + } + + // repeated .google.protobuf.FieldDescriptorProto field = 2; + for (int i = 0; i < this->field_size(); i++) { + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( + 2, this->field(i), output); + } + + // repeated .google.protobuf.DescriptorProto nested_type = 3; + for (int i = 0; i < this->nested_type_size(); i++) { + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( + 3, this->nested_type(i), output); + } + + // repeated .google.protobuf.EnumDescriptorProto enum_type = 4; + for (int i = 0; i < this->enum_type_size(); i++) { + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( + 4, this->enum_type(i), output); + } + + // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5; + for (int i = 0; i < this->extension_range_size(); i++) { + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( + 5, this->extension_range(i), output); + } + + // repeated .google.protobuf.FieldDescriptorProto extension = 6; + for (int i = 0; i < this->extension_size(); i++) { + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( + 6, this->extension(i), output); + } + + // optional .google.protobuf.MessageOptions options = 7; + if (has_options()) { + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( + 7, this->options(), output); + } + + if (!unknown_fields().empty()) { + ::google::protobuf::internal::WireFormat::SerializeUnknownFields( + unknown_fields(), output); + } +} + +::google::protobuf::uint8* DescriptorProto::SerializeWithCachedSizesToArray( + ::google::protobuf::uint8* target) const { + // optional string name = 1; + if (has_name()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + target = + ::google::protobuf::internal::WireFormatLite::WriteStringToArray( + 1, this->name(), target); + } + + // repeated .google.protobuf.FieldDescriptorProto field = 2; + for (int i = 0; i < this->field_size(); i++) { + target = ::google::protobuf::internal::WireFormatLite:: + WriteMessageNoVirtualToArray( + 2, this->field(i), target); + } + + // repeated .google.protobuf.DescriptorProto nested_type = 3; + for (int i = 0; i < this->nested_type_size(); i++) { + target = ::google::protobuf::internal::WireFormatLite:: + WriteMessageNoVirtualToArray( + 3, this->nested_type(i), target); + } + + // repeated .google.protobuf.EnumDescriptorProto enum_type = 4; + for (int i = 0; i < this->enum_type_size(); i++) { + target = ::google::protobuf::internal::WireFormatLite:: + WriteMessageNoVirtualToArray( + 4, this->enum_type(i), target); + } + + // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5; + for (int i = 0; i < this->extension_range_size(); i++) { + target = ::google::protobuf::internal::WireFormatLite:: + WriteMessageNoVirtualToArray( + 5, this->extension_range(i), target); + } + + // repeated .google.protobuf.FieldDescriptorProto extension = 6; + for (int i = 0; i < this->extension_size(); i++) { + target = ::google::protobuf::internal::WireFormatLite:: + WriteMessageNoVirtualToArray( + 6, this->extension(i), target); + } + + // optional .google.protobuf.MessageOptions options = 7; + if (has_options()) { + target = ::google::protobuf::internal::WireFormatLite:: + WriteMessageNoVirtualToArray( + 7, this->options(), target); + } + + if (!unknown_fields().empty()) { + target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( + unknown_fields(), target); + } + return target; +} + +int DescriptorProto::ByteSize() const { + int total_size = 0; + + if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + // optional string name = 1; + if (has_name()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::StringSize( + this->name()); + } + + // optional .google.protobuf.MessageOptions options = 7; + if (has_options()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( + this->options()); + } + + } + // repeated .google.protobuf.FieldDescriptorProto field = 2; + total_size += 1 * this->field_size(); + for (int i = 0; i < this->field_size(); i++) { + total_size += + ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( + this->field(i)); + } + + // repeated .google.protobuf.FieldDescriptorProto extension = 6; + total_size += 1 * this->extension_size(); + for (int i = 0; i < this->extension_size(); i++) { + total_size += + ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( + this->extension(i)); + } + + // repeated .google.protobuf.DescriptorProto nested_type = 3; + total_size += 1 * this->nested_type_size(); + for (int i = 0; i < this->nested_type_size(); i++) { + total_size += + ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( + this->nested_type(i)); + } + + // repeated .google.protobuf.EnumDescriptorProto enum_type = 4; + total_size += 1 * this->enum_type_size(); + for (int i = 0; i < this->enum_type_size(); i++) { + total_size += + ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( + this->enum_type(i)); + } + + // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5; + total_size += 1 * this->extension_range_size(); + for (int i = 0; i < this->extension_range_size(); i++) { + total_size += + ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( + this->extension_range(i)); + } + + if (!unknown_fields().empty()) { + total_size += + ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( + unknown_fields()); + } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); + return total_size; +} + +void DescriptorProto::MergeFrom(const ::google::protobuf::Message& from) { + GOOGLE_CHECK_NE(&from, this); + const DescriptorProto* source = + ::google::protobuf::internal::dynamic_cast_if_available( + &from); + if (source == NULL) { + ::google::protobuf::internal::ReflectionOps::Merge(from, this); + } else { + MergeFrom(*source); + } +} + +void DescriptorProto::MergeFrom(const DescriptorProto& from) { + GOOGLE_CHECK_NE(&from, this); + field_.MergeFrom(from.field_); + extension_.MergeFrom(from.extension_); + nested_type_.MergeFrom(from.nested_type_); + enum_type_.MergeFrom(from.enum_type_); + extension_range_.MergeFrom(from.extension_range_); + if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { + if (from.has_name()) { + set_name(from.name()); + } + if (from.has_options()) { + mutable_options()->::google::protobuf::MessageOptions::MergeFrom(from.options()); + } + } + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); +} + +void DescriptorProto::CopyFrom(const ::google::protobuf::Message& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +void DescriptorProto::CopyFrom(const DescriptorProto& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool DescriptorProto::IsInitialized() const { + + for (int i = 0; i < field_size(); i++) { + if (!this->field(i).IsInitialized()) return false; + } + for (int i = 0; i < extension_size(); i++) { + if (!this->extension(i).IsInitialized()) return false; + } + for (int i = 0; i < nested_type_size(); i++) { + if (!this->nested_type(i).IsInitialized()) return false; + } + for (int i = 0; i < enum_type_size(); i++) { + if (!this->enum_type(i).IsInitialized()) return false; + } + if (has_options()) { + if (!this->options().IsInitialized()) return false; + } + return true; +} + +void DescriptorProto::Swap(DescriptorProto* other) { + if (other != this) { + std::swap(name_, other->name_); + field_.Swap(&other->field_); + extension_.Swap(&other->extension_); + nested_type_.Swap(&other->nested_type_); + enum_type_.Swap(&other->enum_type_); + extension_range_.Swap(&other->extension_range_); + std::swap(options_, other->options_); + std::swap(_has_bits_[0], other->_has_bits_[0]); + _unknown_fields_.Swap(&other->_unknown_fields_); + std::swap(_cached_size_, other->_cached_size_); + } +} + +::google::protobuf::Metadata DescriptorProto::GetMetadata() const { + protobuf_AssignDescriptorsOnce(); + ::google::protobuf::Metadata metadata; + metadata.descriptor = DescriptorProto_descriptor_; + metadata.reflection = DescriptorProto_reflection_; + return metadata; +} + + +// =================================================================== + +const ::google::protobuf::EnumDescriptor* FieldDescriptorProto_Type_descriptor() { + protobuf_AssignDescriptorsOnce(); + return FieldDescriptorProto_Type_descriptor_; +} +bool FieldDescriptorProto_Type_IsValid(int value) { + switch(value) { + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + case 16: + case 17: + case 18: + return true; + default: + return false; + } +} + +#ifndef _MSC_VER +const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_DOUBLE; +const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_FLOAT; +const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_INT64; +const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_UINT64; +const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_INT32; +const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_FIXED64; +const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_FIXED32; +const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_BOOL; +const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_STRING; +const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_GROUP; +const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_MESSAGE; +const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_BYTES; +const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_UINT32; +const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_ENUM; +const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_SFIXED32; +const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_SFIXED64; +const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_SINT32; +const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_SINT64; +const FieldDescriptorProto_Type FieldDescriptorProto::Type_MIN; +const FieldDescriptorProto_Type FieldDescriptorProto::Type_MAX; +const int FieldDescriptorProto::Type_ARRAYSIZE; +#endif // _MSC_VER +const ::google::protobuf::EnumDescriptor* FieldDescriptorProto_Label_descriptor() { + protobuf_AssignDescriptorsOnce(); + return FieldDescriptorProto_Label_descriptor_; +} +bool FieldDescriptorProto_Label_IsValid(int value) { + switch(value) { + case 1: + case 2: + case 3: + return true; + default: + return false; + } +} + +#ifndef _MSC_VER +const FieldDescriptorProto_Label FieldDescriptorProto::LABEL_OPTIONAL; +const FieldDescriptorProto_Label FieldDescriptorProto::LABEL_REQUIRED; +const FieldDescriptorProto_Label FieldDescriptorProto::LABEL_REPEATED; +const FieldDescriptorProto_Label FieldDescriptorProto::Label_MIN; +const FieldDescriptorProto_Label FieldDescriptorProto::Label_MAX; +const int FieldDescriptorProto::Label_ARRAYSIZE; +#endif // _MSC_VER +#ifndef _MSC_VER +const int FieldDescriptorProto::kNameFieldNumber; +const int FieldDescriptorProto::kNumberFieldNumber; +const int FieldDescriptorProto::kLabelFieldNumber; +const int FieldDescriptorProto::kTypeFieldNumber; +const int FieldDescriptorProto::kTypeNameFieldNumber; +const int FieldDescriptorProto::kExtendeeFieldNumber; +const int FieldDescriptorProto::kDefaultValueFieldNumber; +const int FieldDescriptorProto::kOptionsFieldNumber; +#endif // !_MSC_VER + +FieldDescriptorProto::FieldDescriptorProto() + : ::google::protobuf::Message() { + SharedCtor(); +} + +void FieldDescriptorProto::InitAsDefaultInstance() { + options_ = const_cast< ::google::protobuf::FieldOptions*>(&::google::protobuf::FieldOptions::default_instance()); +} + +FieldDescriptorProto::FieldDescriptorProto(const FieldDescriptorProto& from) + : ::google::protobuf::Message() { + SharedCtor(); + MergeFrom(from); +} + +void FieldDescriptorProto::SharedCtor() { + _cached_size_ = 0; + name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + number_ = 0; + label_ = 1; + type_ = 1; + type_name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + extendee_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + default_value_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + options_ = NULL; + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + +FieldDescriptorProto::~FieldDescriptorProto() { + SharedDtor(); +} + +void FieldDescriptorProto::SharedDtor() { + if (name_ != &::google::protobuf::internal::kEmptyString) { + delete name_; + } + if (type_name_ != &::google::protobuf::internal::kEmptyString) { + delete type_name_; + } + if (extendee_ != &::google::protobuf::internal::kEmptyString) { + delete extendee_; + } + if (default_value_ != &::google::protobuf::internal::kEmptyString) { + delete default_value_; + } + if (this != default_instance_) { + delete options_; + } +} + +void FieldDescriptorProto::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} +const ::google::protobuf::Descriptor* FieldDescriptorProto::descriptor() { + protobuf_AssignDescriptorsOnce(); + return FieldDescriptorProto_descriptor_; +} + +const FieldDescriptorProto& FieldDescriptorProto::default_instance() { + if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_; +} + +FieldDescriptorProto* FieldDescriptorProto::default_instance_ = NULL; + +FieldDescriptorProto* FieldDescriptorProto::New() const { + return new FieldDescriptorProto; +} + +void FieldDescriptorProto::Clear() { + if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + if (has_name()) { + if (name_ != &::google::protobuf::internal::kEmptyString) { + name_->clear(); + } + } + number_ = 0; + label_ = 1; + type_ = 1; + if (has_type_name()) { + if (type_name_ != &::google::protobuf::internal::kEmptyString) { + type_name_->clear(); + } + } + if (has_extendee()) { + if (extendee_ != &::google::protobuf::internal::kEmptyString) { + extendee_->clear(); + } + } + if (has_default_value()) { + if (default_value_ != &::google::protobuf::internal::kEmptyString) { + default_value_->clear(); + } + } + if (has_options()) { + if (options_ != NULL) options_->::google::protobuf::FieldOptions::Clear(); + } + } + ::memset(_has_bits_, 0, sizeof(_has_bits_)); + mutable_unknown_fields()->Clear(); +} + +bool FieldDescriptorProto::MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input) { +#define DO_(EXPRESSION) if (!(EXPRESSION)) return false + ::google::protobuf::uint32 tag; + while ((tag = input->ReadTag()) != 0) { + switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { + // optional string name = 1; + case 1: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_name())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(18)) goto parse_extendee; + break; + } + + // optional string extendee = 2; + case 2: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_extendee: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_extendee())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->extendee().data(), this->extendee().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(24)) goto parse_number; + break; + } + + // optional int32 number = 3; + case 3: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_number: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( + input, &number_))); + set_has_number(); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(32)) goto parse_label; + break; + } + + // optional .google.protobuf.FieldDescriptorProto.Label label = 4; + case 4: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_label: + int value; + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>( + input, &value))); + if (::google::protobuf::FieldDescriptorProto_Label_IsValid(value)) { + set_label(static_cast< ::google::protobuf::FieldDescriptorProto_Label >(value)); + } else { + mutable_unknown_fields()->AddVarint(4, value); + } + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(40)) goto parse_type; + break; + } + + // optional .google.protobuf.FieldDescriptorProto.Type type = 5; + case 5: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_type: + int value; + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>( + input, &value))); + if (::google::protobuf::FieldDescriptorProto_Type_IsValid(value)) { + set_type(static_cast< ::google::protobuf::FieldDescriptorProto_Type >(value)); + } else { + mutable_unknown_fields()->AddVarint(5, value); + } + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(50)) goto parse_type_name; + break; + } + + // optional string type_name = 6; + case 6: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_type_name: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_type_name())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->type_name().data(), this->type_name().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(58)) goto parse_default_value; + break; + } + + // optional string default_value = 7; + case 7: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_default_value: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_default_value())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->default_value().data(), this->default_value().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(66)) goto parse_options; + break; + } + + // optional .google.protobuf.FieldOptions options = 8; + case 8: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_options: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, mutable_options())); + } else { + goto handle_uninterpreted; + } + if (input->ExpectAtEnd()) return true; + break; + } + + default: { + handle_uninterpreted: + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { + return true; + } + DO_(::google::protobuf::internal::WireFormat::SkipField( + input, tag, mutable_unknown_fields())); + break; + } + } + } + return true; +#undef DO_ +} + +void FieldDescriptorProto::SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const { + // optional string name = 1; + if (has_name()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + ::google::protobuf::internal::WireFormatLite::WriteString( + 1, this->name(), output); + } + + // optional string extendee = 2; + if (has_extendee()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->extendee().data(), this->extendee().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + ::google::protobuf::internal::WireFormatLite::WriteString( + 2, this->extendee(), output); + } + + // optional int32 number = 3; + if (has_number()) { + ::google::protobuf::internal::WireFormatLite::WriteInt32(3, this->number(), output); + } + + // optional .google.protobuf.FieldDescriptorProto.Label label = 4; + if (has_label()) { + ::google::protobuf::internal::WireFormatLite::WriteEnum( + 4, this->label(), output); + } + + // optional .google.protobuf.FieldDescriptorProto.Type type = 5; + if (has_type()) { + ::google::protobuf::internal::WireFormatLite::WriteEnum( + 5, this->type(), output); + } + + // optional string type_name = 6; + if (has_type_name()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->type_name().data(), this->type_name().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + ::google::protobuf::internal::WireFormatLite::WriteString( + 6, this->type_name(), output); + } + + // optional string default_value = 7; + if (has_default_value()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->default_value().data(), this->default_value().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + ::google::protobuf::internal::WireFormatLite::WriteString( + 7, this->default_value(), output); + } + + // optional .google.protobuf.FieldOptions options = 8; + if (has_options()) { + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( + 8, this->options(), output); + } + + if (!unknown_fields().empty()) { + ::google::protobuf::internal::WireFormat::SerializeUnknownFields( + unknown_fields(), output); + } +} + +::google::protobuf::uint8* FieldDescriptorProto::SerializeWithCachedSizesToArray( + ::google::protobuf::uint8* target) const { + // optional string name = 1; + if (has_name()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + target = + ::google::protobuf::internal::WireFormatLite::WriteStringToArray( + 1, this->name(), target); + } + + // optional string extendee = 2; + if (has_extendee()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->extendee().data(), this->extendee().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + target = + ::google::protobuf::internal::WireFormatLite::WriteStringToArray( + 2, this->extendee(), target); + } + + // optional int32 number = 3; + if (has_number()) { + target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(3, this->number(), target); + } + + // optional .google.protobuf.FieldDescriptorProto.Label label = 4; + if (has_label()) { + target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray( + 4, this->label(), target); + } + + // optional .google.protobuf.FieldDescriptorProto.Type type = 5; + if (has_type()) { + target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray( + 5, this->type(), target); + } + + // optional string type_name = 6; + if (has_type_name()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->type_name().data(), this->type_name().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + target = + ::google::protobuf::internal::WireFormatLite::WriteStringToArray( + 6, this->type_name(), target); + } + + // optional string default_value = 7; + if (has_default_value()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->default_value().data(), this->default_value().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + target = + ::google::protobuf::internal::WireFormatLite::WriteStringToArray( + 7, this->default_value(), target); + } + + // optional .google.protobuf.FieldOptions options = 8; + if (has_options()) { + target = ::google::protobuf::internal::WireFormatLite:: + WriteMessageNoVirtualToArray( + 8, this->options(), target); + } + + if (!unknown_fields().empty()) { + target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( + unknown_fields(), target); + } + return target; +} + +int FieldDescriptorProto::ByteSize() const { + int total_size = 0; + + if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + // optional string name = 1; + if (has_name()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::StringSize( + this->name()); + } + + // optional int32 number = 3; + if (has_number()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::Int32Size( + this->number()); + } + + // optional .google.protobuf.FieldDescriptorProto.Label label = 4; + if (has_label()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::EnumSize(this->label()); + } + + // optional .google.protobuf.FieldDescriptorProto.Type type = 5; + if (has_type()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::EnumSize(this->type()); + } + + // optional string type_name = 6; + if (has_type_name()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::StringSize( + this->type_name()); + } + + // optional string extendee = 2; + if (has_extendee()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::StringSize( + this->extendee()); + } + + // optional string default_value = 7; + if (has_default_value()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::StringSize( + this->default_value()); + } + + // optional .google.protobuf.FieldOptions options = 8; + if (has_options()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( + this->options()); + } + + } + if (!unknown_fields().empty()) { + total_size += + ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( + unknown_fields()); + } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); + return total_size; +} + +void FieldDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) { + GOOGLE_CHECK_NE(&from, this); + const FieldDescriptorProto* source = + ::google::protobuf::internal::dynamic_cast_if_available( + &from); + if (source == NULL) { + ::google::protobuf::internal::ReflectionOps::Merge(from, this); + } else { + MergeFrom(*source); + } +} + +void FieldDescriptorProto::MergeFrom(const FieldDescriptorProto& from) { + GOOGLE_CHECK_NE(&from, this); + if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { + if (from.has_name()) { + set_name(from.name()); + } + if (from.has_number()) { + set_number(from.number()); + } + if (from.has_label()) { + set_label(from.label()); + } + if (from.has_type()) { + set_type(from.type()); + } + if (from.has_type_name()) { + set_type_name(from.type_name()); + } + if (from.has_extendee()) { + set_extendee(from.extendee()); + } + if (from.has_default_value()) { + set_default_value(from.default_value()); + } + if (from.has_options()) { + mutable_options()->::google::protobuf::FieldOptions::MergeFrom(from.options()); + } + } + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); +} + +void FieldDescriptorProto::CopyFrom(const ::google::protobuf::Message& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +void FieldDescriptorProto::CopyFrom(const FieldDescriptorProto& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool FieldDescriptorProto::IsInitialized() const { + + if (has_options()) { + if (!this->options().IsInitialized()) return false; + } + return true; +} + +void FieldDescriptorProto::Swap(FieldDescriptorProto* other) { + if (other != this) { + std::swap(name_, other->name_); + std::swap(number_, other->number_); + std::swap(label_, other->label_); + std::swap(type_, other->type_); + std::swap(type_name_, other->type_name_); + std::swap(extendee_, other->extendee_); + std::swap(default_value_, other->default_value_); + std::swap(options_, other->options_); + std::swap(_has_bits_[0], other->_has_bits_[0]); + _unknown_fields_.Swap(&other->_unknown_fields_); + std::swap(_cached_size_, other->_cached_size_); + } +} + +::google::protobuf::Metadata FieldDescriptorProto::GetMetadata() const { + protobuf_AssignDescriptorsOnce(); + ::google::protobuf::Metadata metadata; + metadata.descriptor = FieldDescriptorProto_descriptor_; + metadata.reflection = FieldDescriptorProto_reflection_; + return metadata; +} + + +// =================================================================== + +#ifndef _MSC_VER +const int EnumDescriptorProto::kNameFieldNumber; +const int EnumDescriptorProto::kValueFieldNumber; +const int EnumDescriptorProto::kOptionsFieldNumber; +#endif // !_MSC_VER + +EnumDescriptorProto::EnumDescriptorProto() + : ::google::protobuf::Message() { + SharedCtor(); +} + +void EnumDescriptorProto::InitAsDefaultInstance() { + options_ = const_cast< ::google::protobuf::EnumOptions*>(&::google::protobuf::EnumOptions::default_instance()); +} + +EnumDescriptorProto::EnumDescriptorProto(const EnumDescriptorProto& from) + : ::google::protobuf::Message() { + SharedCtor(); + MergeFrom(from); +} + +void EnumDescriptorProto::SharedCtor() { + _cached_size_ = 0; + name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + options_ = NULL; + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + +EnumDescriptorProto::~EnumDescriptorProto() { + SharedDtor(); +} + +void EnumDescriptorProto::SharedDtor() { + if (name_ != &::google::protobuf::internal::kEmptyString) { + delete name_; + } + if (this != default_instance_) { + delete options_; + } +} + +void EnumDescriptorProto::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} +const ::google::protobuf::Descriptor* EnumDescriptorProto::descriptor() { + protobuf_AssignDescriptorsOnce(); + return EnumDescriptorProto_descriptor_; +} + +const EnumDescriptorProto& EnumDescriptorProto::default_instance() { + if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_; +} + +EnumDescriptorProto* EnumDescriptorProto::default_instance_ = NULL; + +EnumDescriptorProto* EnumDescriptorProto::New() const { + return new EnumDescriptorProto; +} + +void EnumDescriptorProto::Clear() { + if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + if (has_name()) { + if (name_ != &::google::protobuf::internal::kEmptyString) { + name_->clear(); + } + } + if (has_options()) { + if (options_ != NULL) options_->::google::protobuf::EnumOptions::Clear(); + } + } + value_.Clear(); + ::memset(_has_bits_, 0, sizeof(_has_bits_)); + mutable_unknown_fields()->Clear(); +} + +bool EnumDescriptorProto::MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input) { +#define DO_(EXPRESSION) if (!(EXPRESSION)) return false + ::google::protobuf::uint32 tag; + while ((tag = input->ReadTag()) != 0) { + switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { + // optional string name = 1; + case 1: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_name())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(18)) goto parse_value; + break; + } + + // repeated .google.protobuf.EnumValueDescriptorProto value = 2; + case 2: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_value: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_value())); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(18)) goto parse_value; + if (input->ExpectTag(26)) goto parse_options; + break; + } + + // optional .google.protobuf.EnumOptions options = 3; + case 3: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_options: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, mutable_options())); + } else { + goto handle_uninterpreted; + } + if (input->ExpectAtEnd()) return true; + break; + } + + default: { + handle_uninterpreted: + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { + return true; + } + DO_(::google::protobuf::internal::WireFormat::SkipField( + input, tag, mutable_unknown_fields())); + break; + } + } + } + return true; +#undef DO_ +} + +void EnumDescriptorProto::SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const { + // optional string name = 1; + if (has_name()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + ::google::protobuf::internal::WireFormatLite::WriteString( + 1, this->name(), output); + } + + // repeated .google.protobuf.EnumValueDescriptorProto value = 2; + for (int i = 0; i < this->value_size(); i++) { + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( + 2, this->value(i), output); + } + + // optional .google.protobuf.EnumOptions options = 3; + if (has_options()) { + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( + 3, this->options(), output); + } + + if (!unknown_fields().empty()) { + ::google::protobuf::internal::WireFormat::SerializeUnknownFields( + unknown_fields(), output); + } +} + +::google::protobuf::uint8* EnumDescriptorProto::SerializeWithCachedSizesToArray( + ::google::protobuf::uint8* target) const { + // optional string name = 1; + if (has_name()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + target = + ::google::protobuf::internal::WireFormatLite::WriteStringToArray( + 1, this->name(), target); + } + + // repeated .google.protobuf.EnumValueDescriptorProto value = 2; + for (int i = 0; i < this->value_size(); i++) { + target = ::google::protobuf::internal::WireFormatLite:: + WriteMessageNoVirtualToArray( + 2, this->value(i), target); + } + + // optional .google.protobuf.EnumOptions options = 3; + if (has_options()) { + target = ::google::protobuf::internal::WireFormatLite:: + WriteMessageNoVirtualToArray( + 3, this->options(), target); + } + + if (!unknown_fields().empty()) { + target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( + unknown_fields(), target); + } + return target; +} + +int EnumDescriptorProto::ByteSize() const { + int total_size = 0; + + if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + // optional string name = 1; + if (has_name()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::StringSize( + this->name()); + } + + // optional .google.protobuf.EnumOptions options = 3; + if (has_options()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( + this->options()); + } + + } + // repeated .google.protobuf.EnumValueDescriptorProto value = 2; + total_size += 1 * this->value_size(); + for (int i = 0; i < this->value_size(); i++) { + total_size += + ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( + this->value(i)); + } + + if (!unknown_fields().empty()) { + total_size += + ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( + unknown_fields()); + } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); + return total_size; +} + +void EnumDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) { + GOOGLE_CHECK_NE(&from, this); + const EnumDescriptorProto* source = + ::google::protobuf::internal::dynamic_cast_if_available( + &from); + if (source == NULL) { + ::google::protobuf::internal::ReflectionOps::Merge(from, this); + } else { + MergeFrom(*source); + } +} + +void EnumDescriptorProto::MergeFrom(const EnumDescriptorProto& from) { + GOOGLE_CHECK_NE(&from, this); + value_.MergeFrom(from.value_); + if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { + if (from.has_name()) { + set_name(from.name()); + } + if (from.has_options()) { + mutable_options()->::google::protobuf::EnumOptions::MergeFrom(from.options()); + } + } + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); +} + +void EnumDescriptorProto::CopyFrom(const ::google::protobuf::Message& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +void EnumDescriptorProto::CopyFrom(const EnumDescriptorProto& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool EnumDescriptorProto::IsInitialized() const { + + for (int i = 0; i < value_size(); i++) { + if (!this->value(i).IsInitialized()) return false; + } + if (has_options()) { + if (!this->options().IsInitialized()) return false; + } + return true; +} + +void EnumDescriptorProto::Swap(EnumDescriptorProto* other) { + if (other != this) { + std::swap(name_, other->name_); + value_.Swap(&other->value_); + std::swap(options_, other->options_); + std::swap(_has_bits_[0], other->_has_bits_[0]); + _unknown_fields_.Swap(&other->_unknown_fields_); + std::swap(_cached_size_, other->_cached_size_); + } +} + +::google::protobuf::Metadata EnumDescriptorProto::GetMetadata() const { + protobuf_AssignDescriptorsOnce(); + ::google::protobuf::Metadata metadata; + metadata.descriptor = EnumDescriptorProto_descriptor_; + metadata.reflection = EnumDescriptorProto_reflection_; + return metadata; +} + + +// =================================================================== + +#ifndef _MSC_VER +const int EnumValueDescriptorProto::kNameFieldNumber; +const int EnumValueDescriptorProto::kNumberFieldNumber; +const int EnumValueDescriptorProto::kOptionsFieldNumber; +#endif // !_MSC_VER + +EnumValueDescriptorProto::EnumValueDescriptorProto() + : ::google::protobuf::Message() { + SharedCtor(); +} + +void EnumValueDescriptorProto::InitAsDefaultInstance() { + options_ = const_cast< ::google::protobuf::EnumValueOptions*>(&::google::protobuf::EnumValueOptions::default_instance()); +} + +EnumValueDescriptorProto::EnumValueDescriptorProto(const EnumValueDescriptorProto& from) + : ::google::protobuf::Message() { + SharedCtor(); + MergeFrom(from); +} + +void EnumValueDescriptorProto::SharedCtor() { + _cached_size_ = 0; + name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + number_ = 0; + options_ = NULL; + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + +EnumValueDescriptorProto::~EnumValueDescriptorProto() { + SharedDtor(); +} + +void EnumValueDescriptorProto::SharedDtor() { + if (name_ != &::google::protobuf::internal::kEmptyString) { + delete name_; + } + if (this != default_instance_) { + delete options_; + } +} + +void EnumValueDescriptorProto::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} +const ::google::protobuf::Descriptor* EnumValueDescriptorProto::descriptor() { + protobuf_AssignDescriptorsOnce(); + return EnumValueDescriptorProto_descriptor_; +} + +const EnumValueDescriptorProto& EnumValueDescriptorProto::default_instance() { + if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_; +} + +EnumValueDescriptorProto* EnumValueDescriptorProto::default_instance_ = NULL; + +EnumValueDescriptorProto* EnumValueDescriptorProto::New() const { + return new EnumValueDescriptorProto; +} + +void EnumValueDescriptorProto::Clear() { + if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + if (has_name()) { + if (name_ != &::google::protobuf::internal::kEmptyString) { + name_->clear(); + } + } + number_ = 0; + if (has_options()) { + if (options_ != NULL) options_->::google::protobuf::EnumValueOptions::Clear(); + } + } + ::memset(_has_bits_, 0, sizeof(_has_bits_)); + mutable_unknown_fields()->Clear(); +} + +bool EnumValueDescriptorProto::MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input) { +#define DO_(EXPRESSION) if (!(EXPRESSION)) return false + ::google::protobuf::uint32 tag; + while ((tag = input->ReadTag()) != 0) { + switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { + // optional string name = 1; + case 1: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_name())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(16)) goto parse_number; + break; + } + + // optional int32 number = 2; + case 2: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_number: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( + input, &number_))); + set_has_number(); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(26)) goto parse_options; + break; + } + + // optional .google.protobuf.EnumValueOptions options = 3; + case 3: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_options: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, mutable_options())); + } else { + goto handle_uninterpreted; + } + if (input->ExpectAtEnd()) return true; + break; + } + + default: { + handle_uninterpreted: + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { + return true; + } + DO_(::google::protobuf::internal::WireFormat::SkipField( + input, tag, mutable_unknown_fields())); + break; + } + } + } + return true; +#undef DO_ +} + +void EnumValueDescriptorProto::SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const { + // optional string name = 1; + if (has_name()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + ::google::protobuf::internal::WireFormatLite::WriteString( + 1, this->name(), output); + } + + // optional int32 number = 2; + if (has_number()) { + ::google::protobuf::internal::WireFormatLite::WriteInt32(2, this->number(), output); + } + + // optional .google.protobuf.EnumValueOptions options = 3; + if (has_options()) { + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( + 3, this->options(), output); + } + + if (!unknown_fields().empty()) { + ::google::protobuf::internal::WireFormat::SerializeUnknownFields( + unknown_fields(), output); + } +} + +::google::protobuf::uint8* EnumValueDescriptorProto::SerializeWithCachedSizesToArray( + ::google::protobuf::uint8* target) const { + // optional string name = 1; + if (has_name()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + target = + ::google::protobuf::internal::WireFormatLite::WriteStringToArray( + 1, this->name(), target); + } + + // optional int32 number = 2; + if (has_number()) { + target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(2, this->number(), target); + } + + // optional .google.protobuf.EnumValueOptions options = 3; + if (has_options()) { + target = ::google::protobuf::internal::WireFormatLite:: + WriteMessageNoVirtualToArray( + 3, this->options(), target); + } + + if (!unknown_fields().empty()) { + target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( + unknown_fields(), target); + } + return target; +} + +int EnumValueDescriptorProto::ByteSize() const { + int total_size = 0; + + if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + // optional string name = 1; + if (has_name()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::StringSize( + this->name()); + } + + // optional int32 number = 2; + if (has_number()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::Int32Size( + this->number()); + } + + // optional .google.protobuf.EnumValueOptions options = 3; + if (has_options()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( + this->options()); + } + + } + if (!unknown_fields().empty()) { + total_size += + ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( + unknown_fields()); + } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); + return total_size; +} + +void EnumValueDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) { + GOOGLE_CHECK_NE(&from, this); + const EnumValueDescriptorProto* source = + ::google::protobuf::internal::dynamic_cast_if_available( + &from); + if (source == NULL) { + ::google::protobuf::internal::ReflectionOps::Merge(from, this); + } else { + MergeFrom(*source); + } +} + +void EnumValueDescriptorProto::MergeFrom(const EnumValueDescriptorProto& from) { + GOOGLE_CHECK_NE(&from, this); + if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { + if (from.has_name()) { + set_name(from.name()); + } + if (from.has_number()) { + set_number(from.number()); + } + if (from.has_options()) { + mutable_options()->::google::protobuf::EnumValueOptions::MergeFrom(from.options()); + } + } + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); +} + +void EnumValueDescriptorProto::CopyFrom(const ::google::protobuf::Message& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +void EnumValueDescriptorProto::CopyFrom(const EnumValueDescriptorProto& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool EnumValueDescriptorProto::IsInitialized() const { + + if (has_options()) { + if (!this->options().IsInitialized()) return false; + } + return true; +} + +void EnumValueDescriptorProto::Swap(EnumValueDescriptorProto* other) { + if (other != this) { + std::swap(name_, other->name_); + std::swap(number_, other->number_); + std::swap(options_, other->options_); + std::swap(_has_bits_[0], other->_has_bits_[0]); + _unknown_fields_.Swap(&other->_unknown_fields_); + std::swap(_cached_size_, other->_cached_size_); + } +} + +::google::protobuf::Metadata EnumValueDescriptorProto::GetMetadata() const { + protobuf_AssignDescriptorsOnce(); + ::google::protobuf::Metadata metadata; + metadata.descriptor = EnumValueDescriptorProto_descriptor_; + metadata.reflection = EnumValueDescriptorProto_reflection_; + return metadata; +} + + +// =================================================================== + +#ifndef _MSC_VER +const int ServiceDescriptorProto::kNameFieldNumber; +const int ServiceDescriptorProto::kMethodFieldNumber; +const int ServiceDescriptorProto::kOptionsFieldNumber; +#endif // !_MSC_VER + +ServiceDescriptorProto::ServiceDescriptorProto() + : ::google::protobuf::Message() { + SharedCtor(); +} + +void ServiceDescriptorProto::InitAsDefaultInstance() { + options_ = const_cast< ::google::protobuf::ServiceOptions*>(&::google::protobuf::ServiceOptions::default_instance()); +} + +ServiceDescriptorProto::ServiceDescriptorProto(const ServiceDescriptorProto& from) + : ::google::protobuf::Message() { + SharedCtor(); + MergeFrom(from); +} + +void ServiceDescriptorProto::SharedCtor() { + _cached_size_ = 0; + name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + options_ = NULL; + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + +ServiceDescriptorProto::~ServiceDescriptorProto() { + SharedDtor(); +} + +void ServiceDescriptorProto::SharedDtor() { + if (name_ != &::google::protobuf::internal::kEmptyString) { + delete name_; + } + if (this != default_instance_) { + delete options_; + } +} + +void ServiceDescriptorProto::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} +const ::google::protobuf::Descriptor* ServiceDescriptorProto::descriptor() { + protobuf_AssignDescriptorsOnce(); + return ServiceDescriptorProto_descriptor_; +} + +const ServiceDescriptorProto& ServiceDescriptorProto::default_instance() { + if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_; +} + +ServiceDescriptorProto* ServiceDescriptorProto::default_instance_ = NULL; + +ServiceDescriptorProto* ServiceDescriptorProto::New() const { + return new ServiceDescriptorProto; +} + +void ServiceDescriptorProto::Clear() { + if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + if (has_name()) { + if (name_ != &::google::protobuf::internal::kEmptyString) { + name_->clear(); + } + } + if (has_options()) { + if (options_ != NULL) options_->::google::protobuf::ServiceOptions::Clear(); + } + } + method_.Clear(); + ::memset(_has_bits_, 0, sizeof(_has_bits_)); + mutable_unknown_fields()->Clear(); +} + +bool ServiceDescriptorProto::MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input) { +#define DO_(EXPRESSION) if (!(EXPRESSION)) return false + ::google::protobuf::uint32 tag; + while ((tag = input->ReadTag()) != 0) { + switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { + // optional string name = 1; + case 1: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_name())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(18)) goto parse_method; + break; + } + + // repeated .google.protobuf.MethodDescriptorProto method = 2; + case 2: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_method: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_method())); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(18)) goto parse_method; + if (input->ExpectTag(26)) goto parse_options; + break; + } + + // optional .google.protobuf.ServiceOptions options = 3; + case 3: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_options: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, mutable_options())); + } else { + goto handle_uninterpreted; + } + if (input->ExpectAtEnd()) return true; + break; + } + + default: { + handle_uninterpreted: + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { + return true; + } + DO_(::google::protobuf::internal::WireFormat::SkipField( + input, tag, mutable_unknown_fields())); + break; + } + } + } + return true; +#undef DO_ +} + +void ServiceDescriptorProto::SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const { + // optional string name = 1; + if (has_name()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + ::google::protobuf::internal::WireFormatLite::WriteString( + 1, this->name(), output); + } + + // repeated .google.protobuf.MethodDescriptorProto method = 2; + for (int i = 0; i < this->method_size(); i++) { + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( + 2, this->method(i), output); + } + + // optional .google.protobuf.ServiceOptions options = 3; + if (has_options()) { + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( + 3, this->options(), output); + } + + if (!unknown_fields().empty()) { + ::google::protobuf::internal::WireFormat::SerializeUnknownFields( + unknown_fields(), output); + } +} + +::google::protobuf::uint8* ServiceDescriptorProto::SerializeWithCachedSizesToArray( + ::google::protobuf::uint8* target) const { + // optional string name = 1; + if (has_name()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + target = + ::google::protobuf::internal::WireFormatLite::WriteStringToArray( + 1, this->name(), target); + } + + // repeated .google.protobuf.MethodDescriptorProto method = 2; + for (int i = 0; i < this->method_size(); i++) { + target = ::google::protobuf::internal::WireFormatLite:: + WriteMessageNoVirtualToArray( + 2, this->method(i), target); + } + + // optional .google.protobuf.ServiceOptions options = 3; + if (has_options()) { + target = ::google::protobuf::internal::WireFormatLite:: + WriteMessageNoVirtualToArray( + 3, this->options(), target); + } + + if (!unknown_fields().empty()) { + target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( + unknown_fields(), target); + } + return target; +} + +int ServiceDescriptorProto::ByteSize() const { + int total_size = 0; + + if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + // optional string name = 1; + if (has_name()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::StringSize( + this->name()); + } + + // optional .google.protobuf.ServiceOptions options = 3; + if (has_options()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( + this->options()); + } + + } + // repeated .google.protobuf.MethodDescriptorProto method = 2; + total_size += 1 * this->method_size(); + for (int i = 0; i < this->method_size(); i++) { + total_size += + ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( + this->method(i)); + } + + if (!unknown_fields().empty()) { + total_size += + ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( + unknown_fields()); + } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); + return total_size; +} + +void ServiceDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) { + GOOGLE_CHECK_NE(&from, this); + const ServiceDescriptorProto* source = + ::google::protobuf::internal::dynamic_cast_if_available( + &from); + if (source == NULL) { + ::google::protobuf::internal::ReflectionOps::Merge(from, this); + } else { + MergeFrom(*source); + } +} + +void ServiceDescriptorProto::MergeFrom(const ServiceDescriptorProto& from) { + GOOGLE_CHECK_NE(&from, this); + method_.MergeFrom(from.method_); + if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { + if (from.has_name()) { + set_name(from.name()); + } + if (from.has_options()) { + mutable_options()->::google::protobuf::ServiceOptions::MergeFrom(from.options()); + } + } + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); +} + +void ServiceDescriptorProto::CopyFrom(const ::google::protobuf::Message& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +void ServiceDescriptorProto::CopyFrom(const ServiceDescriptorProto& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool ServiceDescriptorProto::IsInitialized() const { + + for (int i = 0; i < method_size(); i++) { + if (!this->method(i).IsInitialized()) return false; + } + if (has_options()) { + if (!this->options().IsInitialized()) return false; + } + return true; +} + +void ServiceDescriptorProto::Swap(ServiceDescriptorProto* other) { + if (other != this) { + std::swap(name_, other->name_); + method_.Swap(&other->method_); + std::swap(options_, other->options_); + std::swap(_has_bits_[0], other->_has_bits_[0]); + _unknown_fields_.Swap(&other->_unknown_fields_); + std::swap(_cached_size_, other->_cached_size_); + } +} + +::google::protobuf::Metadata ServiceDescriptorProto::GetMetadata() const { + protobuf_AssignDescriptorsOnce(); + ::google::protobuf::Metadata metadata; + metadata.descriptor = ServiceDescriptorProto_descriptor_; + metadata.reflection = ServiceDescriptorProto_reflection_; + return metadata; +} + + +// =================================================================== + +#ifndef _MSC_VER +const int MethodDescriptorProto::kNameFieldNumber; +const int MethodDescriptorProto::kInputTypeFieldNumber; +const int MethodDescriptorProto::kOutputTypeFieldNumber; +const int MethodDescriptorProto::kOptionsFieldNumber; +#endif // !_MSC_VER + +MethodDescriptorProto::MethodDescriptorProto() + : ::google::protobuf::Message() { + SharedCtor(); +} + +void MethodDescriptorProto::InitAsDefaultInstance() { + options_ = const_cast< ::google::protobuf::MethodOptions*>(&::google::protobuf::MethodOptions::default_instance()); +} + +MethodDescriptorProto::MethodDescriptorProto(const MethodDescriptorProto& from) + : ::google::protobuf::Message() { + SharedCtor(); + MergeFrom(from); +} + +void MethodDescriptorProto::SharedCtor() { + _cached_size_ = 0; + name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + input_type_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + output_type_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + options_ = NULL; + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + +MethodDescriptorProto::~MethodDescriptorProto() { + SharedDtor(); +} + +void MethodDescriptorProto::SharedDtor() { + if (name_ != &::google::protobuf::internal::kEmptyString) { + delete name_; + } + if (input_type_ != &::google::protobuf::internal::kEmptyString) { + delete input_type_; + } + if (output_type_ != &::google::protobuf::internal::kEmptyString) { + delete output_type_; + } + if (this != default_instance_) { + delete options_; + } +} + +void MethodDescriptorProto::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} +const ::google::protobuf::Descriptor* MethodDescriptorProto::descriptor() { + protobuf_AssignDescriptorsOnce(); + return MethodDescriptorProto_descriptor_; +} + +const MethodDescriptorProto& MethodDescriptorProto::default_instance() { + if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_; +} + +MethodDescriptorProto* MethodDescriptorProto::default_instance_ = NULL; + +MethodDescriptorProto* MethodDescriptorProto::New() const { + return new MethodDescriptorProto; +} + +void MethodDescriptorProto::Clear() { + if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + if (has_name()) { + if (name_ != &::google::protobuf::internal::kEmptyString) { + name_->clear(); + } + } + if (has_input_type()) { + if (input_type_ != &::google::protobuf::internal::kEmptyString) { + input_type_->clear(); + } + } + if (has_output_type()) { + if (output_type_ != &::google::protobuf::internal::kEmptyString) { + output_type_->clear(); + } + } + if (has_options()) { + if (options_ != NULL) options_->::google::protobuf::MethodOptions::Clear(); + } + } + ::memset(_has_bits_, 0, sizeof(_has_bits_)); + mutable_unknown_fields()->Clear(); +} + +bool MethodDescriptorProto::MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input) { +#define DO_(EXPRESSION) if (!(EXPRESSION)) return false + ::google::protobuf::uint32 tag; + while ((tag = input->ReadTag()) != 0) { + switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { + // optional string name = 1; + case 1: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_name())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(18)) goto parse_input_type; + break; + } + + // optional string input_type = 2; + case 2: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_input_type: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_input_type())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->input_type().data(), this->input_type().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(26)) goto parse_output_type; + break; + } + + // optional string output_type = 3; + case 3: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_output_type: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_output_type())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->output_type().data(), this->output_type().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(34)) goto parse_options; + break; + } + + // optional .google.protobuf.MethodOptions options = 4; + case 4: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_options: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, mutable_options())); + } else { + goto handle_uninterpreted; + } + if (input->ExpectAtEnd()) return true; + break; + } + + default: { + handle_uninterpreted: + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { + return true; + } + DO_(::google::protobuf::internal::WireFormat::SkipField( + input, tag, mutable_unknown_fields())); + break; + } + } + } + return true; +#undef DO_ +} + +void MethodDescriptorProto::SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const { + // optional string name = 1; + if (has_name()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + ::google::protobuf::internal::WireFormatLite::WriteString( + 1, this->name(), output); + } + + // optional string input_type = 2; + if (has_input_type()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->input_type().data(), this->input_type().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + ::google::protobuf::internal::WireFormatLite::WriteString( + 2, this->input_type(), output); + } + + // optional string output_type = 3; + if (has_output_type()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->output_type().data(), this->output_type().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + ::google::protobuf::internal::WireFormatLite::WriteString( + 3, this->output_type(), output); + } + + // optional .google.protobuf.MethodOptions options = 4; + if (has_options()) { + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( + 4, this->options(), output); + } + + if (!unknown_fields().empty()) { + ::google::protobuf::internal::WireFormat::SerializeUnknownFields( + unknown_fields(), output); + } +} + +::google::protobuf::uint8* MethodDescriptorProto::SerializeWithCachedSizesToArray( + ::google::protobuf::uint8* target) const { + // optional string name = 1; + if (has_name()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + target = + ::google::protobuf::internal::WireFormatLite::WriteStringToArray( + 1, this->name(), target); + } + + // optional string input_type = 2; + if (has_input_type()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->input_type().data(), this->input_type().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + target = + ::google::protobuf::internal::WireFormatLite::WriteStringToArray( + 2, this->input_type(), target); + } + + // optional string output_type = 3; + if (has_output_type()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->output_type().data(), this->output_type().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + target = + ::google::protobuf::internal::WireFormatLite::WriteStringToArray( + 3, this->output_type(), target); + } + + // optional .google.protobuf.MethodOptions options = 4; + if (has_options()) { + target = ::google::protobuf::internal::WireFormatLite:: + WriteMessageNoVirtualToArray( + 4, this->options(), target); + } + + if (!unknown_fields().empty()) { + target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( + unknown_fields(), target); + } + return target; +} + +int MethodDescriptorProto::ByteSize() const { + int total_size = 0; + + if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + // optional string name = 1; + if (has_name()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::StringSize( + this->name()); + } + + // optional string input_type = 2; + if (has_input_type()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::StringSize( + this->input_type()); + } + + // optional string output_type = 3; + if (has_output_type()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::StringSize( + this->output_type()); + } + + // optional .google.protobuf.MethodOptions options = 4; + if (has_options()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( + this->options()); + } + + } + if (!unknown_fields().empty()) { + total_size += + ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( + unknown_fields()); + } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); + return total_size; +} + +void MethodDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) { + GOOGLE_CHECK_NE(&from, this); + const MethodDescriptorProto* source = + ::google::protobuf::internal::dynamic_cast_if_available( + &from); + if (source == NULL) { + ::google::protobuf::internal::ReflectionOps::Merge(from, this); + } else { + MergeFrom(*source); + } +} + +void MethodDescriptorProto::MergeFrom(const MethodDescriptorProto& from) { + GOOGLE_CHECK_NE(&from, this); + if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { + if (from.has_name()) { + set_name(from.name()); + } + if (from.has_input_type()) { + set_input_type(from.input_type()); + } + if (from.has_output_type()) { + set_output_type(from.output_type()); + } + if (from.has_options()) { + mutable_options()->::google::protobuf::MethodOptions::MergeFrom(from.options()); + } + } + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); +} + +void MethodDescriptorProto::CopyFrom(const ::google::protobuf::Message& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +void MethodDescriptorProto::CopyFrom(const MethodDescriptorProto& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool MethodDescriptorProto::IsInitialized() const { + + if (has_options()) { + if (!this->options().IsInitialized()) return false; + } + return true; +} + +void MethodDescriptorProto::Swap(MethodDescriptorProto* other) { + if (other != this) { + std::swap(name_, other->name_); + std::swap(input_type_, other->input_type_); + std::swap(output_type_, other->output_type_); + std::swap(options_, other->options_); + std::swap(_has_bits_[0], other->_has_bits_[0]); + _unknown_fields_.Swap(&other->_unknown_fields_); + std::swap(_cached_size_, other->_cached_size_); + } +} + +::google::protobuf::Metadata MethodDescriptorProto::GetMetadata() const { + protobuf_AssignDescriptorsOnce(); + ::google::protobuf::Metadata metadata; + metadata.descriptor = MethodDescriptorProto_descriptor_; + metadata.reflection = MethodDescriptorProto_reflection_; + return metadata; +} + + +// =================================================================== + +const ::google::protobuf::EnumDescriptor* FileOptions_OptimizeMode_descriptor() { + protobuf_AssignDescriptorsOnce(); + return FileOptions_OptimizeMode_descriptor_; +} +bool FileOptions_OptimizeMode_IsValid(int value) { + switch(value) { + case 1: + case 2: + case 3: + return true; + default: + return false; + } +} + +#ifndef _MSC_VER +const FileOptions_OptimizeMode FileOptions::SPEED; +const FileOptions_OptimizeMode FileOptions::CODE_SIZE; +const FileOptions_OptimizeMode FileOptions::LITE_RUNTIME; +const FileOptions_OptimizeMode FileOptions::OptimizeMode_MIN; +const FileOptions_OptimizeMode FileOptions::OptimizeMode_MAX; +const int FileOptions::OptimizeMode_ARRAYSIZE; +#endif // _MSC_VER +#ifndef _MSC_VER +const int FileOptions::kJavaPackageFieldNumber; +const int FileOptions::kJavaOuterClassnameFieldNumber; +const int FileOptions::kJavaMultipleFilesFieldNumber; +const int FileOptions::kJavaGenerateEqualsAndHashFieldNumber; +const int FileOptions::kOptimizeForFieldNumber; +const int FileOptions::kCcGenericServicesFieldNumber; +const int FileOptions::kJavaGenericServicesFieldNumber; +const int FileOptions::kPyGenericServicesFieldNumber; +const int FileOptions::kUninterpretedOptionFieldNumber; +#endif // !_MSC_VER + +FileOptions::FileOptions() + : ::google::protobuf::Message() { + SharedCtor(); +} + +void FileOptions::InitAsDefaultInstance() { +} + +FileOptions::FileOptions(const FileOptions& from) + : ::google::protobuf::Message() { + SharedCtor(); + MergeFrom(from); +} + +void FileOptions::SharedCtor() { + _cached_size_ = 0; + java_package_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + java_outer_classname_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + java_multiple_files_ = false; + java_generate_equals_and_hash_ = false; + optimize_for_ = 1; + cc_generic_services_ = false; + java_generic_services_ = false; + py_generic_services_ = false; + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + +FileOptions::~FileOptions() { + SharedDtor(); +} + +void FileOptions::SharedDtor() { + if (java_package_ != &::google::protobuf::internal::kEmptyString) { + delete java_package_; + } + if (java_outer_classname_ != &::google::protobuf::internal::kEmptyString) { + delete java_outer_classname_; + } + if (this != default_instance_) { + } +} + +void FileOptions::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} +const ::google::protobuf::Descriptor* FileOptions::descriptor() { + protobuf_AssignDescriptorsOnce(); + return FileOptions_descriptor_; +} + +const FileOptions& FileOptions::default_instance() { + if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_; +} + +FileOptions* FileOptions::default_instance_ = NULL; + +FileOptions* FileOptions::New() const { + return new FileOptions; +} + +void FileOptions::Clear() { + _extensions_.Clear(); + if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + if (has_java_package()) { + if (java_package_ != &::google::protobuf::internal::kEmptyString) { + java_package_->clear(); + } + } + if (has_java_outer_classname()) { + if (java_outer_classname_ != &::google::protobuf::internal::kEmptyString) { + java_outer_classname_->clear(); + } + } + java_multiple_files_ = false; + java_generate_equals_and_hash_ = false; + optimize_for_ = 1; + cc_generic_services_ = false; + java_generic_services_ = false; + py_generic_services_ = false; + } + uninterpreted_option_.Clear(); + ::memset(_has_bits_, 0, sizeof(_has_bits_)); + mutable_unknown_fields()->Clear(); +} + +bool FileOptions::MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input) { +#define DO_(EXPRESSION) if (!(EXPRESSION)) return false + ::google::protobuf::uint32 tag; + while ((tag = input->ReadTag()) != 0) { + switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { + // optional string java_package = 1; + case 1: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_java_package())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->java_package().data(), this->java_package().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(66)) goto parse_java_outer_classname; + break; + } + + // optional string java_outer_classname = 8; + case 8: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_java_outer_classname: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_java_outer_classname())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->java_outer_classname().data(), this->java_outer_classname().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(72)) goto parse_optimize_for; + break; + } + + // optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED]; + case 9: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_optimize_for: + int value; + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>( + input, &value))); + if (::google::protobuf::FileOptions_OptimizeMode_IsValid(value)) { + set_optimize_for(static_cast< ::google::protobuf::FileOptions_OptimizeMode >(value)); + } else { + mutable_unknown_fields()->AddVarint(9, value); + } + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(80)) goto parse_java_multiple_files; + break; + } + + // optional bool java_multiple_files = 10 [default = false]; + case 10: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_java_multiple_files: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( + input, &java_multiple_files_))); + set_has_java_multiple_files(); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(128)) goto parse_cc_generic_services; + break; + } + + // optional bool cc_generic_services = 16 [default = false]; + case 16: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_cc_generic_services: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( + input, &cc_generic_services_))); + set_has_cc_generic_services(); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(136)) goto parse_java_generic_services; + break; + } + + // optional bool java_generic_services = 17 [default = false]; + case 17: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_java_generic_services: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( + input, &java_generic_services_))); + set_has_java_generic_services(); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(144)) goto parse_py_generic_services; + break; + } + + // optional bool py_generic_services = 18 [default = false]; + case 18: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_py_generic_services: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( + input, &py_generic_services_))); + set_has_py_generic_services(); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(160)) goto parse_java_generate_equals_and_hash; + break; + } + + // optional bool java_generate_equals_and_hash = 20 [default = false]; + case 20: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_java_generate_equals_and_hash: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( + input, &java_generate_equals_and_hash_))); + set_has_java_generate_equals_and_hash(); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(7994)) goto parse_uninterpreted_option; + break; + } + + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; + case 999: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_uninterpreted_option: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_uninterpreted_option())); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(7994)) goto parse_uninterpreted_option; + if (input->ExpectAtEnd()) return true; + break; + } + + default: { + handle_uninterpreted: + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { + return true; + } + if ((8000u <= tag)) { + DO_(_extensions_.ParseField(tag, input, default_instance_, + mutable_unknown_fields())); + continue; + } + DO_(::google::protobuf::internal::WireFormat::SkipField( + input, tag, mutable_unknown_fields())); + break; + } + } + } + return true; +#undef DO_ +} + +void FileOptions::SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const { + // optional string java_package = 1; + if (has_java_package()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->java_package().data(), this->java_package().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + ::google::protobuf::internal::WireFormatLite::WriteString( + 1, this->java_package(), output); + } + + // optional string java_outer_classname = 8; + if (has_java_outer_classname()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->java_outer_classname().data(), this->java_outer_classname().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + ::google::protobuf::internal::WireFormatLite::WriteString( + 8, this->java_outer_classname(), output); + } + + // optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED]; + if (has_optimize_for()) { + ::google::protobuf::internal::WireFormatLite::WriteEnum( + 9, this->optimize_for(), output); + } + + // optional bool java_multiple_files = 10 [default = false]; + if (has_java_multiple_files()) { + ::google::protobuf::internal::WireFormatLite::WriteBool(10, this->java_multiple_files(), output); + } + + // optional bool cc_generic_services = 16 [default = false]; + if (has_cc_generic_services()) { + ::google::protobuf::internal::WireFormatLite::WriteBool(16, this->cc_generic_services(), output); + } + + // optional bool java_generic_services = 17 [default = false]; + if (has_java_generic_services()) { + ::google::protobuf::internal::WireFormatLite::WriteBool(17, this->java_generic_services(), output); + } + + // optional bool py_generic_services = 18 [default = false]; + if (has_py_generic_services()) { + ::google::protobuf::internal::WireFormatLite::WriteBool(18, this->py_generic_services(), output); + } + + // optional bool java_generate_equals_and_hash = 20 [default = false]; + if (has_java_generate_equals_and_hash()) { + ::google::protobuf::internal::WireFormatLite::WriteBool(20, this->java_generate_equals_and_hash(), output); + } + + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; + for (int i = 0; i < this->uninterpreted_option_size(); i++) { + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( + 999, this->uninterpreted_option(i), output); + } + + // Extension range [1000, 536870912) + _extensions_.SerializeWithCachedSizes( + 1000, 536870912, output); + + if (!unknown_fields().empty()) { + ::google::protobuf::internal::WireFormat::SerializeUnknownFields( + unknown_fields(), output); + } +} + +::google::protobuf::uint8* FileOptions::SerializeWithCachedSizesToArray( + ::google::protobuf::uint8* target) const { + // optional string java_package = 1; + if (has_java_package()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->java_package().data(), this->java_package().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + target = + ::google::protobuf::internal::WireFormatLite::WriteStringToArray( + 1, this->java_package(), target); + } + + // optional string java_outer_classname = 8; + if (has_java_outer_classname()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->java_outer_classname().data(), this->java_outer_classname().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + target = + ::google::protobuf::internal::WireFormatLite::WriteStringToArray( + 8, this->java_outer_classname(), target); + } + + // optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED]; + if (has_optimize_for()) { + target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray( + 9, this->optimize_for(), target); + } + + // optional bool java_multiple_files = 10 [default = false]; + if (has_java_multiple_files()) { + target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(10, this->java_multiple_files(), target); + } + + // optional bool cc_generic_services = 16 [default = false]; + if (has_cc_generic_services()) { + target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(16, this->cc_generic_services(), target); + } + + // optional bool java_generic_services = 17 [default = false]; + if (has_java_generic_services()) { + target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(17, this->java_generic_services(), target); + } + + // optional bool py_generic_services = 18 [default = false]; + if (has_py_generic_services()) { + target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(18, this->py_generic_services(), target); + } + + // optional bool java_generate_equals_and_hash = 20 [default = false]; + if (has_java_generate_equals_and_hash()) { + target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(20, this->java_generate_equals_and_hash(), target); + } + + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; + for (int i = 0; i < this->uninterpreted_option_size(); i++) { + target = ::google::protobuf::internal::WireFormatLite:: + WriteMessageNoVirtualToArray( + 999, this->uninterpreted_option(i), target); + } + + // Extension range [1000, 536870912) + target = _extensions_.SerializeWithCachedSizesToArray( + 1000, 536870912, target); + + if (!unknown_fields().empty()) { + target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( + unknown_fields(), target); + } + return target; +} + +int FileOptions::ByteSize() const { + int total_size = 0; + + if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + // optional string java_package = 1; + if (has_java_package()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::StringSize( + this->java_package()); + } + + // optional string java_outer_classname = 8; + if (has_java_outer_classname()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::StringSize( + this->java_outer_classname()); + } + + // optional bool java_multiple_files = 10 [default = false]; + if (has_java_multiple_files()) { + total_size += 1 + 1; + } + + // optional bool java_generate_equals_and_hash = 20 [default = false]; + if (has_java_generate_equals_and_hash()) { + total_size += 2 + 1; + } + + // optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED]; + if (has_optimize_for()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::EnumSize(this->optimize_for()); + } + + // optional bool cc_generic_services = 16 [default = false]; + if (has_cc_generic_services()) { + total_size += 2 + 1; + } + + // optional bool java_generic_services = 17 [default = false]; + if (has_java_generic_services()) { + total_size += 2 + 1; + } + + // optional bool py_generic_services = 18 [default = false]; + if (has_py_generic_services()) { + total_size += 2 + 1; + } + + } + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; + total_size += 2 * this->uninterpreted_option_size(); + for (int i = 0; i < this->uninterpreted_option_size(); i++) { + total_size += + ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( + this->uninterpreted_option(i)); + } + + total_size += _extensions_.ByteSize(); + + if (!unknown_fields().empty()) { + total_size += + ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( + unknown_fields()); + } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); + return total_size; +} + +void FileOptions::MergeFrom(const ::google::protobuf::Message& from) { + GOOGLE_CHECK_NE(&from, this); + const FileOptions* source = + ::google::protobuf::internal::dynamic_cast_if_available( + &from); + if (source == NULL) { + ::google::protobuf::internal::ReflectionOps::Merge(from, this); + } else { + MergeFrom(*source); + } +} + +void FileOptions::MergeFrom(const FileOptions& from) { + GOOGLE_CHECK_NE(&from, this); + uninterpreted_option_.MergeFrom(from.uninterpreted_option_); + if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { + if (from.has_java_package()) { + set_java_package(from.java_package()); + } + if (from.has_java_outer_classname()) { + set_java_outer_classname(from.java_outer_classname()); + } + if (from.has_java_multiple_files()) { + set_java_multiple_files(from.java_multiple_files()); + } + if (from.has_java_generate_equals_and_hash()) { + set_java_generate_equals_and_hash(from.java_generate_equals_and_hash()); + } + if (from.has_optimize_for()) { + set_optimize_for(from.optimize_for()); + } + if (from.has_cc_generic_services()) { + set_cc_generic_services(from.cc_generic_services()); + } + if (from.has_java_generic_services()) { + set_java_generic_services(from.java_generic_services()); + } + if (from.has_py_generic_services()) { + set_py_generic_services(from.py_generic_services()); + } + } + _extensions_.MergeFrom(from._extensions_); + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); +} + +void FileOptions::CopyFrom(const ::google::protobuf::Message& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +void FileOptions::CopyFrom(const FileOptions& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool FileOptions::IsInitialized() const { + + for (int i = 0; i < uninterpreted_option_size(); i++) { + if (!this->uninterpreted_option(i).IsInitialized()) return false; + } + + if (!_extensions_.IsInitialized()) return false; return true; +} + +void FileOptions::Swap(FileOptions* other) { + if (other != this) { + std::swap(java_package_, other->java_package_); + std::swap(java_outer_classname_, other->java_outer_classname_); + std::swap(java_multiple_files_, other->java_multiple_files_); + std::swap(java_generate_equals_and_hash_, other->java_generate_equals_and_hash_); + std::swap(optimize_for_, other->optimize_for_); + std::swap(cc_generic_services_, other->cc_generic_services_); + std::swap(java_generic_services_, other->java_generic_services_); + std::swap(py_generic_services_, other->py_generic_services_); + uninterpreted_option_.Swap(&other->uninterpreted_option_); + std::swap(_has_bits_[0], other->_has_bits_[0]); + _unknown_fields_.Swap(&other->_unknown_fields_); + std::swap(_cached_size_, other->_cached_size_); + _extensions_.Swap(&other->_extensions_); + } +} + +::google::protobuf::Metadata FileOptions::GetMetadata() const { + protobuf_AssignDescriptorsOnce(); + ::google::protobuf::Metadata metadata; + metadata.descriptor = FileOptions_descriptor_; + metadata.reflection = FileOptions_reflection_; + return metadata; +} + + +// =================================================================== + +#ifndef _MSC_VER +const int MessageOptions::kMessageSetWireFormatFieldNumber; +const int MessageOptions::kNoStandardDescriptorAccessorFieldNumber; +const int MessageOptions::kUninterpretedOptionFieldNumber; +#endif // !_MSC_VER + +MessageOptions::MessageOptions() + : ::google::protobuf::Message() { + SharedCtor(); +} + +void MessageOptions::InitAsDefaultInstance() { +} + +MessageOptions::MessageOptions(const MessageOptions& from) + : ::google::protobuf::Message() { + SharedCtor(); + MergeFrom(from); +} + +void MessageOptions::SharedCtor() { + _cached_size_ = 0; + message_set_wire_format_ = false; + no_standard_descriptor_accessor_ = false; + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + +MessageOptions::~MessageOptions() { + SharedDtor(); +} + +void MessageOptions::SharedDtor() { + if (this != default_instance_) { + } +} + +void MessageOptions::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} +const ::google::protobuf::Descriptor* MessageOptions::descriptor() { + protobuf_AssignDescriptorsOnce(); + return MessageOptions_descriptor_; +} + +const MessageOptions& MessageOptions::default_instance() { + if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_; +} + +MessageOptions* MessageOptions::default_instance_ = NULL; + +MessageOptions* MessageOptions::New() const { + return new MessageOptions; +} + +void MessageOptions::Clear() { + _extensions_.Clear(); + if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + message_set_wire_format_ = false; + no_standard_descriptor_accessor_ = false; + } + uninterpreted_option_.Clear(); + ::memset(_has_bits_, 0, sizeof(_has_bits_)); + mutable_unknown_fields()->Clear(); +} + +bool MessageOptions::MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input) { +#define DO_(EXPRESSION) if (!(EXPRESSION)) return false + ::google::protobuf::uint32 tag; + while ((tag = input->ReadTag()) != 0) { + switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { + // optional bool message_set_wire_format = 1 [default = false]; + case 1: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( + input, &message_set_wire_format_))); + set_has_message_set_wire_format(); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(16)) goto parse_no_standard_descriptor_accessor; + break; + } + + // optional bool no_standard_descriptor_accessor = 2 [default = false]; + case 2: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_no_standard_descriptor_accessor: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( + input, &no_standard_descriptor_accessor_))); + set_has_no_standard_descriptor_accessor(); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(7994)) goto parse_uninterpreted_option; + break; + } + + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; + case 999: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_uninterpreted_option: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_uninterpreted_option())); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(7994)) goto parse_uninterpreted_option; + if (input->ExpectAtEnd()) return true; + break; + } + + default: { + handle_uninterpreted: + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { + return true; + } + if ((8000u <= tag)) { + DO_(_extensions_.ParseField(tag, input, default_instance_, + mutable_unknown_fields())); + continue; + } + DO_(::google::protobuf::internal::WireFormat::SkipField( + input, tag, mutable_unknown_fields())); + break; + } + } + } + return true; +#undef DO_ +} + +void MessageOptions::SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const { + // optional bool message_set_wire_format = 1 [default = false]; + if (has_message_set_wire_format()) { + ::google::protobuf::internal::WireFormatLite::WriteBool(1, this->message_set_wire_format(), output); + } + + // optional bool no_standard_descriptor_accessor = 2 [default = false]; + if (has_no_standard_descriptor_accessor()) { + ::google::protobuf::internal::WireFormatLite::WriteBool(2, this->no_standard_descriptor_accessor(), output); + } + + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; + for (int i = 0; i < this->uninterpreted_option_size(); i++) { + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( + 999, this->uninterpreted_option(i), output); + } + + // Extension range [1000, 536870912) + _extensions_.SerializeWithCachedSizes( + 1000, 536870912, output); + + if (!unknown_fields().empty()) { + ::google::protobuf::internal::WireFormat::SerializeUnknownFields( + unknown_fields(), output); + } +} + +::google::protobuf::uint8* MessageOptions::SerializeWithCachedSizesToArray( + ::google::protobuf::uint8* target) const { + // optional bool message_set_wire_format = 1 [default = false]; + if (has_message_set_wire_format()) { + target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(1, this->message_set_wire_format(), target); + } + + // optional bool no_standard_descriptor_accessor = 2 [default = false]; + if (has_no_standard_descriptor_accessor()) { + target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(2, this->no_standard_descriptor_accessor(), target); + } + + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; + for (int i = 0; i < this->uninterpreted_option_size(); i++) { + target = ::google::protobuf::internal::WireFormatLite:: + WriteMessageNoVirtualToArray( + 999, this->uninterpreted_option(i), target); + } + + // Extension range [1000, 536870912) + target = _extensions_.SerializeWithCachedSizesToArray( + 1000, 536870912, target); + + if (!unknown_fields().empty()) { + target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( + unknown_fields(), target); + } + return target; +} + +int MessageOptions::ByteSize() const { + int total_size = 0; + + if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + // optional bool message_set_wire_format = 1 [default = false]; + if (has_message_set_wire_format()) { + total_size += 1 + 1; + } + + // optional bool no_standard_descriptor_accessor = 2 [default = false]; + if (has_no_standard_descriptor_accessor()) { + total_size += 1 + 1; + } + + } + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; + total_size += 2 * this->uninterpreted_option_size(); + for (int i = 0; i < this->uninterpreted_option_size(); i++) { + total_size += + ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( + this->uninterpreted_option(i)); + } + + total_size += _extensions_.ByteSize(); + + if (!unknown_fields().empty()) { + total_size += + ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( + unknown_fields()); + } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); + return total_size; +} + +void MessageOptions::MergeFrom(const ::google::protobuf::Message& from) { + GOOGLE_CHECK_NE(&from, this); + const MessageOptions* source = + ::google::protobuf::internal::dynamic_cast_if_available( + &from); + if (source == NULL) { + ::google::protobuf::internal::ReflectionOps::Merge(from, this); + } else { + MergeFrom(*source); + } +} + +void MessageOptions::MergeFrom(const MessageOptions& from) { + GOOGLE_CHECK_NE(&from, this); + uninterpreted_option_.MergeFrom(from.uninterpreted_option_); + if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { + if (from.has_message_set_wire_format()) { + set_message_set_wire_format(from.message_set_wire_format()); + } + if (from.has_no_standard_descriptor_accessor()) { + set_no_standard_descriptor_accessor(from.no_standard_descriptor_accessor()); + } + } + _extensions_.MergeFrom(from._extensions_); + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); +} + +void MessageOptions::CopyFrom(const ::google::protobuf::Message& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +void MessageOptions::CopyFrom(const MessageOptions& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool MessageOptions::IsInitialized() const { + + for (int i = 0; i < uninterpreted_option_size(); i++) { + if (!this->uninterpreted_option(i).IsInitialized()) return false; + } + + if (!_extensions_.IsInitialized()) return false; return true; +} + +void MessageOptions::Swap(MessageOptions* other) { + if (other != this) { + std::swap(message_set_wire_format_, other->message_set_wire_format_); + std::swap(no_standard_descriptor_accessor_, other->no_standard_descriptor_accessor_); + uninterpreted_option_.Swap(&other->uninterpreted_option_); + std::swap(_has_bits_[0], other->_has_bits_[0]); + _unknown_fields_.Swap(&other->_unknown_fields_); + std::swap(_cached_size_, other->_cached_size_); + _extensions_.Swap(&other->_extensions_); + } +} + +::google::protobuf::Metadata MessageOptions::GetMetadata() const { + protobuf_AssignDescriptorsOnce(); + ::google::protobuf::Metadata metadata; + metadata.descriptor = MessageOptions_descriptor_; + metadata.reflection = MessageOptions_reflection_; + return metadata; +} + + +// =================================================================== + +const ::google::protobuf::EnumDescriptor* FieldOptions_CType_descriptor() { + protobuf_AssignDescriptorsOnce(); + return FieldOptions_CType_descriptor_; +} +bool FieldOptions_CType_IsValid(int value) { + switch(value) { + case 0: + case 1: + case 2: + return true; + default: + return false; + } +} + +#ifndef _MSC_VER +const FieldOptions_CType FieldOptions::STRING; +const FieldOptions_CType FieldOptions::CORD; +const FieldOptions_CType FieldOptions::STRING_PIECE; +const FieldOptions_CType FieldOptions::CType_MIN; +const FieldOptions_CType FieldOptions::CType_MAX; +const int FieldOptions::CType_ARRAYSIZE; +#endif // _MSC_VER +#ifndef _MSC_VER +const int FieldOptions::kCtypeFieldNumber; +const int FieldOptions::kPackedFieldNumber; +const int FieldOptions::kDeprecatedFieldNumber; +const int FieldOptions::kExperimentalMapKeyFieldNumber; +const int FieldOptions::kUninterpretedOptionFieldNumber; +#endif // !_MSC_VER + +FieldOptions::FieldOptions() + : ::google::protobuf::Message() { + SharedCtor(); +} + +void FieldOptions::InitAsDefaultInstance() { +} + +FieldOptions::FieldOptions(const FieldOptions& from) + : ::google::protobuf::Message() { + SharedCtor(); + MergeFrom(from); +} + +void FieldOptions::SharedCtor() { + _cached_size_ = 0; + ctype_ = 0; + packed_ = false; + deprecated_ = false; + experimental_map_key_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + +FieldOptions::~FieldOptions() { + SharedDtor(); +} + +void FieldOptions::SharedDtor() { + if (experimental_map_key_ != &::google::protobuf::internal::kEmptyString) { + delete experimental_map_key_; + } + if (this != default_instance_) { + } +} + +void FieldOptions::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} +const ::google::protobuf::Descriptor* FieldOptions::descriptor() { + protobuf_AssignDescriptorsOnce(); + return FieldOptions_descriptor_; +} + +const FieldOptions& FieldOptions::default_instance() { + if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_; +} + +FieldOptions* FieldOptions::default_instance_ = NULL; + +FieldOptions* FieldOptions::New() const { + return new FieldOptions; +} + +void FieldOptions::Clear() { + _extensions_.Clear(); + if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + ctype_ = 0; + packed_ = false; + deprecated_ = false; + if (has_experimental_map_key()) { + if (experimental_map_key_ != &::google::protobuf::internal::kEmptyString) { + experimental_map_key_->clear(); + } + } + } + uninterpreted_option_.Clear(); + ::memset(_has_bits_, 0, sizeof(_has_bits_)); + mutable_unknown_fields()->Clear(); +} + +bool FieldOptions::MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input) { +#define DO_(EXPRESSION) if (!(EXPRESSION)) return false + ::google::protobuf::uint32 tag; + while ((tag = input->ReadTag()) != 0) { + switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { + // optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING]; + case 1: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + int value; + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>( + input, &value))); + if (::google::protobuf::FieldOptions_CType_IsValid(value)) { + set_ctype(static_cast< ::google::protobuf::FieldOptions_CType >(value)); + } else { + mutable_unknown_fields()->AddVarint(1, value); + } + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(16)) goto parse_packed; + break; + } + + // optional bool packed = 2; + case 2: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_packed: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( + input, &packed_))); + set_has_packed(); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(24)) goto parse_deprecated; + break; + } + + // optional bool deprecated = 3 [default = false]; + case 3: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_deprecated: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( + input, &deprecated_))); + set_has_deprecated(); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(74)) goto parse_experimental_map_key; + break; + } + + // optional string experimental_map_key = 9; + case 9: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_experimental_map_key: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_experimental_map_key())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->experimental_map_key().data(), this->experimental_map_key().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(7994)) goto parse_uninterpreted_option; + break; + } + + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; + case 999: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_uninterpreted_option: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_uninterpreted_option())); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(7994)) goto parse_uninterpreted_option; + if (input->ExpectAtEnd()) return true; + break; + } + + default: { + handle_uninterpreted: + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { + return true; + } + if ((8000u <= tag)) { + DO_(_extensions_.ParseField(tag, input, default_instance_, + mutable_unknown_fields())); + continue; + } + DO_(::google::protobuf::internal::WireFormat::SkipField( + input, tag, mutable_unknown_fields())); + break; + } + } + } + return true; +#undef DO_ +} + +void FieldOptions::SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const { + // optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING]; + if (has_ctype()) { + ::google::protobuf::internal::WireFormatLite::WriteEnum( + 1, this->ctype(), output); + } + + // optional bool packed = 2; + if (has_packed()) { + ::google::protobuf::internal::WireFormatLite::WriteBool(2, this->packed(), output); + } + + // optional bool deprecated = 3 [default = false]; + if (has_deprecated()) { + ::google::protobuf::internal::WireFormatLite::WriteBool(3, this->deprecated(), output); + } + + // optional string experimental_map_key = 9; + if (has_experimental_map_key()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->experimental_map_key().data(), this->experimental_map_key().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + ::google::protobuf::internal::WireFormatLite::WriteString( + 9, this->experimental_map_key(), output); + } + + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; + for (int i = 0; i < this->uninterpreted_option_size(); i++) { + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( + 999, this->uninterpreted_option(i), output); + } + + // Extension range [1000, 536870912) + _extensions_.SerializeWithCachedSizes( + 1000, 536870912, output); + + if (!unknown_fields().empty()) { + ::google::protobuf::internal::WireFormat::SerializeUnknownFields( + unknown_fields(), output); + } +} + +::google::protobuf::uint8* FieldOptions::SerializeWithCachedSizesToArray( + ::google::protobuf::uint8* target) const { + // optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING]; + if (has_ctype()) { + target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray( + 1, this->ctype(), target); + } + + // optional bool packed = 2; + if (has_packed()) { + target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(2, this->packed(), target); + } + + // optional bool deprecated = 3 [default = false]; + if (has_deprecated()) { + target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(3, this->deprecated(), target); + } + + // optional string experimental_map_key = 9; + if (has_experimental_map_key()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->experimental_map_key().data(), this->experimental_map_key().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + target = + ::google::protobuf::internal::WireFormatLite::WriteStringToArray( + 9, this->experimental_map_key(), target); + } + + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; + for (int i = 0; i < this->uninterpreted_option_size(); i++) { + target = ::google::protobuf::internal::WireFormatLite:: + WriteMessageNoVirtualToArray( + 999, this->uninterpreted_option(i), target); + } + + // Extension range [1000, 536870912) + target = _extensions_.SerializeWithCachedSizesToArray( + 1000, 536870912, target); + + if (!unknown_fields().empty()) { + target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( + unknown_fields(), target); + } + return target; +} + +int FieldOptions::ByteSize() const { + int total_size = 0; + + if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + // optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING]; + if (has_ctype()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::EnumSize(this->ctype()); + } + + // optional bool packed = 2; + if (has_packed()) { + total_size += 1 + 1; + } + + // optional bool deprecated = 3 [default = false]; + if (has_deprecated()) { + total_size += 1 + 1; + } + + // optional string experimental_map_key = 9; + if (has_experimental_map_key()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::StringSize( + this->experimental_map_key()); + } + + } + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; + total_size += 2 * this->uninterpreted_option_size(); + for (int i = 0; i < this->uninterpreted_option_size(); i++) { + total_size += + ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( + this->uninterpreted_option(i)); + } + + total_size += _extensions_.ByteSize(); + + if (!unknown_fields().empty()) { + total_size += + ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( + unknown_fields()); + } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); + return total_size; +} + +void FieldOptions::MergeFrom(const ::google::protobuf::Message& from) { + GOOGLE_CHECK_NE(&from, this); + const FieldOptions* source = + ::google::protobuf::internal::dynamic_cast_if_available( + &from); + if (source == NULL) { + ::google::protobuf::internal::ReflectionOps::Merge(from, this); + } else { + MergeFrom(*source); + } +} + +void FieldOptions::MergeFrom(const FieldOptions& from) { + GOOGLE_CHECK_NE(&from, this); + uninterpreted_option_.MergeFrom(from.uninterpreted_option_); + if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { + if (from.has_ctype()) { + set_ctype(from.ctype()); + } + if (from.has_packed()) { + set_packed(from.packed()); + } + if (from.has_deprecated()) { + set_deprecated(from.deprecated()); + } + if (from.has_experimental_map_key()) { + set_experimental_map_key(from.experimental_map_key()); + } + } + _extensions_.MergeFrom(from._extensions_); + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); +} + +void FieldOptions::CopyFrom(const ::google::protobuf::Message& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +void FieldOptions::CopyFrom(const FieldOptions& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool FieldOptions::IsInitialized() const { + + for (int i = 0; i < uninterpreted_option_size(); i++) { + if (!this->uninterpreted_option(i).IsInitialized()) return false; + } + + if (!_extensions_.IsInitialized()) return false; return true; +} + +void FieldOptions::Swap(FieldOptions* other) { + if (other != this) { + std::swap(ctype_, other->ctype_); + std::swap(packed_, other->packed_); + std::swap(deprecated_, other->deprecated_); + std::swap(experimental_map_key_, other->experimental_map_key_); + uninterpreted_option_.Swap(&other->uninterpreted_option_); + std::swap(_has_bits_[0], other->_has_bits_[0]); + _unknown_fields_.Swap(&other->_unknown_fields_); + std::swap(_cached_size_, other->_cached_size_); + _extensions_.Swap(&other->_extensions_); + } +} + +::google::protobuf::Metadata FieldOptions::GetMetadata() const { + protobuf_AssignDescriptorsOnce(); + ::google::protobuf::Metadata metadata; + metadata.descriptor = FieldOptions_descriptor_; + metadata.reflection = FieldOptions_reflection_; + return metadata; +} + + +// =================================================================== + +#ifndef _MSC_VER +const int EnumOptions::kUninterpretedOptionFieldNumber; +#endif // !_MSC_VER + +EnumOptions::EnumOptions() + : ::google::protobuf::Message() { + SharedCtor(); +} + +void EnumOptions::InitAsDefaultInstance() { +} + +EnumOptions::EnumOptions(const EnumOptions& from) + : ::google::protobuf::Message() { + SharedCtor(); + MergeFrom(from); +} + +void EnumOptions::SharedCtor() { + _cached_size_ = 0; + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + +EnumOptions::~EnumOptions() { + SharedDtor(); +} + +void EnumOptions::SharedDtor() { + if (this != default_instance_) { + } +} + +void EnumOptions::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} +const ::google::protobuf::Descriptor* EnumOptions::descriptor() { + protobuf_AssignDescriptorsOnce(); + return EnumOptions_descriptor_; +} + +const EnumOptions& EnumOptions::default_instance() { + if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_; +} + +EnumOptions* EnumOptions::default_instance_ = NULL; + +EnumOptions* EnumOptions::New() const { + return new EnumOptions; +} + +void EnumOptions::Clear() { + _extensions_.Clear(); + uninterpreted_option_.Clear(); + ::memset(_has_bits_, 0, sizeof(_has_bits_)); + mutable_unknown_fields()->Clear(); +} + +bool EnumOptions::MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input) { +#define DO_(EXPRESSION) if (!(EXPRESSION)) return false + ::google::protobuf::uint32 tag; + while ((tag = input->ReadTag()) != 0) { + switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; + case 999: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_uninterpreted_option: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_uninterpreted_option())); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(7994)) goto parse_uninterpreted_option; + if (input->ExpectAtEnd()) return true; + break; + } + + default: { + handle_uninterpreted: + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { + return true; + } + if ((8000u <= tag)) { + DO_(_extensions_.ParseField(tag, input, default_instance_, + mutable_unknown_fields())); + continue; + } + DO_(::google::protobuf::internal::WireFormat::SkipField( + input, tag, mutable_unknown_fields())); + break; + } + } + } + return true; +#undef DO_ +} + +void EnumOptions::SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const { + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; + for (int i = 0; i < this->uninterpreted_option_size(); i++) { + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( + 999, this->uninterpreted_option(i), output); + } + + // Extension range [1000, 536870912) + _extensions_.SerializeWithCachedSizes( + 1000, 536870912, output); + + if (!unknown_fields().empty()) { + ::google::protobuf::internal::WireFormat::SerializeUnknownFields( + unknown_fields(), output); + } +} + +::google::protobuf::uint8* EnumOptions::SerializeWithCachedSizesToArray( + ::google::protobuf::uint8* target) const { + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; + for (int i = 0; i < this->uninterpreted_option_size(); i++) { + target = ::google::protobuf::internal::WireFormatLite:: + WriteMessageNoVirtualToArray( + 999, this->uninterpreted_option(i), target); + } + + // Extension range [1000, 536870912) + target = _extensions_.SerializeWithCachedSizesToArray( + 1000, 536870912, target); + + if (!unknown_fields().empty()) { + target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( + unknown_fields(), target); + } + return target; +} + +int EnumOptions::ByteSize() const { + int total_size = 0; + + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; + total_size += 2 * this->uninterpreted_option_size(); + for (int i = 0; i < this->uninterpreted_option_size(); i++) { + total_size += + ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( + this->uninterpreted_option(i)); + } + + total_size += _extensions_.ByteSize(); + + if (!unknown_fields().empty()) { + total_size += + ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( + unknown_fields()); + } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); + return total_size; +} + +void EnumOptions::MergeFrom(const ::google::protobuf::Message& from) { + GOOGLE_CHECK_NE(&from, this); + const EnumOptions* source = + ::google::protobuf::internal::dynamic_cast_if_available( + &from); + if (source == NULL) { + ::google::protobuf::internal::ReflectionOps::Merge(from, this); + } else { + MergeFrom(*source); + } +} + +void EnumOptions::MergeFrom(const EnumOptions& from) { + GOOGLE_CHECK_NE(&from, this); + uninterpreted_option_.MergeFrom(from.uninterpreted_option_); + _extensions_.MergeFrom(from._extensions_); + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); +} + +void EnumOptions::CopyFrom(const ::google::protobuf::Message& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +void EnumOptions::CopyFrom(const EnumOptions& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool EnumOptions::IsInitialized() const { + + for (int i = 0; i < uninterpreted_option_size(); i++) { + if (!this->uninterpreted_option(i).IsInitialized()) return false; + } + + if (!_extensions_.IsInitialized()) return false; return true; +} + +void EnumOptions::Swap(EnumOptions* other) { + if (other != this) { + uninterpreted_option_.Swap(&other->uninterpreted_option_); + std::swap(_has_bits_[0], other->_has_bits_[0]); + _unknown_fields_.Swap(&other->_unknown_fields_); + std::swap(_cached_size_, other->_cached_size_); + _extensions_.Swap(&other->_extensions_); + } +} + +::google::protobuf::Metadata EnumOptions::GetMetadata() const { + protobuf_AssignDescriptorsOnce(); + ::google::protobuf::Metadata metadata; + metadata.descriptor = EnumOptions_descriptor_; + metadata.reflection = EnumOptions_reflection_; + return metadata; +} + + +// =================================================================== + +#ifndef _MSC_VER +const int EnumValueOptions::kUninterpretedOptionFieldNumber; +#endif // !_MSC_VER + +EnumValueOptions::EnumValueOptions() + : ::google::protobuf::Message() { + SharedCtor(); +} + +void EnumValueOptions::InitAsDefaultInstance() { +} + +EnumValueOptions::EnumValueOptions(const EnumValueOptions& from) + : ::google::protobuf::Message() { + SharedCtor(); + MergeFrom(from); +} + +void EnumValueOptions::SharedCtor() { + _cached_size_ = 0; + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + +EnumValueOptions::~EnumValueOptions() { + SharedDtor(); +} + +void EnumValueOptions::SharedDtor() { + if (this != default_instance_) { + } +} + +void EnumValueOptions::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} +const ::google::protobuf::Descriptor* EnumValueOptions::descriptor() { + protobuf_AssignDescriptorsOnce(); + return EnumValueOptions_descriptor_; +} + +const EnumValueOptions& EnumValueOptions::default_instance() { + if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_; +} + +EnumValueOptions* EnumValueOptions::default_instance_ = NULL; + +EnumValueOptions* EnumValueOptions::New() const { + return new EnumValueOptions; +} + +void EnumValueOptions::Clear() { + _extensions_.Clear(); + uninterpreted_option_.Clear(); + ::memset(_has_bits_, 0, sizeof(_has_bits_)); + mutable_unknown_fields()->Clear(); +} + +bool EnumValueOptions::MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input) { +#define DO_(EXPRESSION) if (!(EXPRESSION)) return false + ::google::protobuf::uint32 tag; + while ((tag = input->ReadTag()) != 0) { + switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; + case 999: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_uninterpreted_option: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_uninterpreted_option())); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(7994)) goto parse_uninterpreted_option; + if (input->ExpectAtEnd()) return true; + break; + } + + default: { + handle_uninterpreted: + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { + return true; + } + if ((8000u <= tag)) { + DO_(_extensions_.ParseField(tag, input, default_instance_, + mutable_unknown_fields())); + continue; + } + DO_(::google::protobuf::internal::WireFormat::SkipField( + input, tag, mutable_unknown_fields())); + break; + } + } + } + return true; +#undef DO_ +} + +void EnumValueOptions::SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const { + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; + for (int i = 0; i < this->uninterpreted_option_size(); i++) { + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( + 999, this->uninterpreted_option(i), output); + } + + // Extension range [1000, 536870912) + _extensions_.SerializeWithCachedSizes( + 1000, 536870912, output); + + if (!unknown_fields().empty()) { + ::google::protobuf::internal::WireFormat::SerializeUnknownFields( + unknown_fields(), output); + } +} + +::google::protobuf::uint8* EnumValueOptions::SerializeWithCachedSizesToArray( + ::google::protobuf::uint8* target) const { + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; + for (int i = 0; i < this->uninterpreted_option_size(); i++) { + target = ::google::protobuf::internal::WireFormatLite:: + WriteMessageNoVirtualToArray( + 999, this->uninterpreted_option(i), target); + } + + // Extension range [1000, 536870912) + target = _extensions_.SerializeWithCachedSizesToArray( + 1000, 536870912, target); + + if (!unknown_fields().empty()) { + target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( + unknown_fields(), target); + } + return target; +} + +int EnumValueOptions::ByteSize() const { + int total_size = 0; + + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; + total_size += 2 * this->uninterpreted_option_size(); + for (int i = 0; i < this->uninterpreted_option_size(); i++) { + total_size += + ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( + this->uninterpreted_option(i)); + } + + total_size += _extensions_.ByteSize(); + + if (!unknown_fields().empty()) { + total_size += + ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( + unknown_fields()); + } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); + return total_size; +} + +void EnumValueOptions::MergeFrom(const ::google::protobuf::Message& from) { + GOOGLE_CHECK_NE(&from, this); + const EnumValueOptions* source = + ::google::protobuf::internal::dynamic_cast_if_available( + &from); + if (source == NULL) { + ::google::protobuf::internal::ReflectionOps::Merge(from, this); + } else { + MergeFrom(*source); + } +} + +void EnumValueOptions::MergeFrom(const EnumValueOptions& from) { + GOOGLE_CHECK_NE(&from, this); + uninterpreted_option_.MergeFrom(from.uninterpreted_option_); + _extensions_.MergeFrom(from._extensions_); + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); +} + +void EnumValueOptions::CopyFrom(const ::google::protobuf::Message& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +void EnumValueOptions::CopyFrom(const EnumValueOptions& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool EnumValueOptions::IsInitialized() const { + + for (int i = 0; i < uninterpreted_option_size(); i++) { + if (!this->uninterpreted_option(i).IsInitialized()) return false; + } + + if (!_extensions_.IsInitialized()) return false; return true; +} + +void EnumValueOptions::Swap(EnumValueOptions* other) { + if (other != this) { + uninterpreted_option_.Swap(&other->uninterpreted_option_); + std::swap(_has_bits_[0], other->_has_bits_[0]); + _unknown_fields_.Swap(&other->_unknown_fields_); + std::swap(_cached_size_, other->_cached_size_); + _extensions_.Swap(&other->_extensions_); + } +} + +::google::protobuf::Metadata EnumValueOptions::GetMetadata() const { + protobuf_AssignDescriptorsOnce(); + ::google::protobuf::Metadata metadata; + metadata.descriptor = EnumValueOptions_descriptor_; + metadata.reflection = EnumValueOptions_reflection_; + return metadata; +} + + +// =================================================================== + +#ifndef _MSC_VER +const int ServiceOptions::kUninterpretedOptionFieldNumber; +#endif // !_MSC_VER + +ServiceOptions::ServiceOptions() + : ::google::protobuf::Message() { + SharedCtor(); +} + +void ServiceOptions::InitAsDefaultInstance() { +} + +ServiceOptions::ServiceOptions(const ServiceOptions& from) + : ::google::protobuf::Message() { + SharedCtor(); + MergeFrom(from); +} + +void ServiceOptions::SharedCtor() { + _cached_size_ = 0; + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + +ServiceOptions::~ServiceOptions() { + SharedDtor(); +} + +void ServiceOptions::SharedDtor() { + if (this != default_instance_) { + } +} + +void ServiceOptions::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} +const ::google::protobuf::Descriptor* ServiceOptions::descriptor() { + protobuf_AssignDescriptorsOnce(); + return ServiceOptions_descriptor_; +} + +const ServiceOptions& ServiceOptions::default_instance() { + if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_; +} + +ServiceOptions* ServiceOptions::default_instance_ = NULL; + +ServiceOptions* ServiceOptions::New() const { + return new ServiceOptions; +} + +void ServiceOptions::Clear() { + _extensions_.Clear(); + uninterpreted_option_.Clear(); + ::memset(_has_bits_, 0, sizeof(_has_bits_)); + mutable_unknown_fields()->Clear(); +} + +bool ServiceOptions::MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input) { +#define DO_(EXPRESSION) if (!(EXPRESSION)) return false + ::google::protobuf::uint32 tag; + while ((tag = input->ReadTag()) != 0) { + switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; + case 999: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_uninterpreted_option: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_uninterpreted_option())); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(7994)) goto parse_uninterpreted_option; + if (input->ExpectAtEnd()) return true; + break; + } + + default: { + handle_uninterpreted: + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { + return true; + } + if ((8000u <= tag)) { + DO_(_extensions_.ParseField(tag, input, default_instance_, + mutable_unknown_fields())); + continue; + } + DO_(::google::protobuf::internal::WireFormat::SkipField( + input, tag, mutable_unknown_fields())); + break; + } + } + } + return true; +#undef DO_ +} + +void ServiceOptions::SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const { + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; + for (int i = 0; i < this->uninterpreted_option_size(); i++) { + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( + 999, this->uninterpreted_option(i), output); + } + + // Extension range [1000, 536870912) + _extensions_.SerializeWithCachedSizes( + 1000, 536870912, output); + + if (!unknown_fields().empty()) { + ::google::protobuf::internal::WireFormat::SerializeUnknownFields( + unknown_fields(), output); + } +} + +::google::protobuf::uint8* ServiceOptions::SerializeWithCachedSizesToArray( + ::google::protobuf::uint8* target) const { + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; + for (int i = 0; i < this->uninterpreted_option_size(); i++) { + target = ::google::protobuf::internal::WireFormatLite:: + WriteMessageNoVirtualToArray( + 999, this->uninterpreted_option(i), target); + } + + // Extension range [1000, 536870912) + target = _extensions_.SerializeWithCachedSizesToArray( + 1000, 536870912, target); + + if (!unknown_fields().empty()) { + target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( + unknown_fields(), target); + } + return target; +} + +int ServiceOptions::ByteSize() const { + int total_size = 0; + + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; + total_size += 2 * this->uninterpreted_option_size(); + for (int i = 0; i < this->uninterpreted_option_size(); i++) { + total_size += + ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( + this->uninterpreted_option(i)); + } + + total_size += _extensions_.ByteSize(); + + if (!unknown_fields().empty()) { + total_size += + ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( + unknown_fields()); + } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); + return total_size; +} + +void ServiceOptions::MergeFrom(const ::google::protobuf::Message& from) { + GOOGLE_CHECK_NE(&from, this); + const ServiceOptions* source = + ::google::protobuf::internal::dynamic_cast_if_available( + &from); + if (source == NULL) { + ::google::protobuf::internal::ReflectionOps::Merge(from, this); + } else { + MergeFrom(*source); + } +} + +void ServiceOptions::MergeFrom(const ServiceOptions& from) { + GOOGLE_CHECK_NE(&from, this); + uninterpreted_option_.MergeFrom(from.uninterpreted_option_); + _extensions_.MergeFrom(from._extensions_); + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); +} + +void ServiceOptions::CopyFrom(const ::google::protobuf::Message& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +void ServiceOptions::CopyFrom(const ServiceOptions& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool ServiceOptions::IsInitialized() const { + + for (int i = 0; i < uninterpreted_option_size(); i++) { + if (!this->uninterpreted_option(i).IsInitialized()) return false; + } + + if (!_extensions_.IsInitialized()) return false; return true; +} + +void ServiceOptions::Swap(ServiceOptions* other) { + if (other != this) { + uninterpreted_option_.Swap(&other->uninterpreted_option_); + std::swap(_has_bits_[0], other->_has_bits_[0]); + _unknown_fields_.Swap(&other->_unknown_fields_); + std::swap(_cached_size_, other->_cached_size_); + _extensions_.Swap(&other->_extensions_); + } +} + +::google::protobuf::Metadata ServiceOptions::GetMetadata() const { + protobuf_AssignDescriptorsOnce(); + ::google::protobuf::Metadata metadata; + metadata.descriptor = ServiceOptions_descriptor_; + metadata.reflection = ServiceOptions_reflection_; + return metadata; +} + + +// =================================================================== + +#ifndef _MSC_VER +const int MethodOptions::kUninterpretedOptionFieldNumber; +#endif // !_MSC_VER + +MethodOptions::MethodOptions() + : ::google::protobuf::Message() { + SharedCtor(); +} + +void MethodOptions::InitAsDefaultInstance() { +} + +MethodOptions::MethodOptions(const MethodOptions& from) + : ::google::protobuf::Message() { + SharedCtor(); + MergeFrom(from); +} + +void MethodOptions::SharedCtor() { + _cached_size_ = 0; + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + +MethodOptions::~MethodOptions() { + SharedDtor(); +} + +void MethodOptions::SharedDtor() { + if (this != default_instance_) { + } +} + +void MethodOptions::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} +const ::google::protobuf::Descriptor* MethodOptions::descriptor() { + protobuf_AssignDescriptorsOnce(); + return MethodOptions_descriptor_; +} + +const MethodOptions& MethodOptions::default_instance() { + if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_; +} + +MethodOptions* MethodOptions::default_instance_ = NULL; + +MethodOptions* MethodOptions::New() const { + return new MethodOptions; +} + +void MethodOptions::Clear() { + _extensions_.Clear(); + uninterpreted_option_.Clear(); + ::memset(_has_bits_, 0, sizeof(_has_bits_)); + mutable_unknown_fields()->Clear(); +} + +bool MethodOptions::MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input) { +#define DO_(EXPRESSION) if (!(EXPRESSION)) return false + ::google::protobuf::uint32 tag; + while ((tag = input->ReadTag()) != 0) { + switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; + case 999: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_uninterpreted_option: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_uninterpreted_option())); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(7994)) goto parse_uninterpreted_option; + if (input->ExpectAtEnd()) return true; + break; + } + + default: { + handle_uninterpreted: + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { + return true; + } + if ((8000u <= tag)) { + DO_(_extensions_.ParseField(tag, input, default_instance_, + mutable_unknown_fields())); + continue; + } + DO_(::google::protobuf::internal::WireFormat::SkipField( + input, tag, mutable_unknown_fields())); + break; + } + } + } + return true; +#undef DO_ +} + +void MethodOptions::SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const { + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; + for (int i = 0; i < this->uninterpreted_option_size(); i++) { + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( + 999, this->uninterpreted_option(i), output); + } + + // Extension range [1000, 536870912) + _extensions_.SerializeWithCachedSizes( + 1000, 536870912, output); + + if (!unknown_fields().empty()) { + ::google::protobuf::internal::WireFormat::SerializeUnknownFields( + unknown_fields(), output); + } +} + +::google::protobuf::uint8* MethodOptions::SerializeWithCachedSizesToArray( + ::google::protobuf::uint8* target) const { + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; + for (int i = 0; i < this->uninterpreted_option_size(); i++) { + target = ::google::protobuf::internal::WireFormatLite:: + WriteMessageNoVirtualToArray( + 999, this->uninterpreted_option(i), target); + } + + // Extension range [1000, 536870912) + target = _extensions_.SerializeWithCachedSizesToArray( + 1000, 536870912, target); + + if (!unknown_fields().empty()) { + target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( + unknown_fields(), target); + } + return target; +} + +int MethodOptions::ByteSize() const { + int total_size = 0; + + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; + total_size += 2 * this->uninterpreted_option_size(); + for (int i = 0; i < this->uninterpreted_option_size(); i++) { + total_size += + ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( + this->uninterpreted_option(i)); + } + + total_size += _extensions_.ByteSize(); + + if (!unknown_fields().empty()) { + total_size += + ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( + unknown_fields()); + } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); + return total_size; +} + +void MethodOptions::MergeFrom(const ::google::protobuf::Message& from) { + GOOGLE_CHECK_NE(&from, this); + const MethodOptions* source = + ::google::protobuf::internal::dynamic_cast_if_available( + &from); + if (source == NULL) { + ::google::protobuf::internal::ReflectionOps::Merge(from, this); + } else { + MergeFrom(*source); + } +} + +void MethodOptions::MergeFrom(const MethodOptions& from) { + GOOGLE_CHECK_NE(&from, this); + uninterpreted_option_.MergeFrom(from.uninterpreted_option_); + _extensions_.MergeFrom(from._extensions_); + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); +} + +void MethodOptions::CopyFrom(const ::google::protobuf::Message& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +void MethodOptions::CopyFrom(const MethodOptions& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool MethodOptions::IsInitialized() const { + + for (int i = 0; i < uninterpreted_option_size(); i++) { + if (!this->uninterpreted_option(i).IsInitialized()) return false; + } + + if (!_extensions_.IsInitialized()) return false; return true; +} + +void MethodOptions::Swap(MethodOptions* other) { + if (other != this) { + uninterpreted_option_.Swap(&other->uninterpreted_option_); + std::swap(_has_bits_[0], other->_has_bits_[0]); + _unknown_fields_.Swap(&other->_unknown_fields_); + std::swap(_cached_size_, other->_cached_size_); + _extensions_.Swap(&other->_extensions_); + } +} + +::google::protobuf::Metadata MethodOptions::GetMetadata() const { + protobuf_AssignDescriptorsOnce(); + ::google::protobuf::Metadata metadata; + metadata.descriptor = MethodOptions_descriptor_; + metadata.reflection = MethodOptions_reflection_; + return metadata; +} + + +// =================================================================== + +#ifndef _MSC_VER +const int UninterpretedOption_NamePart::kNamePartFieldNumber; +const int UninterpretedOption_NamePart::kIsExtensionFieldNumber; +#endif // !_MSC_VER + +UninterpretedOption_NamePart::UninterpretedOption_NamePart() + : ::google::protobuf::Message() { + SharedCtor(); +} + +void UninterpretedOption_NamePart::InitAsDefaultInstance() { +} + +UninterpretedOption_NamePart::UninterpretedOption_NamePart(const UninterpretedOption_NamePart& from) + : ::google::protobuf::Message() { + SharedCtor(); + MergeFrom(from); +} + +void UninterpretedOption_NamePart::SharedCtor() { + _cached_size_ = 0; + name_part_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + is_extension_ = false; + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + +UninterpretedOption_NamePart::~UninterpretedOption_NamePart() { + SharedDtor(); +} + +void UninterpretedOption_NamePart::SharedDtor() { + if (name_part_ != &::google::protobuf::internal::kEmptyString) { + delete name_part_; + } + if (this != default_instance_) { + } +} + +void UninterpretedOption_NamePart::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} +const ::google::protobuf::Descriptor* UninterpretedOption_NamePart::descriptor() { + protobuf_AssignDescriptorsOnce(); + return UninterpretedOption_NamePart_descriptor_; +} + +const UninterpretedOption_NamePart& UninterpretedOption_NamePart::default_instance() { + if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_; +} + +UninterpretedOption_NamePart* UninterpretedOption_NamePart::default_instance_ = NULL; + +UninterpretedOption_NamePart* UninterpretedOption_NamePart::New() const { + return new UninterpretedOption_NamePart; +} + +void UninterpretedOption_NamePart::Clear() { + if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + if (has_name_part()) { + if (name_part_ != &::google::protobuf::internal::kEmptyString) { + name_part_->clear(); + } + } + is_extension_ = false; + } + ::memset(_has_bits_, 0, sizeof(_has_bits_)); + mutable_unknown_fields()->Clear(); +} + +bool UninterpretedOption_NamePart::MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input) { +#define DO_(EXPRESSION) if (!(EXPRESSION)) return false + ::google::protobuf::uint32 tag; + while ((tag = input->ReadTag()) != 0) { + switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { + // required string name_part = 1; + case 1: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_name_part())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name_part().data(), this->name_part().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(16)) goto parse_is_extension; + break; + } + + // required bool is_extension = 2; + case 2: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_is_extension: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( + input, &is_extension_))); + set_has_is_extension(); + } else { + goto handle_uninterpreted; + } + if (input->ExpectAtEnd()) return true; + break; + } + + default: { + handle_uninterpreted: + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { + return true; + } + DO_(::google::protobuf::internal::WireFormat::SkipField( + input, tag, mutable_unknown_fields())); + break; + } + } + } + return true; +#undef DO_ +} + +void UninterpretedOption_NamePart::SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const { + // required string name_part = 1; + if (has_name_part()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name_part().data(), this->name_part().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + ::google::protobuf::internal::WireFormatLite::WriteString( + 1, this->name_part(), output); + } + + // required bool is_extension = 2; + if (has_is_extension()) { + ::google::protobuf::internal::WireFormatLite::WriteBool(2, this->is_extension(), output); + } + + if (!unknown_fields().empty()) { + ::google::protobuf::internal::WireFormat::SerializeUnknownFields( + unknown_fields(), output); + } +} + +::google::protobuf::uint8* UninterpretedOption_NamePart::SerializeWithCachedSizesToArray( + ::google::protobuf::uint8* target) const { + // required string name_part = 1; + if (has_name_part()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name_part().data(), this->name_part().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + target = + ::google::protobuf::internal::WireFormatLite::WriteStringToArray( + 1, this->name_part(), target); + } + + // required bool is_extension = 2; + if (has_is_extension()) { + target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(2, this->is_extension(), target); + } + + if (!unknown_fields().empty()) { + target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( + unknown_fields(), target); + } + return target; +} + +int UninterpretedOption_NamePart::ByteSize() const { + int total_size = 0; + + if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + // required string name_part = 1; + if (has_name_part()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::StringSize( + this->name_part()); + } + + // required bool is_extension = 2; + if (has_is_extension()) { + total_size += 1 + 1; + } + + } + if (!unknown_fields().empty()) { + total_size += + ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( + unknown_fields()); + } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); + return total_size; +} + +void UninterpretedOption_NamePart::MergeFrom(const ::google::protobuf::Message& from) { + GOOGLE_CHECK_NE(&from, this); + const UninterpretedOption_NamePart* source = + ::google::protobuf::internal::dynamic_cast_if_available( + &from); + if (source == NULL) { + ::google::protobuf::internal::ReflectionOps::Merge(from, this); + } else { + MergeFrom(*source); + } +} + +void UninterpretedOption_NamePart::MergeFrom(const UninterpretedOption_NamePart& from) { + GOOGLE_CHECK_NE(&from, this); + if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { + if (from.has_name_part()) { + set_name_part(from.name_part()); + } + if (from.has_is_extension()) { + set_is_extension(from.is_extension()); + } + } + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); +} + +void UninterpretedOption_NamePart::CopyFrom(const ::google::protobuf::Message& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +void UninterpretedOption_NamePart::CopyFrom(const UninterpretedOption_NamePart& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool UninterpretedOption_NamePart::IsInitialized() const { + if ((_has_bits_[0] & 0x00000003) != 0x00000003) return false; + + return true; +} + +void UninterpretedOption_NamePart::Swap(UninterpretedOption_NamePart* other) { + if (other != this) { + std::swap(name_part_, other->name_part_); + std::swap(is_extension_, other->is_extension_); + std::swap(_has_bits_[0], other->_has_bits_[0]); + _unknown_fields_.Swap(&other->_unknown_fields_); + std::swap(_cached_size_, other->_cached_size_); + } +} + +::google::protobuf::Metadata UninterpretedOption_NamePart::GetMetadata() const { + protobuf_AssignDescriptorsOnce(); + ::google::protobuf::Metadata metadata; + metadata.descriptor = UninterpretedOption_NamePart_descriptor_; + metadata.reflection = UninterpretedOption_NamePart_reflection_; + return metadata; +} + + +// ------------------------------------------------------------------- + +#ifndef _MSC_VER +const int UninterpretedOption::kNameFieldNumber; +const int UninterpretedOption::kIdentifierValueFieldNumber; +const int UninterpretedOption::kPositiveIntValueFieldNumber; +const int UninterpretedOption::kNegativeIntValueFieldNumber; +const int UninterpretedOption::kDoubleValueFieldNumber; +const int UninterpretedOption::kStringValueFieldNumber; +const int UninterpretedOption::kAggregateValueFieldNumber; +#endif // !_MSC_VER + +UninterpretedOption::UninterpretedOption() + : ::google::protobuf::Message() { + SharedCtor(); +} + +void UninterpretedOption::InitAsDefaultInstance() { +} + +UninterpretedOption::UninterpretedOption(const UninterpretedOption& from) + : ::google::protobuf::Message() { + SharedCtor(); + MergeFrom(from); +} + +void UninterpretedOption::SharedCtor() { + _cached_size_ = 0; + identifier_value_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + positive_int_value_ = GOOGLE_ULONGLONG(0); + negative_int_value_ = GOOGLE_LONGLONG(0); + double_value_ = 0; + string_value_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + aggregate_value_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + +UninterpretedOption::~UninterpretedOption() { + SharedDtor(); +} + +void UninterpretedOption::SharedDtor() { + if (identifier_value_ != &::google::protobuf::internal::kEmptyString) { + delete identifier_value_; + } + if (string_value_ != &::google::protobuf::internal::kEmptyString) { + delete string_value_; + } + if (aggregate_value_ != &::google::protobuf::internal::kEmptyString) { + delete aggregate_value_; + } + if (this != default_instance_) { + } +} + +void UninterpretedOption::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} +const ::google::protobuf::Descriptor* UninterpretedOption::descriptor() { + protobuf_AssignDescriptorsOnce(); + return UninterpretedOption_descriptor_; +} + +const UninterpretedOption& UninterpretedOption::default_instance() { + if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_; +} + +UninterpretedOption* UninterpretedOption::default_instance_ = NULL; + +UninterpretedOption* UninterpretedOption::New() const { + return new UninterpretedOption; +} + +void UninterpretedOption::Clear() { + if (_has_bits_[1 / 32] & (0xffu << (1 % 32))) { + if (has_identifier_value()) { + if (identifier_value_ != &::google::protobuf::internal::kEmptyString) { + identifier_value_->clear(); + } + } + positive_int_value_ = GOOGLE_ULONGLONG(0); + negative_int_value_ = GOOGLE_LONGLONG(0); + double_value_ = 0; + if (has_string_value()) { + if (string_value_ != &::google::protobuf::internal::kEmptyString) { + string_value_->clear(); + } + } + if (has_aggregate_value()) { + if (aggregate_value_ != &::google::protobuf::internal::kEmptyString) { + aggregate_value_->clear(); + } + } + } + name_.Clear(); + ::memset(_has_bits_, 0, sizeof(_has_bits_)); + mutable_unknown_fields()->Clear(); +} + +bool UninterpretedOption::MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input) { +#define DO_(EXPRESSION) if (!(EXPRESSION)) return false + ::google::protobuf::uint32 tag; + while ((tag = input->ReadTag()) != 0) { + switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { + // repeated .google.protobuf.UninterpretedOption.NamePart name = 2; + case 2: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_name: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_name())); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(18)) goto parse_name; + if (input->ExpectTag(26)) goto parse_identifier_value; + break; + } + + // optional string identifier_value = 3; + case 3: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_identifier_value: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_identifier_value())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->identifier_value().data(), this->identifier_value().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(32)) goto parse_positive_int_value; + break; + } + + // optional uint64 positive_int_value = 4; + case 4: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_positive_int_value: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>( + input, &positive_int_value_))); + set_has_positive_int_value(); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(40)) goto parse_negative_int_value; + break; + } + + // optional int64 negative_int_value = 5; + case 5: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_negative_int_value: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + ::google::protobuf::int64, ::google::protobuf::internal::WireFormatLite::TYPE_INT64>( + input, &negative_int_value_))); + set_has_negative_int_value(); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(49)) goto parse_double_value; + break; + } + + // optional double double_value = 6; + case 6: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_FIXED64) { + parse_double_value: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + double, ::google::protobuf::internal::WireFormatLite::TYPE_DOUBLE>( + input, &double_value_))); + set_has_double_value(); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(58)) goto parse_string_value; + break; + } + + // optional bytes string_value = 7; + case 7: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_string_value: + DO_(::google::protobuf::internal::WireFormatLite::ReadBytes( + input, this->mutable_string_value())); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(66)) goto parse_aggregate_value; + break; + } + + // optional string aggregate_value = 8; + case 8: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_aggregate_value: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_aggregate_value())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->aggregate_value().data(), this->aggregate_value().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { + goto handle_uninterpreted; + } + if (input->ExpectAtEnd()) return true; + break; + } + + default: { + handle_uninterpreted: + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { + return true; + } + DO_(::google::protobuf::internal::WireFormat::SkipField( + input, tag, mutable_unknown_fields())); + break; + } + } + } + return true; +#undef DO_ +} + +void UninterpretedOption::SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const { + // repeated .google.protobuf.UninterpretedOption.NamePart name = 2; + for (int i = 0; i < this->name_size(); i++) { + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( + 2, this->name(i), output); + } + + // optional string identifier_value = 3; + if (has_identifier_value()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->identifier_value().data(), this->identifier_value().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + ::google::protobuf::internal::WireFormatLite::WriteString( + 3, this->identifier_value(), output); + } + + // optional uint64 positive_int_value = 4; + if (has_positive_int_value()) { + ::google::protobuf::internal::WireFormatLite::WriteUInt64(4, this->positive_int_value(), output); + } + + // optional int64 negative_int_value = 5; + if (has_negative_int_value()) { + ::google::protobuf::internal::WireFormatLite::WriteInt64(5, this->negative_int_value(), output); + } + + // optional double double_value = 6; + if (has_double_value()) { + ::google::protobuf::internal::WireFormatLite::WriteDouble(6, this->double_value(), output); + } + + // optional bytes string_value = 7; + if (has_string_value()) { + ::google::protobuf::internal::WireFormatLite::WriteBytes( + 7, this->string_value(), output); + } + + // optional string aggregate_value = 8; + if (has_aggregate_value()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->aggregate_value().data(), this->aggregate_value().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + ::google::protobuf::internal::WireFormatLite::WriteString( + 8, this->aggregate_value(), output); + } + + if (!unknown_fields().empty()) { + ::google::protobuf::internal::WireFormat::SerializeUnknownFields( + unknown_fields(), output); + } +} + +::google::protobuf::uint8* UninterpretedOption::SerializeWithCachedSizesToArray( + ::google::protobuf::uint8* target) const { + // repeated .google.protobuf.UninterpretedOption.NamePart name = 2; + for (int i = 0; i < this->name_size(); i++) { + target = ::google::protobuf::internal::WireFormatLite:: + WriteMessageNoVirtualToArray( + 2, this->name(i), target); + } + + // optional string identifier_value = 3; + if (has_identifier_value()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->identifier_value().data(), this->identifier_value().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + target = + ::google::protobuf::internal::WireFormatLite::WriteStringToArray( + 3, this->identifier_value(), target); + } + + // optional uint64 positive_int_value = 4; + if (has_positive_int_value()) { + target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(4, this->positive_int_value(), target); + } + + // optional int64 negative_int_value = 5; + if (has_negative_int_value()) { + target = ::google::protobuf::internal::WireFormatLite::WriteInt64ToArray(5, this->negative_int_value(), target); + } + + // optional double double_value = 6; + if (has_double_value()) { + target = ::google::protobuf::internal::WireFormatLite::WriteDoubleToArray(6, this->double_value(), target); + } + + // optional bytes string_value = 7; + if (has_string_value()) { + target = + ::google::protobuf::internal::WireFormatLite::WriteBytesToArray( + 7, this->string_value(), target); + } + + // optional string aggregate_value = 8; + if (has_aggregate_value()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->aggregate_value().data(), this->aggregate_value().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + target = + ::google::protobuf::internal::WireFormatLite::WriteStringToArray( + 8, this->aggregate_value(), target); + } + + if (!unknown_fields().empty()) { + target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( + unknown_fields(), target); + } + return target; +} + +int UninterpretedOption::ByteSize() const { + int total_size = 0; + + if (_has_bits_[1 / 32] & (0xffu << (1 % 32))) { + // optional string identifier_value = 3; + if (has_identifier_value()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::StringSize( + this->identifier_value()); + } + + // optional uint64 positive_int_value = 4; + if (has_positive_int_value()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::UInt64Size( + this->positive_int_value()); + } + + // optional int64 negative_int_value = 5; + if (has_negative_int_value()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::Int64Size( + this->negative_int_value()); + } + + // optional double double_value = 6; + if (has_double_value()) { + total_size += 1 + 8; + } + + // optional bytes string_value = 7; + if (has_string_value()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::BytesSize( + this->string_value()); + } + + // optional string aggregate_value = 8; + if (has_aggregate_value()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::StringSize( + this->aggregate_value()); + } + + } + // repeated .google.protobuf.UninterpretedOption.NamePart name = 2; + total_size += 1 * this->name_size(); + for (int i = 0; i < this->name_size(); i++) { + total_size += + ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( + this->name(i)); + } + + if (!unknown_fields().empty()) { + total_size += + ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( + unknown_fields()); + } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); + return total_size; +} + +void UninterpretedOption::MergeFrom(const ::google::protobuf::Message& from) { + GOOGLE_CHECK_NE(&from, this); + const UninterpretedOption* source = + ::google::protobuf::internal::dynamic_cast_if_available( + &from); + if (source == NULL) { + ::google::protobuf::internal::ReflectionOps::Merge(from, this); + } else { + MergeFrom(*source); + } +} + +void UninterpretedOption::MergeFrom(const UninterpretedOption& from) { + GOOGLE_CHECK_NE(&from, this); + name_.MergeFrom(from.name_); + if (from._has_bits_[1 / 32] & (0xffu << (1 % 32))) { + if (from.has_identifier_value()) { + set_identifier_value(from.identifier_value()); + } + if (from.has_positive_int_value()) { + set_positive_int_value(from.positive_int_value()); + } + if (from.has_negative_int_value()) { + set_negative_int_value(from.negative_int_value()); + } + if (from.has_double_value()) { + set_double_value(from.double_value()); + } + if (from.has_string_value()) { + set_string_value(from.string_value()); + } + if (from.has_aggregate_value()) { + set_aggregate_value(from.aggregate_value()); + } + } + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); +} + +void UninterpretedOption::CopyFrom(const ::google::protobuf::Message& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +void UninterpretedOption::CopyFrom(const UninterpretedOption& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool UninterpretedOption::IsInitialized() const { + + for (int i = 0; i < name_size(); i++) { + if (!this->name(i).IsInitialized()) return false; + } + return true; +} + +void UninterpretedOption::Swap(UninterpretedOption* other) { + if (other != this) { + name_.Swap(&other->name_); + std::swap(identifier_value_, other->identifier_value_); + std::swap(positive_int_value_, other->positive_int_value_); + std::swap(negative_int_value_, other->negative_int_value_); + std::swap(double_value_, other->double_value_); + std::swap(string_value_, other->string_value_); + std::swap(aggregate_value_, other->aggregate_value_); + std::swap(_has_bits_[0], other->_has_bits_[0]); + _unknown_fields_.Swap(&other->_unknown_fields_); + std::swap(_cached_size_, other->_cached_size_); + } +} + +::google::protobuf::Metadata UninterpretedOption::GetMetadata() const { + protobuf_AssignDescriptorsOnce(); + ::google::protobuf::Metadata metadata; + metadata.descriptor = UninterpretedOption_descriptor_; + metadata.reflection = UninterpretedOption_reflection_; + return metadata; +} + + +// =================================================================== + +#ifndef _MSC_VER +const int SourceCodeInfo_Location::kPathFieldNumber; +const int SourceCodeInfo_Location::kSpanFieldNumber; +#endif // !_MSC_VER + +SourceCodeInfo_Location::SourceCodeInfo_Location() + : ::google::protobuf::Message() { + SharedCtor(); +} + +void SourceCodeInfo_Location::InitAsDefaultInstance() { +} + +SourceCodeInfo_Location::SourceCodeInfo_Location(const SourceCodeInfo_Location& from) + : ::google::protobuf::Message() { + SharedCtor(); + MergeFrom(from); +} + +void SourceCodeInfo_Location::SharedCtor() { + _cached_size_ = 0; + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + +SourceCodeInfo_Location::~SourceCodeInfo_Location() { + SharedDtor(); +} + +void SourceCodeInfo_Location::SharedDtor() { + if (this != default_instance_) { + } +} + +void SourceCodeInfo_Location::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} +const ::google::protobuf::Descriptor* SourceCodeInfo_Location::descriptor() { + protobuf_AssignDescriptorsOnce(); + return SourceCodeInfo_Location_descriptor_; +} + +const SourceCodeInfo_Location& SourceCodeInfo_Location::default_instance() { + if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_; +} + +SourceCodeInfo_Location* SourceCodeInfo_Location::default_instance_ = NULL; + +SourceCodeInfo_Location* SourceCodeInfo_Location::New() const { + return new SourceCodeInfo_Location; +} + +void SourceCodeInfo_Location::Clear() { + path_.Clear(); + span_.Clear(); + ::memset(_has_bits_, 0, sizeof(_has_bits_)); + mutable_unknown_fields()->Clear(); +} + +bool SourceCodeInfo_Location::MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input) { +#define DO_(EXPRESSION) if (!(EXPRESSION)) return false + ::google::protobuf::uint32 tag; + while ((tag = input->ReadTag()) != 0) { + switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { + // repeated int32 path = 1 [packed = true]; + case 1: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitive< + ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( + input, this->mutable_path()))); + } else if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) + == ::google::protobuf::internal::WireFormatLite:: + WIRETYPE_VARINT) { + DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitiveNoInline< + ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( + 1, 10, input, this->mutable_path()))); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(18)) goto parse_span; + break; + } + + // repeated int32 span = 2 [packed = true]; + case 2: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_span: + DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitive< + ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( + input, this->mutable_span()))); + } else if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) + == ::google::protobuf::internal::WireFormatLite:: + WIRETYPE_VARINT) { + DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitiveNoInline< + ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( + 1, 18, input, this->mutable_span()))); + } else { + goto handle_uninterpreted; + } + if (input->ExpectAtEnd()) return true; + break; + } + + default: { + handle_uninterpreted: + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { + return true; + } + DO_(::google::protobuf::internal::WireFormat::SkipField( + input, tag, mutable_unknown_fields())); + break; + } + } + } + return true; +#undef DO_ +} + +void SourceCodeInfo_Location::SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const { + // repeated int32 path = 1 [packed = true]; + if (this->path_size() > 0) { + ::google::protobuf::internal::WireFormatLite::WriteTag(1, ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output); + output->WriteVarint32(_path_cached_byte_size_); + } + for (int i = 0; i < this->path_size(); i++) { + ::google::protobuf::internal::WireFormatLite::WriteInt32NoTag( + this->path(i), output); + } + + // repeated int32 span = 2 [packed = true]; + if (this->span_size() > 0) { + ::google::protobuf::internal::WireFormatLite::WriteTag(2, ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output); + output->WriteVarint32(_span_cached_byte_size_); + } + for (int i = 0; i < this->span_size(); i++) { + ::google::protobuf::internal::WireFormatLite::WriteInt32NoTag( + this->span(i), output); + } + + if (!unknown_fields().empty()) { + ::google::protobuf::internal::WireFormat::SerializeUnknownFields( + unknown_fields(), output); + } +} + +::google::protobuf::uint8* SourceCodeInfo_Location::SerializeWithCachedSizesToArray( + ::google::protobuf::uint8* target) const { + // repeated int32 path = 1 [packed = true]; + if (this->path_size() > 0) { + target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray( + 1, + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, + target); + target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray( + _path_cached_byte_size_, target); + } + for (int i = 0; i < this->path_size(); i++) { + target = ::google::protobuf::internal::WireFormatLite:: + WriteInt32NoTagToArray(this->path(i), target); + } + + // repeated int32 span = 2 [packed = true]; + if (this->span_size() > 0) { + target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray( + 2, + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, + target); + target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray( + _span_cached_byte_size_, target); + } + for (int i = 0; i < this->span_size(); i++) { + target = ::google::protobuf::internal::WireFormatLite:: + WriteInt32NoTagToArray(this->span(i), target); + } + + if (!unknown_fields().empty()) { + target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( + unknown_fields(), target); + } + return target; +} + +int SourceCodeInfo_Location::ByteSize() const { + int total_size = 0; + + // repeated int32 path = 1 [packed = true]; + { + int data_size = 0; + for (int i = 0; i < this->path_size(); i++) { + data_size += ::google::protobuf::internal::WireFormatLite:: + Int32Size(this->path(i)); + } + if (data_size > 0) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::Int32Size(data_size); + } + _path_cached_byte_size_ = data_size; + total_size += data_size; + } + + // repeated int32 span = 2 [packed = true]; + { + int data_size = 0; + for (int i = 0; i < this->span_size(); i++) { + data_size += ::google::protobuf::internal::WireFormatLite:: + Int32Size(this->span(i)); + } + if (data_size > 0) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::Int32Size(data_size); + } + _span_cached_byte_size_ = data_size; + total_size += data_size; + } + + if (!unknown_fields().empty()) { + total_size += + ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( + unknown_fields()); + } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); + return total_size; +} + +void SourceCodeInfo_Location::MergeFrom(const ::google::protobuf::Message& from) { + GOOGLE_CHECK_NE(&from, this); + const SourceCodeInfo_Location* source = + ::google::protobuf::internal::dynamic_cast_if_available( + &from); + if (source == NULL) { + ::google::protobuf::internal::ReflectionOps::Merge(from, this); + } else { + MergeFrom(*source); + } +} + +void SourceCodeInfo_Location::MergeFrom(const SourceCodeInfo_Location& from) { + GOOGLE_CHECK_NE(&from, this); + path_.MergeFrom(from.path_); + span_.MergeFrom(from.span_); + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); +} + +void SourceCodeInfo_Location::CopyFrom(const ::google::protobuf::Message& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +void SourceCodeInfo_Location::CopyFrom(const SourceCodeInfo_Location& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool SourceCodeInfo_Location::IsInitialized() const { + + return true; +} + +void SourceCodeInfo_Location::Swap(SourceCodeInfo_Location* other) { + if (other != this) { + path_.Swap(&other->path_); + span_.Swap(&other->span_); + std::swap(_has_bits_[0], other->_has_bits_[0]); + _unknown_fields_.Swap(&other->_unknown_fields_); + std::swap(_cached_size_, other->_cached_size_); + } +} + +::google::protobuf::Metadata SourceCodeInfo_Location::GetMetadata() const { + protobuf_AssignDescriptorsOnce(); + ::google::protobuf::Metadata metadata; + metadata.descriptor = SourceCodeInfo_Location_descriptor_; + metadata.reflection = SourceCodeInfo_Location_reflection_; + return metadata; +} + + +// ------------------------------------------------------------------- + +#ifndef _MSC_VER +const int SourceCodeInfo::kLocationFieldNumber; +#endif // !_MSC_VER + +SourceCodeInfo::SourceCodeInfo() + : ::google::protobuf::Message() { + SharedCtor(); +} + +void SourceCodeInfo::InitAsDefaultInstance() { +} + +SourceCodeInfo::SourceCodeInfo(const SourceCodeInfo& from) + : ::google::protobuf::Message() { + SharedCtor(); + MergeFrom(from); +} + +void SourceCodeInfo::SharedCtor() { + _cached_size_ = 0; + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + +SourceCodeInfo::~SourceCodeInfo() { + SharedDtor(); +} + +void SourceCodeInfo::SharedDtor() { + if (this != default_instance_) { + } +} + +void SourceCodeInfo::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} +const ::google::protobuf::Descriptor* SourceCodeInfo::descriptor() { + protobuf_AssignDescriptorsOnce(); + return SourceCodeInfo_descriptor_; +} + +const SourceCodeInfo& SourceCodeInfo::default_instance() { + if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_; +} + +SourceCodeInfo* SourceCodeInfo::default_instance_ = NULL; + +SourceCodeInfo* SourceCodeInfo::New() const { + return new SourceCodeInfo; +} + +void SourceCodeInfo::Clear() { + location_.Clear(); + ::memset(_has_bits_, 0, sizeof(_has_bits_)); + mutable_unknown_fields()->Clear(); +} + +bool SourceCodeInfo::MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input) { +#define DO_(EXPRESSION) if (!(EXPRESSION)) return false + ::google::protobuf::uint32 tag; + while ((tag = input->ReadTag()) != 0) { + switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { + // repeated .google.protobuf.SourceCodeInfo.Location location = 1; + case 1: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_location: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_location())); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(10)) goto parse_location; + if (input->ExpectAtEnd()) return true; + break; + } + + default: { + handle_uninterpreted: + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { + return true; + } + DO_(::google::protobuf::internal::WireFormat::SkipField( + input, tag, mutable_unknown_fields())); + break; + } + } + } + return true; +#undef DO_ +} + +void SourceCodeInfo::SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const { + // repeated .google.protobuf.SourceCodeInfo.Location location = 1; + for (int i = 0; i < this->location_size(); i++) { + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( + 1, this->location(i), output); + } + + if (!unknown_fields().empty()) { + ::google::protobuf::internal::WireFormat::SerializeUnknownFields( + unknown_fields(), output); + } +} + +::google::protobuf::uint8* SourceCodeInfo::SerializeWithCachedSizesToArray( + ::google::protobuf::uint8* target) const { + // repeated .google.protobuf.SourceCodeInfo.Location location = 1; + for (int i = 0; i < this->location_size(); i++) { + target = ::google::protobuf::internal::WireFormatLite:: + WriteMessageNoVirtualToArray( + 1, this->location(i), target); + } + + if (!unknown_fields().empty()) { + target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( + unknown_fields(), target); + } + return target; +} + +int SourceCodeInfo::ByteSize() const { + int total_size = 0; + + // repeated .google.protobuf.SourceCodeInfo.Location location = 1; + total_size += 1 * this->location_size(); + for (int i = 0; i < this->location_size(); i++) { + total_size += + ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( + this->location(i)); + } + + if (!unknown_fields().empty()) { + total_size += + ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( + unknown_fields()); + } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); + return total_size; +} + +void SourceCodeInfo::MergeFrom(const ::google::protobuf::Message& from) { + GOOGLE_CHECK_NE(&from, this); + const SourceCodeInfo* source = + ::google::protobuf::internal::dynamic_cast_if_available( + &from); + if (source == NULL) { + ::google::protobuf::internal::ReflectionOps::Merge(from, this); + } else { + MergeFrom(*source); + } +} + +void SourceCodeInfo::MergeFrom(const SourceCodeInfo& from) { + GOOGLE_CHECK_NE(&from, this); + location_.MergeFrom(from.location_); + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); +} + +void SourceCodeInfo::CopyFrom(const ::google::protobuf::Message& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +void SourceCodeInfo::CopyFrom(const SourceCodeInfo& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool SourceCodeInfo::IsInitialized() const { + + return true; +} + +void SourceCodeInfo::Swap(SourceCodeInfo* other) { + if (other != this) { + location_.Swap(&other->location_); + std::swap(_has_bits_[0], other->_has_bits_[0]); + _unknown_fields_.Swap(&other->_unknown_fields_); + std::swap(_cached_size_, other->_cached_size_); + } +} + +::google::protobuf::Metadata SourceCodeInfo::GetMetadata() const { + protobuf_AssignDescriptorsOnce(); + ::google::protobuf::Metadata metadata; + metadata.descriptor = SourceCodeInfo_descriptor_; + metadata.reflection = SourceCodeInfo_reflection_; + return metadata; +} + + +// @@protoc_insertion_point(namespace_scope) + +} // namespace protobuf +} // namespace google + +// @@protoc_insertion_point(global_scope) diff --git a/depends/protobuf/google/protobuf/descriptor.pb.h b/depends/protobuf/google/protobuf/descriptor.pb.h new file mode 100644 index 0000000000..95febb8130 --- /dev/null +++ b/depends/protobuf/google/protobuf/descriptor.pb.h @@ -0,0 +1,5223 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: google/protobuf/descriptor.proto + +#ifndef PROTOBUF_google_2fprotobuf_2fdescriptor_2eproto__INCLUDED +#define PROTOBUF_google_2fprotobuf_2fdescriptor_2eproto__INCLUDED + +#include + +#include + +#if GOOGLE_PROTOBUF_VERSION < 2004000 +#error This file was generated by a newer version of protoc which is +#error incompatible with your Protocol Buffer headers. Please update +#error your headers. +#endif +#if 2004001 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION +#error This file was generated by an older version of protoc which is +#error incompatible with your Protocol Buffer headers. Please +#error regenerate this file with a newer version of protoc. +#endif + +#include +#include +#include +#include +// @@protoc_insertion_point(includes) + +namespace google { +namespace protobuf { + +// Internal implementation detail -- do not call these. +void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); +void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); +void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); + +class FileDescriptorSet; +class FileDescriptorProto; +class DescriptorProto; +class DescriptorProto_ExtensionRange; +class FieldDescriptorProto; +class EnumDescriptorProto; +class EnumValueDescriptorProto; +class ServiceDescriptorProto; +class MethodDescriptorProto; +class FileOptions; +class MessageOptions; +class FieldOptions; +class EnumOptions; +class EnumValueOptions; +class ServiceOptions; +class MethodOptions; +class UninterpretedOption; +class UninterpretedOption_NamePart; +class SourceCodeInfo; +class SourceCodeInfo_Location; + +enum FieldDescriptorProto_Type { + FieldDescriptorProto_Type_TYPE_DOUBLE = 1, + FieldDescriptorProto_Type_TYPE_FLOAT = 2, + FieldDescriptorProto_Type_TYPE_INT64 = 3, + FieldDescriptorProto_Type_TYPE_UINT64 = 4, + FieldDescriptorProto_Type_TYPE_INT32 = 5, + FieldDescriptorProto_Type_TYPE_FIXED64 = 6, + FieldDescriptorProto_Type_TYPE_FIXED32 = 7, + FieldDescriptorProto_Type_TYPE_BOOL = 8, + FieldDescriptorProto_Type_TYPE_STRING = 9, + FieldDescriptorProto_Type_TYPE_GROUP = 10, + FieldDescriptorProto_Type_TYPE_MESSAGE = 11, + FieldDescriptorProto_Type_TYPE_BYTES = 12, + FieldDescriptorProto_Type_TYPE_UINT32 = 13, + FieldDescriptorProto_Type_TYPE_ENUM = 14, + FieldDescriptorProto_Type_TYPE_SFIXED32 = 15, + FieldDescriptorProto_Type_TYPE_SFIXED64 = 16, + FieldDescriptorProto_Type_TYPE_SINT32 = 17, + FieldDescriptorProto_Type_TYPE_SINT64 = 18 +}; +LIBPROTOBUF_EXPORT bool FieldDescriptorProto_Type_IsValid(int value); +const FieldDescriptorProto_Type FieldDescriptorProto_Type_Type_MIN = FieldDescriptorProto_Type_TYPE_DOUBLE; +const FieldDescriptorProto_Type FieldDescriptorProto_Type_Type_MAX = FieldDescriptorProto_Type_TYPE_SINT64; +const int FieldDescriptorProto_Type_Type_ARRAYSIZE = FieldDescriptorProto_Type_Type_MAX + 1; + +LIBPROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* FieldDescriptorProto_Type_descriptor(); +inline const ::std::string& FieldDescriptorProto_Type_Name(FieldDescriptorProto_Type value) { + return ::google::protobuf::internal::NameOfEnum( + FieldDescriptorProto_Type_descriptor(), value); +} +inline bool FieldDescriptorProto_Type_Parse( + const ::std::string& name, FieldDescriptorProto_Type* value) { + return ::google::protobuf::internal::ParseNamedEnum( + FieldDescriptorProto_Type_descriptor(), name, value); +} +enum FieldDescriptorProto_Label { + FieldDescriptorProto_Label_LABEL_OPTIONAL = 1, + FieldDescriptorProto_Label_LABEL_REQUIRED = 2, + FieldDescriptorProto_Label_LABEL_REPEATED = 3 +}; +LIBPROTOBUF_EXPORT bool FieldDescriptorProto_Label_IsValid(int value); +const FieldDescriptorProto_Label FieldDescriptorProto_Label_Label_MIN = FieldDescriptorProto_Label_LABEL_OPTIONAL; +const FieldDescriptorProto_Label FieldDescriptorProto_Label_Label_MAX = FieldDescriptorProto_Label_LABEL_REPEATED; +const int FieldDescriptorProto_Label_Label_ARRAYSIZE = FieldDescriptorProto_Label_Label_MAX + 1; + +LIBPROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* FieldDescriptorProto_Label_descriptor(); +inline const ::std::string& FieldDescriptorProto_Label_Name(FieldDescriptorProto_Label value) { + return ::google::protobuf::internal::NameOfEnum( + FieldDescriptorProto_Label_descriptor(), value); +} +inline bool FieldDescriptorProto_Label_Parse( + const ::std::string& name, FieldDescriptorProto_Label* value) { + return ::google::protobuf::internal::ParseNamedEnum( + FieldDescriptorProto_Label_descriptor(), name, value); +} +enum FileOptions_OptimizeMode { + FileOptions_OptimizeMode_SPEED = 1, + FileOptions_OptimizeMode_CODE_SIZE = 2, + FileOptions_OptimizeMode_LITE_RUNTIME = 3 +}; +LIBPROTOBUF_EXPORT bool FileOptions_OptimizeMode_IsValid(int value); +const FileOptions_OptimizeMode FileOptions_OptimizeMode_OptimizeMode_MIN = FileOptions_OptimizeMode_SPEED; +const FileOptions_OptimizeMode FileOptions_OptimizeMode_OptimizeMode_MAX = FileOptions_OptimizeMode_LITE_RUNTIME; +const int FileOptions_OptimizeMode_OptimizeMode_ARRAYSIZE = FileOptions_OptimizeMode_OptimizeMode_MAX + 1; + +LIBPROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* FileOptions_OptimizeMode_descriptor(); +inline const ::std::string& FileOptions_OptimizeMode_Name(FileOptions_OptimizeMode value) { + return ::google::protobuf::internal::NameOfEnum( + FileOptions_OptimizeMode_descriptor(), value); +} +inline bool FileOptions_OptimizeMode_Parse( + const ::std::string& name, FileOptions_OptimizeMode* value) { + return ::google::protobuf::internal::ParseNamedEnum( + FileOptions_OptimizeMode_descriptor(), name, value); +} +enum FieldOptions_CType { + FieldOptions_CType_STRING = 0, + FieldOptions_CType_CORD = 1, + FieldOptions_CType_STRING_PIECE = 2 +}; +LIBPROTOBUF_EXPORT bool FieldOptions_CType_IsValid(int value); +const FieldOptions_CType FieldOptions_CType_CType_MIN = FieldOptions_CType_STRING; +const FieldOptions_CType FieldOptions_CType_CType_MAX = FieldOptions_CType_STRING_PIECE; +const int FieldOptions_CType_CType_ARRAYSIZE = FieldOptions_CType_CType_MAX + 1; + +LIBPROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* FieldOptions_CType_descriptor(); +inline const ::std::string& FieldOptions_CType_Name(FieldOptions_CType value) { + return ::google::protobuf::internal::NameOfEnum( + FieldOptions_CType_descriptor(), value); +} +inline bool FieldOptions_CType_Parse( + const ::std::string& name, FieldOptions_CType* value) { + return ::google::protobuf::internal::ParseNamedEnum( + FieldOptions_CType_descriptor(), name, value); +} +// =================================================================== + +class LIBPROTOBUF_EXPORT FileDescriptorSet : public ::google::protobuf::Message { + public: + FileDescriptorSet(); + virtual ~FileDescriptorSet(); + + FileDescriptorSet(const FileDescriptorSet& from); + + inline FileDescriptorSet& operator=(const FileDescriptorSet& from) { + CopyFrom(from); + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { + return _unknown_fields_; + } + + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { + return &_unknown_fields_; + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const FileDescriptorSet& default_instance(); + + void Swap(FileDescriptorSet* other); + + // implements Message ---------------------------------------------- + + FileDescriptorSet* New() const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const FileDescriptorSet& from); + void MergeFrom(const FileDescriptorSet& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + // repeated .google.protobuf.FileDescriptorProto file = 1; + inline int file_size() const; + inline void clear_file(); + static const int kFileFieldNumber = 1; + inline const ::google::protobuf::FileDescriptorProto& file(int index) const; + inline ::google::protobuf::FileDescriptorProto* mutable_file(int index); + inline ::google::protobuf::FileDescriptorProto* add_file(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >& + file() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >* + mutable_file(); + + // @@protoc_insertion_point(class_scope:google.protobuf.FileDescriptorSet) + private: + + ::google::protobuf::UnknownFieldSet _unknown_fields_; + + ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto > file_; + + mutable int _cached_size_; + ::google::protobuf::uint32 _has_bits_[(1 + 31) / 32]; + + friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); + + void InitAsDefaultInstance(); + static FileDescriptorSet* default_instance_; +}; +// ------------------------------------------------------------------- + +class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Message { + public: + FileDescriptorProto(); + virtual ~FileDescriptorProto(); + + FileDescriptorProto(const FileDescriptorProto& from); + + inline FileDescriptorProto& operator=(const FileDescriptorProto& from) { + CopyFrom(from); + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { + return _unknown_fields_; + } + + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { + return &_unknown_fields_; + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const FileDescriptorProto& default_instance(); + + void Swap(FileDescriptorProto* other); + + // implements Message ---------------------------------------------- + + FileDescriptorProto* New() const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const FileDescriptorProto& from); + void MergeFrom(const FileDescriptorProto& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + // optional string name = 1; + inline bool has_name() const; + inline void clear_name(); + static const int kNameFieldNumber = 1; + inline const ::std::string& name() const; + inline void set_name(const ::std::string& value); + inline void set_name(const char* value); + inline void set_name(const char* value, size_t size); + inline ::std::string* mutable_name(); + inline ::std::string* release_name(); + + // optional string package = 2; + inline bool has_package() const; + inline void clear_package(); + static const int kPackageFieldNumber = 2; + inline const ::std::string& package() const; + inline void set_package(const ::std::string& value); + inline void set_package(const char* value); + inline void set_package(const char* value, size_t size); + inline ::std::string* mutable_package(); + inline ::std::string* release_package(); + + // repeated string dependency = 3; + inline int dependency_size() const; + inline void clear_dependency(); + static const int kDependencyFieldNumber = 3; + inline const ::std::string& dependency(int index) const; + inline ::std::string* mutable_dependency(int index); + inline void set_dependency(int index, const ::std::string& value); + inline void set_dependency(int index, const char* value); + inline void set_dependency(int index, const char* value, size_t size); + inline ::std::string* add_dependency(); + inline void add_dependency(const ::std::string& value); + inline void add_dependency(const char* value); + inline void add_dependency(const char* value, size_t size); + inline const ::google::protobuf::RepeatedPtrField< ::std::string>& dependency() const; + inline ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_dependency(); + + // repeated .google.protobuf.DescriptorProto message_type = 4; + inline int message_type_size() const; + inline void clear_message_type(); + static const int kMessageTypeFieldNumber = 4; + inline const ::google::protobuf::DescriptorProto& message_type(int index) const; + inline ::google::protobuf::DescriptorProto* mutable_message_type(int index); + inline ::google::protobuf::DescriptorProto* add_message_type(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >& + message_type() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >* + mutable_message_type(); + + // repeated .google.protobuf.EnumDescriptorProto enum_type = 5; + inline int enum_type_size() const; + inline void clear_enum_type(); + static const int kEnumTypeFieldNumber = 5; + inline const ::google::protobuf::EnumDescriptorProto& enum_type(int index) const; + inline ::google::protobuf::EnumDescriptorProto* mutable_enum_type(int index); + inline ::google::protobuf::EnumDescriptorProto* add_enum_type(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >& + enum_type() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >* + mutable_enum_type(); + + // repeated .google.protobuf.ServiceDescriptorProto service = 6; + inline int service_size() const; + inline void clear_service(); + static const int kServiceFieldNumber = 6; + inline const ::google::protobuf::ServiceDescriptorProto& service(int index) const; + inline ::google::protobuf::ServiceDescriptorProto* mutable_service(int index); + inline ::google::protobuf::ServiceDescriptorProto* add_service(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >& + service() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >* + mutable_service(); + + // repeated .google.protobuf.FieldDescriptorProto extension = 7; + inline int extension_size() const; + inline void clear_extension(); + static const int kExtensionFieldNumber = 7; + inline const ::google::protobuf::FieldDescriptorProto& extension(int index) const; + inline ::google::protobuf::FieldDescriptorProto* mutable_extension(int index); + inline ::google::protobuf::FieldDescriptorProto* add_extension(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& + extension() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* + mutable_extension(); + + // optional .google.protobuf.FileOptions options = 8; + inline bool has_options() const; + inline void clear_options(); + static const int kOptionsFieldNumber = 8; + inline const ::google::protobuf::FileOptions& options() const; + inline ::google::protobuf::FileOptions* mutable_options(); + inline ::google::protobuf::FileOptions* release_options(); + + // optional .google.protobuf.SourceCodeInfo source_code_info = 9; + inline bool has_source_code_info() const; + inline void clear_source_code_info(); + static const int kSourceCodeInfoFieldNumber = 9; + inline const ::google::protobuf::SourceCodeInfo& source_code_info() const; + inline ::google::protobuf::SourceCodeInfo* mutable_source_code_info(); + inline ::google::protobuf::SourceCodeInfo* release_source_code_info(); + + // @@protoc_insertion_point(class_scope:google.protobuf.FileDescriptorProto) + private: + inline void set_has_name(); + inline void clear_has_name(); + inline void set_has_package(); + inline void clear_has_package(); + inline void set_has_options(); + inline void clear_has_options(); + inline void set_has_source_code_info(); + inline void clear_has_source_code_info(); + + ::google::protobuf::UnknownFieldSet _unknown_fields_; + + ::std::string* name_; + ::std::string* package_; + ::google::protobuf::RepeatedPtrField< ::std::string> dependency_; + ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto > message_type_; + ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto > enum_type_; + ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto > service_; + ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto > extension_; + ::google::protobuf::FileOptions* options_; + ::google::protobuf::SourceCodeInfo* source_code_info_; + + mutable int _cached_size_; + ::google::protobuf::uint32 _has_bits_[(9 + 31) / 32]; + + friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); + + void InitAsDefaultInstance(); + static FileDescriptorProto* default_instance_; +}; +// ------------------------------------------------------------------- + +class LIBPROTOBUF_EXPORT DescriptorProto_ExtensionRange : public ::google::protobuf::Message { + public: + DescriptorProto_ExtensionRange(); + virtual ~DescriptorProto_ExtensionRange(); + + DescriptorProto_ExtensionRange(const DescriptorProto_ExtensionRange& from); + + inline DescriptorProto_ExtensionRange& operator=(const DescriptorProto_ExtensionRange& from) { + CopyFrom(from); + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { + return _unknown_fields_; + } + + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { + return &_unknown_fields_; + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const DescriptorProto_ExtensionRange& default_instance(); + + void Swap(DescriptorProto_ExtensionRange* other); + + // implements Message ---------------------------------------------- + + DescriptorProto_ExtensionRange* New() const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const DescriptorProto_ExtensionRange& from); + void MergeFrom(const DescriptorProto_ExtensionRange& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + // optional int32 start = 1; + inline bool has_start() const; + inline void clear_start(); + static const int kStartFieldNumber = 1; + inline ::google::protobuf::int32 start() const; + inline void set_start(::google::protobuf::int32 value); + + // optional int32 end = 2; + inline bool has_end() const; + inline void clear_end(); + static const int kEndFieldNumber = 2; + inline ::google::protobuf::int32 end() const; + inline void set_end(::google::protobuf::int32 value); + + // @@protoc_insertion_point(class_scope:google.protobuf.DescriptorProto.ExtensionRange) + private: + inline void set_has_start(); + inline void clear_has_start(); + inline void set_has_end(); + inline void clear_has_end(); + + ::google::protobuf::UnknownFieldSet _unknown_fields_; + + ::google::protobuf::int32 start_; + ::google::protobuf::int32 end_; + + mutable int _cached_size_; + ::google::protobuf::uint32 _has_bits_[(2 + 31) / 32]; + + friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); + + void InitAsDefaultInstance(); + static DescriptorProto_ExtensionRange* default_instance_; +}; +// ------------------------------------------------------------------- + +class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message { + public: + DescriptorProto(); + virtual ~DescriptorProto(); + + DescriptorProto(const DescriptorProto& from); + + inline DescriptorProto& operator=(const DescriptorProto& from) { + CopyFrom(from); + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { + return _unknown_fields_; + } + + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { + return &_unknown_fields_; + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const DescriptorProto& default_instance(); + + void Swap(DescriptorProto* other); + + // implements Message ---------------------------------------------- + + DescriptorProto* New() const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const DescriptorProto& from); + void MergeFrom(const DescriptorProto& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + typedef DescriptorProto_ExtensionRange ExtensionRange; + + // accessors ------------------------------------------------------- + + // optional string name = 1; + inline bool has_name() const; + inline void clear_name(); + static const int kNameFieldNumber = 1; + inline const ::std::string& name() const; + inline void set_name(const ::std::string& value); + inline void set_name(const char* value); + inline void set_name(const char* value, size_t size); + inline ::std::string* mutable_name(); + inline ::std::string* release_name(); + + // repeated .google.protobuf.FieldDescriptorProto field = 2; + inline int field_size() const; + inline void clear_field(); + static const int kFieldFieldNumber = 2; + inline const ::google::protobuf::FieldDescriptorProto& field(int index) const; + inline ::google::protobuf::FieldDescriptorProto* mutable_field(int index); + inline ::google::protobuf::FieldDescriptorProto* add_field(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& + field() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* + mutable_field(); + + // repeated .google.protobuf.FieldDescriptorProto extension = 6; + inline int extension_size() const; + inline void clear_extension(); + static const int kExtensionFieldNumber = 6; + inline const ::google::protobuf::FieldDescriptorProto& extension(int index) const; + inline ::google::protobuf::FieldDescriptorProto* mutable_extension(int index); + inline ::google::protobuf::FieldDescriptorProto* add_extension(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& + extension() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* + mutable_extension(); + + // repeated .google.protobuf.DescriptorProto nested_type = 3; + inline int nested_type_size() const; + inline void clear_nested_type(); + static const int kNestedTypeFieldNumber = 3; + inline const ::google::protobuf::DescriptorProto& nested_type(int index) const; + inline ::google::protobuf::DescriptorProto* mutable_nested_type(int index); + inline ::google::protobuf::DescriptorProto* add_nested_type(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >& + nested_type() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >* + mutable_nested_type(); + + // repeated .google.protobuf.EnumDescriptorProto enum_type = 4; + inline int enum_type_size() const; + inline void clear_enum_type(); + static const int kEnumTypeFieldNumber = 4; + inline const ::google::protobuf::EnumDescriptorProto& enum_type(int index) const; + inline ::google::protobuf::EnumDescriptorProto* mutable_enum_type(int index); + inline ::google::protobuf::EnumDescriptorProto* add_enum_type(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >& + enum_type() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >* + mutable_enum_type(); + + // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5; + inline int extension_range_size() const; + inline void clear_extension_range(); + static const int kExtensionRangeFieldNumber = 5; + inline const ::google::protobuf::DescriptorProto_ExtensionRange& extension_range(int index) const; + inline ::google::protobuf::DescriptorProto_ExtensionRange* mutable_extension_range(int index); + inline ::google::protobuf::DescriptorProto_ExtensionRange* add_extension_range(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >& + extension_range() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >* + mutable_extension_range(); + + // optional .google.protobuf.MessageOptions options = 7; + inline bool has_options() const; + inline void clear_options(); + static const int kOptionsFieldNumber = 7; + inline const ::google::protobuf::MessageOptions& options() const; + inline ::google::protobuf::MessageOptions* mutable_options(); + inline ::google::protobuf::MessageOptions* release_options(); + + // @@protoc_insertion_point(class_scope:google.protobuf.DescriptorProto) + private: + inline void set_has_name(); + inline void clear_has_name(); + inline void set_has_options(); + inline void clear_has_options(); + + ::google::protobuf::UnknownFieldSet _unknown_fields_; + + ::std::string* name_; + ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto > field_; + ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto > extension_; + ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto > nested_type_; + ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto > enum_type_; + ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange > extension_range_; + ::google::protobuf::MessageOptions* options_; + + mutable int _cached_size_; + ::google::protobuf::uint32 _has_bits_[(7 + 31) / 32]; + + friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); + + void InitAsDefaultInstance(); + static DescriptorProto* default_instance_; +}; +// ------------------------------------------------------------------- + +class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Message { + public: + FieldDescriptorProto(); + virtual ~FieldDescriptorProto(); + + FieldDescriptorProto(const FieldDescriptorProto& from); + + inline FieldDescriptorProto& operator=(const FieldDescriptorProto& from) { + CopyFrom(from); + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { + return _unknown_fields_; + } + + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { + return &_unknown_fields_; + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const FieldDescriptorProto& default_instance(); + + void Swap(FieldDescriptorProto* other); + + // implements Message ---------------------------------------------- + + FieldDescriptorProto* New() const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const FieldDescriptorProto& from); + void MergeFrom(const FieldDescriptorProto& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + typedef FieldDescriptorProto_Type Type; + static const Type TYPE_DOUBLE = FieldDescriptorProto_Type_TYPE_DOUBLE; + static const Type TYPE_FLOAT = FieldDescriptorProto_Type_TYPE_FLOAT; + static const Type TYPE_INT64 = FieldDescriptorProto_Type_TYPE_INT64; + static const Type TYPE_UINT64 = FieldDescriptorProto_Type_TYPE_UINT64; + static const Type TYPE_INT32 = FieldDescriptorProto_Type_TYPE_INT32; + static const Type TYPE_FIXED64 = FieldDescriptorProto_Type_TYPE_FIXED64; + static const Type TYPE_FIXED32 = FieldDescriptorProto_Type_TYPE_FIXED32; + static const Type TYPE_BOOL = FieldDescriptorProto_Type_TYPE_BOOL; + static const Type TYPE_STRING = FieldDescriptorProto_Type_TYPE_STRING; + static const Type TYPE_GROUP = FieldDescriptorProto_Type_TYPE_GROUP; + static const Type TYPE_MESSAGE = FieldDescriptorProto_Type_TYPE_MESSAGE; + static const Type TYPE_BYTES = FieldDescriptorProto_Type_TYPE_BYTES; + static const Type TYPE_UINT32 = FieldDescriptorProto_Type_TYPE_UINT32; + static const Type TYPE_ENUM = FieldDescriptorProto_Type_TYPE_ENUM; + static const Type TYPE_SFIXED32 = FieldDescriptorProto_Type_TYPE_SFIXED32; + static const Type TYPE_SFIXED64 = FieldDescriptorProto_Type_TYPE_SFIXED64; + static const Type TYPE_SINT32 = FieldDescriptorProto_Type_TYPE_SINT32; + static const Type TYPE_SINT64 = FieldDescriptorProto_Type_TYPE_SINT64; + static inline bool Type_IsValid(int value) { + return FieldDescriptorProto_Type_IsValid(value); + } + static const Type Type_MIN = + FieldDescriptorProto_Type_Type_MIN; + static const Type Type_MAX = + FieldDescriptorProto_Type_Type_MAX; + static const int Type_ARRAYSIZE = + FieldDescriptorProto_Type_Type_ARRAYSIZE; + static inline const ::google::protobuf::EnumDescriptor* + Type_descriptor() { + return FieldDescriptorProto_Type_descriptor(); + } + static inline const ::std::string& Type_Name(Type value) { + return FieldDescriptorProto_Type_Name(value); + } + static inline bool Type_Parse(const ::std::string& name, + Type* value) { + return FieldDescriptorProto_Type_Parse(name, value); + } + + typedef FieldDescriptorProto_Label Label; + static const Label LABEL_OPTIONAL = FieldDescriptorProto_Label_LABEL_OPTIONAL; + static const Label LABEL_REQUIRED = FieldDescriptorProto_Label_LABEL_REQUIRED; + static const Label LABEL_REPEATED = FieldDescriptorProto_Label_LABEL_REPEATED; + static inline bool Label_IsValid(int value) { + return FieldDescriptorProto_Label_IsValid(value); + } + static const Label Label_MIN = + FieldDescriptorProto_Label_Label_MIN; + static const Label Label_MAX = + FieldDescriptorProto_Label_Label_MAX; + static const int Label_ARRAYSIZE = + FieldDescriptorProto_Label_Label_ARRAYSIZE; + static inline const ::google::protobuf::EnumDescriptor* + Label_descriptor() { + return FieldDescriptorProto_Label_descriptor(); + } + static inline const ::std::string& Label_Name(Label value) { + return FieldDescriptorProto_Label_Name(value); + } + static inline bool Label_Parse(const ::std::string& name, + Label* value) { + return FieldDescriptorProto_Label_Parse(name, value); + } + + // accessors ------------------------------------------------------- + + // optional string name = 1; + inline bool has_name() const; + inline void clear_name(); + static const int kNameFieldNumber = 1; + inline const ::std::string& name() const; + inline void set_name(const ::std::string& value); + inline void set_name(const char* value); + inline void set_name(const char* value, size_t size); + inline ::std::string* mutable_name(); + inline ::std::string* release_name(); + + // optional int32 number = 3; + inline bool has_number() const; + inline void clear_number(); + static const int kNumberFieldNumber = 3; + inline ::google::protobuf::int32 number() const; + inline void set_number(::google::protobuf::int32 value); + + // optional .google.protobuf.FieldDescriptorProto.Label label = 4; + inline bool has_label() const; + inline void clear_label(); + static const int kLabelFieldNumber = 4; + inline ::google::protobuf::FieldDescriptorProto_Label label() const; + inline void set_label(::google::protobuf::FieldDescriptorProto_Label value); + + // optional .google.protobuf.FieldDescriptorProto.Type type = 5; + inline bool has_type() const; + inline void clear_type(); + static const int kTypeFieldNumber = 5; + inline ::google::protobuf::FieldDescriptorProto_Type type() const; + inline void set_type(::google::protobuf::FieldDescriptorProto_Type value); + + // optional string type_name = 6; + inline bool has_type_name() const; + inline void clear_type_name(); + static const int kTypeNameFieldNumber = 6; + inline const ::std::string& type_name() const; + inline void set_type_name(const ::std::string& value); + inline void set_type_name(const char* value); + inline void set_type_name(const char* value, size_t size); + inline ::std::string* mutable_type_name(); + inline ::std::string* release_type_name(); + + // optional string extendee = 2; + inline bool has_extendee() const; + inline void clear_extendee(); + static const int kExtendeeFieldNumber = 2; + inline const ::std::string& extendee() const; + inline void set_extendee(const ::std::string& value); + inline void set_extendee(const char* value); + inline void set_extendee(const char* value, size_t size); + inline ::std::string* mutable_extendee(); + inline ::std::string* release_extendee(); + + // optional string default_value = 7; + inline bool has_default_value() const; + inline void clear_default_value(); + static const int kDefaultValueFieldNumber = 7; + inline const ::std::string& default_value() const; + inline void set_default_value(const ::std::string& value); + inline void set_default_value(const char* value); + inline void set_default_value(const char* value, size_t size); + inline ::std::string* mutable_default_value(); + inline ::std::string* release_default_value(); + + // optional .google.protobuf.FieldOptions options = 8; + inline bool has_options() const; + inline void clear_options(); + static const int kOptionsFieldNumber = 8; + inline const ::google::protobuf::FieldOptions& options() const; + inline ::google::protobuf::FieldOptions* mutable_options(); + inline ::google::protobuf::FieldOptions* release_options(); + + // @@protoc_insertion_point(class_scope:google.protobuf.FieldDescriptorProto) + private: + inline void set_has_name(); + inline void clear_has_name(); + inline void set_has_number(); + inline void clear_has_number(); + inline void set_has_label(); + inline void clear_has_label(); + inline void set_has_type(); + inline void clear_has_type(); + inline void set_has_type_name(); + inline void clear_has_type_name(); + inline void set_has_extendee(); + inline void clear_has_extendee(); + inline void set_has_default_value(); + inline void clear_has_default_value(); + inline void set_has_options(); + inline void clear_has_options(); + + ::google::protobuf::UnknownFieldSet _unknown_fields_; + + ::std::string* name_; + ::google::protobuf::int32 number_; + int label_; + ::std::string* type_name_; + ::std::string* extendee_; + ::std::string* default_value_; + ::google::protobuf::FieldOptions* options_; + int type_; + + mutable int _cached_size_; + ::google::protobuf::uint32 _has_bits_[(8 + 31) / 32]; + + friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); + + void InitAsDefaultInstance(); + static FieldDescriptorProto* default_instance_; +}; +// ------------------------------------------------------------------- + +class LIBPROTOBUF_EXPORT EnumDescriptorProto : public ::google::protobuf::Message { + public: + EnumDescriptorProto(); + virtual ~EnumDescriptorProto(); + + EnumDescriptorProto(const EnumDescriptorProto& from); + + inline EnumDescriptorProto& operator=(const EnumDescriptorProto& from) { + CopyFrom(from); + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { + return _unknown_fields_; + } + + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { + return &_unknown_fields_; + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const EnumDescriptorProto& default_instance(); + + void Swap(EnumDescriptorProto* other); + + // implements Message ---------------------------------------------- + + EnumDescriptorProto* New() const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const EnumDescriptorProto& from); + void MergeFrom(const EnumDescriptorProto& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + // optional string name = 1; + inline bool has_name() const; + inline void clear_name(); + static const int kNameFieldNumber = 1; + inline const ::std::string& name() const; + inline void set_name(const ::std::string& value); + inline void set_name(const char* value); + inline void set_name(const char* value, size_t size); + inline ::std::string* mutable_name(); + inline ::std::string* release_name(); + + // repeated .google.protobuf.EnumValueDescriptorProto value = 2; + inline int value_size() const; + inline void clear_value(); + static const int kValueFieldNumber = 2; + inline const ::google::protobuf::EnumValueDescriptorProto& value(int index) const; + inline ::google::protobuf::EnumValueDescriptorProto* mutable_value(int index); + inline ::google::protobuf::EnumValueDescriptorProto* add_value(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >& + value() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >* + mutable_value(); + + // optional .google.protobuf.EnumOptions options = 3; + inline bool has_options() const; + inline void clear_options(); + static const int kOptionsFieldNumber = 3; + inline const ::google::protobuf::EnumOptions& options() const; + inline ::google::protobuf::EnumOptions* mutable_options(); + inline ::google::protobuf::EnumOptions* release_options(); + + // @@protoc_insertion_point(class_scope:google.protobuf.EnumDescriptorProto) + private: + inline void set_has_name(); + inline void clear_has_name(); + inline void set_has_options(); + inline void clear_has_options(); + + ::google::protobuf::UnknownFieldSet _unknown_fields_; + + ::std::string* name_; + ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto > value_; + ::google::protobuf::EnumOptions* options_; + + mutable int _cached_size_; + ::google::protobuf::uint32 _has_bits_[(3 + 31) / 32]; + + friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); + + void InitAsDefaultInstance(); + static EnumDescriptorProto* default_instance_; +}; +// ------------------------------------------------------------------- + +class LIBPROTOBUF_EXPORT EnumValueDescriptorProto : public ::google::protobuf::Message { + public: + EnumValueDescriptorProto(); + virtual ~EnumValueDescriptorProto(); + + EnumValueDescriptorProto(const EnumValueDescriptorProto& from); + + inline EnumValueDescriptorProto& operator=(const EnumValueDescriptorProto& from) { + CopyFrom(from); + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { + return _unknown_fields_; + } + + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { + return &_unknown_fields_; + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const EnumValueDescriptorProto& default_instance(); + + void Swap(EnumValueDescriptorProto* other); + + // implements Message ---------------------------------------------- + + EnumValueDescriptorProto* New() const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const EnumValueDescriptorProto& from); + void MergeFrom(const EnumValueDescriptorProto& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + // optional string name = 1; + inline bool has_name() const; + inline void clear_name(); + static const int kNameFieldNumber = 1; + inline const ::std::string& name() const; + inline void set_name(const ::std::string& value); + inline void set_name(const char* value); + inline void set_name(const char* value, size_t size); + inline ::std::string* mutable_name(); + inline ::std::string* release_name(); + + // optional int32 number = 2; + inline bool has_number() const; + inline void clear_number(); + static const int kNumberFieldNumber = 2; + inline ::google::protobuf::int32 number() const; + inline void set_number(::google::protobuf::int32 value); + + // optional .google.protobuf.EnumValueOptions options = 3; + inline bool has_options() const; + inline void clear_options(); + static const int kOptionsFieldNumber = 3; + inline const ::google::protobuf::EnumValueOptions& options() const; + inline ::google::protobuf::EnumValueOptions* mutable_options(); + inline ::google::protobuf::EnumValueOptions* release_options(); + + // @@protoc_insertion_point(class_scope:google.protobuf.EnumValueDescriptorProto) + private: + inline void set_has_name(); + inline void clear_has_name(); + inline void set_has_number(); + inline void clear_has_number(); + inline void set_has_options(); + inline void clear_has_options(); + + ::google::protobuf::UnknownFieldSet _unknown_fields_; + + ::std::string* name_; + ::google::protobuf::EnumValueOptions* options_; + ::google::protobuf::int32 number_; + + mutable int _cached_size_; + ::google::protobuf::uint32 _has_bits_[(3 + 31) / 32]; + + friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); + + void InitAsDefaultInstance(); + static EnumValueDescriptorProto* default_instance_; +}; +// ------------------------------------------------------------------- + +class LIBPROTOBUF_EXPORT ServiceDescriptorProto : public ::google::protobuf::Message { + public: + ServiceDescriptorProto(); + virtual ~ServiceDescriptorProto(); + + ServiceDescriptorProto(const ServiceDescriptorProto& from); + + inline ServiceDescriptorProto& operator=(const ServiceDescriptorProto& from) { + CopyFrom(from); + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { + return _unknown_fields_; + } + + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { + return &_unknown_fields_; + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const ServiceDescriptorProto& default_instance(); + + void Swap(ServiceDescriptorProto* other); + + // implements Message ---------------------------------------------- + + ServiceDescriptorProto* New() const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const ServiceDescriptorProto& from); + void MergeFrom(const ServiceDescriptorProto& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + // optional string name = 1; + inline bool has_name() const; + inline void clear_name(); + static const int kNameFieldNumber = 1; + inline const ::std::string& name() const; + inline void set_name(const ::std::string& value); + inline void set_name(const char* value); + inline void set_name(const char* value, size_t size); + inline ::std::string* mutable_name(); + inline ::std::string* release_name(); + + // repeated .google.protobuf.MethodDescriptorProto method = 2; + inline int method_size() const; + inline void clear_method(); + static const int kMethodFieldNumber = 2; + inline const ::google::protobuf::MethodDescriptorProto& method(int index) const; + inline ::google::protobuf::MethodDescriptorProto* mutable_method(int index); + inline ::google::protobuf::MethodDescriptorProto* add_method(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >& + method() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >* + mutable_method(); + + // optional .google.protobuf.ServiceOptions options = 3; + inline bool has_options() const; + inline void clear_options(); + static const int kOptionsFieldNumber = 3; + inline const ::google::protobuf::ServiceOptions& options() const; + inline ::google::protobuf::ServiceOptions* mutable_options(); + inline ::google::protobuf::ServiceOptions* release_options(); + + // @@protoc_insertion_point(class_scope:google.protobuf.ServiceDescriptorProto) + private: + inline void set_has_name(); + inline void clear_has_name(); + inline void set_has_options(); + inline void clear_has_options(); + + ::google::protobuf::UnknownFieldSet _unknown_fields_; + + ::std::string* name_; + ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto > method_; + ::google::protobuf::ServiceOptions* options_; + + mutable int _cached_size_; + ::google::protobuf::uint32 _has_bits_[(3 + 31) / 32]; + + friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); + + void InitAsDefaultInstance(); + static ServiceDescriptorProto* default_instance_; +}; +// ------------------------------------------------------------------- + +class LIBPROTOBUF_EXPORT MethodDescriptorProto : public ::google::protobuf::Message { + public: + MethodDescriptorProto(); + virtual ~MethodDescriptorProto(); + + MethodDescriptorProto(const MethodDescriptorProto& from); + + inline MethodDescriptorProto& operator=(const MethodDescriptorProto& from) { + CopyFrom(from); + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { + return _unknown_fields_; + } + + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { + return &_unknown_fields_; + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const MethodDescriptorProto& default_instance(); + + void Swap(MethodDescriptorProto* other); + + // implements Message ---------------------------------------------- + + MethodDescriptorProto* New() const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const MethodDescriptorProto& from); + void MergeFrom(const MethodDescriptorProto& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + // optional string name = 1; + inline bool has_name() const; + inline void clear_name(); + static const int kNameFieldNumber = 1; + inline const ::std::string& name() const; + inline void set_name(const ::std::string& value); + inline void set_name(const char* value); + inline void set_name(const char* value, size_t size); + inline ::std::string* mutable_name(); + inline ::std::string* release_name(); + + // optional string input_type = 2; + inline bool has_input_type() const; + inline void clear_input_type(); + static const int kInputTypeFieldNumber = 2; + inline const ::std::string& input_type() const; + inline void set_input_type(const ::std::string& value); + inline void set_input_type(const char* value); + inline void set_input_type(const char* value, size_t size); + inline ::std::string* mutable_input_type(); + inline ::std::string* release_input_type(); + + // optional string output_type = 3; + inline bool has_output_type() const; + inline void clear_output_type(); + static const int kOutputTypeFieldNumber = 3; + inline const ::std::string& output_type() const; + inline void set_output_type(const ::std::string& value); + inline void set_output_type(const char* value); + inline void set_output_type(const char* value, size_t size); + inline ::std::string* mutable_output_type(); + inline ::std::string* release_output_type(); + + // optional .google.protobuf.MethodOptions options = 4; + inline bool has_options() const; + inline void clear_options(); + static const int kOptionsFieldNumber = 4; + inline const ::google::protobuf::MethodOptions& options() const; + inline ::google::protobuf::MethodOptions* mutable_options(); + inline ::google::protobuf::MethodOptions* release_options(); + + // @@protoc_insertion_point(class_scope:google.protobuf.MethodDescriptorProto) + private: + inline void set_has_name(); + inline void clear_has_name(); + inline void set_has_input_type(); + inline void clear_has_input_type(); + inline void set_has_output_type(); + inline void clear_has_output_type(); + inline void set_has_options(); + inline void clear_has_options(); + + ::google::protobuf::UnknownFieldSet _unknown_fields_; + + ::std::string* name_; + ::std::string* input_type_; + ::std::string* output_type_; + ::google::protobuf::MethodOptions* options_; + + mutable int _cached_size_; + ::google::protobuf::uint32 _has_bits_[(4 + 31) / 32]; + + friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); + + void InitAsDefaultInstance(); + static MethodDescriptorProto* default_instance_; +}; +// ------------------------------------------------------------------- + +class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message { + public: + FileOptions(); + virtual ~FileOptions(); + + FileOptions(const FileOptions& from); + + inline FileOptions& operator=(const FileOptions& from) { + CopyFrom(from); + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { + return _unknown_fields_; + } + + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { + return &_unknown_fields_; + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const FileOptions& default_instance(); + + void Swap(FileOptions* other); + + // implements Message ---------------------------------------------- + + FileOptions* New() const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const FileOptions& from); + void MergeFrom(const FileOptions& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + typedef FileOptions_OptimizeMode OptimizeMode; + static const OptimizeMode SPEED = FileOptions_OptimizeMode_SPEED; + static const OptimizeMode CODE_SIZE = FileOptions_OptimizeMode_CODE_SIZE; + static const OptimizeMode LITE_RUNTIME = FileOptions_OptimizeMode_LITE_RUNTIME; + static inline bool OptimizeMode_IsValid(int value) { + return FileOptions_OptimizeMode_IsValid(value); + } + static const OptimizeMode OptimizeMode_MIN = + FileOptions_OptimizeMode_OptimizeMode_MIN; + static const OptimizeMode OptimizeMode_MAX = + FileOptions_OptimizeMode_OptimizeMode_MAX; + static const int OptimizeMode_ARRAYSIZE = + FileOptions_OptimizeMode_OptimizeMode_ARRAYSIZE; + static inline const ::google::protobuf::EnumDescriptor* + OptimizeMode_descriptor() { + return FileOptions_OptimizeMode_descriptor(); + } + static inline const ::std::string& OptimizeMode_Name(OptimizeMode value) { + return FileOptions_OptimizeMode_Name(value); + } + static inline bool OptimizeMode_Parse(const ::std::string& name, + OptimizeMode* value) { + return FileOptions_OptimizeMode_Parse(name, value); + } + + // accessors ------------------------------------------------------- + + // optional string java_package = 1; + inline bool has_java_package() const; + inline void clear_java_package(); + static const int kJavaPackageFieldNumber = 1; + inline const ::std::string& java_package() const; + inline void set_java_package(const ::std::string& value); + inline void set_java_package(const char* value); + inline void set_java_package(const char* value, size_t size); + inline ::std::string* mutable_java_package(); + inline ::std::string* release_java_package(); + + // optional string java_outer_classname = 8; + inline bool has_java_outer_classname() const; + inline void clear_java_outer_classname(); + static const int kJavaOuterClassnameFieldNumber = 8; + inline const ::std::string& java_outer_classname() const; + inline void set_java_outer_classname(const ::std::string& value); + inline void set_java_outer_classname(const char* value); + inline void set_java_outer_classname(const char* value, size_t size); + inline ::std::string* mutable_java_outer_classname(); + inline ::std::string* release_java_outer_classname(); + + // optional bool java_multiple_files = 10 [default = false]; + inline bool has_java_multiple_files() const; + inline void clear_java_multiple_files(); + static const int kJavaMultipleFilesFieldNumber = 10; + inline bool java_multiple_files() const; + inline void set_java_multiple_files(bool value); + + // optional bool java_generate_equals_and_hash = 20 [default = false]; + inline bool has_java_generate_equals_and_hash() const; + inline void clear_java_generate_equals_and_hash(); + static const int kJavaGenerateEqualsAndHashFieldNumber = 20; + inline bool java_generate_equals_and_hash() const; + inline void set_java_generate_equals_and_hash(bool value); + + // optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED]; + inline bool has_optimize_for() const; + inline void clear_optimize_for(); + static const int kOptimizeForFieldNumber = 9; + inline ::google::protobuf::FileOptions_OptimizeMode optimize_for() const; + inline void set_optimize_for(::google::protobuf::FileOptions_OptimizeMode value); + + // optional bool cc_generic_services = 16 [default = false]; + inline bool has_cc_generic_services() const; + inline void clear_cc_generic_services(); + static const int kCcGenericServicesFieldNumber = 16; + inline bool cc_generic_services() const; + inline void set_cc_generic_services(bool value); + + // optional bool java_generic_services = 17 [default = false]; + inline bool has_java_generic_services() const; + inline void clear_java_generic_services(); + static const int kJavaGenericServicesFieldNumber = 17; + inline bool java_generic_services() const; + inline void set_java_generic_services(bool value); + + // optional bool py_generic_services = 18 [default = false]; + inline bool has_py_generic_services() const; + inline void clear_py_generic_services(); + static const int kPyGenericServicesFieldNumber = 18; + inline bool py_generic_services() const; + inline void set_py_generic_services(bool value); + + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; + inline int uninterpreted_option_size() const; + inline void clear_uninterpreted_option(); + static const int kUninterpretedOptionFieldNumber = 999; + inline const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const; + inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index); + inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& + uninterpreted_option() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* + mutable_uninterpreted_option(); + + GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(FileOptions) + // @@protoc_insertion_point(class_scope:google.protobuf.FileOptions) + private: + inline void set_has_java_package(); + inline void clear_has_java_package(); + inline void set_has_java_outer_classname(); + inline void clear_has_java_outer_classname(); + inline void set_has_java_multiple_files(); + inline void clear_has_java_multiple_files(); + inline void set_has_java_generate_equals_and_hash(); + inline void clear_has_java_generate_equals_and_hash(); + inline void set_has_optimize_for(); + inline void clear_has_optimize_for(); + inline void set_has_cc_generic_services(); + inline void clear_has_cc_generic_services(); + inline void set_has_java_generic_services(); + inline void clear_has_java_generic_services(); + inline void set_has_py_generic_services(); + inline void clear_has_py_generic_services(); + + ::google::protobuf::internal::ExtensionSet _extensions_; + + ::google::protobuf::UnknownFieldSet _unknown_fields_; + + ::std::string* java_package_; + ::std::string* java_outer_classname_; + int optimize_for_; + bool java_multiple_files_; + bool java_generate_equals_and_hash_; + bool cc_generic_services_; + bool java_generic_services_; + ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_; + bool py_generic_services_; + + mutable int _cached_size_; + ::google::protobuf::uint32 _has_bits_[(9 + 31) / 32]; + + friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); + + void InitAsDefaultInstance(); + static FileOptions* default_instance_; +}; +// ------------------------------------------------------------------- + +class LIBPROTOBUF_EXPORT MessageOptions : public ::google::protobuf::Message { + public: + MessageOptions(); + virtual ~MessageOptions(); + + MessageOptions(const MessageOptions& from); + + inline MessageOptions& operator=(const MessageOptions& from) { + CopyFrom(from); + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { + return _unknown_fields_; + } + + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { + return &_unknown_fields_; + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const MessageOptions& default_instance(); + + void Swap(MessageOptions* other); + + // implements Message ---------------------------------------------- + + MessageOptions* New() const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const MessageOptions& from); + void MergeFrom(const MessageOptions& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + // optional bool message_set_wire_format = 1 [default = false]; + inline bool has_message_set_wire_format() const; + inline void clear_message_set_wire_format(); + static const int kMessageSetWireFormatFieldNumber = 1; + inline bool message_set_wire_format() const; + inline void set_message_set_wire_format(bool value); + + // optional bool no_standard_descriptor_accessor = 2 [default = false]; + inline bool has_no_standard_descriptor_accessor() const; + inline void clear_no_standard_descriptor_accessor(); + static const int kNoStandardDescriptorAccessorFieldNumber = 2; + inline bool no_standard_descriptor_accessor() const; + inline void set_no_standard_descriptor_accessor(bool value); + + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; + inline int uninterpreted_option_size() const; + inline void clear_uninterpreted_option(); + static const int kUninterpretedOptionFieldNumber = 999; + inline const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const; + inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index); + inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& + uninterpreted_option() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* + mutable_uninterpreted_option(); + + GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(MessageOptions) + // @@protoc_insertion_point(class_scope:google.protobuf.MessageOptions) + private: + inline void set_has_message_set_wire_format(); + inline void clear_has_message_set_wire_format(); + inline void set_has_no_standard_descriptor_accessor(); + inline void clear_has_no_standard_descriptor_accessor(); + + ::google::protobuf::internal::ExtensionSet _extensions_; + + ::google::protobuf::UnknownFieldSet _unknown_fields_; + + ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_; + bool message_set_wire_format_; + bool no_standard_descriptor_accessor_; + + mutable int _cached_size_; + ::google::protobuf::uint32 _has_bits_[(3 + 31) / 32]; + + friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); + + void InitAsDefaultInstance(); + static MessageOptions* default_instance_; +}; +// ------------------------------------------------------------------- + +class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message { + public: + FieldOptions(); + virtual ~FieldOptions(); + + FieldOptions(const FieldOptions& from); + + inline FieldOptions& operator=(const FieldOptions& from) { + CopyFrom(from); + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { + return _unknown_fields_; + } + + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { + return &_unknown_fields_; + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const FieldOptions& default_instance(); + + void Swap(FieldOptions* other); + + // implements Message ---------------------------------------------- + + FieldOptions* New() const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const FieldOptions& from); + void MergeFrom(const FieldOptions& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + typedef FieldOptions_CType CType; + static const CType STRING = FieldOptions_CType_STRING; + static const CType CORD = FieldOptions_CType_CORD; + static const CType STRING_PIECE = FieldOptions_CType_STRING_PIECE; + static inline bool CType_IsValid(int value) { + return FieldOptions_CType_IsValid(value); + } + static const CType CType_MIN = + FieldOptions_CType_CType_MIN; + static const CType CType_MAX = + FieldOptions_CType_CType_MAX; + static const int CType_ARRAYSIZE = + FieldOptions_CType_CType_ARRAYSIZE; + static inline const ::google::protobuf::EnumDescriptor* + CType_descriptor() { + return FieldOptions_CType_descriptor(); + } + static inline const ::std::string& CType_Name(CType value) { + return FieldOptions_CType_Name(value); + } + static inline bool CType_Parse(const ::std::string& name, + CType* value) { + return FieldOptions_CType_Parse(name, value); + } + + // accessors ------------------------------------------------------- + + // optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING]; + inline bool has_ctype() const; + inline void clear_ctype(); + static const int kCtypeFieldNumber = 1; + inline ::google::protobuf::FieldOptions_CType ctype() const; + inline void set_ctype(::google::protobuf::FieldOptions_CType value); + + // optional bool packed = 2; + inline bool has_packed() const; + inline void clear_packed(); + static const int kPackedFieldNumber = 2; + inline bool packed() const; + inline void set_packed(bool value); + + // optional bool deprecated = 3 [default = false]; + inline bool has_deprecated() const; + inline void clear_deprecated(); + static const int kDeprecatedFieldNumber = 3; + inline bool deprecated() const; + inline void set_deprecated(bool value); + + // optional string experimental_map_key = 9; + inline bool has_experimental_map_key() const; + inline void clear_experimental_map_key(); + static const int kExperimentalMapKeyFieldNumber = 9; + inline const ::std::string& experimental_map_key() const; + inline void set_experimental_map_key(const ::std::string& value); + inline void set_experimental_map_key(const char* value); + inline void set_experimental_map_key(const char* value, size_t size); + inline ::std::string* mutable_experimental_map_key(); + inline ::std::string* release_experimental_map_key(); + + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; + inline int uninterpreted_option_size() const; + inline void clear_uninterpreted_option(); + static const int kUninterpretedOptionFieldNumber = 999; + inline const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const; + inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index); + inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& + uninterpreted_option() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* + mutable_uninterpreted_option(); + + GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(FieldOptions) + // @@protoc_insertion_point(class_scope:google.protobuf.FieldOptions) + private: + inline void set_has_ctype(); + inline void clear_has_ctype(); + inline void set_has_packed(); + inline void clear_has_packed(); + inline void set_has_deprecated(); + inline void clear_has_deprecated(); + inline void set_has_experimental_map_key(); + inline void clear_has_experimental_map_key(); + + ::google::protobuf::internal::ExtensionSet _extensions_; + + ::google::protobuf::UnknownFieldSet _unknown_fields_; + + int ctype_; + bool packed_; + bool deprecated_; + ::std::string* experimental_map_key_; + ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_; + + mutable int _cached_size_; + ::google::protobuf::uint32 _has_bits_[(5 + 31) / 32]; + + friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); + + void InitAsDefaultInstance(); + static FieldOptions* default_instance_; +}; +// ------------------------------------------------------------------- + +class LIBPROTOBUF_EXPORT EnumOptions : public ::google::protobuf::Message { + public: + EnumOptions(); + virtual ~EnumOptions(); + + EnumOptions(const EnumOptions& from); + + inline EnumOptions& operator=(const EnumOptions& from) { + CopyFrom(from); + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { + return _unknown_fields_; + } + + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { + return &_unknown_fields_; + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const EnumOptions& default_instance(); + + void Swap(EnumOptions* other); + + // implements Message ---------------------------------------------- + + EnumOptions* New() const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const EnumOptions& from); + void MergeFrom(const EnumOptions& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; + inline int uninterpreted_option_size() const; + inline void clear_uninterpreted_option(); + static const int kUninterpretedOptionFieldNumber = 999; + inline const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const; + inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index); + inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& + uninterpreted_option() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* + mutable_uninterpreted_option(); + + GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(EnumOptions) + // @@protoc_insertion_point(class_scope:google.protobuf.EnumOptions) + private: + + ::google::protobuf::internal::ExtensionSet _extensions_; + + ::google::protobuf::UnknownFieldSet _unknown_fields_; + + ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_; + + mutable int _cached_size_; + ::google::protobuf::uint32 _has_bits_[(1 + 31) / 32]; + + friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); + + void InitAsDefaultInstance(); + static EnumOptions* default_instance_; +}; +// ------------------------------------------------------------------- + +class LIBPROTOBUF_EXPORT EnumValueOptions : public ::google::protobuf::Message { + public: + EnumValueOptions(); + virtual ~EnumValueOptions(); + + EnumValueOptions(const EnumValueOptions& from); + + inline EnumValueOptions& operator=(const EnumValueOptions& from) { + CopyFrom(from); + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { + return _unknown_fields_; + } + + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { + return &_unknown_fields_; + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const EnumValueOptions& default_instance(); + + void Swap(EnumValueOptions* other); + + // implements Message ---------------------------------------------- + + EnumValueOptions* New() const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const EnumValueOptions& from); + void MergeFrom(const EnumValueOptions& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; + inline int uninterpreted_option_size() const; + inline void clear_uninterpreted_option(); + static const int kUninterpretedOptionFieldNumber = 999; + inline const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const; + inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index); + inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& + uninterpreted_option() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* + mutable_uninterpreted_option(); + + GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(EnumValueOptions) + // @@protoc_insertion_point(class_scope:google.protobuf.EnumValueOptions) + private: + + ::google::protobuf::internal::ExtensionSet _extensions_; + + ::google::protobuf::UnknownFieldSet _unknown_fields_; + + ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_; + + mutable int _cached_size_; + ::google::protobuf::uint32 _has_bits_[(1 + 31) / 32]; + + friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); + + void InitAsDefaultInstance(); + static EnumValueOptions* default_instance_; +}; +// ------------------------------------------------------------------- + +class LIBPROTOBUF_EXPORT ServiceOptions : public ::google::protobuf::Message { + public: + ServiceOptions(); + virtual ~ServiceOptions(); + + ServiceOptions(const ServiceOptions& from); + + inline ServiceOptions& operator=(const ServiceOptions& from) { + CopyFrom(from); + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { + return _unknown_fields_; + } + + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { + return &_unknown_fields_; + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const ServiceOptions& default_instance(); + + void Swap(ServiceOptions* other); + + // implements Message ---------------------------------------------- + + ServiceOptions* New() const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const ServiceOptions& from); + void MergeFrom(const ServiceOptions& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; + inline int uninterpreted_option_size() const; + inline void clear_uninterpreted_option(); + static const int kUninterpretedOptionFieldNumber = 999; + inline const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const; + inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index); + inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& + uninterpreted_option() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* + mutable_uninterpreted_option(); + + GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(ServiceOptions) + // @@protoc_insertion_point(class_scope:google.protobuf.ServiceOptions) + private: + + ::google::protobuf::internal::ExtensionSet _extensions_; + + ::google::protobuf::UnknownFieldSet _unknown_fields_; + + ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_; + + mutable int _cached_size_; + ::google::protobuf::uint32 _has_bits_[(1 + 31) / 32]; + + friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); + + void InitAsDefaultInstance(); + static ServiceOptions* default_instance_; +}; +// ------------------------------------------------------------------- + +class LIBPROTOBUF_EXPORT MethodOptions : public ::google::protobuf::Message { + public: + MethodOptions(); + virtual ~MethodOptions(); + + MethodOptions(const MethodOptions& from); + + inline MethodOptions& operator=(const MethodOptions& from) { + CopyFrom(from); + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { + return _unknown_fields_; + } + + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { + return &_unknown_fields_; + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const MethodOptions& default_instance(); + + void Swap(MethodOptions* other); + + // implements Message ---------------------------------------------- + + MethodOptions* New() const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const MethodOptions& from); + void MergeFrom(const MethodOptions& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; + inline int uninterpreted_option_size() const; + inline void clear_uninterpreted_option(); + static const int kUninterpretedOptionFieldNumber = 999; + inline const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const; + inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index); + inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& + uninterpreted_option() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* + mutable_uninterpreted_option(); + + GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(MethodOptions) + // @@protoc_insertion_point(class_scope:google.protobuf.MethodOptions) + private: + + ::google::protobuf::internal::ExtensionSet _extensions_; + + ::google::protobuf::UnknownFieldSet _unknown_fields_; + + ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_; + + mutable int _cached_size_; + ::google::protobuf::uint32 _has_bits_[(1 + 31) / 32]; + + friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); + + void InitAsDefaultInstance(); + static MethodOptions* default_instance_; +}; +// ------------------------------------------------------------------- + +class LIBPROTOBUF_EXPORT UninterpretedOption_NamePart : public ::google::protobuf::Message { + public: + UninterpretedOption_NamePart(); + virtual ~UninterpretedOption_NamePart(); + + UninterpretedOption_NamePart(const UninterpretedOption_NamePart& from); + + inline UninterpretedOption_NamePart& operator=(const UninterpretedOption_NamePart& from) { + CopyFrom(from); + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { + return _unknown_fields_; + } + + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { + return &_unknown_fields_; + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const UninterpretedOption_NamePart& default_instance(); + + void Swap(UninterpretedOption_NamePart* other); + + // implements Message ---------------------------------------------- + + UninterpretedOption_NamePart* New() const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const UninterpretedOption_NamePart& from); + void MergeFrom(const UninterpretedOption_NamePart& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + // required string name_part = 1; + inline bool has_name_part() const; + inline void clear_name_part(); + static const int kNamePartFieldNumber = 1; + inline const ::std::string& name_part() const; + inline void set_name_part(const ::std::string& value); + inline void set_name_part(const char* value); + inline void set_name_part(const char* value, size_t size); + inline ::std::string* mutable_name_part(); + inline ::std::string* release_name_part(); + + // required bool is_extension = 2; + inline bool has_is_extension() const; + inline void clear_is_extension(); + static const int kIsExtensionFieldNumber = 2; + inline bool is_extension() const; + inline void set_is_extension(bool value); + + // @@protoc_insertion_point(class_scope:google.protobuf.UninterpretedOption.NamePart) + private: + inline void set_has_name_part(); + inline void clear_has_name_part(); + inline void set_has_is_extension(); + inline void clear_has_is_extension(); + + ::google::protobuf::UnknownFieldSet _unknown_fields_; + + ::std::string* name_part_; + bool is_extension_; + + mutable int _cached_size_; + ::google::protobuf::uint32 _has_bits_[(2 + 31) / 32]; + + friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); + + void InitAsDefaultInstance(); + static UninterpretedOption_NamePart* default_instance_; +}; +// ------------------------------------------------------------------- + +class LIBPROTOBUF_EXPORT UninterpretedOption : public ::google::protobuf::Message { + public: + UninterpretedOption(); + virtual ~UninterpretedOption(); + + UninterpretedOption(const UninterpretedOption& from); + + inline UninterpretedOption& operator=(const UninterpretedOption& from) { + CopyFrom(from); + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { + return _unknown_fields_; + } + + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { + return &_unknown_fields_; + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const UninterpretedOption& default_instance(); + + void Swap(UninterpretedOption* other); + + // implements Message ---------------------------------------------- + + UninterpretedOption* New() const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const UninterpretedOption& from); + void MergeFrom(const UninterpretedOption& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + typedef UninterpretedOption_NamePart NamePart; + + // accessors ------------------------------------------------------- + + // repeated .google.protobuf.UninterpretedOption.NamePart name = 2; + inline int name_size() const; + inline void clear_name(); + static const int kNameFieldNumber = 2; + inline const ::google::protobuf::UninterpretedOption_NamePart& name(int index) const; + inline ::google::protobuf::UninterpretedOption_NamePart* mutable_name(int index); + inline ::google::protobuf::UninterpretedOption_NamePart* add_name(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >& + name() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >* + mutable_name(); + + // optional string identifier_value = 3; + inline bool has_identifier_value() const; + inline void clear_identifier_value(); + static const int kIdentifierValueFieldNumber = 3; + inline const ::std::string& identifier_value() const; + inline void set_identifier_value(const ::std::string& value); + inline void set_identifier_value(const char* value); + inline void set_identifier_value(const char* value, size_t size); + inline ::std::string* mutable_identifier_value(); + inline ::std::string* release_identifier_value(); + + // optional uint64 positive_int_value = 4; + inline bool has_positive_int_value() const; + inline void clear_positive_int_value(); + static const int kPositiveIntValueFieldNumber = 4; + inline ::google::protobuf::uint64 positive_int_value() const; + inline void set_positive_int_value(::google::protobuf::uint64 value); + + // optional int64 negative_int_value = 5; + inline bool has_negative_int_value() const; + inline void clear_negative_int_value(); + static const int kNegativeIntValueFieldNumber = 5; + inline ::google::protobuf::int64 negative_int_value() const; + inline void set_negative_int_value(::google::protobuf::int64 value); + + // optional double double_value = 6; + inline bool has_double_value() const; + inline void clear_double_value(); + static const int kDoubleValueFieldNumber = 6; + inline double double_value() const; + inline void set_double_value(double value); + + // optional bytes string_value = 7; + inline bool has_string_value() const; + inline void clear_string_value(); + static const int kStringValueFieldNumber = 7; + inline const ::std::string& string_value() const; + inline void set_string_value(const ::std::string& value); + inline void set_string_value(const char* value); + inline void set_string_value(const void* value, size_t size); + inline ::std::string* mutable_string_value(); + inline ::std::string* release_string_value(); + + // optional string aggregate_value = 8; + inline bool has_aggregate_value() const; + inline void clear_aggregate_value(); + static const int kAggregateValueFieldNumber = 8; + inline const ::std::string& aggregate_value() const; + inline void set_aggregate_value(const ::std::string& value); + inline void set_aggregate_value(const char* value); + inline void set_aggregate_value(const char* value, size_t size); + inline ::std::string* mutable_aggregate_value(); + inline ::std::string* release_aggregate_value(); + + // @@protoc_insertion_point(class_scope:google.protobuf.UninterpretedOption) + private: + inline void set_has_identifier_value(); + inline void clear_has_identifier_value(); + inline void set_has_positive_int_value(); + inline void clear_has_positive_int_value(); + inline void set_has_negative_int_value(); + inline void clear_has_negative_int_value(); + inline void set_has_double_value(); + inline void clear_has_double_value(); + inline void set_has_string_value(); + inline void clear_has_string_value(); + inline void set_has_aggregate_value(); + inline void clear_has_aggregate_value(); + + ::google::protobuf::UnknownFieldSet _unknown_fields_; + + ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart > name_; + ::std::string* identifier_value_; + ::google::protobuf::uint64 positive_int_value_; + ::google::protobuf::int64 negative_int_value_; + double double_value_; + ::std::string* string_value_; + ::std::string* aggregate_value_; + + mutable int _cached_size_; + ::google::protobuf::uint32 _has_bits_[(7 + 31) / 32]; + + friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); + + void InitAsDefaultInstance(); + static UninterpretedOption* default_instance_; +}; +// ------------------------------------------------------------------- + +class LIBPROTOBUF_EXPORT SourceCodeInfo_Location : public ::google::protobuf::Message { + public: + SourceCodeInfo_Location(); + virtual ~SourceCodeInfo_Location(); + + SourceCodeInfo_Location(const SourceCodeInfo_Location& from); + + inline SourceCodeInfo_Location& operator=(const SourceCodeInfo_Location& from) { + CopyFrom(from); + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { + return _unknown_fields_; + } + + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { + return &_unknown_fields_; + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const SourceCodeInfo_Location& default_instance(); + + void Swap(SourceCodeInfo_Location* other); + + // implements Message ---------------------------------------------- + + SourceCodeInfo_Location* New() const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const SourceCodeInfo_Location& from); + void MergeFrom(const SourceCodeInfo_Location& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + // repeated int32 path = 1 [packed = true]; + inline int path_size() const; + inline void clear_path(); + static const int kPathFieldNumber = 1; + inline ::google::protobuf::int32 path(int index) const; + inline void set_path(int index, ::google::protobuf::int32 value); + inline void add_path(::google::protobuf::int32 value); + inline const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >& + path() const; + inline ::google::protobuf::RepeatedField< ::google::protobuf::int32 >* + mutable_path(); + + // repeated int32 span = 2 [packed = true]; + inline int span_size() const; + inline void clear_span(); + static const int kSpanFieldNumber = 2; + inline ::google::protobuf::int32 span(int index) const; + inline void set_span(int index, ::google::protobuf::int32 value); + inline void add_span(::google::protobuf::int32 value); + inline const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >& + span() const; + inline ::google::protobuf::RepeatedField< ::google::protobuf::int32 >* + mutable_span(); + + // @@protoc_insertion_point(class_scope:google.protobuf.SourceCodeInfo.Location) + private: + + ::google::protobuf::UnknownFieldSet _unknown_fields_; + + ::google::protobuf::RepeatedField< ::google::protobuf::int32 > path_; + mutable int _path_cached_byte_size_; + ::google::protobuf::RepeatedField< ::google::protobuf::int32 > span_; + mutable int _span_cached_byte_size_; + + mutable int _cached_size_; + ::google::protobuf::uint32 _has_bits_[(2 + 31) / 32]; + + friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); + + void InitAsDefaultInstance(); + static SourceCodeInfo_Location* default_instance_; +}; +// ------------------------------------------------------------------- + +class LIBPROTOBUF_EXPORT SourceCodeInfo : public ::google::protobuf::Message { + public: + SourceCodeInfo(); + virtual ~SourceCodeInfo(); + + SourceCodeInfo(const SourceCodeInfo& from); + + inline SourceCodeInfo& operator=(const SourceCodeInfo& from) { + CopyFrom(from); + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { + return _unknown_fields_; + } + + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { + return &_unknown_fields_; + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const SourceCodeInfo& default_instance(); + + void Swap(SourceCodeInfo* other); + + // implements Message ---------------------------------------------- + + SourceCodeInfo* New() const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const SourceCodeInfo& from); + void MergeFrom(const SourceCodeInfo& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + typedef SourceCodeInfo_Location Location; + + // accessors ------------------------------------------------------- + + // repeated .google.protobuf.SourceCodeInfo.Location location = 1; + inline int location_size() const; + inline void clear_location(); + static const int kLocationFieldNumber = 1; + inline const ::google::protobuf::SourceCodeInfo_Location& location(int index) const; + inline ::google::protobuf::SourceCodeInfo_Location* mutable_location(int index); + inline ::google::protobuf::SourceCodeInfo_Location* add_location(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::SourceCodeInfo_Location >& + location() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::SourceCodeInfo_Location >* + mutable_location(); + + // @@protoc_insertion_point(class_scope:google.protobuf.SourceCodeInfo) + private: + + ::google::protobuf::UnknownFieldSet _unknown_fields_; + + ::google::protobuf::RepeatedPtrField< ::google::protobuf::SourceCodeInfo_Location > location_; + + mutable int _cached_size_; + ::google::protobuf::uint32 _has_bits_[(1 + 31) / 32]; + + friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); + + void InitAsDefaultInstance(); + static SourceCodeInfo* default_instance_; +}; +// =================================================================== + + +// =================================================================== + +// FileDescriptorSet + +// repeated .google.protobuf.FileDescriptorProto file = 1; +inline int FileDescriptorSet::file_size() const { + return file_.size(); +} +inline void FileDescriptorSet::clear_file() { + file_.Clear(); +} +inline const ::google::protobuf::FileDescriptorProto& FileDescriptorSet::file(int index) const { + return file_.Get(index); +} +inline ::google::protobuf::FileDescriptorProto* FileDescriptorSet::mutable_file(int index) { + return file_.Mutable(index); +} +inline ::google::protobuf::FileDescriptorProto* FileDescriptorSet::add_file() { + return file_.Add(); +} +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >& +FileDescriptorSet::file() const { + return file_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >* +FileDescriptorSet::mutable_file() { + return &file_; +} + +// ------------------------------------------------------------------- + +// FileDescriptorProto + +// optional string name = 1; +inline bool FileDescriptorProto::has_name() const { + return (_has_bits_[0] & 0x00000001u) != 0; +} +inline void FileDescriptorProto::set_has_name() { + _has_bits_[0] |= 0x00000001u; +} +inline void FileDescriptorProto::clear_has_name() { + _has_bits_[0] &= ~0x00000001u; +} +inline void FileDescriptorProto::clear_name() { + if (name_ != &::google::protobuf::internal::kEmptyString) { + name_->clear(); + } + clear_has_name(); +} +inline const ::std::string& FileDescriptorProto::name() const { + return *name_; +} +inline void FileDescriptorProto::set_name(const ::std::string& value) { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + name_->assign(value); +} +inline void FileDescriptorProto::set_name(const char* value) { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + name_->assign(value); +} +inline void FileDescriptorProto::set_name(const char* value, size_t size) { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + name_->assign(reinterpret_cast(value), size); +} +inline ::std::string* FileDescriptorProto::mutable_name() { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + return name_; +} +inline ::std::string* FileDescriptorProto::release_name() { + clear_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = name_; + name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} + +// optional string package = 2; +inline bool FileDescriptorProto::has_package() const { + return (_has_bits_[0] & 0x00000002u) != 0; +} +inline void FileDescriptorProto::set_has_package() { + _has_bits_[0] |= 0x00000002u; +} +inline void FileDescriptorProto::clear_has_package() { + _has_bits_[0] &= ~0x00000002u; +} +inline void FileDescriptorProto::clear_package() { + if (package_ != &::google::protobuf::internal::kEmptyString) { + package_->clear(); + } + clear_has_package(); +} +inline const ::std::string& FileDescriptorProto::package() const { + return *package_; +} +inline void FileDescriptorProto::set_package(const ::std::string& value) { + set_has_package(); + if (package_ == &::google::protobuf::internal::kEmptyString) { + package_ = new ::std::string; + } + package_->assign(value); +} +inline void FileDescriptorProto::set_package(const char* value) { + set_has_package(); + if (package_ == &::google::protobuf::internal::kEmptyString) { + package_ = new ::std::string; + } + package_->assign(value); +} +inline void FileDescriptorProto::set_package(const char* value, size_t size) { + set_has_package(); + if (package_ == &::google::protobuf::internal::kEmptyString) { + package_ = new ::std::string; + } + package_->assign(reinterpret_cast(value), size); +} +inline ::std::string* FileDescriptorProto::mutable_package() { + set_has_package(); + if (package_ == &::google::protobuf::internal::kEmptyString) { + package_ = new ::std::string; + } + return package_; +} +inline ::std::string* FileDescriptorProto::release_package() { + clear_has_package(); + if (package_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = package_; + package_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} + +// repeated string dependency = 3; +inline int FileDescriptorProto::dependency_size() const { + return dependency_.size(); +} +inline void FileDescriptorProto::clear_dependency() { + dependency_.Clear(); +} +inline const ::std::string& FileDescriptorProto::dependency(int index) const { + return dependency_.Get(index); +} +inline ::std::string* FileDescriptorProto::mutable_dependency(int index) { + return dependency_.Mutable(index); +} +inline void FileDescriptorProto::set_dependency(int index, const ::std::string& value) { + dependency_.Mutable(index)->assign(value); +} +inline void FileDescriptorProto::set_dependency(int index, const char* value) { + dependency_.Mutable(index)->assign(value); +} +inline void FileDescriptorProto::set_dependency(int index, const char* value, size_t size) { + dependency_.Mutable(index)->assign( + reinterpret_cast(value), size); +} +inline ::std::string* FileDescriptorProto::add_dependency() { + return dependency_.Add(); +} +inline void FileDescriptorProto::add_dependency(const ::std::string& value) { + dependency_.Add()->assign(value); +} +inline void FileDescriptorProto::add_dependency(const char* value) { + dependency_.Add()->assign(value); +} +inline void FileDescriptorProto::add_dependency(const char* value, size_t size) { + dependency_.Add()->assign(reinterpret_cast(value), size); +} +inline const ::google::protobuf::RepeatedPtrField< ::std::string>& +FileDescriptorProto::dependency() const { + return dependency_; +} +inline ::google::protobuf::RepeatedPtrField< ::std::string>* +FileDescriptorProto::mutable_dependency() { + return &dependency_; +} + +// repeated .google.protobuf.DescriptorProto message_type = 4; +inline int FileDescriptorProto::message_type_size() const { + return message_type_.size(); +} +inline void FileDescriptorProto::clear_message_type() { + message_type_.Clear(); +} +inline const ::google::protobuf::DescriptorProto& FileDescriptorProto::message_type(int index) const { + return message_type_.Get(index); +} +inline ::google::protobuf::DescriptorProto* FileDescriptorProto::mutable_message_type(int index) { + return message_type_.Mutable(index); +} +inline ::google::protobuf::DescriptorProto* FileDescriptorProto::add_message_type() { + return message_type_.Add(); +} +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >& +FileDescriptorProto::message_type() const { + return message_type_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >* +FileDescriptorProto::mutable_message_type() { + return &message_type_; +} + +// repeated .google.protobuf.EnumDescriptorProto enum_type = 5; +inline int FileDescriptorProto::enum_type_size() const { + return enum_type_.size(); +} +inline void FileDescriptorProto::clear_enum_type() { + enum_type_.Clear(); +} +inline const ::google::protobuf::EnumDescriptorProto& FileDescriptorProto::enum_type(int index) const { + return enum_type_.Get(index); +} +inline ::google::protobuf::EnumDescriptorProto* FileDescriptorProto::mutable_enum_type(int index) { + return enum_type_.Mutable(index); +} +inline ::google::protobuf::EnumDescriptorProto* FileDescriptorProto::add_enum_type() { + return enum_type_.Add(); +} +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >& +FileDescriptorProto::enum_type() const { + return enum_type_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >* +FileDescriptorProto::mutable_enum_type() { + return &enum_type_; +} + +// repeated .google.protobuf.ServiceDescriptorProto service = 6; +inline int FileDescriptorProto::service_size() const { + return service_.size(); +} +inline void FileDescriptorProto::clear_service() { + service_.Clear(); +} +inline const ::google::protobuf::ServiceDescriptorProto& FileDescriptorProto::service(int index) const { + return service_.Get(index); +} +inline ::google::protobuf::ServiceDescriptorProto* FileDescriptorProto::mutable_service(int index) { + return service_.Mutable(index); +} +inline ::google::protobuf::ServiceDescriptorProto* FileDescriptorProto::add_service() { + return service_.Add(); +} +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >& +FileDescriptorProto::service() const { + return service_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >* +FileDescriptorProto::mutable_service() { + return &service_; +} + +// repeated .google.protobuf.FieldDescriptorProto extension = 7; +inline int FileDescriptorProto::extension_size() const { + return extension_.size(); +} +inline void FileDescriptorProto::clear_extension() { + extension_.Clear(); +} +inline const ::google::protobuf::FieldDescriptorProto& FileDescriptorProto::extension(int index) const { + return extension_.Get(index); +} +inline ::google::protobuf::FieldDescriptorProto* FileDescriptorProto::mutable_extension(int index) { + return extension_.Mutable(index); +} +inline ::google::protobuf::FieldDescriptorProto* FileDescriptorProto::add_extension() { + return extension_.Add(); +} +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& +FileDescriptorProto::extension() const { + return extension_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* +FileDescriptorProto::mutable_extension() { + return &extension_; +} + +// optional .google.protobuf.FileOptions options = 8; +inline bool FileDescriptorProto::has_options() const { + return (_has_bits_[0] & 0x00000080u) != 0; +} +inline void FileDescriptorProto::set_has_options() { + _has_bits_[0] |= 0x00000080u; +} +inline void FileDescriptorProto::clear_has_options() { + _has_bits_[0] &= ~0x00000080u; +} +inline void FileDescriptorProto::clear_options() { + if (options_ != NULL) options_->::google::protobuf::FileOptions::Clear(); + clear_has_options(); +} +inline const ::google::protobuf::FileOptions& FileDescriptorProto::options() const { + return options_ != NULL ? *options_ : *default_instance_->options_; +} +inline ::google::protobuf::FileOptions* FileDescriptorProto::mutable_options() { + set_has_options(); + if (options_ == NULL) options_ = new ::google::protobuf::FileOptions; + return options_; +} +inline ::google::protobuf::FileOptions* FileDescriptorProto::release_options() { + clear_has_options(); + ::google::protobuf::FileOptions* temp = options_; + options_ = NULL; + return temp; +} + +// optional .google.protobuf.SourceCodeInfo source_code_info = 9; +inline bool FileDescriptorProto::has_source_code_info() const { + return (_has_bits_[0] & 0x00000100u) != 0; +} +inline void FileDescriptorProto::set_has_source_code_info() { + _has_bits_[0] |= 0x00000100u; +} +inline void FileDescriptorProto::clear_has_source_code_info() { + _has_bits_[0] &= ~0x00000100u; +} +inline void FileDescriptorProto::clear_source_code_info() { + if (source_code_info_ != NULL) source_code_info_->::google::protobuf::SourceCodeInfo::Clear(); + clear_has_source_code_info(); +} +inline const ::google::protobuf::SourceCodeInfo& FileDescriptorProto::source_code_info() const { + return source_code_info_ != NULL ? *source_code_info_ : *default_instance_->source_code_info_; +} +inline ::google::protobuf::SourceCodeInfo* FileDescriptorProto::mutable_source_code_info() { + set_has_source_code_info(); + if (source_code_info_ == NULL) source_code_info_ = new ::google::protobuf::SourceCodeInfo; + return source_code_info_; +} +inline ::google::protobuf::SourceCodeInfo* FileDescriptorProto::release_source_code_info() { + clear_has_source_code_info(); + ::google::protobuf::SourceCodeInfo* temp = source_code_info_; + source_code_info_ = NULL; + return temp; +} + +// ------------------------------------------------------------------- + +// DescriptorProto_ExtensionRange + +// optional int32 start = 1; +inline bool DescriptorProto_ExtensionRange::has_start() const { + return (_has_bits_[0] & 0x00000001u) != 0; +} +inline void DescriptorProto_ExtensionRange::set_has_start() { + _has_bits_[0] |= 0x00000001u; +} +inline void DescriptorProto_ExtensionRange::clear_has_start() { + _has_bits_[0] &= ~0x00000001u; +} +inline void DescriptorProto_ExtensionRange::clear_start() { + start_ = 0; + clear_has_start(); +} +inline ::google::protobuf::int32 DescriptorProto_ExtensionRange::start() const { + return start_; +} +inline void DescriptorProto_ExtensionRange::set_start(::google::protobuf::int32 value) { + set_has_start(); + start_ = value; +} + +// optional int32 end = 2; +inline bool DescriptorProto_ExtensionRange::has_end() const { + return (_has_bits_[0] & 0x00000002u) != 0; +} +inline void DescriptorProto_ExtensionRange::set_has_end() { + _has_bits_[0] |= 0x00000002u; +} +inline void DescriptorProto_ExtensionRange::clear_has_end() { + _has_bits_[0] &= ~0x00000002u; +} +inline void DescriptorProto_ExtensionRange::clear_end() { + end_ = 0; + clear_has_end(); +} +inline ::google::protobuf::int32 DescriptorProto_ExtensionRange::end() const { + return end_; +} +inline void DescriptorProto_ExtensionRange::set_end(::google::protobuf::int32 value) { + set_has_end(); + end_ = value; +} + +// ------------------------------------------------------------------- + +// DescriptorProto + +// optional string name = 1; +inline bool DescriptorProto::has_name() const { + return (_has_bits_[0] & 0x00000001u) != 0; +} +inline void DescriptorProto::set_has_name() { + _has_bits_[0] |= 0x00000001u; +} +inline void DescriptorProto::clear_has_name() { + _has_bits_[0] &= ~0x00000001u; +} +inline void DescriptorProto::clear_name() { + if (name_ != &::google::protobuf::internal::kEmptyString) { + name_->clear(); + } + clear_has_name(); +} +inline const ::std::string& DescriptorProto::name() const { + return *name_; +} +inline void DescriptorProto::set_name(const ::std::string& value) { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + name_->assign(value); +} +inline void DescriptorProto::set_name(const char* value) { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + name_->assign(value); +} +inline void DescriptorProto::set_name(const char* value, size_t size) { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + name_->assign(reinterpret_cast(value), size); +} +inline ::std::string* DescriptorProto::mutable_name() { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + return name_; +} +inline ::std::string* DescriptorProto::release_name() { + clear_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = name_; + name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} + +// repeated .google.protobuf.FieldDescriptorProto field = 2; +inline int DescriptorProto::field_size() const { + return field_.size(); +} +inline void DescriptorProto::clear_field() { + field_.Clear(); +} +inline const ::google::protobuf::FieldDescriptorProto& DescriptorProto::field(int index) const { + return field_.Get(index); +} +inline ::google::protobuf::FieldDescriptorProto* DescriptorProto::mutable_field(int index) { + return field_.Mutable(index); +} +inline ::google::protobuf::FieldDescriptorProto* DescriptorProto::add_field() { + return field_.Add(); +} +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& +DescriptorProto::field() const { + return field_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* +DescriptorProto::mutable_field() { + return &field_; +} + +// repeated .google.protobuf.FieldDescriptorProto extension = 6; +inline int DescriptorProto::extension_size() const { + return extension_.size(); +} +inline void DescriptorProto::clear_extension() { + extension_.Clear(); +} +inline const ::google::protobuf::FieldDescriptorProto& DescriptorProto::extension(int index) const { + return extension_.Get(index); +} +inline ::google::protobuf::FieldDescriptorProto* DescriptorProto::mutable_extension(int index) { + return extension_.Mutable(index); +} +inline ::google::protobuf::FieldDescriptorProto* DescriptorProto::add_extension() { + return extension_.Add(); +} +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& +DescriptorProto::extension() const { + return extension_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* +DescriptorProto::mutable_extension() { + return &extension_; +} + +// repeated .google.protobuf.DescriptorProto nested_type = 3; +inline int DescriptorProto::nested_type_size() const { + return nested_type_.size(); +} +inline void DescriptorProto::clear_nested_type() { + nested_type_.Clear(); +} +inline const ::google::protobuf::DescriptorProto& DescriptorProto::nested_type(int index) const { + return nested_type_.Get(index); +} +inline ::google::protobuf::DescriptorProto* DescriptorProto::mutable_nested_type(int index) { + return nested_type_.Mutable(index); +} +inline ::google::protobuf::DescriptorProto* DescriptorProto::add_nested_type() { + return nested_type_.Add(); +} +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >& +DescriptorProto::nested_type() const { + return nested_type_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >* +DescriptorProto::mutable_nested_type() { + return &nested_type_; +} + +// repeated .google.protobuf.EnumDescriptorProto enum_type = 4; +inline int DescriptorProto::enum_type_size() const { + return enum_type_.size(); +} +inline void DescriptorProto::clear_enum_type() { + enum_type_.Clear(); +} +inline const ::google::protobuf::EnumDescriptorProto& DescriptorProto::enum_type(int index) const { + return enum_type_.Get(index); +} +inline ::google::protobuf::EnumDescriptorProto* DescriptorProto::mutable_enum_type(int index) { + return enum_type_.Mutable(index); +} +inline ::google::protobuf::EnumDescriptorProto* DescriptorProto::add_enum_type() { + return enum_type_.Add(); +} +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >& +DescriptorProto::enum_type() const { + return enum_type_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >* +DescriptorProto::mutable_enum_type() { + return &enum_type_; +} + +// repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5; +inline int DescriptorProto::extension_range_size() const { + return extension_range_.size(); +} +inline void DescriptorProto::clear_extension_range() { + extension_range_.Clear(); +} +inline const ::google::protobuf::DescriptorProto_ExtensionRange& DescriptorProto::extension_range(int index) const { + return extension_range_.Get(index); +} +inline ::google::protobuf::DescriptorProto_ExtensionRange* DescriptorProto::mutable_extension_range(int index) { + return extension_range_.Mutable(index); +} +inline ::google::protobuf::DescriptorProto_ExtensionRange* DescriptorProto::add_extension_range() { + return extension_range_.Add(); +} +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >& +DescriptorProto::extension_range() const { + return extension_range_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >* +DescriptorProto::mutable_extension_range() { + return &extension_range_; +} + +// optional .google.protobuf.MessageOptions options = 7; +inline bool DescriptorProto::has_options() const { + return (_has_bits_[0] & 0x00000040u) != 0; +} +inline void DescriptorProto::set_has_options() { + _has_bits_[0] |= 0x00000040u; +} +inline void DescriptorProto::clear_has_options() { + _has_bits_[0] &= ~0x00000040u; +} +inline void DescriptorProto::clear_options() { + if (options_ != NULL) options_->::google::protobuf::MessageOptions::Clear(); + clear_has_options(); +} +inline const ::google::protobuf::MessageOptions& DescriptorProto::options() const { + return options_ != NULL ? *options_ : *default_instance_->options_; +} +inline ::google::protobuf::MessageOptions* DescriptorProto::mutable_options() { + set_has_options(); + if (options_ == NULL) options_ = new ::google::protobuf::MessageOptions; + return options_; +} +inline ::google::protobuf::MessageOptions* DescriptorProto::release_options() { + clear_has_options(); + ::google::protobuf::MessageOptions* temp = options_; + options_ = NULL; + return temp; +} + +// ------------------------------------------------------------------- + +// FieldDescriptorProto + +// optional string name = 1; +inline bool FieldDescriptorProto::has_name() const { + return (_has_bits_[0] & 0x00000001u) != 0; +} +inline void FieldDescriptorProto::set_has_name() { + _has_bits_[0] |= 0x00000001u; +} +inline void FieldDescriptorProto::clear_has_name() { + _has_bits_[0] &= ~0x00000001u; +} +inline void FieldDescriptorProto::clear_name() { + if (name_ != &::google::protobuf::internal::kEmptyString) { + name_->clear(); + } + clear_has_name(); +} +inline const ::std::string& FieldDescriptorProto::name() const { + return *name_; +} +inline void FieldDescriptorProto::set_name(const ::std::string& value) { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + name_->assign(value); +} +inline void FieldDescriptorProto::set_name(const char* value) { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + name_->assign(value); +} +inline void FieldDescriptorProto::set_name(const char* value, size_t size) { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + name_->assign(reinterpret_cast(value), size); +} +inline ::std::string* FieldDescriptorProto::mutable_name() { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + return name_; +} +inline ::std::string* FieldDescriptorProto::release_name() { + clear_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = name_; + name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} + +// optional int32 number = 3; +inline bool FieldDescriptorProto::has_number() const { + return (_has_bits_[0] & 0x00000002u) != 0; +} +inline void FieldDescriptorProto::set_has_number() { + _has_bits_[0] |= 0x00000002u; +} +inline void FieldDescriptorProto::clear_has_number() { + _has_bits_[0] &= ~0x00000002u; +} +inline void FieldDescriptorProto::clear_number() { + number_ = 0; + clear_has_number(); +} +inline ::google::protobuf::int32 FieldDescriptorProto::number() const { + return number_; +} +inline void FieldDescriptorProto::set_number(::google::protobuf::int32 value) { + set_has_number(); + number_ = value; +} + +// optional .google.protobuf.FieldDescriptorProto.Label label = 4; +inline bool FieldDescriptorProto::has_label() const { + return (_has_bits_[0] & 0x00000004u) != 0; +} +inline void FieldDescriptorProto::set_has_label() { + _has_bits_[0] |= 0x00000004u; +} +inline void FieldDescriptorProto::clear_has_label() { + _has_bits_[0] &= ~0x00000004u; +} +inline void FieldDescriptorProto::clear_label() { + label_ = 1; + clear_has_label(); +} +inline ::google::protobuf::FieldDescriptorProto_Label FieldDescriptorProto::label() const { + return static_cast< ::google::protobuf::FieldDescriptorProto_Label >(label_); +} +inline void FieldDescriptorProto::set_label(::google::protobuf::FieldDescriptorProto_Label value) { + GOOGLE_DCHECK(::google::protobuf::FieldDescriptorProto_Label_IsValid(value)); + set_has_label(); + label_ = value; +} + +// optional .google.protobuf.FieldDescriptorProto.Type type = 5; +inline bool FieldDescriptorProto::has_type() const { + return (_has_bits_[0] & 0x00000008u) != 0; +} +inline void FieldDescriptorProto::set_has_type() { + _has_bits_[0] |= 0x00000008u; +} +inline void FieldDescriptorProto::clear_has_type() { + _has_bits_[0] &= ~0x00000008u; +} +inline void FieldDescriptorProto::clear_type() { + type_ = 1; + clear_has_type(); +} +inline ::google::protobuf::FieldDescriptorProto_Type FieldDescriptorProto::type() const { + return static_cast< ::google::protobuf::FieldDescriptorProto_Type >(type_); +} +inline void FieldDescriptorProto::set_type(::google::protobuf::FieldDescriptorProto_Type value) { + GOOGLE_DCHECK(::google::protobuf::FieldDescriptorProto_Type_IsValid(value)); + set_has_type(); + type_ = value; +} + +// optional string type_name = 6; +inline bool FieldDescriptorProto::has_type_name() const { + return (_has_bits_[0] & 0x00000010u) != 0; +} +inline void FieldDescriptorProto::set_has_type_name() { + _has_bits_[0] |= 0x00000010u; +} +inline void FieldDescriptorProto::clear_has_type_name() { + _has_bits_[0] &= ~0x00000010u; +} +inline void FieldDescriptorProto::clear_type_name() { + if (type_name_ != &::google::protobuf::internal::kEmptyString) { + type_name_->clear(); + } + clear_has_type_name(); +} +inline const ::std::string& FieldDescriptorProto::type_name() const { + return *type_name_; +} +inline void FieldDescriptorProto::set_type_name(const ::std::string& value) { + set_has_type_name(); + if (type_name_ == &::google::protobuf::internal::kEmptyString) { + type_name_ = new ::std::string; + } + type_name_->assign(value); +} +inline void FieldDescriptorProto::set_type_name(const char* value) { + set_has_type_name(); + if (type_name_ == &::google::protobuf::internal::kEmptyString) { + type_name_ = new ::std::string; + } + type_name_->assign(value); +} +inline void FieldDescriptorProto::set_type_name(const char* value, size_t size) { + set_has_type_name(); + if (type_name_ == &::google::protobuf::internal::kEmptyString) { + type_name_ = new ::std::string; + } + type_name_->assign(reinterpret_cast(value), size); +} +inline ::std::string* FieldDescriptorProto::mutable_type_name() { + set_has_type_name(); + if (type_name_ == &::google::protobuf::internal::kEmptyString) { + type_name_ = new ::std::string; + } + return type_name_; +} +inline ::std::string* FieldDescriptorProto::release_type_name() { + clear_has_type_name(); + if (type_name_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = type_name_; + type_name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} + +// optional string extendee = 2; +inline bool FieldDescriptorProto::has_extendee() const { + return (_has_bits_[0] & 0x00000020u) != 0; +} +inline void FieldDescriptorProto::set_has_extendee() { + _has_bits_[0] |= 0x00000020u; +} +inline void FieldDescriptorProto::clear_has_extendee() { + _has_bits_[0] &= ~0x00000020u; +} +inline void FieldDescriptorProto::clear_extendee() { + if (extendee_ != &::google::protobuf::internal::kEmptyString) { + extendee_->clear(); + } + clear_has_extendee(); +} +inline const ::std::string& FieldDescriptorProto::extendee() const { + return *extendee_; +} +inline void FieldDescriptorProto::set_extendee(const ::std::string& value) { + set_has_extendee(); + if (extendee_ == &::google::protobuf::internal::kEmptyString) { + extendee_ = new ::std::string; + } + extendee_->assign(value); +} +inline void FieldDescriptorProto::set_extendee(const char* value) { + set_has_extendee(); + if (extendee_ == &::google::protobuf::internal::kEmptyString) { + extendee_ = new ::std::string; + } + extendee_->assign(value); +} +inline void FieldDescriptorProto::set_extendee(const char* value, size_t size) { + set_has_extendee(); + if (extendee_ == &::google::protobuf::internal::kEmptyString) { + extendee_ = new ::std::string; + } + extendee_->assign(reinterpret_cast(value), size); +} +inline ::std::string* FieldDescriptorProto::mutable_extendee() { + set_has_extendee(); + if (extendee_ == &::google::protobuf::internal::kEmptyString) { + extendee_ = new ::std::string; + } + return extendee_; +} +inline ::std::string* FieldDescriptorProto::release_extendee() { + clear_has_extendee(); + if (extendee_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = extendee_; + extendee_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} + +// optional string default_value = 7; +inline bool FieldDescriptorProto::has_default_value() const { + return (_has_bits_[0] & 0x00000040u) != 0; +} +inline void FieldDescriptorProto::set_has_default_value() { + _has_bits_[0] |= 0x00000040u; +} +inline void FieldDescriptorProto::clear_has_default_value() { + _has_bits_[0] &= ~0x00000040u; +} +inline void FieldDescriptorProto::clear_default_value() { + if (default_value_ != &::google::protobuf::internal::kEmptyString) { + default_value_->clear(); + } + clear_has_default_value(); +} +inline const ::std::string& FieldDescriptorProto::default_value() const { + return *default_value_; +} +inline void FieldDescriptorProto::set_default_value(const ::std::string& value) { + set_has_default_value(); + if (default_value_ == &::google::protobuf::internal::kEmptyString) { + default_value_ = new ::std::string; + } + default_value_->assign(value); +} +inline void FieldDescriptorProto::set_default_value(const char* value) { + set_has_default_value(); + if (default_value_ == &::google::protobuf::internal::kEmptyString) { + default_value_ = new ::std::string; + } + default_value_->assign(value); +} +inline void FieldDescriptorProto::set_default_value(const char* value, size_t size) { + set_has_default_value(); + if (default_value_ == &::google::protobuf::internal::kEmptyString) { + default_value_ = new ::std::string; + } + default_value_->assign(reinterpret_cast(value), size); +} +inline ::std::string* FieldDescriptorProto::mutable_default_value() { + set_has_default_value(); + if (default_value_ == &::google::protobuf::internal::kEmptyString) { + default_value_ = new ::std::string; + } + return default_value_; +} +inline ::std::string* FieldDescriptorProto::release_default_value() { + clear_has_default_value(); + if (default_value_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = default_value_; + default_value_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} + +// optional .google.protobuf.FieldOptions options = 8; +inline bool FieldDescriptorProto::has_options() const { + return (_has_bits_[0] & 0x00000080u) != 0; +} +inline void FieldDescriptorProto::set_has_options() { + _has_bits_[0] |= 0x00000080u; +} +inline void FieldDescriptorProto::clear_has_options() { + _has_bits_[0] &= ~0x00000080u; +} +inline void FieldDescriptorProto::clear_options() { + if (options_ != NULL) options_->::google::protobuf::FieldOptions::Clear(); + clear_has_options(); +} +inline const ::google::protobuf::FieldOptions& FieldDescriptorProto::options() const { + return options_ != NULL ? *options_ : *default_instance_->options_; +} +inline ::google::protobuf::FieldOptions* FieldDescriptorProto::mutable_options() { + set_has_options(); + if (options_ == NULL) options_ = new ::google::protobuf::FieldOptions; + return options_; +} +inline ::google::protobuf::FieldOptions* FieldDescriptorProto::release_options() { + clear_has_options(); + ::google::protobuf::FieldOptions* temp = options_; + options_ = NULL; + return temp; +} + +// ------------------------------------------------------------------- + +// EnumDescriptorProto + +// optional string name = 1; +inline bool EnumDescriptorProto::has_name() const { + return (_has_bits_[0] & 0x00000001u) != 0; +} +inline void EnumDescriptorProto::set_has_name() { + _has_bits_[0] |= 0x00000001u; +} +inline void EnumDescriptorProto::clear_has_name() { + _has_bits_[0] &= ~0x00000001u; +} +inline void EnumDescriptorProto::clear_name() { + if (name_ != &::google::protobuf::internal::kEmptyString) { + name_->clear(); + } + clear_has_name(); +} +inline const ::std::string& EnumDescriptorProto::name() const { + return *name_; +} +inline void EnumDescriptorProto::set_name(const ::std::string& value) { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + name_->assign(value); +} +inline void EnumDescriptorProto::set_name(const char* value) { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + name_->assign(value); +} +inline void EnumDescriptorProto::set_name(const char* value, size_t size) { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + name_->assign(reinterpret_cast(value), size); +} +inline ::std::string* EnumDescriptorProto::mutable_name() { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + return name_; +} +inline ::std::string* EnumDescriptorProto::release_name() { + clear_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = name_; + name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} + +// repeated .google.protobuf.EnumValueDescriptorProto value = 2; +inline int EnumDescriptorProto::value_size() const { + return value_.size(); +} +inline void EnumDescriptorProto::clear_value() { + value_.Clear(); +} +inline const ::google::protobuf::EnumValueDescriptorProto& EnumDescriptorProto::value(int index) const { + return value_.Get(index); +} +inline ::google::protobuf::EnumValueDescriptorProto* EnumDescriptorProto::mutable_value(int index) { + return value_.Mutable(index); +} +inline ::google::protobuf::EnumValueDescriptorProto* EnumDescriptorProto::add_value() { + return value_.Add(); +} +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >& +EnumDescriptorProto::value() const { + return value_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >* +EnumDescriptorProto::mutable_value() { + return &value_; +} + +// optional .google.protobuf.EnumOptions options = 3; +inline bool EnumDescriptorProto::has_options() const { + return (_has_bits_[0] & 0x00000004u) != 0; +} +inline void EnumDescriptorProto::set_has_options() { + _has_bits_[0] |= 0x00000004u; +} +inline void EnumDescriptorProto::clear_has_options() { + _has_bits_[0] &= ~0x00000004u; +} +inline void EnumDescriptorProto::clear_options() { + if (options_ != NULL) options_->::google::protobuf::EnumOptions::Clear(); + clear_has_options(); +} +inline const ::google::protobuf::EnumOptions& EnumDescriptorProto::options() const { + return options_ != NULL ? *options_ : *default_instance_->options_; +} +inline ::google::protobuf::EnumOptions* EnumDescriptorProto::mutable_options() { + set_has_options(); + if (options_ == NULL) options_ = new ::google::protobuf::EnumOptions; + return options_; +} +inline ::google::protobuf::EnumOptions* EnumDescriptorProto::release_options() { + clear_has_options(); + ::google::protobuf::EnumOptions* temp = options_; + options_ = NULL; + return temp; +} + +// ------------------------------------------------------------------- + +// EnumValueDescriptorProto + +// optional string name = 1; +inline bool EnumValueDescriptorProto::has_name() const { + return (_has_bits_[0] & 0x00000001u) != 0; +} +inline void EnumValueDescriptorProto::set_has_name() { + _has_bits_[0] |= 0x00000001u; +} +inline void EnumValueDescriptorProto::clear_has_name() { + _has_bits_[0] &= ~0x00000001u; +} +inline void EnumValueDescriptorProto::clear_name() { + if (name_ != &::google::protobuf::internal::kEmptyString) { + name_->clear(); + } + clear_has_name(); +} +inline const ::std::string& EnumValueDescriptorProto::name() const { + return *name_; +} +inline void EnumValueDescriptorProto::set_name(const ::std::string& value) { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + name_->assign(value); +} +inline void EnumValueDescriptorProto::set_name(const char* value) { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + name_->assign(value); +} +inline void EnumValueDescriptorProto::set_name(const char* value, size_t size) { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + name_->assign(reinterpret_cast(value), size); +} +inline ::std::string* EnumValueDescriptorProto::mutable_name() { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + return name_; +} +inline ::std::string* EnumValueDescriptorProto::release_name() { + clear_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = name_; + name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} + +// optional int32 number = 2; +inline bool EnumValueDescriptorProto::has_number() const { + return (_has_bits_[0] & 0x00000002u) != 0; +} +inline void EnumValueDescriptorProto::set_has_number() { + _has_bits_[0] |= 0x00000002u; +} +inline void EnumValueDescriptorProto::clear_has_number() { + _has_bits_[0] &= ~0x00000002u; +} +inline void EnumValueDescriptorProto::clear_number() { + number_ = 0; + clear_has_number(); +} +inline ::google::protobuf::int32 EnumValueDescriptorProto::number() const { + return number_; +} +inline void EnumValueDescriptorProto::set_number(::google::protobuf::int32 value) { + set_has_number(); + number_ = value; +} + +// optional .google.protobuf.EnumValueOptions options = 3; +inline bool EnumValueDescriptorProto::has_options() const { + return (_has_bits_[0] & 0x00000004u) != 0; +} +inline void EnumValueDescriptorProto::set_has_options() { + _has_bits_[0] |= 0x00000004u; +} +inline void EnumValueDescriptorProto::clear_has_options() { + _has_bits_[0] &= ~0x00000004u; +} +inline void EnumValueDescriptorProto::clear_options() { + if (options_ != NULL) options_->::google::protobuf::EnumValueOptions::Clear(); + clear_has_options(); +} +inline const ::google::protobuf::EnumValueOptions& EnumValueDescriptorProto::options() const { + return options_ != NULL ? *options_ : *default_instance_->options_; +} +inline ::google::protobuf::EnumValueOptions* EnumValueDescriptorProto::mutable_options() { + set_has_options(); + if (options_ == NULL) options_ = new ::google::protobuf::EnumValueOptions; + return options_; +} +inline ::google::protobuf::EnumValueOptions* EnumValueDescriptorProto::release_options() { + clear_has_options(); + ::google::protobuf::EnumValueOptions* temp = options_; + options_ = NULL; + return temp; +} + +// ------------------------------------------------------------------- + +// ServiceDescriptorProto + +// optional string name = 1; +inline bool ServiceDescriptorProto::has_name() const { + return (_has_bits_[0] & 0x00000001u) != 0; +} +inline void ServiceDescriptorProto::set_has_name() { + _has_bits_[0] |= 0x00000001u; +} +inline void ServiceDescriptorProto::clear_has_name() { + _has_bits_[0] &= ~0x00000001u; +} +inline void ServiceDescriptorProto::clear_name() { + if (name_ != &::google::protobuf::internal::kEmptyString) { + name_->clear(); + } + clear_has_name(); +} +inline const ::std::string& ServiceDescriptorProto::name() const { + return *name_; +} +inline void ServiceDescriptorProto::set_name(const ::std::string& value) { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + name_->assign(value); +} +inline void ServiceDescriptorProto::set_name(const char* value) { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + name_->assign(value); +} +inline void ServiceDescriptorProto::set_name(const char* value, size_t size) { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + name_->assign(reinterpret_cast(value), size); +} +inline ::std::string* ServiceDescriptorProto::mutable_name() { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + return name_; +} +inline ::std::string* ServiceDescriptorProto::release_name() { + clear_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = name_; + name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} + +// repeated .google.protobuf.MethodDescriptorProto method = 2; +inline int ServiceDescriptorProto::method_size() const { + return method_.size(); +} +inline void ServiceDescriptorProto::clear_method() { + method_.Clear(); +} +inline const ::google::protobuf::MethodDescriptorProto& ServiceDescriptorProto::method(int index) const { + return method_.Get(index); +} +inline ::google::protobuf::MethodDescriptorProto* ServiceDescriptorProto::mutable_method(int index) { + return method_.Mutable(index); +} +inline ::google::protobuf::MethodDescriptorProto* ServiceDescriptorProto::add_method() { + return method_.Add(); +} +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >& +ServiceDescriptorProto::method() const { + return method_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >* +ServiceDescriptorProto::mutable_method() { + return &method_; +} + +// optional .google.protobuf.ServiceOptions options = 3; +inline bool ServiceDescriptorProto::has_options() const { + return (_has_bits_[0] & 0x00000004u) != 0; +} +inline void ServiceDescriptorProto::set_has_options() { + _has_bits_[0] |= 0x00000004u; +} +inline void ServiceDescriptorProto::clear_has_options() { + _has_bits_[0] &= ~0x00000004u; +} +inline void ServiceDescriptorProto::clear_options() { + if (options_ != NULL) options_->::google::protobuf::ServiceOptions::Clear(); + clear_has_options(); +} +inline const ::google::protobuf::ServiceOptions& ServiceDescriptorProto::options() const { + return options_ != NULL ? *options_ : *default_instance_->options_; +} +inline ::google::protobuf::ServiceOptions* ServiceDescriptorProto::mutable_options() { + set_has_options(); + if (options_ == NULL) options_ = new ::google::protobuf::ServiceOptions; + return options_; +} +inline ::google::protobuf::ServiceOptions* ServiceDescriptorProto::release_options() { + clear_has_options(); + ::google::protobuf::ServiceOptions* temp = options_; + options_ = NULL; + return temp; +} + +// ------------------------------------------------------------------- + +// MethodDescriptorProto + +// optional string name = 1; +inline bool MethodDescriptorProto::has_name() const { + return (_has_bits_[0] & 0x00000001u) != 0; +} +inline void MethodDescriptorProto::set_has_name() { + _has_bits_[0] |= 0x00000001u; +} +inline void MethodDescriptorProto::clear_has_name() { + _has_bits_[0] &= ~0x00000001u; +} +inline void MethodDescriptorProto::clear_name() { + if (name_ != &::google::protobuf::internal::kEmptyString) { + name_->clear(); + } + clear_has_name(); +} +inline const ::std::string& MethodDescriptorProto::name() const { + return *name_; +} +inline void MethodDescriptorProto::set_name(const ::std::string& value) { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + name_->assign(value); +} +inline void MethodDescriptorProto::set_name(const char* value) { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + name_->assign(value); +} +inline void MethodDescriptorProto::set_name(const char* value, size_t size) { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + name_->assign(reinterpret_cast(value), size); +} +inline ::std::string* MethodDescriptorProto::mutable_name() { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + return name_; +} +inline ::std::string* MethodDescriptorProto::release_name() { + clear_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = name_; + name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} + +// optional string input_type = 2; +inline bool MethodDescriptorProto::has_input_type() const { + return (_has_bits_[0] & 0x00000002u) != 0; +} +inline void MethodDescriptorProto::set_has_input_type() { + _has_bits_[0] |= 0x00000002u; +} +inline void MethodDescriptorProto::clear_has_input_type() { + _has_bits_[0] &= ~0x00000002u; +} +inline void MethodDescriptorProto::clear_input_type() { + if (input_type_ != &::google::protobuf::internal::kEmptyString) { + input_type_->clear(); + } + clear_has_input_type(); +} +inline const ::std::string& MethodDescriptorProto::input_type() const { + return *input_type_; +} +inline void MethodDescriptorProto::set_input_type(const ::std::string& value) { + set_has_input_type(); + if (input_type_ == &::google::protobuf::internal::kEmptyString) { + input_type_ = new ::std::string; + } + input_type_->assign(value); +} +inline void MethodDescriptorProto::set_input_type(const char* value) { + set_has_input_type(); + if (input_type_ == &::google::protobuf::internal::kEmptyString) { + input_type_ = new ::std::string; + } + input_type_->assign(value); +} +inline void MethodDescriptorProto::set_input_type(const char* value, size_t size) { + set_has_input_type(); + if (input_type_ == &::google::protobuf::internal::kEmptyString) { + input_type_ = new ::std::string; + } + input_type_->assign(reinterpret_cast(value), size); +} +inline ::std::string* MethodDescriptorProto::mutable_input_type() { + set_has_input_type(); + if (input_type_ == &::google::protobuf::internal::kEmptyString) { + input_type_ = new ::std::string; + } + return input_type_; +} +inline ::std::string* MethodDescriptorProto::release_input_type() { + clear_has_input_type(); + if (input_type_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = input_type_; + input_type_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} + +// optional string output_type = 3; +inline bool MethodDescriptorProto::has_output_type() const { + return (_has_bits_[0] & 0x00000004u) != 0; +} +inline void MethodDescriptorProto::set_has_output_type() { + _has_bits_[0] |= 0x00000004u; +} +inline void MethodDescriptorProto::clear_has_output_type() { + _has_bits_[0] &= ~0x00000004u; +} +inline void MethodDescriptorProto::clear_output_type() { + if (output_type_ != &::google::protobuf::internal::kEmptyString) { + output_type_->clear(); + } + clear_has_output_type(); +} +inline const ::std::string& MethodDescriptorProto::output_type() const { + return *output_type_; +} +inline void MethodDescriptorProto::set_output_type(const ::std::string& value) { + set_has_output_type(); + if (output_type_ == &::google::protobuf::internal::kEmptyString) { + output_type_ = new ::std::string; + } + output_type_->assign(value); +} +inline void MethodDescriptorProto::set_output_type(const char* value) { + set_has_output_type(); + if (output_type_ == &::google::protobuf::internal::kEmptyString) { + output_type_ = new ::std::string; + } + output_type_->assign(value); +} +inline void MethodDescriptorProto::set_output_type(const char* value, size_t size) { + set_has_output_type(); + if (output_type_ == &::google::protobuf::internal::kEmptyString) { + output_type_ = new ::std::string; + } + output_type_->assign(reinterpret_cast(value), size); +} +inline ::std::string* MethodDescriptorProto::mutable_output_type() { + set_has_output_type(); + if (output_type_ == &::google::protobuf::internal::kEmptyString) { + output_type_ = new ::std::string; + } + return output_type_; +} +inline ::std::string* MethodDescriptorProto::release_output_type() { + clear_has_output_type(); + if (output_type_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = output_type_; + output_type_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} + +// optional .google.protobuf.MethodOptions options = 4; +inline bool MethodDescriptorProto::has_options() const { + return (_has_bits_[0] & 0x00000008u) != 0; +} +inline void MethodDescriptorProto::set_has_options() { + _has_bits_[0] |= 0x00000008u; +} +inline void MethodDescriptorProto::clear_has_options() { + _has_bits_[0] &= ~0x00000008u; +} +inline void MethodDescriptorProto::clear_options() { + if (options_ != NULL) options_->::google::protobuf::MethodOptions::Clear(); + clear_has_options(); +} +inline const ::google::protobuf::MethodOptions& MethodDescriptorProto::options() const { + return options_ != NULL ? *options_ : *default_instance_->options_; +} +inline ::google::protobuf::MethodOptions* MethodDescriptorProto::mutable_options() { + set_has_options(); + if (options_ == NULL) options_ = new ::google::protobuf::MethodOptions; + return options_; +} +inline ::google::protobuf::MethodOptions* MethodDescriptorProto::release_options() { + clear_has_options(); + ::google::protobuf::MethodOptions* temp = options_; + options_ = NULL; + return temp; +} + +// ------------------------------------------------------------------- + +// FileOptions + +// optional string java_package = 1; +inline bool FileOptions::has_java_package() const { + return (_has_bits_[0] & 0x00000001u) != 0; +} +inline void FileOptions::set_has_java_package() { + _has_bits_[0] |= 0x00000001u; +} +inline void FileOptions::clear_has_java_package() { + _has_bits_[0] &= ~0x00000001u; +} +inline void FileOptions::clear_java_package() { + if (java_package_ != &::google::protobuf::internal::kEmptyString) { + java_package_->clear(); + } + clear_has_java_package(); +} +inline const ::std::string& FileOptions::java_package() const { + return *java_package_; +} +inline void FileOptions::set_java_package(const ::std::string& value) { + set_has_java_package(); + if (java_package_ == &::google::protobuf::internal::kEmptyString) { + java_package_ = new ::std::string; + } + java_package_->assign(value); +} +inline void FileOptions::set_java_package(const char* value) { + set_has_java_package(); + if (java_package_ == &::google::protobuf::internal::kEmptyString) { + java_package_ = new ::std::string; + } + java_package_->assign(value); +} +inline void FileOptions::set_java_package(const char* value, size_t size) { + set_has_java_package(); + if (java_package_ == &::google::protobuf::internal::kEmptyString) { + java_package_ = new ::std::string; + } + java_package_->assign(reinterpret_cast(value), size); +} +inline ::std::string* FileOptions::mutable_java_package() { + set_has_java_package(); + if (java_package_ == &::google::protobuf::internal::kEmptyString) { + java_package_ = new ::std::string; + } + return java_package_; +} +inline ::std::string* FileOptions::release_java_package() { + clear_has_java_package(); + if (java_package_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = java_package_; + java_package_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} + +// optional string java_outer_classname = 8; +inline bool FileOptions::has_java_outer_classname() const { + return (_has_bits_[0] & 0x00000002u) != 0; +} +inline void FileOptions::set_has_java_outer_classname() { + _has_bits_[0] |= 0x00000002u; +} +inline void FileOptions::clear_has_java_outer_classname() { + _has_bits_[0] &= ~0x00000002u; +} +inline void FileOptions::clear_java_outer_classname() { + if (java_outer_classname_ != &::google::protobuf::internal::kEmptyString) { + java_outer_classname_->clear(); + } + clear_has_java_outer_classname(); +} +inline const ::std::string& FileOptions::java_outer_classname() const { + return *java_outer_classname_; +} +inline void FileOptions::set_java_outer_classname(const ::std::string& value) { + set_has_java_outer_classname(); + if (java_outer_classname_ == &::google::protobuf::internal::kEmptyString) { + java_outer_classname_ = new ::std::string; + } + java_outer_classname_->assign(value); +} +inline void FileOptions::set_java_outer_classname(const char* value) { + set_has_java_outer_classname(); + if (java_outer_classname_ == &::google::protobuf::internal::kEmptyString) { + java_outer_classname_ = new ::std::string; + } + java_outer_classname_->assign(value); +} +inline void FileOptions::set_java_outer_classname(const char* value, size_t size) { + set_has_java_outer_classname(); + if (java_outer_classname_ == &::google::protobuf::internal::kEmptyString) { + java_outer_classname_ = new ::std::string; + } + java_outer_classname_->assign(reinterpret_cast(value), size); +} +inline ::std::string* FileOptions::mutable_java_outer_classname() { + set_has_java_outer_classname(); + if (java_outer_classname_ == &::google::protobuf::internal::kEmptyString) { + java_outer_classname_ = new ::std::string; + } + return java_outer_classname_; +} +inline ::std::string* FileOptions::release_java_outer_classname() { + clear_has_java_outer_classname(); + if (java_outer_classname_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = java_outer_classname_; + java_outer_classname_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} + +// optional bool java_multiple_files = 10 [default = false]; +inline bool FileOptions::has_java_multiple_files() const { + return (_has_bits_[0] & 0x00000004u) != 0; +} +inline void FileOptions::set_has_java_multiple_files() { + _has_bits_[0] |= 0x00000004u; +} +inline void FileOptions::clear_has_java_multiple_files() { + _has_bits_[0] &= ~0x00000004u; +} +inline void FileOptions::clear_java_multiple_files() { + java_multiple_files_ = false; + clear_has_java_multiple_files(); +} +inline bool FileOptions::java_multiple_files() const { + return java_multiple_files_; +} +inline void FileOptions::set_java_multiple_files(bool value) { + set_has_java_multiple_files(); + java_multiple_files_ = value; +} + +// optional bool java_generate_equals_and_hash = 20 [default = false]; +inline bool FileOptions::has_java_generate_equals_and_hash() const { + return (_has_bits_[0] & 0x00000008u) != 0; +} +inline void FileOptions::set_has_java_generate_equals_and_hash() { + _has_bits_[0] |= 0x00000008u; +} +inline void FileOptions::clear_has_java_generate_equals_and_hash() { + _has_bits_[0] &= ~0x00000008u; +} +inline void FileOptions::clear_java_generate_equals_and_hash() { + java_generate_equals_and_hash_ = false; + clear_has_java_generate_equals_and_hash(); +} +inline bool FileOptions::java_generate_equals_and_hash() const { + return java_generate_equals_and_hash_; +} +inline void FileOptions::set_java_generate_equals_and_hash(bool value) { + set_has_java_generate_equals_and_hash(); + java_generate_equals_and_hash_ = value; +} + +// optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED]; +inline bool FileOptions::has_optimize_for() const { + return (_has_bits_[0] & 0x00000010u) != 0; +} +inline void FileOptions::set_has_optimize_for() { + _has_bits_[0] |= 0x00000010u; +} +inline void FileOptions::clear_has_optimize_for() { + _has_bits_[0] &= ~0x00000010u; +} +inline void FileOptions::clear_optimize_for() { + optimize_for_ = 1; + clear_has_optimize_for(); +} +inline ::google::protobuf::FileOptions_OptimizeMode FileOptions::optimize_for() const { + return static_cast< ::google::protobuf::FileOptions_OptimizeMode >(optimize_for_); +} +inline void FileOptions::set_optimize_for(::google::protobuf::FileOptions_OptimizeMode value) { + GOOGLE_DCHECK(::google::protobuf::FileOptions_OptimizeMode_IsValid(value)); + set_has_optimize_for(); + optimize_for_ = value; +} + +// optional bool cc_generic_services = 16 [default = false]; +inline bool FileOptions::has_cc_generic_services() const { + return (_has_bits_[0] & 0x00000020u) != 0; +} +inline void FileOptions::set_has_cc_generic_services() { + _has_bits_[0] |= 0x00000020u; +} +inline void FileOptions::clear_has_cc_generic_services() { + _has_bits_[0] &= ~0x00000020u; +} +inline void FileOptions::clear_cc_generic_services() { + cc_generic_services_ = false; + clear_has_cc_generic_services(); +} +inline bool FileOptions::cc_generic_services() const { + return cc_generic_services_; +} +inline void FileOptions::set_cc_generic_services(bool value) { + set_has_cc_generic_services(); + cc_generic_services_ = value; +} + +// optional bool java_generic_services = 17 [default = false]; +inline bool FileOptions::has_java_generic_services() const { + return (_has_bits_[0] & 0x00000040u) != 0; +} +inline void FileOptions::set_has_java_generic_services() { + _has_bits_[0] |= 0x00000040u; +} +inline void FileOptions::clear_has_java_generic_services() { + _has_bits_[0] &= ~0x00000040u; +} +inline void FileOptions::clear_java_generic_services() { + java_generic_services_ = false; + clear_has_java_generic_services(); +} +inline bool FileOptions::java_generic_services() const { + return java_generic_services_; +} +inline void FileOptions::set_java_generic_services(bool value) { + set_has_java_generic_services(); + java_generic_services_ = value; +} + +// optional bool py_generic_services = 18 [default = false]; +inline bool FileOptions::has_py_generic_services() const { + return (_has_bits_[0] & 0x00000080u) != 0; +} +inline void FileOptions::set_has_py_generic_services() { + _has_bits_[0] |= 0x00000080u; +} +inline void FileOptions::clear_has_py_generic_services() { + _has_bits_[0] &= ~0x00000080u; +} +inline void FileOptions::clear_py_generic_services() { + py_generic_services_ = false; + clear_has_py_generic_services(); +} +inline bool FileOptions::py_generic_services() const { + return py_generic_services_; +} +inline void FileOptions::set_py_generic_services(bool value) { + set_has_py_generic_services(); + py_generic_services_ = value; +} + +// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; +inline int FileOptions::uninterpreted_option_size() const { + return uninterpreted_option_.size(); +} +inline void FileOptions::clear_uninterpreted_option() { + uninterpreted_option_.Clear(); +} +inline const ::google::protobuf::UninterpretedOption& FileOptions::uninterpreted_option(int index) const { + return uninterpreted_option_.Get(index); +} +inline ::google::protobuf::UninterpretedOption* FileOptions::mutable_uninterpreted_option(int index) { + return uninterpreted_option_.Mutable(index); +} +inline ::google::protobuf::UninterpretedOption* FileOptions::add_uninterpreted_option() { + return uninterpreted_option_.Add(); +} +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +FileOptions::uninterpreted_option() const { + return uninterpreted_option_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* +FileOptions::mutable_uninterpreted_option() { + return &uninterpreted_option_; +} + +// ------------------------------------------------------------------- + +// MessageOptions + +// optional bool message_set_wire_format = 1 [default = false]; +inline bool MessageOptions::has_message_set_wire_format() const { + return (_has_bits_[0] & 0x00000001u) != 0; +} +inline void MessageOptions::set_has_message_set_wire_format() { + _has_bits_[0] |= 0x00000001u; +} +inline void MessageOptions::clear_has_message_set_wire_format() { + _has_bits_[0] &= ~0x00000001u; +} +inline void MessageOptions::clear_message_set_wire_format() { + message_set_wire_format_ = false; + clear_has_message_set_wire_format(); +} +inline bool MessageOptions::message_set_wire_format() const { + return message_set_wire_format_; +} +inline void MessageOptions::set_message_set_wire_format(bool value) { + set_has_message_set_wire_format(); + message_set_wire_format_ = value; +} + +// optional bool no_standard_descriptor_accessor = 2 [default = false]; +inline bool MessageOptions::has_no_standard_descriptor_accessor() const { + return (_has_bits_[0] & 0x00000002u) != 0; +} +inline void MessageOptions::set_has_no_standard_descriptor_accessor() { + _has_bits_[0] |= 0x00000002u; +} +inline void MessageOptions::clear_has_no_standard_descriptor_accessor() { + _has_bits_[0] &= ~0x00000002u; +} +inline void MessageOptions::clear_no_standard_descriptor_accessor() { + no_standard_descriptor_accessor_ = false; + clear_has_no_standard_descriptor_accessor(); +} +inline bool MessageOptions::no_standard_descriptor_accessor() const { + return no_standard_descriptor_accessor_; +} +inline void MessageOptions::set_no_standard_descriptor_accessor(bool value) { + set_has_no_standard_descriptor_accessor(); + no_standard_descriptor_accessor_ = value; +} + +// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; +inline int MessageOptions::uninterpreted_option_size() const { + return uninterpreted_option_.size(); +} +inline void MessageOptions::clear_uninterpreted_option() { + uninterpreted_option_.Clear(); +} +inline const ::google::protobuf::UninterpretedOption& MessageOptions::uninterpreted_option(int index) const { + return uninterpreted_option_.Get(index); +} +inline ::google::protobuf::UninterpretedOption* MessageOptions::mutable_uninterpreted_option(int index) { + return uninterpreted_option_.Mutable(index); +} +inline ::google::protobuf::UninterpretedOption* MessageOptions::add_uninterpreted_option() { + return uninterpreted_option_.Add(); +} +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +MessageOptions::uninterpreted_option() const { + return uninterpreted_option_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* +MessageOptions::mutable_uninterpreted_option() { + return &uninterpreted_option_; +} + +// ------------------------------------------------------------------- + +// FieldOptions + +// optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING]; +inline bool FieldOptions::has_ctype() const { + return (_has_bits_[0] & 0x00000001u) != 0; +} +inline void FieldOptions::set_has_ctype() { + _has_bits_[0] |= 0x00000001u; +} +inline void FieldOptions::clear_has_ctype() { + _has_bits_[0] &= ~0x00000001u; +} +inline void FieldOptions::clear_ctype() { + ctype_ = 0; + clear_has_ctype(); +} +inline ::google::protobuf::FieldOptions_CType FieldOptions::ctype() const { + return static_cast< ::google::protobuf::FieldOptions_CType >(ctype_); +} +inline void FieldOptions::set_ctype(::google::protobuf::FieldOptions_CType value) { + GOOGLE_DCHECK(::google::protobuf::FieldOptions_CType_IsValid(value)); + set_has_ctype(); + ctype_ = value; +} + +// optional bool packed = 2; +inline bool FieldOptions::has_packed() const { + return (_has_bits_[0] & 0x00000002u) != 0; +} +inline void FieldOptions::set_has_packed() { + _has_bits_[0] |= 0x00000002u; +} +inline void FieldOptions::clear_has_packed() { + _has_bits_[0] &= ~0x00000002u; +} +inline void FieldOptions::clear_packed() { + packed_ = false; + clear_has_packed(); +} +inline bool FieldOptions::packed() const { + return packed_; +} +inline void FieldOptions::set_packed(bool value) { + set_has_packed(); + packed_ = value; +} + +// optional bool deprecated = 3 [default = false]; +inline bool FieldOptions::has_deprecated() const { + return (_has_bits_[0] & 0x00000004u) != 0; +} +inline void FieldOptions::set_has_deprecated() { + _has_bits_[0] |= 0x00000004u; +} +inline void FieldOptions::clear_has_deprecated() { + _has_bits_[0] &= ~0x00000004u; +} +inline void FieldOptions::clear_deprecated() { + deprecated_ = false; + clear_has_deprecated(); +} +inline bool FieldOptions::deprecated() const { + return deprecated_; +} +inline void FieldOptions::set_deprecated(bool value) { + set_has_deprecated(); + deprecated_ = value; +} + +// optional string experimental_map_key = 9; +inline bool FieldOptions::has_experimental_map_key() const { + return (_has_bits_[0] & 0x00000008u) != 0; +} +inline void FieldOptions::set_has_experimental_map_key() { + _has_bits_[0] |= 0x00000008u; +} +inline void FieldOptions::clear_has_experimental_map_key() { + _has_bits_[0] &= ~0x00000008u; +} +inline void FieldOptions::clear_experimental_map_key() { + if (experimental_map_key_ != &::google::protobuf::internal::kEmptyString) { + experimental_map_key_->clear(); + } + clear_has_experimental_map_key(); +} +inline const ::std::string& FieldOptions::experimental_map_key() const { + return *experimental_map_key_; +} +inline void FieldOptions::set_experimental_map_key(const ::std::string& value) { + set_has_experimental_map_key(); + if (experimental_map_key_ == &::google::protobuf::internal::kEmptyString) { + experimental_map_key_ = new ::std::string; + } + experimental_map_key_->assign(value); +} +inline void FieldOptions::set_experimental_map_key(const char* value) { + set_has_experimental_map_key(); + if (experimental_map_key_ == &::google::protobuf::internal::kEmptyString) { + experimental_map_key_ = new ::std::string; + } + experimental_map_key_->assign(value); +} +inline void FieldOptions::set_experimental_map_key(const char* value, size_t size) { + set_has_experimental_map_key(); + if (experimental_map_key_ == &::google::protobuf::internal::kEmptyString) { + experimental_map_key_ = new ::std::string; + } + experimental_map_key_->assign(reinterpret_cast(value), size); +} +inline ::std::string* FieldOptions::mutable_experimental_map_key() { + set_has_experimental_map_key(); + if (experimental_map_key_ == &::google::protobuf::internal::kEmptyString) { + experimental_map_key_ = new ::std::string; + } + return experimental_map_key_; +} +inline ::std::string* FieldOptions::release_experimental_map_key() { + clear_has_experimental_map_key(); + if (experimental_map_key_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = experimental_map_key_; + experimental_map_key_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} + +// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; +inline int FieldOptions::uninterpreted_option_size() const { + return uninterpreted_option_.size(); +} +inline void FieldOptions::clear_uninterpreted_option() { + uninterpreted_option_.Clear(); +} +inline const ::google::protobuf::UninterpretedOption& FieldOptions::uninterpreted_option(int index) const { + return uninterpreted_option_.Get(index); +} +inline ::google::protobuf::UninterpretedOption* FieldOptions::mutable_uninterpreted_option(int index) { + return uninterpreted_option_.Mutable(index); +} +inline ::google::protobuf::UninterpretedOption* FieldOptions::add_uninterpreted_option() { + return uninterpreted_option_.Add(); +} +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +FieldOptions::uninterpreted_option() const { + return uninterpreted_option_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* +FieldOptions::mutable_uninterpreted_option() { + return &uninterpreted_option_; +} + +// ------------------------------------------------------------------- + +// EnumOptions + +// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; +inline int EnumOptions::uninterpreted_option_size() const { + return uninterpreted_option_.size(); +} +inline void EnumOptions::clear_uninterpreted_option() { + uninterpreted_option_.Clear(); +} +inline const ::google::protobuf::UninterpretedOption& EnumOptions::uninterpreted_option(int index) const { + return uninterpreted_option_.Get(index); +} +inline ::google::protobuf::UninterpretedOption* EnumOptions::mutable_uninterpreted_option(int index) { + return uninterpreted_option_.Mutable(index); +} +inline ::google::protobuf::UninterpretedOption* EnumOptions::add_uninterpreted_option() { + return uninterpreted_option_.Add(); +} +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +EnumOptions::uninterpreted_option() const { + return uninterpreted_option_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* +EnumOptions::mutable_uninterpreted_option() { + return &uninterpreted_option_; +} + +// ------------------------------------------------------------------- + +// EnumValueOptions + +// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; +inline int EnumValueOptions::uninterpreted_option_size() const { + return uninterpreted_option_.size(); +} +inline void EnumValueOptions::clear_uninterpreted_option() { + uninterpreted_option_.Clear(); +} +inline const ::google::protobuf::UninterpretedOption& EnumValueOptions::uninterpreted_option(int index) const { + return uninterpreted_option_.Get(index); +} +inline ::google::protobuf::UninterpretedOption* EnumValueOptions::mutable_uninterpreted_option(int index) { + return uninterpreted_option_.Mutable(index); +} +inline ::google::protobuf::UninterpretedOption* EnumValueOptions::add_uninterpreted_option() { + return uninterpreted_option_.Add(); +} +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +EnumValueOptions::uninterpreted_option() const { + return uninterpreted_option_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* +EnumValueOptions::mutable_uninterpreted_option() { + return &uninterpreted_option_; +} + +// ------------------------------------------------------------------- + +// ServiceOptions + +// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; +inline int ServiceOptions::uninterpreted_option_size() const { + return uninterpreted_option_.size(); +} +inline void ServiceOptions::clear_uninterpreted_option() { + uninterpreted_option_.Clear(); +} +inline const ::google::protobuf::UninterpretedOption& ServiceOptions::uninterpreted_option(int index) const { + return uninterpreted_option_.Get(index); +} +inline ::google::protobuf::UninterpretedOption* ServiceOptions::mutable_uninterpreted_option(int index) { + return uninterpreted_option_.Mutable(index); +} +inline ::google::protobuf::UninterpretedOption* ServiceOptions::add_uninterpreted_option() { + return uninterpreted_option_.Add(); +} +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +ServiceOptions::uninterpreted_option() const { + return uninterpreted_option_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* +ServiceOptions::mutable_uninterpreted_option() { + return &uninterpreted_option_; +} + +// ------------------------------------------------------------------- + +// MethodOptions + +// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; +inline int MethodOptions::uninterpreted_option_size() const { + return uninterpreted_option_.size(); +} +inline void MethodOptions::clear_uninterpreted_option() { + uninterpreted_option_.Clear(); +} +inline const ::google::protobuf::UninterpretedOption& MethodOptions::uninterpreted_option(int index) const { + return uninterpreted_option_.Get(index); +} +inline ::google::protobuf::UninterpretedOption* MethodOptions::mutable_uninterpreted_option(int index) { + return uninterpreted_option_.Mutable(index); +} +inline ::google::protobuf::UninterpretedOption* MethodOptions::add_uninterpreted_option() { + return uninterpreted_option_.Add(); +} +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +MethodOptions::uninterpreted_option() const { + return uninterpreted_option_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* +MethodOptions::mutable_uninterpreted_option() { + return &uninterpreted_option_; +} + +// ------------------------------------------------------------------- + +// UninterpretedOption_NamePart + +// required string name_part = 1; +inline bool UninterpretedOption_NamePart::has_name_part() const { + return (_has_bits_[0] & 0x00000001u) != 0; +} +inline void UninterpretedOption_NamePart::set_has_name_part() { + _has_bits_[0] |= 0x00000001u; +} +inline void UninterpretedOption_NamePart::clear_has_name_part() { + _has_bits_[0] &= ~0x00000001u; +} +inline void UninterpretedOption_NamePart::clear_name_part() { + if (name_part_ != &::google::protobuf::internal::kEmptyString) { + name_part_->clear(); + } + clear_has_name_part(); +} +inline const ::std::string& UninterpretedOption_NamePart::name_part() const { + return *name_part_; +} +inline void UninterpretedOption_NamePart::set_name_part(const ::std::string& value) { + set_has_name_part(); + if (name_part_ == &::google::protobuf::internal::kEmptyString) { + name_part_ = new ::std::string; + } + name_part_->assign(value); +} +inline void UninterpretedOption_NamePart::set_name_part(const char* value) { + set_has_name_part(); + if (name_part_ == &::google::protobuf::internal::kEmptyString) { + name_part_ = new ::std::string; + } + name_part_->assign(value); +} +inline void UninterpretedOption_NamePart::set_name_part(const char* value, size_t size) { + set_has_name_part(); + if (name_part_ == &::google::protobuf::internal::kEmptyString) { + name_part_ = new ::std::string; + } + name_part_->assign(reinterpret_cast(value), size); +} +inline ::std::string* UninterpretedOption_NamePart::mutable_name_part() { + set_has_name_part(); + if (name_part_ == &::google::protobuf::internal::kEmptyString) { + name_part_ = new ::std::string; + } + return name_part_; +} +inline ::std::string* UninterpretedOption_NamePart::release_name_part() { + clear_has_name_part(); + if (name_part_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = name_part_; + name_part_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} + +// required bool is_extension = 2; +inline bool UninterpretedOption_NamePart::has_is_extension() const { + return (_has_bits_[0] & 0x00000002u) != 0; +} +inline void UninterpretedOption_NamePart::set_has_is_extension() { + _has_bits_[0] |= 0x00000002u; +} +inline void UninterpretedOption_NamePart::clear_has_is_extension() { + _has_bits_[0] &= ~0x00000002u; +} +inline void UninterpretedOption_NamePart::clear_is_extension() { + is_extension_ = false; + clear_has_is_extension(); +} +inline bool UninterpretedOption_NamePart::is_extension() const { + return is_extension_; +} +inline void UninterpretedOption_NamePart::set_is_extension(bool value) { + set_has_is_extension(); + is_extension_ = value; +} + +// ------------------------------------------------------------------- + +// UninterpretedOption + +// repeated .google.protobuf.UninterpretedOption.NamePart name = 2; +inline int UninterpretedOption::name_size() const { + return name_.size(); +} +inline void UninterpretedOption::clear_name() { + name_.Clear(); +} +inline const ::google::protobuf::UninterpretedOption_NamePart& UninterpretedOption::name(int index) const { + return name_.Get(index); +} +inline ::google::protobuf::UninterpretedOption_NamePart* UninterpretedOption::mutable_name(int index) { + return name_.Mutable(index); +} +inline ::google::protobuf::UninterpretedOption_NamePart* UninterpretedOption::add_name() { + return name_.Add(); +} +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >& +UninterpretedOption::name() const { + return name_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >* +UninterpretedOption::mutable_name() { + return &name_; +} + +// optional string identifier_value = 3; +inline bool UninterpretedOption::has_identifier_value() const { + return (_has_bits_[0] & 0x00000002u) != 0; +} +inline void UninterpretedOption::set_has_identifier_value() { + _has_bits_[0] |= 0x00000002u; +} +inline void UninterpretedOption::clear_has_identifier_value() { + _has_bits_[0] &= ~0x00000002u; +} +inline void UninterpretedOption::clear_identifier_value() { + if (identifier_value_ != &::google::protobuf::internal::kEmptyString) { + identifier_value_->clear(); + } + clear_has_identifier_value(); +} +inline const ::std::string& UninterpretedOption::identifier_value() const { + return *identifier_value_; +} +inline void UninterpretedOption::set_identifier_value(const ::std::string& value) { + set_has_identifier_value(); + if (identifier_value_ == &::google::protobuf::internal::kEmptyString) { + identifier_value_ = new ::std::string; + } + identifier_value_->assign(value); +} +inline void UninterpretedOption::set_identifier_value(const char* value) { + set_has_identifier_value(); + if (identifier_value_ == &::google::protobuf::internal::kEmptyString) { + identifier_value_ = new ::std::string; + } + identifier_value_->assign(value); +} +inline void UninterpretedOption::set_identifier_value(const char* value, size_t size) { + set_has_identifier_value(); + if (identifier_value_ == &::google::protobuf::internal::kEmptyString) { + identifier_value_ = new ::std::string; + } + identifier_value_->assign(reinterpret_cast(value), size); +} +inline ::std::string* UninterpretedOption::mutable_identifier_value() { + set_has_identifier_value(); + if (identifier_value_ == &::google::protobuf::internal::kEmptyString) { + identifier_value_ = new ::std::string; + } + return identifier_value_; +} +inline ::std::string* UninterpretedOption::release_identifier_value() { + clear_has_identifier_value(); + if (identifier_value_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = identifier_value_; + identifier_value_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} + +// optional uint64 positive_int_value = 4; +inline bool UninterpretedOption::has_positive_int_value() const { + return (_has_bits_[0] & 0x00000004u) != 0; +} +inline void UninterpretedOption::set_has_positive_int_value() { + _has_bits_[0] |= 0x00000004u; +} +inline void UninterpretedOption::clear_has_positive_int_value() { + _has_bits_[0] &= ~0x00000004u; +} +inline void UninterpretedOption::clear_positive_int_value() { + positive_int_value_ = GOOGLE_ULONGLONG(0); + clear_has_positive_int_value(); +} +inline ::google::protobuf::uint64 UninterpretedOption::positive_int_value() const { + return positive_int_value_; +} +inline void UninterpretedOption::set_positive_int_value(::google::protobuf::uint64 value) { + set_has_positive_int_value(); + positive_int_value_ = value; +} + +// optional int64 negative_int_value = 5; +inline bool UninterpretedOption::has_negative_int_value() const { + return (_has_bits_[0] & 0x00000008u) != 0; +} +inline void UninterpretedOption::set_has_negative_int_value() { + _has_bits_[0] |= 0x00000008u; +} +inline void UninterpretedOption::clear_has_negative_int_value() { + _has_bits_[0] &= ~0x00000008u; +} +inline void UninterpretedOption::clear_negative_int_value() { + negative_int_value_ = GOOGLE_LONGLONG(0); + clear_has_negative_int_value(); +} +inline ::google::protobuf::int64 UninterpretedOption::negative_int_value() const { + return negative_int_value_; +} +inline void UninterpretedOption::set_negative_int_value(::google::protobuf::int64 value) { + set_has_negative_int_value(); + negative_int_value_ = value; +} + +// optional double double_value = 6; +inline bool UninterpretedOption::has_double_value() const { + return (_has_bits_[0] & 0x00000010u) != 0; +} +inline void UninterpretedOption::set_has_double_value() { + _has_bits_[0] |= 0x00000010u; +} +inline void UninterpretedOption::clear_has_double_value() { + _has_bits_[0] &= ~0x00000010u; +} +inline void UninterpretedOption::clear_double_value() { + double_value_ = 0; + clear_has_double_value(); +} +inline double UninterpretedOption::double_value() const { + return double_value_; +} +inline void UninterpretedOption::set_double_value(double value) { + set_has_double_value(); + double_value_ = value; +} + +// optional bytes string_value = 7; +inline bool UninterpretedOption::has_string_value() const { + return (_has_bits_[0] & 0x00000020u) != 0; +} +inline void UninterpretedOption::set_has_string_value() { + _has_bits_[0] |= 0x00000020u; +} +inline void UninterpretedOption::clear_has_string_value() { + _has_bits_[0] &= ~0x00000020u; +} +inline void UninterpretedOption::clear_string_value() { + if (string_value_ != &::google::protobuf::internal::kEmptyString) { + string_value_->clear(); + } + clear_has_string_value(); +} +inline const ::std::string& UninterpretedOption::string_value() const { + return *string_value_; +} +inline void UninterpretedOption::set_string_value(const ::std::string& value) { + set_has_string_value(); + if (string_value_ == &::google::protobuf::internal::kEmptyString) { + string_value_ = new ::std::string; + } + string_value_->assign(value); +} +inline void UninterpretedOption::set_string_value(const char* value) { + set_has_string_value(); + if (string_value_ == &::google::protobuf::internal::kEmptyString) { + string_value_ = new ::std::string; + } + string_value_->assign(value); +} +inline void UninterpretedOption::set_string_value(const void* value, size_t size) { + set_has_string_value(); + if (string_value_ == &::google::protobuf::internal::kEmptyString) { + string_value_ = new ::std::string; + } + string_value_->assign(reinterpret_cast(value), size); +} +inline ::std::string* UninterpretedOption::mutable_string_value() { + set_has_string_value(); + if (string_value_ == &::google::protobuf::internal::kEmptyString) { + string_value_ = new ::std::string; + } + return string_value_; +} +inline ::std::string* UninterpretedOption::release_string_value() { + clear_has_string_value(); + if (string_value_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = string_value_; + string_value_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} + +// optional string aggregate_value = 8; +inline bool UninterpretedOption::has_aggregate_value() const { + return (_has_bits_[0] & 0x00000040u) != 0; +} +inline void UninterpretedOption::set_has_aggregate_value() { + _has_bits_[0] |= 0x00000040u; +} +inline void UninterpretedOption::clear_has_aggregate_value() { + _has_bits_[0] &= ~0x00000040u; +} +inline void UninterpretedOption::clear_aggregate_value() { + if (aggregate_value_ != &::google::protobuf::internal::kEmptyString) { + aggregate_value_->clear(); + } + clear_has_aggregate_value(); +} +inline const ::std::string& UninterpretedOption::aggregate_value() const { + return *aggregate_value_; +} +inline void UninterpretedOption::set_aggregate_value(const ::std::string& value) { + set_has_aggregate_value(); + if (aggregate_value_ == &::google::protobuf::internal::kEmptyString) { + aggregate_value_ = new ::std::string; + } + aggregate_value_->assign(value); +} +inline void UninterpretedOption::set_aggregate_value(const char* value) { + set_has_aggregate_value(); + if (aggregate_value_ == &::google::protobuf::internal::kEmptyString) { + aggregate_value_ = new ::std::string; + } + aggregate_value_->assign(value); +} +inline void UninterpretedOption::set_aggregate_value(const char* value, size_t size) { + set_has_aggregate_value(); + if (aggregate_value_ == &::google::protobuf::internal::kEmptyString) { + aggregate_value_ = new ::std::string; + } + aggregate_value_->assign(reinterpret_cast(value), size); +} +inline ::std::string* UninterpretedOption::mutable_aggregate_value() { + set_has_aggregate_value(); + if (aggregate_value_ == &::google::protobuf::internal::kEmptyString) { + aggregate_value_ = new ::std::string; + } + return aggregate_value_; +} +inline ::std::string* UninterpretedOption::release_aggregate_value() { + clear_has_aggregate_value(); + if (aggregate_value_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = aggregate_value_; + aggregate_value_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} + +// ------------------------------------------------------------------- + +// SourceCodeInfo_Location + +// repeated int32 path = 1 [packed = true]; +inline int SourceCodeInfo_Location::path_size() const { + return path_.size(); +} +inline void SourceCodeInfo_Location::clear_path() { + path_.Clear(); +} +inline ::google::protobuf::int32 SourceCodeInfo_Location::path(int index) const { + return path_.Get(index); +} +inline void SourceCodeInfo_Location::set_path(int index, ::google::protobuf::int32 value) { + path_.Set(index, value); +} +inline void SourceCodeInfo_Location::add_path(::google::protobuf::int32 value) { + path_.Add(value); +} +inline const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >& +SourceCodeInfo_Location::path() const { + return path_; +} +inline ::google::protobuf::RepeatedField< ::google::protobuf::int32 >* +SourceCodeInfo_Location::mutable_path() { + return &path_; +} + +// repeated int32 span = 2 [packed = true]; +inline int SourceCodeInfo_Location::span_size() const { + return span_.size(); +} +inline void SourceCodeInfo_Location::clear_span() { + span_.Clear(); +} +inline ::google::protobuf::int32 SourceCodeInfo_Location::span(int index) const { + return span_.Get(index); +} +inline void SourceCodeInfo_Location::set_span(int index, ::google::protobuf::int32 value) { + span_.Set(index, value); +} +inline void SourceCodeInfo_Location::add_span(::google::protobuf::int32 value) { + span_.Add(value); +} +inline const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >& +SourceCodeInfo_Location::span() const { + return span_; +} +inline ::google::protobuf::RepeatedField< ::google::protobuf::int32 >* +SourceCodeInfo_Location::mutable_span() { + return &span_; +} + +// ------------------------------------------------------------------- + +// SourceCodeInfo + +// repeated .google.protobuf.SourceCodeInfo.Location location = 1; +inline int SourceCodeInfo::location_size() const { + return location_.size(); +} +inline void SourceCodeInfo::clear_location() { + location_.Clear(); +} +inline const ::google::protobuf::SourceCodeInfo_Location& SourceCodeInfo::location(int index) const { + return location_.Get(index); +} +inline ::google::protobuf::SourceCodeInfo_Location* SourceCodeInfo::mutable_location(int index) { + return location_.Mutable(index); +} +inline ::google::protobuf::SourceCodeInfo_Location* SourceCodeInfo::add_location() { + return location_.Add(); +} +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::SourceCodeInfo_Location >& +SourceCodeInfo::location() const { + return location_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::SourceCodeInfo_Location >* +SourceCodeInfo::mutable_location() { + return &location_; +} + + +// @@protoc_insertion_point(namespace_scope) + +} // namespace protobuf +} // namespace google + +#ifndef SWIG +namespace google { +namespace protobuf { + +template <> +inline const EnumDescriptor* GetEnumDescriptor< ::google::protobuf::FieldDescriptorProto_Type>() { + return ::google::protobuf::FieldDescriptorProto_Type_descriptor(); +} +template <> +inline const EnumDescriptor* GetEnumDescriptor< ::google::protobuf::FieldDescriptorProto_Label>() { + return ::google::protobuf::FieldDescriptorProto_Label_descriptor(); +} +template <> +inline const EnumDescriptor* GetEnumDescriptor< ::google::protobuf::FileOptions_OptimizeMode>() { + return ::google::protobuf::FileOptions_OptimizeMode_descriptor(); +} +template <> +inline const EnumDescriptor* GetEnumDescriptor< ::google::protobuf::FieldOptions_CType>() { + return ::google::protobuf::FieldOptions_CType_descriptor(); +} + +} // namespace google +} // namespace protobuf +#endif // SWIG + +// @@protoc_insertion_point(global_scope) + +#endif // PROTOBUF_google_2fprotobuf_2fdescriptor_2eproto__INCLUDED diff --git a/depends/protobuf/google/protobuf/descriptor_database.cc b/depends/protobuf/google/protobuf/descriptor_database.cc new file mode 100644 index 0000000000..23e48a67f5 --- /dev/null +++ b/depends/protobuf/google/protobuf/descriptor_database.cc @@ -0,0 +1,541 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include + +#include + +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { + +DescriptorDatabase::~DescriptorDatabase() {} + +// =================================================================== + +template +bool SimpleDescriptorDatabase::DescriptorIndex::AddFile( + const FileDescriptorProto& file, + Value value) { + if (!InsertIfNotPresent(&by_name_, file.name(), value)) { + GOOGLE_LOG(ERROR) << "File already exists in database: " << file.name(); + return false; + } + + // We must be careful here -- calling file.package() if file.has_package() is + // false could access an uninitialized static-storage variable if we are being + // run at startup time. + string path = file.has_package() ? file.package() : string(); + if (!path.empty()) path += '.'; + + for (int i = 0; i < file.message_type_size(); i++) { + if (!AddSymbol(path + file.message_type(i).name(), value)) return false; + if (!AddNestedExtensions(file.message_type(i), value)) return false; + } + for (int i = 0; i < file.enum_type_size(); i++) { + if (!AddSymbol(path + file.enum_type(i).name(), value)) return false; + } + for (int i = 0; i < file.extension_size(); i++) { + if (!AddSymbol(path + file.extension(i).name(), value)) return false; + if (!AddExtension(file.extension(i), value)) return false; + } + for (int i = 0; i < file.service_size(); i++) { + if (!AddSymbol(path + file.service(i).name(), value)) return false; + } + + return true; +} + +template +bool SimpleDescriptorDatabase::DescriptorIndex::AddSymbol( + const string& name, Value value) { + // We need to make sure not to violate our map invariant. + + // If the symbol name is invalid it could break our lookup algorithm (which + // relies on the fact that '.' sorts before all other characters that are + // valid in symbol names). + if (!ValidateSymbolName(name)) { + GOOGLE_LOG(ERROR) << "Invalid symbol name: " << name; + return false; + } + + // Try to look up the symbol to make sure a super-symbol doesn't already + // exist. + typename map::iterator iter = FindLastLessOrEqual(name); + + if (iter == by_symbol_.end()) { + // Apparently the map is currently empty. Just insert and be done with it. + by_symbol_.insert(typename map::value_type(name, value)); + return true; + } + + if (IsSubSymbol(iter->first, name)) { + GOOGLE_LOG(ERROR) << "Symbol name \"" << name << "\" conflicts with the existing " + "symbol \"" << iter->first << "\"."; + return false; + } + + // OK, that worked. Now we have to make sure that no symbol in the map is + // a sub-symbol of the one we are inserting. The only symbol which could + // be so is the first symbol that is greater than the new symbol. Since + // |iter| points at the last symbol that is less than or equal, we just have + // to increment it. + ++iter; + + if (iter != by_symbol_.end() && IsSubSymbol(name, iter->first)) { + GOOGLE_LOG(ERROR) << "Symbol name \"" << name << "\" conflicts with the existing " + "symbol \"" << iter->first << "\"."; + return false; + } + + // OK, no conflicts. + + // Insert the new symbol using the iterator as a hint, the new entry will + // appear immediately before the one the iterator is pointing at. + by_symbol_.insert(iter, typename map::value_type(name, value)); + + return true; +} + +template +bool SimpleDescriptorDatabase::DescriptorIndex::AddNestedExtensions( + const DescriptorProto& message_type, + Value value) { + for (int i = 0; i < message_type.nested_type_size(); i++) { + if (!AddNestedExtensions(message_type.nested_type(i), value)) return false; + } + for (int i = 0; i < message_type.extension_size(); i++) { + if (!AddExtension(message_type.extension(i), value)) return false; + } + return true; +} + +template +bool SimpleDescriptorDatabase::DescriptorIndex::AddExtension( + const FieldDescriptorProto& field, + Value value) { + if (!field.extendee().empty() && field.extendee()[0] == '.') { + // The extension is fully-qualified. We can use it as a lookup key in + // the by_symbol_ table. + if (!InsertIfNotPresent(&by_extension_, + make_pair(field.extendee().substr(1), + field.number()), + value)) { + GOOGLE_LOG(ERROR) << "Extension conflicts with extension already in database: " + "extend " << field.extendee() << " { " + << field.name() << " = " << field.number() << " }"; + return false; + } + } else { + // Not fully-qualified. We can't really do anything here, unfortunately. + // We don't consider this an error, though, because the descriptor is + // valid. + } + return true; +} + +template +Value SimpleDescriptorDatabase::DescriptorIndex::FindFile( + const string& filename) { + return FindWithDefault(by_name_, filename, Value()); +} + +template +Value SimpleDescriptorDatabase::DescriptorIndex::FindSymbol( + const string& name) { + typename map::iterator iter = FindLastLessOrEqual(name); + + return (iter != by_symbol_.end() && IsSubSymbol(iter->first, name)) ? + iter->second : Value(); +} + +template +Value SimpleDescriptorDatabase::DescriptorIndex::FindExtension( + const string& containing_type, + int field_number) { + return FindWithDefault(by_extension_, + make_pair(containing_type, field_number), + Value()); +} + +template +bool SimpleDescriptorDatabase::DescriptorIndex::FindAllExtensionNumbers( + const string& containing_type, + vector* output) { + typename map, Value >::const_iterator it = + by_extension_.lower_bound(make_pair(containing_type, 0)); + bool success = false; + + for (; it != by_extension_.end() && it->first.first == containing_type; + ++it) { + output->push_back(it->first.second); + success = true; + } + + return success; +} + +template +typename map::iterator +SimpleDescriptorDatabase::DescriptorIndex::FindLastLessOrEqual( + const string& name) { + // Find the last key in the map which sorts less than or equal to the + // symbol name. Since upper_bound() returns the *first* key that sorts + // *greater* than the input, we want the element immediately before that. + typename map::iterator iter = by_symbol_.upper_bound(name); + if (iter != by_symbol_.begin()) --iter; + return iter; +} + +template +bool SimpleDescriptorDatabase::DescriptorIndex::IsSubSymbol( + const string& sub_symbol, const string& super_symbol) { + return sub_symbol == super_symbol || + (HasPrefixString(super_symbol, sub_symbol) && + super_symbol[sub_symbol.size()] == '.'); +} + +template +bool SimpleDescriptorDatabase::DescriptorIndex::ValidateSymbolName( + const string& name) { + for (int i = 0; i < name.size(); i++) { + // I don't trust ctype.h due to locales. :( + if (name[i] != '.' && name[i] != '_' && + (name[i] < '0' || name[i] > '9') && + (name[i] < 'A' || name[i] > 'Z') && + (name[i] < 'a' || name[i] > 'z')) { + return false; + } + } + return true; +} + +// ------------------------------------------------------------------- + +SimpleDescriptorDatabase::SimpleDescriptorDatabase() {} +SimpleDescriptorDatabase::~SimpleDescriptorDatabase() { + STLDeleteElements(&files_to_delete_); +} + +bool SimpleDescriptorDatabase::Add(const FileDescriptorProto& file) { + FileDescriptorProto* new_file = new FileDescriptorProto; + new_file->CopyFrom(file); + return AddAndOwn(new_file); +} + +bool SimpleDescriptorDatabase::AddAndOwn(const FileDescriptorProto* file) { + files_to_delete_.push_back(file); + return index_.AddFile(*file, file); +} + +bool SimpleDescriptorDatabase::FindFileByName( + const string& filename, + FileDescriptorProto* output) { + return MaybeCopy(index_.FindFile(filename), output); +} + +bool SimpleDescriptorDatabase::FindFileContainingSymbol( + const string& symbol_name, + FileDescriptorProto* output) { + return MaybeCopy(index_.FindSymbol(symbol_name), output); +} + +bool SimpleDescriptorDatabase::FindFileContainingExtension( + const string& containing_type, + int field_number, + FileDescriptorProto* output) { + return MaybeCopy(index_.FindExtension(containing_type, field_number), output); +} + +bool SimpleDescriptorDatabase::FindAllExtensionNumbers( + const string& extendee_type, + vector* output) { + return index_.FindAllExtensionNumbers(extendee_type, output); +} + +bool SimpleDescriptorDatabase::MaybeCopy(const FileDescriptorProto* file, + FileDescriptorProto* output) { + if (file == NULL) return false; + output->CopyFrom(*file); + return true; +} + +// ------------------------------------------------------------------- + +EncodedDescriptorDatabase::EncodedDescriptorDatabase() {} +EncodedDescriptorDatabase::~EncodedDescriptorDatabase() { + for (int i = 0; i < files_to_delete_.size(); i++) { + operator delete(files_to_delete_[i]); + } +} + +bool EncodedDescriptorDatabase::Add( + const void* encoded_file_descriptor, int size) { + FileDescriptorProto file; + if (file.ParseFromArray(encoded_file_descriptor, size)) { + return index_.AddFile(file, make_pair(encoded_file_descriptor, size)); + } else { + GOOGLE_LOG(ERROR) << "Invalid file descriptor data passed to " + "EncodedDescriptorDatabase::Add()."; + return false; + } +} + +bool EncodedDescriptorDatabase::AddCopy( + const void* encoded_file_descriptor, int size) { + void* copy = operator new(size); + memcpy(copy, encoded_file_descriptor, size); + files_to_delete_.push_back(copy); + return Add(copy, size); +} + +bool EncodedDescriptorDatabase::FindFileByName( + const string& filename, + FileDescriptorProto* output) { + return MaybeParse(index_.FindFile(filename), output); +} + +bool EncodedDescriptorDatabase::FindFileContainingSymbol( + const string& symbol_name, + FileDescriptorProto* output) { + return MaybeParse(index_.FindSymbol(symbol_name), output); +} + +bool EncodedDescriptorDatabase::FindNameOfFileContainingSymbol( + const string& symbol_name, + string* output) { + pair encoded_file = index_.FindSymbol(symbol_name); + if (encoded_file.first == NULL) return false; + + // Optimization: The name should be the first field in the encoded message. + // Try to just read it directly. + io::CodedInputStream input(reinterpret_cast(encoded_file.first), + encoded_file.second); + + const uint32 kNameTag = internal::WireFormatLite::MakeTag( + FileDescriptorProto::kNameFieldNumber, + internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED); + + if (input.ReadTag() == kNameTag) { + // Success! + return internal::WireFormatLite::ReadString(&input, output); + } else { + // Slow path. Parse whole message. + FileDescriptorProto file_proto; + if (!file_proto.ParseFromArray(encoded_file.first, encoded_file.second)) { + return false; + } + *output = file_proto.name(); + return true; + } +} + +bool EncodedDescriptorDatabase::FindFileContainingExtension( + const string& containing_type, + int field_number, + FileDescriptorProto* output) { + return MaybeParse(index_.FindExtension(containing_type, field_number), + output); +} + +bool EncodedDescriptorDatabase::FindAllExtensionNumbers( + const string& extendee_type, + vector* output) { + return index_.FindAllExtensionNumbers(extendee_type, output); +} + +bool EncodedDescriptorDatabase::MaybeParse( + pair encoded_file, + FileDescriptorProto* output) { + if (encoded_file.first == NULL) return false; + return output->ParseFromArray(encoded_file.first, encoded_file.second); +} + +// =================================================================== + +DescriptorPoolDatabase::DescriptorPoolDatabase(const DescriptorPool& pool) + : pool_(pool) {} +DescriptorPoolDatabase::~DescriptorPoolDatabase() {} + +bool DescriptorPoolDatabase::FindFileByName( + const string& filename, + FileDescriptorProto* output) { + const FileDescriptor* file = pool_.FindFileByName(filename); + if (file == NULL) return false; + output->Clear(); + file->CopyTo(output); + return true; +} + +bool DescriptorPoolDatabase::FindFileContainingSymbol( + const string& symbol_name, + FileDescriptorProto* output) { + const FileDescriptor* file = pool_.FindFileContainingSymbol(symbol_name); + if (file == NULL) return false; + output->Clear(); + file->CopyTo(output); + return true; +} + +bool DescriptorPoolDatabase::FindFileContainingExtension( + const string& containing_type, + int field_number, + FileDescriptorProto* output) { + const Descriptor* extendee = pool_.FindMessageTypeByName(containing_type); + if (extendee == NULL) return false; + + const FieldDescriptor* extension = + pool_.FindExtensionByNumber(extendee, field_number); + if (extension == NULL) return false; + + output->Clear(); + extension->file()->CopyTo(output); + return true; +} + +bool DescriptorPoolDatabase::FindAllExtensionNumbers( + const string& extendee_type, + vector* output) { + const Descriptor* extendee = pool_.FindMessageTypeByName(extendee_type); + if (extendee == NULL) return false; + + vector extensions; + pool_.FindAllExtensions(extendee, &extensions); + + for (int i = 0; i < extensions.size(); ++i) { + output->push_back(extensions[i]->number()); + } + + return true; +} + +// =================================================================== + +MergedDescriptorDatabase::MergedDescriptorDatabase( + DescriptorDatabase* source1, + DescriptorDatabase* source2) { + sources_.push_back(source1); + sources_.push_back(source2); +} +MergedDescriptorDatabase::MergedDescriptorDatabase( + const vector& sources) + : sources_(sources) {} +MergedDescriptorDatabase::~MergedDescriptorDatabase() {} + +bool MergedDescriptorDatabase::FindFileByName( + const string& filename, + FileDescriptorProto* output) { + for (int i = 0; i < sources_.size(); i++) { + if (sources_[i]->FindFileByName(filename, output)) { + return true; + } + } + return false; +} + +bool MergedDescriptorDatabase::FindFileContainingSymbol( + const string& symbol_name, + FileDescriptorProto* output) { + for (int i = 0; i < sources_.size(); i++) { + if (sources_[i]->FindFileContainingSymbol(symbol_name, output)) { + // The symbol was found in source i. However, if one of the previous + // sources defines a file with the same name (which presumably doesn't + // contain the symbol, since it wasn't found in that source), then we + // must hide it from the caller. + FileDescriptorProto temp; + for (int j = 0; j < i; j++) { + if (sources_[j]->FindFileByName(output->name(), &temp)) { + // Found conflicting file in a previous source. + return false; + } + } + return true; + } + } + return false; +} + +bool MergedDescriptorDatabase::FindFileContainingExtension( + const string& containing_type, + int field_number, + FileDescriptorProto* output) { + for (int i = 0; i < sources_.size(); i++) { + if (sources_[i]->FindFileContainingExtension( + containing_type, field_number, output)) { + // The symbol was found in source i. However, if one of the previous + // sources defines a file with the same name (which presumably doesn't + // contain the symbol, since it wasn't found in that source), then we + // must hide it from the caller. + FileDescriptorProto temp; + for (int j = 0; j < i; j++) { + if (sources_[j]->FindFileByName(output->name(), &temp)) { + // Found conflicting file in a previous source. + return false; + } + } + return true; + } + } + return false; +} + +bool MergedDescriptorDatabase::FindAllExtensionNumbers( + const string& extendee_type, + vector* output) { + set merged_results; + vector results; + bool success = false; + + for (int i = 0; i < sources_.size(); i++) { + if (sources_[i]->FindAllExtensionNumbers(extendee_type, &results)) { + copy(results.begin(), results.end(), + insert_iterator >(merged_results, merged_results.begin())); + success = true; + } + results.clear(); + } + + copy(merged_results.begin(), merged_results.end(), + insert_iterator >(*output, output->end())); + + return success; +} + +} // namespace protobuf +} // namespace google diff --git a/depends/protobuf/google/protobuf/descriptor_database.h b/depends/protobuf/google/protobuf/descriptor_database.h new file mode 100644 index 0000000000..f32b1db935 --- /dev/null +++ b/depends/protobuf/google/protobuf/descriptor_database.h @@ -0,0 +1,366 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// Interface for manipulating databases of descriptors. + +#ifndef GOOGLE_PROTOBUF_DESCRIPTOR_DATABASE_H__ +#define GOOGLE_PROTOBUF_DESCRIPTOR_DATABASE_H__ + +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { + +// Defined in this file. +class DescriptorDatabase; +class SimpleDescriptorDatabase; +class EncodedDescriptorDatabase; +class DescriptorPoolDatabase; +class MergedDescriptorDatabase; + +// Abstract interface for a database of descriptors. +// +// This is useful if you want to create a DescriptorPool which loads +// descriptors on-demand from some sort of large database. If the database +// is large, it may be inefficient to enumerate every .proto file inside it +// calling DescriptorPool::BuildFile() for each one. Instead, a DescriptorPool +// can be created which wraps a DescriptorDatabase and only builds particular +// descriptors when they are needed. +class LIBPROTOBUF_EXPORT DescriptorDatabase { + public: + inline DescriptorDatabase() {} + virtual ~DescriptorDatabase(); + + // Find a file by file name. Fills in in *output and returns true if found. + // Otherwise, returns false, leaving the contents of *output undefined. + virtual bool FindFileByName(const string& filename, + FileDescriptorProto* output) = 0; + + // Find the file that declares the given fully-qualified symbol name. + // If found, fills in *output and returns true, otherwise returns false + // and leaves *output undefined. + virtual bool FindFileContainingSymbol(const string& symbol_name, + FileDescriptorProto* output) = 0; + + // Find the file which defines an extension extending the given message type + // with the given field number. If found, fills in *output and returns true, + // otherwise returns false and leaves *output undefined. containing_type + // must be a fully-qualified type name. + virtual bool FindFileContainingExtension(const string& containing_type, + int field_number, + FileDescriptorProto* output) = 0; + + // Finds the tag numbers used by all known extensions of + // extendee_type, and appends them to output in an undefined + // order. This method is best-effort: it's not guaranteed that the + // database will find all extensions, and it's not guaranteed that + // FindFileContainingExtension will return true on all of the found + // numbers. Returns true if the search was successful, otherwise + // returns false and leaves output unchanged. + // + // This method has a default implementation that always returns + // false. + virtual bool FindAllExtensionNumbers(const string& extendee_type, + vector* output) { + return false; + } + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DescriptorDatabase); +}; + +// A DescriptorDatabase into which you can insert files manually. +// +// FindFileContainingSymbol() is fully-implemented. When you add a file, its +// symbols will be indexed for this purpose. Note that the implementation +// may return false positives, but only if it isn't possible for the symbol +// to be defined in any other file. In particular, if a file defines a symbol +// "Foo", then searching for "Foo.[anything]" will match that file. This way, +// the database does not need to aggressively index all children of a symbol. +// +// FindFileContainingExtension() is mostly-implemented. It works if and only +// if the original FieldDescriptorProto defining the extension has a +// fully-qualified type name in its "extendee" field (i.e. starts with a '.'). +// If the extendee is a relative name, SimpleDescriptorDatabase will not +// attempt to resolve the type, so it will not know what type the extension is +// extending. Therefore, calling FindFileContainingExtension() with the +// extension's containing type will never actually find that extension. Note +// that this is an unlikely problem, as all FileDescriptorProtos created by the +// protocol compiler (as well as ones created by calling +// FileDescriptor::CopyTo()) will always use fully-qualified names for all +// types. You only need to worry if you are constructing FileDescriptorProtos +// yourself, or are calling compiler::Parser directly. +class LIBPROTOBUF_EXPORT SimpleDescriptorDatabase : public DescriptorDatabase { + public: + SimpleDescriptorDatabase(); + ~SimpleDescriptorDatabase(); + + // Adds the FileDescriptorProto to the database, making a copy. The object + // can be deleted after Add() returns. Returns false if the file conflicted + // with a file already in the database, in which case an error will have + // been written to GOOGLE_LOG(ERROR). + bool Add(const FileDescriptorProto& file); + + // Adds the FileDescriptorProto to the database and takes ownership of it. + bool AddAndOwn(const FileDescriptorProto* file); + + // implements DescriptorDatabase ----------------------------------- + bool FindFileByName(const string& filename, + FileDescriptorProto* output); + bool FindFileContainingSymbol(const string& symbol_name, + FileDescriptorProto* output); + bool FindFileContainingExtension(const string& containing_type, + int field_number, + FileDescriptorProto* output); + bool FindAllExtensionNumbers(const string& extendee_type, + vector* output); + + private: + // So that it can use DescriptorIndex. + friend class EncodedDescriptorDatabase; + + // An index mapping file names, symbol names, and extension numbers to + // some sort of values. + template + class DescriptorIndex { + public: + // Helpers to recursively add particular descriptors and all their contents + // to the index. + bool AddFile(const FileDescriptorProto& file, + Value value); + bool AddSymbol(const string& name, Value value); + bool AddNestedExtensions(const DescriptorProto& message_type, + Value value); + bool AddExtension(const FieldDescriptorProto& field, + Value value); + + Value FindFile(const string& filename); + Value FindSymbol(const string& name); + Value FindExtension(const string& containing_type, int field_number); + bool FindAllExtensionNumbers(const string& containing_type, + vector* output); + + private: + map by_name_; + map by_symbol_; + map, Value> by_extension_; + + // Invariant: The by_symbol_ map does not contain any symbols which are + // prefixes of other symbols in the map. For example, "foo.bar" is a + // prefix of "foo.bar.baz" (but is not a prefix of "foo.barbaz"). + // + // This invariant is important because it means that given a symbol name, + // we can find a key in the map which is a prefix of the symbol in O(lg n) + // time, and we know that there is at most one such key. + // + // The prefix lookup algorithm works like so: + // 1) Find the last key in the map which is less than or equal to the + // search key. + // 2) If the found key is a prefix of the search key, then return it. + // Otherwise, there is no match. + // + // I am sure this algorithm has been described elsewhere, but since I + // wasn't able to find it quickly I will instead prove that it works + // myself. The key to the algorithm is that if a match exists, step (1) + // will find it. Proof: + // 1) Define the "search key" to be the key we are looking for, the "found + // key" to be the key found in step (1), and the "match key" to be the + // key which actually matches the serach key (i.e. the key we're trying + // to find). + // 2) The found key must be less than or equal to the search key by + // definition. + // 3) The match key must also be less than or equal to the search key + // (because it is a prefix). + // 4) The match key cannot be greater than the found key, because if it + // were, then step (1) of the algorithm would have returned the match + // key instead (since it finds the *greatest* key which is less than or + // equal to the search key). + // 5) Therefore, the found key must be between the match key and the search + // key, inclusive. + // 6) Since the search key must be a sub-symbol of the match key, if it is + // not equal to the match key, then search_key[match_key.size()] must + // be '.'. + // 7) Since '.' sorts before any other character that is valid in a symbol + // name, then if the found key is not equal to the match key, then + // found_key[match_key.size()] must also be '.', because any other value + // would make it sort after the search key. + // 8) Therefore, if the found key is not equal to the match key, then the + // found key must be a sub-symbol of the match key. However, this would + // contradict our map invariant which says that no symbol in the map is + // a sub-symbol of any other. + // 9) Therefore, the found key must match the match key. + // + // The above proof assumes the match key exists. In the case that the + // match key does not exist, then step (1) will return some other symbol. + // That symbol cannot be a super-symbol of the search key since if it were, + // then it would be a match, and we're assuming the match key doesn't exist. + // Therefore, step 2 will correctly return no match. + + // Find the last entry in the by_symbol_ map whose key is less than or + // equal to the given name. + typename map::iterator FindLastLessOrEqual( + const string& name); + + // True if either the arguments are equal or super_symbol identifies a + // parent symbol of sub_symbol (e.g. "foo.bar" is a parent of + // "foo.bar.baz", but not a parent of "foo.barbaz"). + bool IsSubSymbol(const string& sub_symbol, const string& super_symbol); + + // Returns true if and only if all characters in the name are alphanumerics, + // underscores, or periods. + bool ValidateSymbolName(const string& name); + }; + + + DescriptorIndex index_; + vector files_to_delete_; + + // If file is non-NULL, copy it into *output and return true, otherwise + // return false. + bool MaybeCopy(const FileDescriptorProto* file, + FileDescriptorProto* output); + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SimpleDescriptorDatabase); +}; + +// Very similar to SimpleDescriptorDatabase, but stores all the descriptors +// as raw bytes and generally tries to use as little memory as possible. +// +// The same caveats regarding FindFileContainingExtension() apply as with +// SimpleDescriptorDatabase. +class LIBPROTOBUF_EXPORT EncodedDescriptorDatabase : public DescriptorDatabase { + public: + EncodedDescriptorDatabase(); + ~EncodedDescriptorDatabase(); + + // Adds the FileDescriptorProto to the database. The descriptor is provided + // in encoded form. The database does not make a copy of the bytes, nor + // does it take ownership; it's up to the caller to make sure the bytes + // remain valid for the life of the database. Returns false and logs an error + // if the bytes are not a valid FileDescriptorProto or if the file conflicted + // with a file already in the database. + bool Add(const void* encoded_file_descriptor, int size); + + // Like Add(), but makes a copy of the data, so that the caller does not + // need to keep it around. + bool AddCopy(const void* encoded_file_descriptor, int size); + + // Like FindFileContainingSymbol but returns only the name of the file. + bool FindNameOfFileContainingSymbol(const string& symbol_name, + string* output); + + // implements DescriptorDatabase ----------------------------------- + bool FindFileByName(const string& filename, + FileDescriptorProto* output); + bool FindFileContainingSymbol(const string& symbol_name, + FileDescriptorProto* output); + bool FindFileContainingExtension(const string& containing_type, + int field_number, + FileDescriptorProto* output); + bool FindAllExtensionNumbers(const string& extendee_type, + vector* output); + + private: + SimpleDescriptorDatabase::DescriptorIndex > index_; + vector files_to_delete_; + + // If encoded_file.first is non-NULL, parse the data into *output and return + // true, otherwise return false. + bool MaybeParse(pair encoded_file, + FileDescriptorProto* output); + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EncodedDescriptorDatabase); +}; + +// A DescriptorDatabase that fetches files from a given pool. +class LIBPROTOBUF_EXPORT DescriptorPoolDatabase : public DescriptorDatabase { + public: + DescriptorPoolDatabase(const DescriptorPool& pool); + ~DescriptorPoolDatabase(); + + // implements DescriptorDatabase ----------------------------------- + bool FindFileByName(const string& filename, + FileDescriptorProto* output); + bool FindFileContainingSymbol(const string& symbol_name, + FileDescriptorProto* output); + bool FindFileContainingExtension(const string& containing_type, + int field_number, + FileDescriptorProto* output); + bool FindAllExtensionNumbers(const string& extendee_type, + vector* output); + + private: + const DescriptorPool& pool_; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DescriptorPoolDatabase); +}; + +// A DescriptorDatabase that wraps two or more others. It first searches the +// first database and, if that fails, tries the second, and so on. +class LIBPROTOBUF_EXPORT MergedDescriptorDatabase : public DescriptorDatabase { + public: + // Merge just two databases. The sources remain property of the caller. + MergedDescriptorDatabase(DescriptorDatabase* source1, + DescriptorDatabase* source2); + // Merge more than two databases. The sources remain property of the caller. + // The vector may be deleted after the constructor returns but the + // DescriptorDatabases need to stick around. + MergedDescriptorDatabase(const vector& sources); + ~MergedDescriptorDatabase(); + + // implements DescriptorDatabase ----------------------------------- + bool FindFileByName(const string& filename, + FileDescriptorProto* output); + bool FindFileContainingSymbol(const string& symbol_name, + FileDescriptorProto* output); + bool FindFileContainingExtension(const string& containing_type, + int field_number, + FileDescriptorProto* output); + // Merges the results of calling all databases. Returns true iff any + // of the databases returned true. + bool FindAllExtensionNumbers(const string& extendee_type, + vector* output); + + private: + vector sources_; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MergedDescriptorDatabase); +}; + +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_DESCRIPTOR_DATABASE_H__ diff --git a/depends/protobuf/google/protobuf/dynamic_message.cc b/depends/protobuf/google/protobuf/dynamic_message.cc new file mode 100644 index 0000000000..c711a2da43 --- /dev/null +++ b/depends/protobuf/google/protobuf/dynamic_message.cc @@ -0,0 +1,558 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// DynamicMessage is implemented by constructing a data structure which +// has roughly the same memory layout as a generated message would have. +// Then, we use GeneratedMessageReflection to implement our reflection +// interface. All the other operations we need to implement (e.g. +// parsing, copying, etc.) are already implemented in terms of +// Reflection, so the rest is easy. +// +// The up side of this strategy is that it's very efficient. We don't +// need to use hash_maps or generic representations of fields. The +// down side is that this is a low-level memory management hack which +// can be tricky to get right. +// +// As mentioned in the header, we only expose a DynamicMessageFactory +// publicly, not the DynamicMessage class itself. This is because +// GenericMessageReflection wants to have a pointer to a "default" +// copy of the class, with all fields initialized to their default +// values. We only want to construct one of these per message type, +// so DynamicMessageFactory stores a cache of default messages for +// each type it sees (each unique Descriptor pointer). The code +// refers to the "default" copy of the class as the "prototype". +// +// Note on memory allocation: This module often calls "operator new()" +// to allocate untyped memory, rather than calling something like +// "new uint8[]". This is because "operator new()" means "Give me some +// space which I can use as I please." while "new uint8[]" means "Give +// me an array of 8-bit integers.". In practice, the later may return +// a pointer that is not aligned correctly for general use. I believe +// Item 8 of "More Effective C++" discusses this in more detail, though +// I don't have the book on me right now so I'm not sure. + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { + +using internal::WireFormat; +using internal::ExtensionSet; +using internal::GeneratedMessageReflection; + + +// =================================================================== +// Some helper tables and functions... + +namespace { + +// Compute the byte size of the in-memory representation of the field. +int FieldSpaceUsed(const FieldDescriptor* field) { + typedef FieldDescriptor FD; // avoid line wrapping + if (field->label() == FD::LABEL_REPEATED) { + switch (field->cpp_type()) { + case FD::CPPTYPE_INT32 : return sizeof(RepeatedField); + case FD::CPPTYPE_INT64 : return sizeof(RepeatedField); + case FD::CPPTYPE_UINT32 : return sizeof(RepeatedField); + case FD::CPPTYPE_UINT64 : return sizeof(RepeatedField); + case FD::CPPTYPE_DOUBLE : return sizeof(RepeatedField); + case FD::CPPTYPE_FLOAT : return sizeof(RepeatedField); + case FD::CPPTYPE_BOOL : return sizeof(RepeatedField); + case FD::CPPTYPE_ENUM : return sizeof(RepeatedField); + case FD::CPPTYPE_MESSAGE: return sizeof(RepeatedPtrField); + + case FD::CPPTYPE_STRING: + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + return sizeof(RepeatedPtrField); + } + break; + } + } else { + switch (field->cpp_type()) { + case FD::CPPTYPE_INT32 : return sizeof(int32 ); + case FD::CPPTYPE_INT64 : return sizeof(int64 ); + case FD::CPPTYPE_UINT32 : return sizeof(uint32 ); + case FD::CPPTYPE_UINT64 : return sizeof(uint64 ); + case FD::CPPTYPE_DOUBLE : return sizeof(double ); + case FD::CPPTYPE_FLOAT : return sizeof(float ); + case FD::CPPTYPE_BOOL : return sizeof(bool ); + case FD::CPPTYPE_ENUM : return sizeof(int ); + case FD::CPPTYPE_MESSAGE: return sizeof(Message*); + + case FD::CPPTYPE_STRING: + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + return sizeof(string*); + } + break; + } + } + + GOOGLE_LOG(DFATAL) << "Can't get here."; + return 0; +} + +inline int DivideRoundingUp(int i, int j) { + return (i + (j - 1)) / j; +} + +static const int kSafeAlignment = sizeof(uint64); + +inline int AlignTo(int offset, int alignment) { + return DivideRoundingUp(offset, alignment) * alignment; +} + +// Rounds the given byte offset up to the next offset aligned such that any +// type may be stored at it. +inline int AlignOffset(int offset) { + return AlignTo(offset, kSafeAlignment); +} + +#define bitsizeof(T) (sizeof(T) * 8) + +} // namespace + +// =================================================================== + +class DynamicMessage : public Message { + public: + struct TypeInfo { + int size; + int has_bits_offset; + int unknown_fields_offset; + int extensions_offset; + + // Not owned by the TypeInfo. + DynamicMessageFactory* factory; // The factory that created this object. + const DescriptorPool* pool; // The factory's DescriptorPool. + const Descriptor* type; // Type of this DynamicMessage. + + // Warning: The order in which the following pointers are defined is + // important (the prototype must be deleted *before* the offsets). + scoped_array offsets; + scoped_ptr reflection; + scoped_ptr prototype; + }; + + DynamicMessage(const TypeInfo* type_info); + ~DynamicMessage(); + + // Called on the prototype after construction to initialize message fields. + void CrossLinkPrototypes(); + + // implements Message ---------------------------------------------- + + Message* New() const; + + int GetCachedSize() const; + void SetCachedSize(int size) const; + + Metadata GetMetadata() const; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DynamicMessage); + + inline bool is_prototype() const { + return type_info_->prototype == this || + // If type_info_->prototype is NULL, then we must be constructing + // the prototype now, which means we must be the prototype. + type_info_->prototype == NULL; + } + + inline void* OffsetToPointer(int offset) { + return reinterpret_cast(this) + offset; + } + inline const void* OffsetToPointer(int offset) const { + return reinterpret_cast(this) + offset; + } + + const TypeInfo* type_info_; + + // TODO(kenton): Make this an atomic when C++ supports it. + mutable int cached_byte_size_; +}; + +DynamicMessage::DynamicMessage(const TypeInfo* type_info) + : type_info_(type_info), + cached_byte_size_(0) { + // We need to call constructors for various fields manually and set + // default values where appropriate. We use placement new to call + // constructors. If you haven't heard of placement new, I suggest Googling + // it now. We use placement new even for primitive types that don't have + // constructors for consistency. (In theory, placement new should be used + // any time you are trying to convert untyped memory to typed memory, though + // in practice that's not strictly necessary for types that don't have a + // constructor.) + + const Descriptor* descriptor = type_info_->type; + + new(OffsetToPointer(type_info_->unknown_fields_offset)) UnknownFieldSet; + + if (type_info_->extensions_offset != -1) { + new(OffsetToPointer(type_info_->extensions_offset)) ExtensionSet; + } + + for (int i = 0; i < descriptor->field_count(); i++) { + const FieldDescriptor* field = descriptor->field(i); + void* field_ptr = OffsetToPointer(type_info_->offsets[i]); + switch (field->cpp_type()) { +#define HANDLE_TYPE(CPPTYPE, TYPE) \ + case FieldDescriptor::CPPTYPE_##CPPTYPE: \ + if (!field->is_repeated()) { \ + new(field_ptr) TYPE(field->default_value_##TYPE()); \ + } else { \ + new(field_ptr) RepeatedField(); \ + } \ + break; + + HANDLE_TYPE(INT32 , int32 ); + HANDLE_TYPE(INT64 , int64 ); + HANDLE_TYPE(UINT32, uint32); + HANDLE_TYPE(UINT64, uint64); + HANDLE_TYPE(DOUBLE, double); + HANDLE_TYPE(FLOAT , float ); + HANDLE_TYPE(BOOL , bool ); +#undef HANDLE_TYPE + + case FieldDescriptor::CPPTYPE_ENUM: + if (!field->is_repeated()) { + new(field_ptr) int(field->default_value_enum()->number()); + } else { + new(field_ptr) RepeatedField(); + } + break; + + case FieldDescriptor::CPPTYPE_STRING: + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + if (!field->is_repeated()) { + if (is_prototype()) { + new(field_ptr) const string*(&field->default_value_string()); + } else { + string* default_value = + *reinterpret_cast( + type_info_->prototype->OffsetToPointer( + type_info_->offsets[i])); + new(field_ptr) string*(default_value); + } + } else { + new(field_ptr) RepeatedPtrField(); + } + break; + } + break; + + case FieldDescriptor::CPPTYPE_MESSAGE: { + if (!field->is_repeated()) { + new(field_ptr) Message*(NULL); + } else { + new(field_ptr) RepeatedPtrField(); + } + break; + } + } + } +} + +DynamicMessage::~DynamicMessage() { + const Descriptor* descriptor = type_info_->type; + + reinterpret_cast( + OffsetToPointer(type_info_->unknown_fields_offset))->~UnknownFieldSet(); + + if (type_info_->extensions_offset != -1) { + reinterpret_cast( + OffsetToPointer(type_info_->extensions_offset))->~ExtensionSet(); + } + + // We need to manually run the destructors for repeated fields and strings, + // just as we ran their constructors in the the DynamicMessage constructor. + // Additionally, if any singular embedded messages have been allocated, we + // need to delete them, UNLESS we are the prototype message of this type, + // in which case any embedded messages are other prototypes and shouldn't + // be touched. + for (int i = 0; i < descriptor->field_count(); i++) { + const FieldDescriptor* field = descriptor->field(i); + void* field_ptr = OffsetToPointer(type_info_->offsets[i]); + + if (field->is_repeated()) { + switch (field->cpp_type()) { +#define HANDLE_TYPE(UPPERCASE, LOWERCASE) \ + case FieldDescriptor::CPPTYPE_##UPPERCASE : \ + reinterpret_cast*>(field_ptr) \ + ->~RepeatedField(); \ + break + + HANDLE_TYPE( INT32, int32); + HANDLE_TYPE( INT64, int64); + HANDLE_TYPE(UINT32, uint32); + HANDLE_TYPE(UINT64, uint64); + HANDLE_TYPE(DOUBLE, double); + HANDLE_TYPE( FLOAT, float); + HANDLE_TYPE( BOOL, bool); + HANDLE_TYPE( ENUM, int); +#undef HANDLE_TYPE + + case FieldDescriptor::CPPTYPE_STRING: + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + reinterpret_cast*>(field_ptr) + ->~RepeatedPtrField(); + break; + } + break; + + case FieldDescriptor::CPPTYPE_MESSAGE: + reinterpret_cast*>(field_ptr) + ->~RepeatedPtrField(); + break; + } + + } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) { + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: { + string* ptr = *reinterpret_cast(field_ptr); + if (ptr != &field->default_value_string()) { + delete ptr; + } + break; + } + } + } else if ((field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) && + !is_prototype()) { + Message* message = *reinterpret_cast(field_ptr); + if (message != NULL) { + delete message; + } + } + } +} + +void DynamicMessage::CrossLinkPrototypes() { + // This should only be called on the prototype message. + GOOGLE_CHECK(is_prototype()); + + DynamicMessageFactory* factory = type_info_->factory; + const Descriptor* descriptor = type_info_->type; + + // Cross-link default messages. + for (int i = 0; i < descriptor->field_count(); i++) { + const FieldDescriptor* field = descriptor->field(i); + void* field_ptr = OffsetToPointer(type_info_->offsets[i]); + + if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && + !field->is_repeated()) { + // For fields with message types, we need to cross-link with the + // prototype for the field's type. + // For singular fields, the field is just a pointer which should + // point to the prototype. + *reinterpret_cast(field_ptr) = + factory->GetPrototypeNoLock(field->message_type()); + } + } +} + +Message* DynamicMessage::New() const { + void* new_base = reinterpret_cast(operator new(type_info_->size)); + memset(new_base, 0, type_info_->size); + return new(new_base) DynamicMessage(type_info_); +} + +int DynamicMessage::GetCachedSize() const { + return cached_byte_size_; +} + +void DynamicMessage::SetCachedSize(int size) const { + // This is theoretically not thread-compatible, but in practice it works + // because if multiple threads write this simultaneously, they will be + // writing the exact same value. + cached_byte_size_ = size; +} + +Metadata DynamicMessage::GetMetadata() const { + Metadata metadata; + metadata.descriptor = type_info_->type; + metadata.reflection = type_info_->reflection.get(); + return metadata; +} + +// =================================================================== + +struct DynamicMessageFactory::PrototypeMap { + typedef hash_map Map; + Map map_; +}; + +DynamicMessageFactory::DynamicMessageFactory() + : pool_(NULL), delegate_to_generated_factory_(false), + prototypes_(new PrototypeMap) { +} + +DynamicMessageFactory::DynamicMessageFactory(const DescriptorPool* pool) + : pool_(pool), delegate_to_generated_factory_(false), + prototypes_(new PrototypeMap) { +} + +DynamicMessageFactory::~DynamicMessageFactory() { + for (PrototypeMap::Map::iterator iter = prototypes_->map_.begin(); + iter != prototypes_->map_.end(); ++iter) { + delete iter->second; + } +} + +const Message* DynamicMessageFactory::GetPrototype(const Descriptor* type) { + MutexLock lock(&prototypes_mutex_); + return GetPrototypeNoLock(type); +} + +const Message* DynamicMessageFactory::GetPrototypeNoLock( + const Descriptor* type) { + if (delegate_to_generated_factory_ && + type->file()->pool() == DescriptorPool::generated_pool()) { + return MessageFactory::generated_factory()->GetPrototype(type); + } + + const DynamicMessage::TypeInfo** target = &prototypes_->map_[type]; + if (*target != NULL) { + // Already exists. + return (*target)->prototype.get(); + } + + DynamicMessage::TypeInfo* type_info = new DynamicMessage::TypeInfo; + *target = type_info; + + type_info->type = type; + type_info->pool = (pool_ == NULL) ? type->file()->pool() : pool_; + type_info->factory = this; + + // We need to construct all the structures passed to + // GeneratedMessageReflection's constructor. This includes: + // - A block of memory that contains space for all the message's fields. + // - An array of integers indicating the byte offset of each field within + // this block. + // - A big bitfield containing a bit for each field indicating whether + // or not that field is set. + + // Compute size and offsets. + int* offsets = new int[type->field_count()]; + type_info->offsets.reset(offsets); + + // Decide all field offsets by packing in order. + // We place the DynamicMessage object itself at the beginning of the allocated + // space. + int size = sizeof(DynamicMessage); + size = AlignOffset(size); + + // Next the has_bits, which is an array of uint32s. + type_info->has_bits_offset = size; + int has_bits_array_size = + DivideRoundingUp(type->field_count(), bitsizeof(uint32)); + size += has_bits_array_size * sizeof(uint32); + size = AlignOffset(size); + + // The ExtensionSet, if any. + if (type->extension_range_count() > 0) { + type_info->extensions_offset = size; + size += sizeof(ExtensionSet); + size = AlignOffset(size); + } else { + // No extensions. + type_info->extensions_offset = -1; + } + + // All the fields. + for (int i = 0; i < type->field_count(); i++) { + // Make sure field is aligned to avoid bus errors. + int field_size = FieldSpaceUsed(type->field(i)); + size = AlignTo(size, min(kSafeAlignment, field_size)); + offsets[i] = size; + size += field_size; + } + + // Add the UnknownFieldSet to the end. + size = AlignOffset(size); + type_info->unknown_fields_offset = size; + size += sizeof(UnknownFieldSet); + + // Align the final size to make sure no clever allocators think that + // alignment is not necessary. + size = AlignOffset(size); + type_info->size = size; + + // Allocate the prototype. + void* base = operator new(size); + memset(base, 0, size); + DynamicMessage* prototype = new(base) DynamicMessage(type_info); + type_info->prototype.reset(prototype); + + // Construct the reflection object. + type_info->reflection.reset( + new GeneratedMessageReflection( + type_info->type, + type_info->prototype.get(), + type_info->offsets.get(), + type_info->has_bits_offset, + type_info->unknown_fields_offset, + type_info->extensions_offset, + type_info->pool, + this, + type_info->size)); + + // Cross link prototypes. + prototype->CrossLinkPrototypes(); + + return prototype; +} + +} // namespace protobuf +} // namespace google diff --git a/depends/protobuf/google/protobuf/dynamic_message.h b/depends/protobuf/google/protobuf/dynamic_message.h new file mode 100644 index 0000000000..81dd2c639e --- /dev/null +++ b/depends/protobuf/google/protobuf/dynamic_message.h @@ -0,0 +1,136 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// Defines an implementation of Message which can emulate types which are not +// known at compile-time. + +#ifndef GOOGLE_PROTOBUF_DYNAMIC_MESSAGE_H__ +#define GOOGLE_PROTOBUF_DYNAMIC_MESSAGE_H__ + +#include +#include + +namespace google { +namespace protobuf { + +// Defined in other files. +class Descriptor; // descriptor.h +class DescriptorPool; // descriptor.h + +// Constructs implementations of Message which can emulate types which are not +// known at compile-time. +// +// Sometimes you want to be able to manipulate protocol types that you don't +// know about at compile time. It would be nice to be able to construct +// a Message object which implements the message type given by any arbitrary +// Descriptor. DynamicMessage provides this. +// +// As it turns out, a DynamicMessage needs to construct extra +// information about its type in order to operate. Most of this information +// can be shared between all DynamicMessages of the same type. But, caching +// this information in some sort of global map would be a bad idea, since +// the cached information for a particular descriptor could outlive the +// descriptor itself. To avoid this problem, DynamicMessageFactory +// encapsulates this "cache". All DynamicMessages of the same type created +// from the same factory will share the same support data. Any Descriptors +// used with a particular factory must outlive the factory. +class LIBPROTOBUF_EXPORT DynamicMessageFactory : public MessageFactory { + public: + // Construct a DynamicMessageFactory that will search for extensions in + // the DescriptorPool in which the exendee is defined. + DynamicMessageFactory(); + + // Construct a DynamicMessageFactory that will search for extensions in + // the given DescriptorPool. + // + // DEPRECATED: Use CodedInputStream::SetExtensionRegistry() to tell the + // parser to look for extensions in an alternate pool. However, note that + // this is almost never what you want to do. Almost all users should use + // the zero-arg constructor. + DynamicMessageFactory(const DescriptorPool* pool); + + ~DynamicMessageFactory(); + + // Call this to tell the DynamicMessageFactory that if it is given a + // Descriptor d for which: + // d->file()->pool() == DescriptorPool::generated_pool(), + // then it should delegate to MessageFactory::generated_factory() instead + // of constructing a dynamic implementation of the message. In theory there + // is no down side to doing this, so it may become the default in the future. + void SetDelegateToGeneratedFactory(bool enable) { + delegate_to_generated_factory_ = enable; + } + + // implements MessageFactory --------------------------------------- + + // Given a Descriptor, constructs the default (prototype) Message of that + // type. You can then call that message's New() method to construct a + // mutable message of that type. + // + // Calling this method twice with the same Descriptor returns the same + // object. The returned object remains property of the factory and will + // be destroyed when the factory is destroyed. Also, any objects created + // by calling the prototype's New() method share some data with the + // prototype, so these must be destoyed before the DynamicMessageFactory + // is destroyed. + // + // The given descriptor must outlive the returned message, and hence must + // outlive the DynamicMessageFactory. + // + // The method is thread-safe. + const Message* GetPrototype(const Descriptor* type); + + private: + const DescriptorPool* pool_; + bool delegate_to_generated_factory_; + + // This struct just contains a hash_map. We can't #include from + // this header due to hacks needed for hash_map portability in the open source + // release. Namely, stubs/hash.h, which defines hash_map portably, is not a + // public header (for good reason), but dynamic_message.h is, and public + // headers may only #include other public headers. + struct PrototypeMap; + scoped_ptr prototypes_; + mutable Mutex prototypes_mutex_; + + friend class DynamicMessage; + const Message* GetPrototypeNoLock(const Descriptor* type); + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DynamicMessageFactory); +}; + +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_DYNAMIC_MESSAGE_H__ diff --git a/depends/protobuf/google/protobuf/extension_set.cc b/depends/protobuf/google/protobuf/extension_set.cc new file mode 100644 index 0000000000..1a6f5dfc25 --- /dev/null +++ b/depends/protobuf/google/protobuf/extension_set.cc @@ -0,0 +1,1464 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { +namespace internal { + +namespace { + +inline WireFormatLite::FieldType real_type(FieldType type) { + GOOGLE_DCHECK(type > 0 && type <= WireFormatLite::MAX_FIELD_TYPE); + return static_cast(type); +} + +inline WireFormatLite::CppType cpp_type(FieldType type) { + return WireFormatLite::FieldTypeToCppType(real_type(type)); +} + +// Registry stuff. +typedef hash_map, + ExtensionInfo> ExtensionRegistry; +ExtensionRegistry* registry_ = NULL; +GOOGLE_PROTOBUF_DECLARE_ONCE(registry_init_); + +void DeleteRegistry() { + delete registry_; + registry_ = NULL; +} + +void InitRegistry() { + registry_ = new ExtensionRegistry; + internal::OnShutdown(&DeleteRegistry); +} + +// This function is only called at startup, so there is no need for thread- +// safety. +void Register(const MessageLite* containing_type, + int number, ExtensionInfo info) { + ::google::protobuf::GoogleOnceInit(®istry_init_, &InitRegistry); + + if (!InsertIfNotPresent(registry_, make_pair(containing_type, number), + info)) { + GOOGLE_LOG(FATAL) << "Multiple extension registrations for type \"" + << containing_type->GetTypeName() + << "\", field number " << number << "."; + } +} + +const ExtensionInfo* FindRegisteredExtension( + const MessageLite* containing_type, int number) { + return (registry_ == NULL) ? NULL : + FindOrNull(*registry_, make_pair(containing_type, number)); +} + +} // namespace + +ExtensionFinder::~ExtensionFinder() {} + +bool GeneratedExtensionFinder::Find(int number, ExtensionInfo* output) { + const ExtensionInfo* extension = + FindRegisteredExtension(containing_type_, number); + if (extension == NULL) { + return false; + } else { + *output = *extension; + return true; + } +} + +void ExtensionSet::RegisterExtension(const MessageLite* containing_type, + int number, FieldType type, + bool is_repeated, bool is_packed) { + GOOGLE_CHECK_NE(type, WireFormatLite::TYPE_ENUM); + GOOGLE_CHECK_NE(type, WireFormatLite::TYPE_MESSAGE); + GOOGLE_CHECK_NE(type, WireFormatLite::TYPE_GROUP); + ExtensionInfo info(type, is_repeated, is_packed); + Register(containing_type, number, info); +} + +static bool CallNoArgValidityFunc(const void* arg, int number) { + // Note: Must use C-style cast here rather than reinterpret_cast because + // the C++ standard at one point did not allow casts between function and + // data pointers and some compilers enforce this for C++-style casts. No + // compiler enforces it for C-style casts since lots of C-style code has + // relied on these kinds of casts for a long time, despite being + // technically undefined. See: + // http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#195 + // Also note: Some compilers do not allow function pointers to be "const". + // Which makes sense, I suppose, because it's meaningless. + return ((EnumValidityFunc*)arg)(number); +} + +void ExtensionSet::RegisterEnumExtension(const MessageLite* containing_type, + int number, FieldType type, + bool is_repeated, bool is_packed, + EnumValidityFunc* is_valid) { + GOOGLE_CHECK_EQ(type, WireFormatLite::TYPE_ENUM); + ExtensionInfo info(type, is_repeated, is_packed); + info.enum_validity_check.func = CallNoArgValidityFunc; + // See comment in CallNoArgValidityFunc() about why we use a c-style cast. + info.enum_validity_check.arg = (void*)is_valid; + Register(containing_type, number, info); +} + +void ExtensionSet::RegisterMessageExtension(const MessageLite* containing_type, + int number, FieldType type, + bool is_repeated, bool is_packed, + const MessageLite* prototype) { + GOOGLE_CHECK(type == WireFormatLite::TYPE_MESSAGE || + type == WireFormatLite::TYPE_GROUP); + ExtensionInfo info(type, is_repeated, is_packed); + info.message_prototype = prototype; + Register(containing_type, number, info); +} + + +// =================================================================== +// Constructors and basic methods. + +ExtensionSet::ExtensionSet() {} + +ExtensionSet::~ExtensionSet() { + for (map::iterator iter = extensions_.begin(); + iter != extensions_.end(); ++iter) { + iter->second.Free(); + } +} + +// Defined in extension_set_heavy.cc. +// void ExtensionSet::AppendToList(const Descriptor* containing_type, +// const DescriptorPool* pool, +// vector* output) const + +bool ExtensionSet::Has(int number) const { + map::const_iterator iter = extensions_.find(number); + if (iter == extensions_.end()) return false; + GOOGLE_DCHECK(!iter->second.is_repeated); + return !iter->second.is_cleared; +} + +int ExtensionSet::ExtensionSize(int number) const { + map::const_iterator iter = extensions_.find(number); + if (iter == extensions_.end()) return false; + return iter->second.GetSize(); +} + +FieldType ExtensionSet::ExtensionType(int number) const { + map::const_iterator iter = extensions_.find(number); + if (iter == extensions_.end()) { + GOOGLE_LOG(DFATAL) << "Don't lookup extension types if they aren't present (1). "; + return 0; + } + if (iter->second.is_cleared) { + GOOGLE_LOG(DFATAL) << "Don't lookup extension types if they aren't present (2). "; + } + return iter->second.type; +} + +void ExtensionSet::ClearExtension(int number) { + map::iterator iter = extensions_.find(number); + if (iter == extensions_.end()) return; + iter->second.Clear(); +} + +// =================================================================== +// Field accessors + +namespace { + +enum Cardinality { + REPEATED, + OPTIONAL +}; + +} // namespace + +#define GOOGLE_DCHECK_TYPE(EXTENSION, LABEL, CPPTYPE) \ + GOOGLE_DCHECK_EQ((EXTENSION).is_repeated ? REPEATED : OPTIONAL, LABEL); \ + GOOGLE_DCHECK_EQ(cpp_type((EXTENSION).type), WireFormatLite::CPPTYPE_##CPPTYPE) + +// ------------------------------------------------------------------- +// Primitives + +#define PRIMITIVE_ACCESSORS(UPPERCASE, LOWERCASE, CAMELCASE) \ + \ +LOWERCASE ExtensionSet::Get##CAMELCASE(int number, \ + LOWERCASE default_value) const { \ + map::const_iterator iter = extensions_.find(number); \ + if (iter == extensions_.end() || iter->second.is_cleared) { \ + return default_value; \ + } else { \ + GOOGLE_DCHECK_TYPE(iter->second, OPTIONAL, UPPERCASE); \ + return iter->second.LOWERCASE##_value; \ + } \ +} \ + \ +void ExtensionSet::Set##CAMELCASE(int number, FieldType type, \ + LOWERCASE value, \ + const FieldDescriptor* descriptor) { \ + Extension* extension; \ + if (MaybeNewExtension(number, descriptor, &extension)) { \ + extension->type = type; \ + GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_##UPPERCASE); \ + extension->is_repeated = false; \ + } else { \ + GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, UPPERCASE); \ + } \ + extension->is_cleared = false; \ + extension->LOWERCASE##_value = value; \ +} \ + \ +LOWERCASE ExtensionSet::GetRepeated##CAMELCASE(int number, int index) const { \ + map::const_iterator iter = extensions_.find(number); \ + GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty)."; \ + GOOGLE_DCHECK_TYPE(iter->second, REPEATED, UPPERCASE); \ + return iter->second.repeated_##LOWERCASE##_value->Get(index); \ +} \ + \ +void ExtensionSet::SetRepeated##CAMELCASE( \ + int number, int index, LOWERCASE value) { \ + map::iterator iter = extensions_.find(number); \ + GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty)."; \ + GOOGLE_DCHECK_TYPE(iter->second, REPEATED, UPPERCASE); \ + iter->second.repeated_##LOWERCASE##_value->Set(index, value); \ +} \ + \ +void ExtensionSet::Add##CAMELCASE(int number, FieldType type, \ + bool packed, LOWERCASE value, \ + const FieldDescriptor* descriptor) { \ + Extension* extension; \ + if (MaybeNewExtension(number, descriptor, &extension)) { \ + extension->type = type; \ + GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_##UPPERCASE); \ + extension->is_repeated = true; \ + extension->is_packed = packed; \ + extension->repeated_##LOWERCASE##_value = new RepeatedField(); \ + } else { \ + GOOGLE_DCHECK_TYPE(*extension, REPEATED, UPPERCASE); \ + GOOGLE_DCHECK_EQ(extension->is_packed, packed); \ + } \ + extension->repeated_##LOWERCASE##_value->Add(value); \ +} + +PRIMITIVE_ACCESSORS( INT32, int32, Int32) +PRIMITIVE_ACCESSORS( INT64, int64, Int64) +PRIMITIVE_ACCESSORS(UINT32, uint32, UInt32) +PRIMITIVE_ACCESSORS(UINT64, uint64, UInt64) +PRIMITIVE_ACCESSORS( FLOAT, float, Float) +PRIMITIVE_ACCESSORS(DOUBLE, double, Double) +PRIMITIVE_ACCESSORS( BOOL, bool, Bool) + +#undef PRIMITIVE_ACCESSORS + +// ------------------------------------------------------------------- +// Enums + +int ExtensionSet::GetEnum(int number, int default_value) const { + map::const_iterator iter = extensions_.find(number); + if (iter == extensions_.end() || iter->second.is_cleared) { + // Not present. Return the default value. + return default_value; + } else { + GOOGLE_DCHECK_TYPE(iter->second, OPTIONAL, ENUM); + return iter->second.enum_value; + } +} + +void ExtensionSet::SetEnum(int number, FieldType type, int value, + const FieldDescriptor* descriptor) { + Extension* extension; + if (MaybeNewExtension(number, descriptor, &extension)) { + extension->type = type; + GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_ENUM); + extension->is_repeated = false; + } else { + GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, ENUM); + } + extension->is_cleared = false; + extension->enum_value = value; +} + +int ExtensionSet::GetRepeatedEnum(int number, int index) const { + map::const_iterator iter = extensions_.find(number); + GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty)."; + GOOGLE_DCHECK_TYPE(iter->second, REPEATED, ENUM); + return iter->second.repeated_enum_value->Get(index); +} + +void ExtensionSet::SetRepeatedEnum(int number, int index, int value) { + map::iterator iter = extensions_.find(number); + GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty)."; + GOOGLE_DCHECK_TYPE(iter->second, REPEATED, ENUM); + iter->second.repeated_enum_value->Set(index, value); +} + +void ExtensionSet::AddEnum(int number, FieldType type, + bool packed, int value, + const FieldDescriptor* descriptor) { + Extension* extension; + if (MaybeNewExtension(number, descriptor, &extension)) { + extension->type = type; + GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_ENUM); + extension->is_repeated = true; + extension->is_packed = packed; + extension->repeated_enum_value = new RepeatedField(); + } else { + GOOGLE_DCHECK_TYPE(*extension, REPEATED, ENUM); + GOOGLE_DCHECK_EQ(extension->is_packed, packed); + } + extension->repeated_enum_value->Add(value); +} + +// ------------------------------------------------------------------- +// Strings + +const string& ExtensionSet::GetString(int number, + const string& default_value) const { + map::const_iterator iter = extensions_.find(number); + if (iter == extensions_.end() || iter->second.is_cleared) { + // Not present. Return the default value. + return default_value; + } else { + GOOGLE_DCHECK_TYPE(iter->second, OPTIONAL, STRING); + return *iter->second.string_value; + } +} + +string* ExtensionSet::MutableString(int number, FieldType type, + const FieldDescriptor* descriptor) { + Extension* extension; + if (MaybeNewExtension(number, descriptor, &extension)) { + extension->type = type; + GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_STRING); + extension->is_repeated = false; + extension->string_value = new string; + } else { + GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, STRING); + } + extension->is_cleared = false; + return extension->string_value; +} + +const string& ExtensionSet::GetRepeatedString(int number, int index) const { + map::const_iterator iter = extensions_.find(number); + GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty)."; + GOOGLE_DCHECK_TYPE(iter->second, REPEATED, STRING); + return iter->second.repeated_string_value->Get(index); +} + +string* ExtensionSet::MutableRepeatedString(int number, int index) { + map::iterator iter = extensions_.find(number); + GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty)."; + GOOGLE_DCHECK_TYPE(iter->second, REPEATED, STRING); + return iter->second.repeated_string_value->Mutable(index); +} + +string* ExtensionSet::AddString(int number, FieldType type, + const FieldDescriptor* descriptor) { + Extension* extension; + if (MaybeNewExtension(number, descriptor, &extension)) { + extension->type = type; + GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_STRING); + extension->is_repeated = true; + extension->is_packed = false; + extension->repeated_string_value = new RepeatedPtrField(); + } else { + GOOGLE_DCHECK_TYPE(*extension, REPEATED, STRING); + } + return extension->repeated_string_value->Add(); +} + +// ------------------------------------------------------------------- +// Messages + +const MessageLite& ExtensionSet::GetMessage( + int number, const MessageLite& default_value) const { + map::const_iterator iter = extensions_.find(number); + if (iter == extensions_.end()) { + // Not present. Return the default value. + return default_value; + } else { + GOOGLE_DCHECK_TYPE(iter->second, OPTIONAL, MESSAGE); + return *iter->second.message_value; + } +} + +// Defined in extension_set_heavy.cc. +// const MessageLite& ExtensionSet::GetMessage(int number, +// const Descriptor* message_type, +// MessageFactory* factory) const + +MessageLite* ExtensionSet::MutableMessage(int number, FieldType type, + const MessageLite& prototype, + const FieldDescriptor* descriptor) { + Extension* extension; + if (MaybeNewExtension(number, descriptor, &extension)) { + extension->type = type; + GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_MESSAGE); + extension->is_repeated = false; + extension->message_value = prototype.New(); + } else { + GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE); + } + extension->is_cleared = false; + return extension->message_value; +} + +// Defined in extension_set_heavy.cc. +// MessageLite* ExtensionSet::MutableMessage(int number, FieldType type, +// const Descriptor* message_type, +// MessageFactory* factory) + +const MessageLite& ExtensionSet::GetRepeatedMessage( + int number, int index) const { + map::const_iterator iter = extensions_.find(number); + GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty)."; + GOOGLE_DCHECK_TYPE(iter->second, REPEATED, MESSAGE); + return iter->second.repeated_message_value->Get(index); +} + +MessageLite* ExtensionSet::MutableRepeatedMessage(int number, int index) { + map::iterator iter = extensions_.find(number); + GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty)."; + GOOGLE_DCHECK_TYPE(iter->second, REPEATED, MESSAGE); + return iter->second.repeated_message_value->Mutable(index); +} + +MessageLite* ExtensionSet::AddMessage(int number, FieldType type, + const MessageLite& prototype, + const FieldDescriptor* descriptor) { + Extension* extension; + if (MaybeNewExtension(number, descriptor, &extension)) { + extension->type = type; + GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_MESSAGE); + extension->is_repeated = true; + extension->repeated_message_value = + new RepeatedPtrField(); + } else { + GOOGLE_DCHECK_TYPE(*extension, REPEATED, MESSAGE); + } + + // RepeatedPtrField does not know how to Add() since it cannot + // allocate an abstract object, so we have to be tricky. + MessageLite* result = extension->repeated_message_value + ->AddFromCleared >(); + if (result == NULL) { + result = prototype.New(); + extension->repeated_message_value->AddAllocated(result); + } + return result; +} + +// Defined in extension_set_heavy.cc. +// MessageLite* ExtensionSet::AddMessage(int number, FieldType type, +// const Descriptor* message_type, +// MessageFactory* factory) + +#undef GOOGLE_DCHECK_TYPE + +void ExtensionSet::RemoveLast(int number) { + map::iterator iter = extensions_.find(number); + GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty)."; + + Extension* extension = &iter->second; + GOOGLE_DCHECK(extension->is_repeated); + + switch(cpp_type(extension->type)) { + case WireFormatLite::CPPTYPE_INT32: + extension->repeated_int32_value->RemoveLast(); + break; + case WireFormatLite::CPPTYPE_INT64: + extension->repeated_int64_value->RemoveLast(); + break; + case WireFormatLite::CPPTYPE_UINT32: + extension->repeated_uint32_value->RemoveLast(); + break; + case WireFormatLite::CPPTYPE_UINT64: + extension->repeated_uint64_value->RemoveLast(); + break; + case WireFormatLite::CPPTYPE_FLOAT: + extension->repeated_float_value->RemoveLast(); + break; + case WireFormatLite::CPPTYPE_DOUBLE: + extension->repeated_double_value->RemoveLast(); + break; + case WireFormatLite::CPPTYPE_BOOL: + extension->repeated_bool_value->RemoveLast(); + break; + case WireFormatLite::CPPTYPE_ENUM: + extension->repeated_enum_value->RemoveLast(); + break; + case WireFormatLite::CPPTYPE_STRING: + extension->repeated_string_value->RemoveLast(); + break; + case WireFormatLite::CPPTYPE_MESSAGE: + extension->repeated_message_value->RemoveLast(); + break; + } +} + +void ExtensionSet::SwapElements(int number, int index1, int index2) { + map::iterator iter = extensions_.find(number); + GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty)."; + + Extension* extension = &iter->second; + GOOGLE_DCHECK(extension->is_repeated); + + switch(cpp_type(extension->type)) { + case WireFormatLite::CPPTYPE_INT32: + extension->repeated_int32_value->SwapElements(index1, index2); + break; + case WireFormatLite::CPPTYPE_INT64: + extension->repeated_int64_value->SwapElements(index1, index2); + break; + case WireFormatLite::CPPTYPE_UINT32: + extension->repeated_uint32_value->SwapElements(index1, index2); + break; + case WireFormatLite::CPPTYPE_UINT64: + extension->repeated_uint64_value->SwapElements(index1, index2); + break; + case WireFormatLite::CPPTYPE_FLOAT: + extension->repeated_float_value->SwapElements(index1, index2); + break; + case WireFormatLite::CPPTYPE_DOUBLE: + extension->repeated_double_value->SwapElements(index1, index2); + break; + case WireFormatLite::CPPTYPE_BOOL: + extension->repeated_bool_value->SwapElements(index1, index2); + break; + case WireFormatLite::CPPTYPE_ENUM: + extension->repeated_enum_value->SwapElements(index1, index2); + break; + case WireFormatLite::CPPTYPE_STRING: + extension->repeated_string_value->SwapElements(index1, index2); + break; + case WireFormatLite::CPPTYPE_MESSAGE: + extension->repeated_message_value->SwapElements(index1, index2); + break; + } +} + +// =================================================================== + +void ExtensionSet::Clear() { + for (map::iterator iter = extensions_.begin(); + iter != extensions_.end(); ++iter) { + iter->second.Clear(); + } +} + +void ExtensionSet::MergeFrom(const ExtensionSet& other) { + for (map::const_iterator iter = other.extensions_.begin(); + iter != other.extensions_.end(); ++iter) { + const Extension& other_extension = iter->second; + + if (other_extension.is_repeated) { + Extension* extension; + bool is_new = MaybeNewExtension(iter->first, other_extension.descriptor, + &extension); + if (is_new) { + // Extension did not already exist in set. + extension->type = other_extension.type; + extension->is_repeated = true; + } else { + GOOGLE_DCHECK_EQ(extension->type, other_extension.type); + GOOGLE_DCHECK(extension->is_repeated); + } + + switch (cpp_type(other_extension.type)) { +#define HANDLE_TYPE(UPPERCASE, LOWERCASE, REPEATED_TYPE) \ + case WireFormatLite::CPPTYPE_##UPPERCASE: \ + if (is_new) { \ + extension->repeated_##LOWERCASE##_value = \ + new REPEATED_TYPE; \ + } \ + extension->repeated_##LOWERCASE##_value->MergeFrom( \ + *other_extension.repeated_##LOWERCASE##_value); \ + break; + + HANDLE_TYPE( INT32, int32, RepeatedField < int32>); + HANDLE_TYPE( INT64, int64, RepeatedField < int64>); + HANDLE_TYPE( UINT32, uint32, RepeatedField < uint32>); + HANDLE_TYPE( UINT64, uint64, RepeatedField < uint64>); + HANDLE_TYPE( FLOAT, float, RepeatedField < float>); + HANDLE_TYPE( DOUBLE, double, RepeatedField < double>); + HANDLE_TYPE( BOOL, bool, RepeatedField < bool>); + HANDLE_TYPE( ENUM, enum, RepeatedField < int>); + HANDLE_TYPE( STRING, string, RepeatedPtrField< string>); +#undef HANDLE_TYPE + + case WireFormatLite::CPPTYPE_MESSAGE: + if (is_new) { + extension->repeated_message_value = + new RepeatedPtrField(); + } + // We can't call RepeatedPtrField::MergeFrom() because + // it would attempt to allocate new objects. + RepeatedPtrField* other_repeated_message = + other_extension.repeated_message_value; + for (int i = 0; i < other_repeated_message->size(); i++) { + const MessageLite& other_message = other_repeated_message->Get(i); + MessageLite* target = extension->repeated_message_value + ->AddFromCleared >(); + if (target == NULL) { + target = other_message.New(); + extension->repeated_message_value->AddAllocated(target); + } + target->CheckTypeAndMergeFrom(other_message); + } + break; + } + } else { + if (!other_extension.is_cleared) { + switch (cpp_type(other_extension.type)) { +#define HANDLE_TYPE(UPPERCASE, LOWERCASE, CAMELCASE) \ + case WireFormatLite::CPPTYPE_##UPPERCASE: \ + Set##CAMELCASE(iter->first, other_extension.type, \ + other_extension.LOWERCASE##_value, \ + other_extension.descriptor); \ + break; + + HANDLE_TYPE( INT32, int32, Int32); + HANDLE_TYPE( INT64, int64, Int64); + HANDLE_TYPE(UINT32, uint32, UInt32); + HANDLE_TYPE(UINT64, uint64, UInt64); + HANDLE_TYPE( FLOAT, float, Float); + HANDLE_TYPE(DOUBLE, double, Double); + HANDLE_TYPE( BOOL, bool, Bool); + HANDLE_TYPE( ENUM, enum, Enum); +#undef HANDLE_TYPE + case WireFormatLite::CPPTYPE_STRING: + SetString(iter->first, other_extension.type, + *other_extension.string_value, + other_extension.descriptor); + break; + case WireFormatLite::CPPTYPE_MESSAGE: + MutableMessage(iter->first, other_extension.type, + *other_extension.message_value, + other_extension.descriptor) + ->CheckTypeAndMergeFrom(*other_extension.message_value); + break; + } + } + } + } +} + +void ExtensionSet::Swap(ExtensionSet* x) { + extensions_.swap(x->extensions_); +} + +bool ExtensionSet::IsInitialized() const { + // Extensions are never required. However, we need to check that all + // embedded messages are initialized. + for (map::const_iterator iter = extensions_.begin(); + iter != extensions_.end(); ++iter) { + const Extension& extension = iter->second; + if (cpp_type(extension.type) == WireFormatLite::CPPTYPE_MESSAGE) { + if (extension.is_repeated) { + for (int i = 0; i < extension.repeated_message_value->size(); i++) { + if (!extension.repeated_message_value->Get(i).IsInitialized()) { + return false; + } + } + } else { + if (!extension.is_cleared) { + if (!extension.message_value->IsInitialized()) return false; + } + } + } + } + + return true; +} + +bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input, + ExtensionFinder* extension_finder, + FieldSkipper* field_skipper) { + int number = WireFormatLite::GetTagFieldNumber(tag); + WireFormatLite::WireType wire_type = WireFormatLite::GetTagWireType(tag); + + ExtensionInfo extension; + bool is_unknown; + if (!extension_finder->Find(number, &extension)) { + is_unknown = true; + } else if (extension.is_packed) { + is_unknown = (wire_type != WireFormatLite::WIRETYPE_LENGTH_DELIMITED); + } else { + WireFormatLite::WireType expected_wire_type = + WireFormatLite::WireTypeForFieldType(real_type(extension.type)); + is_unknown = (wire_type != expected_wire_type); + } + + if (is_unknown) { + field_skipper->SkipField(input, tag); + } else if (extension.is_packed) { + uint32 size; + if (!input->ReadVarint32(&size)) return false; + io::CodedInputStream::Limit limit = input->PushLimit(size); + + switch (extension.type) { +#define HANDLE_TYPE(UPPERCASE, CPP_CAMELCASE, CPP_LOWERCASE) \ + case WireFormatLite::TYPE_##UPPERCASE: \ + while (input->BytesUntilLimit() > 0) { \ + CPP_LOWERCASE value; \ + if (!WireFormatLite::ReadPrimitive< \ + CPP_LOWERCASE, WireFormatLite::TYPE_##UPPERCASE>( \ + input, &value)) return false; \ + Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, \ + true, value, extension.descriptor); \ + } \ + break + + HANDLE_TYPE( INT32, Int32, int32); + HANDLE_TYPE( INT64, Int64, int64); + HANDLE_TYPE( UINT32, UInt32, uint32); + HANDLE_TYPE( UINT64, UInt64, uint64); + HANDLE_TYPE( SINT32, Int32, int32); + HANDLE_TYPE( SINT64, Int64, int64); + HANDLE_TYPE( FIXED32, UInt32, uint32); + HANDLE_TYPE( FIXED64, UInt64, uint64); + HANDLE_TYPE(SFIXED32, Int32, int32); + HANDLE_TYPE(SFIXED64, Int64, int64); + HANDLE_TYPE( FLOAT, Float, float); + HANDLE_TYPE( DOUBLE, Double, double); + HANDLE_TYPE( BOOL, Bool, bool); +#undef HANDLE_TYPE + + case WireFormatLite::TYPE_ENUM: + while (input->BytesUntilLimit() > 0) { + int value; + if (!WireFormatLite::ReadPrimitive( + input, &value)) return false; + if (extension.enum_validity_check.func( + extension.enum_validity_check.arg, value)) { + AddEnum(number, WireFormatLite::TYPE_ENUM, true, value, + extension.descriptor); + } + } + break; + + case WireFormatLite::TYPE_STRING: + case WireFormatLite::TYPE_BYTES: + case WireFormatLite::TYPE_GROUP: + case WireFormatLite::TYPE_MESSAGE: + GOOGLE_LOG(FATAL) << "Non-primitive types can't be packed."; + break; + } + + input->PopLimit(limit); + } else { + switch (extension.type) { +#define HANDLE_TYPE(UPPERCASE, CPP_CAMELCASE, CPP_LOWERCASE) \ + case WireFormatLite::TYPE_##UPPERCASE: { \ + CPP_LOWERCASE value; \ + if (!WireFormatLite::ReadPrimitive< \ + CPP_LOWERCASE, WireFormatLite::TYPE_##UPPERCASE>( \ + input, &value)) return false; \ + if (extension.is_repeated) { \ + Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, \ + false, value, extension.descriptor); \ + } else { \ + Set##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, value, \ + extension.descriptor); \ + } \ + } break + + HANDLE_TYPE( INT32, Int32, int32); + HANDLE_TYPE( INT64, Int64, int64); + HANDLE_TYPE( UINT32, UInt32, uint32); + HANDLE_TYPE( UINT64, UInt64, uint64); + HANDLE_TYPE( SINT32, Int32, int32); + HANDLE_TYPE( SINT64, Int64, int64); + HANDLE_TYPE( FIXED32, UInt32, uint32); + HANDLE_TYPE( FIXED64, UInt64, uint64); + HANDLE_TYPE(SFIXED32, Int32, int32); + HANDLE_TYPE(SFIXED64, Int64, int64); + HANDLE_TYPE( FLOAT, Float, float); + HANDLE_TYPE( DOUBLE, Double, double); + HANDLE_TYPE( BOOL, Bool, bool); +#undef HANDLE_TYPE + + case WireFormatLite::TYPE_ENUM: { + int value; + if (!WireFormatLite::ReadPrimitive( + input, &value)) return false; + + if (!extension.enum_validity_check.func( + extension.enum_validity_check.arg, value)) { + // Invalid value. Treat as unknown. + field_skipper->SkipUnknownEnum(number, value); + } else if (extension.is_repeated) { + AddEnum(number, WireFormatLite::TYPE_ENUM, false, value, + extension.descriptor); + } else { + SetEnum(number, WireFormatLite::TYPE_ENUM, value, + extension.descriptor); + } + break; + } + + case WireFormatLite::TYPE_STRING: { + string* value = extension.is_repeated ? + AddString(number, WireFormatLite::TYPE_STRING, extension.descriptor) : + MutableString(number, WireFormatLite::TYPE_STRING, + extension.descriptor); + if (!WireFormatLite::ReadString(input, value)) return false; + break; + } + + case WireFormatLite::TYPE_BYTES: { + string* value = extension.is_repeated ? + AddString(number, WireFormatLite::TYPE_STRING, extension.descriptor) : + MutableString(number, WireFormatLite::TYPE_STRING, + extension.descriptor); + if (!WireFormatLite::ReadBytes(input, value)) return false; + break; + } + + case WireFormatLite::TYPE_GROUP: { + MessageLite* value = extension.is_repeated ? + AddMessage(number, WireFormatLite::TYPE_GROUP, + *extension.message_prototype, extension.descriptor) : + MutableMessage(number, WireFormatLite::TYPE_GROUP, + *extension.message_prototype, extension.descriptor); + if (!WireFormatLite::ReadGroup(number, input, value)) return false; + break; + } + + case WireFormatLite::TYPE_MESSAGE: { + MessageLite* value = extension.is_repeated ? + AddMessage(number, WireFormatLite::TYPE_MESSAGE, + *extension.message_prototype, extension.descriptor) : + MutableMessage(number, WireFormatLite::TYPE_MESSAGE, + *extension.message_prototype, extension.descriptor); + if (!WireFormatLite::ReadMessage(input, value)) return false; + break; + } + } + } + + return true; +} + +bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input, + const MessageLite* containing_type) { + FieldSkipper skipper; + GeneratedExtensionFinder finder(containing_type); + return ParseField(tag, input, &finder, &skipper); +} + +// Defined in extension_set_heavy.cc. +// bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input, +// const MessageLite* containing_type, +// UnknownFieldSet* unknown_fields) + +bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input, + ExtensionFinder* extension_finder, + FieldSkipper* field_skipper) { + while (true) { + uint32 tag = input->ReadTag(); + switch (tag) { + case 0: + return true; + case WireFormatLite::kMessageSetItemStartTag: + if (!ParseMessageSetItem(input, extension_finder, field_skipper)) { + return false; + } + break; + default: + if (!ParseField(tag, input, extension_finder, field_skipper)) { + return false; + } + break; + } + } +} + +bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input, + const MessageLite* containing_type) { + FieldSkipper skipper; + GeneratedExtensionFinder finder(containing_type); + return ParseMessageSet(input, &finder, &skipper); +} + +// Defined in extension_set_heavy.cc. +// bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input, +// const MessageLite* containing_type, +// UnknownFieldSet* unknown_fields); + +bool ExtensionSet::ParseMessageSetItem(io::CodedInputStream* input, + ExtensionFinder* extension_finder, + FieldSkipper* field_skipper) { + // TODO(kenton): It would be nice to share code between this and + // WireFormatLite::ParseAndMergeMessageSetItem(), but I think the + // differences would be hard to factor out. + + // This method parses a group which should contain two fields: + // required int32 type_id = 2; + // required data message = 3; + + // Once we see a type_id, we'll construct a fake tag for this extension + // which is the tag it would have had under the proto2 extensions wire + // format. + uint32 fake_tag = 0; + + // If we see message data before the type_id, we'll append it to this so + // we can parse it later. This will probably never happen in practice, + // as no MessageSet encoder I know of writes the message before the type ID. + // But, it's technically valid so we should allow it. + // TODO(kenton): Use a Cord instead? Do I care? + string message_data; + + while (true) { + uint32 tag = input->ReadTag(); + if (tag == 0) return false; + + switch (tag) { + case WireFormatLite::kMessageSetTypeIdTag: { + uint32 type_id; + if (!input->ReadVarint32(&type_id)) return false; + fake_tag = WireFormatLite::MakeTag(type_id, + WireFormatLite::WIRETYPE_LENGTH_DELIMITED); + + if (!message_data.empty()) { + // We saw some message data before the type_id. Have to parse it + // now. + io::CodedInputStream sub_input( + reinterpret_cast(message_data.data()), + message_data.size()); + if (!ParseField(fake_tag, &sub_input, + extension_finder, field_skipper)) { + return false; + } + message_data.clear(); + } + + break; + } + + case WireFormatLite::kMessageSetMessageTag: { + if (fake_tag == 0) { + // We haven't seen a type_id yet. Append this data to message_data. + string temp; + uint32 length; + if (!input->ReadVarint32(&length)) return false; + if (!input->ReadString(&temp, length)) return false; + message_data.append(temp); + } else { + // Already saw type_id, so we can parse this directly. + if (!ParseField(fake_tag, input, + extension_finder, field_skipper)) { + return false; + } + } + + break; + } + + case WireFormatLite::kMessageSetItemEndTag: { + return true; + } + + default: { + if (!field_skipper->SkipField(input, tag)) return false; + } + } + } +} + +void ExtensionSet::SerializeWithCachedSizes( + int start_field_number, int end_field_number, + io::CodedOutputStream* output) const { + map::const_iterator iter; + for (iter = extensions_.lower_bound(start_field_number); + iter != extensions_.end() && iter->first < end_field_number; + ++iter) { + iter->second.SerializeFieldWithCachedSizes(iter->first, output); + } +} + +void ExtensionSet::SerializeMessageSetWithCachedSizes( + io::CodedOutputStream* output) const { + map::const_iterator iter; + for (iter = extensions_.begin(); iter != extensions_.end(); ++iter) { + iter->second.SerializeMessageSetItemWithCachedSizes(iter->first, output); + } +} + +int ExtensionSet::ByteSize() const { + int total_size = 0; + + for (map::const_iterator iter = extensions_.begin(); + iter != extensions_.end(); ++iter) { + total_size += iter->second.ByteSize(iter->first); + } + + return total_size; +} + +int ExtensionSet::MessageSetByteSize() const { + int total_size = 0; + + for (map::const_iterator iter = extensions_.begin(); + iter != extensions_.end(); ++iter) { + total_size += iter->second.MessageSetItemByteSize(iter->first); + } + + return total_size; +} + +// Defined in extension_set_heavy.cc. +// int ExtensionSet::SpaceUsedExcludingSelf() const + +bool ExtensionSet::MaybeNewExtension(int number, + const FieldDescriptor* descriptor, + Extension** result) { + pair::iterator, bool> insert_result = + extensions_.insert(make_pair(number, Extension())); + *result = &insert_result.first->second; + (*result)->descriptor = descriptor; + return insert_result.second; +} + +// =================================================================== +// Methods of ExtensionSet::Extension + +void ExtensionSet::Extension::Clear() { + if (is_repeated) { + switch (cpp_type(type)) { +#define HANDLE_TYPE(UPPERCASE, LOWERCASE) \ + case WireFormatLite::CPPTYPE_##UPPERCASE: \ + repeated_##LOWERCASE##_value->Clear(); \ + break + + HANDLE_TYPE( INT32, int32); + HANDLE_TYPE( INT64, int64); + HANDLE_TYPE( UINT32, uint32); + HANDLE_TYPE( UINT64, uint64); + HANDLE_TYPE( FLOAT, float); + HANDLE_TYPE( DOUBLE, double); + HANDLE_TYPE( BOOL, bool); + HANDLE_TYPE( ENUM, enum); + HANDLE_TYPE( STRING, string); + HANDLE_TYPE(MESSAGE, message); +#undef HANDLE_TYPE + } + } else { + if (!is_cleared) { + switch (cpp_type(type)) { + case WireFormatLite::CPPTYPE_STRING: + string_value->clear(); + break; + case WireFormatLite::CPPTYPE_MESSAGE: + message_value->Clear(); + break; + default: + // No need to do anything. Get*() will return the default value + // as long as is_cleared is true and Set*() will overwrite the + // previous value. + break; + } + + is_cleared = true; + } + } +} + +void ExtensionSet::Extension::SerializeFieldWithCachedSizes( + int number, + io::CodedOutputStream* output) const { + if (is_repeated) { + if (is_packed) { + if (cached_size == 0) return; + + WireFormatLite::WriteTag(number, + WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output); + output->WriteVarint32(cached_size); + + switch (real_type(type)) { +#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE) \ + case WireFormatLite::TYPE_##UPPERCASE: \ + for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) { \ + WireFormatLite::Write##CAMELCASE##NoTag( \ + repeated_##LOWERCASE##_value->Get(i), output); \ + } \ + break + + HANDLE_TYPE( INT32, Int32, int32); + HANDLE_TYPE( INT64, Int64, int64); + HANDLE_TYPE( UINT32, UInt32, uint32); + HANDLE_TYPE( UINT64, UInt64, uint64); + HANDLE_TYPE( SINT32, SInt32, int32); + HANDLE_TYPE( SINT64, SInt64, int64); + HANDLE_TYPE( FIXED32, Fixed32, uint32); + HANDLE_TYPE( FIXED64, Fixed64, uint64); + HANDLE_TYPE(SFIXED32, SFixed32, int32); + HANDLE_TYPE(SFIXED64, SFixed64, int64); + HANDLE_TYPE( FLOAT, Float, float); + HANDLE_TYPE( DOUBLE, Double, double); + HANDLE_TYPE( BOOL, Bool, bool); + HANDLE_TYPE( ENUM, Enum, enum); +#undef HANDLE_TYPE + + case WireFormatLite::TYPE_STRING: + case WireFormatLite::TYPE_BYTES: + case WireFormatLite::TYPE_GROUP: + case WireFormatLite::TYPE_MESSAGE: + GOOGLE_LOG(FATAL) << "Non-primitive types can't be packed."; + break; + } + } else { + switch (real_type(type)) { +#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE) \ + case WireFormatLite::TYPE_##UPPERCASE: \ + for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) { \ + WireFormatLite::Write##CAMELCASE(number, \ + repeated_##LOWERCASE##_value->Get(i), output); \ + } \ + break + + HANDLE_TYPE( INT32, Int32, int32); + HANDLE_TYPE( INT64, Int64, int64); + HANDLE_TYPE( UINT32, UInt32, uint32); + HANDLE_TYPE( UINT64, UInt64, uint64); + HANDLE_TYPE( SINT32, SInt32, int32); + HANDLE_TYPE( SINT64, SInt64, int64); + HANDLE_TYPE( FIXED32, Fixed32, uint32); + HANDLE_TYPE( FIXED64, Fixed64, uint64); + HANDLE_TYPE(SFIXED32, SFixed32, int32); + HANDLE_TYPE(SFIXED64, SFixed64, int64); + HANDLE_TYPE( FLOAT, Float, float); + HANDLE_TYPE( DOUBLE, Double, double); + HANDLE_TYPE( BOOL, Bool, bool); + HANDLE_TYPE( STRING, String, string); + HANDLE_TYPE( BYTES, Bytes, string); + HANDLE_TYPE( ENUM, Enum, enum); + HANDLE_TYPE( GROUP, Group, message); + HANDLE_TYPE( MESSAGE, Message, message); +#undef HANDLE_TYPE + } + } + } else if (!is_cleared) { + switch (real_type(type)) { +#define HANDLE_TYPE(UPPERCASE, CAMELCASE, VALUE) \ + case WireFormatLite::TYPE_##UPPERCASE: \ + WireFormatLite::Write##CAMELCASE(number, VALUE, output); \ + break + + HANDLE_TYPE( INT32, Int32, int32_value); + HANDLE_TYPE( INT64, Int64, int64_value); + HANDLE_TYPE( UINT32, UInt32, uint32_value); + HANDLE_TYPE( UINT64, UInt64, uint64_value); + HANDLE_TYPE( SINT32, SInt32, int32_value); + HANDLE_TYPE( SINT64, SInt64, int64_value); + HANDLE_TYPE( FIXED32, Fixed32, uint32_value); + HANDLE_TYPE( FIXED64, Fixed64, uint64_value); + HANDLE_TYPE(SFIXED32, SFixed32, int32_value); + HANDLE_TYPE(SFIXED64, SFixed64, int64_value); + HANDLE_TYPE( FLOAT, Float, float_value); + HANDLE_TYPE( DOUBLE, Double, double_value); + HANDLE_TYPE( BOOL, Bool, bool_value); + HANDLE_TYPE( STRING, String, *string_value); + HANDLE_TYPE( BYTES, Bytes, *string_value); + HANDLE_TYPE( ENUM, Enum, enum_value); + HANDLE_TYPE( GROUP, Group, *message_value); + HANDLE_TYPE( MESSAGE, Message, *message_value); +#undef HANDLE_TYPE + } + } +} + +void ExtensionSet::Extension::SerializeMessageSetItemWithCachedSizes( + int number, + io::CodedOutputStream* output) const { + if (type != WireFormatLite::TYPE_MESSAGE || is_repeated) { + // Not a valid MessageSet extension, but serialize it the normal way. + SerializeFieldWithCachedSizes(number, output); + return; + } + + if (is_cleared) return; + + // Start group. + output->WriteTag(WireFormatLite::kMessageSetItemStartTag); + + // Write type ID. + WireFormatLite::WriteUInt32(WireFormatLite::kMessageSetTypeIdNumber, + number, + output); + // Write message. + WireFormatLite::WriteMessageMaybeToArray( + WireFormatLite::kMessageSetMessageNumber, + *message_value, + output); + + // End group. + output->WriteTag(WireFormatLite::kMessageSetItemEndTag); +} + +int ExtensionSet::Extension::ByteSize(int number) const { + int result = 0; + + if (is_repeated) { + if (is_packed) { + switch (real_type(type)) { +#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE) \ + case WireFormatLite::TYPE_##UPPERCASE: \ + for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) { \ + result += WireFormatLite::CAMELCASE##Size( \ + repeated_##LOWERCASE##_value->Get(i)); \ + } \ + break + + HANDLE_TYPE( INT32, Int32, int32); + HANDLE_TYPE( INT64, Int64, int64); + HANDLE_TYPE( UINT32, UInt32, uint32); + HANDLE_TYPE( UINT64, UInt64, uint64); + HANDLE_TYPE( SINT32, SInt32, int32); + HANDLE_TYPE( SINT64, SInt64, int64); + HANDLE_TYPE( ENUM, Enum, enum); +#undef HANDLE_TYPE + + // Stuff with fixed size. +#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE) \ + case WireFormatLite::TYPE_##UPPERCASE: \ + result += WireFormatLite::k##CAMELCASE##Size * \ + repeated_##LOWERCASE##_value->size(); \ + break + HANDLE_TYPE( FIXED32, Fixed32, uint32); + HANDLE_TYPE( FIXED64, Fixed64, uint64); + HANDLE_TYPE(SFIXED32, SFixed32, int32); + HANDLE_TYPE(SFIXED64, SFixed64, int64); + HANDLE_TYPE( FLOAT, Float, float); + HANDLE_TYPE( DOUBLE, Double, double); + HANDLE_TYPE( BOOL, Bool, bool); +#undef HANDLE_TYPE + + case WireFormatLite::TYPE_STRING: + case WireFormatLite::TYPE_BYTES: + case WireFormatLite::TYPE_GROUP: + case WireFormatLite::TYPE_MESSAGE: + GOOGLE_LOG(FATAL) << "Non-primitive types can't be packed."; + break; + } + + cached_size = result; + if (result > 0) { + result += io::CodedOutputStream::VarintSize32(result); + result += io::CodedOutputStream::VarintSize32( + WireFormatLite::MakeTag(number, + WireFormatLite::WIRETYPE_LENGTH_DELIMITED)); + } + } else { + int tag_size = WireFormatLite::TagSize(number, real_type(type)); + + switch (real_type(type)) { +#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE) \ + case WireFormatLite::TYPE_##UPPERCASE: \ + result += tag_size * repeated_##LOWERCASE##_value->size(); \ + for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) { \ + result += WireFormatLite::CAMELCASE##Size( \ + repeated_##LOWERCASE##_value->Get(i)); \ + } \ + break + + HANDLE_TYPE( INT32, Int32, int32); + HANDLE_TYPE( INT64, Int64, int64); + HANDLE_TYPE( UINT32, UInt32, uint32); + HANDLE_TYPE( UINT64, UInt64, uint64); + HANDLE_TYPE( SINT32, SInt32, int32); + HANDLE_TYPE( SINT64, SInt64, int64); + HANDLE_TYPE( STRING, String, string); + HANDLE_TYPE( BYTES, Bytes, string); + HANDLE_TYPE( ENUM, Enum, enum); + HANDLE_TYPE( GROUP, Group, message); + HANDLE_TYPE( MESSAGE, Message, message); +#undef HANDLE_TYPE + + // Stuff with fixed size. +#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE) \ + case WireFormatLite::TYPE_##UPPERCASE: \ + result += (tag_size + WireFormatLite::k##CAMELCASE##Size) * \ + repeated_##LOWERCASE##_value->size(); \ + break + HANDLE_TYPE( FIXED32, Fixed32, uint32); + HANDLE_TYPE( FIXED64, Fixed64, uint64); + HANDLE_TYPE(SFIXED32, SFixed32, int32); + HANDLE_TYPE(SFIXED64, SFixed64, int64); + HANDLE_TYPE( FLOAT, Float, float); + HANDLE_TYPE( DOUBLE, Double, double); + HANDLE_TYPE( BOOL, Bool, bool); +#undef HANDLE_TYPE + } + } + } else if (!is_cleared) { + result += WireFormatLite::TagSize(number, real_type(type)); + switch (real_type(type)) { +#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE) \ + case WireFormatLite::TYPE_##UPPERCASE: \ + result += WireFormatLite::CAMELCASE##Size(LOWERCASE); \ + break + + HANDLE_TYPE( INT32, Int32, int32_value); + HANDLE_TYPE( INT64, Int64, int64_value); + HANDLE_TYPE( UINT32, UInt32, uint32_value); + HANDLE_TYPE( UINT64, UInt64, uint64_value); + HANDLE_TYPE( SINT32, SInt32, int32_value); + HANDLE_TYPE( SINT64, SInt64, int64_value); + HANDLE_TYPE( STRING, String, *string_value); + HANDLE_TYPE( BYTES, Bytes, *string_value); + HANDLE_TYPE( ENUM, Enum, enum_value); + HANDLE_TYPE( GROUP, Group, *message_value); + HANDLE_TYPE( MESSAGE, Message, *message_value); +#undef HANDLE_TYPE + + // Stuff with fixed size. +#define HANDLE_TYPE(UPPERCASE, CAMELCASE) \ + case WireFormatLite::TYPE_##UPPERCASE: \ + result += WireFormatLite::k##CAMELCASE##Size; \ + break + HANDLE_TYPE( FIXED32, Fixed32); + HANDLE_TYPE( FIXED64, Fixed64); + HANDLE_TYPE(SFIXED32, SFixed32); + HANDLE_TYPE(SFIXED64, SFixed64); + HANDLE_TYPE( FLOAT, Float); + HANDLE_TYPE( DOUBLE, Double); + HANDLE_TYPE( BOOL, Bool); +#undef HANDLE_TYPE + } + } + + return result; +} + +int ExtensionSet::Extension::MessageSetItemByteSize(int number) const { + if (type != WireFormatLite::TYPE_MESSAGE || is_repeated) { + // Not a valid MessageSet extension, but compute the byte size for it the + // normal way. + return ByteSize(number); + } + + if (is_cleared) return 0; + + int our_size = WireFormatLite::kMessageSetItemTagsSize; + + // type_id + our_size += io::CodedOutputStream::VarintSize32(number); + + // message + int message_size = message_value->ByteSize(); + + our_size += io::CodedOutputStream::VarintSize32(message_size); + our_size += message_size; + + return our_size; +} + +int ExtensionSet::Extension::GetSize() const { + GOOGLE_DCHECK(is_repeated); + switch (cpp_type(type)) { +#define HANDLE_TYPE(UPPERCASE, LOWERCASE) \ + case WireFormatLite::CPPTYPE_##UPPERCASE: \ + return repeated_##LOWERCASE##_value->size() + + HANDLE_TYPE( INT32, int32); + HANDLE_TYPE( INT64, int64); + HANDLE_TYPE( UINT32, uint32); + HANDLE_TYPE( UINT64, uint64); + HANDLE_TYPE( FLOAT, float); + HANDLE_TYPE( DOUBLE, double); + HANDLE_TYPE( BOOL, bool); + HANDLE_TYPE( ENUM, enum); + HANDLE_TYPE( STRING, string); + HANDLE_TYPE(MESSAGE, message); +#undef HANDLE_TYPE + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return 0; +} + +void ExtensionSet::Extension::Free() { + if (is_repeated) { + switch (cpp_type(type)) { +#define HANDLE_TYPE(UPPERCASE, LOWERCASE) \ + case WireFormatLite::CPPTYPE_##UPPERCASE: \ + delete repeated_##LOWERCASE##_value; \ + break + + HANDLE_TYPE( INT32, int32); + HANDLE_TYPE( INT64, int64); + HANDLE_TYPE( UINT32, uint32); + HANDLE_TYPE( UINT64, uint64); + HANDLE_TYPE( FLOAT, float); + HANDLE_TYPE( DOUBLE, double); + HANDLE_TYPE( BOOL, bool); + HANDLE_TYPE( ENUM, enum); + HANDLE_TYPE( STRING, string); + HANDLE_TYPE(MESSAGE, message); +#undef HANDLE_TYPE + } + } else { + switch (cpp_type(type)) { + case WireFormatLite::CPPTYPE_STRING: + delete string_value; + break; + case WireFormatLite::CPPTYPE_MESSAGE: + delete message_value; + break; + default: + break; + } + } +} + +// Defined in extension_set_heavy.cc. +// int ExtensionSet::Extension::SpaceUsedExcludingSelf() const + +} // namespace internal +} // namespace protobuf +} // namespace google diff --git a/depends/protobuf/google/protobuf/extension_set.h b/depends/protobuf/google/protobuf/extension_set.h new file mode 100644 index 0000000000..ac1ada029f --- /dev/null +++ b/depends/protobuf/google/protobuf/extension_set.h @@ -0,0 +1,904 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// This header is logically internal, but is made public because it is used +// from protocol-compiler-generated code, which may reside in other components. + +#ifndef GOOGLE_PROTOBUF_EXTENSION_SET_H__ +#define GOOGLE_PROTOBUF_EXTENSION_SET_H__ + +#include +#include +#include +#include + + +#include + +namespace google { + +namespace protobuf { + class Descriptor; // descriptor.h + class FieldDescriptor; // descriptor.h + class DescriptorPool; // descriptor.h + class MessageLite; // message_lite.h + class Message; // message.h + class MessageFactory; // message.h + class UnknownFieldSet; // unknown_field_set.h + namespace io { + class CodedInputStream; // coded_stream.h + class CodedOutputStream; // coded_stream.h + } + namespace internal { + class FieldSkipper; // wire_format_lite.h + class RepeatedPtrFieldBase; // repeated_field.h + } + template class RepeatedField; // repeated_field.h + template class RepeatedPtrField; // repeated_field.h +} + +namespace protobuf { +namespace internal { + +// Used to store values of type WireFormatLite::FieldType without having to +// #include wire_format_lite.h. Also, ensures that we use only one byte to +// store these values, which is important to keep the layout of +// ExtensionSet::Extension small. +typedef uint8 FieldType; + +// A function which, given an integer value, returns true if the number +// matches one of the defined values for the corresponding enum type. This +// is used with RegisterEnumExtension, below. +typedef bool EnumValidityFunc(int number); + +// Version of the above which takes an argument. This is needed to deal with +// extensions that are not compiled in. +typedef bool EnumValidityFuncWithArg(const void* arg, int number); + +// Information about a registered extension. +struct ExtensionInfo { + inline ExtensionInfo() {} + inline ExtensionInfo(FieldType type, bool is_repeated, bool is_packed) + : type(type), is_repeated(is_repeated), is_packed(is_packed), + descriptor(NULL) {} + + FieldType type; + bool is_repeated; + bool is_packed; + + struct EnumValidityCheck { + EnumValidityFuncWithArg* func; + const void* arg; + }; + + union { + EnumValidityCheck enum_validity_check; + const MessageLite* message_prototype; + }; + + // The descriptor for this extension, if one exists and is known. May be + // NULL. Must not be NULL if the descriptor for the extension does not + // live in the same pool as the descriptor for the containing type. + const FieldDescriptor* descriptor; +}; + +// Abstract interface for an object which looks up extension definitions. Used +// when parsing. +class LIBPROTOBUF_EXPORT ExtensionFinder { + public: + virtual ~ExtensionFinder(); + + // Find the extension with the given containing type and number. + virtual bool Find(int number, ExtensionInfo* output) = 0; +}; + +// Implementation of ExtensionFinder which finds extensions defined in .proto +// files which have been compiled into the binary. +class LIBPROTOBUF_EXPORT GeneratedExtensionFinder : public ExtensionFinder { + public: + GeneratedExtensionFinder(const MessageLite* containing_type) + : containing_type_(containing_type) {} + virtual ~GeneratedExtensionFinder() {} + + // Returns true and fills in *output if found, otherwise returns false. + virtual bool Find(int number, ExtensionInfo* output); + + private: + const MessageLite* containing_type_; +}; + +// Note: extension_set_heavy.cc defines DescriptorPoolExtensionFinder for +// finding extensions from a DescriptorPool. + +// This is an internal helper class intended for use within the protocol buffer +// library and generated classes. Clients should not use it directly. Instead, +// use the generated accessors such as GetExtension() of the class being +// extended. +// +// This class manages extensions for a protocol message object. The +// message's HasExtension(), GetExtension(), MutableExtension(), and +// ClearExtension() methods are just thin wrappers around the embedded +// ExtensionSet. When parsing, if a tag number is encountered which is +// inside one of the message type's extension ranges, the tag is passed +// off to the ExtensionSet for parsing. Etc. +class LIBPROTOBUF_EXPORT ExtensionSet { + public: + ExtensionSet(); + ~ExtensionSet(); + + // These are called at startup by protocol-compiler-generated code to + // register known extensions. The registrations are used by ParseField() + // to look up extensions for parsed field numbers. Note that dynamic parsing + // does not use ParseField(); only protocol-compiler-generated parsing + // methods do. + static void RegisterExtension(const MessageLite* containing_type, + int number, FieldType type, + bool is_repeated, bool is_packed); + static void RegisterEnumExtension(const MessageLite* containing_type, + int number, FieldType type, + bool is_repeated, bool is_packed, + EnumValidityFunc* is_valid); + static void RegisterMessageExtension(const MessageLite* containing_type, + int number, FieldType type, + bool is_repeated, bool is_packed, + const MessageLite* prototype); + + // ================================================================= + + // Add all fields which are currently present to the given vector. This + // is useful to implement Reflection::ListFields(). + void AppendToList(const Descriptor* containing_type, + const DescriptorPool* pool, + vector* output) const; + + // ================================================================= + // Accessors + // + // Generated message classes include type-safe templated wrappers around + // these methods. Generally you should use those rather than call these + // directly, unless you are doing low-level memory management. + // + // When calling any of these accessors, the extension number requested + // MUST exist in the DescriptorPool provided to the constructor. Otheriwse, + // the method will fail an assert. Normally, though, you would not call + // these directly; you would either call the generated accessors of your + // message class (e.g. GetExtension()) or you would call the accessors + // of the reflection interface. In both cases, it is impossible to + // trigger this assert failure: the generated accessors only accept + // linked-in extension types as parameters, while the Reflection interface + // requires you to provide the FieldDescriptor describing the extension. + // + // When calling any of these accessors, a protocol-compiler-generated + // implementation of the extension corresponding to the number MUST + // be linked in, and the FieldDescriptor used to refer to it MUST be + // the one generated by that linked-in code. Otherwise, the method will + // die on an assert failure. The message objects returned by the message + // accessors are guaranteed to be of the correct linked-in type. + // + // These methods pretty much match Reflection except that: + // - They're not virtual. + // - They identify fields by number rather than FieldDescriptors. + // - They identify enum values using integers rather than descriptors. + // - Strings provide Mutable() in addition to Set() accessors. + + bool Has(int number) const; + int ExtensionSize(int number) const; // Size of a repeated extension. + FieldType ExtensionType(int number) const; + void ClearExtension(int number); + + // singular fields ------------------------------------------------- + + int32 GetInt32 (int number, int32 default_value) const; + int64 GetInt64 (int number, int64 default_value) const; + uint32 GetUInt32(int number, uint32 default_value) const; + uint64 GetUInt64(int number, uint64 default_value) const; + float GetFloat (int number, float default_value) const; + double GetDouble(int number, double default_value) const; + bool GetBool (int number, bool default_value) const; + int GetEnum (int number, int default_value) const; + const string & GetString (int number, const string& default_value) const; + const MessageLite& GetMessage(int number, + const MessageLite& default_value) const; + const MessageLite& GetMessage(int number, const Descriptor* message_type, + MessageFactory* factory) const; + + // |descriptor| may be NULL so long as it is known that the descriptor for + // the extension lives in the same pool as the descriptor for the containing + // type. +#define desc const FieldDescriptor* descriptor // avoid line wrapping + void SetInt32 (int number, FieldType type, int32 value, desc); + void SetInt64 (int number, FieldType type, int64 value, desc); + void SetUInt32(int number, FieldType type, uint32 value, desc); + void SetUInt64(int number, FieldType type, uint64 value, desc); + void SetFloat (int number, FieldType type, float value, desc); + void SetDouble(int number, FieldType type, double value, desc); + void SetBool (int number, FieldType type, bool value, desc); + void SetEnum (int number, FieldType type, int value, desc); + void SetString(int number, FieldType type, const string& value, desc); + string * MutableString (int number, FieldType type, desc); + MessageLite* MutableMessage(int number, FieldType type, + const MessageLite& prototype, desc); + MessageLite* MutableMessage(const FieldDescriptor* decsriptor, + MessageFactory* factory); +#undef desc + + // repeated fields ------------------------------------------------- + + int32 GetRepeatedInt32 (int number, int index) const; + int64 GetRepeatedInt64 (int number, int index) const; + uint32 GetRepeatedUInt32(int number, int index) const; + uint64 GetRepeatedUInt64(int number, int index) const; + float GetRepeatedFloat (int number, int index) const; + double GetRepeatedDouble(int number, int index) const; + bool GetRepeatedBool (int number, int index) const; + int GetRepeatedEnum (int number, int index) const; + const string & GetRepeatedString (int number, int index) const; + const MessageLite& GetRepeatedMessage(int number, int index) const; + + void SetRepeatedInt32 (int number, int index, int32 value); + void SetRepeatedInt64 (int number, int index, int64 value); + void SetRepeatedUInt32(int number, int index, uint32 value); + void SetRepeatedUInt64(int number, int index, uint64 value); + void SetRepeatedFloat (int number, int index, float value); + void SetRepeatedDouble(int number, int index, double value); + void SetRepeatedBool (int number, int index, bool value); + void SetRepeatedEnum (int number, int index, int value); + void SetRepeatedString(int number, int index, const string& value); + string * MutableRepeatedString (int number, int index); + MessageLite* MutableRepeatedMessage(int number, int index); + +#define desc const FieldDescriptor* descriptor // avoid line wrapping + void AddInt32 (int number, FieldType type, bool packed, int32 value, desc); + void AddInt64 (int number, FieldType type, bool packed, int64 value, desc); + void AddUInt32(int number, FieldType type, bool packed, uint32 value, desc); + void AddUInt64(int number, FieldType type, bool packed, uint64 value, desc); + void AddFloat (int number, FieldType type, bool packed, float value, desc); + void AddDouble(int number, FieldType type, bool packed, double value, desc); + void AddBool (int number, FieldType type, bool packed, bool value, desc); + void AddEnum (int number, FieldType type, bool packed, int value, desc); + void AddString(int number, FieldType type, const string& value, desc); + string * AddString (int number, FieldType type, desc); + MessageLite* AddMessage(int number, FieldType type, + const MessageLite& prototype, desc); + MessageLite* AddMessage(const FieldDescriptor* descriptor, + MessageFactory* factory); +#undef desc + + void RemoveLast(int number); + void SwapElements(int number, int index1, int index2); + + // ----------------------------------------------------------------- + // TODO(kenton): Hardcore memory management accessors + + // ================================================================= + // convenience methods for implementing methods of Message + // + // These could all be implemented in terms of the other methods of this + // class, but providing them here helps keep the generated code size down. + + void Clear(); + void MergeFrom(const ExtensionSet& other); + void Swap(ExtensionSet* other); + bool IsInitialized() const; + + // Parses a single extension from the input. The input should start out + // positioned immediately after the tag. |containing_type| is the default + // instance for the containing message; it is used only to look up the + // extension by number. See RegisterExtension(), above. Unlike the other + // methods of ExtensionSet, this only works for generated message types -- + // it looks up extensions registered using RegisterExtension(). + bool ParseField(uint32 tag, io::CodedInputStream* input, + ExtensionFinder* extension_finder, + FieldSkipper* field_skipper); + + // Specific versions for lite or full messages (constructs the appropriate + // FieldSkipper automatically). + bool ParseField(uint32 tag, io::CodedInputStream* input, + const MessageLite* containing_type); + bool ParseField(uint32 tag, io::CodedInputStream* input, + const Message* containing_type, + UnknownFieldSet* unknown_fields); + + // Parse an entire message in MessageSet format. Such messages have no + // fields, only extensions. + bool ParseMessageSet(io::CodedInputStream* input, + ExtensionFinder* extension_finder, + FieldSkipper* field_skipper); + + // Specific versions for lite or full messages (constructs the appropriate + // FieldSkipper automatically). + bool ParseMessageSet(io::CodedInputStream* input, + const MessageLite* containing_type); + bool ParseMessageSet(io::CodedInputStream* input, + const Message* containing_type, + UnknownFieldSet* unknown_fields); + + // Write all extension fields with field numbers in the range + // [start_field_number, end_field_number) + // to the output stream, using the cached sizes computed when ByteSize() was + // last called. Note that the range bounds are inclusive-exclusive. + void SerializeWithCachedSizes(int start_field_number, + int end_field_number, + io::CodedOutputStream* output) const; + + // Same as SerializeWithCachedSizes, but without any bounds checking. + // The caller must ensure that target has sufficient capacity for the + // serialized extensions. + // + // Returns a pointer past the last written byte. + uint8* SerializeWithCachedSizesToArray(int start_field_number, + int end_field_number, + uint8* target) const; + + // Like above but serializes in MessageSet format. + void SerializeMessageSetWithCachedSizes(io::CodedOutputStream* output) const; + uint8* SerializeMessageSetWithCachedSizesToArray(uint8* target) const; + + // Returns the total serialized size of all the extensions. + int ByteSize() const; + + // Like ByteSize() but uses MessageSet format. + int MessageSetByteSize() const; + + // Returns (an estimate of) the total number of bytes used for storing the + // extensions in memory, excluding sizeof(*this). If the ExtensionSet is + // for a lite message (and thus possibly contains lite messages), the results + // are undefined (might work, might crash, might corrupt data, might not even + // be linked in). It's up to the protocol compiler to avoid calling this on + // such ExtensionSets (easy enough since lite messages don't implement + // SpaceUsed()). + int SpaceUsedExcludingSelf() const; + + private: + + struct Extension { + union { + int32 int32_value; + int64 int64_value; + uint32 uint32_value; + uint64 uint64_value; + float float_value; + double double_value; + bool bool_value; + int enum_value; + string* string_value; + MessageLite* message_value; + + RepeatedField * repeated_int32_value; + RepeatedField * repeated_int64_value; + RepeatedField * repeated_uint32_value; + RepeatedField * repeated_uint64_value; + RepeatedField * repeated_float_value; + RepeatedField * repeated_double_value; + RepeatedField * repeated_bool_value; + RepeatedField * repeated_enum_value; + RepeatedPtrField* repeated_string_value; + RepeatedPtrField* repeated_message_value; + }; + + FieldType type; + bool is_repeated; + + // For singular types, indicates if the extension is "cleared". This + // happens when an extension is set and then later cleared by the caller. + // We want to keep the Extension object around for reuse, so instead of + // removing it from the map, we just set is_cleared = true. This has no + // meaning for repeated types; for those, the size of the RepeatedField + // simply becomes zero when cleared. + bool is_cleared; + + // For repeated types, this indicates if the [packed=true] option is set. + bool is_packed; + + // The descriptor for this extension, if one exists and is known. May be + // NULL. Must not be NULL if the descriptor for the extension does not + // live in the same pool as the descriptor for the containing type. + const FieldDescriptor* descriptor; + + // For packed fields, the size of the packed data is recorded here when + // ByteSize() is called then used during serialization. + // TODO(kenton): Use atomic when C++ supports it. + mutable int cached_size; + + // Some helper methods for operations on a single Extension. + void SerializeFieldWithCachedSizes( + int number, + io::CodedOutputStream* output) const; + uint8* SerializeFieldWithCachedSizesToArray( + int number, + uint8* target) const; + void SerializeMessageSetItemWithCachedSizes( + int number, + io::CodedOutputStream* output) const; + uint8* SerializeMessageSetItemWithCachedSizesToArray( + int number, + uint8* target) const; + int ByteSize(int number) const; + int MessageSetItemByteSize(int number) const; + void Clear(); + int GetSize() const; + void Free(); + int SpaceUsedExcludingSelf() const; + }; + + + // Gets the extension with the given number, creating it if it does not + // already exist. Returns true if the extension did not already exist. + bool MaybeNewExtension(int number, const FieldDescriptor* descriptor, + Extension** result); + + // Parse a single MessageSet item -- called just after the item group start + // tag has been read. + bool ParseMessageSetItem(io::CodedInputStream* input, + ExtensionFinder* extension_finder, + FieldSkipper* field_skipper); + + + // Hack: RepeatedPtrFieldBase declares ExtensionSet as a friend. This + // friendship should automatically extend to ExtensionSet::Extension, but + // unfortunately some older compilers (e.g. GCC 3.4.4) do not implement this + // correctly. So, we must provide helpers for calling methods of that + // class. + + // Defined in extension_set_heavy.cc. + static inline int RepeatedMessage_SpaceUsedExcludingSelf( + RepeatedPtrFieldBase* field); + + // The Extension struct is small enough to be passed by value, so we use it + // directly as the value type in the map rather than use pointers. We use + // a map rather than hash_map here because we expect most ExtensionSets will + // only contain a small number of extensions whereas hash_map is optimized + // for 100 elements or more. Also, we want AppendToList() to order fields + // by field number. + map extensions_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ExtensionSet); +}; + +// These are just for convenience... +inline void ExtensionSet::SetString(int number, FieldType type, + const string& value, + const FieldDescriptor* descriptor) { + MutableString(number, type, descriptor)->assign(value); +} +inline void ExtensionSet::SetRepeatedString(int number, int index, + const string& value) { + MutableRepeatedString(number, index)->assign(value); +} +inline void ExtensionSet::AddString(int number, FieldType type, + const string& value, + const FieldDescriptor* descriptor) { + AddString(number, type, descriptor)->assign(value); +} + +// =================================================================== +// Glue for generated extension accessors + +// ------------------------------------------------------------------- +// Template magic + +// First we have a set of classes representing "type traits" for different +// field types. A type traits class knows how to implement basic accessors +// for extensions of a particular type given an ExtensionSet. The signature +// for a type traits class looks like this: +// +// class TypeTraits { +// public: +// typedef ? ConstType; +// typedef ? MutableType; +// +// static inline ConstType Get(int number, const ExtensionSet& set); +// static inline void Set(int number, ConstType value, ExtensionSet* set); +// static inline MutableType Mutable(int number, ExtensionSet* set); +// +// // Variants for repeated fields. +// static inline ConstType Get(int number, const ExtensionSet& set, +// int index); +// static inline void Set(int number, int index, +// ConstType value, ExtensionSet* set); +// static inline MutableType Mutable(int number, int index, +// ExtensionSet* set); +// static inline void Add(int number, ConstType value, ExtensionSet* set); +// static inline MutableType Add(int number, ExtensionSet* set); +// }; +// +// Not all of these methods make sense for all field types. For example, the +// "Mutable" methods only make sense for strings and messages, and the +// repeated methods only make sense for repeated types. So, each type +// traits class implements only the set of methods from this signature that it +// actually supports. This will cause a compiler error if the user tries to +// access an extension using a method that doesn't make sense for its type. +// For example, if "foo" is an extension of type "optional int32", then if you +// try to write code like: +// my_message.MutableExtension(foo) +// you will get a compile error because PrimitiveTypeTraits does not +// have a "Mutable()" method. + +// ------------------------------------------------------------------- +// PrimitiveTypeTraits + +// Since the ExtensionSet has different methods for each primitive type, +// we must explicitly define the methods of the type traits class for each +// known type. +template +class PrimitiveTypeTraits { + public: + typedef Type ConstType; + + static inline ConstType Get(int number, const ExtensionSet& set, + ConstType default_value); + static inline void Set(int number, FieldType field_type, + ConstType value, ExtensionSet* set); +}; + +template +class RepeatedPrimitiveTypeTraits { + public: + typedef Type ConstType; + + static inline Type Get(int number, const ExtensionSet& set, int index); + static inline void Set(int number, int index, Type value, ExtensionSet* set); + static inline void Add(int number, FieldType field_type, + bool is_packed, Type value, ExtensionSet* set); +}; + +#define PROTOBUF_DEFINE_PRIMITIVE_TYPE(TYPE, METHOD) \ +template<> inline TYPE PrimitiveTypeTraits::Get( \ + int number, const ExtensionSet& set, TYPE default_value) { \ + return set.Get##METHOD(number, default_value); \ +} \ +template<> inline void PrimitiveTypeTraits::Set( \ + int number, FieldType field_type, TYPE value, ExtensionSet* set) { \ + set->Set##METHOD(number, field_type, value, NULL); \ +} \ + \ +template<> inline TYPE RepeatedPrimitiveTypeTraits::Get( \ + int number, const ExtensionSet& set, int index) { \ + return set.GetRepeated##METHOD(number, index); \ +} \ +template<> inline void RepeatedPrimitiveTypeTraits::Set( \ + int number, int index, TYPE value, ExtensionSet* set) { \ + set->SetRepeated##METHOD(number, index, value); \ +} \ +template<> inline void RepeatedPrimitiveTypeTraits::Add( \ + int number, FieldType field_type, bool is_packed, \ + TYPE value, ExtensionSet* set) { \ + set->Add##METHOD(number, field_type, is_packed, value, NULL); \ +} + +PROTOBUF_DEFINE_PRIMITIVE_TYPE( int32, Int32) +PROTOBUF_DEFINE_PRIMITIVE_TYPE( int64, Int64) +PROTOBUF_DEFINE_PRIMITIVE_TYPE(uint32, UInt32) +PROTOBUF_DEFINE_PRIMITIVE_TYPE(uint64, UInt64) +PROTOBUF_DEFINE_PRIMITIVE_TYPE( float, Float) +PROTOBUF_DEFINE_PRIMITIVE_TYPE(double, Double) +PROTOBUF_DEFINE_PRIMITIVE_TYPE( bool, Bool) + +#undef PROTOBUF_DEFINE_PRIMITIVE_TYPE + +// ------------------------------------------------------------------- +// StringTypeTraits + +// Strings support both Set() and Mutable(). +class LIBPROTOBUF_EXPORT StringTypeTraits { + public: + typedef const string& ConstType; + typedef string* MutableType; + + static inline const string& Get(int number, const ExtensionSet& set, + ConstType default_value) { + return set.GetString(number, default_value); + } + static inline void Set(int number, FieldType field_type, + const string& value, ExtensionSet* set) { + set->SetString(number, field_type, value, NULL); + } + static inline string* Mutable(int number, FieldType field_type, + ExtensionSet* set) { + return set->MutableString(number, field_type, NULL); + } +}; + +class LIBPROTOBUF_EXPORT RepeatedStringTypeTraits { + public: + typedef const string& ConstType; + typedef string* MutableType; + + static inline const string& Get(int number, const ExtensionSet& set, + int index) { + return set.GetRepeatedString(number, index); + } + static inline void Set(int number, int index, + const string& value, ExtensionSet* set) { + set->SetRepeatedString(number, index, value); + } + static inline string* Mutable(int number, int index, ExtensionSet* set) { + return set->MutableRepeatedString(number, index); + } + static inline void Add(int number, FieldType field_type, + bool /*is_packed*/, const string& value, + ExtensionSet* set) { + set->AddString(number, field_type, value, NULL); + } + static inline string* Add(int number, FieldType field_type, + ExtensionSet* set) { + return set->AddString(number, field_type, NULL); + } +}; + +// ------------------------------------------------------------------- +// EnumTypeTraits + +// ExtensionSet represents enums using integers internally, so we have to +// static_cast around. +template +class EnumTypeTraits { + public: + typedef Type ConstType; + + static inline ConstType Get(int number, const ExtensionSet& set, + ConstType default_value) { + return static_cast(set.GetEnum(number, default_value)); + } + static inline void Set(int number, FieldType field_type, + ConstType value, ExtensionSet* set) { + GOOGLE_DCHECK(IsValid(value)); + set->SetEnum(number, field_type, value, NULL); + } +}; + +template +class RepeatedEnumTypeTraits { + public: + typedef Type ConstType; + + static inline ConstType Get(int number, const ExtensionSet& set, int index) { + return static_cast(set.GetRepeatedEnum(number, index)); + } + static inline void Set(int number, int index, + ConstType value, ExtensionSet* set) { + GOOGLE_DCHECK(IsValid(value)); + set->SetRepeatedEnum(number, index, value); + } + static inline void Add(int number, FieldType field_type, + bool is_packed, ConstType value, ExtensionSet* set) { + GOOGLE_DCHECK(IsValid(value)); + set->AddEnum(number, field_type, is_packed, value, NULL); + } +}; + +// ------------------------------------------------------------------- +// MessageTypeTraits + +// ExtensionSet guarantees that when manipulating extensions with message +// types, the implementation used will be the compiled-in class representing +// that type. So, we can static_cast down to the exact type we expect. +template +class MessageTypeTraits { + public: + typedef const Type& ConstType; + typedef Type* MutableType; + + static inline ConstType Get(int number, const ExtensionSet& set, + ConstType default_value) { + return static_cast( + set.GetMessage(number, default_value)); + } + static inline MutableType Mutable(int number, FieldType field_type, + ExtensionSet* set) { + return static_cast( + set->MutableMessage(number, field_type, Type::default_instance(), NULL)); + } +}; + +template +class RepeatedMessageTypeTraits { + public: + typedef const Type& ConstType; + typedef Type* MutableType; + + static inline ConstType Get(int number, const ExtensionSet& set, int index) { + return static_cast(set.GetRepeatedMessage(number, index)); + } + static inline MutableType Mutable(int number, int index, ExtensionSet* set) { + return static_cast(set->MutableRepeatedMessage(number, index)); + } + static inline MutableType Add(int number, FieldType field_type, + ExtensionSet* set) { + return static_cast( + set->AddMessage(number, field_type, Type::default_instance(), NULL)); + } +}; + +// ------------------------------------------------------------------- +// ExtensionIdentifier + +// This is the type of actual extension objects. E.g. if you have: +// extends Foo with optional int32 bar = 1234; +// then "bar" will be defined in C++ as: +// ExtensionIdentifier, 1, false> bar(1234); +// +// Note that we could, in theory, supply the field number as a template +// parameter, and thus make an instance of ExtensionIdentifier have no +// actual contents. However, if we did that, then using at extension +// identifier would not necessarily cause the compiler to output any sort +// of reference to any simple defined in the extension's .pb.o file. Some +// linkers will actually drop object files that are not explicitly referenced, +// but that would be bad because it would cause this extension to not be +// registered at static initialization, and therefore using it would crash. + +template +class ExtensionIdentifier { + public: + typedef TypeTraitsType TypeTraits; + typedef ExtendeeType Extendee; + + ExtensionIdentifier(int number, typename TypeTraits::ConstType default_value) + : number_(number), default_value_(default_value) {} + inline int number() const { return number_; } + typename TypeTraits::ConstType default_value() const { + return default_value_; + } + + private: + const int number_; + typename TypeTraits::ConstType default_value_; +}; + +// ------------------------------------------------------------------- +// Generated accessors + +// This macro should be expanded in the context of a generated type which +// has extensions. +// +// We use "_proto_TypeTraits" as a type name below because "TypeTraits" +// causes problems if the class has a nested message or enum type with that +// name and "_TypeTraits" is technically reserved for the C++ library since +// it starts with an underscore followed by a capital letter. +#define GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(CLASSNAME) \ + /* Has, Size, Clear */ \ + template \ + inline bool HasExtension( \ + const ::google::protobuf::internal::ExtensionIdentifier< \ + CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id) const { \ + return _extensions_.Has(id.number()); \ + } \ + \ + template \ + inline void ClearExtension( \ + const ::google::protobuf::internal::ExtensionIdentifier< \ + CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id) { \ + _extensions_.ClearExtension(id.number()); \ + } \ + \ + template \ + inline int ExtensionSize( \ + const ::google::protobuf::internal::ExtensionIdentifier< \ + CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id) const { \ + return _extensions_.ExtensionSize(id.number()); \ + } \ + \ + /* Singular accessors */ \ + template \ + inline typename _proto_TypeTraits::ConstType GetExtension( \ + const ::google::protobuf::internal::ExtensionIdentifier< \ + CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id) const { \ + return _proto_TypeTraits::Get(id.number(), _extensions_, \ + id.default_value()); \ + } \ + \ + template \ + inline typename _proto_TypeTraits::MutableType MutableExtension( \ + const ::google::protobuf::internal::ExtensionIdentifier< \ + CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id) { \ + return _proto_TypeTraits::Mutable(id.number(), field_type, &_extensions_);\ + } \ + \ + template \ + inline void SetExtension( \ + const ::google::protobuf::internal::ExtensionIdentifier< \ + CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id, \ + typename _proto_TypeTraits::ConstType value) { \ + _proto_TypeTraits::Set(id.number(), field_type, value, &_extensions_); \ + } \ + \ + /* Repeated accessors */ \ + template \ + inline typename _proto_TypeTraits::ConstType GetExtension( \ + const ::google::protobuf::internal::ExtensionIdentifier< \ + CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id, \ + int index) const { \ + return _proto_TypeTraits::Get(id.number(), _extensions_, index); \ + } \ + \ + template \ + inline typename _proto_TypeTraits::MutableType MutableExtension( \ + const ::google::protobuf::internal::ExtensionIdentifier< \ + CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id, \ + int index) { \ + return _proto_TypeTraits::Mutable(id.number(), index, &_extensions_); \ + } \ + \ + template \ + inline void SetExtension( \ + const ::google::protobuf::internal::ExtensionIdentifier< \ + CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id, \ + int index, typename _proto_TypeTraits::ConstType value) { \ + _proto_TypeTraits::Set(id.number(), index, value, &_extensions_); \ + } \ + \ + template \ + inline typename _proto_TypeTraits::MutableType AddExtension( \ + const ::google::protobuf::internal::ExtensionIdentifier< \ + CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id) { \ + return _proto_TypeTraits::Add(id.number(), field_type, &_extensions_); \ + } \ + \ + template \ + inline void AddExtension( \ + const ::google::protobuf::internal::ExtensionIdentifier< \ + CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id, \ + typename _proto_TypeTraits::ConstType value) { \ + _proto_TypeTraits::Add(id.number(), field_type, is_packed, \ + value, &_extensions_); \ + } + +} // namespace internal +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_EXTENSION_SET_H__ diff --git a/depends/protobuf/google/protobuf/extension_set_heavy.cc b/depends/protobuf/google/protobuf/extension_set_heavy.cc new file mode 100644 index 0000000000..2721f15dcd --- /dev/null +++ b/depends/protobuf/google/protobuf/extension_set_heavy.cc @@ -0,0 +1,457 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// Contains methods defined in extension_set.h which cannot be part of the +// lite library because they use descriptors or reflection. + +#include +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { +namespace internal { + +// Implementation of ExtensionFinder which finds extensions in a given +// DescriptorPool, using the given MessageFactory to construct sub-objects. +// This class is implemented in extension_set_heavy.cc. +class DescriptorPoolExtensionFinder : public ExtensionFinder { + public: + DescriptorPoolExtensionFinder(const DescriptorPool* pool, + MessageFactory* factory, + const Descriptor* containing_type) + : pool_(pool), factory_(factory), containing_type_(containing_type) {} + virtual ~DescriptorPoolExtensionFinder() {} + + virtual bool Find(int number, ExtensionInfo* output); + + private: + const DescriptorPool* pool_; + MessageFactory* factory_; + const Descriptor* containing_type_; +}; + +void ExtensionSet::AppendToList(const Descriptor* containing_type, + const DescriptorPool* pool, + vector* output) const { + for (map::const_iterator iter = extensions_.begin(); + iter != extensions_.end(); ++iter) { + bool has = false; + if (iter->second.is_repeated) { + has = iter->second.GetSize() > 0; + } else { + has = !iter->second.is_cleared; + } + + if (has) { + // TODO(kenton): Looking up each field by number is somewhat unfortunate. + // Is there a better way? The problem is that descriptors are lazily- + // initialized, so they might not even be constructed until + // AppendToList() is called. + + if (iter->second.descriptor == NULL) { + output->push_back(pool->FindExtensionByNumber( + containing_type, iter->first)); + } else { + output->push_back(iter->second.descriptor); + } + } + } +} + +inline FieldDescriptor::Type real_type(FieldType type) { + GOOGLE_DCHECK(type > 0 && type <= FieldDescriptor::MAX_TYPE); + return static_cast(type); +} + +inline FieldDescriptor::CppType cpp_type(FieldType type) { + return FieldDescriptor::TypeToCppType( + static_cast(type)); +} + +#define GOOGLE_DCHECK_TYPE(EXTENSION, LABEL, CPPTYPE) \ + GOOGLE_DCHECK_EQ((EXTENSION).is_repeated ? FieldDescriptor::LABEL_REPEATED \ + : FieldDescriptor::LABEL_OPTIONAL, \ + FieldDescriptor::LABEL_##LABEL); \ + GOOGLE_DCHECK_EQ(cpp_type((EXTENSION).type), FieldDescriptor::CPPTYPE_##CPPTYPE) + +const MessageLite& ExtensionSet::GetMessage(int number, + const Descriptor* message_type, + MessageFactory* factory) const { + map::const_iterator iter = extensions_.find(number); + if (iter == extensions_.end() || iter->second.is_cleared) { + // Not present. Return the default value. + return *factory->GetPrototype(message_type); + } else { + GOOGLE_DCHECK_TYPE(iter->second, OPTIONAL, MESSAGE); + return *iter->second.message_value; + } +} + +MessageLite* ExtensionSet::MutableMessage(const FieldDescriptor* descriptor, + MessageFactory* factory) { + Extension* extension; + if (MaybeNewExtension(descriptor->number(), descriptor, &extension)) { + extension->type = descriptor->type(); + GOOGLE_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_MESSAGE); + extension->is_repeated = false; + extension->is_packed = false; + const MessageLite* prototype = + factory->GetPrototype(descriptor->message_type()); + GOOGLE_CHECK(prototype != NULL); + extension->message_value = prototype->New(); + } else { + GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE); + } + extension->is_cleared = false; + return extension->message_value; +} + +MessageLite* ExtensionSet::AddMessage(const FieldDescriptor* descriptor, + MessageFactory* factory) { + Extension* extension; + if (MaybeNewExtension(descriptor->number(), descriptor, &extension)) { + extension->type = descriptor->type(); + GOOGLE_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_MESSAGE); + extension->is_repeated = true; + extension->repeated_message_value = + new RepeatedPtrField(); + } else { + GOOGLE_DCHECK_TYPE(*extension, REPEATED, MESSAGE); + } + + // RepeatedPtrField does not know how to Add() since it cannot + // allocate an abstract object, so we have to be tricky. + MessageLite* result = extension->repeated_message_value + ->AddFromCleared >(); + if (result == NULL) { + const MessageLite* prototype; + if (extension->repeated_message_value->size() == 0) { + prototype = factory->GetPrototype(descriptor->message_type()); + GOOGLE_CHECK(prototype != NULL); + } else { + prototype = &extension->repeated_message_value->Get(0); + } + result = prototype->New(); + extension->repeated_message_value->AddAllocated(result); + } + return result; +} + +static bool ValidateEnumUsingDescriptor(const void* arg, int number) { + return reinterpret_cast(arg) + ->FindValueByNumber(number) != NULL; +} + +bool DescriptorPoolExtensionFinder::Find(int number, ExtensionInfo* output) { + const FieldDescriptor* extension = + pool_->FindExtensionByNumber(containing_type_, number); + if (extension == NULL) { + return false; + } else { + output->type = extension->type(); + output->is_repeated = extension->is_repeated(); + output->is_packed = extension->options().packed(); + output->descriptor = extension; + if (extension->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + output->message_prototype = + factory_->GetPrototype(extension->message_type()); + GOOGLE_CHECK(output->message_prototype != NULL) + << "Extension factory's GetPrototype() returned NULL for extension: " + << extension->full_name(); + } else if (extension->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) { + output->enum_validity_check.func = ValidateEnumUsingDescriptor; + output->enum_validity_check.arg = extension->enum_type(); + } + + return true; + } +} + +bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input, + const Message* containing_type, + UnknownFieldSet* unknown_fields) { + UnknownFieldSetFieldSkipper skipper(unknown_fields); + if (input->GetExtensionPool() == NULL) { + GeneratedExtensionFinder finder(containing_type); + return ParseField(tag, input, &finder, &skipper); + } else { + DescriptorPoolExtensionFinder finder(input->GetExtensionPool(), + input->GetExtensionFactory(), + containing_type->GetDescriptor()); + return ParseField(tag, input, &finder, &skipper); + } +} + +bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input, + const Message* containing_type, + UnknownFieldSet* unknown_fields) { + UnknownFieldSetFieldSkipper skipper(unknown_fields); + if (input->GetExtensionPool() == NULL) { + GeneratedExtensionFinder finder(containing_type); + return ParseMessageSet(input, &finder, &skipper); + } else { + DescriptorPoolExtensionFinder finder(input->GetExtensionPool(), + input->GetExtensionFactory(), + containing_type->GetDescriptor()); + return ParseMessageSet(input, &finder, &skipper); + } +} + +int ExtensionSet::SpaceUsedExcludingSelf() const { + int total_size = + extensions_.size() * sizeof(map::value_type); + for (map::const_iterator iter = extensions_.begin(), + end = extensions_.end(); + iter != end; + ++iter) { + total_size += iter->second.SpaceUsedExcludingSelf(); + } + return total_size; +} + +inline int ExtensionSet::RepeatedMessage_SpaceUsedExcludingSelf( + RepeatedPtrFieldBase* field) { + return field->SpaceUsedExcludingSelf >(); +} + +int ExtensionSet::Extension::SpaceUsedExcludingSelf() const { + int total_size = 0; + if (is_repeated) { + switch (cpp_type(type)) { +#define HANDLE_TYPE(UPPERCASE, LOWERCASE) \ + case FieldDescriptor::CPPTYPE_##UPPERCASE: \ + total_size += sizeof(*repeated_##LOWERCASE##_value) + \ + repeated_##LOWERCASE##_value->SpaceUsedExcludingSelf();\ + break + + HANDLE_TYPE( INT32, int32); + HANDLE_TYPE( INT64, int64); + HANDLE_TYPE( UINT32, uint32); + HANDLE_TYPE( UINT64, uint64); + HANDLE_TYPE( FLOAT, float); + HANDLE_TYPE( DOUBLE, double); + HANDLE_TYPE( BOOL, bool); + HANDLE_TYPE( ENUM, enum); + HANDLE_TYPE( STRING, string); +#undef HANDLE_TYPE + + case FieldDescriptor::CPPTYPE_MESSAGE: + // repeated_message_value is actually a RepeatedPtrField, + // but MessageLite has no SpaceUsed(), so we must directly call + // RepeatedPtrFieldBase::SpaceUsedExcludingSelf() with a different type + // handler. + total_size += sizeof(*repeated_message_value) + + RepeatedMessage_SpaceUsedExcludingSelf(repeated_message_value); + break; + } + } else { + switch (cpp_type(type)) { + case FieldDescriptor::CPPTYPE_STRING: + total_size += sizeof(*string_value) + + StringSpaceUsedExcludingSelf(*string_value); + break; + case FieldDescriptor::CPPTYPE_MESSAGE: + total_size += down_cast(message_value)->SpaceUsed(); + break; + default: + // No extra storage costs for primitive types. + break; + } + } + return total_size; +} + +// The Serialize*ToArray methods are only needed in the heavy library, as +// the lite library only generates SerializeWithCachedSizes. +uint8* ExtensionSet::SerializeWithCachedSizesToArray( + int start_field_number, int end_field_number, + uint8* target) const { + map::const_iterator iter; + for (iter = extensions_.lower_bound(start_field_number); + iter != extensions_.end() && iter->first < end_field_number; + ++iter) { + target = iter->second.SerializeFieldWithCachedSizesToArray(iter->first, + target); + } + return target; +} + +uint8* ExtensionSet::SerializeMessageSetWithCachedSizesToArray( + uint8* target) const { + map::const_iterator iter; + for (iter = extensions_.begin(); iter != extensions_.end(); ++iter) { + target = iter->second.SerializeMessageSetItemWithCachedSizesToArray( + iter->first, target); + } + return target; +} + +uint8* ExtensionSet::Extension::SerializeFieldWithCachedSizesToArray( + int number, uint8* target) const { + if (is_repeated) { + if (is_packed) { + if (cached_size == 0) return target; + + target = WireFormatLite::WriteTagToArray(number, + WireFormatLite::WIRETYPE_LENGTH_DELIMITED, target); + target = WireFormatLite::WriteInt32NoTagToArray(cached_size, target); + + switch (real_type(type)) { +#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE) \ + case FieldDescriptor::TYPE_##UPPERCASE: \ + for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) { \ + target = WireFormatLite::Write##CAMELCASE##NoTagToArray( \ + repeated_##LOWERCASE##_value->Get(i), target); \ + } \ + break + + HANDLE_TYPE( INT32, Int32, int32); + HANDLE_TYPE( INT64, Int64, int64); + HANDLE_TYPE( UINT32, UInt32, uint32); + HANDLE_TYPE( UINT64, UInt64, uint64); + HANDLE_TYPE( SINT32, SInt32, int32); + HANDLE_TYPE( SINT64, SInt64, int64); + HANDLE_TYPE( FIXED32, Fixed32, uint32); + HANDLE_TYPE( FIXED64, Fixed64, uint64); + HANDLE_TYPE(SFIXED32, SFixed32, int32); + HANDLE_TYPE(SFIXED64, SFixed64, int64); + HANDLE_TYPE( FLOAT, Float, float); + HANDLE_TYPE( DOUBLE, Double, double); + HANDLE_TYPE( BOOL, Bool, bool); + HANDLE_TYPE( ENUM, Enum, enum); +#undef HANDLE_TYPE + + case WireFormatLite::TYPE_STRING: + case WireFormatLite::TYPE_BYTES: + case WireFormatLite::TYPE_GROUP: + case WireFormatLite::TYPE_MESSAGE: + GOOGLE_LOG(FATAL) << "Non-primitive types can't be packed."; + break; + } + } else { + switch (real_type(type)) { +#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE) \ + case FieldDescriptor::TYPE_##UPPERCASE: \ + for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) { \ + target = WireFormatLite::Write##CAMELCASE##ToArray(number, \ + repeated_##LOWERCASE##_value->Get(i), target); \ + } \ + break + + HANDLE_TYPE( INT32, Int32, int32); + HANDLE_TYPE( INT64, Int64, int64); + HANDLE_TYPE( UINT32, UInt32, uint32); + HANDLE_TYPE( UINT64, UInt64, uint64); + HANDLE_TYPE( SINT32, SInt32, int32); + HANDLE_TYPE( SINT64, SInt64, int64); + HANDLE_TYPE( FIXED32, Fixed32, uint32); + HANDLE_TYPE( FIXED64, Fixed64, uint64); + HANDLE_TYPE(SFIXED32, SFixed32, int32); + HANDLE_TYPE(SFIXED64, SFixed64, int64); + HANDLE_TYPE( FLOAT, Float, float); + HANDLE_TYPE( DOUBLE, Double, double); + HANDLE_TYPE( BOOL, Bool, bool); + HANDLE_TYPE( STRING, String, string); + HANDLE_TYPE( BYTES, Bytes, string); + HANDLE_TYPE( ENUM, Enum, enum); + HANDLE_TYPE( GROUP, Group, message); + HANDLE_TYPE( MESSAGE, Message, message); +#undef HANDLE_TYPE + } + } + } else if (!is_cleared) { + switch (real_type(type)) { +#define HANDLE_TYPE(UPPERCASE, CAMELCASE, VALUE) \ + case FieldDescriptor::TYPE_##UPPERCASE: \ + target = WireFormatLite::Write##CAMELCASE##ToArray( \ + number, VALUE, target); \ + break + + HANDLE_TYPE( INT32, Int32, int32_value); + HANDLE_TYPE( INT64, Int64, int64_value); + HANDLE_TYPE( UINT32, UInt32, uint32_value); + HANDLE_TYPE( UINT64, UInt64, uint64_value); + HANDLE_TYPE( SINT32, SInt32, int32_value); + HANDLE_TYPE( SINT64, SInt64, int64_value); + HANDLE_TYPE( FIXED32, Fixed32, uint32_value); + HANDLE_TYPE( FIXED64, Fixed64, uint64_value); + HANDLE_TYPE(SFIXED32, SFixed32, int32_value); + HANDLE_TYPE(SFIXED64, SFixed64, int64_value); + HANDLE_TYPE( FLOAT, Float, float_value); + HANDLE_TYPE( DOUBLE, Double, double_value); + HANDLE_TYPE( BOOL, Bool, bool_value); + HANDLE_TYPE( STRING, String, *string_value); + HANDLE_TYPE( BYTES, Bytes, *string_value); + HANDLE_TYPE( ENUM, Enum, enum_value); + HANDLE_TYPE( GROUP, Group, *message_value); + HANDLE_TYPE( MESSAGE, Message, *message_value); +#undef HANDLE_TYPE + } + } + return target; +} + +uint8* ExtensionSet::Extension::SerializeMessageSetItemWithCachedSizesToArray( + int number, + uint8* target) const { + if (type != WireFormatLite::TYPE_MESSAGE || is_repeated) { + // Not a valid MessageSet extension, but serialize it the normal way. + GOOGLE_LOG(WARNING) << "Invalid message set extension."; + return SerializeFieldWithCachedSizesToArray(number, target); + } + + if (is_cleared) return target; + + // Start group. + target = io::CodedOutputStream::WriteTagToArray( + WireFormatLite::kMessageSetItemStartTag, target); + // Write type ID. + target = WireFormatLite::WriteUInt32ToArray( + WireFormatLite::kMessageSetTypeIdNumber, number, target); + // Write message. + target = WireFormatLite::WriteMessageToArray( + WireFormatLite::kMessageSetMessageNumber, *message_value, target); + // End group. + target = io::CodedOutputStream::WriteTagToArray( + WireFormatLite::kMessageSetItemEndTag, target); + return target; +} + +} // namespace internal +} // namespace protobuf +} // namespace google diff --git a/depends/protobuf/google/protobuf/extension_set_unittest.cc b/depends/protobuf/google/protobuf/extension_set_unittest.cc new file mode 100644 index 0000000000..000f846c7f --- /dev/null +++ b/depends/protobuf/google/protobuf/extension_set_unittest.cc @@ -0,0 +1,642 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { +namespace internal { +namespace { + +// This test closely mirrors google/protobuf/compiler/cpp/unittest.cc +// except that it uses extensions rather than regular fields. + +TEST(ExtensionSetTest, Defaults) { + // Check that all default values are set correctly in the initial message. + unittest::TestAllExtensions message; + + TestUtil::ExpectExtensionsClear(message); + + // Messages should return pointers to default instances until first use. + // (This is not checked by ExpectClear() since it is not actually true after + // the fields have been set and then cleared.) + EXPECT_EQ(&unittest::OptionalGroup_extension::default_instance(), + &message.GetExtension(unittest::optionalgroup_extension)); + EXPECT_EQ(&unittest::TestAllTypes::NestedMessage::default_instance(), + &message.GetExtension(unittest::optional_nested_message_extension)); + EXPECT_EQ(&unittest::ForeignMessage::default_instance(), + &message.GetExtension( + unittest::optional_foreign_message_extension)); + EXPECT_EQ(&unittest_import::ImportMessage::default_instance(), + &message.GetExtension(unittest::optional_import_message_extension)); +} + +TEST(ExtensionSetTest, Accessors) { + // Set every field to a unique value then go back and check all those + // values. + unittest::TestAllExtensions message; + + TestUtil::SetAllExtensions(&message); + TestUtil::ExpectAllExtensionsSet(message); + + TestUtil::ModifyRepeatedExtensions(&message); + TestUtil::ExpectRepeatedExtensionsModified(message); +} + +TEST(ExtensionSetTest, Clear) { + // Set every field to a unique value, clear the message, then check that + // it is cleared. + unittest::TestAllExtensions message; + + TestUtil::SetAllExtensions(&message); + message.Clear(); + TestUtil::ExpectExtensionsClear(message); + + // Unlike with the defaults test, we do NOT expect that requesting embedded + // messages will return a pointer to the default instance. Instead, they + // should return the objects that were created when mutable_blah() was + // called. + EXPECT_NE(&unittest::OptionalGroup_extension::default_instance(), + &message.GetExtension(unittest::optionalgroup_extension)); + EXPECT_NE(&unittest::TestAllTypes::NestedMessage::default_instance(), + &message.GetExtension(unittest::optional_nested_message_extension)); + EXPECT_NE(&unittest::ForeignMessage::default_instance(), + &message.GetExtension( + unittest::optional_foreign_message_extension)); + EXPECT_NE(&unittest_import::ImportMessage::default_instance(), + &message.GetExtension(unittest::optional_import_message_extension)); + + // Make sure setting stuff again after clearing works. (This takes slightly + // different code paths since the objects are reused.) + TestUtil::SetAllExtensions(&message); + TestUtil::ExpectAllExtensionsSet(message); +} + +TEST(ExtensionSetTest, ClearOneField) { + // Set every field to a unique value, then clear one value and insure that + // only that one value is cleared. + unittest::TestAllExtensions message; + + TestUtil::SetAllExtensions(&message); + int64 original_value = + message.GetExtension(unittest::optional_int64_extension); + + // Clear the field and make sure it shows up as cleared. + message.ClearExtension(unittest::optional_int64_extension); + EXPECT_FALSE(message.HasExtension(unittest::optional_int64_extension)); + EXPECT_EQ(0, message.GetExtension(unittest::optional_int64_extension)); + + // Other adjacent fields should not be cleared. + EXPECT_TRUE(message.HasExtension(unittest::optional_int32_extension)); + EXPECT_TRUE(message.HasExtension(unittest::optional_uint32_extension)); + + // Make sure if we set it again, then all fields are set. + message.SetExtension(unittest::optional_int64_extension, original_value); + TestUtil::ExpectAllExtensionsSet(message); +} + +TEST(ExtensionSetTest, CopyFrom) { + unittest::TestAllExtensions message1, message2; + string data; + + TestUtil::SetAllExtensions(&message1); + message2.CopyFrom(message1); + TestUtil::ExpectAllExtensionsSet(message2); +} + +TEST(ExtensionSetTest, CopyFromUpcasted) { + unittest::TestAllExtensions message1, message2; + string data; + const Message& upcasted_message = message1; + + TestUtil::SetAllExtensions(&message1); + message2.CopyFrom(upcasted_message); + TestUtil::ExpectAllExtensionsSet(message2); +} + +TEST(ExtensionSetTest, SwapWithEmpty) { + unittest::TestAllExtensions message1, message2; + TestUtil::SetAllExtensions(&message1); + + TestUtil::ExpectAllExtensionsSet(message1); + TestUtil::ExpectExtensionsClear(message2); + message1.Swap(&message2); + TestUtil::ExpectAllExtensionsSet(message2); + TestUtil::ExpectExtensionsClear(message1); +} + +TEST(ExtensionSetTest, SwapWithSelf) { + unittest::TestAllExtensions message; + TestUtil::SetAllExtensions(&message); + + TestUtil::ExpectAllExtensionsSet(message); + message.Swap(&message); + TestUtil::ExpectAllExtensionsSet(message); +} + +TEST(ExtensionSetTest, SerializationToArray) { + // Serialize as TestAllExtensions and parse as TestAllTypes to insure wire + // compatibility of extensions. + // + // This checks serialization to a flat array by explicitly reserving space in + // the string and calling the generated message's + // SerializeWithCachedSizesToArray. + unittest::TestAllExtensions source; + unittest::TestAllTypes destination; + TestUtil::SetAllExtensions(&source); + int size = source.ByteSize(); + string data; + data.resize(size); + uint8* target = reinterpret_cast(string_as_array(&data)); + uint8* end = source.SerializeWithCachedSizesToArray(target); + EXPECT_EQ(size, end - target); + EXPECT_TRUE(destination.ParseFromString(data)); + TestUtil::ExpectAllFieldsSet(destination); +} + +TEST(ExtensionSetTest, SerializationToStream) { + // Serialize as TestAllExtensions and parse as TestAllTypes to insure wire + // compatibility of extensions. + // + // This checks serialization to an output stream by creating an array output + // stream that can only buffer 1 byte at a time - this prevents the message + // from ever jumping to the fast path, ensuring that serialization happens via + // the CodedOutputStream. + unittest::TestAllExtensions source; + unittest::TestAllTypes destination; + TestUtil::SetAllExtensions(&source); + int size = source.ByteSize(); + string data; + data.resize(size); + { + io::ArrayOutputStream array_stream(string_as_array(&data), size, 1); + io::CodedOutputStream output_stream(&array_stream); + source.SerializeWithCachedSizes(&output_stream); + ASSERT_FALSE(output_stream.HadError()); + } + EXPECT_TRUE(destination.ParseFromString(data)); + TestUtil::ExpectAllFieldsSet(destination); +} + +TEST(ExtensionSetTest, PackedSerializationToArray) { + // Serialize as TestPackedExtensions and parse as TestPackedTypes to insure + // wire compatibility of extensions. + // + // This checks serialization to a flat array by explicitly reserving space in + // the string and calling the generated message's + // SerializeWithCachedSizesToArray. + unittest::TestPackedExtensions source; + unittest::TestPackedTypes destination; + TestUtil::SetPackedExtensions(&source); + int size = source.ByteSize(); + string data; + data.resize(size); + uint8* target = reinterpret_cast(string_as_array(&data)); + uint8* end = source.SerializeWithCachedSizesToArray(target); + EXPECT_EQ(size, end - target); + EXPECT_TRUE(destination.ParseFromString(data)); + TestUtil::ExpectPackedFieldsSet(destination); +} + +TEST(ExtensionSetTest, PackedSerializationToStream) { + // Serialize as TestPackedExtensions and parse as TestPackedTypes to insure + // wire compatibility of extensions. + // + // This checks serialization to an output stream by creating an array output + // stream that can only buffer 1 byte at a time - this prevents the message + // from ever jumping to the fast path, ensuring that serialization happens via + // the CodedOutputStream. + unittest::TestPackedExtensions source; + unittest::TestPackedTypes destination; + TestUtil::SetPackedExtensions(&source); + int size = source.ByteSize(); + string data; + data.resize(size); + { + io::ArrayOutputStream array_stream(string_as_array(&data), size, 1); + io::CodedOutputStream output_stream(&array_stream); + source.SerializeWithCachedSizes(&output_stream); + ASSERT_FALSE(output_stream.HadError()); + } + EXPECT_TRUE(destination.ParseFromString(data)); + TestUtil::ExpectPackedFieldsSet(destination); +} + +TEST(ExtensionSetTest, Parsing) { + // Serialize as TestAllTypes and parse as TestAllExtensions. + unittest::TestAllTypes source; + unittest::TestAllExtensions destination; + string data; + + TestUtil::SetAllFields(&source); + source.SerializeToString(&data); + EXPECT_TRUE(destination.ParseFromString(data)); + TestUtil::ExpectAllExtensionsSet(destination); +} + +TEST(ExtensionSetTest, PackedParsing) { + // Serialize as TestPackedTypes and parse as TestPackedExtensions. + unittest::TestPackedTypes source; + unittest::TestPackedExtensions destination; + string data; + + TestUtil::SetPackedFields(&source); + source.SerializeToString(&data); + EXPECT_TRUE(destination.ParseFromString(data)); + TestUtil::ExpectPackedExtensionsSet(destination); +} + +TEST(ExtensionSetTest, IsInitialized) { + // Test that IsInitialized() returns false if required fields in nested + // extensions are missing. + unittest::TestAllExtensions message; + + EXPECT_TRUE(message.IsInitialized()); + + message.MutableExtension(unittest::TestRequired::single); + EXPECT_FALSE(message.IsInitialized()); + + message.MutableExtension(unittest::TestRequired::single)->set_a(1); + EXPECT_FALSE(message.IsInitialized()); + message.MutableExtension(unittest::TestRequired::single)->set_b(2); + EXPECT_FALSE(message.IsInitialized()); + message.MutableExtension(unittest::TestRequired::single)->set_c(3); + EXPECT_TRUE(message.IsInitialized()); + + message.AddExtension(unittest::TestRequired::multi); + EXPECT_FALSE(message.IsInitialized()); + + message.MutableExtension(unittest::TestRequired::multi, 0)->set_a(1); + EXPECT_FALSE(message.IsInitialized()); + message.MutableExtension(unittest::TestRequired::multi, 0)->set_b(2); + EXPECT_FALSE(message.IsInitialized()); + message.MutableExtension(unittest::TestRequired::multi, 0)->set_c(3); + EXPECT_TRUE(message.IsInitialized()); +} + +TEST(ExtensionSetTest, MutableString) { + // Test the mutable string accessors. + unittest::TestAllExtensions message; + + message.MutableExtension(unittest::optional_string_extension)->assign("foo"); + EXPECT_TRUE(message.HasExtension(unittest::optional_string_extension)); + EXPECT_EQ("foo", message.GetExtension(unittest::optional_string_extension)); + + message.AddExtension(unittest::repeated_string_extension)->assign("bar"); + ASSERT_EQ(1, message.ExtensionSize(unittest::repeated_string_extension)); + EXPECT_EQ("bar", + message.GetExtension(unittest::repeated_string_extension, 0)); +} + +TEST(ExtensionSetTest, SpaceUsedExcludingSelf) { + // Scalar primitive extensions should increase the extension set size by a + // minimum of the size of the primitive type. +#define TEST_SCALAR_EXTENSIONS_SPACE_USED(type, value) \ + do { \ + unittest::TestAllExtensions message; \ + const int base_size = message.SpaceUsed(); \ + message.SetExtension(unittest::optional_##type##_extension, value); \ + int min_expected_size = base_size + \ + sizeof(message.GetExtension(unittest::optional_##type##_extension)); \ + EXPECT_LE(min_expected_size, message.SpaceUsed()); \ + } while (0) + + TEST_SCALAR_EXTENSIONS_SPACE_USED(int32 , 101); + TEST_SCALAR_EXTENSIONS_SPACE_USED(int64 , 102); + TEST_SCALAR_EXTENSIONS_SPACE_USED(uint32 , 103); + TEST_SCALAR_EXTENSIONS_SPACE_USED(uint64 , 104); + TEST_SCALAR_EXTENSIONS_SPACE_USED(sint32 , 105); + TEST_SCALAR_EXTENSIONS_SPACE_USED(sint64 , 106); + TEST_SCALAR_EXTENSIONS_SPACE_USED(fixed32 , 107); + TEST_SCALAR_EXTENSIONS_SPACE_USED(fixed64 , 108); + TEST_SCALAR_EXTENSIONS_SPACE_USED(sfixed32, 109); + TEST_SCALAR_EXTENSIONS_SPACE_USED(sfixed64, 110); + TEST_SCALAR_EXTENSIONS_SPACE_USED(float , 111); + TEST_SCALAR_EXTENSIONS_SPACE_USED(double , 112); + TEST_SCALAR_EXTENSIONS_SPACE_USED(bool , true); +#undef TEST_SCALAR_EXTENSIONS_SPACE_USED + { + unittest::TestAllExtensions message; + const int base_size = message.SpaceUsed(); + message.SetExtension(unittest::optional_nested_enum_extension, + unittest::TestAllTypes::FOO); + int min_expected_size = base_size + + sizeof(message.GetExtension(unittest::optional_nested_enum_extension)); + EXPECT_LE(min_expected_size, message.SpaceUsed()); + } + { + // Strings may cause extra allocations depending on their length; ensure + // that gets included as well. + unittest::TestAllExtensions message; + const int base_size = message.SpaceUsed(); + const string s("this is a fairly large string that will cause some " + "allocation in order to store it in the extension"); + message.SetExtension(unittest::optional_string_extension, s); + int min_expected_size = base_size + s.length(); + EXPECT_LE(min_expected_size, message.SpaceUsed()); + } + { + // Messages also have additional allocation that need to be counted. + unittest::TestAllExtensions message; + const int base_size = message.SpaceUsed(); + unittest::ForeignMessage foreign; + foreign.set_c(42); + message.MutableExtension(unittest::optional_foreign_message_extension)-> + CopyFrom(foreign); + int min_expected_size = base_size + foreign.SpaceUsed(); + EXPECT_LE(min_expected_size, message.SpaceUsed()); + } + + // Repeated primitive extensions will increase space used by at least a + // RepeatedField, and will cause additional allocations when the array + // gets too big for the initial space. + // This macro: + // - Adds a value to the repeated extension, then clears it, establishing + // the base size. + // - Adds a small number of values, testing that it doesn't increase the + // SpaceUsed() + // - Adds a large number of values (requiring allocation in the repeated + // field), and ensures that that allocation is included in SpaceUsed() +#define TEST_REPEATED_EXTENSIONS_SPACE_USED(type, cpptype, value) \ + do { \ + unittest::TestAllExtensions message; \ + const int base_size = message.SpaceUsed(); \ + int min_expected_size = sizeof(RepeatedField) + base_size; \ + message.AddExtension(unittest::repeated_##type##_extension, value); \ + message.ClearExtension(unittest::repeated_##type##_extension); \ + const int empty_repeated_field_size = message.SpaceUsed(); \ + EXPECT_LE(min_expected_size, empty_repeated_field_size) << #type; \ + message.AddExtension(unittest::repeated_##type##_extension, value); \ + message.AddExtension(unittest::repeated_##type##_extension, value); \ + EXPECT_EQ(empty_repeated_field_size, message.SpaceUsed()) << #type; \ + message.ClearExtension(unittest::repeated_##type##_extension); \ + for (int i = 0; i < 16; ++i) { \ + message.AddExtension(unittest::repeated_##type##_extension, value); \ + } \ + int expected_size = sizeof(cpptype) * 16 + empty_repeated_field_size; \ + EXPECT_EQ(expected_size, message.SpaceUsed()) << #type; \ + } while (0) + + TEST_REPEATED_EXTENSIONS_SPACE_USED(int32 , int32 , 101); + TEST_REPEATED_EXTENSIONS_SPACE_USED(int64 , int64 , 102); + TEST_REPEATED_EXTENSIONS_SPACE_USED(uint32 , uint32, 103); + TEST_REPEATED_EXTENSIONS_SPACE_USED(uint64 , uint64, 104); + TEST_REPEATED_EXTENSIONS_SPACE_USED(sint32 , int32 , 105); + TEST_REPEATED_EXTENSIONS_SPACE_USED(sint64 , int64 , 106); + TEST_REPEATED_EXTENSIONS_SPACE_USED(fixed32 , uint32, 107); + TEST_REPEATED_EXTENSIONS_SPACE_USED(fixed64 , uint64, 108); + TEST_REPEATED_EXTENSIONS_SPACE_USED(sfixed32, int32 , 109); + TEST_REPEATED_EXTENSIONS_SPACE_USED(sfixed64, int64 , 110); + TEST_REPEATED_EXTENSIONS_SPACE_USED(float , float , 111); + TEST_REPEATED_EXTENSIONS_SPACE_USED(double , double, 112); + TEST_REPEATED_EXTENSIONS_SPACE_USED(bool , bool , true); + TEST_REPEATED_EXTENSIONS_SPACE_USED(nested_enum, int, + unittest::TestAllTypes::FOO); +#undef TEST_REPEATED_EXTENSIONS_SPACE_USED + // Repeated strings + { + unittest::TestAllExtensions message; + const int base_size = message.SpaceUsed(); + int min_expected_size = sizeof(RepeatedPtrField) + base_size; + const string value(256, 'x'); + // Once items are allocated, they may stick around even when cleared so + // without the hardcore memory management accessors there isn't a notion of + // the empty repeated field memory usage as there is with primitive types. + for (int i = 0; i < 16; ++i) { + message.AddExtension(unittest::repeated_string_extension, value); + } + min_expected_size += (sizeof(value) + value.size()) * 16; + EXPECT_LE(min_expected_size, message.SpaceUsed()); + } + // Repeated messages + { + unittest::TestAllExtensions message; + const int base_size = message.SpaceUsed(); + int min_expected_size = sizeof(RepeatedPtrField) + + base_size; + unittest::ForeignMessage prototype; + prototype.set_c(2); + for (int i = 0; i < 16; ++i) { + message.AddExtension(unittest::repeated_foreign_message_extension)-> + CopyFrom(prototype); + } + min_expected_size += 16 * prototype.SpaceUsed(); + EXPECT_LE(min_expected_size, message.SpaceUsed()); + } +} + +#ifdef GTEST_HAS_DEATH_TEST + +TEST(ExtensionSetTest, InvalidEnumDeath) { + unittest::TestAllExtensions message; + EXPECT_DEBUG_DEATH( + message.SetExtension(unittest::optional_foreign_enum_extension, + static_cast(53)), + "IsValid"); +} + +#endif // GTEST_HAS_DEATH_TEST + +TEST(ExtensionSetTest, DynamicExtensions) { + // Test adding a dynamic extension to a compiled-in message object. + + FileDescriptorProto dynamic_proto; + dynamic_proto.set_name("dynamic_extensions_test.proto"); + dynamic_proto.add_dependency( + unittest::TestAllExtensions::descriptor()->file()->name()); + dynamic_proto.set_package("dynamic_extensions"); + + // Copy the fields and nested types from TestDynamicExtensions into our new + // proto, converting the fields into extensions. + const Descriptor* template_descriptor = + unittest::TestDynamicExtensions::descriptor(); + DescriptorProto template_descriptor_proto; + template_descriptor->CopyTo(&template_descriptor_proto); + dynamic_proto.mutable_message_type()->MergeFrom( + template_descriptor_proto.nested_type()); + dynamic_proto.mutable_enum_type()->MergeFrom( + template_descriptor_proto.enum_type()); + dynamic_proto.mutable_extension()->MergeFrom( + template_descriptor_proto.field()); + + // For each extension that we added... + for (int i = 0; i < dynamic_proto.extension_size(); i++) { + // Set its extendee to TestAllExtensions. + FieldDescriptorProto* extension = dynamic_proto.mutable_extension(i); + extension->set_extendee( + unittest::TestAllExtensions::descriptor()->full_name()); + + // If the field refers to one of the types nested in TestDynamicExtensions, + // make it refer to the type in our dynamic proto instead. + string prefix = "." + template_descriptor->full_name() + "."; + if (extension->has_type_name()) { + string* type_name = extension->mutable_type_name(); + if (HasPrefixString(*type_name, prefix)) { + type_name->replace(0, prefix.size(), ".dynamic_extensions."); + } + } + } + + // Now build the file, using the generated pool as an underlay. + DescriptorPool dynamic_pool(DescriptorPool::generated_pool()); + const FileDescriptor* file = dynamic_pool.BuildFile(dynamic_proto); + ASSERT_TRUE(file != NULL); + DynamicMessageFactory dynamic_factory(&dynamic_pool); + dynamic_factory.SetDelegateToGeneratedFactory(true); + + // Construct a message that we can parse with the extensions we defined. + // Since the extensions were based off of the fields of TestDynamicExtensions, + // we can use that message to create this test message. + string data; + { + unittest::TestDynamicExtensions message; + message.set_scalar_extension(123); + message.set_enum_extension(unittest::FOREIGN_BAR); + message.set_dynamic_enum_extension( + unittest::TestDynamicExtensions::DYNAMIC_BAZ); + message.mutable_message_extension()->set_c(456); + message.mutable_dynamic_message_extension()->set_dynamic_field(789); + message.add_repeated_extension("foo"); + message.add_repeated_extension("bar"); + message.add_packed_extension(12); + message.add_packed_extension(-34); + message.add_packed_extension(56); + message.add_packed_extension(-78); + + // Also add some unknown fields. + + // An unknown enum value (for a known field). + message.mutable_unknown_fields()->AddVarint( + unittest::TestDynamicExtensions::kDynamicEnumExtensionFieldNumber, + 12345); + // A regular unknown field. + message.mutable_unknown_fields()->AddLengthDelimited(54321, "unknown"); + + message.SerializeToString(&data); + } + + // Now we can parse this using our dynamic extension definitions... + unittest::TestAllExtensions message; + { + io::ArrayInputStream raw_input(data.data(), data.size()); + io::CodedInputStream input(&raw_input); + input.SetExtensionRegistry(&dynamic_pool, &dynamic_factory); + ASSERT_TRUE(message.ParseFromCodedStream(&input)); + ASSERT_TRUE(input.ConsumedEntireMessage()); + } + + // Can we print it? + EXPECT_EQ( + "[dynamic_extensions.scalar_extension]: 123\n" + "[dynamic_extensions.enum_extension]: FOREIGN_BAR\n" + "[dynamic_extensions.dynamic_enum_extension]: DYNAMIC_BAZ\n" + "[dynamic_extensions.message_extension] {\n" + " c: 456\n" + "}\n" + "[dynamic_extensions.dynamic_message_extension] {\n" + " dynamic_field: 789\n" + "}\n" + "[dynamic_extensions.repeated_extension]: \"foo\"\n" + "[dynamic_extensions.repeated_extension]: \"bar\"\n" + "[dynamic_extensions.packed_extension]: 12\n" + "[dynamic_extensions.packed_extension]: -34\n" + "[dynamic_extensions.packed_extension]: 56\n" + "[dynamic_extensions.packed_extension]: -78\n" + "2002: 12345\n" + "54321: \"unknown\"\n", + message.DebugString()); + + // Can we serialize it? + // (Don't use EXPECT_EQ because we don't want to dump raw binary data to the + // terminal on failure.) + EXPECT_TRUE(message.SerializeAsString() == data); + + // What if we parse using the reflection-based parser? + { + unittest::TestAllExtensions message2; + io::ArrayInputStream raw_input(data.data(), data.size()); + io::CodedInputStream input(&raw_input); + input.SetExtensionRegistry(&dynamic_pool, &dynamic_factory); + ASSERT_TRUE(WireFormat::ParseAndMergePartial(&input, &message2)); + ASSERT_TRUE(input.ConsumedEntireMessage()); + EXPECT_EQ(message.DebugString(), message2.DebugString()); + } + + // Are the embedded generated types actually using the generated objects? + { + const FieldDescriptor* message_extension = + file->FindExtensionByName("message_extension"); + ASSERT_TRUE(message_extension != NULL); + const Message& sub_message = + message.GetReflection()->GetMessage(message, message_extension); + const unittest::ForeignMessage* typed_sub_message = + dynamic_cast(&sub_message); + ASSERT_TRUE(typed_sub_message != NULL); + EXPECT_EQ(456, typed_sub_message->c()); + } + + // What does GetMessage() return for the embedded dynamic type if it isn't + // present? + { + const FieldDescriptor* dynamic_message_extension = + file->FindExtensionByName("dynamic_message_extension"); + ASSERT_TRUE(dynamic_message_extension != NULL); + const Message& parent = unittest::TestAllExtensions::default_instance(); + const Message& sub_message = + parent.GetReflection()->GetMessage(parent, dynamic_message_extension, + &dynamic_factory); + const Message* prototype = + dynamic_factory.GetPrototype(dynamic_message_extension->message_type()); + EXPECT_EQ(prototype, &sub_message); + } +} + +} // namespace +} // namespace internal +} // namespace protobuf +} // namespace google diff --git a/depends/protobuf/google/protobuf/generated_message_reflection.cc b/depends/protobuf/google/protobuf/generated_message_reflection.cc new file mode 100644 index 0000000000..a0dd75c65b --- /dev/null +++ b/depends/protobuf/google/protobuf/generated_message_reflection.cc @@ -0,0 +1,1228 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { +namespace internal { + +int StringSpaceUsedExcludingSelf(const string& str) { + const void* start = &str; + const void* end = &str + 1; + + if (start <= str.data() && str.data() <= end) { + // The string's data is stored inside the string object itself. + return 0; + } else { + return str.capacity(); + } +} + +bool ParseNamedEnum(const EnumDescriptor* descriptor, + const string& name, + int* value) { + const EnumValueDescriptor* d = descriptor->FindValueByName(name); + if (d == NULL) return false; + *value = d->number(); + return true; +} + +const string& NameOfEnum(const EnumDescriptor* descriptor, int value) { + const EnumValueDescriptor* d = descriptor->FindValueByNumber(value); + return (d == NULL ? kEmptyString : d->name()); +} + +// =================================================================== +// Helpers for reporting usage errors (e.g. trying to use GetInt32() on +// a string field). + +namespace { + +void ReportReflectionUsageError( + const Descriptor* descriptor, const FieldDescriptor* field, + const char* method, const char* description) { + GOOGLE_LOG(FATAL) + << "Protocol Buffer reflection usage error:\n" + " Method : google::protobuf::Reflection::" << method << "\n" + " Message type: " << descriptor->full_name() << "\n" + " Field : " << field->full_name() << "\n" + " Problem : " << description; +} + +const char* cpptype_names_[FieldDescriptor::MAX_CPPTYPE + 1] = { + "INVALID_CPPTYPE", + "CPPTYPE_INT32", + "CPPTYPE_INT64", + "CPPTYPE_UINT32", + "CPPTYPE_UINT64", + "CPPTYPE_DOUBLE", + "CPPTYPE_FLOAT", + "CPPTYPE_BOOL", + "CPPTYPE_ENUM", + "CPPTYPE_STRING", + "CPPTYPE_MESSAGE" +}; + +static void ReportReflectionUsageTypeError( + const Descriptor* descriptor, const FieldDescriptor* field, + const char* method, + FieldDescriptor::CppType expected_type) { + GOOGLE_LOG(FATAL) + << "Protocol Buffer reflection usage error:\n" + " Method : google::protobuf::Reflection::" << method << "\n" + " Message type: " << descriptor->full_name() << "\n" + " Field : " << field->full_name() << "\n" + " Problem : Field is not the right type for this message:\n" + " Expected : " << cpptype_names_[expected_type] << "\n" + " Field type: " << cpptype_names_[field->cpp_type()]; +} + +static void ReportReflectionUsageEnumTypeError( + const Descriptor* descriptor, const FieldDescriptor* field, + const char* method, const EnumValueDescriptor* value) { + GOOGLE_LOG(FATAL) + << "Protocol Buffer reflection usage error:\n" + " Method : google::protobuf::Reflection::" << method << "\n" + " Message type: " << descriptor->full_name() << "\n" + " Field : " << field->full_name() << "\n" + " Problem : Enum value did not match field type:\n" + " Expected : " << field->enum_type()->full_name() << "\n" + " Actual : " << value->full_name(); +} + +#define USAGE_CHECK(CONDITION, METHOD, ERROR_DESCRIPTION) \ + if (!(CONDITION)) \ + ReportReflectionUsageError(descriptor_, field, #METHOD, ERROR_DESCRIPTION) +#define USAGE_CHECK_EQ(A, B, METHOD, ERROR_DESCRIPTION) \ + USAGE_CHECK((A) == (B), METHOD, ERROR_DESCRIPTION) +#define USAGE_CHECK_NE(A, B, METHOD, ERROR_DESCRIPTION) \ + USAGE_CHECK((A) != (B), METHOD, ERROR_DESCRIPTION) + +#define USAGE_CHECK_TYPE(METHOD, CPPTYPE) \ + if (field->cpp_type() != FieldDescriptor::CPPTYPE_##CPPTYPE) \ + ReportReflectionUsageTypeError(descriptor_, field, #METHOD, \ + FieldDescriptor::CPPTYPE_##CPPTYPE) + +#define USAGE_CHECK_ENUM_VALUE(METHOD) \ + if (value->type() != field->enum_type()) \ + ReportReflectionUsageEnumTypeError(descriptor_, field, #METHOD, value) + +#define USAGE_CHECK_MESSAGE_TYPE(METHOD) \ + USAGE_CHECK_EQ(field->containing_type(), descriptor_, \ + METHOD, "Field does not match message type."); +#define USAGE_CHECK_SINGULAR(METHOD) \ + USAGE_CHECK_NE(field->label(), FieldDescriptor::LABEL_REPEATED, METHOD, \ + "Field is repeated; the method requires a singular field.") +#define USAGE_CHECK_REPEATED(METHOD) \ + USAGE_CHECK_EQ(field->label(), FieldDescriptor::LABEL_REPEATED, METHOD, \ + "Field is singular; the method requires a repeated field.") + +#define USAGE_CHECK_ALL(METHOD, LABEL, CPPTYPE) \ + USAGE_CHECK_MESSAGE_TYPE(METHOD); \ + USAGE_CHECK_##LABEL(METHOD); \ + USAGE_CHECK_TYPE(METHOD, CPPTYPE) + +} // namespace + +// =================================================================== + +GeneratedMessageReflection::GeneratedMessageReflection( + const Descriptor* descriptor, + const Message* default_instance, + const int offsets[], + int has_bits_offset, + int unknown_fields_offset, + int extensions_offset, + const DescriptorPool* descriptor_pool, + MessageFactory* factory, + int object_size) + : descriptor_ (descriptor), + default_instance_ (default_instance), + offsets_ (offsets), + has_bits_offset_ (has_bits_offset), + unknown_fields_offset_(unknown_fields_offset), + extensions_offset_(extensions_offset), + object_size_ (object_size), + descriptor_pool_ ((descriptor_pool == NULL) ? + DescriptorPool::generated_pool() : + descriptor_pool), + message_factory_ (factory) { +} + +GeneratedMessageReflection::~GeneratedMessageReflection() {} + +const UnknownFieldSet& GeneratedMessageReflection::GetUnknownFields( + const Message& message) const { + const void* ptr = reinterpret_cast(&message) + + unknown_fields_offset_; + return *reinterpret_cast(ptr); +} +UnknownFieldSet* GeneratedMessageReflection::MutableUnknownFields( + Message* message) const { + void* ptr = reinterpret_cast(message) + unknown_fields_offset_; + return reinterpret_cast(ptr); +} + +int GeneratedMessageReflection::SpaceUsed(const Message& message) const { + // object_size_ already includes the in-memory representation of each field + // in the message, so we only need to account for additional memory used by + // the fields. + int total_size = object_size_; + + total_size += GetUnknownFields(message).SpaceUsedExcludingSelf(); + + if (extensions_offset_ != -1) { + total_size += GetExtensionSet(message).SpaceUsedExcludingSelf(); + } + + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + + if (field->is_repeated()) { + switch (field->cpp_type()) { +#define HANDLE_TYPE(UPPERCASE, LOWERCASE) \ + case FieldDescriptor::CPPTYPE_##UPPERCASE : \ + total_size += GetRaw >(message, field) \ + .SpaceUsedExcludingSelf(); \ + break + + HANDLE_TYPE( INT32, int32); + HANDLE_TYPE( INT64, int64); + HANDLE_TYPE(UINT32, uint32); + HANDLE_TYPE(UINT64, uint64); + HANDLE_TYPE(DOUBLE, double); + HANDLE_TYPE( FLOAT, float); + HANDLE_TYPE( BOOL, bool); + HANDLE_TYPE( ENUM, int); +#undef HANDLE_TYPE + + case FieldDescriptor::CPPTYPE_STRING: + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + total_size += GetRaw >(message, field) + .SpaceUsedExcludingSelf(); + break; + } + break; + + case FieldDescriptor::CPPTYPE_MESSAGE: + // We don't know which subclass of RepeatedPtrFieldBase the type is, + // so we use RepeatedPtrFieldBase directly. + total_size += + GetRaw(message, field) + .SpaceUsedExcludingSelf >(); + break; + } + } else { + switch (field->cpp_type()) { + case FieldDescriptor::CPPTYPE_INT32 : + case FieldDescriptor::CPPTYPE_INT64 : + case FieldDescriptor::CPPTYPE_UINT32: + case FieldDescriptor::CPPTYPE_UINT64: + case FieldDescriptor::CPPTYPE_DOUBLE: + case FieldDescriptor::CPPTYPE_FLOAT : + case FieldDescriptor::CPPTYPE_BOOL : + case FieldDescriptor::CPPTYPE_ENUM : + // Field is inline, so we've already counted it. + break; + + case FieldDescriptor::CPPTYPE_STRING: { + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: { + const string* ptr = GetField(message, field); + + // Initially, the string points to the default value stored in + // the prototype. Only count the string if it has been changed + // from the default value. + const string* default_ptr = DefaultRaw(field); + + if (ptr != default_ptr) { + // string fields are represented by just a pointer, so also + // include sizeof(string) as well. + total_size += sizeof(*ptr) + StringSpaceUsedExcludingSelf(*ptr); + } + break; + } + } + break; + } + + case FieldDescriptor::CPPTYPE_MESSAGE: + if (&message == default_instance_) { + // For singular fields, the prototype just stores a pointer to the + // external type's prototype, so there is no extra memory usage. + } else { + const Message* sub_message = GetRaw(message, field); + if (sub_message != NULL) { + total_size += sub_message->SpaceUsed(); + } + } + break; + } + } + } + + return total_size; +} + +void GeneratedMessageReflection::Swap( + Message* message1, + Message* message2) const { + if (message1 == message2) return; + + // TODO(kenton): Other Reflection methods should probably check this too. + GOOGLE_CHECK_EQ(message1->GetReflection(), this) + << "First argument to Swap() (of type \"" + << message1->GetDescriptor()->full_name() + << "\") is not compatible with this reflection object (which is for type \"" + << descriptor_->full_name() + << "\"). Note that the exact same class is required; not just the same " + "descriptor."; + GOOGLE_CHECK_EQ(message2->GetReflection(), this) + << "Second argument to Swap() (of type \"" + << message1->GetDescriptor()->full_name() + << "\") is not compatible with this reflection object (which is for type \"" + << descriptor_->full_name() + << "\"). Note that the exact same class is required; not just the same " + "descriptor."; + + uint32* has_bits1 = MutableHasBits(message1); + uint32* has_bits2 = MutableHasBits(message2); + int has_bits_size = (descriptor_->field_count() + 31) / 32; + + for (int i = 0; i < has_bits_size; i++) { + std::swap(has_bits1[i], has_bits2[i]); + } + + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + if (field->is_repeated()) { + switch (field->cpp_type()) { +#define SWAP_ARRAYS(CPPTYPE, TYPE) \ + case FieldDescriptor::CPPTYPE_##CPPTYPE: \ + MutableRaw >(message1, field)->Swap( \ + MutableRaw >(message2, field)); \ + break; + + SWAP_ARRAYS(INT32 , int32 ); + SWAP_ARRAYS(INT64 , int64 ); + SWAP_ARRAYS(UINT32, uint32); + SWAP_ARRAYS(UINT64, uint64); + SWAP_ARRAYS(FLOAT , float ); + SWAP_ARRAYS(DOUBLE, double); + SWAP_ARRAYS(BOOL , bool ); + SWAP_ARRAYS(ENUM , int ); +#undef SWAP_ARRAYS + + case FieldDescriptor::CPPTYPE_STRING: + case FieldDescriptor::CPPTYPE_MESSAGE: + MutableRaw(message1, field)->Swap( + MutableRaw(message2, field)); + break; + + default: + GOOGLE_LOG(FATAL) << "Unimplemented type: " << field->cpp_type(); + } + } else { + switch (field->cpp_type()) { +#define SWAP_VALUES(CPPTYPE, TYPE) \ + case FieldDescriptor::CPPTYPE_##CPPTYPE: \ + std::swap(*MutableRaw(message1, field), \ + *MutableRaw(message2, field)); \ + break; + + SWAP_VALUES(INT32 , int32 ); + SWAP_VALUES(INT64 , int64 ); + SWAP_VALUES(UINT32, uint32); + SWAP_VALUES(UINT64, uint64); + SWAP_VALUES(FLOAT , float ); + SWAP_VALUES(DOUBLE, double); + SWAP_VALUES(BOOL , bool ); + SWAP_VALUES(ENUM , int ); + SWAP_VALUES(MESSAGE, Message*); +#undef SWAP_VALUES + + case FieldDescriptor::CPPTYPE_STRING: + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + std::swap(*MutableRaw(message1, field), + *MutableRaw(message2, field)); + break; + } + break; + + default: + GOOGLE_LOG(FATAL) << "Unimplemented type: " << field->cpp_type(); + } + } + } + + if (extensions_offset_ != -1) { + MutableExtensionSet(message1)->Swap(MutableExtensionSet(message2)); + } + + MutableUnknownFields(message1)->Swap(MutableUnknownFields(message2)); +} + +// ------------------------------------------------------------------- + +bool GeneratedMessageReflection::HasField(const Message& message, + const FieldDescriptor* field) const { + USAGE_CHECK_MESSAGE_TYPE(HasField); + USAGE_CHECK_SINGULAR(HasField); + + if (field->is_extension()) { + return GetExtensionSet(message).Has(field->number()); + } else { + return HasBit(message, field); + } +} + +int GeneratedMessageReflection::FieldSize(const Message& message, + const FieldDescriptor* field) const { + USAGE_CHECK_MESSAGE_TYPE(FieldSize); + USAGE_CHECK_REPEATED(FieldSize); + + if (field->is_extension()) { + return GetExtensionSet(message).ExtensionSize(field->number()); + } else { + switch (field->cpp_type()) { +#define HANDLE_TYPE(UPPERCASE, LOWERCASE) \ + case FieldDescriptor::CPPTYPE_##UPPERCASE : \ + return GetRaw >(message, field).size() + + HANDLE_TYPE( INT32, int32); + HANDLE_TYPE( INT64, int64); + HANDLE_TYPE(UINT32, uint32); + HANDLE_TYPE(UINT64, uint64); + HANDLE_TYPE(DOUBLE, double); + HANDLE_TYPE( FLOAT, float); + HANDLE_TYPE( BOOL, bool); + HANDLE_TYPE( ENUM, int); +#undef HANDLE_TYPE + + case FieldDescriptor::CPPTYPE_STRING: + case FieldDescriptor::CPPTYPE_MESSAGE: + return GetRaw(message, field).size(); + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return 0; + } +} + +void GeneratedMessageReflection::ClearField( + Message* message, const FieldDescriptor* field) const { + USAGE_CHECK_MESSAGE_TYPE(ClearField); + + if (field->is_extension()) { + MutableExtensionSet(message)->ClearExtension(field->number()); + } else if (!field->is_repeated()) { + if (HasBit(*message, field)) { + ClearBit(message, field); + + // We need to set the field back to its default value. + switch (field->cpp_type()) { +#define CLEAR_TYPE(CPPTYPE, TYPE) \ + case FieldDescriptor::CPPTYPE_##CPPTYPE: \ + *MutableRaw(message, field) = \ + field->default_value_##TYPE(); \ + break; + + CLEAR_TYPE(INT32 , int32 ); + CLEAR_TYPE(INT64 , int64 ); + CLEAR_TYPE(UINT32, uint32); + CLEAR_TYPE(UINT64, uint64); + CLEAR_TYPE(FLOAT , float ); + CLEAR_TYPE(DOUBLE, double); + CLEAR_TYPE(BOOL , bool ); +#undef CLEAR_TYPE + + case FieldDescriptor::CPPTYPE_ENUM: + *MutableRaw(message, field) = + field->default_value_enum()->number(); + break; + + case FieldDescriptor::CPPTYPE_STRING: { + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + const string* default_ptr = DefaultRaw(field); + string** value = MutableRaw(message, field); + if (*value != default_ptr) { + if (field->has_default_value()) { + (*value)->assign(field->default_value_string()); + } else { + (*value)->clear(); + } + } + break; + } + break; + } + + case FieldDescriptor::CPPTYPE_MESSAGE: + (*MutableRaw(message, field))->Clear(); + break; + } + } + } else { + switch (field->cpp_type()) { +#define HANDLE_TYPE(UPPERCASE, LOWERCASE) \ + case FieldDescriptor::CPPTYPE_##UPPERCASE : \ + MutableRaw >(message, field)->Clear(); \ + break + + HANDLE_TYPE( INT32, int32); + HANDLE_TYPE( INT64, int64); + HANDLE_TYPE(UINT32, uint32); + HANDLE_TYPE(UINT64, uint64); + HANDLE_TYPE(DOUBLE, double); + HANDLE_TYPE( FLOAT, float); + HANDLE_TYPE( BOOL, bool); + HANDLE_TYPE( ENUM, int); +#undef HANDLE_TYPE + + case FieldDescriptor::CPPTYPE_STRING: { + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + MutableRaw >(message, field)->Clear(); + break; + } + break; + } + + case FieldDescriptor::CPPTYPE_MESSAGE: { + // We don't know which subclass of RepeatedPtrFieldBase the type is, + // so we use RepeatedPtrFieldBase directly. + MutableRaw(message, field) + ->Clear >(); + break; + } + } + } +} + +void GeneratedMessageReflection::RemoveLast( + Message* message, + const FieldDescriptor* field) const { + USAGE_CHECK_MESSAGE_TYPE(RemoveLast); + USAGE_CHECK_REPEATED(RemoveLast); + + if (field->is_extension()) { + MutableExtensionSet(message)->RemoveLast(field->number()); + } else { + switch (field->cpp_type()) { +#define HANDLE_TYPE(UPPERCASE, LOWERCASE) \ + case FieldDescriptor::CPPTYPE_##UPPERCASE : \ + MutableRaw >(message, field)->RemoveLast(); \ + break + + HANDLE_TYPE( INT32, int32); + HANDLE_TYPE( INT64, int64); + HANDLE_TYPE(UINT32, uint32); + HANDLE_TYPE(UINT64, uint64); + HANDLE_TYPE(DOUBLE, double); + HANDLE_TYPE( FLOAT, float); + HANDLE_TYPE( BOOL, bool); + HANDLE_TYPE( ENUM, int); +#undef HANDLE_TYPE + + case FieldDescriptor::CPPTYPE_STRING: + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + MutableRaw >(message, field)->RemoveLast(); + break; + } + break; + + case FieldDescriptor::CPPTYPE_MESSAGE: + MutableRaw(message, field) + ->RemoveLast >(); + break; + } + } +} + +void GeneratedMessageReflection::SwapElements( + Message* message, + const FieldDescriptor* field, + int index1, + int index2) const { + USAGE_CHECK_MESSAGE_TYPE(Swap); + USAGE_CHECK_REPEATED(Swap); + + if (field->is_extension()) { + MutableExtensionSet(message)->SwapElements(field->number(), index1, index2); + } else { + switch (field->cpp_type()) { +#define HANDLE_TYPE(UPPERCASE, LOWERCASE) \ + case FieldDescriptor::CPPTYPE_##UPPERCASE : \ + MutableRaw >(message, field) \ + ->SwapElements(index1, index2); \ + break + + HANDLE_TYPE( INT32, int32); + HANDLE_TYPE( INT64, int64); + HANDLE_TYPE(UINT32, uint32); + HANDLE_TYPE(UINT64, uint64); + HANDLE_TYPE(DOUBLE, double); + HANDLE_TYPE( FLOAT, float); + HANDLE_TYPE( BOOL, bool); + HANDLE_TYPE( ENUM, int); +#undef HANDLE_TYPE + + case FieldDescriptor::CPPTYPE_STRING: + case FieldDescriptor::CPPTYPE_MESSAGE: + MutableRaw(message, field) + ->SwapElements(index1, index2); + break; + } + } +} + +namespace { +// Comparison functor for sorting FieldDescriptors by field number. +struct FieldNumberSorter { + bool operator()(const FieldDescriptor* left, + const FieldDescriptor* right) const { + return left->number() < right->number(); + } +}; +} // namespace + +void GeneratedMessageReflection::ListFields( + const Message& message, + vector* output) const { + output->clear(); + + // Optimization: The default instance never has any fields set. + if (&message == default_instance_) return; + + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + if (field->is_repeated()) { + if (FieldSize(message, field) > 0) { + output->push_back(field); + } + } else { + if (HasBit(message, field)) { + output->push_back(field); + } + } + } + + if (extensions_offset_ != -1) { + GetExtensionSet(message).AppendToList(descriptor_, descriptor_pool_, + output); + } + + // ListFields() must sort output by field number. + sort(output->begin(), output->end(), FieldNumberSorter()); +} + +// ------------------------------------------------------------------- + +#undef DEFINE_PRIMITIVE_ACCESSORS +#define DEFINE_PRIMITIVE_ACCESSORS(TYPENAME, TYPE, PASSTYPE, CPPTYPE) \ + PASSTYPE GeneratedMessageReflection::Get##TYPENAME( \ + const Message& message, const FieldDescriptor* field) const { \ + USAGE_CHECK_ALL(Get##TYPENAME, SINGULAR, CPPTYPE); \ + if (field->is_extension()) { \ + return GetExtensionSet(message).Get##TYPENAME( \ + field->number(), field->default_value_##PASSTYPE()); \ + } else { \ + return GetField(message, field); \ + } \ + } \ + \ + void GeneratedMessageReflection::Set##TYPENAME( \ + Message* message, const FieldDescriptor* field, \ + PASSTYPE value) const { \ + USAGE_CHECK_ALL(Set##TYPENAME, SINGULAR, CPPTYPE); \ + if (field->is_extension()) { \ + return MutableExtensionSet(message)->Set##TYPENAME( \ + field->number(), field->type(), value, field); \ + } else { \ + SetField(message, field, value); \ + } \ + } \ + \ + PASSTYPE GeneratedMessageReflection::GetRepeated##TYPENAME( \ + const Message& message, \ + const FieldDescriptor* field, int index) const { \ + USAGE_CHECK_ALL(GetRepeated##TYPENAME, REPEATED, CPPTYPE); \ + if (field->is_extension()) { \ + return GetExtensionSet(message).GetRepeated##TYPENAME( \ + field->number(), index); \ + } else { \ + return GetRepeatedField(message, field, index); \ + } \ + } \ + \ + void GeneratedMessageReflection::SetRepeated##TYPENAME( \ + Message* message, const FieldDescriptor* field, \ + int index, PASSTYPE value) const { \ + USAGE_CHECK_ALL(SetRepeated##TYPENAME, REPEATED, CPPTYPE); \ + if (field->is_extension()) { \ + MutableExtensionSet(message)->SetRepeated##TYPENAME( \ + field->number(), index, value); \ + } else { \ + SetRepeatedField(message, field, index, value); \ + } \ + } \ + \ + void GeneratedMessageReflection::Add##TYPENAME( \ + Message* message, const FieldDescriptor* field, \ + PASSTYPE value) const { \ + USAGE_CHECK_ALL(Add##TYPENAME, REPEATED, CPPTYPE); \ + if (field->is_extension()) { \ + MutableExtensionSet(message)->Add##TYPENAME( \ + field->number(), field->type(), field->options().packed(), value, \ + field); \ + } else { \ + AddField(message, field, value); \ + } \ + } + +DEFINE_PRIMITIVE_ACCESSORS(Int32 , int32 , int32 , INT32 ) +DEFINE_PRIMITIVE_ACCESSORS(Int64 , int64 , int64 , INT64 ) +DEFINE_PRIMITIVE_ACCESSORS(UInt32, uint32, uint32, UINT32) +DEFINE_PRIMITIVE_ACCESSORS(UInt64, uint64, uint64, UINT64) +DEFINE_PRIMITIVE_ACCESSORS(Float , float , float , FLOAT ) +DEFINE_PRIMITIVE_ACCESSORS(Double, double, double, DOUBLE) +DEFINE_PRIMITIVE_ACCESSORS(Bool , bool , bool , BOOL ) +#undef DEFINE_PRIMITIVE_ACCESSORS + +// ------------------------------------------------------------------- + +string GeneratedMessageReflection::GetString( + const Message& message, const FieldDescriptor* field) const { + USAGE_CHECK_ALL(GetString, SINGULAR, STRING); + if (field->is_extension()) { + return GetExtensionSet(message).GetString(field->number(), + field->default_value_string()); + } else { + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + return *GetField(message, field); + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return kEmptyString; // Make compiler happy. + } +} + +const string& GeneratedMessageReflection::GetStringReference( + const Message& message, + const FieldDescriptor* field, string* scratch) const { + USAGE_CHECK_ALL(GetStringReference, SINGULAR, STRING); + if (field->is_extension()) { + return GetExtensionSet(message).GetString(field->number(), + field->default_value_string()); + } else { + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + return *GetField(message, field); + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return kEmptyString; // Make compiler happy. + } +} + + +void GeneratedMessageReflection::SetString( + Message* message, const FieldDescriptor* field, + const string& value) const { + USAGE_CHECK_ALL(SetString, SINGULAR, STRING); + if (field->is_extension()) { + return MutableExtensionSet(message)->SetString(field->number(), + field->type(), value, field); + } else { + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: { + string** ptr = MutableField(message, field); + if (*ptr == DefaultRaw(field)) { + *ptr = new string(value); + } else { + (*ptr)->assign(value); + } + break; + } + } + } +} + + +string GeneratedMessageReflection::GetRepeatedString( + const Message& message, const FieldDescriptor* field, int index) const { + USAGE_CHECK_ALL(GetRepeatedString, REPEATED, STRING); + if (field->is_extension()) { + return GetExtensionSet(message).GetRepeatedString(field->number(), index); + } else { + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + return GetRepeatedPtrField(message, field, index); + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return kEmptyString; // Make compiler happy. + } +} + +const string& GeneratedMessageReflection::GetRepeatedStringReference( + const Message& message, const FieldDescriptor* field, + int index, string* scratch) const { + USAGE_CHECK_ALL(GetRepeatedStringReference, REPEATED, STRING); + if (field->is_extension()) { + return GetExtensionSet(message).GetRepeatedString(field->number(), index); + } else { + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + return GetRepeatedPtrField(message, field, index); + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return kEmptyString; // Make compiler happy. + } +} + + +void GeneratedMessageReflection::SetRepeatedString( + Message* message, const FieldDescriptor* field, + int index, const string& value) const { + USAGE_CHECK_ALL(SetRepeatedString, REPEATED, STRING); + if (field->is_extension()) { + MutableExtensionSet(message)->SetRepeatedString( + field->number(), index, value); + } else { + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + *MutableRepeatedField(message, field, index) = value; + break; + } + } +} + + +void GeneratedMessageReflection::AddString( + Message* message, const FieldDescriptor* field, + const string& value) const { + USAGE_CHECK_ALL(AddString, REPEATED, STRING); + if (field->is_extension()) { + MutableExtensionSet(message)->AddString(field->number(), + field->type(), value, field); + } else { + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + *AddField(message, field) = value; + break; + } + } +} + + +// ------------------------------------------------------------------- + +const EnumValueDescriptor* GeneratedMessageReflection::GetEnum( + const Message& message, const FieldDescriptor* field) const { + USAGE_CHECK_ALL(GetEnum, SINGULAR, ENUM); + + int value; + if (field->is_extension()) { + value = GetExtensionSet(message).GetEnum( + field->number(), field->default_value_enum()->number()); + } else { + value = GetField(message, field); + } + const EnumValueDescriptor* result = + field->enum_type()->FindValueByNumber(value); + GOOGLE_CHECK(result != NULL); + return result; +} + +void GeneratedMessageReflection::SetEnum( + Message* message, const FieldDescriptor* field, + const EnumValueDescriptor* value) const { + USAGE_CHECK_ALL(SetEnum, SINGULAR, ENUM); + USAGE_CHECK_ENUM_VALUE(SetEnum); + + if (field->is_extension()) { + MutableExtensionSet(message)->SetEnum(field->number(), field->type(), + value->number(), field); + } else { + SetField(message, field, value->number()); + } +} + +const EnumValueDescriptor* GeneratedMessageReflection::GetRepeatedEnum( + const Message& message, const FieldDescriptor* field, int index) const { + USAGE_CHECK_ALL(GetRepeatedEnum, REPEATED, ENUM); + + int value; + if (field->is_extension()) { + value = GetExtensionSet(message).GetRepeatedEnum(field->number(), index); + } else { + value = GetRepeatedField(message, field, index); + } + const EnumValueDescriptor* result = + field->enum_type()->FindValueByNumber(value); + GOOGLE_CHECK(result != NULL); + return result; +} + +void GeneratedMessageReflection::SetRepeatedEnum( + Message* message, + const FieldDescriptor* field, int index, + const EnumValueDescriptor* value) const { + USAGE_CHECK_ALL(SetRepeatedEnum, REPEATED, ENUM); + USAGE_CHECK_ENUM_VALUE(SetRepeatedEnum); + + if (field->is_extension()) { + MutableExtensionSet(message)->SetRepeatedEnum( + field->number(), index, value->number()); + } else { + SetRepeatedField(message, field, index, value->number()); + } +} + +void GeneratedMessageReflection::AddEnum( + Message* message, const FieldDescriptor* field, + const EnumValueDescriptor* value) const { + USAGE_CHECK_ALL(AddEnum, REPEATED, ENUM); + USAGE_CHECK_ENUM_VALUE(AddEnum); + + if (field->is_extension()) { + MutableExtensionSet(message)->AddEnum(field->number(), field->type(), + field->options().packed(), + value->number(), field); + } else { + AddField(message, field, value->number()); + } +} + +// ------------------------------------------------------------------- + +const Message& GeneratedMessageReflection::GetMessage( + const Message& message, const FieldDescriptor* field, + MessageFactory* factory) const { + USAGE_CHECK_ALL(GetMessage, SINGULAR, MESSAGE); + + if (field->is_extension()) { + return static_cast( + GetExtensionSet(message).GetMessage( + field->number(), field->message_type(), + factory == NULL ? message_factory_ : factory)); + } else { + const Message* result = GetRaw(message, field); + if (result == NULL) { + result = DefaultRaw(field); + } + return *result; + } +} + +Message* GeneratedMessageReflection::MutableMessage( + Message* message, const FieldDescriptor* field, + MessageFactory* factory) const { + USAGE_CHECK_ALL(MutableMessage, SINGULAR, MESSAGE); + + if (field->is_extension()) { + return static_cast( + MutableExtensionSet(message)->MutableMessage(field, + factory == NULL ? message_factory_ : factory)); + } else { + Message** result = MutableField(message, field); + if (*result == NULL) { + const Message* default_message = DefaultRaw(field); + *result = default_message->New(); + } + return *result; + } +} + +const Message& GeneratedMessageReflection::GetRepeatedMessage( + const Message& message, const FieldDescriptor* field, int index) const { + USAGE_CHECK_ALL(GetRepeatedMessage, REPEATED, MESSAGE); + + if (field->is_extension()) { + return static_cast( + GetExtensionSet(message).GetRepeatedMessage(field->number(), index)); + } else { + return GetRaw(message, field) + .Get >(index); + } +} + +Message* GeneratedMessageReflection::MutableRepeatedMessage( + Message* message, const FieldDescriptor* field, int index) const { + USAGE_CHECK_ALL(MutableRepeatedMessage, REPEATED, MESSAGE); + + if (field->is_extension()) { + return static_cast( + MutableExtensionSet(message)->MutableRepeatedMessage( + field->number(), index)); + } else { + return MutableRaw(message, field) + ->Mutable >(index); + } +} + +Message* GeneratedMessageReflection::AddMessage( + Message* message, const FieldDescriptor* field, + MessageFactory* factory) const { + USAGE_CHECK_ALL(AddMessage, REPEATED, MESSAGE); + + if (factory == NULL) factory = message_factory_; + + if (field->is_extension()) { + return static_cast( + MutableExtensionSet(message)->AddMessage(field, factory)); + } else { + // We can't use AddField() because RepeatedPtrFieldBase doesn't + // know how to allocate one. + RepeatedPtrFieldBase* repeated = + MutableRaw(message, field); + Message* result = repeated->AddFromCleared >(); + if (result == NULL) { + // We must allocate a new object. + const Message* prototype; + if (repeated->size() == 0) { + prototype = factory->GetPrototype(field->message_type()); + } else { + prototype = &repeated->Get >(0); + } + result = prototype->New(); + repeated->AddAllocated >(result); + } + return result; + } +} + +// ------------------------------------------------------------------- + +const FieldDescriptor* GeneratedMessageReflection::FindKnownExtensionByName( + const string& name) const { + if (extensions_offset_ == -1) return NULL; + + const FieldDescriptor* result = descriptor_pool_->FindExtensionByName(name); + if (result != NULL && result->containing_type() == descriptor_) { + return result; + } + + if (descriptor_->options().message_set_wire_format()) { + // MessageSet extensions may be identified by type name. + const Descriptor* type = descriptor_pool_->FindMessageTypeByName(name); + if (type != NULL) { + // Look for a matching extension in the foreign type's scope. + for (int i = 0; i < type->extension_count(); i++) { + const FieldDescriptor* extension = type->extension(i); + if (extension->containing_type() == descriptor_ && + extension->type() == FieldDescriptor::TYPE_MESSAGE && + extension->is_optional() && + extension->message_type() == type) { + // Found it. + return extension; + } + } + } + } + + return NULL; +} + +const FieldDescriptor* GeneratedMessageReflection::FindKnownExtensionByNumber( + int number) const { + if (extensions_offset_ == -1) return NULL; + return descriptor_pool_->FindExtensionByNumber(descriptor_, number); +} + +// =================================================================== +// Some private helpers. + +// These simple template accessors obtain pointers (or references) to +// the given field. +template +inline const Type& GeneratedMessageReflection::GetRaw( + const Message& message, const FieldDescriptor* field) const { + const void* ptr = reinterpret_cast(&message) + + offsets_[field->index()]; + return *reinterpret_cast(ptr); +} + +template +inline Type* GeneratedMessageReflection::MutableRaw( + Message* message, const FieldDescriptor* field) const { + void* ptr = reinterpret_cast(message) + offsets_[field->index()]; + return reinterpret_cast(ptr); +} + +template +inline const Type& GeneratedMessageReflection::DefaultRaw( + const FieldDescriptor* field) const { + const void* ptr = reinterpret_cast(default_instance_) + + offsets_[field->index()]; + return *reinterpret_cast(ptr); +} + +inline const uint32* GeneratedMessageReflection::GetHasBits( + const Message& message) const { + const void* ptr = reinterpret_cast(&message) + has_bits_offset_; + return reinterpret_cast(ptr); +} +inline uint32* GeneratedMessageReflection::MutableHasBits( + Message* message) const { + void* ptr = reinterpret_cast(message) + has_bits_offset_; + return reinterpret_cast(ptr); +} + +inline const ExtensionSet& GeneratedMessageReflection::GetExtensionSet( + const Message& message) const { + GOOGLE_DCHECK_NE(extensions_offset_, -1); + const void* ptr = reinterpret_cast(&message) + + extensions_offset_; + return *reinterpret_cast(ptr); +} +inline ExtensionSet* GeneratedMessageReflection::MutableExtensionSet( + Message* message) const { + GOOGLE_DCHECK_NE(extensions_offset_, -1); + void* ptr = reinterpret_cast(message) + extensions_offset_; + return reinterpret_cast(ptr); +} + +// Simple accessors for manipulating has_bits_. +inline bool GeneratedMessageReflection::HasBit( + const Message& message, const FieldDescriptor* field) const { + return GetHasBits(message)[field->index() / 32] & + (1 << (field->index() % 32)); +} + +inline void GeneratedMessageReflection::SetBit( + Message* message, const FieldDescriptor* field) const { + MutableHasBits(message)[field->index() / 32] |= (1 << (field->index() % 32)); +} + +inline void GeneratedMessageReflection::ClearBit( + Message* message, const FieldDescriptor* field) const { + MutableHasBits(message)[field->index() / 32] &= ~(1 << (field->index() % 32)); +} + +// Template implementations of basic accessors. Inline because each +// template instance is only called from one location. These are +// used for all types except messages. +template +inline const Type& GeneratedMessageReflection::GetField( + const Message& message, const FieldDescriptor* field) const { + return GetRaw(message, field); +} + +template +inline void GeneratedMessageReflection::SetField( + Message* message, const FieldDescriptor* field, const Type& value) const { + *MutableRaw(message, field) = value; + SetBit(message, field); +} + +template +inline Type* GeneratedMessageReflection::MutableField( + Message* message, const FieldDescriptor* field) const { + SetBit(message, field); + return MutableRaw(message, field); +} + +template +inline const Type& GeneratedMessageReflection::GetRepeatedField( + const Message& message, const FieldDescriptor* field, int index) const { + return GetRaw >(message, field).Get(index); +} + +template +inline const Type& GeneratedMessageReflection::GetRepeatedPtrField( + const Message& message, const FieldDescriptor* field, int index) const { + return GetRaw >(message, field).Get(index); +} + +template +inline void GeneratedMessageReflection::SetRepeatedField( + Message* message, const FieldDescriptor* field, + int index, Type value) const { + MutableRaw >(message, field)->Set(index, value); +} + +template +inline Type* GeneratedMessageReflection::MutableRepeatedField( + Message* message, const FieldDescriptor* field, int index) const { + RepeatedPtrField* repeated = + MutableRaw >(message, field); + return repeated->Mutable(index); +} + +template +inline void GeneratedMessageReflection::AddField( + Message* message, const FieldDescriptor* field, const Type& value) const { + MutableRaw >(message, field)->Add(value); +} + +template +inline Type* GeneratedMessageReflection::AddField( + Message* message, const FieldDescriptor* field) const { + RepeatedPtrField* repeated = + MutableRaw >(message, field); + return repeated->Add(); +} + +} // namespace internal +} // namespace protobuf +} // namespace google diff --git a/depends/protobuf/google/protobuf/generated_message_reflection.h b/depends/protobuf/google/protobuf/generated_message_reflection.h new file mode 100644 index 0000000000..b545fa1a2a --- /dev/null +++ b/depends/protobuf/google/protobuf/generated_message_reflection.h @@ -0,0 +1,424 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// This header is logically internal, but is made public because it is used +// from protocol-compiler-generated code, which may reside in other components. + +#ifndef GOOGLE_PROTOBUF_GENERATED_MESSAGE_REFLECTION_H__ +#define GOOGLE_PROTOBUF_GENERATED_MESSAGE_REFLECTION_H__ + +#include +#include +#include +#include + + +namespace google { +namespace protobuf { + class DescriptorPool; + // Generated code needs these to have been forward-declared. Easier to do it + // here than to print them inside every .pb.h file. + class FileDescriptor; + class EnumDescriptor; +} + +namespace protobuf { +namespace internal { + +// Defined in this file. +class GeneratedMessageReflection; + +// Defined in other files. +class ExtensionSet; // extension_set.h + +// THIS CLASS IS NOT INTENDED FOR DIRECT USE. It is intended for use +// by generated code. This class is just a big hack that reduces code +// size. +// +// A GeneratedMessageReflection is an implementation of Reflection +// which expects all fields to be backed by simple variables located in +// memory. The locations are given using a base pointer and a set of +// offsets. +// +// It is required that the user represents fields of each type in a standard +// way, so that GeneratedMessageReflection can cast the void* pointer to +// the appropriate type. For primitive fields and string fields, each field +// should be represented using the obvious C++ primitive type. Enums and +// Messages are different: +// - Singular Message fields are stored as a pointer to a Message. These +// should start out NULL, except for in the default instance where they +// should start out pointing to other default instances. +// - Enum fields are stored as an int. This int must always contain +// a valid value, such that EnumDescriptor::FindValueByNumber() would +// not return NULL. +// - Repeated fields are stored as RepeatedFields or RepeatedPtrFields +// of whatever type the individual field would be. Strings and +// Messages use RepeatedPtrFields while everything else uses +// RepeatedFields. +class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { + public: + // Constructs a GeneratedMessageReflection. + // Parameters: + // descriptor: The descriptor for the message type being implemented. + // default_instance: The default instance of the message. This is only + // used to obtain pointers to default instances of embedded + // messages, which GetMessage() will return if the particular + // sub-message has not been initialized yet. (Thus, all + // embedded message fields *must* have non-NULL pointers + // in the default instance.) + // offsets: An array of ints giving the byte offsets, relative to + // the start of the message object, of each field. These can + // be computed at compile time using the + // GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET() macro, defined + // below. + // has_bits_offset: Offset in the message of an array of uint32s of size + // descriptor->field_count()/32, rounded up. This is a + // bitfield where each bit indicates whether or not the + // corresponding field of the message has been initialized. + // The bit for field index i is obtained by the expression: + // has_bits[i / 32] & (1 << (i % 32)) + // unknown_fields_offset: Offset in the message of the UnknownFieldSet for + // the message. + // extensions_offset: Offset in the message of the ExtensionSet for the + // message, or -1 if the message type has no extension + // ranges. + // pool: DescriptorPool to search for extension definitions. Only + // used by FindKnownExtensionByName() and + // FindKnownExtensionByNumber(). + // factory: MessageFactory to use to construct extension messages. + // object_size: The size of a message object of this type, as measured + // by sizeof(). + GeneratedMessageReflection(const Descriptor* descriptor, + const Message* default_instance, + const int offsets[], + int has_bits_offset, + int unknown_fields_offset, + int extensions_offset, + const DescriptorPool* pool, + MessageFactory* factory, + int object_size); + ~GeneratedMessageReflection(); + + // implements Reflection ------------------------------------------- + + const UnknownFieldSet& GetUnknownFields(const Message& message) const; + UnknownFieldSet* MutableUnknownFields(Message* message) const; + + int SpaceUsed(const Message& message) const; + + bool HasField(const Message& message, const FieldDescriptor* field) const; + int FieldSize(const Message& message, const FieldDescriptor* field) const; + void ClearField(Message* message, const FieldDescriptor* field) const; + void RemoveLast(Message* message, const FieldDescriptor* field) const; + void Swap(Message* message1, Message* message2) const; + void SwapElements(Message* message, const FieldDescriptor* field, + int index1, int index2) const; + void ListFields(const Message& message, + vector* output) const; + + int32 GetInt32 (const Message& message, + const FieldDescriptor* field) const; + int64 GetInt64 (const Message& message, + const FieldDescriptor* field) const; + uint32 GetUInt32(const Message& message, + const FieldDescriptor* field) const; + uint64 GetUInt64(const Message& message, + const FieldDescriptor* field) const; + float GetFloat (const Message& message, + const FieldDescriptor* field) const; + double GetDouble(const Message& message, + const FieldDescriptor* field) const; + bool GetBool (const Message& message, + const FieldDescriptor* field) const; + string GetString(const Message& message, + const FieldDescriptor* field) const; + const string& GetStringReference(const Message& message, + const FieldDescriptor* field, + string* scratch) const; + const EnumValueDescriptor* GetEnum(const Message& message, + const FieldDescriptor* field) const; + const Message& GetMessage(const Message& message, + const FieldDescriptor* field, + MessageFactory* factory = NULL) const; + + void SetInt32 (Message* message, + const FieldDescriptor* field, int32 value) const; + void SetInt64 (Message* message, + const FieldDescriptor* field, int64 value) const; + void SetUInt32(Message* message, + const FieldDescriptor* field, uint32 value) const; + void SetUInt64(Message* message, + const FieldDescriptor* field, uint64 value) const; + void SetFloat (Message* message, + const FieldDescriptor* field, float value) const; + void SetDouble(Message* message, + const FieldDescriptor* field, double value) const; + void SetBool (Message* message, + const FieldDescriptor* field, bool value) const; + void SetString(Message* message, + const FieldDescriptor* field, + const string& value) const; + void SetEnum (Message* message, const FieldDescriptor* field, + const EnumValueDescriptor* value) const; + Message* MutableMessage(Message* message, const FieldDescriptor* field, + MessageFactory* factory = NULL) const; + + int32 GetRepeatedInt32 (const Message& message, + const FieldDescriptor* field, int index) const; + int64 GetRepeatedInt64 (const Message& message, + const FieldDescriptor* field, int index) const; + uint32 GetRepeatedUInt32(const Message& message, + const FieldDescriptor* field, int index) const; + uint64 GetRepeatedUInt64(const Message& message, + const FieldDescriptor* field, int index) const; + float GetRepeatedFloat (const Message& message, + const FieldDescriptor* field, int index) const; + double GetRepeatedDouble(const Message& message, + const FieldDescriptor* field, int index) const; + bool GetRepeatedBool (const Message& message, + const FieldDescriptor* field, int index) const; + string GetRepeatedString(const Message& message, + const FieldDescriptor* field, int index) const; + const string& GetRepeatedStringReference(const Message& message, + const FieldDescriptor* field, + int index, string* scratch) const; + const EnumValueDescriptor* GetRepeatedEnum(const Message& message, + const FieldDescriptor* field, + int index) const; + const Message& GetRepeatedMessage(const Message& message, + const FieldDescriptor* field, + int index) const; + + // Set the value of a field. + void SetRepeatedInt32 (Message* message, + const FieldDescriptor* field, int index, int32 value) const; + void SetRepeatedInt64 (Message* message, + const FieldDescriptor* field, int index, int64 value) const; + void SetRepeatedUInt32(Message* message, + const FieldDescriptor* field, int index, uint32 value) const; + void SetRepeatedUInt64(Message* message, + const FieldDescriptor* field, int index, uint64 value) const; + void SetRepeatedFloat (Message* message, + const FieldDescriptor* field, int index, float value) const; + void SetRepeatedDouble(Message* message, + const FieldDescriptor* field, int index, double value) const; + void SetRepeatedBool (Message* message, + const FieldDescriptor* field, int index, bool value) const; + void SetRepeatedString(Message* message, + const FieldDescriptor* field, int index, + const string& value) const; + void SetRepeatedEnum(Message* message, const FieldDescriptor* field, + int index, const EnumValueDescriptor* value) const; + // Get a mutable pointer to a field with a message type. + Message* MutableRepeatedMessage(Message* message, + const FieldDescriptor* field, + int index) const; + + void AddInt32 (Message* message, + const FieldDescriptor* field, int32 value) const; + void AddInt64 (Message* message, + const FieldDescriptor* field, int64 value) const; + void AddUInt32(Message* message, + const FieldDescriptor* field, uint32 value) const; + void AddUInt64(Message* message, + const FieldDescriptor* field, uint64 value) const; + void AddFloat (Message* message, + const FieldDescriptor* field, float value) const; + void AddDouble(Message* message, + const FieldDescriptor* field, double value) const; + void AddBool (Message* message, + const FieldDescriptor* field, bool value) const; + void AddString(Message* message, + const FieldDescriptor* field, const string& value) const; + void AddEnum(Message* message, + const FieldDescriptor* field, + const EnumValueDescriptor* value) const; + Message* AddMessage(Message* message, const FieldDescriptor* field, + MessageFactory* factory = NULL) const; + + const FieldDescriptor* FindKnownExtensionByName(const string& name) const; + const FieldDescriptor* FindKnownExtensionByNumber(int number) const; + + private: + friend class GeneratedMessage; + + const Descriptor* descriptor_; + const Message* default_instance_; + const int* offsets_; + + int has_bits_offset_; + int unknown_fields_offset_; + int extensions_offset_; + int object_size_; + + const DescriptorPool* descriptor_pool_; + MessageFactory* message_factory_; + + template + inline const Type& GetRaw(const Message& message, + const FieldDescriptor* field) const; + template + inline Type* MutableRaw(Message* message, + const FieldDescriptor* field) const; + template + inline const Type& DefaultRaw(const FieldDescriptor* field) const; + inline const Message* GetMessagePrototype(const FieldDescriptor* field) const; + + inline const uint32* GetHasBits(const Message& message) const; + inline uint32* MutableHasBits(Message* message) const; + inline const ExtensionSet& GetExtensionSet(const Message& message) const; + inline ExtensionSet* MutableExtensionSet(Message* message) const; + + inline bool HasBit(const Message& message, + const FieldDescriptor* field) const; + inline void SetBit(Message* message, + const FieldDescriptor* field) const; + inline void ClearBit(Message* message, + const FieldDescriptor* field) const; + + template + inline const Type& GetField(const Message& message, + const FieldDescriptor* field) const; + template + inline void SetField(Message* message, + const FieldDescriptor* field, const Type& value) const; + template + inline Type* MutableField(Message* message, + const FieldDescriptor* field) const; + template + inline const Type& GetRepeatedField(const Message& message, + const FieldDescriptor* field, + int index) const; + template + inline const Type& GetRepeatedPtrField(const Message& message, + const FieldDescriptor* field, + int index) const; + template + inline void SetRepeatedField(Message* message, + const FieldDescriptor* field, int index, + Type value) const; + template + inline Type* MutableRepeatedField(Message* message, + const FieldDescriptor* field, + int index) const; + template + inline void AddField(Message* message, + const FieldDescriptor* field, const Type& value) const; + template + inline Type* AddField(Message* message, + const FieldDescriptor* field) const; + + int GetExtensionNumberOrDie(const Descriptor* type) const; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(GeneratedMessageReflection); +}; + +// Returns the offset of the given field within the given aggregate type. +// This is equivalent to the ANSI C offsetof() macro. However, according +// to the C++ standard, offsetof() only works on POD types, and GCC +// enforces this requirement with a warning. In practice, this rule is +// unnecessarily strict; there is probably no compiler or platform on +// which the offsets of the direct fields of a class are non-constant. +// Fields inherited from superclasses *can* have non-constant offsets, +// but that's not what this macro will be used for. +// +// Note that we calculate relative to the pointer value 16 here since if we +// just use zero, GCC complains about dereferencing a NULL pointer. We +// choose 16 rather than some other number just in case the compiler would +// be confused by an unaligned pointer. +#define GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(TYPE, FIELD) \ + static_cast( \ + reinterpret_cast( \ + &reinterpret_cast(16)->FIELD) - \ + reinterpret_cast(16)) + +// There are some places in proto2 where dynamic_cast would be useful as an +// optimization. For example, take Message::MergeFrom(const Message& other). +// For a given generated message FooMessage, we generate these two methods: +// void MergeFrom(const FooMessage& other); +// void MergeFrom(const Message& other); +// The former method can be implemented directly in terms of FooMessage's +// inline accessors, but the latter method must work with the reflection +// interface. However, if the parameter to the latter method is actually of +// type FooMessage, then we'd like to be able to just call the other method +// as an optimization. So, we use dynamic_cast to check this. +// +// That said, dynamic_cast requires RTTI, which many people like to disable +// for performance and code size reasons. When RTTI is not available, we +// still need to produce correct results. So, in this case we have to fall +// back to using reflection, which is what we would have done anyway if the +// objects were not of the exact same class. +// +// dynamic_cast_if_available() implements this logic. If RTTI is +// enabled, it does a dynamic_cast. If RTTI is disabled, it just returns +// NULL. +// +// If you need to compile without RTTI, simply #define GOOGLE_PROTOBUF_NO_RTTI. +// On MSVC, this should be detected automatically. +template +inline To dynamic_cast_if_available(From from) { +#if defined(GOOGLE_PROTOBUF_NO_RTTI) || (defined(_MSC_VER)&&!defined(_CPPRTTI)) + return NULL; +#else + return dynamic_cast(from); +#endif +} + +// Helper for EnumType_Parse functions: try to parse the string 'name' as an +// enum name of the given type, returning true and filling in value on success, +// or returning false and leaving value unchanged on failure. +LIBPROTOBUF_EXPORT bool ParseNamedEnum(const EnumDescriptor* descriptor, + const string& name, + int* value); + +template +bool ParseNamedEnum(const EnumDescriptor* descriptor, + const string& name, + EnumType* value) { + int tmp; + if (!ParseNamedEnum(descriptor, name, &tmp)) return false; + *value = static_cast(tmp); + return true; +} + +// Just a wrapper around printing the name of a value. The main point of this +// function is not to be inlined, so that you can do this without including +// descriptor.h. +LIBPROTOBUF_EXPORT const string& NameOfEnum(const EnumDescriptor* descriptor, int value); + +} // namespace internal +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_GENERATED_MESSAGE_REFLECTION_H__ diff --git a/depends/protobuf/google/protobuf/generated_message_util.cc b/depends/protobuf/google/protobuf/generated_message_util.cc new file mode 100644 index 0000000000..76e547bb8d --- /dev/null +++ b/depends/protobuf/google/protobuf/generated_message_util.cc @@ -0,0 +1,55 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include + +#include + +namespace google { +namespace protobuf { +namespace internal { + +double Infinity() { + return std::numeric_limits::infinity(); +} +double NaN() { + return std::numeric_limits::quiet_NaN(); +} + +const ::std::string kEmptyString; + + +} // namespace internal +} // namespace protobuf +} // namespace google diff --git a/depends/protobuf/google/protobuf/generated_message_util.h b/depends/protobuf/google/protobuf/generated_message_util.h new file mode 100644 index 0000000000..239daea598 --- /dev/null +++ b/depends/protobuf/google/protobuf/generated_message_util.h @@ -0,0 +1,82 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// This file contains miscellaneous helper code used by generated code -- +// including lite types -- but which should not be used directly by users. + +#ifndef GOOGLE_PROTOBUF_GENERATED_MESSAGE_UTIL_H__ +#define GOOGLE_PROTOBUF_GENERATED_MESSAGE_UTIL_H__ + +#include + +#include + + +namespace google { +namespace protobuf { + namespace io { + class CodedInputStream; // coded_stream.h + } +} + +namespace protobuf { +namespace internal { + +// Annotation for the compiler to emit a deprecation message if a field marked +// with option 'deprecated=true' is used in the code, or for other things in +// generated code which are deprecated. +// +// For internal use in the pb.cc files, deprecation warnings are suppressed +// there. +#undef DEPRECATED_PROTOBUF_FIELD +#if !defined(INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION) +# define PROTOBUF_DEPRECATED GOOGLE_ATTRIBUTE_DEPRECATED +#else +# define PROTOBUF_DEPRECATED +#endif + + +// Constants for special floating point values. +double Infinity(); +double NaN(); + +// Constant used for empty default strings. +extern LIBPROTOBUF_EXPORT const ::std::string kEmptyString; + + +} // namespace internal +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_GENERATED_MESSAGE_UTIL_H__ diff --git a/depends/protobuf/google/protobuf/io/coded_stream.cc b/depends/protobuf/google/protobuf/io/coded_stream.cc new file mode 100644 index 0000000000..57d486f958 --- /dev/null +++ b/depends/protobuf/google/protobuf/io/coded_stream.cc @@ -0,0 +1,839 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// This implementation is heavily optimized to make reads and writes +// of small values (especially varints) as fast as possible. In +// particular, we optimize for the common case that a read or a write +// will not cross the end of the buffer, since we can avoid a lot +// of branching in this case. + +#include +#include +#include +#include +#include +#include + + +namespace google { +namespace protobuf { +namespace io { + +namespace { + +static const int kMaxVarintBytes = 10; +static const int kMaxVarint32Bytes = 5; + + +inline bool NextNonEmpty(ZeroCopyInputStream* input, + const void** data, int* size) { + bool success; + do { + success = input->Next(data, size); + } while (success && *size == 0); + return success; +} + +} // namespace + +// CodedInputStream ================================================== + + +void CodedInputStream::BackUpInputToCurrentPosition() { + int backup_bytes = BufferSize() + buffer_size_after_limit_ + overflow_bytes_; + if (backup_bytes > 0) { + input_->BackUp(backup_bytes); + + // total_bytes_read_ doesn't include overflow_bytes_. + total_bytes_read_ -= BufferSize() + buffer_size_after_limit_; + buffer_end_ = buffer_; + buffer_size_after_limit_ = 0; + overflow_bytes_ = 0; + } +} + +inline void CodedInputStream::RecomputeBufferLimits() { + buffer_end_ += buffer_size_after_limit_; + int closest_limit = min(current_limit_, total_bytes_limit_); + if (closest_limit < total_bytes_read_) { + // The limit position is in the current buffer. We must adjust + // the buffer size accordingly. + buffer_size_after_limit_ = total_bytes_read_ - closest_limit; + buffer_end_ -= buffer_size_after_limit_; + } else { + buffer_size_after_limit_ = 0; + } +} + +CodedInputStream::Limit CodedInputStream::PushLimit(int byte_limit) { + // Current position relative to the beginning of the stream. + int current_position = total_bytes_read_ - + (BufferSize() + buffer_size_after_limit_); + + Limit old_limit = current_limit_; + + // security: byte_limit is possibly evil, so check for negative values + // and overflow. + if (byte_limit >= 0 && + byte_limit <= INT_MAX - current_position) { + current_limit_ = current_position + byte_limit; + } else { + // Negative or overflow. + current_limit_ = INT_MAX; + } + + // We need to enforce all limits, not just the new one, so if the previous + // limit was before the new requested limit, we continue to enforce the + // previous limit. + current_limit_ = min(current_limit_, old_limit); + + RecomputeBufferLimits(); + return old_limit; +} + +void CodedInputStream::PopLimit(Limit limit) { + // The limit passed in is actually the *old* limit, which we returned from + // PushLimit(). + current_limit_ = limit; + RecomputeBufferLimits(); + + // We may no longer be at a legitimate message end. ReadTag() needs to be + // called again to find out. + legitimate_message_end_ = false; +} + +int CodedInputStream::BytesUntilLimit() { + if (current_limit_ == INT_MAX) return -1; + int current_position = total_bytes_read_ - + (BufferSize() + buffer_size_after_limit_); + + return current_limit_ - current_position; +} + +void CodedInputStream::SetTotalBytesLimit( + int total_bytes_limit, int warning_threshold) { + // Make sure the limit isn't already past, since this could confuse other + // code. + int current_position = total_bytes_read_ - + (BufferSize() + buffer_size_after_limit_); + total_bytes_limit_ = max(current_position, total_bytes_limit); + total_bytes_warning_threshold_ = warning_threshold; + RecomputeBufferLimits(); +} + +void CodedInputStream::PrintTotalBytesLimitError() { + GOOGLE_LOG(ERROR) << "A protocol message was rejected because it was too " + "big (more than " << total_bytes_limit_ + << " bytes). To increase the limit (or to disable these " + "warnings), see CodedInputStream::SetTotalBytesLimit() " + "in google/protobuf/io/coded_stream.h."; +} + +bool CodedInputStream::Skip(int count) { + if (count < 0) return false; // security: count is often user-supplied + + const int original_buffer_size = BufferSize(); + + if (count <= original_buffer_size) { + // Just skipping within the current buffer. Easy. + Advance(count); + return true; + } + + if (buffer_size_after_limit_ > 0) { + // We hit a limit inside this buffer. Advance to the limit and fail. + Advance(original_buffer_size); + return false; + } + + count -= original_buffer_size; + buffer_ = NULL; + buffer_end_ = buffer_; + + // Make sure this skip doesn't try to skip past the current limit. + int closest_limit = min(current_limit_, total_bytes_limit_); + int bytes_until_limit = closest_limit - total_bytes_read_; + if (bytes_until_limit < count) { + // We hit the limit. Skip up to it then fail. + if (bytes_until_limit > 0) { + total_bytes_read_ = closest_limit; + input_->Skip(bytes_until_limit); + } + return false; + } + + total_bytes_read_ += count; + return input_->Skip(count); +} + +bool CodedInputStream::GetDirectBufferPointer(const void** data, int* size) { + if (BufferSize() == 0 && !Refresh()) return false; + + *data = buffer_; + *size = BufferSize(); + return true; +} + +bool CodedInputStream::ReadRaw(void* buffer, int size) { + int current_buffer_size; + while ((current_buffer_size = BufferSize()) < size) { + // Reading past end of buffer. Copy what we have, then refresh. + memcpy(buffer, buffer_, current_buffer_size); + buffer = reinterpret_cast(buffer) + current_buffer_size; + size -= current_buffer_size; + Advance(current_buffer_size); + if (!Refresh()) return false; + } + + memcpy(buffer, buffer_, size); + Advance(size); + + return true; +} + +bool CodedInputStream::ReadString(string* buffer, int size) { + if (size < 0) return false; // security: size is often user-supplied + return InternalReadStringInline(buffer, size); +} + +bool CodedInputStream::ReadStringFallback(string* buffer, int size) { + if (!buffer->empty()) { + buffer->clear(); + } + + int current_buffer_size; + while ((current_buffer_size = BufferSize()) < size) { + // Some STL implementations "helpfully" crash on buffer->append(NULL, 0). + if (current_buffer_size != 0) { + // Note: string1.append(string2) is O(string2.size()) (as opposed to + // O(string1.size() + string2.size()), which would be bad). + buffer->append(reinterpret_cast(buffer_), + current_buffer_size); + } + size -= current_buffer_size; + Advance(current_buffer_size); + if (!Refresh()) return false; + } + + buffer->append(reinterpret_cast(buffer_), size); + Advance(size); + + return true; +} + + +bool CodedInputStream::ReadLittleEndian32Fallback(uint32* value) { + uint8 bytes[sizeof(*value)]; + + const uint8* ptr; + if (BufferSize() >= sizeof(*value)) { + // Fast path: Enough bytes in the buffer to read directly. + ptr = buffer_; + Advance(sizeof(*value)); + } else { + // Slow path: Had to read past the end of the buffer. + if (!ReadRaw(bytes, sizeof(*value))) return false; + ptr = bytes; + } + ReadLittleEndian32FromArray(ptr, value); + return true; +} + +bool CodedInputStream::ReadLittleEndian64Fallback(uint64* value) { + uint8 bytes[sizeof(*value)]; + + const uint8* ptr; + if (BufferSize() >= sizeof(*value)) { + // Fast path: Enough bytes in the buffer to read directly. + ptr = buffer_; + Advance(sizeof(*value)); + } else { + // Slow path: Had to read past the end of the buffer. + if (!ReadRaw(bytes, sizeof(*value))) return false; + ptr = bytes; + } + ReadLittleEndian64FromArray(ptr, value); + return true; +} + +namespace { + +inline const uint8* ReadVarint32FromArray( + const uint8* buffer, uint32* value) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; +inline const uint8* ReadVarint32FromArray(const uint8* buffer, uint32* value) { + // Fast path: We have enough bytes left in the buffer to guarantee that + // this read won't cross the end, so we can skip the checks. + const uint8* ptr = buffer; + uint32 b; + uint32 result; + + b = *(ptr++); result = (b & 0x7F) ; if (!(b & 0x80)) goto done; + b = *(ptr++); result |= (b & 0x7F) << 7; if (!(b & 0x80)) goto done; + b = *(ptr++); result |= (b & 0x7F) << 14; if (!(b & 0x80)) goto done; + b = *(ptr++); result |= (b & 0x7F) << 21; if (!(b & 0x80)) goto done; + b = *(ptr++); result |= b << 28; if (!(b & 0x80)) goto done; + + // If the input is larger than 32 bits, we still need to read it all + // and discard the high-order bits. + for (int i = 0; i < kMaxVarintBytes - kMaxVarint32Bytes; i++) { + b = *(ptr++); if (!(b & 0x80)) goto done; + } + + // We have overrun the maximum size of a varint (10 bytes). Assume + // the data is corrupt. + return NULL; + + done: + *value = result; + return ptr; +} + +} // namespace + +bool CodedInputStream::ReadVarint32Slow(uint32* value) { + uint64 result; + // Directly invoke ReadVarint64Fallback, since we already tried to optimize + // for one-byte varints. + if (!ReadVarint64Fallback(&result)) return false; + *value = (uint32)result; + return true; +} + +bool CodedInputStream::ReadVarint32Fallback(uint32* value) { + if (BufferSize() >= kMaxVarintBytes || + // Optimization: If the varint ends at exactly the end of the buffer, + // we can detect that and still use the fast path. + (buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) { + const uint8* end = ReadVarint32FromArray(buffer_, value); + if (end == NULL) return false; + buffer_ = end; + return true; + } else { + // Really slow case: we will incur the cost of an extra function call here, + // but moving this out of line reduces the size of this function, which + // improves the common case. In micro benchmarks, this is worth about 10-15% + return ReadVarint32Slow(value); + } +} + +uint32 CodedInputStream::ReadTagSlow() { + if (buffer_ == buffer_end_) { + // Call refresh. + if (!Refresh()) { + // Refresh failed. Make sure that it failed due to EOF, not because + // we hit total_bytes_limit_, which, unlike normal limits, is not a + // valid place to end a message. + int current_position = total_bytes_read_ - buffer_size_after_limit_; + if (current_position >= total_bytes_limit_) { + // Hit total_bytes_limit_. But if we also hit the normal limit, + // we're still OK. + legitimate_message_end_ = current_limit_ == total_bytes_limit_; + } else { + legitimate_message_end_ = true; + } + return 0; + } + } + + // For the slow path, just do a 64-bit read. Try to optimize for one-byte tags + // again, since we have now refreshed the buffer. + uint64 result; + if (!ReadVarint64(&result)) return 0; + return static_cast(result); +} + +uint32 CodedInputStream::ReadTagFallback() { + if (BufferSize() >= kMaxVarintBytes || + // Optimization: If the varint ends at exactly the end of the buffer, + // we can detect that and still use the fast path. + (buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) { + uint32 tag; + const uint8* end = ReadVarint32FromArray(buffer_, &tag); + if (end == NULL) { + return 0; + } + buffer_ = end; + return tag; + } else { + // We are commonly at a limit when attempting to read tags. Try to quickly + // detect this case without making another function call. + if (buffer_ == buffer_end_ && buffer_size_after_limit_ > 0 && + // Make sure that the limit we hit is not total_bytes_limit_, since + // in that case we still need to call Refresh() so that it prints an + // error. + total_bytes_read_ - buffer_size_after_limit_ < total_bytes_limit_) { + // We hit a byte limit. + legitimate_message_end_ = true; + return 0; + } + return ReadTagSlow(); + } +} + +bool CodedInputStream::ReadVarint64Slow(uint64* value) { + // Slow path: This read might cross the end of the buffer, so we + // need to check and refresh the buffer if and when it does. + + uint64 result = 0; + int count = 0; + uint32 b; + + do { + if (count == kMaxVarintBytes) return false; + while (buffer_ == buffer_end_) { + if (!Refresh()) return false; + } + b = *buffer_; + result |= static_cast(b & 0x7F) << (7 * count); + Advance(1); + ++count; + } while (b & 0x80); + + *value = result; + return true; +} + +bool CodedInputStream::ReadVarint64Fallback(uint64* value) { + if (BufferSize() >= kMaxVarintBytes || + // Optimization: If the varint ends at exactly the end of the buffer, + // we can detect that and still use the fast path. + (buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) { + // Fast path: We have enough bytes left in the buffer to guarantee that + // this read won't cross the end, so we can skip the checks. + + const uint8* ptr = buffer_; + uint32 b; + + // Splitting into 32-bit pieces gives better performance on 32-bit + // processors. + uint32 part0 = 0, part1 = 0, part2 = 0; + + b = *(ptr++); part0 = (b & 0x7F) ; if (!(b & 0x80)) goto done; + b = *(ptr++); part0 |= (b & 0x7F) << 7; if (!(b & 0x80)) goto done; + b = *(ptr++); part0 |= (b & 0x7F) << 14; if (!(b & 0x80)) goto done; + b = *(ptr++); part0 |= (b & 0x7F) << 21; if (!(b & 0x80)) goto done; + b = *(ptr++); part1 = (b & 0x7F) ; if (!(b & 0x80)) goto done; + b = *(ptr++); part1 |= (b & 0x7F) << 7; if (!(b & 0x80)) goto done; + b = *(ptr++); part1 |= (b & 0x7F) << 14; if (!(b & 0x80)) goto done; + b = *(ptr++); part1 |= (b & 0x7F) << 21; if (!(b & 0x80)) goto done; + b = *(ptr++); part2 = (b & 0x7F) ; if (!(b & 0x80)) goto done; + b = *(ptr++); part2 |= (b & 0x7F) << 7; if (!(b & 0x80)) goto done; + + // We have overrun the maximum size of a varint (10 bytes). The data + // must be corrupt. + return NULL; + + done: + Advance(ptr - buffer_); + *value = (static_cast(part0) ) | + (static_cast(part1) << 28) | + (static_cast(part2) << 56); + return true; + } else { + return ReadVarint64Slow(value); + } +} + +bool CodedInputStream::Refresh() { + GOOGLE_DCHECK_EQ(0, BufferSize()); + + if (buffer_size_after_limit_ > 0 || overflow_bytes_ > 0 || + total_bytes_read_ == current_limit_) { + // We've hit a limit. Stop. + int current_position = total_bytes_read_ - buffer_size_after_limit_; + + if (current_position >= total_bytes_limit_ && + total_bytes_limit_ != current_limit_) { + // Hit total_bytes_limit_. + PrintTotalBytesLimitError(); + } + + return false; + } + + if (total_bytes_warning_threshold_ >= 0 && + total_bytes_read_ >= total_bytes_warning_threshold_) { + GOOGLE_LOG(WARNING) << "Reading dangerously large protocol message. If the " + "message turns out to be larger than " + << total_bytes_limit_ << " bytes, parsing will be halted " + "for security reasons. To increase the limit (or to " + "disable these warnings), see " + "CodedInputStream::SetTotalBytesLimit() in " + "google/protobuf/io/coded_stream.h."; + + // Don't warn again for this stream. + total_bytes_warning_threshold_ = -1; + } + + const void* void_buffer; + int buffer_size; + if (NextNonEmpty(input_, &void_buffer, &buffer_size)) { + buffer_ = reinterpret_cast(void_buffer); + buffer_end_ = buffer_ + buffer_size; + GOOGLE_CHECK_GE(buffer_size, 0); + + if (total_bytes_read_ <= INT_MAX - buffer_size) { + total_bytes_read_ += buffer_size; + } else { + // Overflow. Reset buffer_end_ to not include the bytes beyond INT_MAX. + // We can't get that far anyway, because total_bytes_limit_ is guaranteed + // to be less than it. We need to keep track of the number of bytes + // we discarded, though, so that we can call input_->BackUp() to back + // up over them on destruction. + + // The following line is equivalent to: + // overflow_bytes_ = total_bytes_read_ + buffer_size - INT_MAX; + // except that it avoids overflows. Signed integer overflow has + // undefined results according to the C standard. + overflow_bytes_ = total_bytes_read_ - (INT_MAX - buffer_size); + buffer_end_ -= overflow_bytes_; + total_bytes_read_ = INT_MAX; + } + + RecomputeBufferLimits(); + return true; + } else { + buffer_ = NULL; + buffer_end_ = NULL; + return false; + } +} + +// CodedOutputStream ================================================= + +CodedOutputStream::CodedOutputStream(ZeroCopyOutputStream* output) + : output_(output), + buffer_(NULL), + buffer_size_(0), + total_bytes_(0), + had_error_(false) { + // Eagerly Refresh() so buffer space is immediately available. + Refresh(); + // The Refresh() may have failed. If the client doesn't write any data, + // though, don't consider this an error. If the client does write data, then + // another Refresh() will be attempted and it will set the error once again. + had_error_ = false; +} + +CodedOutputStream::~CodedOutputStream() { + if (buffer_size_ > 0) { + output_->BackUp(buffer_size_); + } +} + +bool CodedOutputStream::Skip(int count) { + if (count < 0) return false; + + while (count > buffer_size_) { + count -= buffer_size_; + if (!Refresh()) return false; + } + + Advance(count); + return true; +} + +bool CodedOutputStream::GetDirectBufferPointer(void** data, int* size) { + if (buffer_size_ == 0 && !Refresh()) return false; + + *data = buffer_; + *size = buffer_size_; + return true; +} + +void CodedOutputStream::WriteRaw(const void* data, int size) { + while (buffer_size_ < size) { + memcpy(buffer_, data, buffer_size_); + size -= buffer_size_; + data = reinterpret_cast(data) + buffer_size_; + if (!Refresh()) return; + } + + memcpy(buffer_, data, size); + Advance(size); +} + +uint8* CodedOutputStream::WriteRawToArray( + const void* data, int size, uint8* target) { + memcpy(target, data, size); + return target + size; +} + + +void CodedOutputStream::WriteLittleEndian32(uint32 value) { + uint8 bytes[sizeof(value)]; + + bool use_fast = buffer_size_ >= sizeof(value); + uint8* ptr = use_fast ? buffer_ : bytes; + + WriteLittleEndian32ToArray(value, ptr); + + if (use_fast) { + Advance(sizeof(value)); + } else { + WriteRaw(bytes, sizeof(value)); + } +} + +void CodedOutputStream::WriteLittleEndian64(uint64 value) { + uint8 bytes[sizeof(value)]; + + bool use_fast = buffer_size_ >= sizeof(value); + uint8* ptr = use_fast ? buffer_ : bytes; + + WriteLittleEndian64ToArray(value, ptr); + + if (use_fast) { + Advance(sizeof(value)); + } else { + WriteRaw(bytes, sizeof(value)); + } +} + +inline uint8* CodedOutputStream::WriteVarint32FallbackToArrayInline( + uint32 value, uint8* target) { + target[0] = static_cast(value | 0x80); + if (value >= (1 << 7)) { + target[1] = static_cast((value >> 7) | 0x80); + if (value >= (1 << 14)) { + target[2] = static_cast((value >> 14) | 0x80); + if (value >= (1 << 21)) { + target[3] = static_cast((value >> 21) | 0x80); + if (value >= (1 << 28)) { + target[4] = static_cast(value >> 28); + return target + 5; + } else { + target[3] &= 0x7F; + return target + 4; + } + } else { + target[2] &= 0x7F; + return target + 3; + } + } else { + target[1] &= 0x7F; + return target + 2; + } + } else { + target[0] &= 0x7F; + return target + 1; + } +} + +void CodedOutputStream::WriteVarint32(uint32 value) { + if (buffer_size_ >= kMaxVarint32Bytes) { + // Fast path: We have enough bytes left in the buffer to guarantee that + // this write won't cross the end, so we can skip the checks. + uint8* target = buffer_; + uint8* end = WriteVarint32FallbackToArrayInline(value, target); + int size = end - target; + Advance(size); + } else { + // Slow path: This write might cross the end of the buffer, so we + // compose the bytes first then use WriteRaw(). + uint8 bytes[kMaxVarint32Bytes]; + int size = 0; + while (value > 0x7F) { + bytes[size++] = (static_cast(value) & 0x7F) | 0x80; + value >>= 7; + } + bytes[size++] = static_cast(value) & 0x7F; + WriteRaw(bytes, size); + } +} + +uint8* CodedOutputStream::WriteVarint32FallbackToArray( + uint32 value, uint8* target) { + return WriteVarint32FallbackToArrayInline(value, target); +} + +inline uint8* CodedOutputStream::WriteVarint64ToArrayInline( + uint64 value, uint8* target) { + // Splitting into 32-bit pieces gives better performance on 32-bit + // processors. + uint32 part0 = static_cast(value ); + uint32 part1 = static_cast(value >> 28); + uint32 part2 = static_cast(value >> 56); + + int size; + + // Here we can't really optimize for small numbers, since the value is + // split into three parts. Cheking for numbers < 128, for instance, + // would require three comparisons, since you'd have to make sure part1 + // and part2 are zero. However, if the caller is using 64-bit integers, + // it is likely that they expect the numbers to often be very large, so + // we probably don't want to optimize for small numbers anyway. Thus, + // we end up with a hardcoded binary search tree... + if (part2 == 0) { + if (part1 == 0) { + if (part0 < (1 << 14)) { + if (part0 < (1 << 7)) { + size = 1; goto size1; + } else { + size = 2; goto size2; + } + } else { + if (part0 < (1 << 21)) { + size = 3; goto size3; + } else { + size = 4; goto size4; + } + } + } else { + if (part1 < (1 << 14)) { + if (part1 < (1 << 7)) { + size = 5; goto size5; + } else { + size = 6; goto size6; + } + } else { + if (part1 < (1 << 21)) { + size = 7; goto size7; + } else { + size = 8; goto size8; + } + } + } + } else { + if (part2 < (1 << 7)) { + size = 9; goto size9; + } else { + size = 10; goto size10; + } + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + + size10: target[9] = static_cast((part2 >> 7) | 0x80); + size9 : target[8] = static_cast((part2 ) | 0x80); + size8 : target[7] = static_cast((part1 >> 21) | 0x80); + size7 : target[6] = static_cast((part1 >> 14) | 0x80); + size6 : target[5] = static_cast((part1 >> 7) | 0x80); + size5 : target[4] = static_cast((part1 ) | 0x80); + size4 : target[3] = static_cast((part0 >> 21) | 0x80); + size3 : target[2] = static_cast((part0 >> 14) | 0x80); + size2 : target[1] = static_cast((part0 >> 7) | 0x80); + size1 : target[0] = static_cast((part0 ) | 0x80); + + target[size-1] &= 0x7F; + return target + size; +} + +void CodedOutputStream::WriteVarint64(uint64 value) { + if (buffer_size_ >= kMaxVarintBytes) { + // Fast path: We have enough bytes left in the buffer to guarantee that + // this write won't cross the end, so we can skip the checks. + uint8* target = buffer_; + + uint8* end = WriteVarint64ToArrayInline(value, target); + int size = end - target; + Advance(size); + } else { + // Slow path: This write might cross the end of the buffer, so we + // compose the bytes first then use WriteRaw(). + uint8 bytes[kMaxVarintBytes]; + int size = 0; + while (value > 0x7F) { + bytes[size++] = (static_cast(value) & 0x7F) | 0x80; + value >>= 7; + } + bytes[size++] = static_cast(value) & 0x7F; + WriteRaw(bytes, size); + } +} + +uint8* CodedOutputStream::WriteVarint64ToArray( + uint64 value, uint8* target) { + return WriteVarint64ToArrayInline(value, target); +} + +bool CodedOutputStream::Refresh() { + void* void_buffer; + if (output_->Next(&void_buffer, &buffer_size_)) { + buffer_ = reinterpret_cast(void_buffer); + total_bytes_ += buffer_size_; + return true; + } else { + buffer_ = NULL; + buffer_size_ = 0; + had_error_ = true; + return false; + } +} + +int CodedOutputStream::VarintSize32Fallback(uint32 value) { + if (value < (1 << 7)) { + return 1; + } else if (value < (1 << 14)) { + return 2; + } else if (value < (1 << 21)) { + return 3; + } else if (value < (1 << 28)) { + return 4; + } else { + return 5; + } +} + +int CodedOutputStream::VarintSize64(uint64 value) { + if (value < (1ull << 35)) { + if (value < (1ull << 7)) { + return 1; + } else if (value < (1ull << 14)) { + return 2; + } else if (value < (1ull << 21)) { + return 3; + } else if (value < (1ull << 28)) { + return 4; + } else { + return 5; + } + } else { + if (value < (1ull << 42)) { + return 6; + } else if (value < (1ull << 49)) { + return 7; + } else if (value < (1ull << 56)) { + return 8; + } else if (value < (1ull << 63)) { + return 9; + } else { + return 10; + } + } +} + +} // namespace io +} // namespace protobuf +} // namespace google diff --git a/depends/protobuf/google/protobuf/io/coded_stream.h b/depends/protobuf/google/protobuf/io/coded_stream.h new file mode 100644 index 0000000000..1b6b4e18b4 --- /dev/null +++ b/depends/protobuf/google/protobuf/io/coded_stream.h @@ -0,0 +1,1102 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// This file contains the CodedInputStream and CodedOutputStream classes, +// which wrap a ZeroCopyInputStream or ZeroCopyOutputStream, respectively, +// and allow you to read or write individual pieces of data in various +// formats. In particular, these implement the varint encoding for +// integers, a simple variable-length encoding in which smaller numbers +// take fewer bytes. +// +// Typically these classes will only be used internally by the protocol +// buffer library in order to encode and decode protocol buffers. Clients +// of the library only need to know about this class if they wish to write +// custom message parsing or serialization procedures. +// +// CodedOutputStream example: +// // Write some data to "myfile". First we write a 4-byte "magic number" +// // to identify the file type, then write a length-delimited string. The +// // string is composed of a varint giving the length followed by the raw +// // bytes. +// int fd = open("myfile", O_WRONLY); +// ZeroCopyOutputStream* raw_output = new FileOutputStream(fd); +// CodedOutputStream* coded_output = new CodedOutputStream(raw_output); +// +// int magic_number = 1234; +// char text[] = "Hello world!"; +// coded_output->WriteLittleEndian32(magic_number); +// coded_output->WriteVarint32(strlen(text)); +// coded_output->WriteRaw(text, strlen(text)); +// +// delete coded_output; +// delete raw_output; +// close(fd); +// +// CodedInputStream example: +// // Read a file created by the above code. +// int fd = open("myfile", O_RDONLY); +// ZeroCopyInputStream* raw_input = new FileInputStream(fd); +// CodedInputStream coded_input = new CodedInputStream(raw_input); +// +// coded_input->ReadLittleEndian32(&magic_number); +// if (magic_number != 1234) { +// cerr << "File not in expected format." << endl; +// return; +// } +// +// uint32 size; +// coded_input->ReadVarint32(&size); +// +// char* text = new char[size + 1]; +// coded_input->ReadRaw(buffer, size); +// text[size] = '\0'; +// +// delete coded_input; +// delete raw_input; +// close(fd); +// +// cout << "Text is: " << text << endl; +// delete [] text; +// +// For those who are interested, varint encoding is defined as follows: +// +// The encoding operates on unsigned integers of up to 64 bits in length. +// Each byte of the encoded value has the format: +// * bits 0-6: Seven bits of the number being encoded. +// * bit 7: Zero if this is the last byte in the encoding (in which +// case all remaining bits of the number are zero) or 1 if +// more bytes follow. +// The first byte contains the least-significant 7 bits of the number, the +// second byte (if present) contains the next-least-significant 7 bits, +// and so on. So, the binary number 1011000101011 would be encoded in two +// bytes as "10101011 00101100". +// +// In theory, varint could be used to encode integers of any length. +// However, for practicality we set a limit at 64 bits. The maximum encoded +// length of a number is thus 10 bytes. + +#ifndef GOOGLE_PROTOBUF_IO_CODED_STREAM_H__ +#define GOOGLE_PROTOBUF_IO_CODED_STREAM_H__ + +#include +#ifdef _MSC_VER + #if defined(_M_IX86) && \ + !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST) + #define PROTOBUF_LITTLE_ENDIAN 1 + #endif + #if _MSC_VER >= 1300 + // If MSVC has "/RTCc" set, it will complain about truncating casts at + // runtime. This file contains some intentional truncating casts. + #pragma runtime_checks("c", off) + #endif +#else + #include // __BYTE_ORDER + #if defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN && \ + !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST) + #define PROTOBUF_LITTLE_ENDIAN 1 + #endif +#endif +#include + + +namespace google { +namespace protobuf { + +class DescriptorPool; +class MessageFactory; + +namespace io { + +// Defined in this file. +class CodedInputStream; +class CodedOutputStream; + +// Defined in other files. +class ZeroCopyInputStream; // zero_copy_stream.h +class ZeroCopyOutputStream; // zero_copy_stream.h + +// Class which reads and decodes binary data which is composed of varint- +// encoded integers and fixed-width pieces. Wraps a ZeroCopyInputStream. +// Most users will not need to deal with CodedInputStream. +// +// Most methods of CodedInputStream that return a bool return false if an +// underlying I/O error occurs or if the data is malformed. Once such a +// failure occurs, the CodedInputStream is broken and is no longer useful. +class LIBPROTOBUF_EXPORT CodedInputStream { + public: + // Create a CodedInputStream that reads from the given ZeroCopyInputStream. + explicit CodedInputStream(ZeroCopyInputStream* input); + + // Create a CodedInputStream that reads from the given flat array. This is + // faster than using an ArrayInputStream. PushLimit(size) is implied by + // this constructor. + explicit CodedInputStream(const uint8* buffer, int size); + + // Destroy the CodedInputStream and position the underlying + // ZeroCopyInputStream at the first unread byte. If an error occurred while + // reading (causing a method to return false), then the exact position of + // the input stream may be anywhere between the last value that was read + // successfully and the stream's byte limit. + ~CodedInputStream(); + + + // Skips a number of bytes. Returns false if an underlying read error + // occurs. + bool Skip(int count); + + // Sets *data to point directly at the unread part of the CodedInputStream's + // underlying buffer, and *size to the size of that buffer, but does not + // advance the stream's current position. This will always either produce + // a non-empty buffer or return false. If the caller consumes any of + // this data, it should then call Skip() to skip over the consumed bytes. + // This may be useful for implementing external fast parsing routines for + // types of data not covered by the CodedInputStream interface. + bool GetDirectBufferPointer(const void** data, int* size); + + // Like GetDirectBufferPointer, but this method is inlined, and does not + // attempt to Refresh() if the buffer is currently empty. + inline void GetDirectBufferPointerInline(const void** data, + int* size) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + + // Read raw bytes, copying them into the given buffer. + bool ReadRaw(void* buffer, int size); + + // Like ReadRaw, but reads into a string. + // + // Implementation Note: ReadString() grows the string gradually as it + // reads in the data, rather than allocating the entire requested size + // upfront. This prevents denial-of-service attacks in which a client + // could claim that a string is going to be MAX_INT bytes long in order to + // crash the server because it can't allocate this much space at once. + bool ReadString(string* buffer, int size); + // Like the above, with inlined optimizations. This should only be used + // by the protobuf implementation. + inline bool InternalReadStringInline(string* buffer, + int size) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + + + // Read a 32-bit little-endian integer. + bool ReadLittleEndian32(uint32* value); + // Read a 64-bit little-endian integer. + bool ReadLittleEndian64(uint64* value); + + // These methods read from an externally provided buffer. The caller is + // responsible for ensuring that the buffer has sufficient space. + // Read a 32-bit little-endian integer. + static const uint8* ReadLittleEndian32FromArray(const uint8* buffer, + uint32* value); + // Read a 64-bit little-endian integer. + static const uint8* ReadLittleEndian64FromArray(const uint8* buffer, + uint64* value); + + // Read an unsigned integer with Varint encoding, truncating to 32 bits. + // Reading a 32-bit value is equivalent to reading a 64-bit one and casting + // it to uint32, but may be more efficient. + bool ReadVarint32(uint32* value); + // Read an unsigned integer with Varint encoding. + bool ReadVarint64(uint64* value); + + // Read a tag. This calls ReadVarint32() and returns the result, or returns + // zero (which is not a valid tag) if ReadVarint32() fails. Also, it updates + // the last tag value, which can be checked with LastTagWas(). + // Always inline because this is only called in once place per parse loop + // but it is called for every iteration of said loop, so it should be fast. + // GCC doesn't want to inline this by default. + uint32 ReadTag() GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + + // Usually returns true if calling ReadVarint32() now would produce the given + // value. Will always return false if ReadVarint32() would not return the + // given value. If ExpectTag() returns true, it also advances past + // the varint. For best performance, use a compile-time constant as the + // parameter. + // Always inline because this collapses to a small number of instructions + // when given a constant parameter, but GCC doesn't want to inline by default. + bool ExpectTag(uint32 expected) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + + // Like above, except this reads from the specified buffer. The caller is + // responsible for ensuring that the buffer is large enough to read a varint + // of the expected size. For best performance, use a compile-time constant as + // the expected tag parameter. + // + // Returns a pointer beyond the expected tag if it was found, or NULL if it + // was not. + static const uint8* ExpectTagFromArray( + const uint8* buffer, + uint32 expected) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + + // Usually returns true if no more bytes can be read. Always returns false + // if more bytes can be read. If ExpectAtEnd() returns true, a subsequent + // call to LastTagWas() will act as if ReadTag() had been called and returned + // zero, and ConsumedEntireMessage() will return true. + bool ExpectAtEnd(); + + // If the last call to ReadTag() returned the given value, returns true. + // Otherwise, returns false; + // + // This is needed because parsers for some types of embedded messages + // (with field type TYPE_GROUP) don't actually know that they've reached the + // end of a message until they see an ENDGROUP tag, which was actually part + // of the enclosing message. The enclosing message would like to check that + // tag to make sure it had the right number, so it calls LastTagWas() on + // return from the embedded parser to check. + bool LastTagWas(uint32 expected); + + // When parsing message (but NOT a group), this method must be called + // immediately after MergeFromCodedStream() returns (if it returns true) + // to further verify that the message ended in a legitimate way. For + // example, this verifies that parsing did not end on an end-group tag. + // It also checks for some cases where, due to optimizations, + // MergeFromCodedStream() can incorrectly return true. + bool ConsumedEntireMessage(); + + // Limits ---------------------------------------------------------- + // Limits are used when parsing length-delimited embedded messages. + // After the message's length is read, PushLimit() is used to prevent + // the CodedInputStream from reading beyond that length. Once the + // embedded message has been parsed, PopLimit() is called to undo the + // limit. + + // Opaque type used with PushLimit() and PopLimit(). Do not modify + // values of this type yourself. The only reason that this isn't a + // struct with private internals is for efficiency. + typedef int Limit; + + // Places a limit on the number of bytes that the stream may read, + // starting from the current position. Once the stream hits this limit, + // it will act like the end of the input has been reached until PopLimit() + // is called. + // + // As the names imply, the stream conceptually has a stack of limits. The + // shortest limit on the stack is always enforced, even if it is not the + // top limit. + // + // The value returned by PushLimit() is opaque to the caller, and must + // be passed unchanged to the corresponding call to PopLimit(). + Limit PushLimit(int byte_limit); + + // Pops the last limit pushed by PushLimit(). The input must be the value + // returned by that call to PushLimit(). + void PopLimit(Limit limit); + + // Returns the number of bytes left until the nearest limit on the + // stack is hit, or -1 if no limits are in place. + int BytesUntilLimit(); + + // Total Bytes Limit ----------------------------------------------- + // To prevent malicious users from sending excessively large messages + // and causing integer overflows or memory exhaustion, CodedInputStream + // imposes a hard limit on the total number of bytes it will read. + + // Sets the maximum number of bytes that this CodedInputStream will read + // before refusing to continue. To prevent integer overflows in the + // protocol buffers implementation, as well as to prevent servers from + // allocating enormous amounts of memory to hold parsed messages, the + // maximum message length should be limited to the shortest length that + // will not harm usability. The theoretical shortest message that could + // cause integer overflows is 512MB. The default limit is 64MB. Apps + // should set shorter limits if possible. If warning_threshold is not -1, + // a warning will be printed to stderr after warning_threshold bytes are + // read. An error will always be printed to stderr if the limit is + // reached. + // + // This is unrelated to PushLimit()/PopLimit(). + // + // Hint: If you are reading this because your program is printing a + // warning about dangerously large protocol messages, you may be + // confused about what to do next. The best option is to change your + // design such that excessively large messages are not necessary. + // For example, try to design file formats to consist of many small + // messages rather than a single large one. If this is infeasible, + // you will need to increase the limit. Chances are, though, that + // your code never constructs a CodedInputStream on which the limit + // can be set. You probably parse messages by calling things like + // Message::ParseFromString(). In this case, you will need to change + // your code to instead construct some sort of ZeroCopyInputStream + // (e.g. an ArrayInputStream), construct a CodedInputStream around + // that, then call Message::ParseFromCodedStream() instead. Then + // you can adjust the limit. Yes, it's more work, but you're doing + // something unusual. + void SetTotalBytesLimit(int total_bytes_limit, int warning_threshold); + + // Recursion Limit ------------------------------------------------- + // To prevent corrupt or malicious messages from causing stack overflows, + // we must keep track of the depth of recursion when parsing embedded + // messages and groups. CodedInputStream keeps track of this because it + // is the only object that is passed down the stack during parsing. + + // Sets the maximum recursion depth. The default is 64. + void SetRecursionLimit(int limit); + + // Increments the current recursion depth. Returns true if the depth is + // under the limit, false if it has gone over. + bool IncrementRecursionDepth(); + + // Decrements the recursion depth. + void DecrementRecursionDepth(); + + // Extension Registry ---------------------------------------------- + // ADVANCED USAGE: 99.9% of people can ignore this section. + // + // By default, when parsing extensions, the parser looks for extension + // definitions in the pool which owns the outer message's Descriptor. + // However, you may call SetExtensionRegistry() to provide an alternative + // pool instead. This makes it possible, for example, to parse a message + // using a generated class, but represent some extensions using + // DynamicMessage. + + // Set the pool used to look up extensions. Most users do not need to call + // this as the correct pool will be chosen automatically. + // + // WARNING: It is very easy to misuse this. Carefully read the requirements + // below. Do not use this unless you are sure you need it. Almost no one + // does. + // + // Let's say you are parsing a message into message object m, and you want + // to take advantage of SetExtensionRegistry(). You must follow these + // requirements: + // + // The given DescriptorPool must contain m->GetDescriptor(). It is not + // sufficient for it to simply contain a descriptor that has the same name + // and content -- it must be the *exact object*. In other words: + // assert(pool->FindMessageTypeByName(m->GetDescriptor()->full_name()) == + // m->GetDescriptor()); + // There are two ways to satisfy this requirement: + // 1) Use m->GetDescriptor()->pool() as the pool. This is generally useless + // because this is the pool that would be used anyway if you didn't call + // SetExtensionRegistry() at all. + // 2) Use a DescriptorPool which has m->GetDescriptor()->pool() as an + // "underlay". Read the documentation for DescriptorPool for more + // information about underlays. + // + // You must also provide a MessageFactory. This factory will be used to + // construct Message objects representing extensions. The factory's + // GetPrototype() MUST return non-NULL for any Descriptor which can be found + // through the provided pool. + // + // If the provided factory might return instances of protocol-compiler- + // generated (i.e. compiled-in) types, or if the outer message object m is + // a generated type, then the given factory MUST have this property: If + // GetPrototype() is given a Descriptor which resides in + // DescriptorPool::generated_pool(), the factory MUST return the same + // prototype which MessageFactory::generated_factory() would return. That + // is, given a descriptor for a generated type, the factory must return an + // instance of the generated class (NOT DynamicMessage). However, when + // given a descriptor for a type that is NOT in generated_pool, the factory + // is free to return any implementation. + // + // The reason for this requirement is that generated sub-objects may be + // accessed via the standard (non-reflection) extension accessor methods, + // and these methods will down-cast the object to the generated class type. + // If the object is not actually of that type, the results would be undefined. + // On the other hand, if an extension is not compiled in, then there is no + // way the code could end up accessing it via the standard accessors -- the + // only way to access the extension is via reflection. When using reflection, + // DynamicMessage and generated messages are indistinguishable, so it's fine + // if these objects are represented using DynamicMessage. + // + // Using DynamicMessageFactory on which you have called + // SetDelegateToGeneratedFactory(true) should be sufficient to satisfy the + // above requirement. + // + // If either pool or factory is NULL, both must be NULL. + // + // Note that this feature is ignored when parsing "lite" messages as they do + // not have descriptors. + void SetExtensionRegistry(DescriptorPool* pool, MessageFactory* factory); + + // Get the DescriptorPool set via SetExtensionRegistry(), or NULL if no pool + // has been provided. + const DescriptorPool* GetExtensionPool(); + + // Get the MessageFactory set via SetExtensionRegistry(), or NULL if no + // factory has been provided. + MessageFactory* GetExtensionFactory(); + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CodedInputStream); + + ZeroCopyInputStream* input_; + const uint8* buffer_; + const uint8* buffer_end_; // pointer to the end of the buffer. + int total_bytes_read_; // total bytes read from input_, including + // the current buffer + + // If total_bytes_read_ surpasses INT_MAX, we record the extra bytes here + // so that we can BackUp() on destruction. + int overflow_bytes_; + + // LastTagWas() stuff. + uint32 last_tag_; // result of last ReadTag(). + + // This is set true by ReadTag{Fallback/Slow}() if it is called when exactly + // at EOF, or by ExpectAtEnd() when it returns true. This happens when we + // reach the end of a message and attempt to read another tag. + bool legitimate_message_end_; + + // See EnableAliasing(). + bool aliasing_enabled_; + + // Limits + Limit current_limit_; // if position = -1, no limit is applied + + // For simplicity, if the current buffer crosses a limit (either a normal + // limit created by PushLimit() or the total bytes limit), buffer_size_ + // only tracks the number of bytes before that limit. This field + // contains the number of bytes after it. Note that this implies that if + // buffer_size_ == 0 and buffer_size_after_limit_ > 0, we know we've + // hit a limit. However, if both are zero, it doesn't necessarily mean + // we aren't at a limit -- the buffer may have ended exactly at the limit. + int buffer_size_after_limit_; + + // Maximum number of bytes to read, period. This is unrelated to + // current_limit_. Set using SetTotalBytesLimit(). + int total_bytes_limit_; + int total_bytes_warning_threshold_; + + // Current recursion depth, controlled by IncrementRecursionDepth() and + // DecrementRecursionDepth(). + int recursion_depth_; + // Recursion depth limit, set by SetRecursionLimit(). + int recursion_limit_; + + // See SetExtensionRegistry(). + const DescriptorPool* extension_pool_; + MessageFactory* extension_factory_; + + // Private member functions. + + // Advance the buffer by a given number of bytes. + void Advance(int amount); + + // Back up input_ to the current buffer position. + void BackUpInputToCurrentPosition(); + + // Recomputes the value of buffer_size_after_limit_. Must be called after + // current_limit_ or total_bytes_limit_ changes. + void RecomputeBufferLimits(); + + // Writes an error message saying that we hit total_bytes_limit_. + void PrintTotalBytesLimitError(); + + // Called when the buffer runs out to request more data. Implies an + // Advance(BufferSize()). + bool Refresh(); + + // When parsing varints, we optimize for the common case of small values, and + // then optimize for the case when the varint fits within the current buffer + // piece. The Fallback method is used when we can't use the one-byte + // optimization. The Slow method is yet another fallback when the buffer is + // not large enough. Making the slow path out-of-line speeds up the common + // case by 10-15%. The slow path is fairly uncommon: it only triggers when a + // message crosses multiple buffers. + bool ReadVarint32Fallback(uint32* value); + bool ReadVarint64Fallback(uint64* value); + bool ReadVarint32Slow(uint32* value); + bool ReadVarint64Slow(uint64* value); + bool ReadLittleEndian32Fallback(uint32* value); + bool ReadLittleEndian64Fallback(uint64* value); + // Fallback/slow methods for reading tags. These do not update last_tag_, + // but will set legitimate_message_end_ if we are at the end of the input + // stream. + uint32 ReadTagFallback(); + uint32 ReadTagSlow(); + bool ReadStringFallback(string* buffer, int size); + + // Return the size of the buffer. + int BufferSize() const; + + static const int kDefaultTotalBytesLimit = 64 << 20; // 64MB + + static const int kDefaultTotalBytesWarningThreshold = 32 << 20; // 32MB + static const int kDefaultRecursionLimit = 64; +}; + +// Class which encodes and writes binary data which is composed of varint- +// encoded integers and fixed-width pieces. Wraps a ZeroCopyOutputStream. +// Most users will not need to deal with CodedOutputStream. +// +// Most methods of CodedOutputStream which return a bool return false if an +// underlying I/O error occurs. Once such a failure occurs, the +// CodedOutputStream is broken and is no longer useful. The Write* methods do +// not return the stream status, but will invalidate the stream if an error +// occurs. The client can probe HadError() to determine the status. +// +// Note that every method of CodedOutputStream which writes some data has +// a corresponding static "ToArray" version. These versions write directly +// to the provided buffer, returning a pointer past the last written byte. +// They require that the buffer has sufficient capacity for the encoded data. +// This allows an optimization where we check if an output stream has enough +// space for an entire message before we start writing and, if there is, we +// call only the ToArray methods to avoid doing bound checks for each +// individual value. +// i.e., in the example above: +// +// CodedOutputStream coded_output = new CodedOutputStream(raw_output); +// int magic_number = 1234; +// char text[] = "Hello world!"; +// +// int coded_size = sizeof(magic_number) + +// CodedOutputStream::VarintSize32(strlen(text)) + +// strlen(text); +// +// uint8* buffer = +// coded_output->GetDirectBufferForNBytesAndAdvance(coded_size); +// if (buffer != NULL) { +// // The output stream has enough space in the buffer: write directly to +// // the array. +// buffer = CodedOutputStream::WriteLittleEndian32ToArray(magic_number, +// buffer); +// buffer = CodedOutputStream::WriteVarint32ToArray(strlen(text), buffer); +// buffer = CodedOutputStream::WriteRawToArray(text, strlen(text), buffer); +// } else { +// // Make bound-checked writes, which will ask the underlying stream for +// // more space as needed. +// coded_output->WriteLittleEndian32(magic_number); +// coded_output->WriteVarint32(strlen(text)); +// coded_output->WriteRaw(text, strlen(text)); +// } +// +// delete coded_output; +class LIBPROTOBUF_EXPORT CodedOutputStream { + public: + // Create an CodedOutputStream that writes to the given ZeroCopyOutputStream. + explicit CodedOutputStream(ZeroCopyOutputStream* output); + + // Destroy the CodedOutputStream and position the underlying + // ZeroCopyOutputStream immediately after the last byte written. + ~CodedOutputStream(); + + // Skips a number of bytes, leaving the bytes unmodified in the underlying + // buffer. Returns false if an underlying write error occurs. This is + // mainly useful with GetDirectBufferPointer(). + bool Skip(int count); + + // Sets *data to point directly at the unwritten part of the + // CodedOutputStream's underlying buffer, and *size to the size of that + // buffer, but does not advance the stream's current position. This will + // always either produce a non-empty buffer or return false. If the caller + // writes any data to this buffer, it should then call Skip() to skip over + // the consumed bytes. This may be useful for implementing external fast + // serialization routines for types of data not covered by the + // CodedOutputStream interface. + bool GetDirectBufferPointer(void** data, int* size); + + // If there are at least "size" bytes available in the current buffer, + // returns a pointer directly into the buffer and advances over these bytes. + // The caller may then write directly into this buffer (e.g. using the + // *ToArray static methods) rather than go through CodedOutputStream. If + // there are not enough bytes available, returns NULL. The return pointer is + // invalidated as soon as any other non-const method of CodedOutputStream + // is called. + inline uint8* GetDirectBufferForNBytesAndAdvance(int size); + + // Write raw bytes, copying them from the given buffer. + void WriteRaw(const void* buffer, int size); + // Like WriteRaw() but writing directly to the target array. + // This is _not_ inlined, as the compiler often optimizes memcpy into inline + // copy loops. Since this gets called by every field with string or bytes + // type, inlining may lead to a significant amount of code bloat, with only a + // minor performance gain. + static uint8* WriteRawToArray(const void* buffer, int size, uint8* target); + + // Equivalent to WriteRaw(str.data(), str.size()). + void WriteString(const string& str); + // Like WriteString() but writing directly to the target array. + static uint8* WriteStringToArray(const string& str, uint8* target); + + + // Write a 32-bit little-endian integer. + void WriteLittleEndian32(uint32 value); + // Like WriteLittleEndian32() but writing directly to the target array. + static uint8* WriteLittleEndian32ToArray(uint32 value, uint8* target); + // Write a 64-bit little-endian integer. + void WriteLittleEndian64(uint64 value); + // Like WriteLittleEndian64() but writing directly to the target array. + static uint8* WriteLittleEndian64ToArray(uint64 value, uint8* target); + + // Write an unsigned integer with Varint encoding. Writing a 32-bit value + // is equivalent to casting it to uint64 and writing it as a 64-bit value, + // but may be more efficient. + void WriteVarint32(uint32 value); + // Like WriteVarint32() but writing directly to the target array. + static uint8* WriteVarint32ToArray(uint32 value, uint8* target); + // Write an unsigned integer with Varint encoding. + void WriteVarint64(uint64 value); + // Like WriteVarint64() but writing directly to the target array. + static uint8* WriteVarint64ToArray(uint64 value, uint8* target); + + // Equivalent to WriteVarint32() except when the value is negative, + // in which case it must be sign-extended to a full 10 bytes. + void WriteVarint32SignExtended(int32 value); + // Like WriteVarint32SignExtended() but writing directly to the target array. + static uint8* WriteVarint32SignExtendedToArray(int32 value, uint8* target); + + // This is identical to WriteVarint32(), but optimized for writing tags. + // In particular, if the input is a compile-time constant, this method + // compiles down to a couple instructions. + // Always inline because otherwise the aformentioned optimization can't work, + // but GCC by default doesn't want to inline this. + void WriteTag(uint32 value); + // Like WriteTag() but writing directly to the target array. + static uint8* WriteTagToArray( + uint32 value, uint8* target) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + + // Returns the number of bytes needed to encode the given value as a varint. + static int VarintSize32(uint32 value); + // Returns the number of bytes needed to encode the given value as a varint. + static int VarintSize64(uint64 value); + + // If negative, 10 bytes. Otheriwse, same as VarintSize32(). + static int VarintSize32SignExtended(int32 value); + + // Returns the total number of bytes written since this object was created. + inline int ByteCount() const; + + // Returns true if there was an underlying I/O error since this object was + // created. + bool HadError() const { return had_error_; } + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CodedOutputStream); + + ZeroCopyOutputStream* output_; + uint8* buffer_; + int buffer_size_; + int total_bytes_; // Sum of sizes of all buffers seen so far. + bool had_error_; // Whether an error occurred during output. + + // Advance the buffer by a given number of bytes. + void Advance(int amount); + + // Called when the buffer runs out to request more data. Implies an + // Advance(buffer_size_). + bool Refresh(); + + static uint8* WriteVarint32FallbackToArray(uint32 value, uint8* target); + + // Always-inlined versions of WriteVarint* functions so that code can be + // reused, while still controlling size. For instance, WriteVarint32ToArray() + // should not directly call this: since it is inlined itself, doing so + // would greatly increase the size of generated code. Instead, it should call + // WriteVarint32FallbackToArray. Meanwhile, WriteVarint32() is already + // out-of-line, so it should just invoke this directly to avoid any extra + // function call overhead. + static uint8* WriteVarint32FallbackToArrayInline( + uint32 value, uint8* target) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + static uint8* WriteVarint64ToArrayInline( + uint64 value, uint8* target) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + + static int VarintSize32Fallback(uint32 value); +}; + +// inline methods ==================================================== +// The vast majority of varints are only one byte. These inline +// methods optimize for that case. + +inline bool CodedInputStream::ReadVarint32(uint32* value) { + if (GOOGLE_PREDICT_TRUE(buffer_ < buffer_end_) && *buffer_ < 0x80) { + *value = *buffer_; + Advance(1); + return true; + } else { + return ReadVarint32Fallback(value); + } +} + +inline bool CodedInputStream::ReadVarint64(uint64* value) { + if (GOOGLE_PREDICT_TRUE(buffer_ < buffer_end_) && *buffer_ < 0x80) { + *value = *buffer_; + Advance(1); + return true; + } else { + return ReadVarint64Fallback(value); + } +} + +// static +inline const uint8* CodedInputStream::ReadLittleEndian32FromArray( + const uint8* buffer, + uint32* value) { +#if defined(PROTOBUF_LITTLE_ENDIAN) + memcpy(value, buffer, sizeof(*value)); + return buffer + sizeof(*value); +#else + *value = (static_cast(buffer[0]) ) | + (static_cast(buffer[1]) << 8) | + (static_cast(buffer[2]) << 16) | + (static_cast(buffer[3]) << 24); + return buffer + sizeof(*value); +#endif +} +// static +inline const uint8* CodedInputStream::ReadLittleEndian64FromArray( + const uint8* buffer, + uint64* value) { +#if defined(PROTOBUF_LITTLE_ENDIAN) + memcpy(value, buffer, sizeof(*value)); + return buffer + sizeof(*value); +#else + uint32 part0 = (static_cast(buffer[0]) ) | + (static_cast(buffer[1]) << 8) | + (static_cast(buffer[2]) << 16) | + (static_cast(buffer[3]) << 24); + uint32 part1 = (static_cast(buffer[4]) ) | + (static_cast(buffer[5]) << 8) | + (static_cast(buffer[6]) << 16) | + (static_cast(buffer[7]) << 24); + *value = static_cast(part0) | + (static_cast(part1) << 32); + return buffer + sizeof(*value); +#endif +} + +inline bool CodedInputStream::ReadLittleEndian32(uint32* value) { +#if defined(PROTOBUF_LITTLE_ENDIAN) + if (GOOGLE_PREDICT_TRUE(BufferSize() >= static_cast(sizeof(*value)))) { + memcpy(value, buffer_, sizeof(*value)); + Advance(sizeof(*value)); + return true; + } else { + return ReadLittleEndian32Fallback(value); + } +#else + return ReadLittleEndian32Fallback(value); +#endif +} + +inline bool CodedInputStream::ReadLittleEndian64(uint64* value) { +#if defined(PROTOBUF_LITTLE_ENDIAN) + if (GOOGLE_PREDICT_TRUE(BufferSize() >= static_cast(sizeof(*value)))) { + memcpy(value, buffer_, sizeof(*value)); + Advance(sizeof(*value)); + return true; + } else { + return ReadLittleEndian64Fallback(value); + } +#else + return ReadLittleEndian64Fallback(value); +#endif +} + +inline uint32 CodedInputStream::ReadTag() { + if (GOOGLE_PREDICT_TRUE(buffer_ < buffer_end_) && buffer_[0] < 0x80) { + last_tag_ = buffer_[0]; + Advance(1); + return last_tag_; + } else { + last_tag_ = ReadTagFallback(); + return last_tag_; + } +} + +inline bool CodedInputStream::LastTagWas(uint32 expected) { + return last_tag_ == expected; +} + +inline bool CodedInputStream::ConsumedEntireMessage() { + return legitimate_message_end_; +} + +inline bool CodedInputStream::ExpectTag(uint32 expected) { + if (expected < (1 << 7)) { + if (GOOGLE_PREDICT_TRUE(buffer_ < buffer_end_) && buffer_[0] == expected) { + Advance(1); + return true; + } else { + return false; + } + } else if (expected < (1 << 14)) { + if (GOOGLE_PREDICT_TRUE(BufferSize() >= 2) && + buffer_[0] == static_cast(expected | 0x80) && + buffer_[1] == static_cast(expected >> 7)) { + Advance(2); + return true; + } else { + return false; + } + } else { + // Don't bother optimizing for larger values. + return false; + } +} + +inline const uint8* CodedInputStream::ExpectTagFromArray( + const uint8* buffer, uint32 expected) { + if (expected < (1 << 7)) { + if (buffer[0] == expected) { + return buffer + 1; + } + } else if (expected < (1 << 14)) { + if (buffer[0] == static_cast(expected | 0x80) && + buffer[1] == static_cast(expected >> 7)) { + return buffer + 2; + } + } + return NULL; +} + +inline void CodedInputStream::GetDirectBufferPointerInline(const void** data, + int* size) { + *data = buffer_; + *size = buffer_end_ - buffer_; +} + +inline bool CodedInputStream::ExpectAtEnd() { + // If we are at a limit we know no more bytes can be read. Otherwise, it's + // hard to say without calling Refresh(), and we'd rather not do that. + + if (buffer_ == buffer_end_ && buffer_size_after_limit_ != 0) { + last_tag_ = 0; // Pretend we called ReadTag()... + legitimate_message_end_ = true; // ... and it hit EOF. + return true; + } else { + return false; + } +} + +inline uint8* CodedOutputStream::GetDirectBufferForNBytesAndAdvance(int size) { + if (buffer_size_ < size) { + return NULL; + } else { + uint8* result = buffer_; + Advance(size); + return result; + } +} + +inline uint8* CodedOutputStream::WriteVarint32ToArray(uint32 value, + uint8* target) { + if (value < 0x80) { + *target = value; + return target + 1; + } else { + return WriteVarint32FallbackToArray(value, target); + } +} + +inline void CodedOutputStream::WriteVarint32SignExtended(int32 value) { + if (value < 0) { + WriteVarint64(static_cast(value)); + } else { + WriteVarint32(static_cast(value)); + } +} + +inline uint8* CodedOutputStream::WriteVarint32SignExtendedToArray( + int32 value, uint8* target) { + if (value < 0) { + return WriteVarint64ToArray(static_cast(value), target); + } else { + return WriteVarint32ToArray(static_cast(value), target); + } +} + +inline uint8* CodedOutputStream::WriteLittleEndian32ToArray(uint32 value, + uint8* target) { +#if defined(PROTOBUF_LITTLE_ENDIAN) + memcpy(target, &value, sizeof(value)); +#else + target[0] = static_cast(value); + target[1] = static_cast(value >> 8); + target[2] = static_cast(value >> 16); + target[3] = static_cast(value >> 24); +#endif + return target + sizeof(value); +} + +inline uint8* CodedOutputStream::WriteLittleEndian64ToArray(uint64 value, + uint8* target) { +#if defined(PROTOBUF_LITTLE_ENDIAN) + memcpy(target, &value, sizeof(value)); +#else + uint32 part0 = static_cast(value); + uint32 part1 = static_cast(value >> 32); + + target[0] = static_cast(part0); + target[1] = static_cast(part0 >> 8); + target[2] = static_cast(part0 >> 16); + target[3] = static_cast(part0 >> 24); + target[4] = static_cast(part1); + target[5] = static_cast(part1 >> 8); + target[6] = static_cast(part1 >> 16); + target[7] = static_cast(part1 >> 24); +#endif + return target + sizeof(value); +} + +inline void CodedOutputStream::WriteTag(uint32 value) { + WriteVarint32(value); +} + +inline uint8* CodedOutputStream::WriteTagToArray( + uint32 value, uint8* target) { + if (value < (1 << 7)) { + target[0] = value; + return target + 1; + } else if (value < (1 << 14)) { + target[0] = static_cast(value | 0x80); + target[1] = static_cast(value >> 7); + return target + 2; + } else { + return WriteVarint32FallbackToArray(value, target); + } +} + +inline int CodedOutputStream::VarintSize32(uint32 value) { + if (value < (1 << 7)) { + return 1; + } else { + return VarintSize32Fallback(value); + } +} + +inline int CodedOutputStream::VarintSize32SignExtended(int32 value) { + if (value < 0) { + return 10; // TODO(kenton): Make this a symbolic constant. + } else { + return VarintSize32(static_cast(value)); + } +} + +inline void CodedOutputStream::WriteString(const string& str) { + WriteRaw(str.data(), static_cast(str.size())); +} + +inline uint8* CodedOutputStream::WriteStringToArray( + const string& str, uint8* target) { + return WriteRawToArray(str.data(), static_cast(str.size()), target); +} + +inline int CodedOutputStream::ByteCount() const { + return total_bytes_ - buffer_size_; +} + +inline void CodedInputStream::Advance(int amount) { + buffer_ += amount; +} + +inline void CodedOutputStream::Advance(int amount) { + buffer_ += amount; + buffer_size_ -= amount; +} + +inline void CodedInputStream::SetRecursionLimit(int limit) { + recursion_limit_ = limit; +} + +inline bool CodedInputStream::IncrementRecursionDepth() { + ++recursion_depth_; + return recursion_depth_ <= recursion_limit_; +} + +inline void CodedInputStream::DecrementRecursionDepth() { + if (recursion_depth_ > 0) --recursion_depth_; +} + +inline void CodedInputStream::SetExtensionRegistry(DescriptorPool* pool, + MessageFactory* factory) { + extension_pool_ = pool; + extension_factory_ = factory; +} + +inline const DescriptorPool* CodedInputStream::GetExtensionPool() { + return extension_pool_; +} + +inline MessageFactory* CodedInputStream::GetExtensionFactory() { + return extension_factory_; +} + +inline int CodedInputStream::BufferSize() const { + return buffer_end_ - buffer_; +} + +inline CodedInputStream::CodedInputStream(ZeroCopyInputStream* input) + : input_(input), + buffer_(NULL), + buffer_end_(NULL), + total_bytes_read_(0), + overflow_bytes_(0), + last_tag_(0), + legitimate_message_end_(false), + aliasing_enabled_(false), + current_limit_(kint32max), + buffer_size_after_limit_(0), + total_bytes_limit_(kDefaultTotalBytesLimit), + total_bytes_warning_threshold_(kDefaultTotalBytesWarningThreshold), + recursion_depth_(0), + recursion_limit_(kDefaultRecursionLimit), + extension_pool_(NULL), + extension_factory_(NULL) { + // Eagerly Refresh() so buffer space is immediately available. + Refresh(); +} + +inline CodedInputStream::CodedInputStream(const uint8* buffer, int size) + : input_(NULL), + buffer_(buffer), + buffer_end_(buffer + size), + total_bytes_read_(size), + overflow_bytes_(0), + last_tag_(0), + legitimate_message_end_(false), + aliasing_enabled_(false), + current_limit_(size), + buffer_size_after_limit_(0), + total_bytes_limit_(kDefaultTotalBytesLimit), + total_bytes_warning_threshold_(kDefaultTotalBytesWarningThreshold), + recursion_depth_(0), + recursion_limit_(kDefaultRecursionLimit), + extension_pool_(NULL), + extension_factory_(NULL) { + // Note that setting current_limit_ == size is important to prevent some + // code paths from trying to access input_ and segfaulting. +} + +inline CodedInputStream::~CodedInputStream() { + if (input_ != NULL) { + BackUpInputToCurrentPosition(); + } +} + +} // namespace io +} // namespace protobuf + + +#if defined(_MSC_VER) && _MSC_VER >= 1300 + #pragma runtime_checks("c", restore) +#endif // _MSC_VER + +} // namespace google +#endif // GOOGLE_PROTOBUF_IO_CODED_STREAM_H__ diff --git a/depends/protobuf/google/protobuf/io/coded_stream_inl.h b/depends/protobuf/google/protobuf/io/coded_stream_inl.h new file mode 100644 index 0000000000..e9799d4772 --- /dev/null +++ b/depends/protobuf/google/protobuf/io/coded_stream_inl.h @@ -0,0 +1,64 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: jasonh@google.com (Jason Hsueh) +// +// Implements methods of coded_stream.h that need to be inlined for performance +// reasons, but should not be defined in a public header. + +#ifndef GOOGLE_PROTOBUF_IO_CODED_STREAM_INL_H__ +#define GOOGLE_PROTOBUF_IO_CODED_STREAM_INL_H__ + +#include +#include +#include + +namespace google { +namespace protobuf { +namespace io { + +inline bool CodedInputStream::InternalReadStringInline(string* buffer, + int size) { + if (size < 0) return false; // security: size is often user-supplied + + if (BufferSize() >= size) { + STLStringResizeUninitialized(buffer, size); + memcpy(string_as_array(buffer), buffer_, size); + Advance(size); + return true; + } + + return ReadStringFallback(buffer, size); +} + +} // namespace io +} // namespace protobuf +} // namespace google +#endif // GOOGLE_PROTOBUF_IO_CODED_STREAM_INL_H__ diff --git a/depends/protobuf/google/protobuf/io/gzip_stream.cc b/depends/protobuf/google/protobuf/io/gzip_stream.cc new file mode 100644 index 0000000000..0f1ff872aa --- /dev/null +++ b/depends/protobuf/google/protobuf/io/gzip_stream.cc @@ -0,0 +1,335 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: brianolson@google.com (Brian Olson) +// +// This file contains the implementation of classes GzipInputStream and +// GzipOutputStream. + +#include "config.h" + +#if HAVE_ZLIB +#include + +#include + +namespace google { +namespace protobuf { +namespace io { + +static const int kDefaultBufferSize = 65536; + +GzipInputStream::GzipInputStream( + ZeroCopyInputStream* sub_stream, Format format, int buffer_size) + : format_(format), sub_stream_(sub_stream), zerror_(Z_OK) { + zcontext_.zalloc = Z_NULL; + zcontext_.zfree = Z_NULL; + zcontext_.opaque = Z_NULL; + zcontext_.total_out = 0; + zcontext_.next_in = NULL; + zcontext_.avail_in = 0; + zcontext_.total_in = 0; + zcontext_.msg = NULL; + if (buffer_size == -1) { + output_buffer_length_ = kDefaultBufferSize; + } else { + output_buffer_length_ = buffer_size; + } + output_buffer_ = operator new(output_buffer_length_); + GOOGLE_CHECK(output_buffer_ != NULL); + zcontext_.next_out = static_cast(output_buffer_); + zcontext_.avail_out = output_buffer_length_; + output_position_ = output_buffer_; +} +GzipInputStream::~GzipInputStream() { + operator delete(output_buffer_); + zerror_ = inflateEnd(&zcontext_); +} + +static inline int internalInflateInit2( + z_stream* zcontext, GzipInputStream::Format format) { + int windowBitsFormat = 0; + switch (format) { + case GzipInputStream::GZIP: windowBitsFormat = 16; break; + case GzipInputStream::AUTO: windowBitsFormat = 32; break; + case GzipInputStream::ZLIB: windowBitsFormat = 0; break; + } + return inflateInit2(zcontext, /* windowBits */15 | windowBitsFormat); +} + +int GzipInputStream::Inflate(int flush) { + if ((zerror_ == Z_OK) && (zcontext_.avail_out == 0)) { + // previous inflate filled output buffer. don't change input params yet. + } else if (zcontext_.avail_in == 0) { + const void* in; + int in_size; + bool first = zcontext_.next_in == NULL; + bool ok = sub_stream_->Next(&in, &in_size); + if (!ok) { + zcontext_.next_out = NULL; + zcontext_.avail_out = 0; + return Z_STREAM_END; + } + zcontext_.next_in = static_cast(const_cast(in)); + zcontext_.avail_in = in_size; + if (first) { + int error = internalInflateInit2(&zcontext_, format_); + if (error != Z_OK) { + return error; + } + } + } + zcontext_.next_out = static_cast(output_buffer_); + zcontext_.avail_out = output_buffer_length_; + output_position_ = output_buffer_; + int error = inflate(&zcontext_, flush); + return error; +} + +void GzipInputStream::DoNextOutput(const void** data, int* size) { + *data = output_position_; + *size = ((uintptr_t)zcontext_.next_out) - ((uintptr_t)output_position_); + output_position_ = zcontext_.next_out; +} + +// implements ZeroCopyInputStream ---------------------------------- +bool GzipInputStream::Next(const void** data, int* size) { + bool ok = (zerror_ == Z_OK) || (zerror_ == Z_STREAM_END) + || (zerror_ == Z_BUF_ERROR); + if ((!ok) || (zcontext_.next_out == NULL)) { + return false; + } + if (zcontext_.next_out != output_position_) { + DoNextOutput(data, size); + return true; + } + if (zerror_ == Z_STREAM_END) { + if (zcontext_.next_out != NULL) { + // sub_stream_ may have concatenated streams to follow + zerror_ = inflateEnd(&zcontext_); + if (zerror_ != Z_OK) { + return false; + } + zerror_ = internalInflateInit2(&zcontext_, format_); + if (zerror_ != Z_OK) { + return false; + } + } else { + *data = NULL; + *size = 0; + return false; + } + } + zerror_ = Inflate(Z_NO_FLUSH); + if ((zerror_ == Z_STREAM_END) && (zcontext_.next_out == NULL)) { + // The underlying stream's Next returned false inside Inflate. + return false; + } + ok = (zerror_ == Z_OK) || (zerror_ == Z_STREAM_END) + || (zerror_ == Z_BUF_ERROR); + if (!ok) { + return false; + } + DoNextOutput(data, size); + return true; +} +void GzipInputStream::BackUp(int count) { + output_position_ = reinterpret_cast( + reinterpret_cast(output_position_) - count); +} +bool GzipInputStream::Skip(int count) { + const void* data; + int size; + bool ok = Next(&data, &size); + while (ok && (size < count)) { + count -= size; + ok = Next(&data, &size); + } + if (size > count) { + BackUp(size - count); + } + return ok; +} +int64 GzipInputStream::ByteCount() const { + return zcontext_.total_out + + (((uintptr_t)zcontext_.next_out) - ((uintptr_t)output_position_)); +} + +// ========================================================================= + +GzipOutputStream::Options::Options() + : format(GZIP), + buffer_size(kDefaultBufferSize), + compression_level(Z_DEFAULT_COMPRESSION), + compression_strategy(Z_DEFAULT_STRATEGY) {} + +GzipOutputStream::GzipOutputStream(ZeroCopyOutputStream* sub_stream) { + Init(sub_stream, Options()); +} + +GzipOutputStream::GzipOutputStream(ZeroCopyOutputStream* sub_stream, + const Options& options) { + Init(sub_stream, options); +} + +GzipOutputStream::GzipOutputStream( + ZeroCopyOutputStream* sub_stream, Format format, int buffer_size) { + Options options; + options.format = format; + if (buffer_size != -1) { + options.buffer_size = buffer_size; + } + Init(sub_stream, options); +} + +void GzipOutputStream::Init(ZeroCopyOutputStream* sub_stream, + const Options& options) { + sub_stream_ = sub_stream; + sub_data_ = NULL; + sub_data_size_ = 0; + + input_buffer_length_ = options.buffer_size; + input_buffer_ = operator new(input_buffer_length_); + GOOGLE_CHECK(input_buffer_ != NULL); + + zcontext_.zalloc = Z_NULL; + zcontext_.zfree = Z_NULL; + zcontext_.opaque = Z_NULL; + zcontext_.next_out = NULL; + zcontext_.avail_out = 0; + zcontext_.total_out = 0; + zcontext_.next_in = NULL; + zcontext_.avail_in = 0; + zcontext_.total_in = 0; + zcontext_.msg = NULL; + // default to GZIP format + int windowBitsFormat = 16; + if (options.format == ZLIB) { + windowBitsFormat = 0; + } + zerror_ = deflateInit2( + &zcontext_, + options.compression_level, + Z_DEFLATED, + /* windowBits */15 | windowBitsFormat, + /* memLevel (default) */8, + options.compression_strategy); +} + +GzipOutputStream::~GzipOutputStream() { + Close(); + if (input_buffer_ != NULL) { + operator delete(input_buffer_); + } +} + +// private +int GzipOutputStream::Deflate(int flush) { + int error = Z_OK; + do { + if ((sub_data_ == NULL) || (zcontext_.avail_out == 0)) { + bool ok = sub_stream_->Next(&sub_data_, &sub_data_size_); + if (!ok) { + sub_data_ = NULL; + sub_data_size_ = 0; + return Z_BUF_ERROR; + } + GOOGLE_CHECK_GT(sub_data_size_, 0); + zcontext_.next_out = static_cast(sub_data_); + zcontext_.avail_out = sub_data_size_; + } + error = deflate(&zcontext_, flush); + } while (error == Z_OK && zcontext_.avail_out == 0); + if ((flush == Z_FULL_FLUSH) || (flush == Z_FINISH)) { + // Notify lower layer of data. + sub_stream_->BackUp(zcontext_.avail_out); + // We don't own the buffer anymore. + sub_data_ = NULL; + sub_data_size_ = 0; + } + return error; +} + +// implements ZeroCopyOutputStream --------------------------------- +bool GzipOutputStream::Next(void** data, int* size) { + if ((zerror_ != Z_OK) && (zerror_ != Z_BUF_ERROR)) { + return false; + } + if (zcontext_.avail_in != 0) { + zerror_ = Deflate(Z_NO_FLUSH); + if (zerror_ != Z_OK) { + return false; + } + } + if (zcontext_.avail_in == 0) { + // all input was consumed. reset the buffer. + zcontext_.next_in = static_cast(input_buffer_); + zcontext_.avail_in = input_buffer_length_; + *data = input_buffer_; + *size = input_buffer_length_; + } else { + // The loop in Deflate should consume all avail_in + GOOGLE_LOG(DFATAL) << "Deflate left bytes unconsumed"; + } + return true; +} +void GzipOutputStream::BackUp(int count) { + GOOGLE_CHECK_GE(zcontext_.avail_in, count); + zcontext_.avail_in -= count; +} +int64 GzipOutputStream::ByteCount() const { + return zcontext_.total_in + zcontext_.avail_in; +} + +bool GzipOutputStream::Flush() { + do { + zerror_ = Deflate(Z_FULL_FLUSH); + } while (zerror_ == Z_OK); + return zerror_ == Z_OK; +} + +bool GzipOutputStream::Close() { + if ((zerror_ != Z_OK) && (zerror_ != Z_BUF_ERROR)) { + return false; + } + do { + zerror_ = Deflate(Z_FINISH); + } while (zerror_ == Z_OK); + zerror_ = deflateEnd(&zcontext_); + bool ok = zerror_ == Z_OK; + zerror_ = Z_STREAM_END; + return ok; +} + +} // namespace io +} // namespace protobuf +} // namespace google + +#endif // HAVE_ZLIB diff --git a/depends/protobuf/google/protobuf/io/gzip_stream.h b/depends/protobuf/google/protobuf/io/gzip_stream.h new file mode 100644 index 0000000000..65dbc5b557 --- /dev/null +++ b/depends/protobuf/google/protobuf/io/gzip_stream.h @@ -0,0 +1,207 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: brianolson@google.com (Brian Olson) +// +// This file contains the definition for classes GzipInputStream and +// GzipOutputStream. +// +// GzipInputStream decompresses data from an underlying +// ZeroCopyInputStream and provides the decompressed data as a +// ZeroCopyInputStream. +// +// GzipOutputStream is an ZeroCopyOutputStream that compresses data to +// an underlying ZeroCopyOutputStream. + +#ifndef GOOGLE_PROTOBUF_IO_GZIP_STREAM_H__ +#define GOOGLE_PROTOBUF_IO_GZIP_STREAM_H__ + +#include + +#include + +namespace google { +namespace protobuf { +namespace io { + +// A ZeroCopyInputStream that reads compressed data through zlib +class LIBPROTOBUF_EXPORT GzipInputStream : public ZeroCopyInputStream { + public: + // Format key for constructor + enum Format { + // zlib will autodetect gzip header or deflate stream + AUTO = 0, + + // GZIP streams have some extra header data for file attributes. + GZIP = 1, + + // Simpler zlib stream format. + ZLIB = 2, + }; + + // buffer_size and format may be -1 for default of 64kB and GZIP format + explicit GzipInputStream( + ZeroCopyInputStream* sub_stream, + Format format = AUTO, + int buffer_size = -1); + virtual ~GzipInputStream(); + + // Return last error message or NULL if no error. + inline const char* ZlibErrorMessage() const { + return zcontext_.msg; + } + inline int ZlibErrorCode() const { + return zerror_; + } + + // implements ZeroCopyInputStream ---------------------------------- + bool Next(const void** data, int* size); + void BackUp(int count); + bool Skip(int count); + int64 ByteCount() const; + + private: + Format format_; + + ZeroCopyInputStream* sub_stream_; + + z_stream zcontext_; + int zerror_; + + void* output_buffer_; + void* output_position_; + size_t output_buffer_length_; + + int Inflate(int flush); + void DoNextOutput(const void** data, int* size); + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(GzipInputStream); +}; + + +class LIBPROTOBUF_EXPORT GzipOutputStream : public ZeroCopyOutputStream { + public: + // Format key for constructor + enum Format { + // GZIP streams have some extra header data for file attributes. + GZIP = 1, + + // Simpler zlib stream format. + ZLIB = 2, + }; + + struct Options { + // Defaults to GZIP. + Format format; + + // What size buffer to use internally. Defaults to 64kB. + int buffer_size; + + // A number between 0 and 9, where 0 is no compression and 9 is best + // compression. Defaults to Z_DEFAULT_COMPRESSION (see zlib.h). + int compression_level; + + // Defaults to Z_DEFAULT_STRATEGY. Can also be set to Z_FILTERED, + // Z_HUFFMAN_ONLY, or Z_RLE. See the documentation for deflateInit2 in + // zlib.h for definitions of these constants. + int compression_strategy; + + Options(); // Initializes with default values. + }; + + // Create a GzipOutputStream with default options. + explicit GzipOutputStream(ZeroCopyOutputStream* sub_stream); + + // Create a GzipOutputStream with the given options. + GzipOutputStream( + ZeroCopyOutputStream* sub_stream, + const Options& options); + + // DEPRECATED: Use one of the above constructors instead. + GzipOutputStream( + ZeroCopyOutputStream* sub_stream, + Format format, + int buffer_size = -1) GOOGLE_ATTRIBUTE_DEPRECATED; + + virtual ~GzipOutputStream(); + + // Return last error message or NULL if no error. + inline const char* ZlibErrorMessage() const { + return zcontext_.msg; + } + inline int ZlibErrorCode() const { + return zerror_; + } + + // Flushes data written so far to zipped data in the underlying stream. + // It is the caller's responsibility to flush the underlying stream if + // necessary. + // Compression may be less efficient stopping and starting around flushes. + // Returns true if no error. + bool Flush(); + + // Writes out all data and closes the gzip stream. + // It is the caller's responsibility to close the underlying stream if + // necessary. + // Returns true if no error. + bool Close(); + + // implements ZeroCopyOutputStream --------------------------------- + bool Next(void** data, int* size); + void BackUp(int count); + int64 ByteCount() const; + + private: + ZeroCopyOutputStream* sub_stream_; + // Result from calling Next() on sub_stream_ + void* sub_data_; + int sub_data_size_; + + z_stream zcontext_; + int zerror_; + void* input_buffer_; + size_t input_buffer_length_; + + // Shared constructor code. + void Init(ZeroCopyOutputStream* sub_stream, const Options& options); + + // Do some compression. + // Takes zlib flush mode. + // Returns zlib error code. + int Deflate(int flush); + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(GzipOutputStream); +}; + +} // namespace io +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_IO_GZIP_STREAM_H__ diff --git a/depends/protobuf/google/protobuf/io/package_info.h b/depends/protobuf/google/protobuf/io/package_info.h new file mode 100644 index 0000000000..7a7a4e7738 --- /dev/null +++ b/depends/protobuf/google/protobuf/io/package_info.h @@ -0,0 +1,54 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// This file exists solely to document the google::protobuf::io namespace. +// It is not compiled into anything, but it may be read by an automated +// documentation generator. + +namespace google { + +namespace protobuf { + +// Auxiliary classes used for I/O. +// +// The Protocol Buffer library uses the classes in this package to deal with +// I/O and encoding/decoding raw bytes. Most users will not need to +// deal with this package. However, users who want to adapt the system to +// work with their own I/O abstractions -- e.g., to allow Protocol Buffers +// to be read from a different kind of input stream without the need for a +// temporary buffer -- should take a closer look. +namespace io {} + +} // namespace protobuf +} // namespace google diff --git a/depends/protobuf/google/protobuf/io/printer.cc b/depends/protobuf/google/protobuf/io/printer.cc new file mode 100644 index 0000000000..9ab90deec6 --- /dev/null +++ b/depends/protobuf/google/protobuf/io/printer.cc @@ -0,0 +1,199 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include +#include +#include +#include + +namespace google { +namespace protobuf { +namespace io { + +Printer::Printer(ZeroCopyOutputStream* output, char variable_delimiter) + : variable_delimiter_(variable_delimiter), + output_(output), + buffer_(NULL), + buffer_size_(0), + at_start_of_line_(true), + failed_(false) { +} + +Printer::~Printer() { + // Only BackUp() if we're sure we've successfully called Next() at least once. + if (buffer_size_ > 0) { + output_->BackUp(buffer_size_); + } +} + +void Printer::Print(const map& variables, const char* text) { + int size = strlen(text); + int pos = 0; // The number of bytes we've written so far. + + for (int i = 0; i < size; i++) { + if (text[i] == '\n') { + // Saw newline. If there is more text, we may need to insert an indent + // here. So, write what we have so far, including the '\n'. + WriteRaw(text + pos, i - pos + 1); + pos = i + 1; + + // Setting this true will cause the next WriteRaw() to insert an indent + // first. + at_start_of_line_ = true; + + } else if (text[i] == variable_delimiter_) { + // Saw the start of a variable name. + + // Write what we have so far. + WriteRaw(text + pos, i - pos); + pos = i + 1; + + // Find closing delimiter. + const char* end = strchr(text + pos, variable_delimiter_); + if (end == NULL) { + GOOGLE_LOG(DFATAL) << " Unclosed variable name."; + end = text + pos; + } + int endpos = end - text; + + string varname(text + pos, endpos - pos); + if (varname.empty()) { + // Two delimiters in a row reduce to a literal delimiter character. + WriteRaw(&variable_delimiter_, 1); + } else { + // Replace with the variable's value. + map::const_iterator iter = variables.find(varname); + if (iter == variables.end()) { + GOOGLE_LOG(DFATAL) << " Undefined variable: " << varname; + } else { + WriteRaw(iter->second.data(), iter->second.size()); + } + } + + // Advance past this variable. + i = endpos; + pos = endpos + 1; + } + } + + // Write the rest. + WriteRaw(text + pos, size - pos); +} + +void Printer::Print(const char* text) { + static map empty; + Print(empty, text); +} + +void Printer::Print(const char* text, + const char* variable, const string& value) { + map vars; + vars[variable] = value; + Print(vars, text); +} + +void Printer::Print(const char* text, + const char* variable1, const string& value1, + const char* variable2, const string& value2) { + map vars; + vars[variable1] = value1; + vars[variable2] = value2; + Print(vars, text); +} + +void Printer::Print(const char* text, + const char* variable1, const string& value1, + const char* variable2, const string& value2, + const char* variable3, const string& value3) { + map vars; + vars[variable1] = value1; + vars[variable2] = value2; + vars[variable3] = value3; + Print(vars, text); +} + +void Printer::Indent() { + indent_ += " "; +} + +void Printer::Outdent() { + if (indent_.empty()) { + GOOGLE_LOG(DFATAL) << " Outdent() without matching Indent()."; + return; + } + + indent_.resize(indent_.size() - 2); +} + +void Printer::PrintRaw(const string& data) { + WriteRaw(data.data(), data.size()); +} + +void Printer::PrintRaw(const char* data) { + if (failed_) return; + WriteRaw(data, strlen(data)); +} + +void Printer::WriteRaw(const char* data, int size) { + if (failed_) return; + if (size == 0) return; + + if (at_start_of_line_) { + // Insert an indent. + at_start_of_line_ = false; + WriteRaw(indent_.data(), indent_.size()); + if (failed_) return; + } + + while (size > buffer_size_) { + // Data exceeds space in the buffer. Copy what we can and request a + // new buffer. + memcpy(buffer_, data, buffer_size_); + data += buffer_size_; + size -= buffer_size_; + void* void_buffer; + failed_ = !output_->Next(&void_buffer, &buffer_size_); + if (failed_) return; + buffer_ = reinterpret_cast(void_buffer); + } + + // Buffer is big enough to receive the data; copy it. + memcpy(buffer_, data, size); + buffer_ += size; + buffer_size_ -= size; +} + +} // namespace io +} // namespace protobuf +} // namespace google diff --git a/depends/protobuf/google/protobuf/io/printer.h b/depends/protobuf/google/protobuf/io/printer.h new file mode 100644 index 0000000000..5be48543ab --- /dev/null +++ b/depends/protobuf/google/protobuf/io/printer.h @@ -0,0 +1,136 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// Utility class for writing text to a ZeroCopyOutputStream. + +#ifndef GOOGLE_PROTOBUF_IO_PRINTER_H__ +#define GOOGLE_PROTOBUF_IO_PRINTER_H__ + +#include +#include +#include + +namespace google { +namespace protobuf { +namespace io { + +class ZeroCopyOutputStream; // zero_copy_stream.h + +// This simple utility class assists in code generation. It basically +// allows the caller to define a set of variables and then output some +// text with variable substitutions. Example usage: +// +// Printer printer(output, '$'); +// map vars; +// vars["name"] = "Bob"; +// printer.Print(vars, "My name is $name$."); +// +// The above writes "My name is Bob." to the output stream. +// +// Printer aggressively enforces correct usage, crashing (with assert failures) +// in the case of undefined variables in debug builds. This helps greatly in +// debugging code which uses it. +class LIBPROTOBUF_EXPORT Printer { + public: + // Create a printer that writes text to the given output stream. Use the + // given character as the delimiter for variables. + Printer(ZeroCopyOutputStream* output, char variable_delimiter); + ~Printer(); + + // Print some text after applying variable substitutions. If a particular + // variable in the text is not defined, this will crash. Variables to be + // substituted are identified by their names surrounded by delimiter + // characters (as given to the constructor). The variable bindings are + // defined by the given map. + void Print(const map& variables, const char* text); + + // Like the first Print(), except the substitutions are given as parameters. + void Print(const char* text); + // Like the first Print(), except the substitutions are given as parameters. + void Print(const char* text, const char* variable, const string& value); + // Like the first Print(), except the substitutions are given as parameters. + void Print(const char* text, const char* variable1, const string& value1, + const char* variable2, const string& value2); + // Like the first Print(), except the substitutions are given as parameters. + void Print(const char* text, const char* variable1, const string& value1, + const char* variable2, const string& value2, + const char* variable3, const string& value3); + // TODO(kenton): Overloaded versions with more variables? Three seems + // to be enough. + + // Indent text by two spaces. After calling Indent(), two spaces will be + // inserted at the beginning of each line of text. Indent() may be called + // multiple times to produce deeper indents. + void Indent(); + + // Reduces the current indent level by two spaces, or crashes if the indent + // level is zero. + void Outdent(); + + // Write a string to the output buffer. + // This method does not look for newlines to add indentation. + void PrintRaw(const string& data); + + // Write a zero-delimited string to output buffer. + // This method does not look for newlines to add indentation. + void PrintRaw(const char* data); + + // Write some bytes to the output buffer. + // This method does not look for newlines to add indentation. + void WriteRaw(const char* data, int size); + + // True if any write to the underlying stream failed. (We don't just + // crash in this case because this is an I/O failure, not a programming + // error.) + bool failed() const { return failed_; } + + private: + const char variable_delimiter_; + + ZeroCopyOutputStream* const output_; + char* buffer_; + int buffer_size_; + + string indent_; + bool at_start_of_line_; + bool failed_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Printer); +}; + +} // namespace io +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_IO_PRINTER_H__ diff --git a/depends/protobuf/google/protobuf/io/tokenizer.cc b/depends/protobuf/google/protobuf/io/tokenizer.cc new file mode 100644 index 0000000000..513831d55f --- /dev/null +++ b/depends/protobuf/google/protobuf/io/tokenizer.cc @@ -0,0 +1,694 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// Here we have a hand-written lexer. At first you might ask yourself, +// "Hand-written text processing? Is Kenton crazy?!" Well, first of all, +// yes I am crazy, but that's beside the point. There are actually reasons +// why I ended up writing this this way. +// +// The traditional approach to lexing is to use lex to generate a lexer for +// you. Unfortunately, lex's output is ridiculously ugly and difficult to +// integrate cleanly with C++ code, especially abstract code or code meant +// as a library. Better parser-generators exist but would add dependencies +// which most users won't already have, which we'd like to avoid. (GNU flex +// has a C++ output option, but it's still ridiculously ugly, non-abstract, +// and not library-friendly.) +// +// The next approach that any good software engineer should look at is to +// use regular expressions. And, indeed, I did. I have code which +// implements this same class using regular expressions. It's about 200 +// lines shorter. However: +// - Rather than error messages telling you "This string has an invalid +// escape sequence at line 5, column 45", you get error messages like +// "Parse error on line 5". Giving more precise errors requires adding +// a lot of code that ends up basically as complex as the hand-coded +// version anyway. +// - The regular expression to match a string literal looks like this: +// kString = new RE("(\"([^\"\\\\]|" // non-escaped +// "\\\\[abfnrtv?\"'\\\\0-7]|" // normal escape +// "\\\\x[0-9a-fA-F])*\"|" // hex escape +// "\'([^\'\\\\]|" // Also support single-quotes. +// "\\\\[abfnrtv?\"'\\\\0-7]|" +// "\\\\x[0-9a-fA-F])*\')"); +// Verifying the correctness of this line noise is actually harder than +// verifying the correctness of ConsumeString(), defined below. I'm not +// even confident that the above is correct, after staring at it for some +// time. +// - PCRE is fast, but there's still more overhead involved than the code +// below. +// - Sadly, regular expressions are not part of the C standard library, so +// using them would require depending on some other library. For the +// open source release, this could be really annoying. Nobody likes +// downloading one piece of software just to find that they need to +// download something else to make it work, and in all likelihood +// people downloading Protocol Buffers will already be doing so just +// to make something else work. We could include a copy of PCRE with +// our code, but that obligates us to keep it up-to-date and just seems +// like a big waste just to save 200 lines of code. +// +// On a similar but unrelated note, I'm even scared to use ctype.h. +// Apparently functions like isalpha() are locale-dependent. So, if we used +// that, then if this code is being called from some program that doesn't +// have its locale set to "C", it would behave strangely. We can't just set +// the locale to "C" ourselves since we might break the calling program that +// way, particularly if it is multi-threaded. WTF? Someone please let me +// (Kenton) know if I'm missing something here... +// +// I'd love to hear about other alternatives, though, as this code isn't +// exactly pretty. + +#include +#include +#include + +namespace google { +namespace protobuf { +namespace io { +namespace { + +// As mentioned above, I don't trust ctype.h due to the presence of "locales". +// So, I have written replacement functions here. Someone please smack me if +// this is a bad idea or if there is some way around this. +// +// These "character classes" are designed to be used in template methods. +// For instance, Tokenizer::ConsumeZeroOrMore() will eat +// whitespace. + +// Note: No class is allowed to contain '\0', since this is used to mark end- +// of-input and is handled specially. + +#define CHARACTER_CLASS(NAME, EXPRESSION) \ + class NAME { \ + public: \ + static inline bool InClass(char c) { \ + return EXPRESSION; \ + } \ + } + +CHARACTER_CLASS(Whitespace, c == ' ' || c == '\n' || c == '\t' || + c == '\r' || c == '\v' || c == '\f'); + +CHARACTER_CLASS(Unprintable, c < ' ' && c > '\0'); + +CHARACTER_CLASS(Digit, '0' <= c && c <= '9'); +CHARACTER_CLASS(OctalDigit, '0' <= c && c <= '7'); +CHARACTER_CLASS(HexDigit, ('0' <= c && c <= '9') || + ('a' <= c && c <= 'f') || + ('A' <= c && c <= 'F')); + +CHARACTER_CLASS(Letter, ('a' <= c && c <= 'z') || + ('A' <= c && c <= 'Z') || + (c == '_')); + +CHARACTER_CLASS(Alphanumeric, ('a' <= c && c <= 'z') || + ('A' <= c && c <= 'Z') || + ('0' <= c && c <= '9') || + (c == '_')); + +CHARACTER_CLASS(Escape, c == 'a' || c == 'b' || c == 'f' || c == 'n' || + c == 'r' || c == 't' || c == 'v' || c == '\\' || + c == '?' || c == '\'' || c == '\"'); + +#undef CHARACTER_CLASS + +// Given a char, interpret it as a numeric digit and return its value. +// This supports any number base up to 36. +inline int DigitValue(char digit) { + if ('0' <= digit && digit <= '9') return digit - '0'; + if ('a' <= digit && digit <= 'z') return digit - 'a' + 10; + if ('A' <= digit && digit <= 'Z') return digit - 'A' + 10; + return -1; +} + +// Inline because it's only used in one place. +inline char TranslateEscape(char c) { + switch (c) { + case 'a': return '\a'; + case 'b': return '\b'; + case 'f': return '\f'; + case 'n': return '\n'; + case 'r': return '\r'; + case 't': return '\t'; + case 'v': return '\v'; + case '\\': return '\\'; + case '?': return '\?'; // Trigraphs = :( + case '\'': return '\''; + case '"': return '\"'; + + // We expect escape sequences to have been validated separately. + default: return '?'; + } +} + +} // anonymous namespace + +ErrorCollector::~ErrorCollector() {} + +// =================================================================== + +Tokenizer::Tokenizer(ZeroCopyInputStream* input, + ErrorCollector* error_collector) + : input_(input), + error_collector_(error_collector), + buffer_(NULL), + buffer_size_(0), + buffer_pos_(0), + read_error_(false), + line_(0), + column_(0), + token_start_(-1), + allow_f_after_float_(false), + comment_style_(CPP_COMMENT_STYLE) { + + current_.line = 0; + current_.column = 0; + current_.end_column = 0; + current_.type = TYPE_START; + + Refresh(); +} + +Tokenizer::~Tokenizer() { + // If we had any buffer left unread, return it to the underlying stream + // so that someone else can read it. + if (buffer_size_ > buffer_pos_) { + input_->BackUp(buffer_size_ - buffer_pos_); + } +} + +// ------------------------------------------------------------------- +// Internal helpers. + +void Tokenizer::NextChar() { + // Update our line and column counters based on the character being + // consumed. + if (current_char_ == '\n') { + ++line_; + column_ = 0; + } else if (current_char_ == '\t') { + column_ += kTabWidth - column_ % kTabWidth; + } else { + ++column_; + } + + // Advance to the next character. + ++buffer_pos_; + if (buffer_pos_ < buffer_size_) { + current_char_ = buffer_[buffer_pos_]; + } else { + Refresh(); + } +} + +void Tokenizer::Refresh() { + if (read_error_) { + current_char_ = '\0'; + return; + } + + // If we're in a token, append the rest of the buffer to it. + if (token_start_ >= 0 && token_start_ < buffer_size_) { + current_.text.append(buffer_ + token_start_, buffer_size_ - token_start_); + token_start_ = 0; + } + + const void* data = NULL; + buffer_ = NULL; + buffer_pos_ = 0; + do { + if (!input_->Next(&data, &buffer_size_)) { + // end of stream (or read error) + buffer_size_ = 0; + read_error_ = true; + current_char_ = '\0'; + return; + } + } while (buffer_size_ == 0); + + buffer_ = static_cast(data); + + current_char_ = buffer_[0]; +} + +inline void Tokenizer::StartToken() { + token_start_ = buffer_pos_; + current_.type = TYPE_START; // Just for the sake of initializing it. + current_.text.clear(); + current_.line = line_; + current_.column = column_; +} + +inline void Tokenizer::EndToken() { + // Note: The if() is necessary because some STL implementations crash when + // you call string::append(NULL, 0), presumably because they are trying to + // be helpful by detecting the NULL pointer, even though there's nothing + // wrong with reading zero bytes from NULL. + if (buffer_pos_ != token_start_) { + current_.text.append(buffer_ + token_start_, buffer_pos_ - token_start_); + } + token_start_ = -1; + current_.end_column = column_; +} + +// ------------------------------------------------------------------- +// Helper methods that consume characters. + +template +inline bool Tokenizer::LookingAt() { + return CharacterClass::InClass(current_char_); +} + +template +inline bool Tokenizer::TryConsumeOne() { + if (CharacterClass::InClass(current_char_)) { + NextChar(); + return true; + } else { + return false; + } +} + +inline bool Tokenizer::TryConsume(char c) { + if (current_char_ == c) { + NextChar(); + return true; + } else { + return false; + } +} + +template +inline void Tokenizer::ConsumeZeroOrMore() { + while (CharacterClass::InClass(current_char_)) { + NextChar(); + } +} + +template +inline void Tokenizer::ConsumeOneOrMore(const char* error) { + if (!CharacterClass::InClass(current_char_)) { + AddError(error); + } else { + do { + NextChar(); + } while (CharacterClass::InClass(current_char_)); + } +} + +// ------------------------------------------------------------------- +// Methods that read whole patterns matching certain kinds of tokens +// or comments. + +void Tokenizer::ConsumeString(char delimiter) { + while (true) { + switch (current_char_) { + case '\0': + case '\n': { + AddError("String literals cannot cross line boundaries."); + return; + } + + case '\\': { + // An escape sequence. + NextChar(); + if (TryConsumeOne()) { + // Valid escape sequence. + } else if (TryConsumeOne()) { + // Possibly followed by two more octal digits, but these will + // just be consumed by the main loop anyway so we don't need + // to do so explicitly here. + } else if (TryConsume('x') || TryConsume('X')) { + if (!TryConsumeOne()) { + AddError("Expected hex digits for escape sequence."); + } + // Possibly followed by another hex digit, but again we don't care. + } else { + AddError("Invalid escape sequence in string literal."); + } + break; + } + + default: { + if (current_char_ == delimiter) { + NextChar(); + return; + } + NextChar(); + break; + } + } + } +} + +Tokenizer::TokenType Tokenizer::ConsumeNumber(bool started_with_zero, + bool started_with_dot) { + bool is_float = false; + + if (started_with_zero && (TryConsume('x') || TryConsume('X'))) { + // A hex number (started with "0x"). + ConsumeOneOrMore("\"0x\" must be followed by hex digits."); + + } else if (started_with_zero && LookingAt()) { + // An octal number (had a leading zero). + ConsumeZeroOrMore(); + if (LookingAt()) { + AddError("Numbers starting with leading zero must be in octal."); + ConsumeZeroOrMore(); + } + + } else { + // A decimal number. + if (started_with_dot) { + is_float = true; + ConsumeZeroOrMore(); + } else { + ConsumeZeroOrMore(); + + if (TryConsume('.')) { + is_float = true; + ConsumeZeroOrMore(); + } + } + + if (TryConsume('e') || TryConsume('E')) { + is_float = true; + TryConsume('-') || TryConsume('+'); + ConsumeOneOrMore("\"e\" must be followed by exponent."); + } + + if (allow_f_after_float_ && (TryConsume('f') || TryConsume('F'))) { + is_float = true; + } + } + + if (LookingAt()) { + AddError("Need space between number and identifier."); + } else if (current_char_ == '.') { + if (is_float) { + AddError( + "Already saw decimal point or exponent; can't have another one."); + } else { + AddError("Hex and octal numbers must be integers."); + } + } + + return is_float ? TYPE_FLOAT : TYPE_INTEGER; +} + +void Tokenizer::ConsumeLineComment() { + while (current_char_ != '\0' && current_char_ != '\n') { + NextChar(); + } + TryConsume('\n'); +} + +void Tokenizer::ConsumeBlockComment() { + int start_line = line_; + int start_column = column_ - 2; + + while (true) { + while (current_char_ != '\0' && + current_char_ != '*' && + current_char_ != '/') { + NextChar(); + } + + if (TryConsume('*') && TryConsume('/')) { + // End of comment. + break; + } else if (TryConsume('/') && current_char_ == '*') { + // Note: We didn't consume the '*' because if there is a '/' after it + // we want to interpret that as the end of the comment. + AddError( + "\"/*\" inside block comment. Block comments cannot be nested."); + } else if (current_char_ == '\0') { + AddError("End-of-file inside block comment."); + error_collector_->AddError( + start_line, start_column, " Comment started here."); + break; + } + } +} + +// ------------------------------------------------------------------- + +bool Tokenizer::Next() { + previous_ = current_; + + // Did we skip any characters after the last token? + bool skipped_stuff = false; + + while (!read_error_) { + if (TryConsumeOne()) { + ConsumeZeroOrMore(); + + } else if (comment_style_ == CPP_COMMENT_STYLE && TryConsume('/')) { + // Starting a comment? + if (TryConsume('/')) { + ConsumeLineComment(); + } else if (TryConsume('*')) { + ConsumeBlockComment(); + } else { + // Oops, it was just a slash. Return it. + current_.type = TYPE_SYMBOL; + current_.text = "/"; + current_.line = line_; + current_.column = column_ - 1; + return true; + } + + } else if (comment_style_ == SH_COMMENT_STYLE && TryConsume('#')) { + ConsumeLineComment(); + + } else if (LookingAt() || current_char_ == '\0') { + AddError("Invalid control characters encountered in text."); + NextChar(); + // Skip more unprintable characters, too. But, remember that '\0' is + // also what current_char_ is set to after EOF / read error. We have + // to be careful not to go into an infinite loop of trying to consume + // it, so make sure to check read_error_ explicitly before consuming + // '\0'. + while (TryConsumeOne() || + (!read_error_ && TryConsume('\0'))) { + // Ignore. + } + + } else { + // Reading some sort of token. + StartToken(); + + if (TryConsumeOne()) { + ConsumeZeroOrMore(); + current_.type = TYPE_IDENTIFIER; + } else if (TryConsume('0')) { + current_.type = ConsumeNumber(true, false); + } else if (TryConsume('.')) { + // This could be the beginning of a floating-point number, or it could + // just be a '.' symbol. + + if (TryConsumeOne()) { + // It's a floating-point number. + if (previous_.type == TYPE_IDENTIFIER && !skipped_stuff) { + // We don't accept syntax like "blah.123". + error_collector_->AddError(line_, column_ - 2, + "Need space between identifier and decimal point."); + } + current_.type = ConsumeNumber(false, true); + } else { + current_.type = TYPE_SYMBOL; + } + } else if (TryConsumeOne()) { + current_.type = ConsumeNumber(false, false); + } else if (TryConsume('\"')) { + ConsumeString('\"'); + current_.type = TYPE_STRING; + } else if (TryConsume('\'')) { + ConsumeString('\''); + current_.type = TYPE_STRING; + } else { + NextChar(); + current_.type = TYPE_SYMBOL; + } + + EndToken(); + return true; + } + + skipped_stuff = true; + } + + // EOF + current_.type = TYPE_END; + current_.text.clear(); + current_.line = line_; + current_.column = column_; + current_.end_column = column_; + return false; +} + +// ------------------------------------------------------------------- +// Token-parsing helpers. Remember that these don't need to report +// errors since any errors should already have been reported while +// tokenizing. Also, these can assume that whatever text they +// are given is text that the tokenizer actually parsed as a token +// of the given type. + +bool Tokenizer::ParseInteger(const string& text, uint64 max_value, + uint64* output) { + // Sadly, we can't just use strtoul() since it is only 32-bit and strtoull() + // is non-standard. I hate the C standard library. :( + +// return strtoull(text.c_str(), NULL, 0); + + const char* ptr = text.c_str(); + int base = 10; + if (ptr[0] == '0') { + if (ptr[1] == 'x' || ptr[1] == 'X') { + // This is hex. + base = 16; + ptr += 2; + } else { + // This is octal. + base = 8; + } + } + + uint64 result = 0; + for (; *ptr != '\0'; ptr++) { + int digit = DigitValue(*ptr); + GOOGLE_LOG_IF(DFATAL, digit < 0 || digit >= base) + << " Tokenizer::ParseInteger() passed text that could not have been" + " tokenized as an integer: " << CEscape(text); + if (digit > max_value || result > (max_value - digit) / base) { + // Overflow. + return false; + } + result = result * base + digit; + } + + *output = result; + return true; +} + +double Tokenizer::ParseFloat(const string& text) { + const char* start = text.c_str(); + char* end; + double result = NoLocaleStrtod(start, &end); + + // "1e" is not a valid float, but if the tokenizer reads it, it will + // report an error but still return it as a valid token. We need to + // accept anything the tokenizer could possibly return, error or not. + if (*end == 'e' || *end == 'E') { + ++end; + if (*end == '-' || *end == '+') ++end; + } + + // If the Tokenizer had allow_f_after_float_ enabled, the float may be + // suffixed with the letter 'f'. + if (*end == 'f' || *end == 'F') { + ++end; + } + + GOOGLE_LOG_IF(DFATAL, end - start != text.size() || *start == '-') + << " Tokenizer::ParseFloat() passed text that could not have been" + " tokenized as a float: " << CEscape(text); + return result; +} + +void Tokenizer::ParseStringAppend(const string& text, string* output) { + // Reminder: text[0] is always the quote character. (If text is + // empty, it's invalid, so we'll just return.) + if (text.empty()) { + GOOGLE_LOG(DFATAL) + << " Tokenizer::ParseStringAppend() passed text that could not" + " have been tokenized as a string: " << CEscape(text); + return; + } + + output->reserve(output->size() + text.size()); + + // Loop through the string copying characters to "output" and + // interpreting escape sequences. Note that any invalid escape + // sequences or other errors were already reported while tokenizing. + // In this case we do not need to produce valid results. + for (const char* ptr = text.c_str() + 1; *ptr != '\0'; ptr++) { + if (*ptr == '\\' && ptr[1] != '\0') { + // An escape sequence. + ++ptr; + + if (OctalDigit::InClass(*ptr)) { + // An octal escape. May one, two, or three digits. + int code = DigitValue(*ptr); + if (OctalDigit::InClass(ptr[1])) { + ++ptr; + code = code * 8 + DigitValue(*ptr); + } + if (OctalDigit::InClass(ptr[1])) { + ++ptr; + code = code * 8 + DigitValue(*ptr); + } + output->push_back(static_cast(code)); + + } else if (*ptr == 'x') { + // A hex escape. May zero, one, or two digits. (The zero case + // will have been caught as an error earlier.) + int code = 0; + if (HexDigit::InClass(ptr[1])) { + ++ptr; + code = DigitValue(*ptr); + } + if (HexDigit::InClass(ptr[1])) { + ++ptr; + code = code * 16 + DigitValue(*ptr); + } + output->push_back(static_cast(code)); + + } else { + // Some other escape code. + output->push_back(TranslateEscape(*ptr)); + } + + } else if (*ptr == text[0]) { + // Ignore quote matching the starting quote. + } else { + output->push_back(*ptr); + } + } + + return; +} + +} // namespace io +} // namespace protobuf +} // namespace google diff --git a/depends/protobuf/google/protobuf/io/tokenizer.h b/depends/protobuf/google/protobuf/io/tokenizer.h new file mode 100644 index 0000000000..8f759abbd8 --- /dev/null +++ b/depends/protobuf/google/protobuf/io/tokenizer.h @@ -0,0 +1,313 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// Class for parsing tokenized text from a ZeroCopyInputStream. + +#ifndef GOOGLE_PROTOBUF_IO_TOKENIZER_H__ +#define GOOGLE_PROTOBUF_IO_TOKENIZER_H__ + +#include +#include + +namespace google { +namespace protobuf { +namespace io { + +class ZeroCopyInputStream; // zero_copy_stream.h + +// Defined in this file. +class ErrorCollector; +class Tokenizer; + +// Abstract interface for an object which collects the errors that occur +// during parsing. A typical implementation might simply print the errors +// to stdout. +class LIBPROTOBUF_EXPORT ErrorCollector { + public: + inline ErrorCollector() {} + virtual ~ErrorCollector(); + + // Indicates that there was an error in the input at the given line and + // column numbers. The numbers are zero-based, so you may want to add + // 1 to each before printing them. + virtual void AddError(int line, int column, const string& message) = 0; + + // Indicates that there was a warning in the input at the given line and + // column numbers. The numbers are zero-based, so you may want to add + // 1 to each before printing them. + virtual void AddWarning(int line, int column, const string& message) { } + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ErrorCollector); +}; + +// This class converts a stream of raw text into a stream of tokens for +// the protocol definition parser to parse. The tokens recognized are +// similar to those that make up the C language; see the TokenType enum for +// precise descriptions. Whitespace and comments are skipped. By default, +// C- and C++-style comments are recognized, but other styles can be used by +// calling set_comment_style(). +class LIBPROTOBUF_EXPORT Tokenizer { + public: + // Construct a Tokenizer that reads and tokenizes text from the given + // input stream and writes errors to the given error_collector. + // The caller keeps ownership of input and error_collector. + Tokenizer(ZeroCopyInputStream* input, ErrorCollector* error_collector); + ~Tokenizer(); + + enum TokenType { + TYPE_START, // Next() has not yet been called. + TYPE_END, // End of input reached. "text" is empty. + + TYPE_IDENTIFIER, // A sequence of letters, digits, and underscores, not + // starting with a digit. It is an error for a number + // to be followed by an identifier with no space in + // between. + TYPE_INTEGER, // A sequence of digits representing an integer. Normally + // the digits are decimal, but a prefix of "0x" indicates + // a hex number and a leading zero indicates octal, just + // like with C numeric literals. A leading negative sign + // is NOT included in the token; it's up to the parser to + // interpret the unary minus operator on its own. + TYPE_FLOAT, // A floating point literal, with a fractional part and/or + // an exponent. Always in decimal. Again, never + // negative. + TYPE_STRING, // A quoted sequence of escaped characters. Either single + // or double quotes can be used, but they must match. + // A string literal cannot cross a line break. + TYPE_SYMBOL, // Any other printable character, like '!' or '+'. + // Symbols are always a single character, so "!+$%" is + // four tokens. + }; + + // Structure representing a token read from the token stream. + struct Token { + TokenType type; + string text; // The exact text of the token as it appeared in + // the input. e.g. tokens of TYPE_STRING will still + // be escaped and in quotes. + + // "line" and "column" specify the position of the first character of + // the token within the input stream. They are zero-based. + int line; + int column; + int end_column; + }; + + // Get the current token. This is updated when Next() is called. Before + // the first call to Next(), current() has type TYPE_START and no contents. + const Token& current(); + + // Return the previous token -- i.e. what current() returned before the + // previous call to Next(). + const Token& previous(); + + // Advance to the next token. Returns false if the end of the input is + // reached. + bool Next(); + + // Parse helpers --------------------------------------------------- + + // Parses a TYPE_FLOAT token. This never fails, so long as the text actually + // comes from a TYPE_FLOAT token parsed by Tokenizer. If it doesn't, the + // result is undefined (possibly an assert failure). + static double ParseFloat(const string& text); + + // Parses a TYPE_STRING token. This never fails, so long as the text actually + // comes from a TYPE_STRING token parsed by Tokenizer. If it doesn't, the + // result is undefined (possibly an assert failure). + static void ParseString(const string& text, string* output); + + // Identical to ParseString, but appends to output. + static void ParseStringAppend(const string& text, string* output); + + // Parses a TYPE_INTEGER token. Returns false if the result would be + // greater than max_value. Otherwise, returns true and sets *output to the + // result. If the text is not from a Token of type TYPE_INTEGER originally + // parsed by a Tokenizer, the result is undefined (possibly an assert + // failure). + static bool ParseInteger(const string& text, uint64 max_value, + uint64* output); + + // Options --------------------------------------------------------- + + // Set true to allow floats to be suffixed with the letter 'f'. Tokens + // which would otherwise be integers but which have the 'f' suffix will be + // forced to be interpreted as floats. For all other purposes, the 'f' is + // ignored. + void set_allow_f_after_float(bool value) { allow_f_after_float_ = value; } + + // Valid values for set_comment_style(). + enum CommentStyle { + // Line comments begin with "//", block comments are delimited by "/*" and + // "*/". + CPP_COMMENT_STYLE, + // Line comments begin with "#". No way to write block comments. + SH_COMMENT_STYLE + }; + + // Sets the comment style. + void set_comment_style(CommentStyle style) { comment_style_ = style; } + + // ----------------------------------------------------------------- + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Tokenizer); + + Token current_; // Returned by current(). + Token previous_; // Returned by previous(). + + ZeroCopyInputStream* input_; + ErrorCollector* error_collector_; + + char current_char_; // == buffer_[buffer_pos_], updated by NextChar(). + const char* buffer_; // Current buffer returned from input_. + int buffer_size_; // Size of buffer_. + int buffer_pos_; // Current position within the buffer. + bool read_error_; // Did we previously encounter a read error? + + // Line and column number of current_char_ within the whole input stream. + int line_; + int column_; + + // Position in buffer_ where StartToken() was called. If the token + // started in the previous buffer, this is zero, and current_.text already + // contains the part of the token from the previous buffer. If not + // currently parsing a token, this is -1. + int token_start_; + + // Options. + bool allow_f_after_float_; + CommentStyle comment_style_; + + // Since we count columns we need to interpret tabs somehow. We'll take + // the standard 8-character definition for lack of any way to do better. + static const int kTabWidth = 8; + + // ----------------------------------------------------------------- + // Helper methods. + + // Consume this character and advance to the next one. + void NextChar(); + + // Read a new buffer from the input. + void Refresh(); + + // Called when the current character is the first character of a new + // token (not including whitespace or comments). + inline void StartToken(); + // Called when the current character is the first character after the + // end of the last token. After this returns, current_.text will + // contain all text consumed since StartToken() was called. + inline void EndToken(); + + // Convenience method to add an error at the current line and column. + void AddError(const string& message) { + error_collector_->AddError(line_, column_, message); + } + + // ----------------------------------------------------------------- + // The following four methods are used to consume tokens of specific + // types. They are actually used to consume all characters *after* + // the first, since the calling function consumes the first character + // in order to decide what kind of token is being read. + + // Read and consume a string, ending when the given delimiter is + // consumed. + void ConsumeString(char delimiter); + + // Read and consume a number, returning TYPE_FLOAT or TYPE_INTEGER + // depending on what was read. This needs to know if the first + // character was a zero in order to correctly recognize hex and octal + // numbers. + // It also needs to know if the first characted was a . to parse floating + // point correctly. + TokenType ConsumeNumber(bool started_with_zero, bool started_with_dot); + + // Consume the rest of a line. + void ConsumeLineComment(); + // Consume until "*/". + void ConsumeBlockComment(); + + // ----------------------------------------------------------------- + // These helper methods make the parsing code more readable. The + // "character classes" refered to are defined at the top of the .cc file. + // Basically it is a C++ class with one method: + // static bool InClass(char c); + // The method returns true if c is a member of this "class", like "Letter" + // or "Digit". + + // Returns true if the current character is of the given character + // class, but does not consume anything. + template + inline bool LookingAt(); + + // If the current character is in the given class, consume it and return + // true. Otherwise return false. + // e.g. TryConsumeOne() + template + inline bool TryConsumeOne(); + + // Like above, but try to consume the specific character indicated. + inline bool TryConsume(char c); + + // Consume zero or more of the given character class. + template + inline void ConsumeZeroOrMore(); + + // Consume one or more of the given character class or log the given + // error message. + // e.g. ConsumeOneOrMore("Expected digits."); + template + inline void ConsumeOneOrMore(const char* error); +}; + +// inline methods ==================================================== +inline const Tokenizer::Token& Tokenizer::current() { + return current_; +} + +inline const Tokenizer::Token& Tokenizer::previous() { + return previous_; +} + +inline void Tokenizer::ParseString(const string& text, string* output) { + output->clear(); + ParseStringAppend(text, output); +} + +} // namespace io +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_IO_TOKENIZER_H__ diff --git a/depends/protobuf/google/protobuf/io/zero_copy_stream.cc b/depends/protobuf/google/protobuf/io/zero_copy_stream.cc new file mode 100644 index 0000000000..dad6ff1446 --- /dev/null +++ b/depends/protobuf/google/protobuf/io/zero_copy_stream.cc @@ -0,0 +1,48 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include + + +namespace google { +namespace protobuf { +namespace io { + +ZeroCopyInputStream::~ZeroCopyInputStream() {} +ZeroCopyOutputStream::~ZeroCopyOutputStream() {} + + +} // namespace io +} // namespace protobuf +} // namespace google diff --git a/depends/protobuf/google/protobuf/io/zero_copy_stream.h b/depends/protobuf/google/protobuf/io/zero_copy_stream.h new file mode 100644 index 0000000000..db5326f703 --- /dev/null +++ b/depends/protobuf/google/protobuf/io/zero_copy_stream.h @@ -0,0 +1,238 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// This file contains the ZeroCopyInputStream and ZeroCopyOutputStream +// interfaces, which represent abstract I/O streams to and from which +// protocol buffers can be read and written. For a few simple +// implementations of these interfaces, see zero_copy_stream_impl.h. +// +// These interfaces are different from classic I/O streams in that they +// try to minimize the amount of data copying that needs to be done. +// To accomplish this, responsibility for allocating buffers is moved to +// the stream object, rather than being the responsibility of the caller. +// So, the stream can return a buffer which actually points directly into +// the final data structure where the bytes are to be stored, and the caller +// can interact directly with that buffer, eliminating an intermediate copy +// operation. +// +// As an example, consider the common case in which you are reading bytes +// from an array that is already in memory (or perhaps an mmap()ed file). +// With classic I/O streams, you would do something like: +// char buffer[BUFFER_SIZE]; +// input->Read(buffer, BUFFER_SIZE); +// DoSomething(buffer, BUFFER_SIZE); +// Then, the stream basically just calls memcpy() to copy the data from +// the array into your buffer. With a ZeroCopyInputStream, you would do +// this instead: +// const void* buffer; +// int size; +// input->Next(&buffer, &size); +// DoSomething(buffer, size); +// Here, no copy is performed. The input stream returns a pointer directly +// into the backing array, and the caller ends up reading directly from it. +// +// If you want to be able to read the old-fashion way, you can create +// a CodedInputStream or CodedOutputStream wrapping these objects and use +// their ReadRaw()/WriteRaw() methods. These will, of course, add a copy +// step, but Coded*Stream will handle buffering so at least it will be +// reasonably efficient. +// +// ZeroCopyInputStream example: +// // Read in a file and print its contents to stdout. +// int fd = open("myfile", O_RDONLY); +// ZeroCopyInputStream* input = new FileInputStream(fd); +// +// const void* buffer; +// int size; +// while (input->Next(&buffer, &size)) { +// cout.write(buffer, size); +// } +// +// delete input; +// close(fd); +// +// ZeroCopyOutputStream example: +// // Copy the contents of "infile" to "outfile", using plain read() for +// // "infile" but a ZeroCopyOutputStream for "outfile". +// int infd = open("infile", O_RDONLY); +// int outfd = open("outfile", O_WRONLY); +// ZeroCopyOutputStream* output = new FileOutputStream(outfd); +// +// void* buffer; +// int size; +// while (output->Next(&buffer, &size)) { +// int bytes = read(infd, buffer, size); +// if (bytes < size) { +// // Reached EOF. +// output->BackUp(size - bytes); +// break; +// } +// } +// +// delete output; +// close(infd); +// close(outfd); + +#ifndef GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_H__ +#define GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_H__ + +#include +#include + +namespace google { + +namespace protobuf { +namespace io { + +// Defined in this file. +class ZeroCopyInputStream; +class ZeroCopyOutputStream; + +// Abstract interface similar to an input stream but designed to minimize +// copying. +class LIBPROTOBUF_EXPORT ZeroCopyInputStream { + public: + inline ZeroCopyInputStream() {} + virtual ~ZeroCopyInputStream(); + + // Obtains a chunk of data from the stream. + // + // Preconditions: + // * "size" and "data" are not NULL. + // + // Postconditions: + // * If the returned value is false, there is no more data to return or + // an error occurred. All errors are permanent. + // * Otherwise, "size" points to the actual number of bytes read and "data" + // points to a pointer to a buffer containing these bytes. + // * Ownership of this buffer remains with the stream, and the buffer + // remains valid only until some other method of the stream is called + // or the stream is destroyed. + // * It is legal for the returned buffer to have zero size, as long + // as repeatedly calling Next() eventually yields a buffer with non-zero + // size. + virtual bool Next(const void** data, int* size) = 0; + + // Backs up a number of bytes, so that the next call to Next() returns + // data again that was already returned by the last call to Next(). This + // is useful when writing procedures that are only supposed to read up + // to a certain point in the input, then return. If Next() returns a + // buffer that goes beyond what you wanted to read, you can use BackUp() + // to return to the point where you intended to finish. + // + // Preconditions: + // * The last method called must have been Next(). + // * count must be less than or equal to the size of the last buffer + // returned by Next(). + // + // Postconditions: + // * The last "count" bytes of the last buffer returned by Next() will be + // pushed back into the stream. Subsequent calls to Next() will return + // the same data again before producing new data. + virtual void BackUp(int count) = 0; + + // Skips a number of bytes. Returns false if the end of the stream is + // reached or some input error occurred. In the end-of-stream case, the + // stream is advanced to the end of the stream (so ByteCount() will return + // the total size of the stream). + virtual bool Skip(int count) = 0; + + // Returns the total number of bytes read since this object was created. + virtual int64 ByteCount() const = 0; + + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ZeroCopyInputStream); +}; + +// Abstract interface similar to an output stream but designed to minimize +// copying. +class LIBPROTOBUF_EXPORT ZeroCopyOutputStream { + public: + inline ZeroCopyOutputStream() {} + virtual ~ZeroCopyOutputStream(); + + // Obtains a buffer into which data can be written. Any data written + // into this buffer will eventually (maybe instantly, maybe later on) + // be written to the output. + // + // Preconditions: + // * "size" and "data" are not NULL. + // + // Postconditions: + // * If the returned value is false, an error occurred. All errors are + // permanent. + // * Otherwise, "size" points to the actual number of bytes in the buffer + // and "data" points to the buffer. + // * Ownership of this buffer remains with the stream, and the buffer + // remains valid only until some other method of the stream is called + // or the stream is destroyed. + // * Any data which the caller stores in this buffer will eventually be + // written to the output (unless BackUp() is called). + // * It is legal for the returned buffer to have zero size, as long + // as repeatedly calling Next() eventually yields a buffer with non-zero + // size. + virtual bool Next(void** data, int* size) = 0; + + // Backs up a number of bytes, so that the end of the last buffer returned + // by Next() is not actually written. This is needed when you finish + // writing all the data you want to write, but the last buffer was bigger + // than you needed. You don't want to write a bunch of garbage after the + // end of your data, so you use BackUp() to back up. + // + // Preconditions: + // * The last method called must have been Next(). + // * count must be less than or equal to the size of the last buffer + // returned by Next(). + // * The caller must not have written anything to the last "count" bytes + // of that buffer. + // + // Postconditions: + // * The last "count" bytes of the last buffer returned by Next() will be + // ignored. + virtual void BackUp(int count) = 0; + + // Returns the total number of bytes written since this object was created. + virtual int64 ByteCount() const = 0; + + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ZeroCopyOutputStream); +}; + +} // namespace io +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_H__ diff --git a/depends/protobuf/google/protobuf/io/zero_copy_stream_impl.cc b/depends/protobuf/google/protobuf/io/zero_copy_stream_impl.cc new file mode 100644 index 0000000000..1384c746af --- /dev/null +++ b/depends/protobuf/google/protobuf/io/zero_copy_stream_impl.cc @@ -0,0 +1,470 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifdef _MSC_VER +#include +#else +#include +#include +#include +#include +#endif +#include +#include +#include + +#include +#include +#include + +namespace google { +namespace protobuf { +namespace io { + +#ifdef _WIN32 +// Win32 lseek is broken: If invoked on a non-seekable file descriptor, its +// return value is undefined. We re-define it to always produce an error. +#define lseek(fd, offset, origin) ((off_t)-1) +#endif + +namespace { + +// EINTR sucks. +int close_no_eintr(int fd) { + int result; + do { + result = close(fd); + } while (result < 0 && errno == EINTR); + return result; +} + +} // namespace + + +// =================================================================== + +FileInputStream::FileInputStream(int file_descriptor, int block_size) + : copying_input_(file_descriptor), + impl_(©ing_input_, block_size) { +} + +FileInputStream::~FileInputStream() {} + +bool FileInputStream::Close() { + return copying_input_.Close(); +} + +bool FileInputStream::Next(const void** data, int* size) { + return impl_.Next(data, size); +} + +void FileInputStream::BackUp(int count) { + impl_.BackUp(count); +} + +bool FileInputStream::Skip(int count) { + return impl_.Skip(count); +} + +int64 FileInputStream::ByteCount() const { + return impl_.ByteCount(); +} + +FileInputStream::CopyingFileInputStream::CopyingFileInputStream( + int file_descriptor) + : file_(file_descriptor), + close_on_delete_(false), + is_closed_(false), + errno_(0), + previous_seek_failed_(false) { +} + +FileInputStream::CopyingFileInputStream::~CopyingFileInputStream() { + if (close_on_delete_) { + if (!Close()) { + GOOGLE_LOG(ERROR) << "close() failed: " << strerror(errno_); + } + } +} + +bool FileInputStream::CopyingFileInputStream::Close() { + GOOGLE_CHECK(!is_closed_); + + is_closed_ = true; + if (close_no_eintr(file_) != 0) { + // The docs on close() do not specify whether a file descriptor is still + // open after close() fails with EIO. However, the glibc source code + // seems to indicate that it is not. + errno_ = errno; + return false; + } + + return true; +} + +int FileInputStream::CopyingFileInputStream::Read(void* buffer, int size) { + GOOGLE_CHECK(!is_closed_); + + int result; + do { + result = read(file_, buffer, size); + } while (result < 0 && errno == EINTR); + + if (result < 0) { + // Read error (not EOF). + errno_ = errno; + } + + return result; +} + +int FileInputStream::CopyingFileInputStream::Skip(int count) { + GOOGLE_CHECK(!is_closed_); + + if (!previous_seek_failed_ && + lseek(file_, count, SEEK_CUR) != (off_t)-1) { + // Seek succeeded. + return count; + } else { + // Failed to seek. + + // Note to self: Don't seek again. This file descriptor doesn't + // support it. + previous_seek_failed_ = true; + + // Use the default implementation. + return CopyingInputStream::Skip(count); + } +} + +// =================================================================== + +FileOutputStream::FileOutputStream(int file_descriptor, int block_size) + : copying_output_(file_descriptor), + impl_(©ing_output_, block_size) { +} + +FileOutputStream::~FileOutputStream() { + impl_.Flush(); +} + +bool FileOutputStream::Close() { + bool flush_succeeded = impl_.Flush(); + return copying_output_.Close() && flush_succeeded; +} + +bool FileOutputStream::Flush() { + return impl_.Flush(); +} + +bool FileOutputStream::Next(void** data, int* size) { + return impl_.Next(data, size); +} + +void FileOutputStream::BackUp(int count) { + impl_.BackUp(count); +} + +int64 FileOutputStream::ByteCount() const { + return impl_.ByteCount(); +} + +FileOutputStream::CopyingFileOutputStream::CopyingFileOutputStream( + int file_descriptor) + : file_(file_descriptor), + close_on_delete_(false), + is_closed_(false), + errno_(0) { +} + +FileOutputStream::CopyingFileOutputStream::~CopyingFileOutputStream() { + if (close_on_delete_) { + if (!Close()) { + GOOGLE_LOG(ERROR) << "close() failed: " << strerror(errno_); + } + } +} + +bool FileOutputStream::CopyingFileOutputStream::Close() { + GOOGLE_CHECK(!is_closed_); + + is_closed_ = true; + if (close_no_eintr(file_) != 0) { + // The docs on close() do not specify whether a file descriptor is still + // open after close() fails with EIO. However, the glibc source code + // seems to indicate that it is not. + errno_ = errno; + return false; + } + + return true; +} + +bool FileOutputStream::CopyingFileOutputStream::Write( + const void* buffer, int size) { + GOOGLE_CHECK(!is_closed_); + int total_written = 0; + + const uint8* buffer_base = reinterpret_cast(buffer); + + while (total_written < size) { + int bytes; + do { + bytes = write(file_, buffer_base + total_written, size - total_written); + } while (bytes < 0 && errno == EINTR); + + if (bytes <= 0) { + // Write error. + + // FIXME(kenton): According to the man page, if write() returns zero, + // there was no error; write() simply did not write anything. It's + // unclear under what circumstances this might happen, but presumably + // errno won't be set in this case. I am confused as to how such an + // event should be handled. For now I'm treating it as an error, since + // retrying seems like it could lead to an infinite loop. I suspect + // this never actually happens anyway. + + if (bytes < 0) { + errno_ = errno; + } + return false; + } + total_written += bytes; + } + + return true; +} + +// =================================================================== + +IstreamInputStream::IstreamInputStream(istream* input, int block_size) + : copying_input_(input), + impl_(©ing_input_, block_size) { +} + +IstreamInputStream::~IstreamInputStream() {} + +bool IstreamInputStream::Next(const void** data, int* size) { + return impl_.Next(data, size); +} + +void IstreamInputStream::BackUp(int count) { + impl_.BackUp(count); +} + +bool IstreamInputStream::Skip(int count) { + return impl_.Skip(count); +} + +int64 IstreamInputStream::ByteCount() const { + return impl_.ByteCount(); +} + +IstreamInputStream::CopyingIstreamInputStream::CopyingIstreamInputStream( + istream* input) + : input_(input) { +} + +IstreamInputStream::CopyingIstreamInputStream::~CopyingIstreamInputStream() {} + +int IstreamInputStream::CopyingIstreamInputStream::Read( + void* buffer, int size) { + input_->read(reinterpret_cast(buffer), size); + int result = input_->gcount(); + if (result == 0 && input_->fail() && !input_->eof()) { + return -1; + } + return result; +} + +// =================================================================== + +OstreamOutputStream::OstreamOutputStream(ostream* output, int block_size) + : copying_output_(output), + impl_(©ing_output_, block_size) { +} + +OstreamOutputStream::~OstreamOutputStream() { + impl_.Flush(); +} + +bool OstreamOutputStream::Next(void** data, int* size) { + return impl_.Next(data, size); +} + +void OstreamOutputStream::BackUp(int count) { + impl_.BackUp(count); +} + +int64 OstreamOutputStream::ByteCount() const { + return impl_.ByteCount(); +} + +OstreamOutputStream::CopyingOstreamOutputStream::CopyingOstreamOutputStream( + ostream* output) + : output_(output) { +} + +OstreamOutputStream::CopyingOstreamOutputStream::~CopyingOstreamOutputStream() { +} + +bool OstreamOutputStream::CopyingOstreamOutputStream::Write( + const void* buffer, int size) { + output_->write(reinterpret_cast(buffer), size); + return output_->good(); +} + +// =================================================================== + +ConcatenatingInputStream::ConcatenatingInputStream( + ZeroCopyInputStream* const streams[], int count) + : streams_(streams), stream_count_(count), bytes_retired_(0) { +} + +ConcatenatingInputStream::~ConcatenatingInputStream() { +} + +bool ConcatenatingInputStream::Next(const void** data, int* size) { + while (stream_count_ > 0) { + if (streams_[0]->Next(data, size)) return true; + + // That stream is done. Advance to the next one. + bytes_retired_ += streams_[0]->ByteCount(); + ++streams_; + --stream_count_; + } + + // No more streams. + return false; +} + +void ConcatenatingInputStream::BackUp(int count) { + if (stream_count_ > 0) { + streams_[0]->BackUp(count); + } else { + GOOGLE_LOG(DFATAL) << "Can't BackUp() after failed Next()."; + } +} + +bool ConcatenatingInputStream::Skip(int count) { + while (stream_count_ > 0) { + // Assume that ByteCount() can be used to find out how much we actually + // skipped when Skip() fails. + int64 target_byte_count = streams_[0]->ByteCount() + count; + if (streams_[0]->Skip(count)) return true; + + // Hit the end of the stream. Figure out how many more bytes we still have + // to skip. + int64 final_byte_count = streams_[0]->ByteCount(); + GOOGLE_DCHECK_LT(final_byte_count, target_byte_count); + count = target_byte_count - final_byte_count; + + // That stream is done. Advance to the next one. + bytes_retired_ += final_byte_count; + ++streams_; + --stream_count_; + } + + return false; +} + +int64 ConcatenatingInputStream::ByteCount() const { + if (stream_count_ == 0) { + return bytes_retired_; + } else { + return bytes_retired_ + streams_[0]->ByteCount(); + } +} + + +// =================================================================== + +LimitingInputStream::LimitingInputStream(ZeroCopyInputStream* input, + int64 limit) + : input_(input), limit_(limit) {} + +LimitingInputStream::~LimitingInputStream() { + // If we overshot the limit, back up. + if (limit_ < 0) input_->BackUp(-limit_); +} + +bool LimitingInputStream::Next(const void** data, int* size) { + if (limit_ <= 0) return false; + if (!input_->Next(data, size)) return false; + + limit_ -= *size; + if (limit_ < 0) { + // We overshot the limit. Reduce *size to hide the rest of the buffer. + *size += limit_; + } + return true; +} + +void LimitingInputStream::BackUp(int count) { + if (limit_ < 0) { + input_->BackUp(count - limit_); + limit_ = count; + } else { + input_->BackUp(count); + limit_ += count; + } +} + +bool LimitingInputStream::Skip(int count) { + if (count > limit_) { + if (limit_ < 0) return false; + input_->Skip(limit_); + limit_ = 0; + return false; + } else { + if (!input_->Skip(count)) return false; + limit_ -= count; + return true; + } +} + +int64 LimitingInputStream::ByteCount() const { + if (limit_ < 0) { + return input_->ByteCount() + limit_; + } else { + return input_->ByteCount(); + } +} + + +// =================================================================== + +} // namespace io +} // namespace protobuf +} // namespace google diff --git a/depends/protobuf/google/protobuf/io/zero_copy_stream_impl.h b/depends/protobuf/google/protobuf/io/zero_copy_stream_impl.h new file mode 100644 index 0000000000..9fedb00576 --- /dev/null +++ b/depends/protobuf/google/protobuf/io/zero_copy_stream_impl.h @@ -0,0 +1,357 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// This file contains common implementations of the interfaces defined in +// zero_copy_stream.h which are only included in the full (non-lite) +// protobuf library. These implementations include Unix file descriptors +// and C++ iostreams. See also: zero_copy_stream_impl_lite.h + +#ifndef GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_H__ +#define GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_H__ + +#include +#include +#include +#include +#include + + +namespace google { +namespace protobuf { +namespace io { + + +// =================================================================== + +// A ZeroCopyInputStream which reads from a file descriptor. +// +// FileInputStream is preferred over using an ifstream with IstreamInputStream. +// The latter will introduce an extra layer of buffering, harming performance. +// Also, it's conceivable that FileInputStream could someday be enhanced +// to use zero-copy file descriptors on OSs which support them. +class LIBPROTOBUF_EXPORT FileInputStream : public ZeroCopyInputStream { + public: + // Creates a stream that reads from the given Unix file descriptor. + // If a block_size is given, it specifies the number of bytes that + // should be read and returned with each call to Next(). Otherwise, + // a reasonable default is used. + explicit FileInputStream(int file_descriptor, int block_size = -1); + ~FileInputStream(); + + // Flushes any buffers and closes the underlying file. Returns false if + // an error occurs during the process; use GetErrno() to examine the error. + // Even if an error occurs, the file descriptor is closed when this returns. + bool Close(); + + // By default, the file descriptor is not closed when the stream is + // destroyed. Call SetCloseOnDelete(true) to change that. WARNING: + // This leaves no way for the caller to detect if close() fails. If + // detecting close() errors is important to you, you should arrange + // to close the descriptor yourself. + void SetCloseOnDelete(bool value) { copying_input_.SetCloseOnDelete(value); } + + // If an I/O error has occurred on this file descriptor, this is the + // errno from that error. Otherwise, this is zero. Once an error + // occurs, the stream is broken and all subsequent operations will + // fail. + int GetErrno() { return copying_input_.GetErrno(); } + + // implements ZeroCopyInputStream ---------------------------------- + bool Next(const void** data, int* size); + void BackUp(int count); + bool Skip(int count); + int64 ByteCount() const; + + private: + class LIBPROTOBUF_EXPORT CopyingFileInputStream : public CopyingInputStream { + public: + CopyingFileInputStream(int file_descriptor); + ~CopyingFileInputStream(); + + bool Close(); + void SetCloseOnDelete(bool value) { close_on_delete_ = value; } + int GetErrno() { return errno_; } + + // implements CopyingInputStream --------------------------------- + int Read(void* buffer, int size); + int Skip(int count); + + private: + // The file descriptor. + const int file_; + bool close_on_delete_; + bool is_closed_; + + // The errno of the I/O error, if one has occurred. Otherwise, zero. + int errno_; + + // Did we try to seek once and fail? If so, we assume this file descriptor + // doesn't support seeking and won't try again. + bool previous_seek_failed_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CopyingFileInputStream); + }; + + CopyingFileInputStream copying_input_; + CopyingInputStreamAdaptor impl_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileInputStream); +}; + +// =================================================================== + +// A ZeroCopyOutputStream which writes to a file descriptor. +// +// FileOutputStream is preferred over using an ofstream with +// OstreamOutputStream. The latter will introduce an extra layer of buffering, +// harming performance. Also, it's conceivable that FileOutputStream could +// someday be enhanced to use zero-copy file descriptors on OSs which +// support them. +class LIBPROTOBUF_EXPORT FileOutputStream : public ZeroCopyOutputStream { + public: + // Creates a stream that writes to the given Unix file descriptor. + // If a block_size is given, it specifies the size of the buffers + // that should be returned by Next(). Otherwise, a reasonable default + // is used. + explicit FileOutputStream(int file_descriptor, int block_size = -1); + ~FileOutputStream(); + + // Flushes any buffers and closes the underlying file. Returns false if + // an error occurs during the process; use GetErrno() to examine the error. + // Even if an error occurs, the file descriptor is closed when this returns. + bool Close(); + + // Flushes FileOutputStream's buffers but does not close the + // underlying file. No special measures are taken to ensure that + // underlying operating system file object is synchronized to disk. + bool Flush(); + + // By default, the file descriptor is not closed when the stream is + // destroyed. Call SetCloseOnDelete(true) to change that. WARNING: + // This leaves no way for the caller to detect if close() fails. If + // detecting close() errors is important to you, you should arrange + // to close the descriptor yourself. + void SetCloseOnDelete(bool value) { copying_output_.SetCloseOnDelete(value); } + + // If an I/O error has occurred on this file descriptor, this is the + // errno from that error. Otherwise, this is zero. Once an error + // occurs, the stream is broken and all subsequent operations will + // fail. + int GetErrno() { return copying_output_.GetErrno(); } + + // implements ZeroCopyOutputStream --------------------------------- + bool Next(void** data, int* size); + void BackUp(int count); + int64 ByteCount() const; + + private: + class LIBPROTOBUF_EXPORT CopyingFileOutputStream : public CopyingOutputStream { + public: + CopyingFileOutputStream(int file_descriptor); + ~CopyingFileOutputStream(); + + bool Close(); + void SetCloseOnDelete(bool value) { close_on_delete_ = value; } + int GetErrno() { return errno_; } + + // implements CopyingOutputStream -------------------------------- + bool Write(const void* buffer, int size); + + private: + // The file descriptor. + const int file_; + bool close_on_delete_; + bool is_closed_; + + // The errno of the I/O error, if one has occurred. Otherwise, zero. + int errno_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CopyingFileOutputStream); + }; + + CopyingFileOutputStream copying_output_; + CopyingOutputStreamAdaptor impl_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileOutputStream); +}; + +// =================================================================== + +// A ZeroCopyInputStream which reads from a C++ istream. +// +// Note that for reading files (or anything represented by a file descriptor), +// FileInputStream is more efficient. +class LIBPROTOBUF_EXPORT IstreamInputStream : public ZeroCopyInputStream { + public: + // Creates a stream that reads from the given C++ istream. + // If a block_size is given, it specifies the number of bytes that + // should be read and returned with each call to Next(). Otherwise, + // a reasonable default is used. + explicit IstreamInputStream(istream* stream, int block_size = -1); + ~IstreamInputStream(); + + // implements ZeroCopyInputStream ---------------------------------- + bool Next(const void** data, int* size); + void BackUp(int count); + bool Skip(int count); + int64 ByteCount() const; + + private: + class LIBPROTOBUF_EXPORT CopyingIstreamInputStream : public CopyingInputStream { + public: + CopyingIstreamInputStream(istream* input); + ~CopyingIstreamInputStream(); + + // implements CopyingInputStream --------------------------------- + int Read(void* buffer, int size); + // (We use the default implementation of Skip().) + + private: + // The stream. + istream* input_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CopyingIstreamInputStream); + }; + + CopyingIstreamInputStream copying_input_; + CopyingInputStreamAdaptor impl_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(IstreamInputStream); +}; + +// =================================================================== + +// A ZeroCopyOutputStream which writes to a C++ ostream. +// +// Note that for writing files (or anything represented by a file descriptor), +// FileOutputStream is more efficient. +class LIBPROTOBUF_EXPORT OstreamOutputStream : public ZeroCopyOutputStream { + public: + // Creates a stream that writes to the given C++ ostream. + // If a block_size is given, it specifies the size of the buffers + // that should be returned by Next(). Otherwise, a reasonable default + // is used. + explicit OstreamOutputStream(ostream* stream, int block_size = -1); + ~OstreamOutputStream(); + + // implements ZeroCopyOutputStream --------------------------------- + bool Next(void** data, int* size); + void BackUp(int count); + int64 ByteCount() const; + + private: + class LIBPROTOBUF_EXPORT CopyingOstreamOutputStream : public CopyingOutputStream { + public: + CopyingOstreamOutputStream(ostream* output); + ~CopyingOstreamOutputStream(); + + // implements CopyingOutputStream -------------------------------- + bool Write(const void* buffer, int size); + + private: + // The stream. + ostream* output_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CopyingOstreamOutputStream); + }; + + CopyingOstreamOutputStream copying_output_; + CopyingOutputStreamAdaptor impl_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(OstreamOutputStream); +}; + +// =================================================================== + +// A ZeroCopyInputStream which reads from several other streams in sequence. +// ConcatenatingInputStream is unable to distinguish between end-of-stream +// and read errors in the underlying streams, so it assumes any errors mean +// end-of-stream. So, if the underlying streams fail for any other reason, +// ConcatenatingInputStream may do odd things. It is suggested that you do +// not use ConcatenatingInputStream on streams that might produce read errors +// other than end-of-stream. +class LIBPROTOBUF_EXPORT ConcatenatingInputStream : public ZeroCopyInputStream { + public: + // All streams passed in as well as the array itself must remain valid + // until the ConcatenatingInputStream is destroyed. + ConcatenatingInputStream(ZeroCopyInputStream* const streams[], int count); + ~ConcatenatingInputStream(); + + // implements ZeroCopyInputStream ---------------------------------- + bool Next(const void** data, int* size); + void BackUp(int count); + bool Skip(int count); + int64 ByteCount() const; + + + private: + // As streams are retired, streams_ is incremented and count_ is + // decremented. + ZeroCopyInputStream* const* streams_; + int stream_count_; + int64 bytes_retired_; // Bytes read from previous streams. + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ConcatenatingInputStream); +}; + +// =================================================================== + +// A ZeroCopyInputStream which wraps some other stream and limits it to +// a particular byte count. +class LIBPROTOBUF_EXPORT LimitingInputStream : public ZeroCopyInputStream { + public: + LimitingInputStream(ZeroCopyInputStream* input, int64 limit); + ~LimitingInputStream(); + + // implements ZeroCopyInputStream ---------------------------------- + bool Next(const void** data, int* size); + void BackUp(int count); + bool Skip(int count); + int64 ByteCount() const; + + + private: + ZeroCopyInputStream* input_; + int64 limit_; // Decreases as we go, becomes negative if we overshoot. + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(LimitingInputStream); +}; + +// =================================================================== + +} // namespace io +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_H__ diff --git a/depends/protobuf/google/protobuf/io/zero_copy_stream_impl_lite.cc b/depends/protobuf/google/protobuf/io/zero_copy_stream_impl_lite.cc new file mode 100644 index 0000000000..e80125109f --- /dev/null +++ b/depends/protobuf/google/protobuf/io/zero_copy_stream_impl_lite.cc @@ -0,0 +1,393 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include +#include +#include + +namespace google { +namespace protobuf { +namespace io { + +namespace { + +// Default block size for Copying{In,Out}putStreamAdaptor. +static const int kDefaultBlockSize = 8192; + +} // namespace + +// =================================================================== + +ArrayInputStream::ArrayInputStream(const void* data, int size, + int block_size) + : data_(reinterpret_cast(data)), + size_(size), + block_size_(block_size > 0 ? block_size : size), + position_(0), + last_returned_size_(0) { +} + +ArrayInputStream::~ArrayInputStream() { +} + +bool ArrayInputStream::Next(const void** data, int* size) { + if (position_ < size_) { + last_returned_size_ = min(block_size_, size_ - position_); + *data = data_ + position_; + *size = last_returned_size_; + position_ += last_returned_size_; + return true; + } else { + // We're at the end of the array. + last_returned_size_ = 0; // Don't let caller back up. + return false; + } +} + +void ArrayInputStream::BackUp(int count) { + GOOGLE_CHECK_GT(last_returned_size_, 0) + << "BackUp() can only be called after a successful Next()."; + GOOGLE_CHECK_LE(count, last_returned_size_); + GOOGLE_CHECK_GE(count, 0); + position_ -= count; + last_returned_size_ = 0; // Don't let caller back up further. +} + +bool ArrayInputStream::Skip(int count) { + GOOGLE_CHECK_GE(count, 0); + last_returned_size_ = 0; // Don't let caller back up. + if (count > size_ - position_) { + position_ = size_; + return false; + } else { + position_ += count; + return true; + } +} + +int64 ArrayInputStream::ByteCount() const { + return position_; +} + + +// =================================================================== + +ArrayOutputStream::ArrayOutputStream(void* data, int size, int block_size) + : data_(reinterpret_cast(data)), + size_(size), + block_size_(block_size > 0 ? block_size : size), + position_(0), + last_returned_size_(0) { +} + +ArrayOutputStream::~ArrayOutputStream() { +} + +bool ArrayOutputStream::Next(void** data, int* size) { + if (position_ < size_) { + last_returned_size_ = min(block_size_, size_ - position_); + *data = data_ + position_; + *size = last_returned_size_; + position_ += last_returned_size_; + return true; + } else { + // We're at the end of the array. + last_returned_size_ = 0; // Don't let caller back up. + return false; + } +} + +void ArrayOutputStream::BackUp(int count) { + GOOGLE_CHECK_GT(last_returned_size_, 0) + << "BackUp() can only be called after a successful Next()."; + GOOGLE_CHECK_LE(count, last_returned_size_); + GOOGLE_CHECK_GE(count, 0); + position_ -= count; + last_returned_size_ = 0; // Don't let caller back up further. +} + +int64 ArrayOutputStream::ByteCount() const { + return position_; +} + +// =================================================================== + +StringOutputStream::StringOutputStream(string* target) + : target_(target) { +} + +StringOutputStream::~StringOutputStream() { +} + +bool StringOutputStream::Next(void** data, int* size) { + int old_size = target_->size(); + + // Grow the string. + if (old_size < target_->capacity()) { + // Resize the string to match its capacity, since we can get away + // without a memory allocation this way. + STLStringResizeUninitialized(target_, target_->capacity()); + } else { + // Size has reached capacity, so double the size. Also make sure + // that the new size is at least kMinimumSize. + STLStringResizeUninitialized( + target_, + max(old_size * 2, + kMinimumSize + 0)); // "+ 0" works around GCC4 weirdness. + } + + *data = string_as_array(target_) + old_size; + *size = target_->size() - old_size; + return true; +} + +void StringOutputStream::BackUp(int count) { + GOOGLE_CHECK_GE(count, 0); + GOOGLE_CHECK_LE(count, target_->size()); + target_->resize(target_->size() - count); +} + +int64 StringOutputStream::ByteCount() const { + return target_->size(); +} + +// =================================================================== + +CopyingInputStream::~CopyingInputStream() {} + +int CopyingInputStream::Skip(int count) { + char junk[4096]; + int skipped = 0; + while (skipped < count) { + int bytes = Read(junk, min(count - skipped, + implicit_cast(sizeof(junk)))); + if (bytes <= 0) { + // EOF or read error. + return skipped; + } + skipped += bytes; + } + return skipped; +} + +CopyingInputStreamAdaptor::CopyingInputStreamAdaptor( + CopyingInputStream* copying_stream, int block_size) + : copying_stream_(copying_stream), + owns_copying_stream_(false), + failed_(false), + position_(0), + buffer_size_(block_size > 0 ? block_size : kDefaultBlockSize), + buffer_used_(0), + backup_bytes_(0) { +} + +CopyingInputStreamAdaptor::~CopyingInputStreamAdaptor() { + if (owns_copying_stream_) { + delete copying_stream_; + } +} + +bool CopyingInputStreamAdaptor::Next(const void** data, int* size) { + if (failed_) { + // Already failed on a previous read. + return false; + } + + AllocateBufferIfNeeded(); + + if (backup_bytes_ > 0) { + // We have data left over from a previous BackUp(), so just return that. + *data = buffer_.get() + buffer_used_ - backup_bytes_; + *size = backup_bytes_; + backup_bytes_ = 0; + return true; + } + + // Read new data into the buffer. + buffer_used_ = copying_stream_->Read(buffer_.get(), buffer_size_); + if (buffer_used_ <= 0) { + // EOF or read error. We don't need the buffer anymore. + if (buffer_used_ < 0) { + // Read error (not EOF). + failed_ = true; + } + FreeBuffer(); + return false; + } + position_ += buffer_used_; + + *size = buffer_used_; + *data = buffer_.get(); + return true; +} + +void CopyingInputStreamAdaptor::BackUp(int count) { + GOOGLE_CHECK(backup_bytes_ == 0 && buffer_.get() != NULL) + << " BackUp() can only be called after Next()."; + GOOGLE_CHECK_LE(count, buffer_used_) + << " Can't back up over more bytes than were returned by the last call" + " to Next()."; + GOOGLE_CHECK_GE(count, 0) + << " Parameter to BackUp() can't be negative."; + + backup_bytes_ = count; +} + +bool CopyingInputStreamAdaptor::Skip(int count) { + GOOGLE_CHECK_GE(count, 0); + + if (failed_) { + // Already failed on a previous read. + return false; + } + + // First skip any bytes left over from a previous BackUp(). + if (backup_bytes_ >= count) { + // We have more data left over than we're trying to skip. Just chop it. + backup_bytes_ -= count; + return true; + } + + count -= backup_bytes_; + backup_bytes_ = 0; + + int skipped = copying_stream_->Skip(count); + position_ += skipped; + return skipped == count; +} + +int64 CopyingInputStreamAdaptor::ByteCount() const { + return position_ - backup_bytes_; +} + +void CopyingInputStreamAdaptor::AllocateBufferIfNeeded() { + if (buffer_.get() == NULL) { + buffer_.reset(new uint8[buffer_size_]); + } +} + +void CopyingInputStreamAdaptor::FreeBuffer() { + GOOGLE_CHECK_EQ(backup_bytes_, 0); + buffer_used_ = 0; + buffer_.reset(); +} + +// =================================================================== + +CopyingOutputStream::~CopyingOutputStream() {} + +CopyingOutputStreamAdaptor::CopyingOutputStreamAdaptor( + CopyingOutputStream* copying_stream, int block_size) + : copying_stream_(copying_stream), + owns_copying_stream_(false), + failed_(false), + position_(0), + buffer_size_(block_size > 0 ? block_size : kDefaultBlockSize), + buffer_used_(0) { +} + +CopyingOutputStreamAdaptor::~CopyingOutputStreamAdaptor() { + WriteBuffer(); + if (owns_copying_stream_) { + delete copying_stream_; + } +} + +bool CopyingOutputStreamAdaptor::Flush() { + return WriteBuffer(); +} + +bool CopyingOutputStreamAdaptor::Next(void** data, int* size) { + if (buffer_used_ == buffer_size_) { + if (!WriteBuffer()) return false; + } + + AllocateBufferIfNeeded(); + + *data = buffer_.get() + buffer_used_; + *size = buffer_size_ - buffer_used_; + buffer_used_ = buffer_size_; + return true; +} + +void CopyingOutputStreamAdaptor::BackUp(int count) { + GOOGLE_CHECK_GE(count, 0); + GOOGLE_CHECK_EQ(buffer_used_, buffer_size_) + << " BackUp() can only be called after Next()."; + GOOGLE_CHECK_LE(count, buffer_used_) + << " Can't back up over more bytes than were returned by the last call" + " to Next()."; + + buffer_used_ -= count; +} + +int64 CopyingOutputStreamAdaptor::ByteCount() const { + return position_ + buffer_used_; +} + +bool CopyingOutputStreamAdaptor::WriteBuffer() { + if (failed_) { + // Already failed on a previous write. + return false; + } + + if (buffer_used_ == 0) return true; + + if (copying_stream_->Write(buffer_.get(), buffer_used_)) { + position_ += buffer_used_; + buffer_used_ = 0; + return true; + } else { + failed_ = true; + FreeBuffer(); + return false; + } +} + +void CopyingOutputStreamAdaptor::AllocateBufferIfNeeded() { + if (buffer_ == NULL) { + buffer_.reset(new uint8[buffer_size_]); + } +} + +void CopyingOutputStreamAdaptor::FreeBuffer() { + buffer_used_ = 0; + buffer_.reset(); +} + +// =================================================================== + +} // namespace io +} // namespace protobuf +} // namespace google diff --git a/depends/protobuf/google/protobuf/io/zero_copy_stream_impl_lite.h b/depends/protobuf/google/protobuf/io/zero_copy_stream_impl_lite.h new file mode 100644 index 0000000000..153f543ee4 --- /dev/null +++ b/depends/protobuf/google/protobuf/io/zero_copy_stream_impl_lite.h @@ -0,0 +1,340 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// This file contains common implementations of the interfaces defined in +// zero_copy_stream.h which are included in the "lite" protobuf library. +// These implementations cover I/O on raw arrays and strings, as well as +// adaptors which make it easy to implement streams based on traditional +// streams. Of course, many users will probably want to write their own +// implementations of these interfaces specific to the particular I/O +// abstractions they prefer to use, but these should cover the most common +// cases. + +#ifndef GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_LITE_H__ +#define GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_LITE_H__ + +#include +#include +#include +#include + + +namespace google { +namespace protobuf { +namespace io { + +// =================================================================== + +// A ZeroCopyInputStream backed by an in-memory array of bytes. +class LIBPROTOBUF_EXPORT ArrayInputStream : public ZeroCopyInputStream { + public: + // Create an InputStream that returns the bytes pointed to by "data". + // "data" remains the property of the caller but must remain valid until + // the stream is destroyed. If a block_size is given, calls to Next() + // will return data blocks no larger than the given size. Otherwise, the + // first call to Next() returns the entire array. block_size is mainly + // useful for testing; in production you would probably never want to set + // it. + ArrayInputStream(const void* data, int size, int block_size = -1); + ~ArrayInputStream(); + + // implements ZeroCopyInputStream ---------------------------------- + bool Next(const void** data, int* size); + void BackUp(int count); + bool Skip(int count); + int64 ByteCount() const; + + + private: + const uint8* const data_; // The byte array. + const int size_; // Total size of the array. + const int block_size_; // How many bytes to return at a time. + + int position_; + int last_returned_size_; // How many bytes we returned last time Next() + // was called (used for error checking only). + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ArrayInputStream); +}; + +// =================================================================== + +// A ZeroCopyOutputStream backed by an in-memory array of bytes. +class LIBPROTOBUF_EXPORT ArrayOutputStream : public ZeroCopyOutputStream { + public: + // Create an OutputStream that writes to the bytes pointed to by "data". + // "data" remains the property of the caller but must remain valid until + // the stream is destroyed. If a block_size is given, calls to Next() + // will return data blocks no larger than the given size. Otherwise, the + // first call to Next() returns the entire array. block_size is mainly + // useful for testing; in production you would probably never want to set + // it. + ArrayOutputStream(void* data, int size, int block_size = -1); + ~ArrayOutputStream(); + + // implements ZeroCopyOutputStream --------------------------------- + bool Next(void** data, int* size); + void BackUp(int count); + int64 ByteCount() const; + + private: + uint8* const data_; // The byte array. + const int size_; // Total size of the array. + const int block_size_; // How many bytes to return at a time. + + int position_; + int last_returned_size_; // How many bytes we returned last time Next() + // was called (used for error checking only). + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ArrayOutputStream); +}; + +// =================================================================== + +// A ZeroCopyOutputStream which appends bytes to a string. +class LIBPROTOBUF_EXPORT StringOutputStream : public ZeroCopyOutputStream { + public: + // Create a StringOutputStream which appends bytes to the given string. + // The string remains property of the caller, but it MUST NOT be accessed + // in any way until the stream is destroyed. + // + // Hint: If you call target->reserve(n) before creating the stream, + // the first call to Next() will return at least n bytes of buffer + // space. + explicit StringOutputStream(string* target); + ~StringOutputStream(); + + // implements ZeroCopyOutputStream --------------------------------- + bool Next(void** data, int* size); + void BackUp(int count); + int64 ByteCount() const; + + private: + static const int kMinimumSize = 16; + + string* target_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringOutputStream); +}; + +// Note: There is no StringInputStream. Instead, just create an +// ArrayInputStream as follows: +// ArrayInputStream input(str.data(), str.size()); + +// =================================================================== + +// A generic traditional input stream interface. +// +// Lots of traditional input streams (e.g. file descriptors, C stdio +// streams, and C++ iostreams) expose an interface where every read +// involves copying bytes into a buffer. If you want to take such an +// interface and make a ZeroCopyInputStream based on it, simply implement +// CopyingInputStream and then use CopyingInputStreamAdaptor. +// +// CopyingInputStream implementations should avoid buffering if possible. +// CopyingInputStreamAdaptor does its own buffering and will read data +// in large blocks. +class LIBPROTOBUF_EXPORT CopyingInputStream { + public: + virtual ~CopyingInputStream(); + + // Reads up to "size" bytes into the given buffer. Returns the number of + // bytes read. Read() waits until at least one byte is available, or + // returns zero if no bytes will ever become available (EOF), or -1 if a + // permanent read error occurred. + virtual int Read(void* buffer, int size) = 0; + + // Skips the next "count" bytes of input. Returns the number of bytes + // actually skipped. This will always be exactly equal to "count" unless + // EOF was reached or a permanent read error occurred. + // + // The default implementation just repeatedly calls Read() into a scratch + // buffer. + virtual int Skip(int count); +}; + +// A ZeroCopyInputStream which reads from a CopyingInputStream. This is +// useful for implementing ZeroCopyInputStreams that read from traditional +// streams. Note that this class is not really zero-copy. +// +// If you want to read from file descriptors or C++ istreams, this is +// already implemented for you: use FileInputStream or IstreamInputStream +// respectively. +class LIBPROTOBUF_EXPORT CopyingInputStreamAdaptor : public ZeroCopyInputStream { + public: + // Creates a stream that reads from the given CopyingInputStream. + // If a block_size is given, it specifies the number of bytes that + // should be read and returned with each call to Next(). Otherwise, + // a reasonable default is used. The caller retains ownership of + // copying_stream unless SetOwnsCopyingStream(true) is called. + explicit CopyingInputStreamAdaptor(CopyingInputStream* copying_stream, + int block_size = -1); + ~CopyingInputStreamAdaptor(); + + // Call SetOwnsCopyingStream(true) to tell the CopyingInputStreamAdaptor to + // delete the underlying CopyingInputStream when it is destroyed. + void SetOwnsCopyingStream(bool value) { owns_copying_stream_ = value; } + + // implements ZeroCopyInputStream ---------------------------------- + bool Next(const void** data, int* size); + void BackUp(int count); + bool Skip(int count); + int64 ByteCount() const; + + private: + // Insures that buffer_ is not NULL. + void AllocateBufferIfNeeded(); + // Frees the buffer and resets buffer_used_. + void FreeBuffer(); + + // The underlying copying stream. + CopyingInputStream* copying_stream_; + bool owns_copying_stream_; + + // True if we have seen a permenant error from the underlying stream. + bool failed_; + + // The current position of copying_stream_, relative to the point where + // we started reading. + int64 position_; + + // Data is read into this buffer. It may be NULL if no buffer is currently + // in use. Otherwise, it points to an array of size buffer_size_. + scoped_array buffer_; + const int buffer_size_; + + // Number of valid bytes currently in the buffer (i.e. the size last + // returned by Next()). 0 <= buffer_used_ <= buffer_size_. + int buffer_used_; + + // Number of bytes in the buffer which were backed up over by a call to + // BackUp(). These need to be returned again. + // 0 <= backup_bytes_ <= buffer_used_ + int backup_bytes_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CopyingInputStreamAdaptor); +}; + +// =================================================================== + +// A generic traditional output stream interface. +// +// Lots of traditional output streams (e.g. file descriptors, C stdio +// streams, and C++ iostreams) expose an interface where every write +// involves copying bytes from a buffer. If you want to take such an +// interface and make a ZeroCopyOutputStream based on it, simply implement +// CopyingOutputStream and then use CopyingOutputStreamAdaptor. +// +// CopyingOutputStream implementations should avoid buffering if possible. +// CopyingOutputStreamAdaptor does its own buffering and will write data +// in large blocks. +class LIBPROTOBUF_EXPORT CopyingOutputStream { + public: + virtual ~CopyingOutputStream(); + + // Writes "size" bytes from the given buffer to the output. Returns true + // if successful, false on a write error. + virtual bool Write(const void* buffer, int size) = 0; +}; + +// A ZeroCopyOutputStream which writes to a CopyingOutputStream. This is +// useful for implementing ZeroCopyOutputStreams that write to traditional +// streams. Note that this class is not really zero-copy. +// +// If you want to write to file descriptors or C++ ostreams, this is +// already implemented for you: use FileOutputStream or OstreamOutputStream +// respectively. +class LIBPROTOBUF_EXPORT CopyingOutputStreamAdaptor : public ZeroCopyOutputStream { + public: + // Creates a stream that writes to the given Unix file descriptor. + // If a block_size is given, it specifies the size of the buffers + // that should be returned by Next(). Otherwise, a reasonable default + // is used. + explicit CopyingOutputStreamAdaptor(CopyingOutputStream* copying_stream, + int block_size = -1); + ~CopyingOutputStreamAdaptor(); + + // Writes all pending data to the underlying stream. Returns false if a + // write error occurred on the underlying stream. (The underlying + // stream itself is not necessarily flushed.) + bool Flush(); + + // Call SetOwnsCopyingStream(true) to tell the CopyingOutputStreamAdaptor to + // delete the underlying CopyingOutputStream when it is destroyed. + void SetOwnsCopyingStream(bool value) { owns_copying_stream_ = value; } + + // implements ZeroCopyOutputStream --------------------------------- + bool Next(void** data, int* size); + void BackUp(int count); + int64 ByteCount() const; + + private: + // Write the current buffer, if it is present. + bool WriteBuffer(); + // Insures that buffer_ is not NULL. + void AllocateBufferIfNeeded(); + // Frees the buffer. + void FreeBuffer(); + + // The underlying copying stream. + CopyingOutputStream* copying_stream_; + bool owns_copying_stream_; + + // True if we have seen a permenant error from the underlying stream. + bool failed_; + + // The current position of copying_stream_, relative to the point where + // we started writing. + int64 position_; + + // Data is written from this buffer. It may be NULL if no buffer is + // currently in use. Otherwise, it points to an array of size buffer_size_. + scoped_array buffer_; + const int buffer_size_; + + // Number of valid bytes currently in the buffer (i.e. the size last + // returned by Next()). When BackUp() is called, we just reduce this. + // 0 <= buffer_used_ <= buffer_size_. + int buffer_used_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CopyingOutputStreamAdaptor); +}; + +// =================================================================== + +} // namespace io +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_LITE_H__ diff --git a/depends/protobuf/google/protobuf/message.cc b/depends/protobuf/google/protobuf/message.cc new file mode 100644 index 0000000000..37db6a4852 --- /dev/null +++ b/depends/protobuf/google/protobuf/message.cc @@ -0,0 +1,319 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { + +using internal::WireFormat; +using internal::ReflectionOps; + +Message::~Message() {} + +void Message::MergeFrom(const Message& from) { + const Descriptor* descriptor = GetDescriptor(); + GOOGLE_CHECK_EQ(from.GetDescriptor(), descriptor) + << ": Tried to merge from a message with a different type. " + "to: " << descriptor->full_name() << ", " + "from:" << from.GetDescriptor()->full_name(); + ReflectionOps::Merge(from, this); +} + +void Message::CheckTypeAndMergeFrom(const MessageLite& other) { + MergeFrom(*down_cast(&other)); +} + +void Message::CopyFrom(const Message& from) { + const Descriptor* descriptor = GetDescriptor(); + GOOGLE_CHECK_EQ(from.GetDescriptor(), descriptor) + << ": Tried to copy from a message with a different type." + "to: " << descriptor->full_name() << ", " + "from:" << from.GetDescriptor()->full_name(); + ReflectionOps::Copy(from, this); +} + +string Message::GetTypeName() const { + return GetDescriptor()->full_name(); +} + +void Message::Clear() { + ReflectionOps::Clear(this); +} + +bool Message::IsInitialized() const { + return ReflectionOps::IsInitialized(*this); +} + +void Message::FindInitializationErrors(vector* errors) const { + return ReflectionOps::FindInitializationErrors(*this, "", errors); +} + +string Message::InitializationErrorString() const { + vector errors; + FindInitializationErrors(&errors); + return JoinStrings(errors, ", "); +} + +void Message::CheckInitialized() const { + GOOGLE_CHECK(IsInitialized()) + << "Message of type \"" << GetDescriptor()->full_name() + << "\" is missing required fields: " << InitializationErrorString(); +} + +void Message::DiscardUnknownFields() { + return ReflectionOps::DiscardUnknownFields(this); +} + +bool Message::MergePartialFromCodedStream(io::CodedInputStream* input) { + return WireFormat::ParseAndMergePartial(input, this); +} + +bool Message::ParseFromFileDescriptor(int file_descriptor) { + io::FileInputStream input(file_descriptor); + return ParseFromZeroCopyStream(&input) && input.GetErrno() == 0; +} + +bool Message::ParsePartialFromFileDescriptor(int file_descriptor) { + io::FileInputStream input(file_descriptor); + return ParsePartialFromZeroCopyStream(&input) && input.GetErrno() == 0; +} + +bool Message::ParseFromIstream(istream* input) { + io::IstreamInputStream zero_copy_input(input); + return ParseFromZeroCopyStream(&zero_copy_input) && input->eof(); +} + +bool Message::ParsePartialFromIstream(istream* input) { + io::IstreamInputStream zero_copy_input(input); + return ParsePartialFromZeroCopyStream(&zero_copy_input) && input->eof(); +} + + +void Message::SerializeWithCachedSizes( + io::CodedOutputStream* output) const { + WireFormat::SerializeWithCachedSizes(*this, GetCachedSize(), output); +} + +int Message::ByteSize() const { + int size = WireFormat::ByteSize(*this); + SetCachedSize(size); + return size; +} + +void Message::SetCachedSize(int size) const { + GOOGLE_LOG(FATAL) << "Message class \"" << GetDescriptor()->full_name() + << "\" implements neither SetCachedSize() nor ByteSize(). " + "Must implement one or the other."; +} + +int Message::SpaceUsed() const { + return GetReflection()->SpaceUsed(*this); +} + +bool Message::SerializeToFileDescriptor(int file_descriptor) const { + io::FileOutputStream output(file_descriptor); + return SerializeToZeroCopyStream(&output); +} + +bool Message::SerializePartialToFileDescriptor(int file_descriptor) const { + io::FileOutputStream output(file_descriptor); + return SerializePartialToZeroCopyStream(&output); +} + +bool Message::SerializeToOstream(ostream* output) const { + { + io::OstreamOutputStream zero_copy_output(output); + if (!SerializeToZeroCopyStream(&zero_copy_output)) return false; + } + return output->good(); +} + +bool Message::SerializePartialToOstream(ostream* output) const { + io::OstreamOutputStream zero_copy_output(output); + return SerializePartialToZeroCopyStream(&zero_copy_output); +} + + +Reflection::~Reflection() {} + +// =================================================================== +// MessageFactory + +MessageFactory::~MessageFactory() {} + +namespace { + +class GeneratedMessageFactory : public MessageFactory { + public: + GeneratedMessageFactory(); + ~GeneratedMessageFactory(); + + static GeneratedMessageFactory* singleton(); + + typedef void RegistrationFunc(const string&); + void RegisterFile(const char* file, RegistrationFunc* registration_func); + void RegisterType(const Descriptor* descriptor, const Message* prototype); + + // implements MessageFactory --------------------------------------- + const Message* GetPrototype(const Descriptor* type); + + private: + // Only written at static init time, so does not require locking. + hash_map, streq> file_map_; + + // Initialized lazily, so requires locking. + Mutex mutex_; + hash_map type_map_; +}; + +GeneratedMessageFactory* generated_message_factory_ = NULL; +GOOGLE_PROTOBUF_DECLARE_ONCE(generated_message_factory_once_init_); + +void ShutdownGeneratedMessageFactory() { + delete generated_message_factory_; +} + +void InitGeneratedMessageFactory() { + generated_message_factory_ = new GeneratedMessageFactory; + internal::OnShutdown(&ShutdownGeneratedMessageFactory); +} + +GeneratedMessageFactory::GeneratedMessageFactory() {} +GeneratedMessageFactory::~GeneratedMessageFactory() {} + +GeneratedMessageFactory* GeneratedMessageFactory::singleton() { + ::google::protobuf::GoogleOnceInit(&generated_message_factory_once_init_, + &InitGeneratedMessageFactory); + return generated_message_factory_; +} + +void GeneratedMessageFactory::RegisterFile( + const char* file, RegistrationFunc* registration_func) { + if (!InsertIfNotPresent(&file_map_, file, registration_func)) { + GOOGLE_LOG(FATAL) << "File is already registered: " << file; + } +} + +void GeneratedMessageFactory::RegisterType(const Descriptor* descriptor, + const Message* prototype) { + GOOGLE_DCHECK_EQ(descriptor->file()->pool(), DescriptorPool::generated_pool()) + << "Tried to register a non-generated type with the generated " + "type registry."; + + // This should only be called as a result of calling a file registration + // function during GetPrototype(), in which case we already have locked + // the mutex. + mutex_.AssertHeld(); + if (!InsertIfNotPresent(&type_map_, descriptor, prototype)) { + GOOGLE_LOG(DFATAL) << "Type is already registered: " << descriptor->full_name(); + } +} + +const Message* GeneratedMessageFactory::GetPrototype(const Descriptor* type) { + { + ReaderMutexLock lock(&mutex_); + const Message* result = FindPtrOrNull(type_map_, type); + if (result != NULL) return result; + } + + // If the type is not in the generated pool, then we can't possibly handle + // it. + if (type->file()->pool() != DescriptorPool::generated_pool()) return NULL; + + // Apparently the file hasn't been registered yet. Let's do that now. + RegistrationFunc* registration_func = + FindPtrOrNull(file_map_, type->file()->name().c_str()); + if (registration_func == NULL) { + GOOGLE_LOG(DFATAL) << "File appears to be in generated pool but wasn't " + "registered: " << type->file()->name(); + return NULL; + } + + WriterMutexLock lock(&mutex_); + + // Check if another thread preempted us. + const Message* result = FindPtrOrNull(type_map_, type); + if (result == NULL) { + // Nope. OK, register everything. + registration_func(type->file()->name()); + // Should be here now. + result = FindPtrOrNull(type_map_, type); + } + + if (result == NULL) { + GOOGLE_LOG(DFATAL) << "Type appears to be in generated pool but wasn't " + << "registered: " << type->full_name(); + } + + return result; +} + +} // namespace + +MessageFactory* MessageFactory::generated_factory() { + return GeneratedMessageFactory::singleton(); +} + +void MessageFactory::InternalRegisterGeneratedFile( + const char* filename, void (*register_messages)(const string&)) { + GeneratedMessageFactory::singleton()->RegisterFile(filename, + register_messages); +} + +void MessageFactory::InternalRegisterGeneratedMessage( + const Descriptor* descriptor, const Message* prototype) { + GeneratedMessageFactory::singleton()->RegisterType(descriptor, prototype); +} + + +} // namespace protobuf +} // namespace google diff --git a/depends/protobuf/google/protobuf/message.h b/depends/protobuf/google/protobuf/message.h new file mode 100644 index 0000000000..4bbc641832 --- /dev/null +++ b/depends/protobuf/google/protobuf/message.h @@ -0,0 +1,692 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// Defines Message, the abstract interface implemented by non-lite +// protocol message objects. Although it's possible to implement this +// interface manually, most users will use the protocol compiler to +// generate implementations. +// +// Example usage: +// +// Say you have a message defined as: +// +// message Foo { +// optional string text = 1; +// repeated int32 numbers = 2; +// } +// +// Then, if you used the protocol compiler to generate a class from the above +// definition, you could use it like so: +// +// string data; // Will store a serialized version of the message. +// +// { +// // Create a message and serialize it. +// Foo foo; +// foo.set_text("Hello World!"); +// foo.add_numbers(1); +// foo.add_numbers(5); +// foo.add_numbers(42); +// +// foo.SerializeToString(&data); +// } +// +// { +// // Parse the serialized message and check that it contains the +// // correct data. +// Foo foo; +// foo.ParseFromString(data); +// +// assert(foo.text() == "Hello World!"); +// assert(foo.numbers_size() == 3); +// assert(foo.numbers(0) == 1); +// assert(foo.numbers(1) == 5); +// assert(foo.numbers(2) == 42); +// } +// +// { +// // Same as the last block, but do it dynamically via the Message +// // reflection interface. +// Message* foo = new Foo; +// Descriptor* descriptor = foo->GetDescriptor(); +// +// // Get the descriptors for the fields we're interested in and verify +// // their types. +// FieldDescriptor* text_field = descriptor->FindFieldByName("text"); +// assert(text_field != NULL); +// assert(text_field->type() == FieldDescriptor::TYPE_STRING); +// assert(text_field->label() == FieldDescriptor::TYPE_OPTIONAL); +// FieldDescriptor* numbers_field = descriptor->FindFieldByName("numbers"); +// assert(numbers_field != NULL); +// assert(numbers_field->type() == FieldDescriptor::TYPE_INT32); +// assert(numbers_field->label() == FieldDescriptor::TYPE_REPEATED); +// +// // Parse the message. +// foo->ParseFromString(data); +// +// // Use the reflection interface to examine the contents. +// const Reflection* reflection = foo->GetReflection(); +// assert(reflection->GetString(foo, text_field) == "Hello World!"); +// assert(reflection->FieldSize(foo, numbers_field) == 3); +// assert(reflection->GetRepeatedInt32(foo, numbers_field, 0) == 1); +// assert(reflection->GetRepeatedInt32(foo, numbers_field, 1) == 5); +// assert(reflection->GetRepeatedInt32(foo, numbers_field, 2) == 42); +// +// delete foo; +// } + +#ifndef GOOGLE_PROTOBUF_MESSAGE_H__ +#define GOOGLE_PROTOBUF_MESSAGE_H__ + +#include +#include + +#ifdef __DECCXX +// HP C++'s iosfwd doesn't work. +#include +#else +#include +#endif + +#include + +#include + + +namespace google { +namespace protobuf { + +// Defined in this file. +class Message; +class Reflection; +class MessageFactory; + +// Defined in other files. +class Descriptor; // descriptor.h +class FieldDescriptor; // descriptor.h +class EnumDescriptor; // descriptor.h +class EnumValueDescriptor; // descriptor.h +namespace io { + class ZeroCopyInputStream; // zero_copy_stream.h + class ZeroCopyOutputStream; // zero_copy_stream.h + class CodedInputStream; // coded_stream.h + class CodedOutputStream; // coded_stream.h +} +class UnknownFieldSet; // unknown_field_set.h + +// A container to hold message metadata. +struct Metadata { + const Descriptor* descriptor; + const Reflection* reflection; +}; + +// Returns the EnumDescriptor for enum type E, which must be a +// proto-declared enum type. Code generated by the protocol compiler +// will include specializations of this template for each enum type declared. +template +const EnumDescriptor* GetEnumDescriptor(); + +// Abstract interface for protocol messages. +// +// See also MessageLite, which contains most every-day operations. Message +// adds descriptors and reflection on top of that. +// +// The methods of this class that are virtual but not pure-virtual have +// default implementations based on reflection. Message classes which are +// optimized for speed will want to override these with faster implementations, +// but classes optimized for code size may be happy with keeping them. See +// the optimize_for option in descriptor.proto. +class LIBPROTOBUF_EXPORT Message : public MessageLite { + public: + inline Message() {} + virtual ~Message(); + + // Basic Operations ------------------------------------------------ + + // Construct a new instance of the same type. Ownership is passed to the + // caller. (This is also defined in MessageLite, but is defined again here + // for return-type covariance.) + virtual Message* New() const = 0; + + // Make this message into a copy of the given message. The given message + // must have the same descriptor, but need not necessarily be the same class. + // By default this is just implemented as "Clear(); MergeFrom(from);". + virtual void CopyFrom(const Message& from); + + // Merge the fields from the given message into this message. Singular + // fields will be overwritten, except for embedded messages which will + // be merged. Repeated fields will be concatenated. The given message + // must be of the same type as this message (i.e. the exact same class). + virtual void MergeFrom(const Message& from); + + // Verifies that IsInitialized() returns true. GOOGLE_CHECK-fails otherwise, with + // a nice error message. + void CheckInitialized() const; + + // Slowly build a list of all required fields that are not set. + // This is much, much slower than IsInitialized() as it is implemented + // purely via reflection. Generally, you should not call this unless you + // have already determined that an error exists by calling IsInitialized(). + void FindInitializationErrors(vector* errors) const; + + // Like FindInitializationErrors, but joins all the strings, delimited by + // commas, and returns them. + string InitializationErrorString() const; + + // Clears all unknown fields from this message and all embedded messages. + // Normally, if unknown tag numbers are encountered when parsing a message, + // the tag and value are stored in the message's UnknownFieldSet and + // then written back out when the message is serialized. This allows servers + // which simply route messages to other servers to pass through messages + // that have new field definitions which they don't yet know about. However, + // this behavior can have security implications. To avoid it, call this + // method after parsing. + // + // See Reflection::GetUnknownFields() for more on unknown fields. + virtual void DiscardUnknownFields(); + + // Computes (an estimate of) the total number of bytes currently used for + // storing the message in memory. The default implementation calls the + // Reflection object's SpaceUsed() method. + virtual int SpaceUsed() const; + + // Debugging & Testing---------------------------------------------- + + // Generates a human readable form of this message, useful for debugging + // and other purposes. + string DebugString() const; + // Like DebugString(), but with less whitespace. + string ShortDebugString() const; + // Like DebugString(), but do not escape UTF-8 byte sequences. + string Utf8DebugString() const; + // Convenience function useful in GDB. Prints DebugString() to stdout. + void PrintDebugString() const; + + // Heavy I/O ------------------------------------------------------- + // Additional parsing and serialization methods not implemented by + // MessageLite because they are not supported by the lite library. + + // Parse a protocol buffer from a file descriptor. If successful, the entire + // input will be consumed. + bool ParseFromFileDescriptor(int file_descriptor); + // Like ParseFromFileDescriptor(), but accepts messages that are missing + // required fields. + bool ParsePartialFromFileDescriptor(int file_descriptor); + // Parse a protocol buffer from a C++ istream. If successful, the entire + // input will be consumed. + bool ParseFromIstream(istream* input); + // Like ParseFromIstream(), but accepts messages that are missing + // required fields. + bool ParsePartialFromIstream(istream* input); + + // Serialize the message and write it to the given file descriptor. All + // required fields must be set. + bool SerializeToFileDescriptor(int file_descriptor) const; + // Like SerializeToFileDescriptor(), but allows missing required fields. + bool SerializePartialToFileDescriptor(int file_descriptor) const; + // Serialize the message and write it to the given C++ ostream. All + // required fields must be set. + bool SerializeToOstream(ostream* output) const; + // Like SerializeToOstream(), but allows missing required fields. + bool SerializePartialToOstream(ostream* output) const; + + + // Reflection-based methods ---------------------------------------- + // These methods are pure-virtual in MessageLite, but Message provides + // reflection-based default implementations. + + virtual string GetTypeName() const; + virtual void Clear(); + virtual bool IsInitialized() const; + virtual void CheckTypeAndMergeFrom(const MessageLite& other); + virtual bool MergePartialFromCodedStream(io::CodedInputStream* input); + virtual int ByteSize() const; + virtual void SerializeWithCachedSizes(io::CodedOutputStream* output) const; + + private: + // This is called only by the default implementation of ByteSize(), to + // update the cached size. If you override ByteSize(), you do not need + // to override this. If you do not override ByteSize(), you MUST override + // this; the default implementation will crash. + // + // The method is private because subclasses should never call it; only + // override it. Yes, C++ lets you do that. Crazy, huh? + virtual void SetCachedSize(int size) const; + + public: + + // Introspection --------------------------------------------------- + + // Typedef for backwards-compatibility. + typedef google::protobuf::Reflection Reflection; + + // Get a Descriptor for this message's type. This describes what + // fields the message contains, the types of those fields, etc. + const Descriptor* GetDescriptor() const { return GetMetadata().descriptor; } + + // Get the Reflection interface for this Message, which can be used to + // read and modify the fields of the Message dynamically (in other words, + // without knowing the message type at compile time). This object remains + // property of the Message. + // + // This method remains virtual in case a subclass does not implement + // reflection and wants to override the default behavior. + virtual const Reflection* GetReflection() const { + return GetMetadata().reflection; + } + + protected: + // Get a struct containing the metadata for the Message. Most subclasses only + // need to implement this method, rather than the GetDescriptor() and + // GetReflection() wrappers. + virtual Metadata GetMetadata() const = 0; + + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Message); +}; + +// This interface contains methods that can be used to dynamically access +// and modify the fields of a protocol message. Their semantics are +// similar to the accessors the protocol compiler generates. +// +// To get the Reflection for a given Message, call Message::GetReflection(). +// +// This interface is separate from Message only for efficiency reasons; +// the vast majority of implementations of Message will share the same +// implementation of Reflection (GeneratedMessageReflection, +// defined in generated_message.h), and all Messages of a particular class +// should share the same Reflection object (though you should not rely on +// the latter fact). +// +// There are several ways that these methods can be used incorrectly. For +// example, any of the following conditions will lead to undefined +// results (probably assertion failures): +// - The FieldDescriptor is not a field of this message type. +// - The method called is not appropriate for the field's type. For +// each field type in FieldDescriptor::TYPE_*, there is only one +// Get*() method, one Set*() method, and one Add*() method that is +// valid for that type. It should be obvious which (except maybe +// for TYPE_BYTES, which are represented using strings in C++). +// - A Get*() or Set*() method for singular fields is called on a repeated +// field. +// - GetRepeated*(), SetRepeated*(), or Add*() is called on a non-repeated +// field. +// - The Message object passed to any method is not of the right type for +// this Reflection object (i.e. message.GetReflection() != reflection). +// +// You might wonder why there is not any abstract representation for a field +// of arbitrary type. E.g., why isn't there just a "GetField()" method that +// returns "const Field&", where "Field" is some class with accessors like +// "GetInt32Value()". The problem is that someone would have to deal with +// allocating these Field objects. For generated message classes, having to +// allocate space for an additional object to wrap every field would at least +// double the message's memory footprint, probably worse. Allocating the +// objects on-demand, on the other hand, would be expensive and prone to +// memory leaks. So, instead we ended up with this flat interface. +// +// TODO(kenton): Create a utility class which callers can use to read and +// write fields from a Reflection without paying attention to the type. +class LIBPROTOBUF_EXPORT Reflection { + public: + // TODO(kenton): Remove parameter. + inline Reflection() {} + virtual ~Reflection(); + + // Get the UnknownFieldSet for the message. This contains fields which + // were seen when the Message was parsed but were not recognized according + // to the Message's definition. + virtual const UnknownFieldSet& GetUnknownFields( + const Message& message) const = 0; + // Get a mutable pointer to the UnknownFieldSet for the message. This + // contains fields which were seen when the Message was parsed but were not + // recognized according to the Message's definition. + virtual UnknownFieldSet* MutableUnknownFields(Message* message) const = 0; + + // Estimate the amount of memory used by the message object. + virtual int SpaceUsed(const Message& message) const = 0; + + // Check if the given non-repeated field is set. + virtual bool HasField(const Message& message, + const FieldDescriptor* field) const = 0; + + // Get the number of elements of a repeated field. + virtual int FieldSize(const Message& message, + const FieldDescriptor* field) const = 0; + + // Clear the value of a field, so that HasField() returns false or + // FieldSize() returns zero. + virtual void ClearField(Message* message, + const FieldDescriptor* field) const = 0; + + // Remove the last element of a repeated field. + // We don't provide a way to remove any element other than the last + // because it invites inefficient use, such as O(n^2) filtering loops + // that should have been O(n). If you want to remove an element other + // than the last, the best way to do it is to re-arrange the elements + // (using Swap()) so that the one you want removed is at the end, then + // call RemoveLast(). + virtual void RemoveLast(Message* message, + const FieldDescriptor* field) const = 0; + + // Swap the complete contents of two messages. + virtual void Swap(Message* message1, Message* message2) const = 0; + + // Swap two elements of a repeated field. + virtual void SwapElements(Message* message, + const FieldDescriptor* field, + int index1, + int index2) const = 0; + + // List all fields of the message which are currently set. This includes + // extensions. Singular fields will only be listed if HasField(field) would + // return true and repeated fields will only be listed if FieldSize(field) + // would return non-zero. Fields (both normal fields and extension fields) + // will be listed ordered by field number. + virtual void ListFields(const Message& message, + vector* output) const = 0; + + // Singular field getters ------------------------------------------ + // These get the value of a non-repeated field. They return the default + // value for fields that aren't set. + + virtual int32 GetInt32 (const Message& message, + const FieldDescriptor* field) const = 0; + virtual int64 GetInt64 (const Message& message, + const FieldDescriptor* field) const = 0; + virtual uint32 GetUInt32(const Message& message, + const FieldDescriptor* field) const = 0; + virtual uint64 GetUInt64(const Message& message, + const FieldDescriptor* field) const = 0; + virtual float GetFloat (const Message& message, + const FieldDescriptor* field) const = 0; + virtual double GetDouble(const Message& message, + const FieldDescriptor* field) const = 0; + virtual bool GetBool (const Message& message, + const FieldDescriptor* field) const = 0; + virtual string GetString(const Message& message, + const FieldDescriptor* field) const = 0; + virtual const EnumValueDescriptor* GetEnum( + const Message& message, const FieldDescriptor* field) const = 0; + // See MutableMessage() for the meaning of the "factory" parameter. + virtual const Message& GetMessage(const Message& message, + const FieldDescriptor* field, + MessageFactory* factory = NULL) const = 0; + + // Get a string value without copying, if possible. + // + // GetString() necessarily returns a copy of the string. This can be + // inefficient when the string is already stored in a string object in the + // underlying message. GetStringReference() will return a reference to the + // underlying string in this case. Otherwise, it will copy the string into + // *scratch and return that. + // + // Note: It is perfectly reasonable and useful to write code like: + // str = reflection->GetStringReference(field, &str); + // This line would ensure that only one copy of the string is made + // regardless of the field's underlying representation. When initializing + // a newly-constructed string, though, it's just as fast and more readable + // to use code like: + // string str = reflection->GetString(field); + virtual const string& GetStringReference(const Message& message, + const FieldDescriptor* field, + string* scratch) const = 0; + + + // Singular field mutators ----------------------------------------- + // These mutate the value of a non-repeated field. + + virtual void SetInt32 (Message* message, + const FieldDescriptor* field, int32 value) const = 0; + virtual void SetInt64 (Message* message, + const FieldDescriptor* field, int64 value) const = 0; + virtual void SetUInt32(Message* message, + const FieldDescriptor* field, uint32 value) const = 0; + virtual void SetUInt64(Message* message, + const FieldDescriptor* field, uint64 value) const = 0; + virtual void SetFloat (Message* message, + const FieldDescriptor* field, float value) const = 0; + virtual void SetDouble(Message* message, + const FieldDescriptor* field, double value) const = 0; + virtual void SetBool (Message* message, + const FieldDescriptor* field, bool value) const = 0; + virtual void SetString(Message* message, + const FieldDescriptor* field, + const string& value) const = 0; + virtual void SetEnum (Message* message, + const FieldDescriptor* field, + const EnumValueDescriptor* value) const = 0; + // Get a mutable pointer to a field with a message type. If a MessageFactory + // is provided, it will be used to construct instances of the sub-message; + // otherwise, the default factory is used. If the field is an extension that + // does not live in the same pool as the containing message's descriptor (e.g. + // it lives in an overlay pool), then a MessageFactory must be provided. + // If you have no idea what that meant, then you probably don't need to worry + // about it (don't provide a MessageFactory). WARNING: If the + // FieldDescriptor is for a compiled-in extension, then + // factory->GetPrototype(field->message_type() MUST return an instance of the + // compiled-in class for this type, NOT DynamicMessage. + virtual Message* MutableMessage(Message* message, + const FieldDescriptor* field, + MessageFactory* factory = NULL) const = 0; + + + // Repeated field getters ------------------------------------------ + // These get the value of one element of a repeated field. + + virtual int32 GetRepeatedInt32 (const Message& message, + const FieldDescriptor* field, + int index) const = 0; + virtual int64 GetRepeatedInt64 (const Message& message, + const FieldDescriptor* field, + int index) const = 0; + virtual uint32 GetRepeatedUInt32(const Message& message, + const FieldDescriptor* field, + int index) const = 0; + virtual uint64 GetRepeatedUInt64(const Message& message, + const FieldDescriptor* field, + int index) const = 0; + virtual float GetRepeatedFloat (const Message& message, + const FieldDescriptor* field, + int index) const = 0; + virtual double GetRepeatedDouble(const Message& message, + const FieldDescriptor* field, + int index) const = 0; + virtual bool GetRepeatedBool (const Message& message, + const FieldDescriptor* field, + int index) const = 0; + virtual string GetRepeatedString(const Message& message, + const FieldDescriptor* field, + int index) const = 0; + virtual const EnumValueDescriptor* GetRepeatedEnum( + const Message& message, + const FieldDescriptor* field, int index) const = 0; + virtual const Message& GetRepeatedMessage( + const Message& message, + const FieldDescriptor* field, int index) const = 0; + + // See GetStringReference(), above. + virtual const string& GetRepeatedStringReference( + const Message& message, const FieldDescriptor* field, + int index, string* scratch) const = 0; + + + // Repeated field mutators ----------------------------------------- + // These mutate the value of one element of a repeated field. + + virtual void SetRepeatedInt32 (Message* message, + const FieldDescriptor* field, + int index, int32 value) const = 0; + virtual void SetRepeatedInt64 (Message* message, + const FieldDescriptor* field, + int index, int64 value) const = 0; + virtual void SetRepeatedUInt32(Message* message, + const FieldDescriptor* field, + int index, uint32 value) const = 0; + virtual void SetRepeatedUInt64(Message* message, + const FieldDescriptor* field, + int index, uint64 value) const = 0; + virtual void SetRepeatedFloat (Message* message, + const FieldDescriptor* field, + int index, float value) const = 0; + virtual void SetRepeatedDouble(Message* message, + const FieldDescriptor* field, + int index, double value) const = 0; + virtual void SetRepeatedBool (Message* message, + const FieldDescriptor* field, + int index, bool value) const = 0; + virtual void SetRepeatedString(Message* message, + const FieldDescriptor* field, + int index, const string& value) const = 0; + virtual void SetRepeatedEnum(Message* message, + const FieldDescriptor* field, int index, + const EnumValueDescriptor* value) const = 0; + // Get a mutable pointer to an element of a repeated field with a message + // type. + virtual Message* MutableRepeatedMessage( + Message* message, const FieldDescriptor* field, int index) const = 0; + + + // Repeated field adders ------------------------------------------- + // These add an element to a repeated field. + + virtual void AddInt32 (Message* message, + const FieldDescriptor* field, int32 value) const = 0; + virtual void AddInt64 (Message* message, + const FieldDescriptor* field, int64 value) const = 0; + virtual void AddUInt32(Message* message, + const FieldDescriptor* field, uint32 value) const = 0; + virtual void AddUInt64(Message* message, + const FieldDescriptor* field, uint64 value) const = 0; + virtual void AddFloat (Message* message, + const FieldDescriptor* field, float value) const = 0; + virtual void AddDouble(Message* message, + const FieldDescriptor* field, double value) const = 0; + virtual void AddBool (Message* message, + const FieldDescriptor* field, bool value) const = 0; + virtual void AddString(Message* message, + const FieldDescriptor* field, + const string& value) const = 0; + virtual void AddEnum (Message* message, + const FieldDescriptor* field, + const EnumValueDescriptor* value) const = 0; + // See MutableMessage() for comments on the "factory" parameter. + virtual Message* AddMessage(Message* message, + const FieldDescriptor* field, + MessageFactory* factory = NULL) const = 0; + + + // Extensions ------------------------------------------------------ + + // Try to find an extension of this message type by fully-qualified field + // name. Returns NULL if no extension is known for this name or number. + virtual const FieldDescriptor* FindKnownExtensionByName( + const string& name) const = 0; + + // Try to find an extension of this message type by field number. + // Returns NULL if no extension is known for this name or number. + virtual const FieldDescriptor* FindKnownExtensionByNumber( + int number) const = 0; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Reflection); +}; + +// Abstract interface for a factory for message objects. +class LIBPROTOBUF_EXPORT MessageFactory { + public: + inline MessageFactory() {} + virtual ~MessageFactory(); + + // Given a Descriptor, gets or constructs the default (prototype) Message + // of that type. You can then call that message's New() method to construct + // a mutable message of that type. + // + // Calling this method twice with the same Descriptor returns the same + // object. The returned object remains property of the factory. Also, any + // objects created by calling the prototype's New() method share some data + // with the prototype, so these must be destoyed before the MessageFactory + // is destroyed. + // + // The given descriptor must outlive the returned message, and hence must + // outlive the MessageFactory. + // + // Some implementations do not support all types. GetPrototype() will + // return NULL if the descriptor passed in is not supported. + // + // This method may or may not be thread-safe depending on the implementation. + // Each implementation should document its own degree thread-safety. + virtual const Message* GetPrototype(const Descriptor* type) = 0; + + // Gets a MessageFactory which supports all generated, compiled-in messages. + // In other words, for any compiled-in type FooMessage, the following is true: + // MessageFactory::generated_factory()->GetPrototype( + // FooMessage::descriptor()) == FooMessage::default_instance() + // This factory supports all types which are found in + // DescriptorPool::generated_pool(). If given a descriptor from any other + // pool, GetPrototype() will return NULL. (You can also check if a + // descriptor is for a generated message by checking if + // descriptor->file()->pool() == DescriptorPool::generated_pool().) + // + // This factory is 100% thread-safe; calling GetPrototype() does not modify + // any shared data. + // + // This factory is a singleton. The caller must not delete the object. + static MessageFactory* generated_factory(); + + // For internal use only: Registers a .proto file at static initialization + // time, to be placed in generated_factory. The first time GetPrototype() + // is called with a descriptor from this file, |register_messages| will be + // called, with the file name as the parameter. It must call + // InternalRegisterGeneratedMessage() (below) to register each message type + // in the file. This strange mechanism is necessary because descriptors are + // built lazily, so we can't register types by their descriptor until we + // know that the descriptor exists. |filename| must be a permanent string. + static void InternalRegisterGeneratedFile( + const char* filename, void (*register_messages)(const string&)); + + // For internal use only: Registers a message type. Called only by the + // functions which are registered with InternalRegisterGeneratedFile(), + // above. + static void InternalRegisterGeneratedMessage(const Descriptor* descriptor, + const Message* prototype); + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageFactory); +}; + +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_MESSAGE_H__ diff --git a/depends/protobuf/google/protobuf/message_lite.cc b/depends/protobuf/google/protobuf/message_lite.cc new file mode 100644 index 0000000000..7c8f37dc7f --- /dev/null +++ b/depends/protobuf/google/protobuf/message_lite.cc @@ -0,0 +1,334 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Authors: wink@google.com (Wink Saville), +// kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { + +MessageLite::~MessageLite() {} + +string MessageLite::InitializationErrorString() const { + return "(cannot determine missing fields for lite message)"; +} + +namespace { + +// When serializing, we first compute the byte size, then serialize the message. +// If serialization produces a different number of bytes than expected, we +// call this function, which crashes. The problem could be due to a bug in the +// protobuf implementation but is more likely caused by concurrent modification +// of the message. This function attempts to distinguish between the two and +// provide a useful error message. +void ByteSizeConsistencyError(int byte_size_before_serialization, + int byte_size_after_serialization, + int bytes_produced_by_serialization) { + GOOGLE_CHECK_EQ(byte_size_before_serialization, byte_size_after_serialization) + << "Protocol message was modified concurrently during serialization."; + GOOGLE_CHECK_EQ(bytes_produced_by_serialization, byte_size_before_serialization) + << "Byte size calculation and serialization were inconsistent. This " + "may indicate a bug in protocol buffers or it may be caused by " + "concurrent modification of the message."; + GOOGLE_LOG(FATAL) << "This shouldn't be called if all the sizes are equal."; +} + +string InitializationErrorMessage(const char* action, + const MessageLite& message) { + // Note: We want to avoid depending on strutil in the lite library, otherwise + // we'd use: + // + // return strings::Substitute( + // "Can't $0 message of type \"$1\" because it is missing required " + // "fields: $2", + // action, message.GetTypeName(), + // message.InitializationErrorString()); + + string result; + result += "Can't "; + result += action; + result += " message of type \""; + result += message.GetTypeName(); + result += "\" because it is missing required fields: "; + result += message.InitializationErrorString(); + return result; +} + +// Several of the Parse methods below just do one thing and then call another +// method. In a naive implementation, we might have ParseFromString() call +// ParseFromArray() which would call ParseFromZeroCopyStream() which would call +// ParseFromCodedStream() which would call MergeFromCodedStream() which would +// call MergePartialFromCodedStream(). However, when parsing very small +// messages, every function call introduces significant overhead. To avoid +// this without reproducing code, we use these forced-inline helpers. +// +// Note: GCC only allows GOOGLE_ATTRIBUTE_ALWAYS_INLINE on declarations, not +// definitions. +inline bool InlineMergeFromCodedStream(io::CodedInputStream* input, + MessageLite* message) + GOOGLE_ATTRIBUTE_ALWAYS_INLINE; +inline bool InlineParseFromCodedStream(io::CodedInputStream* input, + MessageLite* message) + GOOGLE_ATTRIBUTE_ALWAYS_INLINE; +inline bool InlineParsePartialFromCodedStream(io::CodedInputStream* input, + MessageLite* message) + GOOGLE_ATTRIBUTE_ALWAYS_INLINE; +inline bool InlineParseFromArray(const void* data, int size, + MessageLite* message) + GOOGLE_ATTRIBUTE_ALWAYS_INLINE; +inline bool InlineParsePartialFromArray(const void* data, int size, + MessageLite* message) + GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + +bool InlineMergeFromCodedStream(io::CodedInputStream* input, + MessageLite* message) { + if (!message->MergePartialFromCodedStream(input)) return false; + if (!message->IsInitialized()) { + GOOGLE_LOG(ERROR) << InitializationErrorMessage("parse", *message); + return false; + } + return true; +} + +bool InlineParseFromCodedStream(io::CodedInputStream* input, + MessageLite* message) { + message->Clear(); + return InlineMergeFromCodedStream(input, message); +} + +bool InlineParsePartialFromCodedStream(io::CodedInputStream* input, + MessageLite* message) { + message->Clear(); + return message->MergePartialFromCodedStream(input); +} + +bool InlineParseFromArray(const void* data, int size, MessageLite* message) { + io::CodedInputStream input(reinterpret_cast(data), size); + return InlineParseFromCodedStream(&input, message) && + input.ConsumedEntireMessage(); +} + +bool InlineParsePartialFromArray(const void* data, int size, + MessageLite* message) { + io::CodedInputStream input(reinterpret_cast(data), size); + return InlineParsePartialFromCodedStream(&input, message) && + input.ConsumedEntireMessage(); +} + +} // namespace + +bool MessageLite::MergeFromCodedStream(io::CodedInputStream* input) { + return InlineMergeFromCodedStream(input, this); +} + +bool MessageLite::ParseFromCodedStream(io::CodedInputStream* input) { + return InlineParseFromCodedStream(input, this); +} + +bool MessageLite::ParsePartialFromCodedStream(io::CodedInputStream* input) { + return InlineParsePartialFromCodedStream(input, this); +} + +bool MessageLite::ParseFromZeroCopyStream(io::ZeroCopyInputStream* input) { + io::CodedInputStream decoder(input); + return ParseFromCodedStream(&decoder) && decoder.ConsumedEntireMessage(); +} + +bool MessageLite::ParsePartialFromZeroCopyStream( + io::ZeroCopyInputStream* input) { + io::CodedInputStream decoder(input); + return ParsePartialFromCodedStream(&decoder) && + decoder.ConsumedEntireMessage(); +} + +bool MessageLite::ParseFromBoundedZeroCopyStream( + io::ZeroCopyInputStream* input, int size) { + io::CodedInputStream decoder(input); + decoder.PushLimit(size); + return ParseFromCodedStream(&decoder) && + decoder.ConsumedEntireMessage() && + decoder.BytesUntilLimit() == 0; +} + +bool MessageLite::ParsePartialFromBoundedZeroCopyStream( + io::ZeroCopyInputStream* input, int size) { + io::CodedInputStream decoder(input); + decoder.PushLimit(size); + return ParsePartialFromCodedStream(&decoder) && + decoder.ConsumedEntireMessage() && + decoder.BytesUntilLimit() == 0; +} + +bool MessageLite::ParseFromString(const string& data) { + return InlineParseFromArray(data.data(), data.size(), this); +} + +bool MessageLite::ParsePartialFromString(const string& data) { + return InlineParsePartialFromArray(data.data(), data.size(), this); +} + +bool MessageLite::ParseFromArray(const void* data, int size) { + return InlineParseFromArray(data, size, this); +} + +bool MessageLite::ParsePartialFromArray(const void* data, int size) { + return InlineParsePartialFromArray(data, size, this); +} + + +// =================================================================== + +uint8* MessageLite::SerializeWithCachedSizesToArray(uint8* target) const { + // We only optimize this when using optimize_for = SPEED. In other cases + // we just use the CodedOutputStream path. + int size = GetCachedSize(); + io::ArrayOutputStream out(target, size); + io::CodedOutputStream coded_out(&out); + SerializeWithCachedSizes(&coded_out); + GOOGLE_CHECK(!coded_out.HadError()); + return target + size; +} + +bool MessageLite::SerializeToCodedStream(io::CodedOutputStream* output) const { + GOOGLE_DCHECK(IsInitialized()) << InitializationErrorMessage("serialize", *this); + return SerializePartialToCodedStream(output); +} + +bool MessageLite::SerializePartialToCodedStream( + io::CodedOutputStream* output) const { + const int size = ByteSize(); // Force size to be cached. + uint8* buffer = output->GetDirectBufferForNBytesAndAdvance(size); + if (buffer != NULL) { + uint8* end = SerializeWithCachedSizesToArray(buffer); + if (end - buffer != size) { + ByteSizeConsistencyError(size, ByteSize(), end - buffer); + } + return true; + } else { + int original_byte_count = output->ByteCount(); + SerializeWithCachedSizes(output); + if (output->HadError()) { + return false; + } + int final_byte_count = output->ByteCount(); + + if (final_byte_count - original_byte_count != size) { + ByteSizeConsistencyError(size, ByteSize(), + final_byte_count - original_byte_count); + } + + return true; + } +} + +bool MessageLite::SerializeToZeroCopyStream( + io::ZeroCopyOutputStream* output) const { + io::CodedOutputStream encoder(output); + return SerializeToCodedStream(&encoder); +} + +bool MessageLite::SerializePartialToZeroCopyStream( + io::ZeroCopyOutputStream* output) const { + io::CodedOutputStream encoder(output); + return SerializePartialToCodedStream(&encoder); +} + +bool MessageLite::AppendToString(string* output) const { + GOOGLE_DCHECK(IsInitialized()) << InitializationErrorMessage("serialize", *this); + return AppendPartialToString(output); +} + +bool MessageLite::AppendPartialToString(string* output) const { + int old_size = output->size(); + int byte_size = ByteSize(); + STLStringResizeUninitialized(output, old_size + byte_size); + uint8* start = reinterpret_cast(string_as_array(output) + old_size); + uint8* end = SerializeWithCachedSizesToArray(start); + if (end - start != byte_size) { + ByteSizeConsistencyError(byte_size, ByteSize(), end - start); + } + return true; +} + +bool MessageLite::SerializeToString(string* output) const { + output->clear(); + return AppendToString(output); +} + +bool MessageLite::SerializePartialToString(string* output) const { + output->clear(); + return AppendPartialToString(output); +} + +bool MessageLite::SerializeToArray(void* data, int size) const { + GOOGLE_DCHECK(IsInitialized()) << InitializationErrorMessage("serialize", *this); + return SerializePartialToArray(data, size); +} + +bool MessageLite::SerializePartialToArray(void* data, int size) const { + int byte_size = ByteSize(); + if (size < byte_size) return false; + uint8* start = reinterpret_cast(data); + uint8* end = SerializeWithCachedSizesToArray(start); + if (end - start != byte_size) { + ByteSizeConsistencyError(byte_size, ByteSize(), end - start); + } + return true; +} + +string MessageLite::SerializeAsString() const { + // If the compiler implements the (Named) Return Value Optimization, + // the local variable 'result' will not actually reside on the stack + // of this function, but will be overlaid with the object that the + // caller supplied for the return value to be constructed in. + string output; + if (!AppendToString(&output)) + output.clear(); + return output; +} + +string MessageLite::SerializePartialAsString() const { + string output; + if (!AppendPartialToString(&output)) + output.clear(); + return output; +} + +} // namespace protobuf +} // namespace google diff --git a/depends/protobuf/google/protobuf/message_lite.h b/depends/protobuf/google/protobuf/message_lite.h new file mode 100644 index 0000000000..ebf4ba3c88 --- /dev/null +++ b/depends/protobuf/google/protobuf/message_lite.h @@ -0,0 +1,239 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Authors: wink@google.com (Wink Saville), +// kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// Defines MessageLite, the abstract interface implemented by all (lite +// and non-lite) protocol message objects. + +#ifndef GOOGLE_PROTOBUF_MESSAGE_LITE_H__ +#define GOOGLE_PROTOBUF_MESSAGE_LITE_H__ + +#include +#include + +namespace google { +namespace protobuf { + +// Interface to light weight protocol messages. +// +// This interface is implemented by all protocol message objects. Non-lite +// messages additionally implement the Message interface, which is a +// subclass of MessageLite. Use MessageLite instead when you only need +// the subset of features which it supports -- namely, nothing that uses +// descriptors or reflection. You can instruct the protocol compiler +// to generate classes which implement only MessageLite, not the full +// Message interface, by adding the following line to the .proto file: +// +// option optimize_for = LITE_RUNTIME; +// +// This is particularly useful on resource-constrained systems where +// the full protocol buffers runtime library is too big. +// +// Note that on non-constrained systems (e.g. servers) when you need +// to link in lots of protocol definitions, a better way to reduce +// total code footprint is to use optimize_for = CODE_SIZE. This +// will make the generated code smaller while still supporting all the +// same features (at the expense of speed). optimize_for = LITE_RUNTIME +// is best when you only have a small number of message types linked +// into your binary, in which case the size of the protocol buffers +// runtime itself is the biggest problem. +class LIBPROTOBUF_EXPORT MessageLite { + public: + inline MessageLite() {} + virtual ~MessageLite(); + + // Basic Operations ------------------------------------------------ + + // Get the name of this message type, e.g. "foo.bar.BazProto". + virtual string GetTypeName() const = 0; + + // Construct a new instance of the same type. Ownership is passed to the + // caller. + virtual MessageLite* New() const = 0; + + // Clear all fields of the message and set them to their default values. + // Clear() avoids freeing memory, assuming that any memory allocated + // to hold parts of the message will be needed again to hold the next + // message. If you actually want to free the memory used by a Message, + // you must delete it. + virtual void Clear() = 0; + + // Quickly check if all required fields have values set. + virtual bool IsInitialized() const = 0; + + // This is not implemented for Lite messages -- it just returns "(cannot + // determine missing fields for lite message)". However, it is implemented + // for full messages. See message.h. + virtual string InitializationErrorString() const; + + // If |other| is the exact same class as this, calls MergeFrom(). Otherwise, + // results are undefined (probably crash). + virtual void CheckTypeAndMergeFrom(const MessageLite& other) = 0; + + // Parsing --------------------------------------------------------- + // Methods for parsing in protocol buffer format. Most of these are + // just simple wrappers around MergeFromCodedStream(). + + // Fill the message with a protocol buffer parsed from the given input + // stream. Returns false on a read error or if the input is in the + // wrong format. + bool ParseFromCodedStream(io::CodedInputStream* input); + // Like ParseFromCodedStream(), but accepts messages that are missing + // required fields. + bool ParsePartialFromCodedStream(io::CodedInputStream* input); + // Read a protocol buffer from the given zero-copy input stream. If + // successful, the entire input will be consumed. + bool ParseFromZeroCopyStream(io::ZeroCopyInputStream* input); + // Like ParseFromZeroCopyStream(), but accepts messages that are missing + // required fields. + bool ParsePartialFromZeroCopyStream(io::ZeroCopyInputStream* input); + // Read a protocol buffer from the given zero-copy input stream, expecting + // the message to be exactly "size" bytes long. If successful, exactly + // this many bytes will have been consumed from the input. + bool ParseFromBoundedZeroCopyStream(io::ZeroCopyInputStream* input, int size); + // Like ParseFromBoundedZeroCopyStream(), but accepts messages that are + // missing required fields. + bool ParsePartialFromBoundedZeroCopyStream(io::ZeroCopyInputStream* input, + int size); + // Parse a protocol buffer contained in a string. + bool ParseFromString(const string& data); + // Like ParseFromString(), but accepts messages that are missing + // required fields. + bool ParsePartialFromString(const string& data); + // Parse a protocol buffer contained in an array of bytes. + bool ParseFromArray(const void* data, int size); + // Like ParseFromArray(), but accepts messages that are missing + // required fields. + bool ParsePartialFromArray(const void* data, int size); + + + // Reads a protocol buffer from the stream and merges it into this + // Message. Singular fields read from the input overwrite what is + // already in the Message and repeated fields are appended to those + // already present. + // + // It is the responsibility of the caller to call input->LastTagWas() + // (for groups) or input->ConsumedEntireMessage() (for non-groups) after + // this returns to verify that the message's end was delimited correctly. + // + // ParsefromCodedStream() is implemented as Clear() followed by + // MergeFromCodedStream(). + bool MergeFromCodedStream(io::CodedInputStream* input); + + // Like MergeFromCodedStream(), but succeeds even if required fields are + // missing in the input. + // + // MergeFromCodedStream() is just implemented as MergePartialFromCodedStream() + // followed by IsInitialized(). + virtual bool MergePartialFromCodedStream(io::CodedInputStream* input) = 0; + + // Serialization --------------------------------------------------- + // Methods for serializing in protocol buffer format. Most of these + // are just simple wrappers around ByteSize() and SerializeWithCachedSizes(). + + // Write a protocol buffer of this message to the given output. Returns + // false on a write error. If the message is missing required fields, + // this may GOOGLE_CHECK-fail. + bool SerializeToCodedStream(io::CodedOutputStream* output) const; + // Like SerializeToCodedStream(), but allows missing required fields. + bool SerializePartialToCodedStream(io::CodedOutputStream* output) const; + // Write the message to the given zero-copy output stream. All required + // fields must be set. + bool SerializeToZeroCopyStream(io::ZeroCopyOutputStream* output) const; + // Like SerializeToZeroCopyStream(), but allows missing required fields. + bool SerializePartialToZeroCopyStream(io::ZeroCopyOutputStream* output) const; + // Serialize the message and store it in the given string. All required + // fields must be set. + bool SerializeToString(string* output) const; + // Like SerializeToString(), but allows missing required fields. + bool SerializePartialToString(string* output) const; + // Serialize the message and store it in the given byte array. All required + // fields must be set. + bool SerializeToArray(void* data, int size) const; + // Like SerializeToArray(), but allows missing required fields. + bool SerializePartialToArray(void* data, int size) const; + + // Make a string encoding the message. Is equivalent to calling + // SerializeToString() on a string and using that. Returns the empty + // string if SerializeToString() would have returned an error. + // Note: If you intend to generate many such strings, you may + // reduce heap fragmentation by instead re-using the same string + // object with calls to SerializeToString(). + string SerializeAsString() const; + // Like SerializeAsString(), but allows missing required fields. + string SerializePartialAsString() const; + + // Like SerializeToString(), but appends to the data to the string's existing + // contents. All required fields must be set. + bool AppendToString(string* output) const; + // Like AppendToString(), but allows missing required fields. + bool AppendPartialToString(string* output) const; + + // Computes the serialized size of the message. This recursively calls + // ByteSize() on all embedded messages. If a subclass does not override + // this, it MUST override SetCachedSize(). + virtual int ByteSize() const = 0; + + // Serializes the message without recomputing the size. The message must + // not have changed since the last call to ByteSize(); if it has, the results + // are undefined. + virtual void SerializeWithCachedSizes( + io::CodedOutputStream* output) const = 0; + + // Like SerializeWithCachedSizes, but writes directly to *target, returning + // a pointer to the byte immediately after the last byte written. "target" + // must point at a byte array of at least ByteSize() bytes. + virtual uint8* SerializeWithCachedSizesToArray(uint8* target) const; + + // Returns the result of the last call to ByteSize(). An embedded message's + // size is needed both to serialize it (because embedded messages are + // length-delimited) and to compute the outer message's size. Caching + // the size avoids computing it multiple times. + // + // ByteSize() does not automatically use the cached size when available + // because this would require invalidating it every time the message was + // modified, which would be too hard and expensive. (E.g. if a deeply-nested + // sub-message is changed, all of its parents' cached sizes would need to be + // invalidated, which is too much work for an otherwise inlined setter + // method.) + virtual int GetCachedSize() const = 0; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageLite); +}; + +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_MESSAGE_LITE_H__ diff --git a/depends/protobuf/google/protobuf/package_info.h b/depends/protobuf/google/protobuf/package_info.h new file mode 100644 index 0000000000..60cd3994cb --- /dev/null +++ b/depends/protobuf/google/protobuf/package_info.h @@ -0,0 +1,64 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// This file exists solely to document the google::protobuf namespace. +// It is not compiled into anything, but it may be read by an automated +// documentation generator. + +namespace google { + +// Core components of the Protocol Buffers runtime library. +// +// The files in this package represent the core of the Protocol Buffer +// system. All of them are part of the libprotobuf library. +// +// A note on thread-safety: +// +// Thread-safety in the Protocol Buffer library follows a simple rule: +// unless explicitly noted otherwise, it is always safe to use an object +// from multiple threads simultaneously as long as the object is declared +// const in all threads (or, it is only used in ways that would be allowed +// if it were declared const). However, if an object is accessed in one +// thread in a way that would not be allowed if it were const, then it is +// not safe to access that object in any other thread simultaneously. +// +// Put simply, read-only access to an object can happen in multiple threads +// simultaneously, but write access can only happen in a single thread at +// a time. +// +// The implementation does contain some "const" methods which actually modify +// the object behind the scenes -- e.g., to cache results -- but in these cases +// mutex locking is used to make the access thread-safe. +namespace protobuf {} +} // namespace google diff --git a/depends/protobuf/google/protobuf/reflection_ops.cc b/depends/protobuf/google/protobuf/reflection_ops.cc new file mode 100644 index 0000000000..897c0d7c8a --- /dev/null +++ b/depends/protobuf/google/protobuf/reflection_ops.cc @@ -0,0 +1,262 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include +#include +#include +#include + +namespace google { +namespace protobuf { +namespace internal { + +void ReflectionOps::Copy(const Message& from, Message* to) { + if (&from == to) return; + Clear(to); + Merge(from, to); +} + +void ReflectionOps::Merge(const Message& from, Message* to) { + GOOGLE_CHECK_NE(&from, to); + + const Descriptor* descriptor = from.GetDescriptor(); + GOOGLE_CHECK_EQ(to->GetDescriptor(), descriptor) + << "Tried to merge messages of different types."; + + const Reflection* from_reflection = from.GetReflection(); + const Reflection* to_reflection = to->GetReflection(); + + vector fields; + from_reflection->ListFields(from, &fields); + for (int i = 0; i < fields.size(); i++) { + const FieldDescriptor* field = fields[i]; + + if (field->is_repeated()) { + int count = from_reflection->FieldSize(from, field); + for (int j = 0; j < count; j++) { + switch (field->cpp_type()) { +#define HANDLE_TYPE(CPPTYPE, METHOD) \ + case FieldDescriptor::CPPTYPE_##CPPTYPE: \ + to_reflection->Add##METHOD(to, field, \ + from_reflection->GetRepeated##METHOD(from, field, j)); \ + break; + + HANDLE_TYPE(INT32 , Int32 ); + HANDLE_TYPE(INT64 , Int64 ); + HANDLE_TYPE(UINT32, UInt32); + HANDLE_TYPE(UINT64, UInt64); + HANDLE_TYPE(FLOAT , Float ); + HANDLE_TYPE(DOUBLE, Double); + HANDLE_TYPE(BOOL , Bool ); + HANDLE_TYPE(STRING, String); + HANDLE_TYPE(ENUM , Enum ); +#undef HANDLE_TYPE + + case FieldDescriptor::CPPTYPE_MESSAGE: + to_reflection->AddMessage(to, field)->MergeFrom( + from_reflection->GetRepeatedMessage(from, field, j)); + break; + } + } + } else { + switch (field->cpp_type()) { +#define HANDLE_TYPE(CPPTYPE, METHOD) \ + case FieldDescriptor::CPPTYPE_##CPPTYPE: \ + to_reflection->Set##METHOD(to, field, \ + from_reflection->Get##METHOD(from, field)); \ + break; + + HANDLE_TYPE(INT32 , Int32 ); + HANDLE_TYPE(INT64 , Int64 ); + HANDLE_TYPE(UINT32, UInt32); + HANDLE_TYPE(UINT64, UInt64); + HANDLE_TYPE(FLOAT , Float ); + HANDLE_TYPE(DOUBLE, Double); + HANDLE_TYPE(BOOL , Bool ); + HANDLE_TYPE(STRING, String); + HANDLE_TYPE(ENUM , Enum ); +#undef HANDLE_TYPE + + case FieldDescriptor::CPPTYPE_MESSAGE: + to_reflection->MutableMessage(to, field)->MergeFrom( + from_reflection->GetMessage(from, field)); + break; + } + } + } + + to_reflection->MutableUnknownFields(to)->MergeFrom( + from_reflection->GetUnknownFields(from)); +} + +void ReflectionOps::Clear(Message* message) { + const Reflection* reflection = message->GetReflection(); + + vector fields; + reflection->ListFields(*message, &fields); + for (int i = 0; i < fields.size(); i++) { + reflection->ClearField(message, fields[i]); + } + + reflection->MutableUnknownFields(message)->Clear(); +} + +bool ReflectionOps::IsInitialized(const Message& message) { + const Descriptor* descriptor = message.GetDescriptor(); + const Reflection* reflection = message.GetReflection(); + + // Check required fields of this message. + for (int i = 0; i < descriptor->field_count(); i++) { + if (descriptor->field(i)->is_required()) { + if (!reflection->HasField(message, descriptor->field(i))) { + return false; + } + } + } + + // Check that sub-messages are initialized. + vector fields; + reflection->ListFields(message, &fields); + for (int i = 0; i < fields.size(); i++) { + const FieldDescriptor* field = fields[i]; + if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + if (field->is_repeated()) { + int size = reflection->FieldSize(message, field); + + for (int i = 0; i < size; i++) { + if (!reflection->GetRepeatedMessage(message, field, i) + .IsInitialized()) { + return false; + } + } + } else { + if (!reflection->GetMessage(message, field).IsInitialized()) { + return false; + } + } + } + } + + return true; +} + +void ReflectionOps::DiscardUnknownFields(Message* message) { + const Reflection* reflection = message->GetReflection(); + + reflection->MutableUnknownFields(message)->Clear(); + + vector fields; + reflection->ListFields(*message, &fields); + for (int i = 0; i < fields.size(); i++) { + const FieldDescriptor* field = fields[i]; + if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + if (field->is_repeated()) { + int size = reflection->FieldSize(*message, field); + for (int i = 0; i < size; i++) { + reflection->MutableRepeatedMessage(message, field, i) + ->DiscardUnknownFields(); + } + } else { + reflection->MutableMessage(message, field)->DiscardUnknownFields(); + } + } + } +} + +static string SubMessagePrefix(const string& prefix, + const FieldDescriptor* field, + int index) { + string result(prefix); + if (field->is_extension()) { + result.append("("); + result.append(field->full_name()); + result.append(")"); + } else { + result.append(field->name()); + } + if (index != -1) { + result.append("["); + result.append(SimpleItoa(index)); + result.append("]"); + } + result.append("."); + return result; +} + +void ReflectionOps::FindInitializationErrors( + const Message& message, + const string& prefix, + vector* errors) { + const Descriptor* descriptor = message.GetDescriptor(); + const Reflection* reflection = message.GetReflection(); + + // Check required fields of this message. + for (int i = 0; i < descriptor->field_count(); i++) { + if (descriptor->field(i)->is_required()) { + if (!reflection->HasField(message, descriptor->field(i))) { + errors->push_back(prefix + descriptor->field(i)->name()); + } + } + } + + // Check sub-messages. + vector fields; + reflection->ListFields(message, &fields); + for (int i = 0; i < fields.size(); i++) { + const FieldDescriptor* field = fields[i]; + if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + + if (field->is_repeated()) { + int size = reflection->FieldSize(message, field); + + for (int i = 0; i < size; i++) { + const Message& sub_message = + reflection->GetRepeatedMessage(message, field, i); + FindInitializationErrors(sub_message, + SubMessagePrefix(prefix, field, i), + errors); + } + } else { + const Message& sub_message = reflection->GetMessage(message, field); + FindInitializationErrors(sub_message, + SubMessagePrefix(prefix, field, -1), + errors); + } + } + } +} + +} // namespace internal +} // namespace protobuf +} // namespace google diff --git a/depends/protobuf/google/protobuf/reflection_ops.h b/depends/protobuf/google/protobuf/reflection_ops.h new file mode 100644 index 0000000000..355a0a5d26 --- /dev/null +++ b/depends/protobuf/google/protobuf/reflection_ops.h @@ -0,0 +1,80 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// This header is logically internal, but is made public because it is used +// from protocol-compiler-generated code, which may reside in other components. + +#ifndef GOOGLE_PROTOBUF_REFLECTION_OPS_H__ +#define GOOGLE_PROTOBUF_REFLECTION_OPS_H__ + +#include + +namespace google { +namespace protobuf { +namespace internal { + +// Basic operations that can be performed using reflection. +// These can be used as a cheap way to implement the corresponding +// methods of the Message interface, though they are likely to be +// slower than implementations tailored for the specific message type. +// +// This class should stay limited to operations needed to implement +// the Message interface. +// +// This class is really a namespace that contains only static methods. +class LIBPROTOBUF_EXPORT ReflectionOps { + public: + static void Copy(const Message& from, Message* to); + static void Merge(const Message& from, Message* to); + static void Clear(Message* message); + static bool IsInitialized(const Message& message); + static void DiscardUnknownFields(Message* message); + + // Finds all unset required fields in the message and adds their full + // paths (e.g. "foo.bar[5].baz") to *names. "prefix" will be attached to + // the front of each name. + static void FindInitializationErrors(const Message& message, + const string& prefix, + vector* errors); + + private: + // All methods are static. No need to construct. + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ReflectionOps); +}; + +} // namespace internal +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_REFLECTION_OPS_H__ diff --git a/depends/protobuf/google/protobuf/repeated_field.cc b/depends/protobuf/google/protobuf/repeated_field.cc new file mode 100644 index 0000000000..09377742af --- /dev/null +++ b/depends/protobuf/google/protobuf/repeated_field.cc @@ -0,0 +1,98 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include + +#include +#include + +namespace google { +namespace protobuf { + +namespace internal { + +void RepeatedPtrFieldBase::Reserve(int new_size) { + if (total_size_ >= new_size) return; + + void** old_elements = elements_; + total_size_ = max(total_size_ * 2, new_size); + elements_ = new void*[total_size_]; + memcpy(elements_, old_elements, allocated_size_ * sizeof(elements_[0])); + if (old_elements != initial_space_) { + delete [] old_elements; + } +} + +void RepeatedPtrFieldBase::Swap(RepeatedPtrFieldBase* other) { + void** swap_elements = elements_; + int swap_current_size = current_size_; + int swap_allocated_size = allocated_size_; + int swap_total_size = total_size_; + // We may not be using initial_space_ but it's not worth checking. Just + // copy it anyway. + void* swap_initial_space[kInitialSize]; + memcpy(swap_initial_space, initial_space_, sizeof(initial_space_)); + + elements_ = other->elements_; + current_size_ = other->current_size_; + allocated_size_ = other->allocated_size_; + total_size_ = other->total_size_; + memcpy(initial_space_, other->initial_space_, sizeof(initial_space_)); + + other->elements_ = swap_elements; + other->current_size_ = swap_current_size; + other->allocated_size_ = swap_allocated_size; + other->total_size_ = swap_total_size; + memcpy(other->initial_space_, swap_initial_space, sizeof(swap_initial_space)); + + if (elements_ == other->initial_space_) { + elements_ = initial_space_; + } + if (other->elements_ == initial_space_) { + other->elements_ = other->initial_space_; + } +} + +string* StringTypeHandlerBase::New() { + return new string; +} +void StringTypeHandlerBase::Delete(string* value) { + delete value; +} + +} // namespace internal + + +} // namespace protobuf +} // namespace google diff --git a/depends/protobuf/google/protobuf/repeated_field.h b/depends/protobuf/google/protobuf/repeated_field.h new file mode 100644 index 0000000000..6377082540 --- /dev/null +++ b/depends/protobuf/google/protobuf/repeated_field.h @@ -0,0 +1,1299 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// RepeatedField and RepeatedPtrField are used by generated protocol message +// classes to manipulate repeated fields. These classes are very similar to +// STL's vector, but include a number of optimizations found to be useful +// specifically in the case of Protocol Buffers. RepeatedPtrField is +// particularly different from STL vector as it manages ownership of the +// pointers that it contains. +// +// Typically, clients should not need to access RepeatedField objects directly, +// but should instead use the accessor functions generated automatically by the +// protocol compiler. + +#ifndef GOOGLE_PROTOBUF_REPEATED_FIELD_H__ +#define GOOGLE_PROTOBUF_REPEATED_FIELD_H__ + +#ifdef __GNUC__ +#pragma GCC system_header +#endif + +#include +#include +#include +#include + +namespace google { + +namespace protobuf { + +class Message; + +namespace internal { + +// We need this (from generated_message_reflection.cc). +LIBPROTOBUF_EXPORT int StringSpaceUsedExcludingSelf(const string& str); + +} // namespace internal + +// RepeatedField is used to represent repeated fields of a primitive type (in +// other words, everything except strings and nested Messages). Most users will +// not ever use a RepeatedField directly; they will use the get-by-index, +// set-by-index, and add accessors that are generated for all repeated fields. +template +class RepeatedField { + public: + RepeatedField(); + RepeatedField(const RepeatedField& other); + ~RepeatedField(); + + RepeatedField& operator=(const RepeatedField& other); + + int size() const; + + const Element& Get(int index) const; + Element* Mutable(int index); + void Set(int index, const Element& value); + void Add(const Element& value); + Element* Add(); + // Remove the last element in the array. + // We don't provide a way to remove any element other than the last + // because it invites inefficient use, such as O(n^2) filtering loops + // that should have been O(n). If you want to remove an element other + // than the last, the best way to do it is to re-arrange the elements + // so that the one you want removed is at the end, then call RemoveLast(). + void RemoveLast(); + void Clear(); + void MergeFrom(const RepeatedField& other); + void CopyFrom(const RepeatedField& other); + + // Reserve space to expand the field to at least the given size. If the + // array is grown, it will always be at least doubled in size. + void Reserve(int new_size); + + // Resize the RepeatedField to a new, smaller size. This is O(1). + void Truncate(int new_size); + + void AddAlreadyReserved(const Element& value); + Element* AddAlreadyReserved(); + int Capacity() const; + + // Gets the underlying array. This pointer is possibly invalidated by + // any add or remove operation. + Element* mutable_data(); + const Element* data() const; + + // Swap entire contents with "other". + void Swap(RepeatedField* other); + + // Swap two elements. + void SwapElements(int index1, int index2); + + // STL-like iterator support + typedef Element* iterator; + typedef const Element* const_iterator; + typedef Element value_type; + + iterator begin(); + const_iterator begin() const; + iterator end(); + const_iterator end() const; + + // Returns the number of bytes used by the repeated field, excluding + // sizeof(*this) + int SpaceUsedExcludingSelf() const; + + private: + static const int kInitialSize = 4; + + Element* elements_; + int current_size_; + int total_size_; + + Element initial_space_[kInitialSize]; + + // Move the contents of |from| into |to|, possibly clobbering |from| in the + // process. For primitive types this is just a memcpy(), but it could be + // specialized for non-primitive types to, say, swap each element instead. + void MoveArray(Element to[], Element from[], int size); + + // Copy the elements of |from| into |to|. + void CopyArray(Element to[], const Element from[], int size); +}; + +namespace internal { +template class RepeatedPtrIterator; +template class RepeatedPtrOverPtrsIterator; +} // namespace internal + +namespace internal { + +// This is the common base class for RepeatedPtrFields. It deals only in void* +// pointers. Users should not use this interface directly. +// +// The methods of this interface correspond to the methods of RepeatedPtrField, +// but may have a template argument called TypeHandler. Its signature is: +// class TypeHandler { +// public: +// typedef MyType Type; +// static Type* New(); +// static void Delete(Type*); +// static void Clear(Type*); +// static void Merge(const Type& from, Type* to); +// +// // Only needs to be implemented if SpaceUsedExcludingSelf() is called. +// static int SpaceUsed(const Type&); +// }; +class LIBPROTOBUF_EXPORT RepeatedPtrFieldBase { + protected: + // The reflection implementation needs to call protected methods directly, + // reinterpreting pointers as being to Message instead of a specific Message + // subclass. + friend class GeneratedMessageReflection; + + // ExtensionSet stores repeated message extensions as + // RepeatedPtrField, but non-lite ExtensionSets need to + // implement SpaceUsed(), and thus need to call SpaceUsedExcludingSelf() + // reinterpreting MessageLite as Message. ExtensionSet also needs to make + // use of AddFromCleared(), which is not part of the public interface. + friend class ExtensionSet; + + RepeatedPtrFieldBase(); + + // Must be called from destructor. + template + void Destroy(); + + int size() const; + + template + const typename TypeHandler::Type& Get(int index) const; + template + typename TypeHandler::Type* Mutable(int index); + template + typename TypeHandler::Type* Add(); + template + void RemoveLast(); + template + void Clear(); + template + void MergeFrom(const RepeatedPtrFieldBase& other); + template + void CopyFrom(const RepeatedPtrFieldBase& other); + + void Reserve(int new_size); + + int Capacity() const; + + // Used for constructing iterators. + void* const* raw_data() const; + void** raw_mutable_data() const; + + template + typename TypeHandler::Type** mutable_data(); + template + const typename TypeHandler::Type* const* data() const; + + void Swap(RepeatedPtrFieldBase* other); + + void SwapElements(int index1, int index2); + + template + int SpaceUsedExcludingSelf() const; + + + // Advanced memory management -------------------------------------- + + // Like Add(), but if there are no cleared objects to use, returns NULL. + template + typename TypeHandler::Type* AddFromCleared(); + + template + void AddAllocated(typename TypeHandler::Type* value); + template + typename TypeHandler::Type* ReleaseLast(); + + int ClearedCount() const; + template + void AddCleared(typename TypeHandler::Type* value); + template + typename TypeHandler::Type* ReleaseCleared(); + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPtrFieldBase); + + static const int kInitialSize = 4; + + void** elements_; + int current_size_; + int allocated_size_; + int total_size_; + + void* initial_space_[kInitialSize]; + + template + static inline typename TypeHandler::Type* cast(void* element) { + return reinterpret_cast(element); + } + template + static inline const typename TypeHandler::Type* cast(const void* element) { + return reinterpret_cast(element); + } +}; + +template +class GenericTypeHandler { + public: + typedef GenericType Type; + static GenericType* New() { return new GenericType; } + static void Delete(GenericType* value) { delete value; } + static void Clear(GenericType* value) { value->Clear(); } + static void Merge(const GenericType& from, GenericType* to) { + to->MergeFrom(from); + } + static int SpaceUsed(const GenericType& value) { return value.SpaceUsed(); } +}; + +template <> +inline void GenericTypeHandler::Merge( + const MessageLite& from, MessageLite* to) { + to->CheckTypeAndMergeFrom(from); +} + +// HACK: If a class is declared as DLL-exported in MSVC, it insists on +// generating copies of all its methods -- even inline ones -- to include +// in the DLL. But SpaceUsed() calls StringSpaceUsedExcludingSelf() which +// isn't in the lite library, therefore the lite library cannot link if +// StringTypeHandler is exported. So, we factor out StringTypeHandlerBase, +// export that, then make StringTypeHandler be a subclass which is NOT +// exported. +// TODO(kenton): There has to be a better way. +class LIBPROTOBUF_EXPORT StringTypeHandlerBase { + public: + typedef string Type; + static string* New(); + static void Delete(string* value); + static void Clear(string* value) { value->clear(); } + static void Merge(const string& from, string* to) { *to = from; } +}; + +class StringTypeHandler : public StringTypeHandlerBase { + public: + static int SpaceUsed(const string& value) { + return sizeof(value) + StringSpaceUsedExcludingSelf(value); + } +}; + + +} // namespace internal + +// RepeatedPtrField is like RepeatedField, but used for repeated strings or +// Messages. +template +class RepeatedPtrField : public internal::RepeatedPtrFieldBase { + public: + RepeatedPtrField(); + RepeatedPtrField(const RepeatedPtrField& other); + ~RepeatedPtrField(); + + RepeatedPtrField& operator=(const RepeatedPtrField& other); + + int size() const; + + const Element& Get(int index) const; + Element* Mutable(int index); + Element* Add(); + void RemoveLast(); // Remove the last element in the array. + void Clear(); + void MergeFrom(const RepeatedPtrField& other); + void CopyFrom(const RepeatedPtrField& other); + + // Reserve space to expand the field to at least the given size. This only + // resizes the pointer array; it doesn't allocate any objects. If the + // array is grown, it will always be at least doubled in size. + void Reserve(int new_size); + + int Capacity() const; + + // Gets the underlying array. This pointer is possibly invalidated by + // any add or remove operation. + Element** mutable_data(); + const Element* const* data() const; + + // Swap entire contents with "other". + void Swap(RepeatedPtrField* other); + + // Swap two elements. + void SwapElements(int index1, int index2); + + // STL-like iterator support + typedef internal::RepeatedPtrIterator iterator; + typedef internal::RepeatedPtrIterator const_iterator; + typedef Element value_type; + + iterator begin(); + const_iterator begin() const; + iterator end(); + const_iterator end() const; + + // Custom STL-like iterator that iterates over and returns the underlying + // pointers to Element rather than Element itself. + typedef internal::RepeatedPtrOverPtrsIterator pointer_iterator; + pointer_iterator pointer_begin(); + pointer_iterator pointer_end(); + + // Returns (an estimate of) the number of bytes used by the repeated field, + // excluding sizeof(*this). + int SpaceUsedExcludingSelf() const; + + // Advanced memory management -------------------------------------- + // When hardcore memory management becomes necessary -- as it often + // does here at Google -- the following methods may be useful. + + // Add an already-allocated object, passing ownership to the + // RepeatedPtrField. + void AddAllocated(Element* value); + // Remove the last element and return it, passing ownership to the + // caller. + // Requires: size() > 0 + Element* ReleaseLast(); + + // When elements are removed by calls to RemoveLast() or Clear(), they + // are not actually freed. Instead, they are cleared and kept so that + // they can be reused later. This can save lots of CPU time when + // repeatedly reusing a protocol message for similar purposes. + // + // Really, extremely hardcore programs may actually want to manipulate + // these objects to better-optimize memory management. These methods + // allow that. + + // Get the number of cleared objects that are currently being kept + // around for reuse. + int ClearedCount() const; + // Add an element to the pool of cleared objects, passing ownership to + // the RepeatedPtrField. The element must be cleared prior to calling + // this method. + void AddCleared(Element* value); + // Remove a single element from the cleared pool and return it, passing + // ownership to the caller. The element is guaranteed to be cleared. + // Requires: ClearedCount() > 0 + Element* ReleaseCleared(); + + protected: + // Note: RepeatedPtrField SHOULD NOT be subclassed by users. We only + // subclass it in one place as a hack for compatibility with proto1. The + // subclass needs to know about TypeHandler in order to call protected + // methods on RepeatedPtrFieldBase. + class TypeHandler; + +}; + +// implementation ==================================================== + +template +inline RepeatedField::RepeatedField() + : elements_(initial_space_), + current_size_(0), + total_size_(kInitialSize) { +} + +template +inline RepeatedField::RepeatedField(const RepeatedField& other) + : elements_(initial_space_), + current_size_(0), + total_size_(kInitialSize) { + CopyFrom(other); +} + +template +RepeatedField::~RepeatedField() { + if (elements_ != initial_space_) { + delete [] elements_; + } +} + +template +inline RepeatedField& +RepeatedField::operator=(const RepeatedField& other) { + CopyFrom(other); + return *this; +} + +template +inline int RepeatedField::size() const { + return current_size_; +} + +template +inline int RepeatedField::Capacity() const { + return total_size_; +} + +template +inline void RepeatedField::AddAlreadyReserved(const Element& value) { + GOOGLE_DCHECK_LT(size(), Capacity()); + elements_[current_size_++] = value; +} + +template +inline Element* RepeatedField::AddAlreadyReserved() { + GOOGLE_DCHECK_LT(size(), Capacity()); + return &elements_[current_size_++]; +} + +template +inline const Element& RepeatedField::Get(int index) const { + GOOGLE_DCHECK_LT(index, size()); + return elements_[index]; +} + +template +inline Element* RepeatedField::Mutable(int index) { + GOOGLE_DCHECK_LT(index, size()); + return elements_ + index; +} + +template +inline void RepeatedField::Set(int index, const Element& value) { + GOOGLE_DCHECK_LT(index, size()); + elements_[index] = value; +} + +template +inline void RepeatedField::Add(const Element& value) { + if (current_size_ == total_size_) Reserve(total_size_ + 1); + elements_[current_size_++] = value; +} + +template +inline Element* RepeatedField::Add() { + if (current_size_ == total_size_) Reserve(total_size_ + 1); + return &elements_[current_size_++]; +} + +template +inline void RepeatedField::RemoveLast() { + GOOGLE_DCHECK_GT(current_size_, 0); + --current_size_; +} + +template +inline void RepeatedField::Clear() { + current_size_ = 0; +} + +template +inline void RepeatedField::MergeFrom(const RepeatedField& other) { + Reserve(current_size_ + other.current_size_); + CopyArray(elements_ + current_size_, other.elements_, other.current_size_); + current_size_ += other.current_size_; +} + +template +inline void RepeatedField::CopyFrom(const RepeatedField& other) { + Clear(); + MergeFrom(other); +} + +template +inline Element* RepeatedField::mutable_data() { + return elements_; +} + +template +inline const Element* RepeatedField::data() const { + return elements_; +} + + +template +void RepeatedField::Swap(RepeatedField* other) { + Element* swap_elements = elements_; + int swap_current_size = current_size_; + int swap_total_size = total_size_; + // We may not be using initial_space_ but it's not worth checking. Just + // copy it anyway. + Element swap_initial_space[kInitialSize]; + MoveArray(swap_initial_space, initial_space_, kInitialSize); + + elements_ = other->elements_; + current_size_ = other->current_size_; + total_size_ = other->total_size_; + MoveArray(initial_space_, other->initial_space_, kInitialSize); + + other->elements_ = swap_elements; + other->current_size_ = swap_current_size; + other->total_size_ = swap_total_size; + MoveArray(other->initial_space_, swap_initial_space, kInitialSize); + + if (elements_ == other->initial_space_) { + elements_ = initial_space_; + } + if (other->elements_ == initial_space_) { + other->elements_ = other->initial_space_; + } +} + +template +void RepeatedField::SwapElements(int index1, int index2) { + std::swap(elements_[index1], elements_[index2]); +} + +template +inline typename RepeatedField::iterator +RepeatedField::begin() { + return elements_; +} +template +inline typename RepeatedField::const_iterator +RepeatedField::begin() const { + return elements_; +} +template +inline typename RepeatedField::iterator +RepeatedField::end() { + return elements_ + current_size_; +} +template +inline typename RepeatedField::const_iterator +RepeatedField::end() const { + return elements_ + current_size_; +} + +template +inline int RepeatedField::SpaceUsedExcludingSelf() const { + return (elements_ != initial_space_) ? total_size_ * sizeof(elements_[0]) : 0; +} + +// Avoid inlining of Reserve(): new, memcpy, and delete[] lead to a significant +// amount of code bloat. +template +void RepeatedField::Reserve(int new_size) { + if (total_size_ >= new_size) return; + + Element* old_elements = elements_; + total_size_ = max(total_size_ * 2, new_size); + elements_ = new Element[total_size_]; + MoveArray(elements_, old_elements, current_size_); + if (old_elements != initial_space_) { + delete [] old_elements; + } +} + +template +inline void RepeatedField::Truncate(int new_size) { + GOOGLE_DCHECK_LE(new_size, current_size_); + current_size_ = new_size; +} + +template +inline void RepeatedField::MoveArray( + Element to[], Element from[], int array_size) { + memcpy(to, from, array_size * sizeof(Element)); +} + +template +inline void RepeatedField::CopyArray( + Element to[], const Element from[], int array_size) { + memcpy(to, from, array_size * sizeof(Element)); +} + + +// ------------------------------------------------------------------- + +namespace internal { + +inline RepeatedPtrFieldBase::RepeatedPtrFieldBase() + : elements_(initial_space_), + current_size_(0), + allocated_size_(0), + total_size_(kInitialSize) { +} + +template +void RepeatedPtrFieldBase::Destroy() { + for (int i = 0; i < allocated_size_; i++) { + TypeHandler::Delete(cast(elements_[i])); + } + if (elements_ != initial_space_) { + delete [] elements_; + } +} + +inline int RepeatedPtrFieldBase::size() const { + return current_size_; +} + + +template +inline const typename TypeHandler::Type& +RepeatedPtrFieldBase::Get(int index) const { + GOOGLE_DCHECK_LT(index, size()); + return *cast(elements_[index]); +} + +template +inline typename TypeHandler::Type* +RepeatedPtrFieldBase::Mutable(int index) { + GOOGLE_DCHECK_LT(index, size()); + return cast(elements_[index]); +} + +template +inline typename TypeHandler::Type* RepeatedPtrFieldBase::Add() { + if (current_size_ < allocated_size_) { + return cast(elements_[current_size_++]); + } + if (allocated_size_ == total_size_) Reserve(total_size_ + 1); + ++allocated_size_; + typename TypeHandler::Type* result = TypeHandler::New(); + elements_[current_size_++] = result; + return result; +} + +template +inline void RepeatedPtrFieldBase::RemoveLast() { + GOOGLE_DCHECK_GT(current_size_, 0); + TypeHandler::Clear(cast(elements_[--current_size_])); +} + +template +void RepeatedPtrFieldBase::Clear() { + for (int i = 0; i < current_size_; i++) { + TypeHandler::Clear(cast(elements_[i])); + } + current_size_ = 0; +} + +template +inline void RepeatedPtrFieldBase::MergeFrom(const RepeatedPtrFieldBase& other) { + Reserve(current_size_ + other.current_size_); + for (int i = 0; i < other.current_size_; i++) { + TypeHandler::Merge(other.template Get(i), Add()); + } +} + +template +inline void RepeatedPtrFieldBase::CopyFrom(const RepeatedPtrFieldBase& other) { + RepeatedPtrFieldBase::Clear(); + RepeatedPtrFieldBase::MergeFrom(other); +} + +inline int RepeatedPtrFieldBase::Capacity() const { + return total_size_; +} + +inline void* const* RepeatedPtrFieldBase::raw_data() const { + return elements_; +} + +inline void** RepeatedPtrFieldBase::raw_mutable_data() const { + return elements_; +} + +template +inline typename TypeHandler::Type** RepeatedPtrFieldBase::mutable_data() { + // TODO(kenton): Breaks C++ aliasing rules. We should probably remove this + // method entirely. + return reinterpret_cast(elements_); +} + +template +inline const typename TypeHandler::Type* const* +RepeatedPtrFieldBase::data() const { + // TODO(kenton): Breaks C++ aliasing rules. We should probably remove this + // method entirely. + return reinterpret_cast(elements_); +} + +inline void RepeatedPtrFieldBase::SwapElements(int index1, int index2) { + std::swap(elements_[index1], elements_[index2]); +} + +template +inline int RepeatedPtrFieldBase::SpaceUsedExcludingSelf() const { + int allocated_bytes = + (elements_ != initial_space_) ? total_size_ * sizeof(elements_[0]) : 0; + for (int i = 0; i < allocated_size_; ++i) { + allocated_bytes += TypeHandler::SpaceUsed(*cast(elements_[i])); + } + return allocated_bytes; +} + +template +inline typename TypeHandler::Type* RepeatedPtrFieldBase::AddFromCleared() { + if (current_size_ < allocated_size_) { + return cast(elements_[current_size_++]); + } else { + return NULL; + } +} + +template +void RepeatedPtrFieldBase::AddAllocated( + typename TypeHandler::Type* value) { + // Make room for the new pointer. + if (current_size_ == total_size_) { + // The array is completely full with no cleared objects, so grow it. + Reserve(total_size_ + 1); + ++allocated_size_; + } else if (allocated_size_ == total_size_) { + // There is no more space in the pointer array because it contains some + // cleared objects awaiting reuse. We don't want to grow the array in this + // case because otherwise a loop calling AddAllocated() followed by Clear() + // would leak memory. + TypeHandler::Delete(cast(elements_[current_size_])); + } else if (current_size_ < allocated_size_) { + // We have some cleared objects. We don't care about their order, so we + // can just move the first one to the end to make space. + elements_[allocated_size_] = elements_[current_size_]; + ++allocated_size_; + } else { + // There are no cleared objects. + ++allocated_size_; + } + + elements_[current_size_++] = value; +} + +template +inline typename TypeHandler::Type* RepeatedPtrFieldBase::ReleaseLast() { + GOOGLE_DCHECK_GT(current_size_, 0); + typename TypeHandler::Type* result = + cast(elements_[--current_size_]); + --allocated_size_; + if (current_size_ < allocated_size_) { + // There are cleared elements on the end; replace the removed element + // with the last allocated element. + elements_[current_size_] = elements_[allocated_size_]; + } + return result; +} + + +inline int RepeatedPtrFieldBase::ClearedCount() const { + return allocated_size_ - current_size_; +} + +template +inline void RepeatedPtrFieldBase::AddCleared( + typename TypeHandler::Type* value) { + if (allocated_size_ == total_size_) Reserve(total_size_ + 1); + elements_[allocated_size_++] = value; +} + +template +inline typename TypeHandler::Type* RepeatedPtrFieldBase::ReleaseCleared() { + GOOGLE_DCHECK_GT(allocated_size_, current_size_); + return cast(elements_[--allocated_size_]); +} + +} // namespace internal + +// ------------------------------------------------------------------- + +template +class RepeatedPtrField::TypeHandler + : public internal::GenericTypeHandler {}; + +template <> +class RepeatedPtrField::TypeHandler + : public internal::StringTypeHandler {}; + + +template +inline RepeatedPtrField::RepeatedPtrField() {} + +template +inline RepeatedPtrField::RepeatedPtrField( + const RepeatedPtrField& other) { + CopyFrom(other); +} + +template +RepeatedPtrField::~RepeatedPtrField() { + Destroy(); +} + +template +inline RepeatedPtrField& RepeatedPtrField::operator=( + const RepeatedPtrField& other) { + CopyFrom(other); + return *this; +} + +template +inline int RepeatedPtrField::size() const { + return RepeatedPtrFieldBase::size(); +} + +template +inline const Element& RepeatedPtrField::Get(int index) const { + return RepeatedPtrFieldBase::Get(index); +} + +template +inline Element* RepeatedPtrField::Mutable(int index) { + return RepeatedPtrFieldBase::Mutable(index); +} + +template +inline Element* RepeatedPtrField::Add() { + return RepeatedPtrFieldBase::Add(); +} + +template +inline void RepeatedPtrField::RemoveLast() { + RepeatedPtrFieldBase::RemoveLast(); +} + +template +inline void RepeatedPtrField::Clear() { + RepeatedPtrFieldBase::Clear(); +} + +template +inline void RepeatedPtrField::MergeFrom( + const RepeatedPtrField& other) { + RepeatedPtrFieldBase::MergeFrom(other); +} + +template +inline void RepeatedPtrField::CopyFrom( + const RepeatedPtrField& other) { + RepeatedPtrFieldBase::CopyFrom(other); +} + +template +inline Element** RepeatedPtrField::mutable_data() { + return RepeatedPtrFieldBase::mutable_data(); +} + +template +inline const Element* const* RepeatedPtrField::data() const { + return RepeatedPtrFieldBase::data(); +} + +template +void RepeatedPtrField::Swap(RepeatedPtrField* other) { + RepeatedPtrFieldBase::Swap(other); +} + +template +void RepeatedPtrField::SwapElements(int index1, int index2) { + RepeatedPtrFieldBase::SwapElements(index1, index2); +} + +template +inline int RepeatedPtrField::SpaceUsedExcludingSelf() const { + return RepeatedPtrFieldBase::SpaceUsedExcludingSelf(); +} + +template +inline void RepeatedPtrField::AddAllocated(Element* value) { + RepeatedPtrFieldBase::AddAllocated(value); +} + +template +inline Element* RepeatedPtrField::ReleaseLast() { + return RepeatedPtrFieldBase::ReleaseLast(); +} + + +template +inline int RepeatedPtrField::ClearedCount() const { + return RepeatedPtrFieldBase::ClearedCount(); +} + +template +inline void RepeatedPtrField::AddCleared(Element* value) { + return RepeatedPtrFieldBase::AddCleared(value); +} + +template +inline Element* RepeatedPtrField::ReleaseCleared() { + return RepeatedPtrFieldBase::ReleaseCleared(); +} + +template +inline void RepeatedPtrField::Reserve(int new_size) { + return RepeatedPtrFieldBase::Reserve(new_size); +} + +template +inline int RepeatedPtrField::Capacity() const { + return RepeatedPtrFieldBase::Capacity(); +} + +// ------------------------------------------------------------------- + +namespace internal { + +// STL-like iterator implementation for RepeatedPtrField. You should not +// refer to this class directly; use RepeatedPtrField::iterator instead. +// +// The iterator for RepeatedPtrField, RepeatedPtrIterator, is +// very similar to iterator_ptr in util/gtl/iterator_adaptors-inl.h, +// but adds random-access operators and is modified to wrap a void** base +// iterator (since RepeatedPtrField stores its array as a void* array and +// casting void** to T** would violate C++ aliasing rules). +// +// This code based on net/proto/proto-array-internal.h by Jeffrey Yasskin +// (jyasskin@google.com). +template +class RepeatedPtrIterator + : public std::iterator< + std::random_access_iterator_tag, Element> { + public: + typedef RepeatedPtrIterator iterator; + typedef std::iterator< + std::random_access_iterator_tag, Element> superclass; + + // Let the compiler know that these are type names, so we don't have to + // write "typename" in front of them everywhere. + typedef typename superclass::reference reference; + typedef typename superclass::pointer pointer; + typedef typename superclass::difference_type difference_type; + + RepeatedPtrIterator() : it_(NULL) {} + explicit RepeatedPtrIterator(void* const* it) : it_(it) {} + + // Allow "upcasting" from RepeatedPtrIterator to + // RepeatedPtrIterator. + template + RepeatedPtrIterator(const RepeatedPtrIterator& other) + : it_(other.it_) { + // Force a compiler error if the other type is not convertible to ours. + if (false) { + implicit_cast(0); + } + } + + // dereferenceable + reference operator*() const { return *reinterpret_cast(*it_); } + pointer operator->() const { return &(operator*()); } + + // {inc,dec}rementable + iterator& operator++() { ++it_; return *this; } + iterator operator++(int) { return iterator(it_++); } + iterator& operator--() { --it_; return *this; } + iterator operator--(int) { return iterator(it_--); } + + // equality_comparable + bool operator==(const iterator& x) const { return it_ == x.it_; } + bool operator!=(const iterator& x) const { return it_ != x.it_; } + + // less_than_comparable + bool operator<(const iterator& x) const { return it_ < x.it_; } + bool operator<=(const iterator& x) const { return it_ <= x.it_; } + bool operator>(const iterator& x) const { return it_ > x.it_; } + bool operator>=(const iterator& x) const { return it_ >= x.it_; } + + // addable, subtractable + iterator& operator+=(difference_type d) { + it_ += d; + return *this; + } + friend iterator operator+(iterator it, difference_type d) { + it += d; + return it; + } + friend iterator operator+(difference_type d, iterator it) { + it += d; + return it; + } + iterator& operator-=(difference_type d) { + it_ -= d; + return *this; + } + friend iterator operator-(iterator it, difference_type d) { + it -= d; + return it; + } + + // indexable + reference operator[](difference_type d) const { return *(*this + d); } + + // random access iterator + difference_type operator-(const iterator& x) const { return it_ - x.it_; } + + private: + template + friend class RepeatedPtrIterator; + + // The internal iterator. + void* const* it_; +}; + +// Provide an iterator that operates on pointers to the underlying objects +// rather than the objects themselves as RepeatedPtrIterator does. +// Consider using this when working with stl algorithms that change +// the array. +template +class RepeatedPtrOverPtrsIterator + : public std::iterator { + public: + typedef RepeatedPtrOverPtrsIterator iterator; + typedef std::iterator< + std::random_access_iterator_tag, Element*> superclass; + + // Let the compiler know that these are type names, so we don't have to + // write "typename" in front of them everywhere. + typedef typename superclass::reference reference; + typedef typename superclass::pointer pointer; + typedef typename superclass::difference_type difference_type; + + RepeatedPtrOverPtrsIterator() : it_(NULL) {} + explicit RepeatedPtrOverPtrsIterator(void** it) : it_(it) {} + + // dereferenceable + reference operator*() const { return *reinterpret_cast(it_); } + pointer operator->() const { return &(operator*()); } + + // {inc,dec}rementable + iterator& operator++() { ++it_; return *this; } + iterator operator++(int) { return iterator(it_++); } + iterator& operator--() { --it_; return *this; } + iterator operator--(int) { return iterator(it_--); } + + // equality_comparable + bool operator==(const iterator& x) const { return it_ == x.it_; } + bool operator!=(const iterator& x) const { return it_ != x.it_; } + + // less_than_comparable + bool operator<(const iterator& x) const { return it_ < x.it_; } + bool operator<=(const iterator& x) const { return it_ <= x.it_; } + bool operator>(const iterator& x) const { return it_ > x.it_; } + bool operator>=(const iterator& x) const { return it_ >= x.it_; } + + // addable, subtractable + iterator& operator+=(difference_type d) { + it_ += d; + return *this; + } + friend iterator operator+(iterator it, difference_type d) { + it += d; + return it; + } + friend iterator operator+(difference_type d, iterator it) { + it += d; + return it; + } + iterator& operator-=(difference_type d) { + it_ -= d; + return *this; + } + friend iterator operator-(iterator it, difference_type d) { + it -= d; + return it; + } + + // indexable + reference operator[](difference_type d) const { return *(*this + d); } + + // random access iterator + difference_type operator-(const iterator& x) const { return it_ - x.it_; } + + private: + template + friend class RepeatedPtrIterator; + + // The internal iterator. + void** it_; +}; + + +} // namespace internal + +template +inline typename RepeatedPtrField::iterator +RepeatedPtrField::begin() { + return iterator(raw_data()); +} +template +inline typename RepeatedPtrField::const_iterator +RepeatedPtrField::begin() const { + return iterator(raw_data()); +} +template +inline typename RepeatedPtrField::iterator +RepeatedPtrField::end() { + return iterator(raw_data() + size()); +} +template +inline typename RepeatedPtrField::const_iterator +RepeatedPtrField::end() const { + return iterator(raw_data() + size()); +} + +template +inline typename RepeatedPtrField::pointer_iterator +RepeatedPtrField::pointer_begin() { + return pointer_iterator(raw_mutable_data()); +} +template +inline typename RepeatedPtrField::pointer_iterator +RepeatedPtrField::pointer_end() { + return pointer_iterator(raw_mutable_data() + size()); +} + + +// Iterators and helper functions that follow the spirit of the STL +// std::back_insert_iterator and std::back_inserter but are tailor-made +// for RepeatedField and RepatedPtrField. Typical usage would be: +// +// std::copy(some_sequence.begin(), some_sequence.end(), +// google::protobuf::RepeatedFieldBackInserter(proto.mutable_sequence())); +// +// Ported by johannes from util/gtl/proto-array-iterators-inl.h + +namespace internal { +// A back inserter for RepeatedField objects. +template class RepeatedFieldBackInsertIterator + : public std::iterator { + public: + explicit RepeatedFieldBackInsertIterator( + RepeatedField* const mutable_field) + : field_(mutable_field) { + } + RepeatedFieldBackInsertIterator& operator=(const T& value) { + field_->Add(value); + return *this; + } + RepeatedFieldBackInsertIterator& operator*() { + return *this; + } + RepeatedFieldBackInsertIterator& operator++() { + return *this; + } + RepeatedFieldBackInsertIterator& operator++(int ignores_parameter) { + return *this; + } + + private: + RepeatedField* field_; +}; + +// A back inserter for RepeatedPtrField objects. +template class RepeatedPtrFieldBackInsertIterator + : public std::iterator { + public: + RepeatedPtrFieldBackInsertIterator( + RepeatedPtrField* const mutable_field) + : field_(mutable_field) { + } + RepeatedPtrFieldBackInsertIterator& operator=(const T& value) { + *field_->Add() = value; + return *this; + } + RepeatedPtrFieldBackInsertIterator& operator=( + const T* const ptr_to_value) { + *field_->Add() = *ptr_to_value; + return *this; + } + RepeatedPtrFieldBackInsertIterator& operator*() { + return *this; + } + RepeatedPtrFieldBackInsertIterator& operator++() { + return *this; + } + RepeatedPtrFieldBackInsertIterator& operator++(int ignores_parameter) { + return *this; + } + + private: + RepeatedPtrField* field_; +}; + +// A back inserter for RepeatedPtrFields that inserts by transfering ownership +// of a pointer. +template class AllocatedRepeatedPtrFieldBackInsertIterator + : public std::iterator { + public: + explicit AllocatedRepeatedPtrFieldBackInsertIterator( + RepeatedPtrField* const mutable_field) + : field_(mutable_field) { + } + AllocatedRepeatedPtrFieldBackInsertIterator& operator=( + T* const ptr_to_value) { + field_->AddAllocated(ptr_to_value); + return *this; + } + AllocatedRepeatedPtrFieldBackInsertIterator& operator*() { + return *this; + } + AllocatedRepeatedPtrFieldBackInsertIterator& operator++() { + return *this; + } + AllocatedRepeatedPtrFieldBackInsertIterator& operator++( + int ignores_parameter) { + return *this; + } + + private: + RepeatedPtrField* field_; +}; +} // namespace internal + +// Provides a back insert iterator for RepeatedField instances, +// similar to std::back_inserter(). Note the identically named +// function for RepeatedPtrField instances. +template internal::RepeatedFieldBackInsertIterator +RepeatedFieldBackInserter(RepeatedField* const mutable_field) { + return internal::RepeatedFieldBackInsertIterator(mutable_field); +} + +// Provides a back insert iterator for RepeatedPtrField instances, +// similar to std::back_inserter(). Note the identically named +// function for RepeatedField instances. +template internal::RepeatedPtrFieldBackInsertIterator +RepeatedFieldBackInserter(RepeatedPtrField* const mutable_field) { + return internal::RepeatedPtrFieldBackInsertIterator(mutable_field); +} + +// Provides a back insert iterator for RepeatedPtrField instances +// similar to std::back_inserter() which transfers the ownership while +// copying elements. +template internal::AllocatedRepeatedPtrFieldBackInsertIterator +AllocatedRepeatedPtrFieldBackInserter( + RepeatedPtrField* const mutable_field) { + return internal::AllocatedRepeatedPtrFieldBackInsertIterator( + mutable_field); +} + +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_REPEATED_FIELD_H__ diff --git a/depends/protobuf/google/protobuf/service.cc b/depends/protobuf/google/protobuf/service.cc new file mode 100644 index 0000000000..caf968ca5b --- /dev/null +++ b/depends/protobuf/google/protobuf/service.cc @@ -0,0 +1,46 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include + +namespace google { +namespace protobuf { + +Service::~Service() {} +RpcChannel::~RpcChannel() {} +RpcController::~RpcController() {} + +} // namespace protobuf + +} // namespace google diff --git a/depends/protobuf/google/protobuf/service.h b/depends/protobuf/google/protobuf/service.h new file mode 100644 index 0000000000..a6a7d16deb --- /dev/null +++ b/depends/protobuf/google/protobuf/service.h @@ -0,0 +1,291 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// DEPRECATED: This module declares the abstract interfaces underlying proto2 +// RPC services. These are intented to be independent of any particular RPC +// implementation, so that proto2 services can be used on top of a variety +// of implementations. Starting with version 2.3.0, RPC implementations should +// not try to build on these, but should instead provide code generator plugins +// which generate code specific to the particular RPC implementation. This way +// the generated code can be more appropriate for the implementation in use +// and can avoid unnecessary layers of indirection. +// +// +// When you use the protocol compiler to compile a service definition, it +// generates two classes: An abstract interface for the service (with +// methods matching the service definition) and a "stub" implementation. +// A stub is just a type-safe wrapper around an RpcChannel which emulates a +// local implementation of the service. +// +// For example, the service definition: +// service MyService { +// rpc Foo(MyRequest) returns(MyResponse); +// } +// will generate abstract interface "MyService" and class "MyService::Stub". +// You could implement a MyService as follows: +// class MyServiceImpl : public MyService { +// public: +// MyServiceImpl() {} +// ~MyServiceImpl() {} +// +// // implements MyService --------------------------------------- +// +// void Foo(google::protobuf::RpcController* controller, +// const MyRequest* request, +// MyResponse* response, +// Closure* done) { +// // ... read request and fill in response ... +// done->Run(); +// } +// }; +// You would then register an instance of MyServiceImpl with your RPC server +// implementation. (How to do that depends on the implementation.) +// +// To call a remote MyServiceImpl, first you need an RpcChannel connected to it. +// How to construct a channel depends, again, on your RPC implementation. +// Here we use a hypothentical "MyRpcChannel" as an example: +// MyRpcChannel channel("rpc:hostname:1234/myservice"); +// MyRpcController controller; +// MyServiceImpl::Stub stub(&channel); +// FooRequest request; +// FooRespnose response; +// +// // ... fill in request ... +// +// stub.Foo(&controller, request, &response, NewCallback(HandleResponse)); +// +// On Thread-Safety: +// +// Different RPC implementations may make different guarantees about what +// threads they may run callbacks on, and what threads the application is +// allowed to use to call the RPC system. Portable software should be ready +// for callbacks to be called on any thread, but should not try to call the +// RPC system from any thread except for the ones on which it received the +// callbacks. Realistically, though, simple software will probably want to +// use a single-threaded RPC system while high-end software will want to +// use multiple threads. RPC implementations should provide multiple +// choices. + +#ifndef GOOGLE_PROTOBUF_SERVICE_H__ +#define GOOGLE_PROTOBUF_SERVICE_H__ + +#include +#include + +namespace google { +namespace protobuf { + +// Defined in this file. +class Service; +class RpcController; +class RpcChannel; + +// Defined in other files. +class Descriptor; // descriptor.h +class ServiceDescriptor; // descriptor.h +class MethodDescriptor; // descriptor.h +class Message; // message.h + +// Abstract base interface for protocol-buffer-based RPC services. Services +// themselves are abstract interfaces (implemented either by servers or as +// stubs), but they subclass this base interface. The methods of this +// interface can be used to call the methods of the Service without knowing +// its exact type at compile time (analogous to Reflection). +class LIBPROTOBUF_EXPORT Service { + public: + inline Service() {} + virtual ~Service(); + + // When constructing a stub, you may pass STUB_OWNS_CHANNEL as the second + // parameter to the constructor to tell it to delete its RpcChannel when + // destroyed. + enum ChannelOwnership { + STUB_OWNS_CHANNEL, + STUB_DOESNT_OWN_CHANNEL + }; + + // Get the ServiceDescriptor describing this service and its methods. + virtual const ServiceDescriptor* GetDescriptor() = 0; + + // Call a method of the service specified by MethodDescriptor. This is + // normally implemented as a simple switch() that calls the standard + // definitions of the service's methods. + // + // Preconditions: + // * method->service() == GetDescriptor() + // * request and response are of the exact same classes as the objects + // returned by GetRequestPrototype(method) and + // GetResponsePrototype(method). + // * After the call has started, the request must not be modified and the + // response must not be accessed at all until "done" is called. + // * "controller" is of the correct type for the RPC implementation being + // used by this Service. For stubs, the "correct type" depends on the + // RpcChannel which the stub is using. Server-side Service + // implementations are expected to accept whatever type of RpcController + // the server-side RPC implementation uses. + // + // Postconditions: + // * "done" will be called when the method is complete. This may be + // before CallMethod() returns or it may be at some point in the future. + // * If the RPC succeeded, "response" contains the response returned by + // the server. + // * If the RPC failed, "response"'s contents are undefined. The + // RpcController can be queried to determine if an error occurred and + // possibly to get more information about the error. + virtual void CallMethod(const MethodDescriptor* method, + RpcController* controller, + const Message* request, + Message* response, + Closure* done) = 0; + + // CallMethod() requires that the request and response passed in are of a + // particular subclass of Message. GetRequestPrototype() and + // GetResponsePrototype() get the default instances of these required types. + // You can then call Message::New() on these instances to construct mutable + // objects which you can then pass to CallMethod(). + // + // Example: + // const MethodDescriptor* method = + // service->GetDescriptor()->FindMethodByName("Foo"); + // Message* request = stub->GetRequestPrototype (method)->New(); + // Message* response = stub->GetResponsePrototype(method)->New(); + // request->ParseFromString(input); + // service->CallMethod(method, *request, response, callback); + virtual const Message& GetRequestPrototype( + const MethodDescriptor* method) const = 0; + virtual const Message& GetResponsePrototype( + const MethodDescriptor* method) const = 0; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Service); +}; + +// An RpcController mediates a single method call. The primary purpose of +// the controller is to provide a way to manipulate settings specific to the +// RPC implementation and to find out about RPC-level errors. +// +// The methods provided by the RpcController interface are intended to be a +// "least common denominator" set of features which we expect all +// implementations to support. Specific implementations may provide more +// advanced features (e.g. deadline propagation). +class LIBPROTOBUF_EXPORT RpcController { + public: + inline RpcController() {} + virtual ~RpcController(); + + // Client-side methods --------------------------------------------- + // These calls may be made from the client side only. Their results + // are undefined on the server side (may crash). + + // Resets the RpcController to its initial state so that it may be reused in + // a new call. Must not be called while an RPC is in progress. + virtual void Reset() = 0; + + // After a call has finished, returns true if the call failed. The possible + // reasons for failure depend on the RPC implementation. Failed() must not + // be called before a call has finished. If Failed() returns true, the + // contents of the response message are undefined. + virtual bool Failed() const = 0; + + // If Failed() is true, returns a human-readable description of the error. + virtual string ErrorText() const = 0; + + // Advises the RPC system that the caller desires that the RPC call be + // canceled. The RPC system may cancel it immediately, may wait awhile and + // then cancel it, or may not even cancel the call at all. If the call is + // canceled, the "done" callback will still be called and the RpcController + // will indicate that the call failed at that time. + virtual void StartCancel() = 0; + + // Server-side methods --------------------------------------------- + // These calls may be made from the server side only. Their results + // are undefined on the client side (may crash). + + // Causes Failed() to return true on the client side. "reason" will be + // incorporated into the message returned by ErrorText(). If you find + // you need to return machine-readable information about failures, you + // should incorporate it into your response protocol buffer and should + // NOT call SetFailed(). + virtual void SetFailed(const string& reason) = 0; + + // If true, indicates that the client canceled the RPC, so the server may + // as well give up on replying to it. The server should still call the + // final "done" callback. + virtual bool IsCanceled() const = 0; + + // Asks that the given callback be called when the RPC is canceled. The + // callback will always be called exactly once. If the RPC completes without + // being canceled, the callback will be called after completion. If the RPC + // has already been canceled when NotifyOnCancel() is called, the callback + // will be called immediately. + // + // NotifyOnCancel() must be called no more than once per request. + virtual void NotifyOnCancel(Closure* callback) = 0; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RpcController); +}; + +// Abstract interface for an RPC channel. An RpcChannel represents a +// communication line to a Service which can be used to call that Service's +// methods. The Service may be running on another machine. Normally, you +// should not call an RpcChannel directly, but instead construct a stub Service +// wrapping it. Example: +// RpcChannel* channel = new MyRpcChannel("remotehost.example.com:1234"); +// MyService* service = new MyService::Stub(channel); +// service->MyMethod(request, &response, callback); +class LIBPROTOBUF_EXPORT RpcChannel { + public: + inline RpcChannel() {} + virtual ~RpcChannel(); + + // Call the given method of the remote service. The signature of this + // procedure looks the same as Service::CallMethod(), but the requirements + // are less strict in one important way: the request and response objects + // need not be of any specific class as long as their descriptors are + // method->input_type() and method->output_type(). + virtual void CallMethod(const MethodDescriptor* method, + RpcController* controller, + const Message* request, + Message* response, + Closure* done) = 0; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RpcChannel); +}; + +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_SERVICE_H__ diff --git a/depends/protobuf/google/protobuf/stubs/common.cc b/depends/protobuf/google/protobuf/stubs/common.cc new file mode 100644 index 0000000000..7b15be44d8 --- /dev/null +++ b/depends/protobuf/google/protobuf/stubs/common.cc @@ -0,0 +1,377 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) + +#include +#include +#include +#include +#include + +#include "config.h" + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN // We only need minimal includes +#include +#define snprintf _snprintf // see comment in strutil.cc +#elif defined(HAVE_PTHREAD) +#include +#else +#error "No suitable threading library available." +#endif + +namespace google { +namespace protobuf { + +namespace internal { + +void VerifyVersion(int headerVersion, + int minLibraryVersion, + const char* filename) { + if (GOOGLE_PROTOBUF_VERSION < minLibraryVersion) { + // Library is too old for headers. + GOOGLE_LOG(FATAL) + << "This program requires version " << VersionString(minLibraryVersion) + << " of the Protocol Buffer runtime library, but the installed version " + "is " << VersionString(GOOGLE_PROTOBUF_VERSION) << ". Please update " + "your library. If you compiled the program yourself, make sure that " + "your headers are from the same version of Protocol Buffers as your " + "link-time library. (Version verification failed in \"" + << filename << "\".)"; + } + if (headerVersion < kMinHeaderVersionForLibrary) { + // Headers are too old for library. + GOOGLE_LOG(FATAL) + << "This program was compiled against version " + << VersionString(headerVersion) << " of the Protocol Buffer runtime " + "library, which is not compatible with the installed version (" + << VersionString(GOOGLE_PROTOBUF_VERSION) << "). Contact the program " + "author for an update. If you compiled the program yourself, make " + "sure that your headers are from the same version of Protocol Buffers " + "as your link-time library. (Version verification failed in \"" + << filename << "\".)"; + } +} + +string VersionString(int version) { + int major = version / 1000000; + int minor = (version / 1000) % 1000; + int micro = version % 1000; + + // 128 bytes should always be enough, but we use snprintf() anyway to be + // safe. + char buffer[128]; + snprintf(buffer, sizeof(buffer), "%d.%d.%d", major, minor, micro); + + // Guard against broken MSVC snprintf(). + buffer[sizeof(buffer)-1] = '\0'; + + return buffer; +} + +} // namespace internal + +// =================================================================== +// emulates google3/base/logging.cc + +namespace internal { + +void DefaultLogHandler(LogLevel level, const char* filename, int line, + const string& message) { + static const char* level_names[] = { "INFO", "WARNING", "ERROR", "FATAL" }; + + // We use fprintf() instead of cerr because we want this to work at static + // initialization time. + fprintf(stderr, "libprotobuf %s %s:%d] %s\n", + level_names[level], filename, line, message.c_str()); + fflush(stderr); // Needed on MSVC. +} + +void NullLogHandler(LogLevel level, const char* filename, int line, + const string& message) { + // Nothing. +} + +static LogHandler* log_handler_ = &DefaultLogHandler; +static int log_silencer_count_ = 0; + +static Mutex* log_silencer_count_mutex_ = NULL; +GOOGLE_PROTOBUF_DECLARE_ONCE(log_silencer_count_init_); + +void DeleteLogSilencerCount() { + delete log_silencer_count_mutex_; + log_silencer_count_mutex_ = NULL; +} +void InitLogSilencerCount() { + log_silencer_count_mutex_ = new Mutex; + OnShutdown(&DeleteLogSilencerCount); +} +void InitLogSilencerCountOnce() { + GoogleOnceInit(&log_silencer_count_init_, &InitLogSilencerCount); +} + +LogMessage& LogMessage::operator<<(const string& value) { + message_ += value; + return *this; +} + +LogMessage& LogMessage::operator<<(const char* value) { + message_ += value; + return *this; +} + +// Since this is just for logging, we don't care if the current locale changes +// the results -- in fact, we probably prefer that. So we use snprintf() +// instead of Simple*toa(). +#undef DECLARE_STREAM_OPERATOR +#define DECLARE_STREAM_OPERATOR(TYPE, FORMAT) \ + LogMessage& LogMessage::operator<<(TYPE value) { \ + /* 128 bytes should be big enough for any of the primitive */ \ + /* values which we print with this, but well use snprintf() */ \ + /* anyway to be extra safe. */ \ + char buffer[128]; \ + snprintf(buffer, sizeof(buffer), FORMAT, value); \ + /* Guard against broken MSVC snprintf(). */ \ + buffer[sizeof(buffer)-1] = '\0'; \ + message_ += buffer; \ + return *this; \ + } + +DECLARE_STREAM_OPERATOR(char , "%c" ) +DECLARE_STREAM_OPERATOR(int , "%d" ) +DECLARE_STREAM_OPERATOR(uint , "%u" ) +DECLARE_STREAM_OPERATOR(long , "%ld") +DECLARE_STREAM_OPERATOR(unsigned long, "%lu") +DECLARE_STREAM_OPERATOR(double , "%g" ) +#undef DECLARE_STREAM_OPERATOR + +LogMessage::LogMessage(LogLevel level, const char* filename, int line) + : level_(level), filename_(filename), line_(line) {} +LogMessage::~LogMessage() {} + +void LogMessage::Finish() { + bool suppress = false; + + if (level_ != LOGLEVEL_FATAL) { + InitLogSilencerCountOnce(); + MutexLock lock(log_silencer_count_mutex_); + suppress = internal::log_silencer_count_ > 0; + } + + if (!suppress) { + internal::log_handler_(level_, filename_, line_, message_); + } + + if (level_ == LOGLEVEL_FATAL) { +#ifdef PROTOBUF_USE_EXCEPTIONS + throw FatalException(filename_, line_, message_); +#else + abort(); +#endif + } +} + +void LogFinisher::operator=(LogMessage& other) { + other.Finish(); +} + +} // namespace internal + +LogHandler* SetLogHandler(LogHandler* new_func) { + LogHandler* old = internal::log_handler_; + if (old == &internal::NullLogHandler) { + old = NULL; + } + if (new_func == NULL) { + internal::log_handler_ = &internal::NullLogHandler; + } else { + internal::log_handler_ = new_func; + } + return old; +} + +LogSilencer::LogSilencer() { + internal::InitLogSilencerCountOnce(); + MutexLock lock(internal::log_silencer_count_mutex_); + ++internal::log_silencer_count_; +}; + +LogSilencer::~LogSilencer() { + internal::InitLogSilencerCountOnce(); + MutexLock lock(internal::log_silencer_count_mutex_); + --internal::log_silencer_count_; +}; + +// =================================================================== +// emulates google3/base/callback.cc + +Closure::~Closure() {} + +namespace internal { FunctionClosure0::~FunctionClosure0() {} } + +void DoNothing() {} + +// =================================================================== +// emulates google3/base/mutex.cc + +#ifdef _WIN32 + +struct Mutex::Internal { + CRITICAL_SECTION mutex; +#ifndef NDEBUG + // Used only to implement AssertHeld(). + DWORD thread_id; +#endif +}; + +Mutex::Mutex() + : mInternal(new Internal) { + InitializeCriticalSection(&mInternal->mutex); +} + +Mutex::~Mutex() { + DeleteCriticalSection(&mInternal->mutex); + delete mInternal; +} + +void Mutex::Lock() { + EnterCriticalSection(&mInternal->mutex); +#ifndef NDEBUG + mInternal->thread_id = GetCurrentThreadId(); +#endif +} + +void Mutex::Unlock() { +#ifndef NDEBUG + mInternal->thread_id = 0; +#endif + LeaveCriticalSection(&mInternal->mutex); +} + +void Mutex::AssertHeld() { +#ifndef NDEBUG + GOOGLE_DCHECK_EQ(mInternal->thread_id, GetCurrentThreadId()); +#endif +} + +#elif defined(HAVE_PTHREAD) + +struct Mutex::Internal { + pthread_mutex_t mutex; +}; + +Mutex::Mutex() + : mInternal(new Internal) { + pthread_mutex_init(&mInternal->mutex, NULL); +} + +Mutex::~Mutex() { + pthread_mutex_destroy(&mInternal->mutex); + delete mInternal; +} + +void Mutex::Lock() { + int result = pthread_mutex_lock(&mInternal->mutex); + if (result != 0) { + GOOGLE_LOG(FATAL) << "pthread_mutex_lock: " << strerror(result); + } +} + +void Mutex::Unlock() { + int result = pthread_mutex_unlock(&mInternal->mutex); + if (result != 0) { + GOOGLE_LOG(FATAL) << "pthread_mutex_unlock: " << strerror(result); + } +} + +void Mutex::AssertHeld() { + // pthreads dosn't provide a way to check which thread holds the mutex. + // TODO(kenton): Maybe keep track of locking thread ID like with WIN32? +} + +#endif + +// =================================================================== +// Shutdown support. + +namespace internal { + +typedef void OnShutdownFunc(); +vector* shutdown_functions = NULL; +Mutex* shutdown_functions_mutex = NULL; +GOOGLE_PROTOBUF_DECLARE_ONCE(shutdown_functions_init); + +void InitShutdownFunctions() { + shutdown_functions = new vector; + shutdown_functions_mutex = new Mutex; +} + +inline void InitShutdownFunctionsOnce() { + GoogleOnceInit(&shutdown_functions_init, &InitShutdownFunctions); +} + +void OnShutdown(void (*func)()) { + InitShutdownFunctionsOnce(); + MutexLock lock(shutdown_functions_mutex); + shutdown_functions->push_back(func); +} + +} // namespace internal + +void ShutdownProtobufLibrary() { + internal::InitShutdownFunctionsOnce(); + + // We don't need to lock shutdown_functions_mutex because it's up to the + // caller to make sure that no one is using the library before this is + // called. + + // Make it safe to call this multiple times. + if (internal::shutdown_functions == NULL) return; + + for (int i = 0; i < internal::shutdown_functions->size(); i++) { + internal::shutdown_functions->at(i)(); + } + delete internal::shutdown_functions; + internal::shutdown_functions = NULL; + delete internal::shutdown_functions_mutex; + internal::shutdown_functions_mutex = NULL; +} + +#ifdef PROTOBUF_USE_EXCEPTIONS +FatalException::~FatalException() throw() {} + +const char* FatalException::what() const throw() { + return message_.c_str(); +} +#endif + +} // namespace protobuf +} // namespace google diff --git a/depends/protobuf/google/protobuf/stubs/common.h b/depends/protobuf/google/protobuf/stubs/common.h new file mode 100644 index 0000000000..9cd2b9e9ad --- /dev/null +++ b/depends/protobuf/google/protobuf/stubs/common.h @@ -0,0 +1,1234 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) and others +// +// Contains basic types and utilities used by the rest of the library. + +#ifndef GOOGLE_PROTOBUF_COMMON_H__ +#define GOOGLE_PROTOBUF_COMMON_H__ + +#include +#include +#include +#include +#include +#if defined(__osf__) +// Tru64 lacks stdint.h, but has inttypes.h which defines a superset of +// what stdint.h would define. +#include +#elif !defined(_MSC_VER) +#include +#endif +#include + +using std::min; +using std::max; + +// make MSVC shut up about some things +#ifdef _MSC_VER + // don't spew nonsense! + #pragma warning( disable: 4251 ) + // POSIX is OK, stop complaining. + #pragma warning( disable: 4996 ) + // using 'this' in initializer lists... + #pragma warning( disable: 4355 ) + // signed/unsigned mismatch + #pragma warning( disable: 4018 ) + // possible loss of data from assignments between different numeric types + #pragma warning( disable: 4244 ) + // forcing value to 'bool' + #pragma warning( disable: 4800 ) +#endif + +#if defined(_MSC_VER) && defined(_CPPUNWIND) + #define PROTOBUF_USE_EXCEPTIONS +#elif defined(__EXCEPTIONS) + #define PROTOBUF_USE_EXCEPTIONS +#endif +#ifdef PROTOBUF_USE_EXCEPTIONS +#include +#endif + +#if defined(_WIN32) && defined(GetMessage) +// Allow GetMessage to be used as a valid method name in protobuf classes. +// windows.h defines GetMessage() as a macro. Let's re-define it as an inline +// function. The inline function should be equivalent for C++ users. +inline BOOL GetMessage_Win32( + LPMSG lpMsg, HWND hWnd, + UINT wMsgFilterMin, UINT wMsgFilterMax) { + return GetMessage(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax); +} +#undef GetMessage +inline BOOL GetMessage( + LPMSG lpMsg, HWND hWnd, + UINT wMsgFilterMin, UINT wMsgFilterMax) { + return GetMessage_Win32(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax); +} +#endif + + +namespace std {} + +namespace google { +namespace protobuf { + +#undef GOOGLE_DISALLOW_EVIL_CONSTRUCTORS +#define GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(TypeName) \ + TypeName(const TypeName&); \ + void operator=(const TypeName&) + +#if defined(_MSC_VER) && defined(PROTOBUF_USE_DLLS) + #ifdef LIBPROTOBUF_EXPORTS + #define LIBPROTOBUF_EXPORT __declspec(dllexport) + #else + #define LIBPROTOBUF_EXPORT __declspec(dllimport) + #endif + #ifdef LIBPROTOC_EXPORTS + #define LIBPROTOC_EXPORT __declspec(dllexport) + #else + #define LIBPROTOC_EXPORT __declspec(dllimport) + #endif +#elif defined(PROTOBUF_USE_DLLS) + #define LIBPROTOBUF_EXPORT __attribute__ ((visibility("default"))) + #define LIBPROTOC_EXPORT __attribute__ ((visibility("default"))) +#else + #define LIBPROTOBUF_EXPORT + #define LIBPROTOC_EXPORT +#endif + +namespace internal { + +// Some of these constants are macros rather than const ints so that they can +// be used in #if directives. + +// The current version, represented as a single integer to make comparison +// easier: major * 10^6 + minor * 10^3 + micro +#define GOOGLE_PROTOBUF_VERSION 2004001 + +// The minimum library version which works with the current version of the +// headers. +#define GOOGLE_PROTOBUF_MIN_LIBRARY_VERSION 2004000 + +// The minimum header version which works with the current version of +// the library. This constant should only be used by protoc's C++ code +// generator. +static const int kMinHeaderVersionForLibrary = 2004000; + +// The minimum protoc version which works with the current version of the +// headers. +#define GOOGLE_PROTOBUF_MIN_PROTOC_VERSION 2004000 + +// The minimum header version which works with the current version of +// protoc. This constant should only be used in VerifyVersion(). +static const int kMinHeaderVersionForProtoc = 2004000; + +// Verifies that the headers and libraries are compatible. Use the macro +// below to call this. +void LIBPROTOBUF_EXPORT VerifyVersion(int headerVersion, int minLibraryVersion, + const char* filename); + +// Converts a numeric version number to a string. +std::string LIBPROTOBUF_EXPORT VersionString(int version); + +} // namespace internal + +// Place this macro in your main() function (or somewhere before you attempt +// to use the protobuf library) to verify that the version you link against +// matches the headers you compiled against. If a version mismatch is +// detected, the process will abort. +#define GOOGLE_PROTOBUF_VERIFY_VERSION \ + ::google::protobuf::internal::VerifyVersion( \ + GOOGLE_PROTOBUF_VERSION, GOOGLE_PROTOBUF_MIN_LIBRARY_VERSION, \ + __FILE__) + +// =================================================================== +// from google3/base/port.h + +typedef unsigned int uint; + +#ifdef _MSC_VER +typedef __int8 int8; +typedef __int16 int16; +typedef __int32 int32; +typedef __int64 int64; + +typedef unsigned __int8 uint8; +typedef unsigned __int16 uint16; +typedef unsigned __int32 uint32; +typedef unsigned __int64 uint64; +#else +typedef int8_t int8; +typedef int16_t int16; +typedef int32_t int32; +typedef int64_t int64; + +typedef uint8_t uint8; +typedef uint16_t uint16; +typedef uint32_t uint32; +typedef uint64_t uint64; +#endif + +// long long macros to be used because gcc and vc++ use different suffixes, +// and different size specifiers in format strings +#undef GOOGLE_LONGLONG +#undef GOOGLE_ULONGLONG +#undef GOOGLE_LL_FORMAT + +#ifdef _MSC_VER +#define GOOGLE_LONGLONG(x) x##I64 +#define GOOGLE_ULONGLONG(x) x##UI64 +#define GOOGLE_LL_FORMAT "I64" // As in printf("%I64d", ...) +#else +#define GOOGLE_LONGLONG(x) x##LL +#define GOOGLE_ULONGLONG(x) x##ULL +#define GOOGLE_LL_FORMAT "ll" // As in "%lld". Note that "q" is poor form also. +#endif + +static const int32 kint32max = 0x7FFFFFFF; +static const int32 kint32min = -kint32max - 1; +static const int64 kint64max = GOOGLE_LONGLONG(0x7FFFFFFFFFFFFFFF); +static const int64 kint64min = -kint64max - 1; +static const uint32 kuint32max = 0xFFFFFFFFu; +static const uint64 kuint64max = GOOGLE_ULONGLONG(0xFFFFFFFFFFFFFFFF); + +// ------------------------------------------------------------------- +// Annotations: Some parts of the code have been annotated in ways that might +// be useful to some compilers or tools, but are not supported universally. +// You can #define these annotations yourself if the default implementation +// is not right for you. + +#ifndef GOOGLE_ATTRIBUTE_ALWAYS_INLINE +#if defined(__GNUC__) && (__GNUC__ > 3 ||(__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) +// For functions we want to force inline. +// Introduced in gcc 3.1. +#define GOOGLE_ATTRIBUTE_ALWAYS_INLINE __attribute__ ((always_inline)) +#else +// Other compilers will have to figure it out for themselves. +#define GOOGLE_ATTRIBUTE_ALWAYS_INLINE +#endif +#endif + +#ifndef GOOGLE_ATTRIBUTE_DEPRECATED +#ifdef __GNUC__ +// If the method/variable/type is used anywhere, produce a warning. +#define GOOGLE_ATTRIBUTE_DEPRECATED __attribute__((deprecated)) +#else +#define GOOGLE_ATTRIBUTE_DEPRECATED +#endif +#endif + +#ifndef GOOGLE_PREDICT_TRUE +#ifdef __GNUC__ +// Provided at least since GCC 3.0. +#define GOOGLE_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1)) +#else +#define GOOGLE_PREDICT_TRUE +#endif +#endif + +// Delimits a block of code which may write to memory which is simultaneously +// written by other threads, but which has been determined to be thread-safe +// (e.g. because it is an idempotent write). +#ifndef GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN +#define GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN() +#endif +#ifndef GOOGLE_SAFE_CONCURRENT_WRITES_END +#define GOOGLE_SAFE_CONCURRENT_WRITES_END() +#endif + +// =================================================================== +// from google3/base/basictypes.h + +// The GOOGLE_ARRAYSIZE(arr) macro returns the # of elements in an array arr. +// The expression is a compile-time constant, and therefore can be +// used in defining new arrays, for example. +// +// GOOGLE_ARRAYSIZE catches a few type errors. If you see a compiler error +// +// "warning: division by zero in ..." +// +// when using GOOGLE_ARRAYSIZE, you are (wrongfully) giving it a pointer. +// You should only use GOOGLE_ARRAYSIZE on statically allocated arrays. +// +// The following comments are on the implementation details, and can +// be ignored by the users. +// +// ARRAYSIZE(arr) works by inspecting sizeof(arr) (the # of bytes in +// the array) and sizeof(*(arr)) (the # of bytes in one array +// element). If the former is divisible by the latter, perhaps arr is +// indeed an array, in which case the division result is the # of +// elements in the array. Otherwise, arr cannot possibly be an array, +// and we generate a compiler error to prevent the code from +// compiling. +// +// Since the size of bool is implementation-defined, we need to cast +// !(sizeof(a) & sizeof(*(a))) to size_t in order to ensure the final +// result has type size_t. +// +// This macro is not perfect as it wrongfully accepts certain +// pointers, namely where the pointer size is divisible by the pointee +// size. Since all our code has to go through a 32-bit compiler, +// where a pointer is 4 bytes, this means all pointers to a type whose +// size is 3 or greater than 4 will be (righteously) rejected. +// +// Kudos to Jorg Brown for this simple and elegant implementation. + +#undef GOOGLE_ARRAYSIZE +#define GOOGLE_ARRAYSIZE(a) \ + ((sizeof(a) / sizeof(*(a))) / \ + static_cast(!(sizeof(a) % sizeof(*(a))))) + +namespace internal { + +// Use implicit_cast as a safe version of static_cast or const_cast +// for upcasting in the type hierarchy (i.e. casting a pointer to Foo +// to a pointer to SuperclassOfFoo or casting a pointer to Foo to +// a const pointer to Foo). +// When you use implicit_cast, the compiler checks that the cast is safe. +// Such explicit implicit_casts are necessary in surprisingly many +// situations where C++ demands an exact type match instead of an +// argument type convertable to a target type. +// +// The From type can be inferred, so the preferred syntax for using +// implicit_cast is the same as for static_cast etc.: +// +// implicit_cast(expr) +// +// implicit_cast would have been part of the C++ standard library, +// but the proposal was submitted too late. It will probably make +// its way into the language in the future. +template +inline To implicit_cast(From const &f) { + return f; +} + +// When you upcast (that is, cast a pointer from type Foo to type +// SuperclassOfFoo), it's fine to use implicit_cast<>, since upcasts +// always succeed. When you downcast (that is, cast a pointer from +// type Foo to type SubclassOfFoo), static_cast<> isn't safe, because +// how do you know the pointer is really of type SubclassOfFoo? It +// could be a bare Foo, or of type DifferentSubclassOfFoo. Thus, +// when you downcast, you should use this macro. In debug mode, we +// use dynamic_cast<> to double-check the downcast is legal (we die +// if it's not). In normal mode, we do the efficient static_cast<> +// instead. Thus, it's important to test in debug mode to make sure +// the cast is legal! +// This is the only place in the code we should use dynamic_cast<>. +// In particular, you SHOULDN'T be using dynamic_cast<> in order to +// do RTTI (eg code like this: +// if (dynamic_cast(foo)) HandleASubclass1Object(foo); +// if (dynamic_cast(foo)) HandleASubclass2Object(foo); +// You should design the code some other way not to need this. + +template // use like this: down_cast(foo); +inline To down_cast(From* f) { // so we only accept pointers + // Ensures that To is a sub-type of From *. This test is here only + // for compile-time type checking, and has no overhead in an + // optimized build at run-time, as it will be optimized away + // completely. + if (false) { + implicit_cast(0); + } + +#if !defined(NDEBUG) && !defined(GOOGLE_PROTOBUF_NO_RTTI) + assert(f == NULL || dynamic_cast(f) != NULL); // RTTI: debug mode only! +#endif + return static_cast(f); +} + +} // namespace internal + +// We made these internal so that they would show up as such in the docs, +// but we don't want to stick "internal::" in front of them everywhere. +using internal::implicit_cast; +using internal::down_cast; + +// The COMPILE_ASSERT macro can be used to verify that a compile time +// expression is true. For example, you could use it to verify the +// size of a static array: +// +// COMPILE_ASSERT(ARRAYSIZE(content_type_names) == CONTENT_NUM_TYPES, +// content_type_names_incorrect_size); +// +// or to make sure a struct is smaller than a certain size: +// +// COMPILE_ASSERT(sizeof(foo) < 128, foo_too_large); +// +// The second argument to the macro is the name of the variable. If +// the expression is false, most compilers will issue a warning/error +// containing the name of the variable. + +namespace internal { + +template +struct CompileAssert { +}; + +} // namespace internal + +#undef GOOGLE_COMPILE_ASSERT +#define GOOGLE_COMPILE_ASSERT(expr, msg) \ + typedef ::google::protobuf::internal::CompileAssert<(bool(expr))> \ + msg[bool(expr) ? 1 : -1] + + +// Implementation details of COMPILE_ASSERT: +// +// - COMPILE_ASSERT works by defining an array type that has -1 +// elements (and thus is invalid) when the expression is false. +// +// - The simpler definition +// +// #define COMPILE_ASSERT(expr, msg) typedef char msg[(expr) ? 1 : -1] +// +// does not work, as gcc supports variable-length arrays whose sizes +// are determined at run-time (this is gcc's extension and not part +// of the C++ standard). As a result, gcc fails to reject the +// following code with the simple definition: +// +// int foo; +// COMPILE_ASSERT(foo, msg); // not supposed to compile as foo is +// // not a compile-time constant. +// +// - By using the type CompileAssert<(bool(expr))>, we ensures that +// expr is a compile-time constant. (Template arguments must be +// determined at compile-time.) +// +// - The outter parentheses in CompileAssert<(bool(expr))> are necessary +// to work around a bug in gcc 3.4.4 and 4.0.1. If we had written +// +// CompileAssert +// +// instead, these compilers will refuse to compile +// +// COMPILE_ASSERT(5 > 0, some_message); +// +// (They seem to think the ">" in "5 > 0" marks the end of the +// template argument list.) +// +// - The array size is (bool(expr) ? 1 : -1), instead of simply +// +// ((expr) ? 1 : -1). +// +// This is to avoid running into a bug in MS VC 7.1, which +// causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1. + +// =================================================================== +// from google3/base/scoped_ptr.h + +namespace internal { + +// This is an implementation designed to match the anticipated future TR2 +// implementation of the scoped_ptr class, and its closely-related brethren, +// scoped_array, scoped_ptr_malloc, and make_scoped_ptr. + +template class scoped_ptr; +template class scoped_array; + +// A scoped_ptr is like a T*, except that the destructor of scoped_ptr +// automatically deletes the pointer it holds (if any). +// That is, scoped_ptr owns the T object that it points to. +// Like a T*, a scoped_ptr may hold either NULL or a pointer to a T object. +// +// The size of a scoped_ptr is small: +// sizeof(scoped_ptr) == sizeof(C*) +template +class scoped_ptr { + public: + + // The element type + typedef C element_type; + + // Constructor. Defaults to intializing with NULL. + // There is no way to create an uninitialized scoped_ptr. + // The input parameter must be allocated with new. + explicit scoped_ptr(C* p = NULL) : ptr_(p) { } + + // Destructor. If there is a C object, delete it. + // We don't need to test ptr_ == NULL because C++ does that for us. + ~scoped_ptr() { + enum { type_must_be_complete = sizeof(C) }; + delete ptr_; + } + + // Reset. Deletes the current owned object, if any. + // Then takes ownership of a new object, if given. + // this->reset(this->get()) works. + void reset(C* p = NULL) { + if (p != ptr_) { + enum { type_must_be_complete = sizeof(C) }; + delete ptr_; + ptr_ = p; + } + } + + // Accessors to get the owned object. + // operator* and operator-> will assert() if there is no current object. + C& operator*() const { + assert(ptr_ != NULL); + return *ptr_; + } + C* operator->() const { + assert(ptr_ != NULL); + return ptr_; + } + C* get() const { return ptr_; } + + // Comparison operators. + // These return whether two scoped_ptr refer to the same object, not just to + // two different but equal objects. + bool operator==(C* p) const { return ptr_ == p; } + bool operator!=(C* p) const { return ptr_ != p; } + + // Swap two scoped pointers. + void swap(scoped_ptr& p2) { + C* tmp = ptr_; + ptr_ = p2.ptr_; + p2.ptr_ = tmp; + } + + // Release a pointer. + // The return value is the current pointer held by this object. + // If this object holds a NULL pointer, the return value is NULL. + // After this operation, this object will hold a NULL pointer, + // and will not own the object any more. + C* release() { + C* retVal = ptr_; + ptr_ = NULL; + return retVal; + } + + private: + C* ptr_; + + // Forbid comparison of scoped_ptr types. If C2 != C, it totally doesn't + // make sense, and if C2 == C, it still doesn't make sense because you should + // never have the same object owned by two different scoped_ptrs. + template bool operator==(scoped_ptr const& p2) const; + template bool operator!=(scoped_ptr const& p2) const; + + // Disallow evil constructors + scoped_ptr(const scoped_ptr&); + void operator=(const scoped_ptr&); +}; + +// scoped_array is like scoped_ptr, except that the caller must allocate +// with new [] and the destructor deletes objects with delete []. +// +// As with scoped_ptr, a scoped_array either points to an object +// or is NULL. A scoped_array owns the object that it points to. +// +// Size: sizeof(scoped_array) == sizeof(C*) +template +class scoped_array { + public: + + // The element type + typedef C element_type; + + // Constructor. Defaults to intializing with NULL. + // There is no way to create an uninitialized scoped_array. + // The input parameter must be allocated with new []. + explicit scoped_array(C* p = NULL) : array_(p) { } + + // Destructor. If there is a C object, delete it. + // We don't need to test ptr_ == NULL because C++ does that for us. + ~scoped_array() { + enum { type_must_be_complete = sizeof(C) }; + delete[] array_; + } + + // Reset. Deletes the current owned object, if any. + // Then takes ownership of a new object, if given. + // this->reset(this->get()) works. + void reset(C* p = NULL) { + if (p != array_) { + enum { type_must_be_complete = sizeof(C) }; + delete[] array_; + array_ = p; + } + } + + // Get one element of the current object. + // Will assert() if there is no current object, or index i is negative. + C& operator[](std::ptrdiff_t i) const { + assert(i >= 0); + assert(array_ != NULL); + return array_[i]; + } + + // Get a pointer to the zeroth element of the current object. + // If there is no current object, return NULL. + C* get() const { + return array_; + } + + // Comparison operators. + // These return whether two scoped_array refer to the same object, not just to + // two different but equal objects. + bool operator==(C* p) const { return array_ == p; } + bool operator!=(C* p) const { return array_ != p; } + + // Swap two scoped arrays. + void swap(scoped_array& p2) { + C* tmp = array_; + array_ = p2.array_; + p2.array_ = tmp; + } + + // Release an array. + // The return value is the current pointer held by this object. + // If this object holds a NULL pointer, the return value is NULL. + // After this operation, this object will hold a NULL pointer, + // and will not own the object any more. + C* release() { + C* retVal = array_; + array_ = NULL; + return retVal; + } + + private: + C* array_; + + // Forbid comparison of different scoped_array types. + template bool operator==(scoped_array const& p2) const; + template bool operator!=(scoped_array const& p2) const; + + // Disallow evil constructors + scoped_array(const scoped_array&); + void operator=(const scoped_array&); +}; + +} // namespace internal + +// We made these internal so that they would show up as such in the docs, +// but we don't want to stick "internal::" in front of them everywhere. +using internal::scoped_ptr; +using internal::scoped_array; + +// =================================================================== +// emulates google3/base/logging.h + +enum LogLevel { + LOGLEVEL_INFO, // Informational. This is never actually used by + // libprotobuf. + LOGLEVEL_WARNING, // Warns about issues that, although not technically a + // problem now, could cause problems in the future. For + // example, a // warning will be printed when parsing a + // message that is near the message size limit. + LOGLEVEL_ERROR, // An error occurred which should never happen during + // normal use. + LOGLEVEL_FATAL, // An error occurred from which the library cannot + // recover. This usually indicates a programming error + // in the code which calls the library, especially when + // compiled in debug mode. + +#ifdef NDEBUG + LOGLEVEL_DFATAL = LOGLEVEL_ERROR +#else + LOGLEVEL_DFATAL = LOGLEVEL_FATAL +#endif +}; + +namespace internal { + +class LogFinisher; + +class LIBPROTOBUF_EXPORT LogMessage { + public: + LogMessage(LogLevel level, const char* filename, int line); + ~LogMessage(); + + LogMessage& operator<<(const std::string& value); + LogMessage& operator<<(const char* value); + LogMessage& operator<<(char value); + LogMessage& operator<<(int value); + LogMessage& operator<<(uint value); + LogMessage& operator<<(long value); + LogMessage& operator<<(unsigned long value); + LogMessage& operator<<(double value); + + private: + friend class LogFinisher; + void Finish(); + + LogLevel level_; + const char* filename_; + int line_; + std::string message_; +}; + +// Used to make the entire "LOG(BLAH) << etc." expression have a void return +// type and print a newline after each message. +class LIBPROTOBUF_EXPORT LogFinisher { + public: + void operator=(LogMessage& other); +}; + +} // namespace internal + +// Undef everything in case we're being mixed with some other Google library +// which already defined them itself. Presumably all Google libraries will +// support the same syntax for these so it should not be a big deal if they +// end up using our definitions instead. +#undef GOOGLE_LOG +#undef GOOGLE_LOG_IF + +#undef GOOGLE_CHECK +#undef GOOGLE_CHECK_EQ +#undef GOOGLE_CHECK_NE +#undef GOOGLE_CHECK_LT +#undef GOOGLE_CHECK_LE +#undef GOOGLE_CHECK_GT +#undef GOOGLE_CHECK_GE + +#undef GOOGLE_DLOG +#undef GOOGLE_DCHECK +#undef GOOGLE_DCHECK_EQ +#undef GOOGLE_DCHECK_NE +#undef GOOGLE_DCHECK_LT +#undef GOOGLE_DCHECK_LE +#undef GOOGLE_DCHECK_GT +#undef GOOGLE_DCHECK_GE + +#define GOOGLE_LOG(LEVEL) \ + ::google::protobuf::internal::LogFinisher() = \ + ::google::protobuf::internal::LogMessage( \ + ::google::protobuf::LOGLEVEL_##LEVEL, __FILE__, __LINE__) +#define GOOGLE_LOG_IF(LEVEL, CONDITION) \ + !(CONDITION) ? (void)0 : GOOGLE_LOG(LEVEL) + +#define GOOGLE_CHECK(EXPRESSION) \ + GOOGLE_LOG_IF(FATAL, !(EXPRESSION)) << "CHECK failed: " #EXPRESSION ": " +#define GOOGLE_CHECK_EQ(A, B) GOOGLE_CHECK((A) == (B)) +#define GOOGLE_CHECK_NE(A, B) GOOGLE_CHECK((A) != (B)) +#define GOOGLE_CHECK_LT(A, B) GOOGLE_CHECK((A) < (B)) +#define GOOGLE_CHECK_LE(A, B) GOOGLE_CHECK((A) <= (B)) +#define GOOGLE_CHECK_GT(A, B) GOOGLE_CHECK((A) > (B)) +#define GOOGLE_CHECK_GE(A, B) GOOGLE_CHECK((A) >= (B)) + +#ifdef NDEBUG + +#define GOOGLE_DLOG GOOGLE_LOG_IF(INFO, false) + +#define GOOGLE_DCHECK(EXPRESSION) while(false) GOOGLE_CHECK(EXPRESSION) +#define GOOGLE_DCHECK_EQ(A, B) GOOGLE_DCHECK((A) == (B)) +#define GOOGLE_DCHECK_NE(A, B) GOOGLE_DCHECK((A) != (B)) +#define GOOGLE_DCHECK_LT(A, B) GOOGLE_DCHECK((A) < (B)) +#define GOOGLE_DCHECK_LE(A, B) GOOGLE_DCHECK((A) <= (B)) +#define GOOGLE_DCHECK_GT(A, B) GOOGLE_DCHECK((A) > (B)) +#define GOOGLE_DCHECK_GE(A, B) GOOGLE_DCHECK((A) >= (B)) + +#else // NDEBUG + +#define GOOGLE_DLOG GOOGLE_LOG + +#define GOOGLE_DCHECK GOOGLE_CHECK +#define GOOGLE_DCHECK_EQ GOOGLE_CHECK_EQ +#define GOOGLE_DCHECK_NE GOOGLE_CHECK_NE +#define GOOGLE_DCHECK_LT GOOGLE_CHECK_LT +#define GOOGLE_DCHECK_LE GOOGLE_CHECK_LE +#define GOOGLE_DCHECK_GT GOOGLE_CHECK_GT +#define GOOGLE_DCHECK_GE GOOGLE_CHECK_GE + +#endif // !NDEBUG + +typedef void LogHandler(LogLevel level, const char* filename, int line, + const std::string& message); + +// The protobuf library sometimes writes warning and error messages to +// stderr. These messages are primarily useful for developers, but may +// also help end users figure out a problem. If you would prefer that +// these messages be sent somewhere other than stderr, call SetLogHandler() +// to set your own handler. This returns the old handler. Set the handler +// to NULL to ignore log messages (but see also LogSilencer, below). +// +// Obviously, SetLogHandler is not thread-safe. You should only call it +// at initialization time, and probably not from library code. If you +// simply want to suppress log messages temporarily (e.g. because you +// have some code that tends to trigger them frequently and you know +// the warnings are not important to you), use the LogSilencer class +// below. +LIBPROTOBUF_EXPORT LogHandler* SetLogHandler(LogHandler* new_func); + +// Create a LogSilencer if you want to temporarily suppress all log +// messages. As long as any LogSilencer objects exist, non-fatal +// log messages will be discarded (the current LogHandler will *not* +// be called). Constructing a LogSilencer is thread-safe. You may +// accidentally suppress log messages occurring in another thread, but +// since messages are generally for debugging purposes only, this isn't +// a big deal. If you want to intercept log messages, use SetLogHandler(). +class LIBPROTOBUF_EXPORT LogSilencer { + public: + LogSilencer(); + ~LogSilencer(); +}; + +// =================================================================== +// emulates google3/base/callback.h + +// Abstract interface for a callback. When calling an RPC, you must provide +// a Closure to call when the procedure completes. See the Service interface +// in service.h. +// +// To automatically construct a Closure which calls a particular function or +// method with a particular set of parameters, use the NewCallback() function. +// Example: +// void FooDone(const FooResponse* response) { +// ... +// } +// +// void CallFoo() { +// ... +// // When done, call FooDone() and pass it a pointer to the response. +// Closure* callback = NewCallback(&FooDone, response); +// // Make the call. +// service->Foo(controller, request, response, callback); +// } +// +// Example that calls a method: +// class Handler { +// public: +// ... +// +// void FooDone(const FooResponse* response) { +// ... +// } +// +// void CallFoo() { +// ... +// // When done, call FooDone() and pass it a pointer to the response. +// Closure* callback = NewCallback(this, &Handler::FooDone, response); +// // Make the call. +// service->Foo(controller, request, response, callback); +// } +// }; +// +// Currently NewCallback() supports binding zero, one, or two arguments. +// +// Callbacks created with NewCallback() automatically delete themselves when +// executed. They should be used when a callback is to be called exactly +// once (usually the case with RPC callbacks). If a callback may be called +// a different number of times (including zero), create it with +// NewPermanentCallback() instead. You are then responsible for deleting the +// callback (using the "delete" keyword as normal). +// +// Note that NewCallback() is a bit touchy regarding argument types. Generally, +// the values you provide for the parameter bindings must exactly match the +// types accepted by the callback function. For example: +// void Foo(string s); +// NewCallback(&Foo, "foo"); // WON'T WORK: const char* != string +// NewCallback(&Foo, string("foo")); // WORKS +// Also note that the arguments cannot be references: +// void Foo(const string& s); +// string my_str; +// NewCallback(&Foo, my_str); // WON'T WORK: Can't use referecnes. +// However, correctly-typed pointers will work just fine. +class LIBPROTOBUF_EXPORT Closure { + public: + Closure() {} + virtual ~Closure(); + + virtual void Run() = 0; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Closure); +}; + +namespace internal { + +class LIBPROTOBUF_EXPORT FunctionClosure0 : public Closure { + public: + typedef void (*FunctionType)(); + + FunctionClosure0(FunctionType function, bool self_deleting) + : function_(function), self_deleting_(self_deleting) {} + ~FunctionClosure0(); + + void Run() { + bool needs_delete = self_deleting_; // read in case callback deletes + function_(); + if (needs_delete) delete this; + } + + private: + FunctionType function_; + bool self_deleting_; +}; + +template +class MethodClosure0 : public Closure { + public: + typedef void (Class::*MethodType)(); + + MethodClosure0(Class* object, MethodType method, bool self_deleting) + : object_(object), method_(method), self_deleting_(self_deleting) {} + ~MethodClosure0() {} + + void Run() { + bool needs_delete = self_deleting_; // read in case callback deletes + (object_->*method_)(); + if (needs_delete) delete this; + } + + private: + Class* object_; + MethodType method_; + bool self_deleting_; +}; + +template +class FunctionClosure1 : public Closure { + public: + typedef void (*FunctionType)(Arg1 arg1); + + FunctionClosure1(FunctionType function, bool self_deleting, + Arg1 arg1) + : function_(function), self_deleting_(self_deleting), + arg1_(arg1) {} + ~FunctionClosure1() {} + + void Run() { + bool needs_delete = self_deleting_; // read in case callback deletes + function_(arg1_); + if (needs_delete) delete this; + } + + private: + FunctionType function_; + bool self_deleting_; + Arg1 arg1_; +}; + +template +class MethodClosure1 : public Closure { + public: + typedef void (Class::*MethodType)(Arg1 arg1); + + MethodClosure1(Class* object, MethodType method, bool self_deleting, + Arg1 arg1) + : object_(object), method_(method), self_deleting_(self_deleting), + arg1_(arg1) {} + ~MethodClosure1() {} + + void Run() { + bool needs_delete = self_deleting_; // read in case callback deletes + (object_->*method_)(arg1_); + if (needs_delete) delete this; + } + + private: + Class* object_; + MethodType method_; + bool self_deleting_; + Arg1 arg1_; +}; + +template +class FunctionClosure2 : public Closure { + public: + typedef void (*FunctionType)(Arg1 arg1, Arg2 arg2); + + FunctionClosure2(FunctionType function, bool self_deleting, + Arg1 arg1, Arg2 arg2) + : function_(function), self_deleting_(self_deleting), + arg1_(arg1), arg2_(arg2) {} + ~FunctionClosure2() {} + + void Run() { + bool needs_delete = self_deleting_; // read in case callback deletes + function_(arg1_, arg2_); + if (needs_delete) delete this; + } + + private: + FunctionType function_; + bool self_deleting_; + Arg1 arg1_; + Arg2 arg2_; +}; + +template +class MethodClosure2 : public Closure { + public: + typedef void (Class::*MethodType)(Arg1 arg1, Arg2 arg2); + + MethodClosure2(Class* object, MethodType method, bool self_deleting, + Arg1 arg1, Arg2 arg2) + : object_(object), method_(method), self_deleting_(self_deleting), + arg1_(arg1), arg2_(arg2) {} + ~MethodClosure2() {} + + void Run() { + bool needs_delete = self_deleting_; // read in case callback deletes + (object_->*method_)(arg1_, arg2_); + if (needs_delete) delete this; + } + + private: + Class* object_; + MethodType method_; + bool self_deleting_; + Arg1 arg1_; + Arg2 arg2_; +}; + +} // namespace internal + +// See Closure. +inline Closure* NewCallback(void (*function)()) { + return new internal::FunctionClosure0(function, true); +} + +// See Closure. +inline Closure* NewPermanentCallback(void (*function)()) { + return new internal::FunctionClosure0(function, false); +} + +// See Closure. +template +inline Closure* NewCallback(Class* object, void (Class::*method)()) { + return new internal::MethodClosure0(object, method, true); +} + +// See Closure. +template +inline Closure* NewPermanentCallback(Class* object, void (Class::*method)()) { + return new internal::MethodClosure0(object, method, false); +} + +// See Closure. +template +inline Closure* NewCallback(void (*function)(Arg1), + Arg1 arg1) { + return new internal::FunctionClosure1(function, true, arg1); +} + +// See Closure. +template +inline Closure* NewPermanentCallback(void (*function)(Arg1), + Arg1 arg1) { + return new internal::FunctionClosure1(function, false, arg1); +} + +// See Closure. +template +inline Closure* NewCallback(Class* object, void (Class::*method)(Arg1), + Arg1 arg1) { + return new internal::MethodClosure1(object, method, true, arg1); +} + +// See Closure. +template +inline Closure* NewPermanentCallback(Class* object, void (Class::*method)(Arg1), + Arg1 arg1) { + return new internal::MethodClosure1(object, method, false, arg1); +} + +// See Closure. +template +inline Closure* NewCallback(void (*function)(Arg1, Arg2), + Arg1 arg1, Arg2 arg2) { + return new internal::FunctionClosure2( + function, true, arg1, arg2); +} + +// See Closure. +template +inline Closure* NewPermanentCallback(void (*function)(Arg1, Arg2), + Arg1 arg1, Arg2 arg2) { + return new internal::FunctionClosure2( + function, false, arg1, arg2); +} + +// See Closure. +template +inline Closure* NewCallback(Class* object, void (Class::*method)(Arg1, Arg2), + Arg1 arg1, Arg2 arg2) { + return new internal::MethodClosure2( + object, method, true, arg1, arg2); +} + +// See Closure. +template +inline Closure* NewPermanentCallback( + Class* object, void (Class::*method)(Arg1, Arg2), + Arg1 arg1, Arg2 arg2) { + return new internal::MethodClosure2( + object, method, false, arg1, arg2); +} + +// A function which does nothing. Useful for creating no-op callbacks, e.g.: +// Closure* nothing = NewCallback(&DoNothing); +void LIBPROTOBUF_EXPORT DoNothing(); + +// =================================================================== +// emulates google3/base/mutex.h + +namespace internal { + +// A Mutex is a non-reentrant (aka non-recursive) mutex. At most one thread T +// may hold a mutex at a given time. If T attempts to Lock() the same Mutex +// while holding it, T will deadlock. +class LIBPROTOBUF_EXPORT Mutex { + public: + // Create a Mutex that is not held by anybody. + Mutex(); + + // Destructor + ~Mutex(); + + // Block if necessary until this Mutex is free, then acquire it exclusively. + void Lock(); + + // Release this Mutex. Caller must hold it exclusively. + void Unlock(); + + // Crash if this Mutex is not held exclusively by this thread. + // May fail to crash when it should; will never crash when it should not. + void AssertHeld(); + + private: + struct Internal; + Internal* mInternal; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Mutex); +}; + +// MutexLock(mu) acquires mu when constructed and releases it when destroyed. +class LIBPROTOBUF_EXPORT MutexLock { + public: + explicit MutexLock(Mutex *mu) : mu_(mu) { this->mu_->Lock(); } + ~MutexLock() { this->mu_->Unlock(); } + private: + Mutex *const mu_; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MutexLock); +}; + +// TODO(kenton): Implement these? Hard to implement portably. +typedef MutexLock ReaderMutexLock; +typedef MutexLock WriterMutexLock; + +// MutexLockMaybe is like MutexLock, but is a no-op when mu is NULL. +class LIBPROTOBUF_EXPORT MutexLockMaybe { + public: + explicit MutexLockMaybe(Mutex *mu) : + mu_(mu) { if (this->mu_ != NULL) { this->mu_->Lock(); } } + ~MutexLockMaybe() { if (this->mu_ != NULL) { this->mu_->Unlock(); } } + private: + Mutex *const mu_; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MutexLockMaybe); +}; + +} // namespace internal + +// We made these internal so that they would show up as such in the docs, +// but we don't want to stick "internal::" in front of them everywhere. +using internal::Mutex; +using internal::MutexLock; +using internal::ReaderMutexLock; +using internal::WriterMutexLock; +using internal::MutexLockMaybe; + +// =================================================================== +// from google3/base/type_traits.h + +namespace internal { + +// Specified by TR1 [4.7.4] Pointer modifications. +template struct remove_pointer { typedef T type; }; +template struct remove_pointer { typedef T type; }; +template struct remove_pointer { typedef T type; }; +template struct remove_pointer { typedef T type; }; +template struct remove_pointer { + typedef T type; }; + +// =================================================================== + +// Checks if the buffer contains structurally-valid UTF-8. Implemented in +// structurally_valid.cc. +LIBPROTOBUF_EXPORT bool IsStructurallyValidUTF8(const char* buf, int len); + +} // namespace internal + +// =================================================================== +// Shutdown support. + +// Shut down the entire protocol buffers library, deleting all static-duration +// objects allocated by the library or by generated .pb.cc files. +// +// There are two reasons you might want to call this: +// * You use a draconian definition of "memory leak" in which you expect +// every single malloc() to have a corresponding free(), even for objects +// which live until program exit. +// * You are writing a dynamically-loaded library which needs to clean up +// after itself when the library is unloaded. +// +// It is safe to call this multiple times. However, it is not safe to use +// any other part of the protocol buffers library after +// ShutdownProtobufLibrary() has been called. +LIBPROTOBUF_EXPORT void ShutdownProtobufLibrary(); + +namespace internal { + +// Register a function to be called when ShutdownProtocolBuffers() is called. +LIBPROTOBUF_EXPORT void OnShutdown(void (*func)()); + +} // namespace internal + +#ifdef PROTOBUF_USE_EXCEPTIONS +class FatalException : public std::exception { + public: + FatalException(const char* filename, int line, const std::string& message) + : filename_(filename), line_(line), message_(message) {} + virtual ~FatalException() throw(); + + virtual const char* what() const throw(); + + const char* filename() const { return filename_; } + int line() const { return line_; } + const std::string& message() const { return message_; } + + private: + const char* filename_; + const int line_; + const std::string message_; +}; +#endif + +// This is at the end of the file instead of the beginning to work around a bug +// in some versions of MSVC. +using namespace std; // Don't do this at home, kids. + +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMMON_H__ diff --git a/depends/protobuf/google/protobuf/stubs/hash.h b/depends/protobuf/google/protobuf/stubs/hash.h new file mode 100644 index 0000000000..0ee778563e --- /dev/null +++ b/depends/protobuf/google/protobuf/stubs/hash.h @@ -0,0 +1,445 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// +// Deals with the fact that hash_map is not defined everywhere. + +#ifndef GOOGLE_PROTOBUF_STUBS_HASH_H__ +#define GOOGLE_PROTOBUF_STUBS_HASH_H__ + +#include +#include + +#define GOOGLE_PROTOBUF_HAVE_HASH_MAP 1 +#define GOOGLE_PROTOBUF_HAVE_HASH_SET 1 + +// Android +#if defined(__ANDROID__) +# undef GOOGLE_PROTOBUF_HAVE_HASH_MAP +# undef GOOGLE_PROTOBUF_HAVE_HASH_MAP + +// Use C++11 unordered_{map|set} if available. +#elif ((_LIBCPP_STD_VER >= 11) || \ + (((__cplusplus >= 201103L) || defined(__GXX_EXPERIMENTAL_CXX0X)) && \ + (__GLIBCXX__ > 20090421))) +# define GOOGLE_PROTOBUF_HAS_CXX11_HASH + +// For XCode >= 4.6: the compiler is clang with libc++. +// For earlier XCode version: the compiler is gcc-4.2.1 with libstdc++. +// libc++ provides and friends even in non C++11 mode, +// and it does not provide the tr1 library. Therefore the following macro +// checks against this special case. +// Note that we should not test the __APPLE_CC__ version number or the +// __clang__ macro, since the new compiler can still use -stdlib=libstdc++, in +// which case is not compilable without -std=c++11 +#elif defined(__APPLE_CC__) +# if __GNUC__ >= 4 +# define GOOGLE_PROTOBUF_HAS_TR1 +# else +// Not tested for gcc < 4... These setting can compile under 4.2.1 though. +# define GOOGLE_PROTOBUF_HASH_NAMESPACE __gnu_cxx +# include +# define GOOGLE_PROTOBUF_HASH_MAP_CLASS hash_map +# include +# define GOOGLE_PROTOBUF_HASH_SET_CLASS hash_set +# endif + +// Version checks for gcc. +#elif defined(__GNUC__) +// For GCC 4.x+, use tr1::unordered_map/set; otherwise, follow the +// instructions from: +// https://gcc.gnu.org/onlinedocs/libstdc++/manual/backwards.html +# if __GNUC__ >= 4 +# define GOOGLE_PROTOBUF_HAS_TR1 +# elif __GNUC__ >= 3 +# include +# define GOOGLE_PROTOBUF_HASH_MAP_CLASS hash_map +# include +# define GOOGLE_PROTOBUF_HASH_SET_CLASS hash_set +# if __GNUC__ == 3 && __GNUC_MINOR__ == 0 +# define GOOGLE_PROTOBUF_HASH_NAMESPACE std // GCC 3.0 +# else +# define GOOGLE_PROTOBUF_HASH_NAMESPACE __gnu_cxx // GCC 3.1 and later +# endif +# else +# define GOOGLE_PROTOBUF_HASH_NAMESPACE +# include +# define GOOGLE_PROTOBUF_HASH_MAP_CLASS hash_map +# include +# define GOOGLE_PROTOBUF_HASH_SET_CLASS hash_set +# endif + +// Version checks for MSC. +// Apparently Microsoft decided to move hash_map *back* to the std namespace in +// MSVC 2010: +// http://blogs.msdn.com/vcblog/archive/2009/05/25/stl-breaking-changes-in-visual-studio-2010-beta-1.aspx +// And.. they are moved back to stdext in MSVC 2013 (haven't checked 2012). That +// said, use unordered_map for MSVC 2010 and beyond is our safest bet. +#elif defined(_MSC_VER) +# if _MSC_VER >= 1900 // Since Visual Studio 2019 +# define GOOGLE_PROTOBUF_HASH_NAMESPACE std +# include +# define GOOGLE_PROTOBUF_HASH_MAP_CLASS unordered_map +# include +# define GOOGLE_PROTOBUF_HASH_SET_CLASS unordered_set + +# elif _MSC_VER >= 1600 // Since Visual Studio 2010 +# define GOOGLE_PROTOBUF_HAS_CXX11_HASH +# define GOOGLE_PROTOBUF_HASH_COMPARE std::hash_compare +# elif _MSC_VER >= 1500 // Since Visual Studio 2008 +# define GOOGLE_PROTOBUF_HASH_NAMESPACE stdext +# include +# define GOOGLE_PROTOBUF_HASH_MAP_CLASS hash_map +# include +# define GOOGLE_PROTOBUF_HASH_SET_CLASS hash_set +# define GOOGLE_PROTOBUF_HASH_COMPARE stdext::hash_compare +# define GOOGLE_PROTOBUF_CONTAINERS_NEED_HASH_COMPARE +# elif _MSC_VER >= 1310 +# define GOOGLE_PROTOBUF_HASH_NAMESPACE stdext +# include +# define GOOGLE_PROTOBUF_HASH_MAP_CLASS hash_map +# include +# define GOOGLE_PROTOBUF_HASH_SET_CLASS hash_set +# define GOOGLE_PROTOBUF_HASH_COMPARE stdext::hash_compare +# else +# define GOOGLE_PROTOBUF_HASH_NAMESPACE std +# include +# define GOOGLE_PROTOBUF_HASH_MAP_CLASS hash_map +# include +# define GOOGLE_PROTOBUF_HASH_SET_CLASS hash_set +# define GOOGLE_PROTOBUF_HASH_COMPARE stdext::hash_compare +# endif + +// **ADD NEW COMPILERS SUPPORT HERE.** +// For other compilers, undefine the macro and fallback to use std::map, in +// google/protobuf/stubs/hash.h +#else +# undef GOOGLE_PROTOBUF_HAVE_HASH_MAP +# undef GOOGLE_PROTOBUF_HAVE_HASH_SET +#endif + +#if defined(GOOGLE_PROTOBUF_HAS_CXX11_HASH) +# define GOOGLE_PROTOBUF_HASH_NAMESPACE std +# include +# define GOOGLE_PROTOBUF_HASH_MAP_CLASS unordered_map +# include +# define GOOGLE_PROTOBUF_HASH_SET_CLASS unordered_set +#elif defined(GOOGLE_PROTOBUF_HAS_TR1) +# define GOOGLE_PROTOBUF_HASH_NAMESPACE std::tr1 +# include +# define GOOGLE_PROTOBUF_HASH_MAP_CLASS unordered_map +# include +# define GOOGLE_PROTOBUF_HASH_SET_CLASS unordered_set +#endif + +# define GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_START \ + namespace google { \ + namespace protobuf { +# define GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_END }} + +#undef GOOGLE_PROTOBUF_HAS_CXX11_HASH +#undef GOOGLE_PROTOBUF_HAS_TR1 + +#if defined(GOOGLE_PROTOBUF_HAVE_HASH_MAP) && \ + defined(GOOGLE_PROTOBUF_HAVE_HASH_SET) +#else +#define GOOGLE_PROTOBUF_MISSING_HASH +#include +#include +#endif + +namespace google { + namespace protobuf { + +#ifdef GOOGLE_PROTOBUF_MISSING_HASH +#undef GOOGLE_PROTOBUF_MISSING_HASH + + // This system doesn't have hash_map or hash_set. Emulate them using map and + // set. + + // Make hash be the same as less. Note that everywhere where custom + // hash functions are defined in the protobuf code, they are also defined such + // that they can be used as "less" functions, which is required by MSVC anyway. + template + struct hash { + // Dummy, just to make derivative hash functions compile. + int operator()(const Key& key) { + GOOGLE_LOG(FATAL) << "Should never be called."; + return 0; + } + + inline bool operator()(const Key& a, const Key& b) const { + return a < b; + } + }; + + // Make sure char* is compared by value. + template <> + struct hash { + // Dummy, just to make derivative hash functions compile. + int operator()(const char* key) { + GOOGLE_LOG(FATAL) << "Should never be called."; + return 0; + } + + inline bool operator()(const char* a, const char* b) const { + return strcmp(a, b) < 0; + } + }; + + template , + typename EqualKey = std::equal_to, + typename Alloc = std::allocator< std::pair > > + class hash_map : public std::map { + typedef std::map BaseClass; + + public: + hash_map(int a = 0, const HashFcn& b = HashFcn(), + const EqualKey& c = EqualKey(), + const Alloc& d = Alloc()) : BaseClass(b, d) {} + + HashFcn hash_function() const { return HashFcn(); } + }; + + template , + typename EqualKey = std::equal_to > + class hash_set : public std::set { + public: + hash_set(int = 0) {} + + HashFcn hash_function() const { return HashFcn(); } + }; + +#elif defined(_MSC_VER) && _MSC_VER < 1900 && !defined(_STLPORT_VERSION) + + template + struct hash : public GOOGLE_PROTOBUF_HASH_COMPARE { + }; + + // MSVC's hash_compare hashes based on the string contents but + // compares based on the string pointer. WTF? + class CstringLess { + public: + inline bool operator()(const char* a, const char* b) const { + return strcmp(a, b) < 0; + } + }; + + template <> + struct hash + : public GOOGLE_PROTOBUF_HASH_COMPARE {}; + +#ifdef GOOGLE_PROTOBUF_CONTAINERS_NEED_HASH_COMPARE + + template + struct InternalHashCompare : public GOOGLE_PROTOBUF_HASH_COMPARE { + InternalHashCompare() {} + InternalHashCompare(HashFcn hashfcn, EqualKey equalkey) + : hashfcn_(hashfcn), equalkey_(equalkey) {} + size_t operator()(const Key& key) const { return hashfcn_(key); } + bool operator()(const Key& key1, const Key& key2) const { + return !equalkey_(key1, key2); + } + HashFcn hashfcn_; + EqualKey equalkey_; + }; + + template , + typename EqualKey = std::equal_to, + typename Alloc = std::allocator< std::pair > > + class hash_map + : public GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_MAP_CLASS< + Key, Data, InternalHashCompare, Alloc> { + typedef GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_MAP_CLASS< + Key, Data, InternalHashCompare, Alloc> BaseClass; + + public: + hash_map(int a = 0, const HashFcn& b = HashFcn(), + const EqualKey& c = EqualKey(), const Alloc& d = Alloc()) + : BaseClass(InternalHashCompare(b, c), d) {} + + HashFcn hash_function() const { return HashFcn(); } + }; + + template , + typename EqualKey = std::equal_to > + class hash_set + : public GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_SET_CLASS< + Key, InternalHashCompare > { + public: + hash_set(int = 0) {} + + HashFcn hash_function() const { return HashFcn(); } + }; + +#else // GOOGLE_PROTOBUF_CONTAINERS_NEED_HASH_COMPARE + + template , + typename EqualKey = std::equal_to, + typename Alloc = std::allocator< std::pair > > + class hash_map + : public GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_MAP_CLASS< + Key, Data, HashFcn, EqualKey, Alloc> { + typedef GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_MAP_CLASS< + Key, Data, HashFcn, EqualKey, Alloc> BaseClass; + + public: + hash_map(int a = 0, const HashFcn& b = HashFcn(), + const EqualKey& c = EqualKey(), + const Alloc& d = Alloc()) : BaseClass(a, b, c, d) {} + + HashFcn hash_function() const { return HashFcn(); } + }; + + template , + typename EqualKey = std::equal_to > + class hash_set + : public GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_SET_CLASS< + Key, HashFcn, EqualKey> { + public: + hash_set(int = 0) {} + + HashFcn hash_function() const { return HashFcn(); } + }; +#endif // GOOGLE_PROTOBUF_CONTAINERS_NEED_HASH_COMPARE + +#else // defined(_MSC_VER) && !defined(_STLPORT_VERSION) + + template + struct hash : public GOOGLE_PROTOBUF_HASH_NAMESPACE::hash { + }; + + template + struct hash { + inline size_t operator()(const Key* key) const { + return reinterpret_cast(key); + } + }; + + // Unlike the old SGI version, the TR1 "hash" does not special-case char*. So, + // we go ahead and provide our own implementation. + template <> + struct hash { + inline size_t operator()(const char* str) const { + size_t result = 0; + for (; *str != '\0'; str++) { + result = 5 * result + *str; + } + return result; + } + }; + + template<> + struct hash { + size_t operator()(bool x) const { + return static_cast(x); + } + }; + + template , + typename EqualKey = std::equal_to, + typename Alloc = std::allocator< std::pair > > + class hash_map + : public GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_MAP_CLASS< + Key, Data, HashFcn, EqualKey, Alloc> { + typedef GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_MAP_CLASS< + Key, Data, HashFcn, EqualKey, Alloc> BaseClass; + + public: + hash_map(int a = 0, const HashFcn& b = HashFcn(), + const EqualKey& c = EqualKey(), + const Alloc& d = Alloc()) : BaseClass(a, b, c, d) {} + + HashFcn hash_function() const { return HashFcn(); } + }; + + template , + typename EqualKey = std::equal_to > + class hash_set + : public GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_SET_CLASS< + Key, HashFcn, EqualKey> { + public: + hash_set(int = 0) {} + + HashFcn hash_function() const { return HashFcn(); } + }; + +#endif // !GOOGLE_PROTOBUF_MISSING_HASH + + template <> + struct hash { + inline size_t operator()(const string& key) const { + return hash()(key.c_str()); + } + + static const size_t bucket_size = 4; + static const size_t min_buckets = 8; + inline bool operator()(const string& a, const string& b) const { + return a < b; + } + }; + + template + struct hash > { + inline size_t operator()(const pair& key) const { + size_t first_hash = hash()(key.first); + size_t second_hash = hash()(key.second); + + // FIXME(kenton): What is the best way to compute this hash? I have + // no idea! This seems a bit better than an XOR. + return first_hash * ((1 << 16) - 1) + second_hash; + } + + static const size_t bucket_size = 4; + static const size_t min_buckets = 8; + inline bool operator()(const pair& a, + const pair& b) const { + return a < b; + } + }; + + // Used by GCC/SGI STL only. (Why isn't this provided by the standard + // library? :( ) + struct streq { + inline bool operator()(const char* a, const char* b) const { + return strcmp(a, b) == 0; + } + }; + + } // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_STUBS_HASH_H__ diff --git a/depends/protobuf/google/protobuf/stubs/map-util.h b/depends/protobuf/google/protobuf/stubs/map-util.h new file mode 100644 index 0000000000..f5c9d6b6d9 --- /dev/null +++ b/depends/protobuf/google/protobuf/stubs/map-util.h @@ -0,0 +1,119 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// from google3/util/gtl/map-util.h +// Author: Anton Carver + +#ifndef GOOGLE_PROTOBUF_STUBS_MAP_UTIL_H__ +#define GOOGLE_PROTOBUF_STUBS_MAP_UTIL_H__ + +#include + +namespace google { +namespace protobuf { + +// Perform a lookup in a map or hash_map. +// If the key is present in the map then the value associated with that +// key is returned, otherwise the value passed as a default is returned. +template +const typename Collection::value_type::second_type& +FindWithDefault(const Collection& collection, + const typename Collection::value_type::first_type& key, + const typename Collection::value_type::second_type& value) { + typename Collection::const_iterator it = collection.find(key); + if (it == collection.end()) { + return value; + } + return it->second; +} + +// Perform a lookup in a map or hash_map. +// If the key is present a const pointer to the associated value is returned, +// otherwise a NULL pointer is returned. +template +const typename Collection::value_type::second_type* +FindOrNull(const Collection& collection, + const typename Collection::value_type::first_type& key) { + typename Collection::const_iterator it = collection.find(key); + if (it == collection.end()) { + return 0; + } + return &it->second; +} + +// Perform a lookup in a map or hash_map whose values are pointers. +// If the key is present a const pointer to the associated value is returned, +// otherwise a NULL pointer is returned. +// This function does not distinguish between a missing key and a key mapped +// to a NULL value. +template +const typename Collection::value_type::second_type +FindPtrOrNull(const Collection& collection, + const typename Collection::value_type::first_type& key) { + typename Collection::const_iterator it = collection.find(key); + if (it == collection.end()) { + return 0; + } + return it->second; +} + +// Change the value associated with a particular key in a map or hash_map. +// If the key is not present in the map the key and value are inserted, +// otherwise the value is updated to be a copy of the value provided. +// True indicates that an insert took place, false indicates an update. +template +bool InsertOrUpdate(Collection * const collection, + const Key& key, const Value& value) { + pair ret = + collection->insert(typename Collection::value_type(key, value)); + if (!ret.second) { + // update + ret.first->second = value; + return false; + } + return true; +} + +// Insert a new key and value into a map or hash_map. +// If the key is not present in the map the key and value are +// inserted, otherwise nothing happens. True indicates that an insert +// took place, false indicates the key was already present. +template +bool InsertIfNotPresent(Collection * const collection, + const Key& key, const Value& value) { + pair ret = + collection->insert(typename Collection::value_type(key, value)); + return ret.second; +} + +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_STUBS_MAP_UTIL_H__ diff --git a/depends/protobuf/google/protobuf/stubs/once.cc b/depends/protobuf/google/protobuf/stubs/once.cc new file mode 100644 index 0000000000..5b7af9ce99 --- /dev/null +++ b/depends/protobuf/google/protobuf/stubs/once.cc @@ -0,0 +1,88 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// +// emulates google3/base/once.h +// +// This header is intended to be included only by internal .cc files and +// generated .pb.cc files. Users should not use this directly. + +#ifdef _WIN32 +#include +#endif + +#include + +namespace google { +namespace protobuf { + +#ifdef _WIN32 + +struct ProtobufOnceInternal { + ProtobufOnceInternal() { + InitializeCriticalSection(&critical_section); + } + ~ProtobufOnceInternal() { + DeleteCriticalSection(&critical_section); + } + CRITICAL_SECTION critical_section; +}; + +ProtobufOnceType::~ProtobufOnceType() +{ + delete internal_; + internal_ = NULL; +} + +ProtobufOnceType::ProtobufOnceType() { + // internal_ may be non-NULL if Init() was already called. + if (internal_ == NULL) internal_ = new ProtobufOnceInternal; +} + +void ProtobufOnceType::Init(void (*init_func)()) { + // internal_ may be NULL if we're still in dynamic initialization and the + // constructor has not been called yet. As mentioned in once.h, we assume + // that the program is still single-threaded at this time, and therefore it + // should be safe to initialize internal_ like so. + if (internal_ == NULL) internal_ = new ProtobufOnceInternal; + + EnterCriticalSection(&internal_->critical_section); + if (!initialized_) { + init_func(); + initialized_ = true; + } + LeaveCriticalSection(&internal_->critical_section); +} + +#endif + +} // namespace protobuf +} // namespace google diff --git a/depends/protobuf/google/protobuf/stubs/once.h b/depends/protobuf/google/protobuf/stubs/once.h new file mode 100644 index 0000000000..0dee407662 --- /dev/null +++ b/depends/protobuf/google/protobuf/stubs/once.h @@ -0,0 +1,123 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// +// emulates google3/base/once.h +// +// This header is intended to be included only by internal .cc files and +// generated .pb.cc files. Users should not use this directly. +// +// This is basically a portable version of pthread_once(). +// +// This header declares three things: +// * A type called ProtobufOnceType. +// * A macro GOOGLE_PROTOBUF_DECLARE_ONCE() which declares a variable of type +// ProtobufOnceType. This is the only legal way to declare such a variable. +// The macro may only be used at the global scope (you cannot create local +// or class member variables of this type). +// * A function GogoleOnceInit(ProtobufOnceType* once, void (*init_func)()). +// This function, when invoked multiple times given the same ProtobufOnceType +// object, will invoke init_func on the first call only, and will make sure +// none of the calls return before that first call to init_func has finished. +// +// This implements a way to perform lazy initialization. It's more efficient +// than using mutexes as no lock is needed if initialization has already +// happened. +// +// Example usage: +// void Init(); +// GOOGLE_PROTOBUF_DECLARE_ONCE(once_init); +// +// // Calls Init() exactly once. +// void InitOnce() { +// GoogleOnceInit(&once_init, &Init); +// } +// +// Note that if GoogleOnceInit() is called before main() has begun, it must +// only be called by the thread that will eventually call main() -- that is, +// the thread that performs dynamic initialization. In general this is a safe +// assumption since people don't usually construct threads before main() starts, +// but it is technically not guaranteed. Unfortunately, Win32 provides no way +// whatsoever to statically-initialize its synchronization primitives, so our +// only choice is to assume that dynamic initialization is single-threaded. + +#ifndef GOOGLE_PROTOBUF_STUBS_ONCE_H__ +#define GOOGLE_PROTOBUF_STUBS_ONCE_H__ + +#include + +#ifndef _WIN32 +#include +#endif + +namespace google { +namespace protobuf { + +#ifdef _WIN32 + +struct ProtobufOnceInternal; + +struct LIBPROTOBUF_EXPORT ProtobufOnceType { + ProtobufOnceType(); + ~ProtobufOnceType(); + void Init(void (*init_func)()); + + volatile bool initialized_; + ProtobufOnceInternal* internal_; +}; + +#define GOOGLE_PROTOBUF_DECLARE_ONCE(NAME) \ + ::google::protobuf::ProtobufOnceType NAME + +inline void GoogleOnceInit(ProtobufOnceType* once, void (*init_func)()) { + // Note: Double-checked locking is safe on x86. + if (!once->initialized_) { + once->Init(init_func); + } +} + +#else + +typedef pthread_once_t ProtobufOnceType; + +#define GOOGLE_PROTOBUF_DECLARE_ONCE(NAME) \ + pthread_once_t NAME = PTHREAD_ONCE_INIT + +inline void GoogleOnceInit(ProtobufOnceType* once, void (*init_func)()) { + pthread_once(once, init_func); +} + +#endif + +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_STUBS_ONCE_H__ diff --git a/depends/protobuf/google/protobuf/stubs/stl_util-inl.h b/depends/protobuf/google/protobuf/stubs/stl_util-inl.h new file mode 100644 index 0000000000..a2e671bb74 --- /dev/null +++ b/depends/protobuf/google/protobuf/stubs/stl_util-inl.h @@ -0,0 +1,121 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// from google3/util/gtl/stl_util-inl.h + +#ifndef GOOGLE_PROTOBUF_STUBS_STL_UTIL_INL_H__ +#define GOOGLE_PROTOBUF_STUBS_STL_UTIL_INL_H__ + +#include + +namespace google { +namespace protobuf { + +// STLDeleteContainerPointers() +// For a range within a container of pointers, calls delete +// (non-array version) on these pointers. +// NOTE: for these three functions, we could just implement a DeleteObject +// functor and then call for_each() on the range and functor, but this +// requires us to pull in all of algorithm.h, which seems expensive. +// For hash_[multi]set, it is important that this deletes behind the iterator +// because the hash_set may call the hash function on the iterator when it is +// advanced, which could result in the hash function trying to deference a +// stale pointer. +template +void STLDeleteContainerPointers(ForwardIterator begin, + ForwardIterator end) { + while (begin != end) { + ForwardIterator temp = begin; + ++begin; + delete *temp; + } +} + +// Inside Google, this function implements a horrible, disgusting hack in which +// we reach into the string's private implementation and resize it without +// initializing the new bytes. In some cases doing this can significantly +// improve performance. However, since it's totally non-portable it has no +// place in open source code. Feel free to fill this function in with your +// own disgusting hack if you want the perf boost. +inline void STLStringResizeUninitialized(string* s, size_t new_size) { + s->resize(new_size); +} + +// Return a mutable char* pointing to a string's internal buffer, +// which may not be null-terminated. Writing through this pointer will +// modify the string. +// +// string_as_array(&str)[i] is valid for 0 <= i < str.size() until the +// next call to a string method that invalidates iterators. +// +// As of 2006-04, there is no standard-blessed way of getting a +// mutable reference to a string's internal buffer. However, issue 530 +// (http://www.open-std.org/JTC1/SC22/WG21/docs/lwg-active.html#530) +// proposes this as the method. According to Matt Austern, this should +// already work on all current implementations. +inline char* string_as_array(string* str) { + // DO NOT USE const_cast(str->data())! See the unittest for why. + return str->empty() ? NULL : &*str->begin(); +} + +// STLDeleteElements() deletes all the elements in an STL container and clears +// the container. This function is suitable for use with a vector, set, +// hash_set, or any other STL container which defines sensible begin(), end(), +// and clear() methods. +// +// If container is NULL, this function is a no-op. +// +// As an alternative to calling STLDeleteElements() directly, consider +// ElementDeleter (defined below), which ensures that your container's elements +// are deleted when the ElementDeleter goes out of scope. +template +void STLDeleteElements(T *container) { + if (!container) return; + STLDeleteContainerPointers(container->begin(), container->end()); + container->clear(); +} + +// Given an STL container consisting of (key, value) pairs, STLDeleteValues +// deletes all the "value" components and clears the container. Does nothing +// in the case it's given a NULL pointer. + +template +void STLDeleteValues(T *v) { + if (!v) return; + for (typename T::iterator i = v->begin(); i != v->end(); ++i) { + delete i->second; + } + v->clear(); +} + +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_STUBS_STL_UTIL_INL_H__ diff --git a/depends/protobuf/google/protobuf/stubs/structurally_valid.cc b/depends/protobuf/google/protobuf/stubs/structurally_valid.cc new file mode 100644 index 0000000000..0f6afe6dc8 --- /dev/null +++ b/depends/protobuf/google/protobuf/stubs/structurally_valid.cc @@ -0,0 +1,536 @@ +// Copyright 2005-2008 Google Inc. All Rights Reserved. +// Author: jrm@google.com (Jim Meehan) + +#include + +namespace google { +namespace protobuf { +namespace internal { + +// These four-byte entries compactly encode how many bytes 0..255 to delete +// in making a string replacement, how many bytes to add 0..255, and the offset +// 0..64k-1 of the replacement string in remap_string. +struct RemapEntry { + uint8 delete_bytes; + uint8 add_bytes; + uint16 bytes_offset; +}; + +// Exit type codes for state tables. All but the first get stuffed into +// signed one-byte entries. The first is only generated by executable code. +// To distinguish from next-state entries, these must be contiguous and +// all <= kExitNone +typedef enum { + kExitDstSpaceFull = 239, + kExitIllegalStructure, // 240 + kExitOK, // 241 + kExitReject, // ... + kExitReplace1, + kExitReplace2, + kExitReplace3, + kExitReplace21, + kExitReplace31, + kExitReplace32, + kExitReplaceOffset1, + kExitReplaceOffset2, + kExitReplace1S0, + kExitSpecial, + kExitDoAgain, + kExitRejectAlt, + kExitNone // 255 +} ExitReason; + + +// This struct represents one entire state table. The three initialized byte +// areas are state_table, remap_base, and remap_string. state0 and state0_size +// give the byte offset and length within state_table of the initial state -- +// table lookups are expected to start and end in this state, but for +// truncated UTF-8 strings, may end in a different state. These allow a quick +// test for that condition. entry_shift is 8 for tables subscripted by a full +// byte value and 6 for space-optimized tables subscripted by only six +// significant bits in UTF-8 continuation bytes. +typedef struct { + const uint32 state0; + const uint32 state0_size; + const uint32 total_size; + const int max_expand; + const int entry_shift; + const int bytes_per_entry; + const uint32 losub; + const uint32 hiadd; + const uint8* state_table; + const RemapEntry* remap_base; + const uint8* remap_string; + const uint8* fast_state; +} UTF8StateMachineObj; + +typedef UTF8StateMachineObj UTF8ScanObj; + +#define X__ (kExitIllegalStructure) +#define RJ_ (kExitReject) +#define S1_ (kExitReplace1) +#define S2_ (kExitReplace2) +#define S3_ (kExitReplace3) +#define S21 (kExitReplace21) +#define S31 (kExitReplace31) +#define S32 (kExitReplace32) +#define T1_ (kExitReplaceOffset1) +#define T2_ (kExitReplaceOffset2) +#define S11 (kExitReplace1S0) +#define SP_ (kExitSpecial) +#define D__ (kExitDoAgain) +#define RJA (kExitRejectAlt) + +// Entire table has 9 state blocks of 256 entries each +static const unsigned int utf8acceptnonsurrogates_STATE0 = 0; // state[0] +static const unsigned int utf8acceptnonsurrogates_STATE0_SIZE = 256; // =[1] +static const unsigned int utf8acceptnonsurrogates_TOTAL_SIZE = 2304; +static const unsigned int utf8acceptnonsurrogates_MAX_EXPAND_X4 = 0; +static const unsigned int utf8acceptnonsurrogates_SHIFT = 8; +static const unsigned int utf8acceptnonsurrogates_BYTES = 1; +static const unsigned int utf8acceptnonsurrogates_LOSUB = 0x20202020; +static const unsigned int utf8acceptnonsurrogates_HIADD = 0x00000000; + +static const uint8 utf8acceptnonsurrogates[] = { +// state[0] 0x000000 Byte 1 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, + +X__, X__, 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, + 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 3, 3, + 4, 5, 5, 5, 6, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, + +// state[1] 0x000080 Byte 2 of 2 +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, + +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, + +// state[2] 0x000000 Byte 2 of 3 +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, + +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, + +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, + 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, + +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, + +// state[3] 0x001000 Byte 2 of 3 +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, + +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, + + 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, 1, 1, + +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, + +// state[4] 0x000000 Byte 2 of 4 +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, + +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, + +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, + +// state[5] 0x040000 Byte 2 of 4 +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, + +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, + + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, + +// state[6] 0x100000 Byte 2 of 4 +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, + +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, + + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, + +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, + +// state[7] 0x00d000 Byte 2 of 3 +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, + +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, + + 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, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, + +// state[8] 0x00d800 Byte 3 of 3 +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, + +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, + +RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, +RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, +RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, +RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, + +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, +}; + +// Remap base[0] = (del, add, string_offset) +static const RemapEntry utf8acceptnonsurrogates_remap_base[] = { +{0, 0, 0} }; + +// Remap string[0] +static const unsigned char utf8acceptnonsurrogates_remap_string[] = { +0 }; + +static const unsigned char utf8acceptnonsurrogates_fast[256] = { +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +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, 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, 1, 1, 1, 1, +}; + +static const UTF8ScanObj utf8acceptnonsurrogates_obj = { + utf8acceptnonsurrogates_STATE0, + utf8acceptnonsurrogates_STATE0_SIZE, + utf8acceptnonsurrogates_TOTAL_SIZE, + utf8acceptnonsurrogates_MAX_EXPAND_X4, + utf8acceptnonsurrogates_SHIFT, + utf8acceptnonsurrogates_BYTES, + utf8acceptnonsurrogates_LOSUB, + utf8acceptnonsurrogates_HIADD, + utf8acceptnonsurrogates, + utf8acceptnonsurrogates_remap_base, + utf8acceptnonsurrogates_remap_string, + utf8acceptnonsurrogates_fast +}; + + +#undef X__ +#undef RJ_ +#undef S1_ +#undef S2_ +#undef S3_ +#undef S21 +#undef S31 +#undef S32 +#undef T1_ +#undef T2_ +#undef S11 +#undef SP_ +#undef D__ +#undef RJA + +// Return true if current Tbl pointer is within state0 range +// Note that unsigned compare checks both ends of range simultaneously +static inline bool InStateZero(const UTF8ScanObj* st, const uint8* Tbl) { + const uint8* Tbl0 = &st->state_table[st->state0]; + return (static_cast(Tbl - Tbl0) < st->state0_size); +} + +// Scan a UTF-8 string based on state table. +// Always scan complete UTF-8 characters +// Set number of bytes scanned. Return reason for exiting +int UTF8GenericScan(const UTF8ScanObj* st, + const char * str, + int str_length, + int* bytes_consumed) { + *bytes_consumed = 0; + if (str_length == 0) return kExitOK; + + int eshift = st->entry_shift; + const uint8* isrc = reinterpret_cast(str); + const uint8* src = isrc; + const uint8* srclimit = isrc + str_length; + const uint8* srclimit8 = srclimit - 7; + const uint8* Tbl_0 = &st->state_table[st->state0]; + + DoAgain: + // Do state-table scan + int e = 0; + uint8 c; + const uint8* Tbl2 = &st->fast_state[0]; + const uint32 losub = st->losub; + const uint32 hiadd = st->hiadd; + // Check initial few bytes one at a time until 8-byte aligned + //---------------------------- + while ((((uintptr_t)src & 0x07) != 0) && + (src < srclimit) && + Tbl2[src[0]] == 0) { + src++; + } + if (((uintptr_t)src & 0x07) == 0) { + // Do fast for groups of 8 identity bytes. + // This covers a lot of 7-bit ASCII ~8x faster then the 1-byte loop, + // including slowing slightly on cr/lf/ht + //---------------------------- + while (src < srclimit8) { + uint32 s0123 = (reinterpret_cast(src))[0]; + uint32 s4567 = (reinterpret_cast(src))[1]; + src += 8; + // This is a fast range check for all bytes in [lowsub..0x80-hiadd) + uint32 temp = (s0123 - losub) | (s0123 + hiadd) | + (s4567 - losub) | (s4567 + hiadd); + if ((temp & 0x80808080) != 0) { + // We typically end up here on cr/lf/ht; src was incremented + int e0123 = (Tbl2[src[-8]] | Tbl2[src[-7]]) | + (Tbl2[src[-6]] | Tbl2[src[-5]]); + if (e0123 != 0) { + src -= 8; + break; + } // Exit on Non-interchange + e0123 = (Tbl2[src[-4]] | Tbl2[src[-3]]) | + (Tbl2[src[-2]] | Tbl2[src[-1]]); + if (e0123 != 0) { + src -= 4; + break; + } // Exit on Non-interchange + // Else OK, go around again + } + } + } + //---------------------------- + + // Byte-at-a-time scan + //---------------------------- + const uint8* Tbl = Tbl_0; + while (src < srclimit) { + c = *src; + e = Tbl[c]; + src++; + if (e >= kExitIllegalStructure) {break;} + Tbl = &Tbl_0[e << eshift]; + } + //---------------------------- + + + // Exit posibilities: + // Some exit code, !state0, back up over last char + // Some exit code, state0, back up one byte exactly + // source consumed, !state0, back up over partial char + // source consumed, state0, exit OK + // For illegal byte in state0, avoid backup up over PREVIOUS char + // For truncated last char, back up to beginning of it + + if (e >= kExitIllegalStructure) { + // Back up over exactly one byte of rejected/illegal UTF-8 character + src--; + // Back up more if needed + if (!InStateZero(st, Tbl)) { + do { + src--; + } while ((src > isrc) && ((src[0] & 0xc0) == 0x80)); + } + } else if (!InStateZero(st, Tbl)) { + // Back up over truncated UTF-8 character + e = kExitIllegalStructure; + do { + src--; + } while ((src > isrc) && ((src[0] & 0xc0) == 0x80)); + } else { + // Normal termination, source fully consumed + e = kExitOK; + } + + if (e == kExitDoAgain) { + // Loop back up to the fast scan + goto DoAgain; + } + + *bytes_consumed = src - isrc; + return e; +} + +int UTF8GenericScanFastAscii(const UTF8ScanObj* st, + const char * str, + int str_length, + int* bytes_consumed) { + *bytes_consumed = 0; + if (str_length == 0) return kExitOK; + + const uint8* isrc = reinterpret_cast(str); + const uint8* src = isrc; + const uint8* srclimit = isrc + str_length; + const uint8* srclimit8 = srclimit - 7; + int n; + int rest_consumed; + int exit_reason; + do { + // Check initial few bytes one at a time until 8-byte aligned + while ((((uintptr_t)src & 0x07) != 0) && + (src < srclimit) && (src[0] < 0x80)) { + src++; + } + if (((uintptr_t)src & 0x07) == 0) { + while ((src < srclimit8) && + (((reinterpret_cast(src)[0] | + reinterpret_cast(src)[1]) & 0x80808080) == 0)) { + src += 8; + } + } + while ((src < srclimit) && (src[0] < 0x80)) { + src++; + } + // Run state table on the rest + n = src - isrc; + exit_reason = UTF8GenericScan(st, str + n, str_length - n, &rest_consumed); + src += rest_consumed; + } while ( exit_reason == kExitDoAgain ); + + *bytes_consumed = src - isrc; + return exit_reason; +} + +// Hack: On some compilers the static tables are initialized at startup. +// We can't use them until they are initialized. However, some Protocol +// Buffer parsing happens at static init time and may try to validate +// UTF-8 strings. Since UTF-8 validation is only used for debugging +// anyway, we simply always return success if initialization hasn't +// occurred yet. +namespace { + +bool module_initialized_ = false; + +struct InitDetector { + InitDetector() { + module_initialized_ = true; + } +}; +InitDetector init_detector; + +} // namespace + +bool IsStructurallyValidUTF8(const char* buf, int len) { + if (!module_initialized_) return true; + + int bytes_consumed = 0; + UTF8GenericScanFastAscii(&utf8acceptnonsurrogates_obj, + buf, len, &bytes_consumed); + return (bytes_consumed == len); +} + +} // namespace internal +} // namespace protobuf +} // namespace google diff --git a/depends/protobuf/google/protobuf/stubs/strutil.cc b/depends/protobuf/google/protobuf/stubs/strutil.cc new file mode 100644 index 0000000000..bb658ba8d3 --- /dev/null +++ b/depends/protobuf/google/protobuf/stubs/strutil.cc @@ -0,0 +1,1166 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// from google3/strings/strutil.cc + +#include +#include +#include // FLT_DIG and DBL_DIG +#include +#include +#include +#include + +#ifdef _WIN32 +// MSVC has only _snprintf, not snprintf. +// +// MinGW has both snprintf and _snprintf, but they appear to be different +// functions. The former is buggy. When invoked like so: +// char buffer[32]; +// snprintf(buffer, 32, "%.*g\n", FLT_DIG, 1.23e10f); +// it prints "1.23000e+10". This is plainly wrong: %g should never print +// trailing zeros after the decimal point. For some reason this bug only +// occurs with some input values, not all. In any case, _snprintf does the +// right thing, so we use it. +#define snprintf _snprintf +#endif + +namespace google { +namespace protobuf { + +inline bool IsNaN(double value) { + // NaN is never equal to anything, even itself. + return value != value; +} + +// These are defined as macros on some platforms. #undef them so that we can +// redefine them. +#undef isxdigit +#undef isprint + +// The definitions of these in ctype.h change based on locale. Since our +// string manipulation is all in relation to the protocol buffer and C++ +// languages, we always want to use the C locale. So, we re-define these +// exactly as we want them. +inline bool isxdigit(char c) { + return ('0' <= c && c <= '9') || + ('a' <= c && c <= 'f') || + ('A' <= c && c <= 'F'); +} + +inline bool isprint(char c) { + return c >= 0x20 && c <= 0x7E; +} + +// ---------------------------------------------------------------------- +// StripString +// Replaces any occurrence of the character 'remove' (or the characters +// in 'remove') with the character 'replacewith'. +// ---------------------------------------------------------------------- +void StripString(string* s, const char* remove, char replacewith) { + const char * str_start = s->c_str(); + const char * str = str_start; + for (str = strpbrk(str, remove); + str != NULL; + str = strpbrk(str + 1, remove)) { + (*s)[str - str_start] = replacewith; + } +} + +// ---------------------------------------------------------------------- +// StringReplace() +// Replace the "old" pattern with the "new" pattern in a string, +// and append the result to "res". If replace_all is false, +// it only replaces the first instance of "old." +// ---------------------------------------------------------------------- + +void StringReplace(const string& s, const string& oldsub, + const string& newsub, bool replace_all, + string* res) { + if (oldsub.empty()) { + res->append(s); // if empty, append the given string. + return; + } + + string::size_type start_pos = 0; + string::size_type pos; + do { + pos = s.find(oldsub, start_pos); + if (pos == string::npos) { + break; + } + res->append(s, start_pos, pos - start_pos); + res->append(newsub); + start_pos = pos + oldsub.size(); // start searching again after the "old" + } while (replace_all); + res->append(s, start_pos, s.length() - start_pos); +} + +// ---------------------------------------------------------------------- +// StringReplace() +// Give me a string and two patterns "old" and "new", and I replace +// the first instance of "old" in the string with "new", if it +// exists. If "global" is true; call this repeatedly until it +// fails. RETURN a new string, regardless of whether the replacement +// happened or not. +// ---------------------------------------------------------------------- + +string StringReplace(const string& s, const string& oldsub, + const string& newsub, bool replace_all) { + string ret; + StringReplace(s, oldsub, newsub, replace_all, &ret); + return ret; +} + +// ---------------------------------------------------------------------- +// SplitStringUsing() +// Split a string using a character delimiter. Append the components +// to 'result'. +// +// Note: For multi-character delimiters, this routine will split on *ANY* of +// the characters in the string, not the entire string as a single delimiter. +// ---------------------------------------------------------------------- +template +static inline +void SplitStringToIteratorUsing(const string& full, + const char* delim, + ITR& result) { + // Optimize the common case where delim is a single character. + if (delim[0] != '\0' && delim[1] == '\0') { + char c = delim[0]; + const char* p = full.data(); + const char* end = p + full.size(); + while (p != end) { + if (*p == c) { + ++p; + } else { + const char* start = p; + while (++p != end && *p != c); + *result++ = string(start, p - start); + } + } + return; + } + + string::size_type begin_index, end_index; + begin_index = full.find_first_not_of(delim); + while (begin_index != string::npos) { + end_index = full.find_first_of(delim, begin_index); + if (end_index == string::npos) { + *result++ = full.substr(begin_index); + return; + } + *result++ = full.substr(begin_index, (end_index - begin_index)); + begin_index = full.find_first_not_of(delim, end_index); + } +} + +void SplitStringUsing(const string& full, + const char* delim, + vector* result) { + back_insert_iterator< vector > it(*result); + SplitStringToIteratorUsing(full, delim, it); +} + +// ---------------------------------------------------------------------- +// JoinStrings() +// This merges a vector of string components with delim inserted +// as separaters between components. +// +// ---------------------------------------------------------------------- +template +static void JoinStringsIterator(const ITERATOR& start, + const ITERATOR& end, + const char* delim, + string* result) { + GOOGLE_CHECK(result != NULL); + result->clear(); + int delim_length = strlen(delim); + + // Precompute resulting length so we can reserve() memory in one shot. + int length = 0; + for (ITERATOR iter = start; iter != end; ++iter) { + if (iter != start) { + length += delim_length; + } + length += iter->size(); + } + result->reserve(length); + + // Now combine everything. + for (ITERATOR iter = start; iter != end; ++iter) { + if (iter != start) { + result->append(delim, delim_length); + } + result->append(iter->data(), iter->size()); + } +} + +void JoinStrings(const vector& components, + const char* delim, + string * result) { + JoinStringsIterator(components.begin(), components.end(), delim, result); +} + +// ---------------------------------------------------------------------- +// UnescapeCEscapeSequences() +// This does all the unescaping that C does: \ooo, \r, \n, etc +// Returns length of resulting string. +// The implementation of \x parses any positive number of hex digits, +// but it is an error if the value requires more than 8 bits, and the +// result is truncated to 8 bits. +// +// The second call stores its errors in a supplied string vector. +// If the string vector pointer is NULL, it reports the errors with LOG(). +// ---------------------------------------------------------------------- + +#define IS_OCTAL_DIGIT(c) (((c) >= '0') && ((c) <= '7')) + +inline int hex_digit_to_int(char c) { + /* Assume ASCII. */ + assert('0' == 0x30 && 'A' == 0x41 && 'a' == 0x61); + assert(isxdigit(c)); + int x = static_cast(c); + if (x > '9') { + x += 9; + } + return x & 0xf; +} + +// Protocol buffers doesn't ever care about errors, but I don't want to remove +// the code. +#define LOG_STRING(LEVEL, VECTOR) GOOGLE_LOG_IF(LEVEL, false) + +int UnescapeCEscapeSequences(const char* source, char* dest) { + return UnescapeCEscapeSequences(source, dest, NULL); +} + +int UnescapeCEscapeSequences(const char* source, char* dest, + vector *errors) { + GOOGLE_DCHECK(errors == NULL) << "Error reporting not implemented."; + + char* d = dest; + const char* p = source; + + // Small optimization for case where source = dest and there's no escaping + while ( p == d && *p != '\0' && *p != '\\' ) + p++, d++; + + while (*p != '\0') { + if (*p != '\\') { + *d++ = *p++; + } else { + switch ( *++p ) { // skip past the '\\' + case '\0': + LOG_STRING(ERROR, errors) << "String cannot end with \\"; + *d = '\0'; + return d - dest; // we're done with p + case 'a': *d++ = '\a'; break; + case 'b': *d++ = '\b'; break; + case 'f': *d++ = '\f'; break; + case 'n': *d++ = '\n'; break; + case 'r': *d++ = '\r'; break; + case 't': *d++ = '\t'; break; + case 'v': *d++ = '\v'; break; + case '\\': *d++ = '\\'; break; + case '?': *d++ = '\?'; break; // \? Who knew? + case '\'': *d++ = '\''; break; + case '"': *d++ = '\"'; break; + case '0': case '1': case '2': case '3': // octal digit: 1 to 3 digits + case '4': case '5': case '6': case '7': { + char ch = *p - '0'; + if ( IS_OCTAL_DIGIT(p[1]) ) + ch = ch * 8 + *++p - '0'; + if ( IS_OCTAL_DIGIT(p[1]) ) // safe (and easy) to do this twice + ch = ch * 8 + *++p - '0'; // now points at last digit + *d++ = ch; + break; + } + case 'x': case 'X': { + if (!isxdigit(p[1])) { + if (p[1] == '\0') { + LOG_STRING(ERROR, errors) << "String cannot end with \\x"; + } else { + LOG_STRING(ERROR, errors) << + "\\x cannot be followed by non-hex digit: \\" << *p << p[1]; + } + break; + } + unsigned int ch = 0; + const char *hex_start = p; + while (isxdigit(p[1])) // arbitrarily many hex digits + ch = (ch << 4) + hex_digit_to_int(*++p); + if (ch > 0xFF) + LOG_STRING(ERROR, errors) << "Value of " << + "\\" << string(hex_start, p+1-hex_start) << " exceeds 8 bits"; + *d++ = ch; + break; + } +#if 0 // TODO(kenton): Support \u and \U? Requires runetochar(). + case 'u': { + // \uhhhh => convert 4 hex digits to UTF-8 + char32 rune = 0; + const char *hex_start = p; + for (int i = 0; i < 4; ++i) { + if (isxdigit(p[1])) { // Look one char ahead. + rune = (rune << 4) + hex_digit_to_int(*++p); // Advance p. + } else { + LOG_STRING(ERROR, errors) + << "\\u must be followed by 4 hex digits: \\" + << string(hex_start, p+1-hex_start); + break; + } + } + d += runetochar(d, &rune); + break; + } + case 'U': { + // \Uhhhhhhhh => convert 8 hex digits to UTF-8 + char32 rune = 0; + const char *hex_start = p; + for (int i = 0; i < 8; ++i) { + if (isxdigit(p[1])) { // Look one char ahead. + // Don't change rune until we're sure this + // is within the Unicode limit, but do advance p. + char32 newrune = (rune << 4) + hex_digit_to_int(*++p); + if (newrune > 0x10FFFF) { + LOG_STRING(ERROR, errors) + << "Value of \\" + << string(hex_start, p + 1 - hex_start) + << " exceeds Unicode limit (0x10FFFF)"; + break; + } else { + rune = newrune; + } + } else { + LOG_STRING(ERROR, errors) + << "\\U must be followed by 8 hex digits: \\" + << string(hex_start, p+1-hex_start); + break; + } + } + d += runetochar(d, &rune); + break; + } +#endif + default: + LOG_STRING(ERROR, errors) << "Unknown escape sequence: \\" << *p; + } + p++; // read past letter we escaped + } + } + *d = '\0'; + return d - dest; +} + +// ---------------------------------------------------------------------- +// UnescapeCEscapeString() +// This does the same thing as UnescapeCEscapeSequences, but creates +// a new string. The caller does not need to worry about allocating +// a dest buffer. This should be used for non performance critical +// tasks such as printing debug messages. It is safe for src and dest +// to be the same. +// +// The second call stores its errors in a supplied string vector. +// If the string vector pointer is NULL, it reports the errors with LOG(). +// +// In the first and second calls, the length of dest is returned. In the +// the third call, the new string is returned. +// ---------------------------------------------------------------------- +int UnescapeCEscapeString(const string& src, string* dest) { + return UnescapeCEscapeString(src, dest, NULL); +} + +int UnescapeCEscapeString(const string& src, string* dest, + vector *errors) { + scoped_array unescaped(new char[src.size() + 1]); + int len = UnescapeCEscapeSequences(src.c_str(), unescaped.get(), errors); + GOOGLE_CHECK(dest); + dest->assign(unescaped.get(), len); + return len; +} + +string UnescapeCEscapeString(const string& src) { + scoped_array unescaped(new char[src.size() + 1]); + int len = UnescapeCEscapeSequences(src.c_str(), unescaped.get(), NULL); + return string(unescaped.get(), len); +} + +// ---------------------------------------------------------------------- +// CEscapeString() +// CHexEscapeString() +// Copies 'src' to 'dest', escaping dangerous characters using +// C-style escape sequences. This is very useful for preparing query +// flags. 'src' and 'dest' should not overlap. The 'Hex' version uses +// hexadecimal rather than octal sequences. +// Returns the number of bytes written to 'dest' (not including the \0) +// or -1 if there was insufficient space. +// +// Currently only \n, \r, \t, ", ', \ and !isprint() chars are escaped. +// ---------------------------------------------------------------------- +int CEscapeInternal(const char* src, int src_len, char* dest, + int dest_len, bool use_hex, bool utf8_safe) { + const char* src_end = src + src_len; + int used = 0; + bool last_hex_escape = false; // true if last output char was \xNN + + for (; src < src_end; src++) { + if (dest_len - used < 2) // Need space for two letter escape + return -1; + + bool is_hex_escape = false; + switch (*src) { + case '\n': dest[used++] = '\\'; dest[used++] = 'n'; break; + case '\r': dest[used++] = '\\'; dest[used++] = 'r'; break; + case '\t': dest[used++] = '\\'; dest[used++] = 't'; break; + case '\"': dest[used++] = '\\'; dest[used++] = '\"'; break; + case '\'': dest[used++] = '\\'; dest[used++] = '\''; break; + case '\\': dest[used++] = '\\'; dest[used++] = '\\'; break; + default: + // Note that if we emit \xNN and the src character after that is a hex + // digit then that digit must be escaped too to prevent it being + // interpreted as part of the character code by C. + if ((!utf8_safe || static_cast(*src) < 0x80) && + (!isprint(*src) || + (last_hex_escape && isxdigit(*src)))) { + if (dest_len - used < 4) // need space for 4 letter escape + return -1; + sprintf(dest + used, (use_hex ? "\\x%02x" : "\\%03o"), + static_cast(*src)); + is_hex_escape = use_hex; + used += 4; + } else { + dest[used++] = *src; break; + } + } + last_hex_escape = is_hex_escape; + } + + if (dest_len - used < 1) // make sure that there is room for \0 + return -1; + + dest[used] = '\0'; // doesn't count towards return value though + return used; +} + +int CEscapeString(const char* src, int src_len, char* dest, int dest_len) { + return CEscapeInternal(src, src_len, dest, dest_len, false, false); +} + +// ---------------------------------------------------------------------- +// CEscape() +// CHexEscape() +// Copies 'src' to result, escaping dangerous characters using +// C-style escape sequences. This is very useful for preparing query +// flags. 'src' and 'dest' should not overlap. The 'Hex' version +// hexadecimal rather than octal sequences. +// +// Currently only \n, \r, \t, ", ', \ and !isprint() chars are escaped. +// ---------------------------------------------------------------------- +string CEscape(const string& src) { + const int dest_length = src.size() * 4 + 1; // Maximum possible expansion + scoped_array dest(new char[dest_length]); + const int len = CEscapeInternal(src.data(), src.size(), + dest.get(), dest_length, false, false); + GOOGLE_DCHECK_GE(len, 0); + return string(dest.get(), len); +} + +namespace strings { + +string Utf8SafeCEscape(const string& src) { + const int dest_length = src.size() * 4 + 1; // Maximum possible expansion + scoped_array dest(new char[dest_length]); + const int len = CEscapeInternal(src.data(), src.size(), + dest.get(), dest_length, false, true); + GOOGLE_DCHECK_GE(len, 0); + return string(dest.get(), len); +} + +string CHexEscape(const string& src) { + const int dest_length = src.size() * 4 + 1; // Maximum possible expansion + scoped_array dest(new char[dest_length]); + const int len = CEscapeInternal(src.data(), src.size(), + dest.get(), dest_length, true, false); + GOOGLE_DCHECK_GE(len, 0); + return string(dest.get(), len); +} + +} // namespace strings + +// ---------------------------------------------------------------------- +// strto32_adaptor() +// strtou32_adaptor() +// Implementation of strto[u]l replacements that have identical +// overflow and underflow characteristics for both ILP-32 and LP-64 +// platforms, including errno preservation in error-free calls. +// ---------------------------------------------------------------------- + +int32 strto32_adaptor(const char *nptr, char **endptr, int base) { + const int saved_errno = errno; + errno = 0; + const long result = strtol(nptr, endptr, base); + if (errno == ERANGE && result == LONG_MIN) { + return kint32min; + } else if (errno == ERANGE && result == LONG_MAX) { + return kint32max; + } else if (errno == 0 && result < kint32min) { + errno = ERANGE; + return kint32min; + } else if (errno == 0 && result > kint32max) { + errno = ERANGE; + return kint32max; + } + if (errno == 0) + errno = saved_errno; + return static_cast(result); +} + +uint32 strtou32_adaptor(const char *nptr, char **endptr, int base) { + const int saved_errno = errno; + errno = 0; + const unsigned long result = strtoul(nptr, endptr, base); + if (errno == ERANGE && result == ULONG_MAX) { + return kuint32max; + } else if (errno == 0 && result > kuint32max) { + errno = ERANGE; + return kuint32max; + } + if (errno == 0) + errno = saved_errno; + return static_cast(result); +} + +// ---------------------------------------------------------------------- +// FastIntToBuffer() +// FastInt64ToBuffer() +// FastHexToBuffer() +// FastHex64ToBuffer() +// FastHex32ToBuffer() +// ---------------------------------------------------------------------- + +// Offset into buffer where FastInt64ToBuffer places the end of string +// null character. Also used by FastInt64ToBufferLeft. +static const int kFastInt64ToBufferOffset = 21; + +char *FastInt64ToBuffer(int64 i, char* buffer) { + // We could collapse the positive and negative sections, but that + // would be slightly slower for positive numbers... + // 22 bytes is enough to store -2**64, -18446744073709551616. + char* p = buffer + kFastInt64ToBufferOffset; + *p-- = '\0'; + if (i >= 0) { + do { + *p-- = '0' + i % 10; + i /= 10; + } while (i > 0); + return p + 1; + } else { + // On different platforms, % and / have different behaviors for + // negative numbers, so we need to jump through hoops to make sure + // we don't divide negative numbers. + if (i > -10) { + i = -i; + *p-- = '0' + i; + *p = '-'; + return p; + } else { + // Make sure we aren't at MIN_INT, in which case we can't say i = -i + i = i + 10; + i = -i; + *p-- = '0' + i % 10; + // Undo what we did a moment ago + i = i / 10 + 1; + do { + *p-- = '0' + i % 10; + i /= 10; + } while (i > 0); + *p = '-'; + return p; + } + } +} + +// Offset into buffer where FastInt32ToBuffer places the end of string +// null character. Also used by FastInt32ToBufferLeft +static const int kFastInt32ToBufferOffset = 11; + +// Yes, this is a duplicate of FastInt64ToBuffer. But, we need this for the +// compiler to generate 32 bit arithmetic instructions. It's much faster, at +// least with 32 bit binaries. +char *FastInt32ToBuffer(int32 i, char* buffer) { + // We could collapse the positive and negative sections, but that + // would be slightly slower for positive numbers... + // 12 bytes is enough to store -2**32, -4294967296. + char* p = buffer + kFastInt32ToBufferOffset; + *p-- = '\0'; + if (i >= 0) { + do { + *p-- = '0' + i % 10; + i /= 10; + } while (i > 0); + return p + 1; + } else { + // On different platforms, % and / have different behaviors for + // negative numbers, so we need to jump through hoops to make sure + // we don't divide negative numbers. + if (i > -10) { + i = -i; + *p-- = '0' + i; + *p = '-'; + return p; + } else { + // Make sure we aren't at MIN_INT, in which case we can't say i = -i + i = i + 10; + i = -i; + *p-- = '0' + i % 10; + // Undo what we did a moment ago + i = i / 10 + 1; + do { + *p-- = '0' + i % 10; + i /= 10; + } while (i > 0); + *p = '-'; + return p; + } + } +} + +char *FastHexToBuffer(int i, char* buffer) { + GOOGLE_CHECK(i >= 0) << "FastHexToBuffer() wants non-negative integers, not " << i; + + static const char *hexdigits = "0123456789abcdef"; + char *p = buffer + 21; + *p-- = '\0'; + do { + *p-- = hexdigits[i & 15]; // mod by 16 + i >>= 4; // divide by 16 + } while (i > 0); + return p + 1; +} + +char *InternalFastHexToBuffer(uint64 value, char* buffer, int num_byte) { + static const char *hexdigits = "0123456789abcdef"; + buffer[num_byte] = '\0'; + for (int i = num_byte - 1; i >= 0; i--) { + buffer[i] = hexdigits[uint32(value) & 0xf]; + value >>= 4; + } + return buffer; +} + +char *FastHex64ToBuffer(uint64 value, char* buffer) { + return InternalFastHexToBuffer(value, buffer, 16); +} + +char *FastHex32ToBuffer(uint32 value, char* buffer) { + return InternalFastHexToBuffer(value, buffer, 8); +} + +static inline char* PlaceNum(char* p, int num, char prev_sep) { + *p-- = '0' + num % 10; + *p-- = '0' + num / 10; + *p-- = prev_sep; + return p; +} + +// ---------------------------------------------------------------------- +// FastInt32ToBufferLeft() +// FastUInt32ToBufferLeft() +// FastInt64ToBufferLeft() +// FastUInt64ToBufferLeft() +// +// Like the Fast*ToBuffer() functions above, these are intended for speed. +// Unlike the Fast*ToBuffer() functions, however, these functions write +// their output to the beginning of the buffer (hence the name, as the +// output is left-aligned). The caller is responsible for ensuring that +// the buffer has enough space to hold the output. +// +// Returns a pointer to the end of the string (i.e. the null character +// terminating the string). +// ---------------------------------------------------------------------- + +static const char two_ASCII_digits[100][2] = { + {'0','0'}, {'0','1'}, {'0','2'}, {'0','3'}, {'0','4'}, + {'0','5'}, {'0','6'}, {'0','7'}, {'0','8'}, {'0','9'}, + {'1','0'}, {'1','1'}, {'1','2'}, {'1','3'}, {'1','4'}, + {'1','5'}, {'1','6'}, {'1','7'}, {'1','8'}, {'1','9'}, + {'2','0'}, {'2','1'}, {'2','2'}, {'2','3'}, {'2','4'}, + {'2','5'}, {'2','6'}, {'2','7'}, {'2','8'}, {'2','9'}, + {'3','0'}, {'3','1'}, {'3','2'}, {'3','3'}, {'3','4'}, + {'3','5'}, {'3','6'}, {'3','7'}, {'3','8'}, {'3','9'}, + {'4','0'}, {'4','1'}, {'4','2'}, {'4','3'}, {'4','4'}, + {'4','5'}, {'4','6'}, {'4','7'}, {'4','8'}, {'4','9'}, + {'5','0'}, {'5','1'}, {'5','2'}, {'5','3'}, {'5','4'}, + {'5','5'}, {'5','6'}, {'5','7'}, {'5','8'}, {'5','9'}, + {'6','0'}, {'6','1'}, {'6','2'}, {'6','3'}, {'6','4'}, + {'6','5'}, {'6','6'}, {'6','7'}, {'6','8'}, {'6','9'}, + {'7','0'}, {'7','1'}, {'7','2'}, {'7','3'}, {'7','4'}, + {'7','5'}, {'7','6'}, {'7','7'}, {'7','8'}, {'7','9'}, + {'8','0'}, {'8','1'}, {'8','2'}, {'8','3'}, {'8','4'}, + {'8','5'}, {'8','6'}, {'8','7'}, {'8','8'}, {'8','9'}, + {'9','0'}, {'9','1'}, {'9','2'}, {'9','3'}, {'9','4'}, + {'9','5'}, {'9','6'}, {'9','7'}, {'9','8'}, {'9','9'} +}; + +char* FastUInt32ToBufferLeft(uint32 u, char* buffer) { + int digits; + const char *ASCII_digits = NULL; + // The idea of this implementation is to trim the number of divides to as few + // as possible by using multiplication and subtraction rather than mod (%), + // and by outputting two digits at a time rather than one. + // The huge-number case is first, in the hopes that the compiler will output + // that case in one branch-free block of code, and only output conditional + // branches into it from below. + if (u >= 1000000000) { // >= 1,000,000,000 + digits = u / 100000000; // 100,000,000 + ASCII_digits = two_ASCII_digits[digits]; + buffer[0] = ASCII_digits[0]; + buffer[1] = ASCII_digits[1]; + buffer += 2; +sublt100_000_000: + u -= digits * 100000000; // 100,000,000 +lt100_000_000: + digits = u / 1000000; // 1,000,000 + ASCII_digits = two_ASCII_digits[digits]; + buffer[0] = ASCII_digits[0]; + buffer[1] = ASCII_digits[1]; + buffer += 2; +sublt1_000_000: + u -= digits * 1000000; // 1,000,000 +lt1_000_000: + digits = u / 10000; // 10,000 + ASCII_digits = two_ASCII_digits[digits]; + buffer[0] = ASCII_digits[0]; + buffer[1] = ASCII_digits[1]; + buffer += 2; +sublt10_000: + u -= digits * 10000; // 10,000 +lt10_000: + digits = u / 100; + ASCII_digits = two_ASCII_digits[digits]; + buffer[0] = ASCII_digits[0]; + buffer[1] = ASCII_digits[1]; + buffer += 2; +sublt100: + u -= digits * 100; +lt100: + digits = u; + ASCII_digits = two_ASCII_digits[digits]; + buffer[0] = ASCII_digits[0]; + buffer[1] = ASCII_digits[1]; + buffer += 2; +done: + *buffer = 0; + return buffer; + } + + if (u < 100) { + digits = u; + if (u >= 10) goto lt100; + *buffer++ = '0' + digits; + goto done; + } + if (u < 10000) { // 10,000 + if (u >= 1000) goto lt10_000; + digits = u / 100; + *buffer++ = '0' + digits; + goto sublt100; + } + if (u < 1000000) { // 1,000,000 + if (u >= 100000) goto lt1_000_000; + digits = u / 10000; // 10,000 + *buffer++ = '0' + digits; + goto sublt10_000; + } + if (u < 100000000) { // 100,000,000 + if (u >= 10000000) goto lt100_000_000; + digits = u / 1000000; // 1,000,000 + *buffer++ = '0' + digits; + goto sublt1_000_000; + } + // we already know that u < 1,000,000,000 + digits = u / 100000000; // 100,000,000 + *buffer++ = '0' + digits; + goto sublt100_000_000; +} + +char* FastInt32ToBufferLeft(int32 i, char* buffer) { + uint32 u = i; + if (i < 0) { + *buffer++ = '-'; + u = -i; + } + return FastUInt32ToBufferLeft(u, buffer); +} + +char* FastUInt64ToBufferLeft(uint64 u64, char* buffer) { + int digits; + const char *ASCII_digits = NULL; + + uint32 u = static_cast(u64); + if (u == u64) return FastUInt32ToBufferLeft(u, buffer); + + uint64 top_11_digits = u64 / 1000000000; + buffer = FastUInt64ToBufferLeft(top_11_digits, buffer); + u = u64 - (top_11_digits * 1000000000); + + digits = u / 10000000; // 10,000,000 + GOOGLE_DCHECK_LT(digits, 100); + ASCII_digits = two_ASCII_digits[digits]; + buffer[0] = ASCII_digits[0]; + buffer[1] = ASCII_digits[1]; + buffer += 2; + u -= digits * 10000000; // 10,000,000 + digits = u / 100000; // 100,000 + ASCII_digits = two_ASCII_digits[digits]; + buffer[0] = ASCII_digits[0]; + buffer[1] = ASCII_digits[1]; + buffer += 2; + u -= digits * 100000; // 100,000 + digits = u / 1000; // 1,000 + ASCII_digits = two_ASCII_digits[digits]; + buffer[0] = ASCII_digits[0]; + buffer[1] = ASCII_digits[1]; + buffer += 2; + u -= digits * 1000; // 1,000 + digits = u / 10; + ASCII_digits = two_ASCII_digits[digits]; + buffer[0] = ASCII_digits[0]; + buffer[1] = ASCII_digits[1]; + buffer += 2; + u -= digits * 10; + digits = u; + *buffer++ = '0' + digits; + *buffer = 0; + return buffer; +} + +char* FastInt64ToBufferLeft(int64 i, char* buffer) { + uint64 u = i; + if (i < 0) { + *buffer++ = '-'; + u = -i; + } + return FastUInt64ToBufferLeft(u, buffer); +} + +// ---------------------------------------------------------------------- +// SimpleItoa() +// Description: converts an integer to a string. +// +// Return value: string +// ---------------------------------------------------------------------- + +string SimpleItoa(int i) { + char buffer[kFastToBufferSize]; + return (sizeof(i) == 4) ? + FastInt32ToBuffer(i, buffer) : + FastInt64ToBuffer(i, buffer); +} + +string SimpleItoa(unsigned int i) { + char buffer[kFastToBufferSize]; + return string(buffer, (sizeof(i) == 4) ? + FastUInt32ToBufferLeft(i, buffer) : + FastUInt64ToBufferLeft(i, buffer)); +} + +string SimpleItoa(long i) { + char buffer[kFastToBufferSize]; + return (sizeof(i) == 4) ? + FastInt32ToBuffer(i, buffer) : + FastInt64ToBuffer(i, buffer); +} + +string SimpleItoa(unsigned long i) { + char buffer[kFastToBufferSize]; + return string(buffer, (sizeof(i) == 4) ? + FastUInt32ToBufferLeft(i, buffer) : + FastUInt64ToBufferLeft(i, buffer)); +} + +string SimpleItoa(long long i) { + char buffer[kFastToBufferSize]; + return (sizeof(i) == 4) ? + FastInt32ToBuffer(i, buffer) : + FastInt64ToBuffer(i, buffer); +} + +string SimpleItoa(unsigned long long i) { + char buffer[kFastToBufferSize]; + return string(buffer, (sizeof(i) == 4) ? + FastUInt32ToBufferLeft(i, buffer) : + FastUInt64ToBufferLeft(i, buffer)); +} + +// ---------------------------------------------------------------------- +// SimpleDtoa() +// SimpleFtoa() +// DoubleToBuffer() +// FloatToBuffer() +// We want to print the value without losing precision, but we also do +// not want to print more digits than necessary. This turns out to be +// trickier than it sounds. Numbers like 0.2 cannot be represented +// exactly in binary. If we print 0.2 with a very large precision, +// e.g. "%.50g", we get "0.2000000000000000111022302462515654042363167". +// On the other hand, if we set the precision too low, we lose +// significant digits when printing numbers that actually need them. +// It turns out there is no precision value that does the right thing +// for all numbers. +// +// Our strategy is to first try printing with a precision that is never +// over-precise, then parse the result with strtod() to see if it +// matches. If not, we print again with a precision that will always +// give a precise result, but may use more digits than necessary. +// +// An arguably better strategy would be to use the algorithm described +// in "How to Print Floating-Point Numbers Accurately" by Steele & +// White, e.g. as implemented by David M. Gay's dtoa(). It turns out, +// however, that the following implementation is about as fast as +// DMG's code. Furthermore, DMG's code locks mutexes, which means it +// will not scale well on multi-core machines. DMG's code is slightly +// more accurate (in that it will never use more digits than +// necessary), but this is probably irrelevant for most users. +// +// Rob Pike and Ken Thompson also have an implementation of dtoa() in +// third_party/fmt/fltfmt.cc. Their implementation is similar to this +// one in that it makes guesses and then uses strtod() to check them. +// Their implementation is faster because they use their own code to +// generate the digits in the first place rather than use snprintf(), +// thus avoiding format string parsing overhead. However, this makes +// it considerably more complicated than the following implementation, +// and it is embedded in a larger library. If speed turns out to be +// an issue, we could re-implement this in terms of their +// implementation. +// ---------------------------------------------------------------------- + +string SimpleDtoa(double value) { + char buffer[kDoubleToBufferSize]; + return DoubleToBuffer(value, buffer); +} + +string SimpleFtoa(float value) { + char buffer[kFloatToBufferSize]; + return FloatToBuffer(value, buffer); +} + +static inline bool IsValidFloatChar(char c) { + return ('0' <= c && c <= '9') || + c == 'e' || c == 'E' || + c == '+' || c == '-'; +} + +void DelocalizeRadix(char* buffer) { + // Fast check: if the buffer has a normal decimal point, assume no + // translation is needed. + if (strchr(buffer, '.') != NULL) return; + + // Find the first unknown character. + while (IsValidFloatChar(*buffer)) ++buffer; + + if (*buffer == '\0') { + // No radix character found. + return; + } + + // We are now pointing at the locale-specific radix character. Replace it + // with '.'. + *buffer = '.'; + ++buffer; + + if (!IsValidFloatChar(*buffer) && *buffer != '\0') { + // It appears the radix was a multi-byte character. We need to remove the + // extra bytes. + char* target = buffer; + do { ++buffer; } while (!IsValidFloatChar(*buffer) && *buffer != '\0'); + memmove(target, buffer, strlen(buffer) + 1); + } +} + +char* DoubleToBuffer(double value, char* buffer) { + // DBL_DIG is 15 for IEEE-754 doubles, which are used on almost all + // platforms these days. Just in case some system exists where DBL_DIG + // is significantly larger -- and risks overflowing our buffer -- we have + // this assert. + GOOGLE_COMPILE_ASSERT(DBL_DIG < 20, DBL_DIG_is_too_big); + + if (value == numeric_limits::infinity()) { + strcpy(buffer, "inf"); + return buffer; + } else if (value == -numeric_limits::infinity()) { + strcpy(buffer, "-inf"); + return buffer; + } else if (IsNaN(value)) { + strcpy(buffer, "nan"); + return buffer; + } + + int snprintf_result = + snprintf(buffer, kDoubleToBufferSize, "%.*g", DBL_DIG, value); + + // The snprintf should never overflow because the buffer is significantly + // larger than the precision we asked for. + GOOGLE_DCHECK(snprintf_result > 0 && snprintf_result < kDoubleToBufferSize); + + // We need to make parsed_value volatile in order to force the compiler to + // write it out to the stack. Otherwise, it may keep the value in a + // register, and if it does that, it may keep it as a long double instead + // of a double. This long double may have extra bits that make it compare + // unequal to "value" even though it would be exactly equal if it were + // truncated to a double. + volatile double parsed_value = strtod(buffer, NULL); + if (parsed_value != value) { + int snprintf_result = + snprintf(buffer, kDoubleToBufferSize, "%.*g", DBL_DIG+2, value); + + // Should never overflow; see above. + GOOGLE_DCHECK(snprintf_result > 0 && snprintf_result < kDoubleToBufferSize); + } + + DelocalizeRadix(buffer); + return buffer; +} + +bool safe_strtof(const char* str, float* value) { + char* endptr; + errno = 0; // errno only gets set on errors +#if defined(_WIN32) || defined (__hpux) // has no strtof() + *value = strtod(str, &endptr); +#else + *value = strtof(str, &endptr); +#endif + return *str != 0 && *endptr == 0 && errno == 0; +} + +char* FloatToBuffer(float value, char* buffer) { + // FLT_DIG is 6 for IEEE-754 floats, which are used on almost all + // platforms these days. Just in case some system exists where FLT_DIG + // is significantly larger -- and risks overflowing our buffer -- we have + // this assert. + GOOGLE_COMPILE_ASSERT(FLT_DIG < 10, FLT_DIG_is_too_big); + + if (value == numeric_limits::infinity()) { + strcpy(buffer, "inf"); + return buffer; + } else if (value == -numeric_limits::infinity()) { + strcpy(buffer, "-inf"); + return buffer; + } else if (IsNaN(value)) { + strcpy(buffer, "nan"); + return buffer; + } + + int snprintf_result = + snprintf(buffer, kFloatToBufferSize, "%.*g", FLT_DIG, value); + + // The snprintf should never overflow because the buffer is significantly + // larger than the precision we asked for. + GOOGLE_DCHECK(snprintf_result > 0 && snprintf_result < kFloatToBufferSize); + + float parsed_value; + if (!safe_strtof(buffer, &parsed_value) || parsed_value != value) { + int snprintf_result = + snprintf(buffer, kFloatToBufferSize, "%.*g", FLT_DIG+2, value); + + // Should never overflow; see above. + GOOGLE_DCHECK(snprintf_result > 0 && snprintf_result < kFloatToBufferSize); + } + + DelocalizeRadix(buffer); + return buffer; +} + +// ---------------------------------------------------------------------- +// NoLocaleStrtod() +// This code will make you cry. +// ---------------------------------------------------------------------- + +// Returns a string identical to *input except that the character pointed to +// by radix_pos (which should be '.') is replaced with the locale-specific +// radix character. +string LocalizeRadix(const char* input, const char* radix_pos) { + // Determine the locale-specific radix character by calling sprintf() to + // print the number 1.5, then stripping off the digits. As far as I can + // tell, this is the only portable, thread-safe way to get the C library + // to divuldge the locale's radix character. No, localeconv() is NOT + // thread-safe. + char temp[16]; + int size = sprintf(temp, "%.1f", 1.5); + GOOGLE_CHECK_EQ(temp[0], '1'); + GOOGLE_CHECK_EQ(temp[size-1], '5'); + GOOGLE_CHECK_LE(size, 6); + + // Now replace the '.' in the input with it. + string result; + result.reserve(strlen(input) + size - 3); + result.append(input, radix_pos); + result.append(temp + 1, size - 2); + result.append(radix_pos + 1); + return result; +} + +double NoLocaleStrtod(const char* text, char** original_endptr) { + // We cannot simply set the locale to "C" temporarily with setlocale() + // as this is not thread-safe. Instead, we try to parse in the current + // locale first. If parsing stops at a '.' character, then this is a + // pretty good hint that we're actually in some other locale in which + // '.' is not the radix character. + + char* temp_endptr; + double result = strtod(text, &temp_endptr); + if (original_endptr != NULL) *original_endptr = temp_endptr; + if (*temp_endptr != '.') return result; + + // Parsing halted on a '.'. Perhaps we're in a different locale? Let's + // try to replace the '.' with a locale-specific radix character and + // try again. + string localized = LocalizeRadix(text, temp_endptr); + const char* localized_cstr = localized.c_str(); + char* localized_endptr; + result = strtod(localized_cstr, &localized_endptr); + if ((localized_endptr - localized_cstr) > + (temp_endptr - text)) { + // This attempt got further, so replacing the decimal must have helped. + // Update original_endptr to point at the right location. + if (original_endptr != NULL) { + // size_diff is non-zero if the localized radix has multiple bytes. + int size_diff = localized.size() - strlen(text); + // const_cast is necessary to match the strtod() interface. + *original_endptr = const_cast( + text + (localized_endptr - localized_cstr - size_diff)); + } + } + + return result; +} + +} // namespace protobuf +} // namespace google diff --git a/depends/protobuf/google/protobuf/stubs/strutil.h b/depends/protobuf/google/protobuf/stubs/strutil.h new file mode 100644 index 0000000000..4a79c2240c --- /dev/null +++ b/depends/protobuf/google/protobuf/stubs/strutil.h @@ -0,0 +1,457 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// from google3/strings/strutil.h + +#ifndef GOOGLE_PROTOBUF_STUBS_STRUTIL_H__ +#define GOOGLE_PROTOBUF_STUBS_STRUTIL_H__ + +#include +#include +#include + +namespace google { +namespace protobuf { + +#ifdef _MSC_VER +#define strtoll _strtoi64 +#define strtoull _strtoui64 +#elif defined(__DECCXX) && defined(__osf__) +// HP C++ on Tru64 does not have strtoll, but strtol is already 64-bit. +#define strtoll strtol +#define strtoull strtoul +#endif + +// ---------------------------------------------------------------------- +// ascii_isalnum() +// Check if an ASCII character is alphanumeric. We can't use ctype's +// isalnum() because it is affected by locale. This function is applied +// to identifiers in the protocol buffer language, not to natural-language +// strings, so locale should not be taken into account. +// ascii_isdigit() +// Like above, but only accepts digits. +// ---------------------------------------------------------------------- + +inline bool ascii_isalnum(char c) { + return ('a' <= c && c <= 'z') || + ('A' <= c && c <= 'Z') || + ('0' <= c && c <= '9'); +} + +inline bool ascii_isdigit(char c) { + return ('0' <= c && c <= '9'); +} + +// ---------------------------------------------------------------------- +// HasPrefixString() +// Check if a string begins with a given prefix. +// StripPrefixString() +// Given a string and a putative prefix, returns the string minus the +// prefix string if the prefix matches, otherwise the original +// string. +// ---------------------------------------------------------------------- +inline bool HasPrefixString(const string& str, + const string& prefix) { + return str.size() >= prefix.size() && + str.compare(0, prefix.size(), prefix) == 0; +} + +inline string StripPrefixString(const string& str, const string& prefix) { + if (HasPrefixString(str, prefix)) { + return str.substr(prefix.size()); + } else { + return str; + } +} + +// ---------------------------------------------------------------------- +// HasSuffixString() +// Return true if str ends in suffix. +// StripSuffixString() +// Given a string and a putative suffix, returns the string minus the +// suffix string if the suffix matches, otherwise the original +// string. +// ---------------------------------------------------------------------- +inline bool HasSuffixString(const string& str, + const string& suffix) { + return str.size() >= suffix.size() && + str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0; +} + +inline string StripSuffixString(const string& str, const string& suffix) { + if (HasSuffixString(str, suffix)) { + return str.substr(0, str.size() - suffix.size()); + } else { + return str; + } +} + +// ---------------------------------------------------------------------- +// StripString +// Replaces any occurrence of the character 'remove' (or the characters +// in 'remove') with the character 'replacewith'. +// Good for keeping html characters or protocol characters (\t) out +// of places where they might cause a problem. +// ---------------------------------------------------------------------- +LIBPROTOBUF_EXPORT void StripString(string* s, const char* remove, + char replacewith); + +// ---------------------------------------------------------------------- +// LowerString() +// UpperString() +// Convert the characters in "s" to lowercase or uppercase. ASCII-only: +// these functions intentionally ignore locale because they are applied to +// identifiers used in the Protocol Buffer language, not to natural-language +// strings. +// ---------------------------------------------------------------------- + +inline void LowerString(string * s) { + string::iterator end = s->end(); + for (string::iterator i = s->begin(); i != end; ++i) { + // tolower() changes based on locale. We don't want this! + if ('A' <= *i && *i <= 'Z') *i += 'a' - 'A'; + } +} + +inline void UpperString(string * s) { + string::iterator end = s->end(); + for (string::iterator i = s->begin(); i != end; ++i) { + // toupper() changes based on locale. We don't want this! + if ('a' <= *i && *i <= 'z') *i += 'A' - 'a'; + } +} + +// ---------------------------------------------------------------------- +// StringReplace() +// Give me a string and two patterns "old" and "new", and I replace +// the first instance of "old" in the string with "new", if it +// exists. RETURN a new string, regardless of whether the replacement +// happened or not. +// ---------------------------------------------------------------------- + +LIBPROTOBUF_EXPORT string StringReplace(const string& s, const string& oldsub, + const string& newsub, bool replace_all); + +// ---------------------------------------------------------------------- +// SplitStringUsing() +// Split a string using a character delimiter. Append the components +// to 'result'. If there are consecutive delimiters, this function skips +// over all of them. +// ---------------------------------------------------------------------- +LIBPROTOBUF_EXPORT void SplitStringUsing(const string& full, const char* delim, + vector* res); + +// ---------------------------------------------------------------------- +// JoinStrings() +// These methods concatenate a vector of strings into a C++ string, using +// the C-string "delim" as a separator between components. There are two +// flavors of the function, one flavor returns the concatenated string, +// another takes a pointer to the target string. In the latter case the +// target string is cleared and overwritten. +// ---------------------------------------------------------------------- +LIBPROTOBUF_EXPORT void JoinStrings(const vector& components, + const char* delim, string* result); + +inline string JoinStrings(const vector& components, + const char* delim) { + string result; + JoinStrings(components, delim, &result); + return result; +} + +// ---------------------------------------------------------------------- +// UnescapeCEscapeSequences() +// Copies "source" to "dest", rewriting C-style escape sequences +// -- '\n', '\r', '\\', '\ooo', etc -- to their ASCII +// equivalents. "dest" must be sufficiently large to hold all +// the characters in the rewritten string (i.e. at least as large +// as strlen(source) + 1 should be safe, since the replacements +// are always shorter than the original escaped sequences). It's +// safe for source and dest to be the same. RETURNS the length +// of dest. +// +// It allows hex sequences \xhh, or generally \xhhhhh with an +// arbitrary number of hex digits, but all of them together must +// specify a value of a single byte (e.g. \x0045 is equivalent +// to \x45, and \x1234 is erroneous). +// +// It also allows escape sequences of the form \uhhhh (exactly four +// hex digits, upper or lower case) or \Uhhhhhhhh (exactly eight +// hex digits, upper or lower case) to specify a Unicode code +// point. The dest array will contain the UTF8-encoded version of +// that code-point (e.g., if source contains \u2019, then dest will +// contain the three bytes 0xE2, 0x80, and 0x99). +// +// Errors: In the first form of the call, errors are reported with +// LOG(ERROR). The same is true for the second form of the call if +// the pointer to the string vector is NULL; otherwise, error +// messages are stored in the vector. In either case, the effect on +// the dest array is not defined, but rest of the source will be +// processed. +// ---------------------------------------------------------------------- + +LIBPROTOBUF_EXPORT int UnescapeCEscapeSequences(const char* source, char* dest); +LIBPROTOBUF_EXPORT int UnescapeCEscapeSequences(const char* source, char* dest, + vector *errors); + +// ---------------------------------------------------------------------- +// UnescapeCEscapeString() +// This does the same thing as UnescapeCEscapeSequences, but creates +// a new string. The caller does not need to worry about allocating +// a dest buffer. This should be used for non performance critical +// tasks such as printing debug messages. It is safe for src and dest +// to be the same. +// +// The second call stores its errors in a supplied string vector. +// If the string vector pointer is NULL, it reports the errors with LOG(). +// +// In the first and second calls, the length of dest is returned. In the +// the third call, the new string is returned. +// ---------------------------------------------------------------------- + +LIBPROTOBUF_EXPORT int UnescapeCEscapeString(const string& src, string* dest); +LIBPROTOBUF_EXPORT int UnescapeCEscapeString(const string& src, string* dest, + vector *errors); +LIBPROTOBUF_EXPORT string UnescapeCEscapeString(const string& src); + +// ---------------------------------------------------------------------- +// CEscapeString() +// Copies 'src' to 'dest', escaping dangerous characters using +// C-style escape sequences. This is very useful for preparing query +// flags. 'src' and 'dest' should not overlap. +// Returns the number of bytes written to 'dest' (not including the \0) +// or -1 if there was insufficient space. +// +// Currently only \n, \r, \t, ", ', \ and !isprint() chars are escaped. +// ---------------------------------------------------------------------- +LIBPROTOBUF_EXPORT int CEscapeString(const char* src, int src_len, + char* dest, int dest_len); + +// ---------------------------------------------------------------------- +// CEscape() +// More convenient form of CEscapeString: returns result as a "string". +// This version is slower than CEscapeString() because it does more +// allocation. However, it is much more convenient to use in +// non-speed-critical code like logging messages etc. +// ---------------------------------------------------------------------- +LIBPROTOBUF_EXPORT string CEscape(const string& src); + +namespace strings { +// Like CEscape() but does not escape bytes with the upper bit set. +LIBPROTOBUF_EXPORT string Utf8SafeCEscape(const string& src); + +// Like CEscape() but uses hex (\x) escapes instead of octals. +LIBPROTOBUF_EXPORT string CHexEscape(const string& src); +} // namespace strings + +// ---------------------------------------------------------------------- +// strto32() +// strtou32() +// strto64() +// strtou64() +// Architecture-neutral plug compatible replacements for strtol() and +// strtoul(). Long's have different lengths on ILP-32 and LP-64 +// platforms, so using these is safer, from the point of view of +// overflow behavior, than using the standard libc functions. +// ---------------------------------------------------------------------- +LIBPROTOBUF_EXPORT int32 strto32_adaptor(const char *nptr, char **endptr, + int base); +LIBPROTOBUF_EXPORT uint32 strtou32_adaptor(const char *nptr, char **endptr, + int base); + +inline int32 strto32(const char *nptr, char **endptr, int base) { + if (sizeof(int32) == sizeof(long)) + return strtol(nptr, endptr, base); + else + return strto32_adaptor(nptr, endptr, base); +} + +inline uint32 strtou32(const char *nptr, char **endptr, int base) { + if (sizeof(uint32) == sizeof(unsigned long)) + return strtoul(nptr, endptr, base); + else + return strtou32_adaptor(nptr, endptr, base); +} + +// For now, long long is 64-bit on all the platforms we care about, so these +// functions can simply pass the call to strto[u]ll. +inline int64 strto64(const char *nptr, char **endptr, int base) { + GOOGLE_COMPILE_ASSERT(sizeof(int64) == sizeof(long long), + sizeof_int64_is_not_sizeof_long_long); + return strtoll(nptr, endptr, base); +} + +inline uint64 strtou64(const char *nptr, char **endptr, int base) { + GOOGLE_COMPILE_ASSERT(sizeof(uint64) == sizeof(unsigned long long), + sizeof_uint64_is_not_sizeof_long_long); + return strtoull(nptr, endptr, base); +} + +// ---------------------------------------------------------------------- +// FastIntToBuffer() +// FastHexToBuffer() +// FastHex64ToBuffer() +// FastHex32ToBuffer() +// FastTimeToBuffer() +// These are intended for speed. FastIntToBuffer() assumes the +// integer is non-negative. FastHexToBuffer() puts output in +// hex rather than decimal. FastTimeToBuffer() puts the output +// into RFC822 format. +// +// FastHex64ToBuffer() puts a 64-bit unsigned value in hex-format, +// padded to exactly 16 bytes (plus one byte for '\0') +// +// FastHex32ToBuffer() puts a 32-bit unsigned value in hex-format, +// padded to exactly 8 bytes (plus one byte for '\0') +// +// All functions take the output buffer as an arg. +// They all return a pointer to the beginning of the output, +// which may not be the beginning of the input buffer. +// ---------------------------------------------------------------------- + +// Suggested buffer size for FastToBuffer functions. Also works with +// DoubleToBuffer() and FloatToBuffer(). +static const int kFastToBufferSize = 32; + +LIBPROTOBUF_EXPORT char* FastInt32ToBuffer(int32 i, char* buffer); +LIBPROTOBUF_EXPORT char* FastInt64ToBuffer(int64 i, char* buffer); +char* FastUInt32ToBuffer(uint32 i, char* buffer); // inline below +char* FastUInt64ToBuffer(uint64 i, char* buffer); // inline below +LIBPROTOBUF_EXPORT char* FastHexToBuffer(int i, char* buffer); +LIBPROTOBUF_EXPORT char* FastHex64ToBuffer(uint64 i, char* buffer); +LIBPROTOBUF_EXPORT char* FastHex32ToBuffer(uint32 i, char* buffer); + +// at least 22 bytes long +inline char* FastIntToBuffer(int i, char* buffer) { + return (sizeof(i) == 4 ? + FastInt32ToBuffer(i, buffer) : FastInt64ToBuffer(i, buffer)); +} +inline char* FastUIntToBuffer(unsigned int i, char* buffer) { + return (sizeof(i) == 4 ? + FastUInt32ToBuffer(i, buffer) : FastUInt64ToBuffer(i, buffer)); +} +inline char* FastLongToBuffer(long i, char* buffer) { + return (sizeof(i) == 4 ? + FastInt32ToBuffer(i, buffer) : FastInt64ToBuffer(i, buffer)); +} +inline char* FastULongToBuffer(unsigned long i, char* buffer) { + return (sizeof(i) == 4 ? + FastUInt32ToBuffer(i, buffer) : FastUInt64ToBuffer(i, buffer)); +} + +// ---------------------------------------------------------------------- +// FastInt32ToBufferLeft() +// FastUInt32ToBufferLeft() +// FastInt64ToBufferLeft() +// FastUInt64ToBufferLeft() +// +// Like the Fast*ToBuffer() functions above, these are intended for speed. +// Unlike the Fast*ToBuffer() functions, however, these functions write +// their output to the beginning of the buffer (hence the name, as the +// output is left-aligned). The caller is responsible for ensuring that +// the buffer has enough space to hold the output. +// +// Returns a pointer to the end of the string (i.e. the null character +// terminating the string). +// ---------------------------------------------------------------------- + +LIBPROTOBUF_EXPORT char* FastInt32ToBufferLeft(int32 i, char* buffer); +LIBPROTOBUF_EXPORT char* FastUInt32ToBufferLeft(uint32 i, char* buffer); +LIBPROTOBUF_EXPORT char* FastInt64ToBufferLeft(int64 i, char* buffer); +LIBPROTOBUF_EXPORT char* FastUInt64ToBufferLeft(uint64 i, char* buffer); + +// Just define these in terms of the above. +inline char* FastUInt32ToBuffer(uint32 i, char* buffer) { + FastUInt32ToBufferLeft(i, buffer); + return buffer; +} +inline char* FastUInt64ToBuffer(uint64 i, char* buffer) { + FastUInt64ToBufferLeft(i, buffer); + return buffer; +} + +// ---------------------------------------------------------------------- +// SimpleItoa() +// Description: converts an integer to a string. +// +// Return value: string +// ---------------------------------------------------------------------- +LIBPROTOBUF_EXPORT string SimpleItoa(int i); +LIBPROTOBUF_EXPORT string SimpleItoa(unsigned int i); +LIBPROTOBUF_EXPORT string SimpleItoa(long i); +LIBPROTOBUF_EXPORT string SimpleItoa(unsigned long i); +LIBPROTOBUF_EXPORT string SimpleItoa(long long i); +LIBPROTOBUF_EXPORT string SimpleItoa(unsigned long long i); + +// ---------------------------------------------------------------------- +// SimpleDtoa() +// SimpleFtoa() +// DoubleToBuffer() +// FloatToBuffer() +// Description: converts a double or float to a string which, if +// passed to NoLocaleStrtod(), will produce the exact same original double +// (except in case of NaN; all NaNs are considered the same value). +// We try to keep the string short but it's not guaranteed to be as +// short as possible. +// +// DoubleToBuffer() and FloatToBuffer() write the text to the given +// buffer and return it. The buffer must be at least +// kDoubleToBufferSize bytes for doubles and kFloatToBufferSize +// bytes for floats. kFastToBufferSize is also guaranteed to be large +// enough to hold either. +// +// Return value: string +// ---------------------------------------------------------------------- +LIBPROTOBUF_EXPORT string SimpleDtoa(double value); +LIBPROTOBUF_EXPORT string SimpleFtoa(float value); + +LIBPROTOBUF_EXPORT char* DoubleToBuffer(double i, char* buffer); +LIBPROTOBUF_EXPORT char* FloatToBuffer(float i, char* buffer); + +// In practice, doubles should never need more than 24 bytes and floats +// should never need more than 14 (including null terminators), but we +// overestimate to be safe. +static const int kDoubleToBufferSize = 32; +static const int kFloatToBufferSize = 24; + +// ---------------------------------------------------------------------- +// NoLocaleStrtod() +// Exactly like strtod(), except it always behaves as if in the "C" +// locale (i.e. decimal points must be '.'s). +// ---------------------------------------------------------------------- + +LIBPROTOBUF_EXPORT double NoLocaleStrtod(const char* text, char** endptr); + +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_STUBS_STRUTIL_H__ + + diff --git a/depends/protobuf/google/protobuf/stubs/substitute.cc b/depends/protobuf/google/protobuf/stubs/substitute.cc new file mode 100644 index 0000000000..b542aaa41e --- /dev/null +++ b/depends/protobuf/google/protobuf/stubs/substitute.cc @@ -0,0 +1,134 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) + +#include +#include +#include + +namespace google { +namespace protobuf { +namespace strings { + +using internal::SubstituteArg; + +// Returns the number of args in arg_array which were passed explicitly +// to Substitute(). +static int CountSubstituteArgs(const SubstituteArg* const* args_array) { + int count = 0; + while (args_array[count] != NULL && args_array[count]->size() != -1) { + ++count; + } + return count; +} + +string Substitute( + const char* format, + const SubstituteArg& arg0, const SubstituteArg& arg1, + const SubstituteArg& arg2, const SubstituteArg& arg3, + const SubstituteArg& arg4, const SubstituteArg& arg5, + const SubstituteArg& arg6, const SubstituteArg& arg7, + const SubstituteArg& arg8, const SubstituteArg& arg9) { + string result; + SubstituteAndAppend(&result, format, arg0, arg1, arg2, arg3, arg4, + arg5, arg6, arg7, arg8, arg9); + return result; +} + +void SubstituteAndAppend( + string* output, const char* format, + const SubstituteArg& arg0, const SubstituteArg& arg1, + const SubstituteArg& arg2, const SubstituteArg& arg3, + const SubstituteArg& arg4, const SubstituteArg& arg5, + const SubstituteArg& arg6, const SubstituteArg& arg7, + const SubstituteArg& arg8, const SubstituteArg& arg9) { + const SubstituteArg* const args_array[] = { + &arg0, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6, &arg7, &arg8, &arg9, NULL + }; + + // Determine total size needed. + int size = 0; + for (int i = 0; format[i] != '\0'; i++) { + if (format[i] == '$') { + if (ascii_isdigit(format[i+1])) { + int index = format[i+1] - '0'; + if (args_array[index]->size() == -1) { + GOOGLE_LOG(DFATAL) + << "strings::Substitute format string invalid: asked for \"$" + << index << "\", but only " << CountSubstituteArgs(args_array) + << " args were given. Full format string was: \"" + << CEscape(format) << "\"."; + return; + } + size += args_array[index]->size(); + ++i; // Skip next char. + } else if (format[i+1] == '$') { + ++size; + ++i; // Skip next char. + } else { + GOOGLE_LOG(DFATAL) + << "Invalid strings::Substitute() format string: \"" + << CEscape(format) << "\"."; + return; + } + } else { + ++size; + } + } + + if (size == 0) return; + + // Build the string. + int original_size = output->size(); + STLStringResizeUninitialized(output, original_size + size); + char* target = string_as_array(output) + original_size; + for (int i = 0; format[i] != '\0'; i++) { + if (format[i] == '$') { + if (ascii_isdigit(format[i+1])) { + const SubstituteArg* src = args_array[format[i+1] - '0']; + memcpy(target, src->data(), src->size()); + target += src->size(); + ++i; // Skip next char. + } else if (format[i+1] == '$') { + *target++ = '$'; + ++i; // Skip next char. + } + } else { + *target++ = format[i]; + } + } + + GOOGLE_DCHECK_EQ(target - output->data(), output->size()); +} + +} // namespace strings +} // namespace protobuf +} // namespace google diff --git a/depends/protobuf/google/protobuf/stubs/substitute.h b/depends/protobuf/google/protobuf/stubs/substitute.h new file mode 100644 index 0000000000..2581793b57 --- /dev/null +++ b/depends/protobuf/google/protobuf/stubs/substitute.h @@ -0,0 +1,170 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// from google3/strings/substitute.h + +#include +#include +#include + +#ifndef GOOGLE_PROTOBUF_STUBS_SUBSTITUTE_H_ +#define GOOGLE_PROTOBUF_STUBS_SUBSTITUTE_H_ + +namespace google { +namespace protobuf { +namespace strings { + +// ---------------------------------------------------------------------- +// strings::Substitute() +// strings::SubstituteAndAppend() +// Kind of like StringPrintf, but different. +// +// Example: +// string GetMessage(string first_name, string last_name, int age) { +// return strings::Substitute("My name is $0 $1 and I am $2 years old.", +// first_name, last_name, age); +// } +// +// Differences from StringPrintf: +// * The format string does not identify the types of arguments. +// Instead, the magic of C++ deals with this for us. See below +// for a list of accepted types. +// * Substitutions in the format string are identified by a '$' +// followed by a digit. So, you can use arguments out-of-order and +// use the same argument multiple times. +// * It's much faster than StringPrintf. +// +// Supported types: +// * Strings (const char*, const string&) +// * Note that this means you do not have to add .c_str() to all of +// your strings. In fact, you shouldn't; it will be slower. +// * int32, int64, uint32, uint64: Formatted using SimpleItoa(). +// * float, double: Formatted using SimpleFtoa() and SimpleDtoa(). +// * bool: Printed as "true" or "false". +// +// SubstituteAndAppend() is like Substitute() but appends the result to +// *output. Example: +// +// string str; +// strings::SubstituteAndAppend(&str, +// "My name is $0 $1 and I am $2 years old.", +// first_name, last_name, age); +// +// Substitute() is significantly faster than StringPrintf(). For very +// large strings, it may be orders of magnitude faster. +// ---------------------------------------------------------------------- + +namespace internal { // Implementation details. + +class SubstituteArg { + public: + inline SubstituteArg(const char* value) + : text_(value), size_(strlen(text_)) {} + inline SubstituteArg(const string& value) + : text_(value.data()), size_(value.size()) {} + + // Indicates that no argument was given. + inline explicit SubstituteArg() + : text_(NULL), size_(-1) {} + + // Primitives + // We don't overload for signed and unsigned char because if people are + // explicitly declaring their chars as signed or unsigned then they are + // probably actually using them as 8-bit integers and would probably + // prefer an integer representation. But, we don't really know. So, we + // make the caller decide what to do. + inline SubstituteArg(char value) + : text_(scratch_), size_(1) { scratch_[0] = value; } + inline SubstituteArg(short value) + : text_(FastInt32ToBuffer(value, scratch_)), size_(strlen(text_)) {} + inline SubstituteArg(unsigned short value) + : text_(FastUInt32ToBuffer(value, scratch_)), size_(strlen(text_)) {} + inline SubstituteArg(int value) + : text_(FastInt32ToBuffer(value, scratch_)), size_(strlen(text_)) {} + inline SubstituteArg(unsigned int value) + : text_(FastUInt32ToBuffer(value, scratch_)), size_(strlen(text_)) {} + inline SubstituteArg(long value) + : text_(FastLongToBuffer(value, scratch_)), size_(strlen(text_)) {} + inline SubstituteArg(unsigned long value) + : text_(FastULongToBuffer(value, scratch_)), size_(strlen(text_)) {} + inline SubstituteArg(long long value) + : text_(FastInt64ToBuffer(value, scratch_)), size_(strlen(text_)) {} + inline SubstituteArg(unsigned long long value) + : text_(FastUInt64ToBuffer(value, scratch_)), size_(strlen(text_)) {} + inline SubstituteArg(float value) + : text_(FloatToBuffer(value, scratch_)), size_(strlen(text_)) {} + inline SubstituteArg(double value) + : text_(DoubleToBuffer(value, scratch_)), size_(strlen(text_)) {} + inline SubstituteArg(bool value) + : text_(value ? "true" : "false"), size_(strlen(text_)) {} + + inline const char* data() const { return text_; } + inline int size() const { return size_; } + + private: + const char* text_; + int size_; + char scratch_[kFastToBufferSize]; +}; + +} // namespace internal + +LIBPROTOBUF_EXPORT string Substitute( + const char* format, + const internal::SubstituteArg& arg0 = internal::SubstituteArg(), + const internal::SubstituteArg& arg1 = internal::SubstituteArg(), + const internal::SubstituteArg& arg2 = internal::SubstituteArg(), + const internal::SubstituteArg& arg3 = internal::SubstituteArg(), + const internal::SubstituteArg& arg4 = internal::SubstituteArg(), + const internal::SubstituteArg& arg5 = internal::SubstituteArg(), + const internal::SubstituteArg& arg6 = internal::SubstituteArg(), + const internal::SubstituteArg& arg7 = internal::SubstituteArg(), + const internal::SubstituteArg& arg8 = internal::SubstituteArg(), + const internal::SubstituteArg& arg9 = internal::SubstituteArg()); + +LIBPROTOBUF_EXPORT void SubstituteAndAppend( + string* output, const char* format, + const internal::SubstituteArg& arg0 = internal::SubstituteArg(), + const internal::SubstituteArg& arg1 = internal::SubstituteArg(), + const internal::SubstituteArg& arg2 = internal::SubstituteArg(), + const internal::SubstituteArg& arg3 = internal::SubstituteArg(), + const internal::SubstituteArg& arg4 = internal::SubstituteArg(), + const internal::SubstituteArg& arg5 = internal::SubstituteArg(), + const internal::SubstituteArg& arg6 = internal::SubstituteArg(), + const internal::SubstituteArg& arg7 = internal::SubstituteArg(), + const internal::SubstituteArg& arg8 = internal::SubstituteArg(), + const internal::SubstituteArg& arg9 = internal::SubstituteArg()); + +} // namespace strings +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_STUBS_SUBSTITUTE_H_ diff --git a/depends/protobuf/google/protobuf/text_format.cc b/depends/protobuf/google/protobuf/text_format.cc new file mode 100644 index 0000000000..1494ebd78d --- /dev/null +++ b/depends/protobuf/google/protobuf/text_format.cc @@ -0,0 +1,1285 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: jschorr@google.com (Joseph Schorr) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { + +string Message::DebugString() const { + string debug_string; + + TextFormat::PrintToString(*this, &debug_string); + + return debug_string; +} + +string Message::ShortDebugString() const { + string debug_string; + + TextFormat::Printer printer; + printer.SetSingleLineMode(true); + + printer.PrintToString(*this, &debug_string); + // Single line mode currently might have an extra space at the end. + if (debug_string.size() > 0 && + debug_string[debug_string.size() - 1] == ' ') { + debug_string.resize(debug_string.size() - 1); + } + + return debug_string; +} + +string Message::Utf8DebugString() const { + string debug_string; + + TextFormat::Printer printer; + printer.SetUseUtf8StringEscaping(true); + + printer.PrintToString(*this, &debug_string); + + return debug_string; +} + +void Message::PrintDebugString() const { + printf("%s", DebugString().c_str()); +} + + +// =========================================================================== +// Internal class for parsing an ASCII representation of a Protocol Message. +// This class makes use of the Protocol Message compiler's tokenizer found +// in //google/protobuf/io/tokenizer.h. Note that class's Parse +// method is *not* thread-safe and should only be used in a single thread at +// a time. + +// Makes code slightly more readable. The meaning of "DO(foo)" is +// "Execute foo and fail if it fails.", where failure is indicated by +// returning false. Borrowed from parser.cc (Thanks Kenton!). +#define DO(STATEMENT) if (STATEMENT) {} else return false + +class TextFormat::Parser::ParserImpl { + public: + + // Determines if repeated values for a non-repeated field are + // permitted, e.g., the string "foo: 1 foo: 2" for a + // required/optional field named "foo". + enum SingularOverwritePolicy { + ALLOW_SINGULAR_OVERWRITES = 0, // the last value is retained + FORBID_SINGULAR_OVERWRITES = 1, // an error is issued + }; + + ParserImpl(const Descriptor* root_message_type, + io::ZeroCopyInputStream* input_stream, + io::ErrorCollector* error_collector, + TextFormat::Finder* finder, + SingularOverwritePolicy singular_overwrite_policy) + : error_collector_(error_collector), + finder_(finder), + tokenizer_error_collector_(this), + tokenizer_(input_stream, &tokenizer_error_collector_), + root_message_type_(root_message_type), + singular_overwrite_policy_(singular_overwrite_policy), + had_errors_(false) { + // For backwards-compatibility with proto1, we need to allow the 'f' suffix + // for floats. + tokenizer_.set_allow_f_after_float(true); + + // '#' starts a comment. + tokenizer_.set_comment_style(io::Tokenizer::SH_COMMENT_STYLE); + + // Consume the starting token. + tokenizer_.Next(); + } + ~ParserImpl() { } + + // Parses the ASCII representation specified in input and saves the + // information into the output pointer (a Message). Returns + // false if an error occurs (an error will also be logged to + // GOOGLE_LOG(ERROR)). + bool Parse(Message* output) { + // Consume fields until we cannot do so anymore. + while(true) { + if (LookingAtType(io::Tokenizer::TYPE_END)) { + return !had_errors_; + } + + DO(ConsumeField(output)); + } + } + + bool ParseField(const FieldDescriptor* field, Message* output) { + bool suc; + if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + suc = ConsumeFieldMessage(output, output->GetReflection(), field); + } else { + suc = ConsumeFieldValue(output, output->GetReflection(), field); + } + return suc && LookingAtType(io::Tokenizer::TYPE_END); + } + + void ReportError(int line, int col, const string& message) { + had_errors_ = true; + if (error_collector_ == NULL) { + if (line >= 0) { + GOOGLE_LOG(ERROR) << "Error parsing text-format " + << root_message_type_->full_name() + << ": " << (line + 1) << ":" + << (col + 1) << ": " << message; + } else { + GOOGLE_LOG(ERROR) << "Error parsing text-format " + << root_message_type_->full_name() + << ": " << message; + } + } else { + error_collector_->AddError(line, col, message); + } + } + + void ReportWarning(int line, int col, const string& message) { + if (error_collector_ == NULL) { + if (line >= 0) { + GOOGLE_LOG(WARNING) << "Warning parsing text-format " + << root_message_type_->full_name() + << ": " << (line + 1) << ":" + << (col + 1) << ": " << message; + } else { + GOOGLE_LOG(WARNING) << "Warning parsing text-format " + << root_message_type_->full_name() + << ": " << message; + } + } else { + error_collector_->AddWarning(line, col, message); + } + } + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ParserImpl); + + // Reports an error with the given message with information indicating + // the position (as derived from the current token). + void ReportError(const string& message) { + ReportError(tokenizer_.current().line, tokenizer_.current().column, + message); + } + + // Reports a warning with the given message with information indicating + // the position (as derived from the current token). + void ReportWarning(const string& message) { + ReportWarning(tokenizer_.current().line, tokenizer_.current().column, + message); + } + + // Consumes the specified message with the given starting delimeter. + // This method checks to see that the end delimeter at the conclusion of + // the consumption matches the starting delimeter passed in here. + bool ConsumeMessage(Message* message, const string delimeter) { + while (!LookingAt(">") && !LookingAt("}")) { + DO(ConsumeField(message)); + } + + // Confirm that we have a valid ending delimeter. + DO(Consume(delimeter)); + + return true; + } + + // Consumes the current field (as returned by the tokenizer) on the + // passed in message. + bool ConsumeField(Message* message) { + const Reflection* reflection = message->GetReflection(); + const Descriptor* descriptor = message->GetDescriptor(); + + string field_name; + + const FieldDescriptor* field = NULL; + + if (TryConsume("[")) { + // Extension. + DO(ConsumeIdentifier(&field_name)); + while (TryConsume(".")) { + string part; + DO(ConsumeIdentifier(&part)); + field_name += "."; + field_name += part; + } + DO(Consume("]")); + + field = (finder_ != NULL + ? finder_->FindExtension(message, field_name) + : reflection->FindKnownExtensionByName(field_name)); + + if (field == NULL) { + ReportError("Extension \"" + field_name + "\" is not defined or " + "is not an extension of \"" + + descriptor->full_name() + "\"."); + return false; + } + } else { + DO(ConsumeIdentifier(&field_name)); + + field = descriptor->FindFieldByName(field_name); + // Group names are expected to be capitalized as they appear in the + // .proto file, which actually matches their type names, not their field + // names. + if (field == NULL) { + string lower_field_name = field_name; + LowerString(&lower_field_name); + field = descriptor->FindFieldByName(lower_field_name); + // If the case-insensitive match worked but the field is NOT a group, + if (field != NULL && field->type() != FieldDescriptor::TYPE_GROUP) { + field = NULL; + } + } + // Again, special-case group names as described above. + if (field != NULL && field->type() == FieldDescriptor::TYPE_GROUP + && field->message_type()->name() != field_name) { + field = NULL; + } + + if (field == NULL) { + ReportError("Message type \"" + descriptor->full_name() + + "\" has no field named \"" + field_name + "\"."); + return false; + } + } + + // Fail if the field is not repeated and it has already been specified. + if ((singular_overwrite_policy_ == FORBID_SINGULAR_OVERWRITES) && + !field->is_repeated() && reflection->HasField(*message, field)) { + ReportError("Non-repeated field \"" + field_name + + "\" is specified multiple times."); + return false; + } + + // Perform special handling for embedded message types. + if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + // ':' is optional here. + TryConsume(":"); + DO(ConsumeFieldMessage(message, reflection, field)); + } else { + DO(Consume(":")); + if (field->is_repeated() && TryConsume("[")) { + // Short repeated format, e.g. "foo: [1, 2, 3]" + while (true) { + DO(ConsumeFieldValue(message, reflection, field)); + if (TryConsume("]")) { + break; + } + DO(Consume(",")); + } + } else { + DO(ConsumeFieldValue(message, reflection, field)); + } + } + + // For historical reasons, fields may optionally be separated by commas or + // semicolons. + TryConsume(";") || TryConsume(","); + + if (field->options().deprecated()) { + ReportWarning("text format contains deprecated field \"" + + field_name + "\""); + } + + return true; + } + + bool ConsumeFieldMessage(Message* message, + const Reflection* reflection, + const FieldDescriptor* field) { + string delimeter; + if (TryConsume("<")) { + delimeter = ">"; + } else { + DO(Consume("{")); + delimeter = "}"; + } + + if (field->is_repeated()) { + DO(ConsumeMessage(reflection->AddMessage(message, field), delimeter)); + } else { + DO(ConsumeMessage(reflection->MutableMessage(message, field), + delimeter)); + } + return true; + } + + bool ConsumeFieldValue(Message* message, + const Reflection* reflection, + const FieldDescriptor* field) { + +// Define an easy to use macro for setting fields. This macro checks +// to see if the field is repeated (in which case we need to use the Add +// methods or not (in which case we need to use the Set methods). +#define SET_FIELD(CPPTYPE, VALUE) \ + if (field->is_repeated()) { \ + reflection->Add##CPPTYPE(message, field, VALUE); \ + } else { \ + reflection->Set##CPPTYPE(message, field, VALUE); \ + } \ + + switch(field->cpp_type()) { + case FieldDescriptor::CPPTYPE_INT32: { + int64 value; + DO(ConsumeSignedInteger(&value, kint32max)); + SET_FIELD(Int32, static_cast(value)); + break; + } + + case FieldDescriptor::CPPTYPE_UINT32: { + uint64 value; + DO(ConsumeUnsignedInteger(&value, kuint32max)); + SET_FIELD(UInt32, static_cast(value)); + break; + } + + case FieldDescriptor::CPPTYPE_INT64: { + int64 value; + DO(ConsumeSignedInteger(&value, kint64max)); + SET_FIELD(Int64, value); + break; + } + + case FieldDescriptor::CPPTYPE_UINT64: { + uint64 value; + DO(ConsumeUnsignedInteger(&value, kuint64max)); + SET_FIELD(UInt64, value); + break; + } + + case FieldDescriptor::CPPTYPE_FLOAT: { + double value; + DO(ConsumeDouble(&value)); + SET_FIELD(Float, static_cast(value)); + break; + } + + case FieldDescriptor::CPPTYPE_DOUBLE: { + double value; + DO(ConsumeDouble(&value)); + SET_FIELD(Double, value); + break; + } + + case FieldDescriptor::CPPTYPE_STRING: { + string value; + DO(ConsumeString(&value)); + SET_FIELD(String, value); + break; + } + + case FieldDescriptor::CPPTYPE_BOOL: { + if (LookingAtType(io::Tokenizer::TYPE_INTEGER)) { + uint64 value; + DO(ConsumeUnsignedInteger(&value, 1)); + SET_FIELD(Bool, value); + } else { + string value; + DO(ConsumeIdentifier(&value)); + if (value == "true" || value == "t") { + SET_FIELD(Bool, true); + } else if (value == "false" || value == "f") { + SET_FIELD(Bool, false); + } else { + ReportError("Invalid value for boolean field \"" + field->name() + + "\". Value: \"" + value + "\"."); + return false; + } + } + break; + } + + case FieldDescriptor::CPPTYPE_ENUM: { + string value; + const EnumDescriptor* enum_type = field->enum_type(); + const EnumValueDescriptor* enum_value = NULL; + + if (LookingAtType(io::Tokenizer::TYPE_IDENTIFIER)) { + DO(ConsumeIdentifier(&value)); + // Find the enumeration value. + enum_value = enum_type->FindValueByName(value); + + } else if (LookingAt("-") || + LookingAtType(io::Tokenizer::TYPE_INTEGER)) { + int64 int_value; + DO(ConsumeSignedInteger(&int_value, kint32max)); + value = SimpleItoa(int_value); // for error reporting + enum_value = enum_type->FindValueByNumber(int_value); + } else { + ReportError("Expected integer or identifier."); + return false; + } + + if (enum_value == NULL) { + ReportError("Unknown enumeration value of \"" + value + "\" for " + "field \"" + field->name() + "\"."); + return false; + } + + SET_FIELD(Enum, enum_value); + break; + } + + case FieldDescriptor::CPPTYPE_MESSAGE: { + // We should never get here. Put here instead of a default + // so that if new types are added, we get a nice compiler warning. + GOOGLE_LOG(FATAL) << "Reached an unintended state: CPPTYPE_MESSAGE"; + break; + } + } +#undef SET_FIELD + return true; + } + + // Returns true if the current token's text is equal to that specified. + bool LookingAt(const string& text) { + return tokenizer_.current().text == text; + } + + // Returns true if the current token's type is equal to that specified. + bool LookingAtType(io::Tokenizer::TokenType token_type) { + return tokenizer_.current().type == token_type; + } + + // Consumes an identifier and saves its value in the identifier parameter. + // Returns false if the token is not of type IDENTFIER. + bool ConsumeIdentifier(string* identifier) { + if (!LookingAtType(io::Tokenizer::TYPE_IDENTIFIER)) { + ReportError("Expected identifier."); + return false; + } + + *identifier = tokenizer_.current().text; + + tokenizer_.Next(); + return true; + } + + // Consumes a string and saves its value in the text parameter. + // Returns false if the token is not of type STRING. + bool ConsumeString(string* text) { + if (!LookingAtType(io::Tokenizer::TYPE_STRING)) { + ReportError("Expected string."); + return false; + } + + text->clear(); + while (LookingAtType(io::Tokenizer::TYPE_STRING)) { + io::Tokenizer::ParseStringAppend(tokenizer_.current().text, text); + + tokenizer_.Next(); + } + + return true; + } + + // Consumes a uint64 and saves its value in the value parameter. + // Returns false if the token is not of type INTEGER. + bool ConsumeUnsignedInteger(uint64* value, uint64 max_value) { + if (!LookingAtType(io::Tokenizer::TYPE_INTEGER)) { + ReportError("Expected integer."); + return false; + } + + if (!io::Tokenizer::ParseInteger(tokenizer_.current().text, + max_value, value)) { + ReportError("Integer out of range."); + return false; + } + + tokenizer_.Next(); + return true; + } + + // Consumes an int64 and saves its value in the value parameter. + // Note that since the tokenizer does not support negative numbers, + // we actually may consume an additional token (for the minus sign) in this + // method. Returns false if the token is not an integer + // (signed or otherwise). + bool ConsumeSignedInteger(int64* value, uint64 max_value) { + bool negative = false; + + if (TryConsume("-")) { + negative = true; + // Two's complement always allows one more negative integer than + // positive. + ++max_value; + } + + uint64 unsigned_value; + + DO(ConsumeUnsignedInteger(&unsigned_value, max_value)); + + *value = static_cast(unsigned_value); + + if (negative) { + *value = -*value; + } + + return true; + } + + // Consumes a double and saves its value in the value parameter. + // Note that since the tokenizer does not support negative numbers, + // we actually may consume an additional token (for the minus sign) in this + // method. Returns false if the token is not a double + // (signed or otherwise). + bool ConsumeDouble(double* value) { + bool negative = false; + + if (TryConsume("-")) { + negative = true; + } + + // A double can actually be an integer, according to the tokenizer. + // Therefore, we must check both cases here. + if (LookingAtType(io::Tokenizer::TYPE_INTEGER)) { + // We have found an integer value for the double. + uint64 integer_value; + DO(ConsumeUnsignedInteger(&integer_value, kuint64max)); + + *value = static_cast(integer_value); + } else if (LookingAtType(io::Tokenizer::TYPE_FLOAT)) { + // We have found a float value for the double. + *value = io::Tokenizer::ParseFloat(tokenizer_.current().text); + + // Mark the current token as consumed. + tokenizer_.Next(); + } else if (LookingAtType(io::Tokenizer::TYPE_IDENTIFIER)) { + string text = tokenizer_.current().text; + LowerString(&text); + if (text == "inf" || text == "infinity") { + *value = std::numeric_limits::infinity(); + tokenizer_.Next(); + } else if (text == "nan") { + *value = std::numeric_limits::quiet_NaN(); + tokenizer_.Next(); + } else { + ReportError("Expected double."); + return false; + } + } else { + ReportError("Expected double."); + return false; + } + + if (negative) { + *value = -*value; + } + + return true; + } + + // Consumes a token and confirms that it matches that specified in the + // value parameter. Returns false if the token found does not match that + // which was specified. + bool Consume(const string& value) { + const string& current_value = tokenizer_.current().text; + + if (current_value != value) { + ReportError("Expected \"" + value + "\", found \"" + current_value + + "\"."); + return false; + } + + tokenizer_.Next(); + + return true; + } + + // Attempts to consume the supplied value. Returns false if a the + // token found does not match the value specified. + bool TryConsume(const string& value) { + if (tokenizer_.current().text == value) { + tokenizer_.Next(); + return true; + } else { + return false; + } + } + + // An internal instance of the Tokenizer's error collector, used to + // collect any base-level parse errors and feed them to the ParserImpl. + class ParserErrorCollector : public io::ErrorCollector { + public: + explicit ParserErrorCollector(TextFormat::Parser::ParserImpl* parser) : + parser_(parser) { } + + virtual ~ParserErrorCollector() { }; + + virtual void AddError(int line, int column, const string& message) { + parser_->ReportError(line, column, message); + } + + virtual void AddWarning(int line, int column, const string& message) { + parser_->ReportWarning(line, column, message); + } + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ParserErrorCollector); + TextFormat::Parser::ParserImpl* parser_; + }; + + io::ErrorCollector* error_collector_; + TextFormat::Finder* finder_; + ParserErrorCollector tokenizer_error_collector_; + io::Tokenizer tokenizer_; + const Descriptor* root_message_type_; + SingularOverwritePolicy singular_overwrite_policy_; + bool had_errors_; +}; + +#undef DO + +// =========================================================================== +// Internal class for writing text to the io::ZeroCopyOutputStream. Adapted +// from the Printer found in //google/protobuf/io/printer.h +class TextFormat::Printer::TextGenerator { + public: + explicit TextGenerator(io::ZeroCopyOutputStream* output, + int initial_indent_level) + : output_(output), + buffer_(NULL), + buffer_size_(0), + at_start_of_line_(true), + failed_(false), + indent_(""), + initial_indent_level_(initial_indent_level) { + indent_.resize(initial_indent_level_ * 2, ' '); + } + + ~TextGenerator() { + // Only BackUp() if we're sure we've successfully called Next() at least + // once. + if (buffer_size_ > 0) { + output_->BackUp(buffer_size_); + } + } + + // Indent text by two spaces. After calling Indent(), two spaces will be + // inserted at the beginning of each line of text. Indent() may be called + // multiple times to produce deeper indents. + void Indent() { + indent_ += " "; + } + + // Reduces the current indent level by two spaces, or crashes if the indent + // level is zero. + void Outdent() { + if (indent_.empty() || + indent_.size() < initial_indent_level_ * 2) { + GOOGLE_LOG(DFATAL) << " Outdent() without matching Indent()."; + return; + } + + indent_.resize(indent_.size() - 2); + } + + // Print text to the output stream. + void Print(const string& str) { + Print(str.data(), str.size()); + } + + // Print text to the output stream. + void Print(const char* text) { + Print(text, strlen(text)); + } + + // Print text to the output stream. + void Print(const char* text, int size) { + int pos = 0; // The number of bytes we've written so far. + + for (int i = 0; i < size; i++) { + if (text[i] == '\n') { + // Saw newline. If there is more text, we may need to insert an indent + // here. So, write what we have so far, including the '\n'. + Write(text + pos, i - pos + 1); + pos = i + 1; + + // Setting this true will cause the next Write() to insert an indent + // first. + at_start_of_line_ = true; + } + } + + // Write the rest. + Write(text + pos, size - pos); + } + + // True if any write to the underlying stream failed. (We don't just + // crash in this case because this is an I/O failure, not a programming + // error.) + bool failed() const { return failed_; } + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(TextGenerator); + + void Write(const char* data, int size) { + if (failed_) return; + if (size == 0) return; + + if (at_start_of_line_) { + // Insert an indent. + at_start_of_line_ = false; + Write(indent_.data(), indent_.size()); + if (failed_) return; + } + + while (size > buffer_size_) { + // Data exceeds space in the buffer. Copy what we can and request a + // new buffer. + memcpy(buffer_, data, buffer_size_); + data += buffer_size_; + size -= buffer_size_; + void* void_buffer; + failed_ = !output_->Next(&void_buffer, &buffer_size_); + if (failed_) return; + buffer_ = reinterpret_cast(void_buffer); + } + + // Buffer is big enough to receive the data; copy it. + memcpy(buffer_, data, size); + buffer_ += size; + buffer_size_ -= size; + } + + io::ZeroCopyOutputStream* const output_; + char* buffer_; + int buffer_size_; + bool at_start_of_line_; + bool failed_; + + string indent_; + int initial_indent_level_; +}; + +// =========================================================================== + +TextFormat::Finder::~Finder() { +} + +TextFormat::Parser::Parser() + : error_collector_(NULL), + finder_(NULL), + allow_partial_(false) { +} + +TextFormat::Parser::~Parser() {} + +bool TextFormat::Parser::Parse(io::ZeroCopyInputStream* input, + Message* output) { + output->Clear(); + ParserImpl parser(output->GetDescriptor(), input, error_collector_, + finder_, ParserImpl::FORBID_SINGULAR_OVERWRITES); + return MergeUsingImpl(input, output, &parser); +} + +bool TextFormat::Parser::ParseFromString(const string& input, + Message* output) { + io::ArrayInputStream input_stream(input.data(), input.size()); + return Parse(&input_stream, output); +} + +bool TextFormat::Parser::Merge(io::ZeroCopyInputStream* input, + Message* output) { + ParserImpl parser(output->GetDescriptor(), input, error_collector_, + finder_, ParserImpl::ALLOW_SINGULAR_OVERWRITES); + return MergeUsingImpl(input, output, &parser); +} + +bool TextFormat::Parser::MergeFromString(const string& input, + Message* output) { + io::ArrayInputStream input_stream(input.data(), input.size()); + return Merge(&input_stream, output); +} + +bool TextFormat::Parser::MergeUsingImpl(io::ZeroCopyInputStream* input, + Message* output, + ParserImpl* parser_impl) { + if (!parser_impl->Parse(output)) return false; + if (!allow_partial_ && !output->IsInitialized()) { + vector missing_fields; + output->FindInitializationErrors(&missing_fields); + parser_impl->ReportError(-1, 0, "Message missing required fields: " + + JoinStrings(missing_fields, ", ")); + return false; + } + return true; +} + +bool TextFormat::Parser::ParseFieldValueFromString( + const string& input, + const FieldDescriptor* field, + Message* output) { + io::ArrayInputStream input_stream(input.data(), input.size()); + ParserImpl parser(output->GetDescriptor(), &input_stream, error_collector_, + finder_, ParserImpl::ALLOW_SINGULAR_OVERWRITES); + return parser.ParseField(field, output); +} + +/* static */ bool TextFormat::Parse(io::ZeroCopyInputStream* input, + Message* output) { + return Parser().Parse(input, output); +} + +/* static */ bool TextFormat::Merge(io::ZeroCopyInputStream* input, + Message* output) { + return Parser().Merge(input, output); +} + +/* static */ bool TextFormat::ParseFromString(const string& input, + Message* output) { + return Parser().ParseFromString(input, output); +} + +/* static */ bool TextFormat::MergeFromString(const string& input, + Message* output) { + return Parser().MergeFromString(input, output); +} + +// =========================================================================== + +TextFormat::Printer::Printer() + : initial_indent_level_(0), + single_line_mode_(false), + use_short_repeated_primitives_(false), + utf8_string_escaping_(false) {} + +TextFormat::Printer::~Printer() {} + +bool TextFormat::Printer::PrintToString(const Message& message, + string* output) const { + GOOGLE_DCHECK(output) << "output specified is NULL"; + + output->clear(); + io::StringOutputStream output_stream(output); + + bool result = Print(message, &output_stream); + + return result; +} + +bool TextFormat::Printer::PrintUnknownFieldsToString( + const UnknownFieldSet& unknown_fields, + string* output) const { + GOOGLE_DCHECK(output) << "output specified is NULL"; + + output->clear(); + io::StringOutputStream output_stream(output); + return PrintUnknownFields(unknown_fields, &output_stream); +} + +bool TextFormat::Printer::Print(const Message& message, + io::ZeroCopyOutputStream* output) const { + TextGenerator generator(output, initial_indent_level_); + + Print(message, generator); + + // Output false if the generator failed internally. + return !generator.failed(); +} + +bool TextFormat::Printer::PrintUnknownFields( + const UnknownFieldSet& unknown_fields, + io::ZeroCopyOutputStream* output) const { + TextGenerator generator(output, initial_indent_level_); + + PrintUnknownFields(unknown_fields, generator); + + // Output false if the generator failed internally. + return !generator.failed(); +} + +void TextFormat::Printer::Print(const Message& message, + TextGenerator& generator) const { + const Reflection* reflection = message.GetReflection(); + vector fields; + reflection->ListFields(message, &fields); + for (int i = 0; i < fields.size(); i++) { + PrintField(message, reflection, fields[i], generator); + } + PrintUnknownFields(reflection->GetUnknownFields(message), generator); +} + +void TextFormat::Printer::PrintFieldValueToString( + const Message& message, + const FieldDescriptor* field, + int index, + string* output) const { + + GOOGLE_DCHECK(output) << "output specified is NULL"; + + output->clear(); + io::StringOutputStream output_stream(output); + TextGenerator generator(&output_stream, initial_indent_level_); + + PrintFieldValue(message, message.GetReflection(), field, index, generator); +} + +void TextFormat::Printer::PrintField(const Message& message, + const Reflection* reflection, + const FieldDescriptor* field, + TextGenerator& generator) const { + if (use_short_repeated_primitives_ && + field->is_repeated() && + field->cpp_type() != FieldDescriptor::CPPTYPE_STRING && + field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) { + PrintShortRepeatedField(message, reflection, field, generator); + return; + } + + int count = 0; + + if (field->is_repeated()) { + count = reflection->FieldSize(message, field); + } else if (reflection->HasField(message, field)) { + count = 1; + } + + for (int j = 0; j < count; ++j) { + PrintFieldName(message, reflection, field, generator); + + if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + if (single_line_mode_) { + generator.Print(" { "); + } else { + generator.Print(" {\n"); + generator.Indent(); + } + } else { + generator.Print(": "); + } + + // Write the field value. + int field_index = j; + if (!field->is_repeated()) { + field_index = -1; + } + + PrintFieldValue(message, reflection, field, field_index, generator); + + if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + if (single_line_mode_) { + generator.Print("} "); + } else { + generator.Outdent(); + generator.Print("}\n"); + } + } else { + if (single_line_mode_) { + generator.Print(" "); + } else { + generator.Print("\n"); + } + } + } +} + +void TextFormat::Printer::PrintShortRepeatedField( + const Message& message, + const Reflection* reflection, + const FieldDescriptor* field, + TextGenerator& generator) const { + // Print primitive repeated field in short form. + PrintFieldName(message, reflection, field, generator); + + int size = reflection->FieldSize(message, field); + generator.Print(": ["); + for (int i = 0; i < size; i++) { + if (i > 0) generator.Print(", "); + PrintFieldValue(message, reflection, field, i, generator); + } + if (single_line_mode_) { + generator.Print("] "); + } else { + generator.Print("]\n"); + } +} + +void TextFormat::Printer::PrintFieldName(const Message& message, + const Reflection* reflection, + const FieldDescriptor* field, + TextGenerator& generator) const { + if (field->is_extension()) { + generator.Print("["); + // We special-case MessageSet elements for compatibility with proto1. + if (field->containing_type()->options().message_set_wire_format() + && field->type() == FieldDescriptor::TYPE_MESSAGE + && field->is_optional() + && field->extension_scope() == field->message_type()) { + generator.Print(field->message_type()->full_name()); + } else { + generator.Print(field->full_name()); + } + generator.Print("]"); + } else { + if (field->type() == FieldDescriptor::TYPE_GROUP) { + // Groups must be serialized with their original capitalization. + generator.Print(field->message_type()->name()); + } else { + generator.Print(field->name()); + } + } +} + +void TextFormat::Printer::PrintFieldValue( + const Message& message, + const Reflection* reflection, + const FieldDescriptor* field, + int index, + TextGenerator& generator) const { + GOOGLE_DCHECK(field->is_repeated() || (index == -1)) + << "Index must be -1 for non-repeated fields"; + + switch (field->cpp_type()) { +#define OUTPUT_FIELD(CPPTYPE, METHOD, TO_STRING) \ + case FieldDescriptor::CPPTYPE_##CPPTYPE: \ + generator.Print(TO_STRING(field->is_repeated() ? \ + reflection->GetRepeated##METHOD(message, field, index) : \ + reflection->Get##METHOD(message, field))); \ + break; \ + + OUTPUT_FIELD( INT32, Int32, SimpleItoa); + OUTPUT_FIELD( INT64, Int64, SimpleItoa); + OUTPUT_FIELD(UINT32, UInt32, SimpleItoa); + OUTPUT_FIELD(UINT64, UInt64, SimpleItoa); + OUTPUT_FIELD( FLOAT, Float, SimpleFtoa); + OUTPUT_FIELD(DOUBLE, Double, SimpleDtoa); +#undef OUTPUT_FIELD + + case FieldDescriptor::CPPTYPE_STRING: { + string scratch; + const string& value = field->is_repeated() ? + reflection->GetRepeatedStringReference( + message, field, index, &scratch) : + reflection->GetStringReference(message, field, &scratch); + + generator.Print("\""); + if (utf8_string_escaping_) { + generator.Print(strings::Utf8SafeCEscape(value)); + } else { + generator.Print(CEscape(value)); + } + generator.Print("\""); + + break; + } + + case FieldDescriptor::CPPTYPE_BOOL: + if (field->is_repeated()) { + generator.Print(reflection->GetRepeatedBool(message, field, index) + ? "true" : "false"); + } else { + generator.Print(reflection->GetBool(message, field) + ? "true" : "false"); + } + break; + + case FieldDescriptor::CPPTYPE_ENUM: + generator.Print(field->is_repeated() ? + reflection->GetRepeatedEnum(message, field, index)->name() : + reflection->GetEnum(message, field)->name()); + break; + + case FieldDescriptor::CPPTYPE_MESSAGE: + Print(field->is_repeated() ? + reflection->GetRepeatedMessage(message, field, index) : + reflection->GetMessage(message, field), + generator); + break; + } +} + +/* static */ bool TextFormat::Print(const Message& message, + io::ZeroCopyOutputStream* output) { + return Printer().Print(message, output); +} + +/* static */ bool TextFormat::PrintUnknownFields( + const UnknownFieldSet& unknown_fields, + io::ZeroCopyOutputStream* output) { + return Printer().PrintUnknownFields(unknown_fields, output); +} + +/* static */ bool TextFormat::PrintToString( + const Message& message, string* output) { + return Printer().PrintToString(message, output); +} + +/* static */ bool TextFormat::PrintUnknownFieldsToString( + const UnknownFieldSet& unknown_fields, string* output) { + return Printer().PrintUnknownFieldsToString(unknown_fields, output); +} + +/* static */ void TextFormat::PrintFieldValueToString( + const Message& message, + const FieldDescriptor* field, + int index, + string* output) { + return Printer().PrintFieldValueToString(message, field, index, output); +} + +/* static */ bool TextFormat::ParseFieldValueFromString( + const string& input, + const FieldDescriptor* field, + Message* message) { + return Parser().ParseFieldValueFromString(input, field, message); +} + +// Prints an integer as hex with a fixed number of digits dependent on the +// integer type. +template +static string PaddedHex(IntType value) { + string result; + result.reserve(sizeof(value) * 2); + for (int i = sizeof(value) * 2 - 1; i >= 0; i--) { + result.push_back(int_to_hex_digit(value >> (i*4) & 0x0F)); + } + return result; +} + +void TextFormat::Printer::PrintUnknownFields( + const UnknownFieldSet& unknown_fields, TextGenerator& generator) const { + for (int i = 0; i < unknown_fields.field_count(); i++) { + const UnknownField& field = unknown_fields.field(i); + string field_number = SimpleItoa(field.number()); + + switch (field.type()) { + case UnknownField::TYPE_VARINT: + generator.Print(field_number); + generator.Print(": "); + generator.Print(SimpleItoa(field.varint())); + if (single_line_mode_) { + generator.Print(" "); + } else { + generator.Print("\n"); + } + break; + case UnknownField::TYPE_FIXED32: { + generator.Print(field_number); + generator.Print(": 0x"); + char buffer[kFastToBufferSize]; + generator.Print(FastHex32ToBuffer(field.fixed32(), buffer)); + if (single_line_mode_) { + generator.Print(" "); + } else { + generator.Print("\n"); + } + break; + } + case UnknownField::TYPE_FIXED64: { + generator.Print(field_number); + generator.Print(": 0x"); + char buffer[kFastToBufferSize]; + generator.Print(FastHex64ToBuffer(field.fixed64(), buffer)); + if (single_line_mode_) { + generator.Print(" "); + } else { + generator.Print("\n"); + } + break; + } + case UnknownField::TYPE_LENGTH_DELIMITED: { + generator.Print(field_number); + const string& value = field.length_delimited(); + UnknownFieldSet embedded_unknown_fields; + if (!value.empty() && embedded_unknown_fields.ParseFromString(value)) { + // This field is parseable as a Message. + // So it is probably an embedded message. + if (single_line_mode_) { + generator.Print(" { "); + } else { + generator.Print(" {\n"); + generator.Indent(); + } + PrintUnknownFields(embedded_unknown_fields, generator); + if (single_line_mode_) { + generator.Print("} "); + } else { + generator.Outdent(); + generator.Print("}\n"); + } + } else { + // This field is not parseable as a Message. + // So it is probably just a plain string. + generator.Print(": \""); + generator.Print(CEscape(value)); + generator.Print("\""); + if (single_line_mode_) { + generator.Print(" "); + } else { + generator.Print("\n"); + } + } + break; + } + case UnknownField::TYPE_GROUP: + generator.Print(field_number); + if (single_line_mode_) { + generator.Print(" { "); + } else { + generator.Print(" {\n"); + generator.Indent(); + } + PrintUnknownFields(field.group(), generator); + if (single_line_mode_) { + generator.Print("} "); + } else { + generator.Outdent(); + generator.Print("}\n"); + } + break; + } + } +} + +} // namespace protobuf +} // namespace google diff --git a/depends/protobuf/google/protobuf/text_format.h b/depends/protobuf/google/protobuf/text_format.h new file mode 100644 index 0000000000..03c0491025 --- /dev/null +++ b/depends/protobuf/google/protobuf/text_format.h @@ -0,0 +1,285 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: jschorr@google.com (Joseph Schorr) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// Utilities for printing and parsing protocol messages in a human-readable, +// text-based format. + +#ifndef GOOGLE_PROTOBUF_TEXT_FORMAT_H__ +#define GOOGLE_PROTOBUF_TEXT_FORMAT_H__ + +#include +#include +#include + +namespace google { +namespace protobuf { + +namespace io { + class ErrorCollector; // tokenizer.h +} + +// This class implements protocol buffer text format. Printing and parsing +// protocol messages in text format is useful for debugging and human editing +// of messages. +// +// This class is really a namespace that contains only static methods. +class LIBPROTOBUF_EXPORT TextFormat { + public: + // Outputs a textual representation of the given message to the given + // output stream. + static bool Print(const Message& message, io::ZeroCopyOutputStream* output); + + // Print the fields in an UnknownFieldSet. They are printed by tag number + // only. Embedded messages are heuristically identified by attempting to + // parse them. + static bool PrintUnknownFields(const UnknownFieldSet& unknown_fields, + io::ZeroCopyOutputStream* output); + + // Like Print(), but outputs directly to a string. + static bool PrintToString(const Message& message, string* output); + + // Like PrintUnknownFields(), but outputs directly to a string. + static bool PrintUnknownFieldsToString(const UnknownFieldSet& unknown_fields, + string* output); + + // Outputs a textual representation of the value of the field supplied on + // the message supplied. For non-repeated fields, an index of -1 must + // be supplied. Note that this method will print the default value for a + // field if it is not set. + static void PrintFieldValueToString(const Message& message, + const FieldDescriptor* field, + int index, + string* output); + + // Class for those users which require more fine-grained control over how + // a protobuffer message is printed out. + class LIBPROTOBUF_EXPORT Printer { + public: + Printer(); + ~Printer(); + + // Like TextFormat::Print + bool Print(const Message& message, io::ZeroCopyOutputStream* output) const; + // Like TextFormat::PrintUnknownFields + bool PrintUnknownFields(const UnknownFieldSet& unknown_fields, + io::ZeroCopyOutputStream* output) const; + // Like TextFormat::PrintToString + bool PrintToString(const Message& message, string* output) const; + // Like TextFormat::PrintUnknownFieldsToString + bool PrintUnknownFieldsToString(const UnknownFieldSet& unknown_fields, + string* output) const; + // Like TextFormat::PrintFieldValueToString + void PrintFieldValueToString(const Message& message, + const FieldDescriptor* field, + int index, + string* output) const; + + // Adjust the initial indent level of all output. Each indent level is + // equal to two spaces. + void SetInitialIndentLevel(int indent_level) { + initial_indent_level_ = indent_level; + } + + // If printing in single line mode, then the entire message will be output + // on a single line with no line breaks. + void SetSingleLineMode(bool single_line_mode) { + single_line_mode_ = single_line_mode; + } + + // Set true to print repeated primitives in a format like: + // field_name: [1, 2, 3, 4] + // instead of printing each value on its own line. Short format applies + // only to primitive values -- i.e. everything except strings and + // sub-messages/groups. + void SetUseShortRepeatedPrimitives(bool use_short_repeated_primitives) { + use_short_repeated_primitives_ = use_short_repeated_primitives; + } + + // Set true to output UTF-8 instead of ASCII. The only difference + // is that bytes >= 0x80 in string fields will not be escaped, + // because they are assumed to be part of UTF-8 multi-byte + // sequences. + void SetUseUtf8StringEscaping(bool as_utf8) { + utf8_string_escaping_ = as_utf8; + } + + private: + // Forward declaration of an internal class used to print the text + // output to the OutputStream (see text_format.cc for implementation). + class TextGenerator; + + // Internal Print method, used for writing to the OutputStream via + // the TextGenerator class. + void Print(const Message& message, + TextGenerator& generator) const; + + // Print a single field. + void PrintField(const Message& message, + const Reflection* reflection, + const FieldDescriptor* field, + TextGenerator& generator) const; + + // Print a repeated primitive field in short form. + void PrintShortRepeatedField(const Message& message, + const Reflection* reflection, + const FieldDescriptor* field, + TextGenerator& generator) const; + + // Print the name of a field -- i.e. everything that comes before the + // ':' for a single name/value pair. + void PrintFieldName(const Message& message, + const Reflection* reflection, + const FieldDescriptor* field, + TextGenerator& generator) const; + + // Outputs a textual representation of the value of the field supplied on + // the message supplied or the default value if not set. + void PrintFieldValue(const Message& message, + const Reflection* reflection, + const FieldDescriptor* field, + int index, + TextGenerator& generator) const; + + // Print the fields in an UnknownFieldSet. They are printed by tag number + // only. Embedded messages are heuristically identified by attempting to + // parse them. + void PrintUnknownFields(const UnknownFieldSet& unknown_fields, + TextGenerator& generator) const; + + int initial_indent_level_; + + bool single_line_mode_; + + bool use_short_repeated_primitives_; + + bool utf8_string_escaping_; + }; + + // Parses a text-format protocol message from the given input stream to + // the given message object. This function parses the format written + // by Print(). + static bool Parse(io::ZeroCopyInputStream* input, Message* output); + // Like Parse(), but reads directly from a string. + static bool ParseFromString(const string& input, Message* output); + + // Like Parse(), but the data is merged into the given message, as if + // using Message::MergeFrom(). + static bool Merge(io::ZeroCopyInputStream* input, Message* output); + // Like Merge(), but reads directly from a string. + static bool MergeFromString(const string& input, Message* output); + + // Parse the given text as a single field value and store it into the + // given field of the given message. If the field is a repeated field, + // the new value will be added to the end + static bool ParseFieldValueFromString(const string& input, + const FieldDescriptor* field, + Message* message); + + // Interface that TextFormat::Parser can use to find extensions. + // This class may be extended in the future to find more information + // like fields, etc. + class LIBPROTOBUF_EXPORT Finder { + public: + virtual ~Finder(); + + // Try to find an extension of *message by fully-qualified field + // name. Returns NULL if no extension is known for this name or number. + virtual const FieldDescriptor* FindExtension( + Message* message, + const string& name) const = 0; + }; + + // For more control over parsing, use this class. + class LIBPROTOBUF_EXPORT Parser { + public: + Parser(); + ~Parser(); + + // Like TextFormat::Parse(). + bool Parse(io::ZeroCopyInputStream* input, Message* output); + // Like TextFormat::ParseFromString(). + bool ParseFromString(const string& input, Message* output); + // Like TextFormat::Merge(). + bool Merge(io::ZeroCopyInputStream* input, Message* output); + // Like TextFormat::MergeFromString(). + bool MergeFromString(const string& input, Message* output); + + // Set where to report parse errors. If NULL (the default), errors will + // be printed to stderr. + void RecordErrorsTo(io::ErrorCollector* error_collector) { + error_collector_ = error_collector; + } + + // Set how parser finds extensions. If NULL (the default), the + // parser will use the standard Reflection object associated with + // the message being parsed. + void SetFinder(Finder* finder) { + finder_ = finder; + } + + // Normally parsing fails if, after parsing, output->IsInitialized() + // returns false. Call AllowPartialMessage(true) to skip this check. + void AllowPartialMessage(bool allow) { + allow_partial_ = allow; + } + + // Like TextFormat::ParseFieldValueFromString + bool ParseFieldValueFromString(const string& input, + const FieldDescriptor* field, + Message* output); + + private: + // Forward declaration of an internal class used to parse text + // representations (see text_format.cc for implementation). + class ParserImpl; + + // Like TextFormat::Merge(). The provided implementation is used + // to do the parsing. + bool MergeUsingImpl(io::ZeroCopyInputStream* input, + Message* output, + ParserImpl* parser_impl); + + io::ErrorCollector* error_collector_; + Finder* finder_; + bool allow_partial_; + }; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(TextFormat); +}; + +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_TEXT_FORMAT_H__ diff --git a/depends/protobuf/google/protobuf/unknown_field_set.cc b/depends/protobuf/google/protobuf/unknown_field_set.cc new file mode 100644 index 0000000000..e1f8b838f8 --- /dev/null +++ b/depends/protobuf/google/protobuf/unknown_field_set.cc @@ -0,0 +1,204 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include +#include +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { + +UnknownFieldSet::UnknownFieldSet() + : fields_(NULL) {} + +UnknownFieldSet::~UnknownFieldSet() { + Clear(); + delete fields_; +} + +void UnknownFieldSet::ClearFallback() { + GOOGLE_DCHECK(fields_ != NULL); + for (int i = 0; i < fields_->size(); i++) { + (*fields_)[i].Delete(); + } + fields_->clear(); +} + +void UnknownFieldSet::MergeFrom(const UnknownFieldSet& other) { + for (int i = 0; i < other.field_count(); i++) { + AddField(other.field(i)); + } +} + +int UnknownFieldSet::SpaceUsedExcludingSelf() const { + if (fields_ == NULL) return 0; + + int total_size = sizeof(*fields_) + sizeof(UnknownField) * fields_->size(); + for (int i = 0; i < fields_->size(); i++) { + const UnknownField& field = (*fields_)[i]; + switch (field.type()) { + case UnknownField::TYPE_LENGTH_DELIMITED: + total_size += sizeof(*field.length_delimited_) + + internal::StringSpaceUsedExcludingSelf(*field.length_delimited_); + break; + case UnknownField::TYPE_GROUP: + total_size += field.group_->SpaceUsed(); + break; + default: + break; + } + } + return total_size; +} + +int UnknownFieldSet::SpaceUsed() const { + return sizeof(*this) + SpaceUsedExcludingSelf(); +} + +void UnknownFieldSet::AddVarint(int number, uint64 value) { + if (fields_ == NULL) fields_ = new vector; + UnknownField field; + field.number_ = number; + field.type_ = UnknownField::TYPE_VARINT; + field.varint_ = value; + fields_->push_back(field); +} + +void UnknownFieldSet::AddFixed32(int number, uint32 value) { + if (fields_ == NULL) fields_ = new vector; + UnknownField field; + field.number_ = number; + field.type_ = UnknownField::TYPE_FIXED32; + field.fixed32_ = value; + fields_->push_back(field); +} + +void UnknownFieldSet::AddFixed64(int number, uint64 value) { + if (fields_ == NULL) fields_ = new vector; + UnknownField field; + field.number_ = number; + field.type_ = UnknownField::TYPE_FIXED64; + field.fixed64_ = value; + fields_->push_back(field); +} + +string* UnknownFieldSet::AddLengthDelimited(int number) { + if (fields_ == NULL) fields_ = new vector; + UnknownField field; + field.number_ = number; + field.type_ = UnknownField::TYPE_LENGTH_DELIMITED; + field.length_delimited_ = new string; + fields_->push_back(field); + return field.length_delimited_; +} + +UnknownFieldSet* UnknownFieldSet::AddGroup(int number) { + if (fields_ == NULL) fields_ = new vector; + UnknownField field; + field.number_ = number; + field.type_ = UnknownField::TYPE_GROUP; + field.group_ = new UnknownFieldSet; + fields_->push_back(field); + return field.group_; +} + +void UnknownFieldSet::AddField(const UnknownField& field) { + if (fields_ == NULL) fields_ = new vector; + fields_->push_back(field); + fields_->back().DeepCopy(); +} + +bool UnknownFieldSet::MergeFromCodedStream(io::CodedInputStream* input) { + + UnknownFieldSet other; + if (internal::WireFormat::SkipMessage(input, &other) && + input->ConsumedEntireMessage()) { + MergeFrom(other); + return true; + } else { + return false; + } +} + +bool UnknownFieldSet::ParseFromCodedStream(io::CodedInputStream* input) { + Clear(); + return MergeFromCodedStream(input); +} + +bool UnknownFieldSet::ParseFromZeroCopyStream(io::ZeroCopyInputStream* input) { + io::CodedInputStream coded_input(input); + return ParseFromCodedStream(&coded_input) && + coded_input.ConsumedEntireMessage(); +} + +bool UnknownFieldSet::ParseFromArray(const void* data, int size) { + io::ArrayInputStream input(data, size); + return ParseFromZeroCopyStream(&input); +} + +void UnknownField::Delete() { + switch (type()) { + case UnknownField::TYPE_LENGTH_DELIMITED: + delete length_delimited_; + break; + case UnknownField::TYPE_GROUP: + delete group_; + break; + default: + break; + } +} + +void UnknownField::DeepCopy() { + switch (type()) { + case UnknownField::TYPE_LENGTH_DELIMITED: + length_delimited_ = new string(*length_delimited_); + break; + case UnknownField::TYPE_GROUP: { + UnknownFieldSet* group = new UnknownFieldSet; + group->MergeFrom(*group_); + group_ = group; + break; + } + default: + break; + } +} + +} // namespace protobuf +} // namespace google diff --git a/depends/protobuf/google/protobuf/unknown_field_set.h b/depends/protobuf/google/protobuf/unknown_field_set.h new file mode 100644 index 0000000000..84c2e2b609 --- /dev/null +++ b/depends/protobuf/google/protobuf/unknown_field_set.h @@ -0,0 +1,268 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// Contains classes used to keep track of unrecognized fields seen while +// parsing a protocol message. + +#ifndef GOOGLE_PROTOBUF_UNKNOWN_FIELD_SET_H__ +#define GOOGLE_PROTOBUF_UNKNOWN_FIELD_SET_H__ + +#include +#include +#include + +namespace google { +namespace protobuf { + +class Message; // message.h +class UnknownField; // below + +// An UnknownFieldSet contains fields that were encountered while parsing a +// message but were not defined by its type. Keeping track of these can be +// useful, especially in that they may be written if the message is serialized +// again without being cleared in between. This means that software which +// simply receives messages and forwards them to other servers does not need +// to be updated every time a new field is added to the message definition. +// +// To get the UnknownFieldSet attached to any message, call +// Reflection::GetUnknownFields(). +// +// This class is necessarily tied to the protocol buffer wire format, unlike +// the Reflection interface which is independent of any serialization scheme. +class LIBPROTOBUF_EXPORT UnknownFieldSet { + public: + UnknownFieldSet(); + ~UnknownFieldSet(); + + // Remove all fields. + inline void Clear(); + + // Is this set empty? + inline bool empty() const; + + // Merge the contents of some other UnknownFieldSet with this one. + void MergeFrom(const UnknownFieldSet& other); + + // Swaps the contents of some other UnknownFieldSet with this one. + inline void Swap(UnknownFieldSet* x); + + // Computes (an estimate of) the total number of bytes currently used for + // storing the unknown fields in memory. Does NOT include + // sizeof(*this) in the calculation. + int SpaceUsedExcludingSelf() const; + + // Version of SpaceUsed() including sizeof(*this). + int SpaceUsed() const; + + // Returns the number of fields present in the UnknownFieldSet. + inline int field_count() const; + // Get a field in the set, where 0 <= index < field_count(). The fields + // appear in the order in which they were added. + inline const UnknownField& field(int index) const; + // Get a mutable pointer to a field in the set, where + // 0 <= index < field_count(). The fields appear in the order in which + // they were added. + inline UnknownField* mutable_field(int index); + + // Adding fields --------------------------------------------------- + + void AddVarint(int number, uint64 value); + void AddFixed32(int number, uint32 value); + void AddFixed64(int number, uint64 value); + void AddLengthDelimited(int number, const string& value); + string* AddLengthDelimited(int number); + UnknownFieldSet* AddGroup(int number); + + // Adds an unknown field from another set. + void AddField(const UnknownField& field); + + // Parsing helpers ------------------------------------------------- + // These work exactly like the similarly-named methods of Message. + + bool MergeFromCodedStream(io::CodedInputStream* input); + bool ParseFromCodedStream(io::CodedInputStream* input); + bool ParseFromZeroCopyStream(io::ZeroCopyInputStream* input); + bool ParseFromArray(const void* data, int size); + inline bool ParseFromString(const string& data) { + return ParseFromArray(data.data(), data.size()); + } + + private: + void ClearFallback(); + + vector* fields_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(UnknownFieldSet); +}; + +// Represents one field in an UnknownFieldSet. +class LIBPROTOBUF_EXPORT UnknownField { + public: + enum Type { + TYPE_VARINT, + TYPE_FIXED32, + TYPE_FIXED64, + TYPE_LENGTH_DELIMITED, + TYPE_GROUP + }; + + // The field's tag number, as seen on the wire. + inline int number() const; + + // The field type. + inline Type type() const; + + // Accessors ------------------------------------------------------- + // Each method works only for UnknownFields of the corresponding type. + + inline uint64 varint() const; + inline uint32 fixed32() const; + inline uint64 fixed64() const; + inline const string& length_delimited() const; + inline const UnknownFieldSet& group() const; + + inline void set_varint(uint64 value); + inline void set_fixed32(uint32 value); + inline void set_fixed64(uint64 value); + inline void set_length_delimited(const string& value); + inline string* mutable_length_delimited(); + inline UnknownFieldSet* mutable_group(); + + private: + friend class UnknownFieldSet; + + // If this UnknownField contains a pointer, delete it. + void Delete(); + + // Make a deep copy of any pointers in this UnknownField. + void DeepCopy(); + + unsigned int number_ : 29; + unsigned int type_ : 3; + union { + uint64 varint_; + uint32 fixed32_; + uint64 fixed64_; + string* length_delimited_; + UnknownFieldSet* group_; + }; +}; + +// =================================================================== +// inline implementations + +inline void UnknownFieldSet::Clear() { + if (fields_ != NULL) { + ClearFallback(); + } +} + +inline bool UnknownFieldSet::empty() const { + return fields_ == NULL || fields_->empty(); +} + +inline void UnknownFieldSet::Swap(UnknownFieldSet* x) { + std::swap(fields_, x->fields_); +} + +inline int UnknownFieldSet::field_count() const { + return (fields_ == NULL) ? 0 : fields_->size(); +} +inline const UnknownField& UnknownFieldSet::field(int index) const { + return (*fields_)[index]; +} +inline UnknownField* UnknownFieldSet::mutable_field(int index) { + return &(*fields_)[index]; +} + +inline void UnknownFieldSet::AddLengthDelimited( + int number, const string& value) { + AddLengthDelimited(number)->assign(value); +} + +inline int UnknownField::number() const { return number_; } +inline UnknownField::Type UnknownField::type() const { + return static_cast(type_); +} + +inline uint64 UnknownField::varint () const { + GOOGLE_DCHECK_EQ(type_, TYPE_VARINT); + return varint_; +} +inline uint32 UnknownField::fixed32() const { + GOOGLE_DCHECK_EQ(type_, TYPE_FIXED32); + return fixed32_; +} +inline uint64 UnknownField::fixed64() const { + GOOGLE_DCHECK_EQ(type_, TYPE_FIXED64); + return fixed64_; +} +inline const string& UnknownField::length_delimited() const { + GOOGLE_DCHECK_EQ(type_, TYPE_LENGTH_DELIMITED); + return *length_delimited_; +} +inline const UnknownFieldSet& UnknownField::group() const { + GOOGLE_DCHECK_EQ(type_, TYPE_GROUP); + return *group_; +} + +inline void UnknownField::set_varint(uint64 value) { + GOOGLE_DCHECK_EQ(type_, TYPE_VARINT); + varint_ = value; +} +inline void UnknownField::set_fixed32(uint32 value) { + GOOGLE_DCHECK_EQ(type_, TYPE_FIXED32); + fixed32_ = value; +} +inline void UnknownField::set_fixed64(uint64 value) { + GOOGLE_DCHECK_EQ(type_, TYPE_FIXED64); + fixed64_ = value; +} +inline void UnknownField::set_length_delimited(const string& value) { + GOOGLE_DCHECK_EQ(type_, TYPE_LENGTH_DELIMITED); + length_delimited_->assign(value); +} +inline string* UnknownField::mutable_length_delimited() { + GOOGLE_DCHECK_EQ(type_, TYPE_LENGTH_DELIMITED); + return length_delimited_; +} +inline UnknownFieldSet* UnknownField::mutable_group() { + GOOGLE_DCHECK_EQ(type_, TYPE_GROUP); + return group_; +} + +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_UNKNOWN_FIELD_SET_H__ diff --git a/depends/protobuf/google/protobuf/wire_format.cc b/depends/protobuf/google/protobuf/wire_format.cc new file mode 100644 index 0000000000..831a579450 --- /dev/null +++ b/depends/protobuf/google/protobuf/wire_format.cc @@ -0,0 +1,1069 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace google { +namespace protobuf { +namespace internal { + +using internal::WireFormatLite; + +namespace { + +// This function turns out to be convenient when using some macros later. +inline int GetEnumNumber(const EnumValueDescriptor* descriptor) { + return descriptor->number(); +} + +} // anonymous namespace + +// =================================================================== + +bool UnknownFieldSetFieldSkipper::SkipField( + io::CodedInputStream* input, uint32 tag) { + return WireFormat::SkipField(input, tag, unknown_fields_); +} + +bool UnknownFieldSetFieldSkipper::SkipMessage(io::CodedInputStream* input) { + return WireFormat::SkipMessage(input, unknown_fields_); +} + +void UnknownFieldSetFieldSkipper::SkipUnknownEnum( + int field_number, int value) { + unknown_fields_->AddVarint(field_number, value); +} + +bool WireFormat::SkipField(io::CodedInputStream* input, uint32 tag, + UnknownFieldSet* unknown_fields) { + int number = WireFormatLite::GetTagFieldNumber(tag); + + switch (WireFormatLite::GetTagWireType(tag)) { + case WireFormatLite::WIRETYPE_VARINT: { + uint64 value; + if (!input->ReadVarint64(&value)) return false; + if (unknown_fields != NULL) unknown_fields->AddVarint(number, value); + return true; + } + case WireFormatLite::WIRETYPE_FIXED64: { + uint64 value; + if (!input->ReadLittleEndian64(&value)) return false; + if (unknown_fields != NULL) unknown_fields->AddFixed64(number, value); + return true; + } + case WireFormatLite::WIRETYPE_LENGTH_DELIMITED: { + uint32 length; + if (!input->ReadVarint32(&length)) return false; + if (unknown_fields == NULL) { + if (!input->Skip(length)) return false; + } else { + if (!input->ReadString(unknown_fields->AddLengthDelimited(number), + length)) { + return false; + } + } + return true; + } + case WireFormatLite::WIRETYPE_START_GROUP: { + if (!input->IncrementRecursionDepth()) return false; + if (!SkipMessage(input, (unknown_fields == NULL) ? + NULL : unknown_fields->AddGroup(number))) { + return false; + } + input->DecrementRecursionDepth(); + // Check that the ending tag matched the starting tag. + if (!input->LastTagWas(WireFormatLite::MakeTag( + WireFormatLite::GetTagFieldNumber(tag), + WireFormatLite::WIRETYPE_END_GROUP))) { + return false; + } + return true; + } + case WireFormatLite::WIRETYPE_END_GROUP: { + return false; + } + case WireFormatLite::WIRETYPE_FIXED32: { + uint32 value; + if (!input->ReadLittleEndian32(&value)) return false; + if (unknown_fields != NULL) unknown_fields->AddFixed32(number, value); + return true; + } + default: { + return false; + } + } +} + +bool WireFormat::SkipMessage(io::CodedInputStream* input, + UnknownFieldSet* unknown_fields) { + while(true) { + uint32 tag = input->ReadTag(); + if (tag == 0) { + // End of input. This is a valid place to end, so return true. + return true; + } + + WireFormatLite::WireType wire_type = WireFormatLite::GetTagWireType(tag); + + if (wire_type == WireFormatLite::WIRETYPE_END_GROUP) { + // Must be the end of the message. + return true; + } + + if (!SkipField(input, tag, unknown_fields)) return false; + } +} + +void WireFormat::SerializeUnknownFields(const UnknownFieldSet& unknown_fields, + io::CodedOutputStream* output) { + for (int i = 0; i < unknown_fields.field_count(); i++) { + const UnknownField& field = unknown_fields.field(i); + switch (field.type()) { + case UnknownField::TYPE_VARINT: + output->WriteVarint32(WireFormatLite::MakeTag(field.number(), + WireFormatLite::WIRETYPE_VARINT)); + output->WriteVarint64(field.varint()); + break; + case UnknownField::TYPE_FIXED32: + output->WriteVarint32(WireFormatLite::MakeTag(field.number(), + WireFormatLite::WIRETYPE_FIXED32)); + output->WriteLittleEndian32(field.fixed32()); + break; + case UnknownField::TYPE_FIXED64: + output->WriteVarint32(WireFormatLite::MakeTag(field.number(), + WireFormatLite::WIRETYPE_FIXED64)); + output->WriteLittleEndian64(field.fixed64()); + break; + case UnknownField::TYPE_LENGTH_DELIMITED: + output->WriteVarint32(WireFormatLite::MakeTag(field.number(), + WireFormatLite::WIRETYPE_LENGTH_DELIMITED)); + output->WriteVarint32(field.length_delimited().size()); + output->WriteString(field.length_delimited()); + break; + case UnknownField::TYPE_GROUP: + output->WriteVarint32(WireFormatLite::MakeTag(field.number(), + WireFormatLite::WIRETYPE_START_GROUP)); + SerializeUnknownFields(field.group(), output); + output->WriteVarint32(WireFormatLite::MakeTag(field.number(), + WireFormatLite::WIRETYPE_END_GROUP)); + break; + } + } +} + +uint8* WireFormat::SerializeUnknownFieldsToArray( + const UnknownFieldSet& unknown_fields, + uint8* target) { + for (int i = 0; i < unknown_fields.field_count(); i++) { + const UnknownField& field = unknown_fields.field(i); + + switch (field.type()) { + case UnknownField::TYPE_VARINT: + target = WireFormatLite::WriteInt64ToArray( + field.number(), field.varint(), target); + break; + case UnknownField::TYPE_FIXED32: + target = WireFormatLite::WriteFixed32ToArray( + field.number(), field.fixed32(), target); + break; + case UnknownField::TYPE_FIXED64: + target = WireFormatLite::WriteFixed64ToArray( + field.number(), field.fixed64(), target); + break; + case UnknownField::TYPE_LENGTH_DELIMITED: + target = WireFormatLite::WriteBytesToArray( + field.number(), field.length_delimited(), target); + break; + case UnknownField::TYPE_GROUP: + target = WireFormatLite::WriteTagToArray( + field.number(), WireFormatLite::WIRETYPE_START_GROUP, target); + target = SerializeUnknownFieldsToArray(field.group(), target); + target = WireFormatLite::WriteTagToArray( + field.number(), WireFormatLite::WIRETYPE_END_GROUP, target); + break; + } + } + return target; +} + +void WireFormat::SerializeUnknownMessageSetItems( + const UnknownFieldSet& unknown_fields, + io::CodedOutputStream* output) { + for (int i = 0; i < unknown_fields.field_count(); i++) { + const UnknownField& field = unknown_fields.field(i); + // The only unknown fields that are allowed to exist in a MessageSet are + // messages, which are length-delimited. + if (field.type() == UnknownField::TYPE_LENGTH_DELIMITED) { + const string& data = field.length_delimited(); + + // Start group. + output->WriteVarint32(WireFormatLite::kMessageSetItemStartTag); + + // Write type ID. + output->WriteVarint32(WireFormatLite::kMessageSetTypeIdTag); + output->WriteVarint32(field.number()); + + // Write message. + output->WriteVarint32(WireFormatLite::kMessageSetMessageTag); + output->WriteVarint32(data.size()); + output->WriteString(data); + + // End group. + output->WriteVarint32(WireFormatLite::kMessageSetItemEndTag); + } + } +} + +uint8* WireFormat::SerializeUnknownMessageSetItemsToArray( + const UnknownFieldSet& unknown_fields, + uint8* target) { + for (int i = 0; i < unknown_fields.field_count(); i++) { + const UnknownField& field = unknown_fields.field(i); + + // The only unknown fields that are allowed to exist in a MessageSet are + // messages, which are length-delimited. + if (field.type() == UnknownField::TYPE_LENGTH_DELIMITED) { + const string& data = field.length_delimited(); + + // Start group. + target = io::CodedOutputStream::WriteTagToArray( + WireFormatLite::kMessageSetItemStartTag, target); + + // Write type ID. + target = io::CodedOutputStream::WriteTagToArray( + WireFormatLite::kMessageSetTypeIdTag, target); + target = io::CodedOutputStream::WriteVarint32ToArray( + field.number(), target); + + // Write message. + target = io::CodedOutputStream::WriteTagToArray( + WireFormatLite::kMessageSetMessageTag, target); + target = io::CodedOutputStream::WriteVarint32ToArray(data.size(), target); + target = io::CodedOutputStream::WriteStringToArray(data, target); + + // End group. + target = io::CodedOutputStream::WriteTagToArray( + WireFormatLite::kMessageSetItemEndTag, target); + } + } + + return target; +} + +int WireFormat::ComputeUnknownFieldsSize( + const UnknownFieldSet& unknown_fields) { + int size = 0; + for (int i = 0; i < unknown_fields.field_count(); i++) { + const UnknownField& field = unknown_fields.field(i); + + switch (field.type()) { + case UnknownField::TYPE_VARINT: + size += io::CodedOutputStream::VarintSize32( + WireFormatLite::MakeTag(field.number(), + WireFormatLite::WIRETYPE_VARINT)); + size += io::CodedOutputStream::VarintSize64(field.varint()); + break; + case UnknownField::TYPE_FIXED32: + size += io::CodedOutputStream::VarintSize32( + WireFormatLite::MakeTag(field.number(), + WireFormatLite::WIRETYPE_FIXED32)); + size += sizeof(int32); + break; + case UnknownField::TYPE_FIXED64: + size += io::CodedOutputStream::VarintSize32( + WireFormatLite::MakeTag(field.number(), + WireFormatLite::WIRETYPE_FIXED64)); + size += sizeof(int64); + break; + case UnknownField::TYPE_LENGTH_DELIMITED: + size += io::CodedOutputStream::VarintSize32( + WireFormatLite::MakeTag(field.number(), + WireFormatLite::WIRETYPE_LENGTH_DELIMITED)); + size += io::CodedOutputStream::VarintSize32( + field.length_delimited().size()); + size += field.length_delimited().size(); + break; + case UnknownField::TYPE_GROUP: + size += io::CodedOutputStream::VarintSize32( + WireFormatLite::MakeTag(field.number(), + WireFormatLite::WIRETYPE_START_GROUP)); + size += ComputeUnknownFieldsSize(field.group()); + size += io::CodedOutputStream::VarintSize32( + WireFormatLite::MakeTag(field.number(), + WireFormatLite::WIRETYPE_END_GROUP)); + break; + } + } + + return size; +} + +int WireFormat::ComputeUnknownMessageSetItemsSize( + const UnknownFieldSet& unknown_fields) { + int size = 0; + for (int i = 0; i < unknown_fields.field_count(); i++) { + const UnknownField& field = unknown_fields.field(i); + + // The only unknown fields that are allowed to exist in a MessageSet are + // messages, which are length-delimited. + if (field.type() == UnknownField::TYPE_LENGTH_DELIMITED) { + size += WireFormatLite::kMessageSetItemTagsSize; + size += io::CodedOutputStream::VarintSize32(field.number()); + size += io::CodedOutputStream::VarintSize32( + field.length_delimited().size()); + size += field.length_delimited().size(); + } + } + + return size; +} + +// =================================================================== + +bool WireFormat::ParseAndMergePartial(io::CodedInputStream* input, + Message* message) { + const Descriptor* descriptor = message->GetDescriptor(); + const Reflection* message_reflection = message->GetReflection(); + + while(true) { + uint32 tag = input->ReadTag(); + if (tag == 0) { + // End of input. This is a valid place to end, so return true. + return true; + } + + if (WireFormatLite::GetTagWireType(tag) == + WireFormatLite::WIRETYPE_END_GROUP) { + // Must be the end of the message. + return true; + } + + const FieldDescriptor* field = NULL; + + if (descriptor != NULL) { + int field_number = WireFormatLite::GetTagFieldNumber(tag); + field = descriptor->FindFieldByNumber(field_number); + + // If that failed, check if the field is an extension. + if (field == NULL && descriptor->IsExtensionNumber(field_number)) { + if (input->GetExtensionPool() == NULL) { + field = message_reflection->FindKnownExtensionByNumber(field_number); + } else { + field = input->GetExtensionPool() + ->FindExtensionByNumber(descriptor, field_number); + } + } + + // If that failed, but we're a MessageSet, and this is the tag for a + // MessageSet item, then parse that. + if (field == NULL && + descriptor->options().message_set_wire_format() && + tag == WireFormatLite::kMessageSetItemStartTag) { + if (!ParseAndMergeMessageSetItem(input, message)) { + return false; + } + continue; // Skip ParseAndMergeField(); already taken care of. + } + } + + if (!ParseAndMergeField(tag, field, message, input)) { + return false; + } + } +} + +bool WireFormat::ParseAndMergeField( + uint32 tag, + const FieldDescriptor* field, // May be NULL for unknown + Message* message, + io::CodedInputStream* input) { + const Reflection* message_reflection = message->GetReflection(); + + enum { UNKNOWN, NORMAL_FORMAT, PACKED_FORMAT } value_format; + + if (field == NULL) { + value_format = UNKNOWN; + } else if (WireFormatLite::GetTagWireType(tag) == + WireTypeForFieldType(field->type())) { + value_format = NORMAL_FORMAT; + } else if (field->is_packable() && + WireFormatLite::GetTagWireType(tag) == + WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + value_format = PACKED_FORMAT; + } else { + // We don't recognize this field. Either the field number is unknown + // or the wire type doesn't match. Put it in our unknown field set. + value_format = UNKNOWN; + } + + if (value_format == UNKNOWN) { + return SkipField(input, tag, + message_reflection->MutableUnknownFields(message)); + } else if (value_format == PACKED_FORMAT) { + uint32 length; + if (!input->ReadVarint32(&length)) return false; + io::CodedInputStream::Limit limit = input->PushLimit(length); + + switch (field->type()) { +#define HANDLE_PACKED_TYPE(TYPE, CPPTYPE, CPPTYPE_METHOD) \ + case FieldDescriptor::TYPE_##TYPE: { \ + while (input->BytesUntilLimit() > 0) { \ + CPPTYPE value; \ + if (!WireFormatLite::ReadPrimitive< \ + CPPTYPE, WireFormatLite::TYPE_##TYPE>(input, &value)) \ + return false; \ + message_reflection->Add##CPPTYPE_METHOD(message, field, value); \ + } \ + break; \ + } + + HANDLE_PACKED_TYPE( INT32, int32, Int32) + HANDLE_PACKED_TYPE( INT64, int64, Int64) + HANDLE_PACKED_TYPE(SINT32, int32, Int32) + HANDLE_PACKED_TYPE(SINT64, int64, Int64) + HANDLE_PACKED_TYPE(UINT32, uint32, UInt32) + HANDLE_PACKED_TYPE(UINT64, uint64, UInt64) + + HANDLE_PACKED_TYPE( FIXED32, uint32, UInt32) + HANDLE_PACKED_TYPE( FIXED64, uint64, UInt64) + HANDLE_PACKED_TYPE(SFIXED32, int32, Int32) + HANDLE_PACKED_TYPE(SFIXED64, int64, Int64) + + HANDLE_PACKED_TYPE(FLOAT , float , Float ) + HANDLE_PACKED_TYPE(DOUBLE, double, Double) + + HANDLE_PACKED_TYPE(BOOL, bool, Bool) +#undef HANDLE_PACKED_TYPE + + case FieldDescriptor::TYPE_ENUM: { + while (input->BytesUntilLimit() > 0) { + int value; + if (!WireFormatLite::ReadPrimitive( + input, &value)) return false; + const EnumValueDescriptor* enum_value = + field->enum_type()->FindValueByNumber(value); + if (enum_value != NULL) { + message_reflection->AddEnum(message, field, enum_value); + } + } + + break; + } + + case FieldDescriptor::TYPE_STRING: + case FieldDescriptor::TYPE_GROUP: + case FieldDescriptor::TYPE_MESSAGE: + case FieldDescriptor::TYPE_BYTES: + // Can't have packed fields of these types: these should be caught by + // the protocol compiler. + return false; + break; + } + + input->PopLimit(limit); + } else { + // Non-packed value (value_format == NORMAL_FORMAT) + switch (field->type()) { +#define HANDLE_TYPE(TYPE, CPPTYPE, CPPTYPE_METHOD) \ + case FieldDescriptor::TYPE_##TYPE: { \ + CPPTYPE value; \ + if (!WireFormatLite::ReadPrimitive< \ + CPPTYPE, WireFormatLite::TYPE_##TYPE>(input, &value)) \ + return false; \ + if (field->is_repeated()) { \ + message_reflection->Add##CPPTYPE_METHOD(message, field, value); \ + } else { \ + message_reflection->Set##CPPTYPE_METHOD(message, field, value); \ + } \ + break; \ + } + + HANDLE_TYPE( INT32, int32, Int32) + HANDLE_TYPE( INT64, int64, Int64) + HANDLE_TYPE(SINT32, int32, Int32) + HANDLE_TYPE(SINT64, int64, Int64) + HANDLE_TYPE(UINT32, uint32, UInt32) + HANDLE_TYPE(UINT64, uint64, UInt64) + + HANDLE_TYPE( FIXED32, uint32, UInt32) + HANDLE_TYPE( FIXED64, uint64, UInt64) + HANDLE_TYPE(SFIXED32, int32, Int32) + HANDLE_TYPE(SFIXED64, int64, Int64) + + HANDLE_TYPE(FLOAT , float , Float ) + HANDLE_TYPE(DOUBLE, double, Double) + + HANDLE_TYPE(BOOL, bool, Bool) +#undef HANDLE_TYPE + + case FieldDescriptor::TYPE_ENUM: { + int value; + if (!WireFormatLite::ReadPrimitive( + input, &value)) return false; + const EnumValueDescriptor* enum_value = + field->enum_type()->FindValueByNumber(value); + if (enum_value != NULL) { + if (field->is_repeated()) { + message_reflection->AddEnum(message, field, enum_value); + } else { + message_reflection->SetEnum(message, field, enum_value); + } + } else { + // The enum value is not one of the known values. Add it to the + // UnknownFieldSet. + int64 sign_extended_value = static_cast(value); + message_reflection->MutableUnknownFields(message) + ->AddVarint(WireFormatLite::GetTagFieldNumber(tag), + sign_extended_value); + } + break; + } + + // Handle strings separately so that we can optimize the ctype=CORD case. + case FieldDescriptor::TYPE_STRING: { + string value; + if (!WireFormatLite::ReadString(input, &value)) return false; + VerifyUTF8String(value.data(), value.length(), PARSE); + if (field->is_repeated()) { + message_reflection->AddString(message, field, value); + } else { + message_reflection->SetString(message, field, value); + } + break; + } + + case FieldDescriptor::TYPE_BYTES: { + string value; + if (!WireFormatLite::ReadBytes(input, &value)) return false; + if (field->is_repeated()) { + message_reflection->AddString(message, field, value); + } else { + message_reflection->SetString(message, field, value); + } + break; + } + + case FieldDescriptor::TYPE_GROUP: { + Message* sub_message; + if (field->is_repeated()) { + sub_message = message_reflection->AddMessage( + message, field, input->GetExtensionFactory()); + } else { + sub_message = message_reflection->MutableMessage( + message, field, input->GetExtensionFactory()); + } + + if (!WireFormatLite::ReadGroup(WireFormatLite::GetTagFieldNumber(tag), + input, sub_message)) + return false; + break; + } + + case FieldDescriptor::TYPE_MESSAGE: { + Message* sub_message; + if (field->is_repeated()) { + sub_message = message_reflection->AddMessage( + message, field, input->GetExtensionFactory()); + } else { + sub_message = message_reflection->MutableMessage( + message, field, input->GetExtensionFactory()); + } + + if (!WireFormatLite::ReadMessage(input, sub_message)) return false; + break; + } + } + } + + return true; +} + +bool WireFormat::ParseAndMergeMessageSetItem( + io::CodedInputStream* input, + Message* message) { + const Reflection* message_reflection = message->GetReflection(); + + // This method parses a group which should contain two fields: + // required int32 type_id = 2; + // required data message = 3; + + // Once we see a type_id, we'll construct a fake tag for this extension + // which is the tag it would have had under the proto2 extensions wire + // format. + uint32 fake_tag = 0; + + // Once we see a type_id, we'll look up the FieldDescriptor for the + // extension. + const FieldDescriptor* field = NULL; + + // If we see message data before the type_id, we'll append it to this so + // we can parse it later. This will probably never happen in practice, + // as no MessageSet encoder I know of writes the message before the type ID. + // But, it's technically valid so we should allow it. + // TODO(kenton): Use a Cord instead? Do I care? + string message_data; + + while (true) { + uint32 tag = input->ReadTag(); + if (tag == 0) return false; + + switch (tag) { + case WireFormatLite::kMessageSetTypeIdTag: { + uint32 type_id; + if (!input->ReadVarint32(&type_id)) return false; + fake_tag = WireFormatLite::MakeTag( + type_id, WireFormatLite::WIRETYPE_LENGTH_DELIMITED); + field = message_reflection->FindKnownExtensionByNumber(type_id); + + if (!message_data.empty()) { + // We saw some message data before the type_id. Have to parse it + // now. + io::ArrayInputStream raw_input(message_data.data(), + message_data.size()); + io::CodedInputStream sub_input(&raw_input); + if (!ParseAndMergeField(fake_tag, field, message, + &sub_input)) { + return false; + } + message_data.clear(); + } + + break; + } + + case WireFormatLite::kMessageSetMessageTag: { + if (fake_tag == 0) { + // We haven't seen a type_id yet. Append this data to message_data. + string temp; + uint32 length; + if (!input->ReadVarint32(&length)) return false; + if (!input->ReadString(&temp, length)) return false; + message_data.append(temp); + } else { + // Already saw type_id, so we can parse this directly. + if (!ParseAndMergeField(fake_tag, field, message, input)) { + return false; + } + } + + break; + } + + case WireFormatLite::kMessageSetItemEndTag: { + return true; + } + + default: { + if (!SkipField(input, tag, NULL)) return false; + } + } + } +} + +// =================================================================== + +void WireFormat::SerializeWithCachedSizes( + const Message& message, + int size, io::CodedOutputStream* output) { + const Descriptor* descriptor = message.GetDescriptor(); + const Reflection* message_reflection = message.GetReflection(); + int expected_endpoint = output->ByteCount() + size; + + vector fields; + message_reflection->ListFields(message, &fields); + for (int i = 0; i < fields.size(); i++) { + SerializeFieldWithCachedSizes(fields[i], message, output); + } + + if (descriptor->options().message_set_wire_format()) { + SerializeUnknownMessageSetItems( + message_reflection->GetUnknownFields(message), output); + } else { + SerializeUnknownFields( + message_reflection->GetUnknownFields(message), output); + } + + GOOGLE_CHECK_EQ(output->ByteCount(), expected_endpoint) + << ": Protocol message serialized to a size different from what was " + "originally expected. Perhaps it was modified by another thread " + "during serialization?"; +} + +void WireFormat::SerializeFieldWithCachedSizes( + const FieldDescriptor* field, + const Message& message, + io::CodedOutputStream* output) { + const Reflection* message_reflection = message.GetReflection(); + + if (field->is_extension() && + field->containing_type()->options().message_set_wire_format() && + field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && + !field->is_repeated()) { + SerializeMessageSetItemWithCachedSizes(field, message, output); + return; + } + + int count = 0; + + if (field->is_repeated()) { + count = message_reflection->FieldSize(message, field); + } else if (message_reflection->HasField(message, field)) { + count = 1; + } + + const bool is_packed = field->options().packed(); + if (is_packed && count > 0) { + WireFormatLite::WriteTag(field->number(), + WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output); + const int data_size = FieldDataOnlyByteSize(field, message); + output->WriteVarint32(data_size); + } + + for (int j = 0; j < count; j++) { + switch (field->type()) { +#define HANDLE_PRIMITIVE_TYPE(TYPE, CPPTYPE, TYPE_METHOD, CPPTYPE_METHOD) \ + case FieldDescriptor::TYPE_##TYPE: { \ + const CPPTYPE value = field->is_repeated() ? \ + message_reflection->GetRepeated##CPPTYPE_METHOD( \ + message, field, j) : \ + message_reflection->Get##CPPTYPE_METHOD( \ + message, field); \ + if (is_packed) { \ + WireFormatLite::Write##TYPE_METHOD##NoTag(value, output); \ + } else { \ + WireFormatLite::Write##TYPE_METHOD(field->number(), value, output); \ + } \ + break; \ + } + + HANDLE_PRIMITIVE_TYPE( INT32, int32, Int32, Int32) + HANDLE_PRIMITIVE_TYPE( INT64, int64, Int64, Int64) + HANDLE_PRIMITIVE_TYPE(SINT32, int32, SInt32, Int32) + HANDLE_PRIMITIVE_TYPE(SINT64, int64, SInt64, Int64) + HANDLE_PRIMITIVE_TYPE(UINT32, uint32, UInt32, UInt32) + HANDLE_PRIMITIVE_TYPE(UINT64, uint64, UInt64, UInt64) + + HANDLE_PRIMITIVE_TYPE( FIXED32, uint32, Fixed32, UInt32) + HANDLE_PRIMITIVE_TYPE( FIXED64, uint64, Fixed64, UInt64) + HANDLE_PRIMITIVE_TYPE(SFIXED32, int32, SFixed32, Int32) + HANDLE_PRIMITIVE_TYPE(SFIXED64, int64, SFixed64, Int64) + + HANDLE_PRIMITIVE_TYPE(FLOAT , float , Float , Float ) + HANDLE_PRIMITIVE_TYPE(DOUBLE, double, Double, Double) + + HANDLE_PRIMITIVE_TYPE(BOOL, bool, Bool, Bool) +#undef HANDLE_PRIMITIVE_TYPE + +#define HANDLE_TYPE(TYPE, TYPE_METHOD, CPPTYPE_METHOD) \ + case FieldDescriptor::TYPE_##TYPE: \ + WireFormatLite::Write##TYPE_METHOD( \ + field->number(), \ + field->is_repeated() ? \ + message_reflection->GetRepeated##CPPTYPE_METHOD( \ + message, field, j) : \ + message_reflection->Get##CPPTYPE_METHOD(message, field), \ + output); \ + break; + + HANDLE_TYPE(GROUP , Group , Message) + HANDLE_TYPE(MESSAGE, Message, Message) +#undef HANDLE_TYPE + + case FieldDescriptor::TYPE_ENUM: { + const EnumValueDescriptor* value = field->is_repeated() ? + message_reflection->GetRepeatedEnum(message, field, j) : + message_reflection->GetEnum(message, field); + if (is_packed) { + WireFormatLite::WriteEnumNoTag(value->number(), output); + } else { + WireFormatLite::WriteEnum(field->number(), value->number(), output); + } + break; + } + + // Handle strings separately so that we can get string references + // instead of copying. + case FieldDescriptor::TYPE_STRING: { + string scratch; + const string& value = field->is_repeated() ? + message_reflection->GetRepeatedStringReference( + message, field, j, &scratch) : + message_reflection->GetStringReference(message, field, &scratch); + VerifyUTF8String(value.data(), value.length(), SERIALIZE); + WireFormatLite::WriteString(field->number(), value, output); + break; + } + + case FieldDescriptor::TYPE_BYTES: { + string scratch; + const string& value = field->is_repeated() ? + message_reflection->GetRepeatedStringReference( + message, field, j, &scratch) : + message_reflection->GetStringReference(message, field, &scratch); + WireFormatLite::WriteBytes(field->number(), value, output); + break; + } + } + } +} + +void WireFormat::SerializeMessageSetItemWithCachedSizes( + const FieldDescriptor* field, + const Message& message, + io::CodedOutputStream* output) { + const Reflection* message_reflection = message.GetReflection(); + + // Start group. + output->WriteVarint32(WireFormatLite::kMessageSetItemStartTag); + + // Write type ID. + output->WriteVarint32(WireFormatLite::kMessageSetTypeIdTag); + output->WriteVarint32(field->number()); + + // Write message. + output->WriteVarint32(WireFormatLite::kMessageSetMessageTag); + + const Message& sub_message = message_reflection->GetMessage(message, field); + output->WriteVarint32(sub_message.GetCachedSize()); + sub_message.SerializeWithCachedSizes(output); + + // End group. + output->WriteVarint32(WireFormatLite::kMessageSetItemEndTag); +} + +// =================================================================== + +int WireFormat::ByteSize(const Message& message) { + const Descriptor* descriptor = message.GetDescriptor(); + const Reflection* message_reflection = message.GetReflection(); + + int our_size = 0; + + vector fields; + message_reflection->ListFields(message, &fields); + for (int i = 0; i < fields.size(); i++) { + our_size += FieldByteSize(fields[i], message); + } + + if (descriptor->options().message_set_wire_format()) { + our_size += ComputeUnknownMessageSetItemsSize( + message_reflection->GetUnknownFields(message)); + } else { + our_size += ComputeUnknownFieldsSize( + message_reflection->GetUnknownFields(message)); + } + + return our_size; +} + +int WireFormat::FieldByteSize( + const FieldDescriptor* field, + const Message& message) { + const Reflection* message_reflection = message.GetReflection(); + + if (field->is_extension() && + field->containing_type()->options().message_set_wire_format() && + field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && + !field->is_repeated()) { + return MessageSetItemByteSize(field, message); + } + + int count = 0; + if (field->is_repeated()) { + count = message_reflection->FieldSize(message, field); + } else if (message_reflection->HasField(message, field)) { + count = 1; + } + + const int data_size = FieldDataOnlyByteSize(field, message); + int our_size = data_size; + if (field->options().packed()) { + if (data_size > 0) { + // Packed fields get serialized like a string, not their native type. + // Technically this doesn't really matter; the size only changes if it's + // a GROUP + our_size += TagSize(field->number(), FieldDescriptor::TYPE_STRING); + our_size += io::CodedOutputStream::VarintSize32(data_size); + } + } else { + our_size += count * TagSize(field->number(), field->type()); + } + return our_size; +} + +int WireFormat::FieldDataOnlyByteSize( + const FieldDescriptor* field, + const Message& message) { + const Reflection* message_reflection = message.GetReflection(); + + int count = 0; + if (field->is_repeated()) { + count = message_reflection->FieldSize(message, field); + } else if (message_reflection->HasField(message, field)) { + count = 1; + } + + int data_size = 0; + switch (field->type()) { +#define HANDLE_TYPE(TYPE, TYPE_METHOD, CPPTYPE_METHOD) \ + case FieldDescriptor::TYPE_##TYPE: \ + if (field->is_repeated()) { \ + for (int j = 0; j < count; j++) { \ + data_size += WireFormatLite::TYPE_METHOD##Size( \ + message_reflection->GetRepeated##CPPTYPE_METHOD( \ + message, field, j)); \ + } \ + } else { \ + data_size += WireFormatLite::TYPE_METHOD##Size( \ + message_reflection->Get##CPPTYPE_METHOD(message, field)); \ + } \ + break; + +#define HANDLE_FIXED_TYPE(TYPE, TYPE_METHOD) \ + case FieldDescriptor::TYPE_##TYPE: \ + data_size += count * WireFormatLite::k##TYPE_METHOD##Size; \ + break; + + HANDLE_TYPE( INT32, Int32, Int32) + HANDLE_TYPE( INT64, Int64, Int64) + HANDLE_TYPE(SINT32, SInt32, Int32) + HANDLE_TYPE(SINT64, SInt64, Int64) + HANDLE_TYPE(UINT32, UInt32, UInt32) + HANDLE_TYPE(UINT64, UInt64, UInt64) + + HANDLE_FIXED_TYPE( FIXED32, Fixed32) + HANDLE_FIXED_TYPE( FIXED64, Fixed64) + HANDLE_FIXED_TYPE(SFIXED32, SFixed32) + HANDLE_FIXED_TYPE(SFIXED64, SFixed64) + + HANDLE_FIXED_TYPE(FLOAT , Float ) + HANDLE_FIXED_TYPE(DOUBLE, Double) + + HANDLE_FIXED_TYPE(BOOL, Bool) + + HANDLE_TYPE(GROUP , Group , Message) + HANDLE_TYPE(MESSAGE, Message, Message) +#undef HANDLE_TYPE +#undef HANDLE_FIXED_TYPE + + case FieldDescriptor::TYPE_ENUM: { + if (field->is_repeated()) { + for (int j = 0; j < count; j++) { + data_size += WireFormatLite::EnumSize( + message_reflection->GetRepeatedEnum(message, field, j)->number()); + } + } else { + data_size += WireFormatLite::EnumSize( + message_reflection->GetEnum(message, field)->number()); + } + break; + } + + // Handle strings separately so that we can get string references + // instead of copying. + case FieldDescriptor::TYPE_STRING: + case FieldDescriptor::TYPE_BYTES: { + for (int j = 0; j < count; j++) { + string scratch; + const string& value = field->is_repeated() ? + message_reflection->GetRepeatedStringReference( + message, field, j, &scratch) : + message_reflection->GetStringReference(message, field, &scratch); + data_size += WireFormatLite::StringSize(value); + } + break; + } + } + return data_size; +} + +int WireFormat::MessageSetItemByteSize( + const FieldDescriptor* field, + const Message& message) { + const Reflection* message_reflection = message.GetReflection(); + + int our_size = WireFormatLite::kMessageSetItemTagsSize; + + // type_id + our_size += io::CodedOutputStream::VarintSize32(field->number()); + + // message + const Message& sub_message = message_reflection->GetMessage(message, field); + int message_size = sub_message.ByteSize(); + + our_size += io::CodedOutputStream::VarintSize32(message_size); + our_size += message_size; + + return our_size; +} + +void WireFormat::VerifyUTF8StringFallback(const char* data, + int size, + Operation op) { + if (!IsStructurallyValidUTF8(data, size)) { + const char* operation_str = NULL; + switch (op) { + case PARSE: + operation_str = "parsing"; + break; + case SERIALIZE: + operation_str = "serializing"; + break; + // no default case: have the compiler warn if a case is not covered. + } + GOOGLE_LOG(ERROR) << "Encountered string containing invalid UTF-8 data while " + << operation_str + << " protocol buffer. Strings must contain only UTF-8; " + "use the 'bytes' type for raw bytes."; + } +} + + +} // namespace internal +} // namespace protobuf +} // namespace google diff --git a/depends/protobuf/google/protobuf/wire_format.h b/depends/protobuf/google/protobuf/wire_format.h new file mode 100644 index 0000000000..c753925085 --- /dev/null +++ b/depends/protobuf/google/protobuf/wire_format.h @@ -0,0 +1,304 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// atenasio@google.com (Chris Atenasio) (ZigZag transform) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// This header is logically internal, but is made public because it is used +// from protocol-compiler-generated code, which may reside in other components. + +#ifndef GOOGLE_PROTOBUF_WIRE_FORMAT_H__ +#define GOOGLE_PROTOBUF_WIRE_FORMAT_H__ + +#include +#include +#include +#include +#include + +// Do UTF-8 validation on string type in Debug build only +#ifndef NDEBUG +#define GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED +#endif + +namespace google { +namespace protobuf { + namespace io { + class CodedInputStream; // coded_stream.h + class CodedOutputStream; // coded_stream.h + } + class UnknownFieldSet; // unknown_field_set.h +} + +namespace protobuf { +namespace internal { + +// This class is for internal use by the protocol buffer library and by +// protocol-complier-generated message classes. It must not be called +// directly by clients. +// +// This class contains code for implementing the binary protocol buffer +// wire format via reflection. The WireFormatLite class implements the +// non-reflection based routines. +// +// This class is really a namespace that contains only static methods +class LIBPROTOBUF_EXPORT WireFormat { + public: + + // Given a field return its WireType + static inline WireFormatLite::WireType WireTypeForField( + const FieldDescriptor* field); + + // Given a FieldSescriptor::Type return its WireType + static inline WireFormatLite::WireType WireTypeForFieldType( + FieldDescriptor::Type type); + + // Compute the byte size of a tag. For groups, this includes both the start + // and end tags. + static inline int TagSize(int field_number, FieldDescriptor::Type type); + + // These procedures can be used to implement the methods of Message which + // handle parsing and serialization of the protocol buffer wire format + // using only the Reflection interface. When you ask the protocol + // compiler to optimize for code size rather than speed, it will implement + // those methods in terms of these procedures. Of course, these are much + // slower than the specialized implementations which the protocol compiler + // generates when told to optimize for speed. + + // Read a message in protocol buffer wire format. + // + // This procedure reads either to the end of the input stream or through + // a WIRETYPE_END_GROUP tag ending the message, whichever comes first. + // It returns false if the input is invalid. + // + // Required fields are NOT checked by this method. You must call + // IsInitialized() on the resulting message yourself. + static bool ParseAndMergePartial(io::CodedInputStream* input, + Message* message); + + // Serialize a message in protocol buffer wire format. + // + // Any embedded messages within the message must have their correct sizes + // cached. However, the top-level message need not; its size is passed as + // a parameter to this procedure. + // + // These return false iff the underlying stream returns a write error. + static void SerializeWithCachedSizes( + const Message& message, + int size, io::CodedOutputStream* output); + + // Implements Message::ByteSize() via reflection. WARNING: The result + // of this method is *not* cached anywhere. However, all embedded messages + // will have their ByteSize() methods called, so their sizes will be cached. + // Therefore, calling this method is sufficient to allow you to call + // WireFormat::SerializeWithCachedSizes() on the same object. + static int ByteSize(const Message& message); + + // ----------------------------------------------------------------- + // Helpers for dealing with unknown fields + + // Skips a field value of the given WireType. The input should start + // positioned immediately after the tag. If unknown_fields is non-NULL, + // the contents of the field will be added to it. + static bool SkipField(io::CodedInputStream* input, uint32 tag, + UnknownFieldSet* unknown_fields); + + // Reads and ignores a message from the input. If unknown_fields is non-NULL, + // the contents will be added to it. + static bool SkipMessage(io::CodedInputStream* input, + UnknownFieldSet* unknown_fields); + + // Write the contents of an UnknownFieldSet to the output. + static void SerializeUnknownFields(const UnknownFieldSet& unknown_fields, + io::CodedOutputStream* output); + // Same as above, except writing directly to the provided buffer. + // Requires that the buffer have sufficient capacity for + // ComputeUnknownFieldsSize(unknown_fields). + // + // Returns a pointer past the last written byte. + static uint8* SerializeUnknownFieldsToArray( + const UnknownFieldSet& unknown_fields, + uint8* target); + + // Same thing except for messages that have the message_set_wire_format + // option. + static void SerializeUnknownMessageSetItems( + const UnknownFieldSet& unknown_fields, + io::CodedOutputStream* output); + // Same as above, except writing directly to the provided buffer. + // Requires that the buffer have sufficient capacity for + // ComputeUnknownMessageSetItemsSize(unknown_fields). + // + // Returns a pointer past the last written byte. + static uint8* SerializeUnknownMessageSetItemsToArray( + const UnknownFieldSet& unknown_fields, + uint8* target); + + // Compute the size of the UnknownFieldSet on the wire. + static int ComputeUnknownFieldsSize(const UnknownFieldSet& unknown_fields); + + // Same thing except for messages that have the message_set_wire_format + // option. + static int ComputeUnknownMessageSetItemsSize( + const UnknownFieldSet& unknown_fields); + + + // Helper functions for encoding and decoding tags. (Inlined below and in + // _inl.h) + // + // This is different from MakeTag(field->number(), field->type()) in the case + // of packed repeated fields. + static uint32 MakeTag(const FieldDescriptor* field); + + // Parse a single field. The input should start out positioned immidately + // after the tag. + static bool ParseAndMergeField( + uint32 tag, + const FieldDescriptor* field, // May be NULL for unknown + Message* message, + io::CodedInputStream* input); + + // Serialize a single field. + static void SerializeFieldWithCachedSizes( + const FieldDescriptor* field, // Cannot be NULL + const Message& message, + io::CodedOutputStream* output); + + // Compute size of a single field. If the field is a message type, this + // will call ByteSize() for the embedded message, insuring that it caches + // its size. + static int FieldByteSize( + const FieldDescriptor* field, // Cannot be NULL + const Message& message); + + // Parse/serialize a MessageSet::Item group. Used with messages that use + // opion message_set_wire_format = true. + static bool ParseAndMergeMessageSetItem( + io::CodedInputStream* input, + Message* message); + static void SerializeMessageSetItemWithCachedSizes( + const FieldDescriptor* field, + const Message& message, + io::CodedOutputStream* output); + static int MessageSetItemByteSize( + const FieldDescriptor* field, + const Message& message); + + // Computes the byte size of a field, excluding tags. For packed fields, it + // only includes the size of the raw data, and not the size of the total + // length, but for other length-delimited types, the size of the length is + // included. + static int FieldDataOnlyByteSize( + const FieldDescriptor* field, // Cannot be NULL + const Message& message); + + enum Operation { + PARSE, + SERIALIZE, + }; + + // Verifies that a string field is valid UTF8, logging an error if not. + static void VerifyUTF8String(const char* data, int size, Operation op); + + private: + // Verifies that a string field is valid UTF8, logging an error if not. + static void VerifyUTF8StringFallback( + const char* data, + int size, + Operation op); + + + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(WireFormat); +}; + +// Subclass of FieldSkipper which saves skipped fields to an UnknownFieldSet. +class LIBPROTOBUF_EXPORT UnknownFieldSetFieldSkipper : public FieldSkipper { + public: + UnknownFieldSetFieldSkipper(UnknownFieldSet* unknown_fields) + : unknown_fields_(unknown_fields) {} + virtual ~UnknownFieldSetFieldSkipper() {} + + // implements FieldSkipper ----------------------------------------- + virtual bool SkipField(io::CodedInputStream* input, uint32 tag); + virtual bool SkipMessage(io::CodedInputStream* input); + virtual void SkipUnknownEnum(int field_number, int value); + + private: + UnknownFieldSet* unknown_fields_; +}; + +// inline methods ==================================================== + +inline WireFormatLite::WireType WireFormat::WireTypeForField( + const FieldDescriptor* field) { + if (field->options().packed()) { + return WireFormatLite::WIRETYPE_LENGTH_DELIMITED; + } else { + return WireTypeForFieldType(field->type()); + } +} + +inline WireFormatLite::WireType WireFormat::WireTypeForFieldType( + FieldDescriptor::Type type) { + // Some compilers don't like enum -> enum casts, so we implicit_cast to + // int first. + return WireFormatLite::WireTypeForFieldType( + static_cast( + implicit_cast(type))); +} + +inline uint32 WireFormat::MakeTag(const FieldDescriptor* field) { + return WireFormatLite::MakeTag(field->number(), WireTypeForField(field)); +} + +inline int WireFormat::TagSize(int field_number, FieldDescriptor::Type type) { + // Some compilers don't like enum -> enum casts, so we implicit_cast to + // int first. + return WireFormatLite::TagSize(field_number, + static_cast( + implicit_cast(type))); +} + +inline void WireFormat::VerifyUTF8String(const char* data, int size, + WireFormat::Operation op) { +#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED + WireFormat::VerifyUTF8StringFallback(data, size, op); +#endif +} + + +} // namespace internal +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_WIRE_FORMAT_H__ diff --git a/depends/protobuf/google/protobuf/wire_format_lite.cc b/depends/protobuf/google/protobuf/wire_format_lite.cc new file mode 100644 index 0000000000..d347d11697 --- /dev/null +++ b/depends/protobuf/google/protobuf/wire_format_lite.cc @@ -0,0 +1,359 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { +namespace internal { + +#ifndef _MSC_VER // MSVC doesn't like definitions of inline constants, GCC + // requires them. +const int WireFormatLite::kMessageSetItemStartTag; +const int WireFormatLite::kMessageSetItemEndTag; +const int WireFormatLite::kMessageSetTypeIdTag; +const int WireFormatLite::kMessageSetMessageTag; + +#endif + +const int WireFormatLite::kMessageSetItemTagsSize = + io::CodedOutputStream::VarintSize32(kMessageSetItemStartTag) + + io::CodedOutputStream::VarintSize32(kMessageSetItemEndTag) + + io::CodedOutputStream::VarintSize32(kMessageSetTypeIdTag) + + io::CodedOutputStream::VarintSize32(kMessageSetMessageTag); + +const WireFormatLite::CppType +WireFormatLite::kFieldTypeToCppTypeMap[MAX_FIELD_TYPE + 1] = { + static_cast(0), // 0 is reserved for errors + + CPPTYPE_DOUBLE, // TYPE_DOUBLE + CPPTYPE_FLOAT, // TYPE_FLOAT + CPPTYPE_INT64, // TYPE_INT64 + CPPTYPE_UINT64, // TYPE_UINT64 + CPPTYPE_INT32, // TYPE_INT32 + CPPTYPE_UINT64, // TYPE_FIXED64 + CPPTYPE_UINT32, // TYPE_FIXED32 + CPPTYPE_BOOL, // TYPE_BOOL + CPPTYPE_STRING, // TYPE_STRING + CPPTYPE_MESSAGE, // TYPE_GROUP + CPPTYPE_MESSAGE, // TYPE_MESSAGE + CPPTYPE_STRING, // TYPE_BYTES + CPPTYPE_UINT32, // TYPE_UINT32 + CPPTYPE_ENUM, // TYPE_ENUM + CPPTYPE_INT32, // TYPE_SFIXED32 + CPPTYPE_INT64, // TYPE_SFIXED64 + CPPTYPE_INT32, // TYPE_SINT32 + CPPTYPE_INT64, // TYPE_SINT64 +}; + +const WireFormatLite::WireType +WireFormatLite::kWireTypeForFieldType[MAX_FIELD_TYPE + 1] = { + static_cast(-1), // invalid + WireFormatLite::WIRETYPE_FIXED64, // TYPE_DOUBLE + WireFormatLite::WIRETYPE_FIXED32, // TYPE_FLOAT + WireFormatLite::WIRETYPE_VARINT, // TYPE_INT64 + WireFormatLite::WIRETYPE_VARINT, // TYPE_UINT64 + WireFormatLite::WIRETYPE_VARINT, // TYPE_INT32 + WireFormatLite::WIRETYPE_FIXED64, // TYPE_FIXED64 + WireFormatLite::WIRETYPE_FIXED32, // TYPE_FIXED32 + WireFormatLite::WIRETYPE_VARINT, // TYPE_BOOL + WireFormatLite::WIRETYPE_LENGTH_DELIMITED, // TYPE_STRING + WireFormatLite::WIRETYPE_START_GROUP, // TYPE_GROUP + WireFormatLite::WIRETYPE_LENGTH_DELIMITED, // TYPE_MESSAGE + WireFormatLite::WIRETYPE_LENGTH_DELIMITED, // TYPE_BYTES + WireFormatLite::WIRETYPE_VARINT, // TYPE_UINT32 + WireFormatLite::WIRETYPE_VARINT, // TYPE_ENUM + WireFormatLite::WIRETYPE_FIXED32, // TYPE_SFIXED32 + WireFormatLite::WIRETYPE_FIXED64, // TYPE_SFIXED64 + WireFormatLite::WIRETYPE_VARINT, // TYPE_SINT32 + WireFormatLite::WIRETYPE_VARINT, // TYPE_SINT64 +}; + +bool WireFormatLite::SkipField( + io::CodedInputStream* input, uint32 tag) { + switch (WireFormatLite::GetTagWireType(tag)) { + case WireFormatLite::WIRETYPE_VARINT: { + uint64 value; + if (!input->ReadVarint64(&value)) return false; + return true; + } + case WireFormatLite::WIRETYPE_FIXED64: { + uint64 value; + if (!input->ReadLittleEndian64(&value)) return false; + return true; + } + case WireFormatLite::WIRETYPE_LENGTH_DELIMITED: { + uint32 length; + if (!input->ReadVarint32(&length)) return false; + if (!input->Skip(length)) return false; + return true; + } + case WireFormatLite::WIRETYPE_START_GROUP: { + if (!input->IncrementRecursionDepth()) return false; + if (!SkipMessage(input)) return false; + input->DecrementRecursionDepth(); + // Check that the ending tag matched the starting tag. + if (!input->LastTagWas(WireFormatLite::MakeTag( + WireFormatLite::GetTagFieldNumber(tag), + WireFormatLite::WIRETYPE_END_GROUP))) { + return false; + } + return true; + } + case WireFormatLite::WIRETYPE_END_GROUP: { + return false; + } + case WireFormatLite::WIRETYPE_FIXED32: { + uint32 value; + if (!input->ReadLittleEndian32(&value)) return false; + return true; + } + default: { + return false; + } + } +} + +bool WireFormatLite::SkipMessage(io::CodedInputStream* input) { + while(true) { + uint32 tag = input->ReadTag(); + if (tag == 0) { + // End of input. This is a valid place to end, so return true. + return true; + } + + WireFormatLite::WireType wire_type = WireFormatLite::GetTagWireType(tag); + + if (wire_type == WireFormatLite::WIRETYPE_END_GROUP) { + // Must be the end of the message. + return true; + } + + if (!SkipField(input, tag)) return false; + } +} + +bool FieldSkipper::SkipField( + io::CodedInputStream* input, uint32 tag) { + return WireFormatLite::SkipField(input, tag); +} + +bool FieldSkipper::SkipMessage(io::CodedInputStream* input) { + return WireFormatLite::SkipMessage(input); +} + +void FieldSkipper::SkipUnknownEnum( + int field_number, int value) { + // Nothing. +} + +bool WireFormatLite::ReadPackedEnumNoInline(io::CodedInputStream* input, + bool (*is_valid)(int), + RepeatedField* values) { + uint32 length; + if (!input->ReadVarint32(&length)) return false; + io::CodedInputStream::Limit limit = input->PushLimit(length); + while (input->BytesUntilLimit() > 0) { + int value; + if (!google::protobuf::internal::WireFormatLite::ReadPrimitive< + int, WireFormatLite::TYPE_ENUM>(input, &value)) { + return false; + } + if (is_valid(value)) { + values->Add(value); + } + } + input->PopLimit(limit); + return true; +} + +void WireFormatLite::WriteInt32(int field_number, int32 value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_VARINT, output); + WriteInt32NoTag(value, output); +} +void WireFormatLite::WriteInt64(int field_number, int64 value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_VARINT, output); + WriteInt64NoTag(value, output); +} +void WireFormatLite::WriteUInt32(int field_number, uint32 value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_VARINT, output); + WriteUInt32NoTag(value, output); +} +void WireFormatLite::WriteUInt64(int field_number, uint64 value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_VARINT, output); + WriteUInt64NoTag(value, output); +} +void WireFormatLite::WriteSInt32(int field_number, int32 value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_VARINT, output); + WriteSInt32NoTag(value, output); +} +void WireFormatLite::WriteSInt64(int field_number, int64 value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_VARINT, output); + WriteSInt64NoTag(value, output); +} +void WireFormatLite::WriteFixed32(int field_number, uint32 value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_FIXED32, output); + WriteFixed32NoTag(value, output); +} +void WireFormatLite::WriteFixed64(int field_number, uint64 value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_FIXED64, output); + WriteFixed64NoTag(value, output); +} +void WireFormatLite::WriteSFixed32(int field_number, int32 value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_FIXED32, output); + WriteSFixed32NoTag(value, output); +} +void WireFormatLite::WriteSFixed64(int field_number, int64 value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_FIXED64, output); + WriteSFixed64NoTag(value, output); +} +void WireFormatLite::WriteFloat(int field_number, float value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_FIXED32, output); + WriteFloatNoTag(value, output); +} +void WireFormatLite::WriteDouble(int field_number, double value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_FIXED64, output); + WriteDoubleNoTag(value, output); +} +void WireFormatLite::WriteBool(int field_number, bool value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_VARINT, output); + WriteBoolNoTag(value, output); +} +void WireFormatLite::WriteEnum(int field_number, int value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_VARINT, output); + WriteEnumNoTag(value, output); +} + +void WireFormatLite::WriteString(int field_number, const string& value, + io::CodedOutputStream* output) { + // String is for UTF-8 text only + WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output); + output->WriteVarint32(value.size()); + output->WriteString(value); +} +void WireFormatLite::WriteBytes(int field_number, const string& value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output); + output->WriteVarint32(value.size()); + output->WriteString(value); +} + + +void WireFormatLite::WriteGroup(int field_number, + const MessageLite& value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_START_GROUP, output); + value.SerializeWithCachedSizes(output); + WriteTag(field_number, WIRETYPE_END_GROUP, output); +} + +void WireFormatLite::WriteMessage(int field_number, + const MessageLite& value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output); + const int size = value.GetCachedSize(); + output->WriteVarint32(size); + value.SerializeWithCachedSizes(output); +} + +void WireFormatLite::WriteGroupMaybeToArray(int field_number, + const MessageLite& value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_START_GROUP, output); + const int size = value.GetCachedSize(); + uint8* target = output->GetDirectBufferForNBytesAndAdvance(size); + if (target != NULL) { + uint8* end = value.SerializeWithCachedSizesToArray(target); + GOOGLE_DCHECK_EQ(end - target, size); + } else { + value.SerializeWithCachedSizes(output); + } + WriteTag(field_number, WIRETYPE_END_GROUP, output); +} + +void WireFormatLite::WriteMessageMaybeToArray(int field_number, + const MessageLite& value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output); + const int size = value.GetCachedSize(); + output->WriteVarint32(size); + uint8* target = output->GetDirectBufferForNBytesAndAdvance(size); + if (target != NULL) { + uint8* end = value.SerializeWithCachedSizesToArray(target); + GOOGLE_DCHECK_EQ(end - target, size); + } else { + value.SerializeWithCachedSizes(output); + } +} + +bool WireFormatLite::ReadString(io::CodedInputStream* input, + string* value) { + // String is for UTF-8 text only + uint32 length; + if (!input->ReadVarint32(&length)) return false; + if (!input->InternalReadStringInline(value, length)) return false; + return true; +} +bool WireFormatLite::ReadBytes(io::CodedInputStream* input, + string* value) { + uint32 length; + if (!input->ReadVarint32(&length)) return false; + return input->InternalReadStringInline(value, length); +} + +} // namespace internal +} // namespace protobuf +} // namespace google diff --git a/depends/protobuf/google/protobuf/wire_format_lite.h b/depends/protobuf/google/protobuf/wire_format_lite.h new file mode 100644 index 0000000000..e3d5b2d8d0 --- /dev/null +++ b/depends/protobuf/google/protobuf/wire_format_lite.h @@ -0,0 +1,620 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// atenasio@google.com (Chris Atenasio) (ZigZag transform) +// wink@google.com (Wink Saville) (refactored from wire_format.h) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// This header is logically internal, but is made public because it is used +// from protocol-compiler-generated code, which may reside in other components. + +#ifndef GOOGLE_PROTOBUF_WIRE_FORMAT_LITE_H__ +#define GOOGLE_PROTOBUF_WIRE_FORMAT_LITE_H__ + +#include +#include + +namespace google { + +namespace protobuf { + template class RepeatedField; // repeated_field.h + namespace io { + class CodedInputStream; // coded_stream.h + class CodedOutputStream; // coded_stream.h + } +} + +namespace protobuf { +namespace internal { + +class StringPieceField; + +// This class is for internal use by the protocol buffer library and by +// protocol-complier-generated message classes. It must not be called +// directly by clients. +// +// This class contains helpers for implementing the binary protocol buffer +// wire format without the need for reflection. Use WireFormat when using +// reflection. +// +// This class is really a namespace that contains only static methods. +class LIBPROTOBUF_EXPORT WireFormatLite { + public: + + // ----------------------------------------------------------------- + // Helper constants and functions related to the format. These are + // mostly meant for internal and generated code to use. + + // The wire format is composed of a sequence of tag/value pairs, each + // of which contains the value of one field (or one element of a repeated + // field). Each tag is encoded as a varint. The lower bits of the tag + // identify its wire type, which specifies the format of the data to follow. + // The rest of the bits contain the field number. Each type of field (as + // declared by FieldDescriptor::Type, in descriptor.h) maps to one of + // these wire types. Immediately following each tag is the field's value, + // encoded in the format specified by the wire type. Because the tag + // identifies the encoding of this data, it is possible to skip + // unrecognized fields for forwards compatibility. + + enum WireType { + WIRETYPE_VARINT = 0, + WIRETYPE_FIXED64 = 1, + WIRETYPE_LENGTH_DELIMITED = 2, + WIRETYPE_START_GROUP = 3, + WIRETYPE_END_GROUP = 4, + WIRETYPE_FIXED32 = 5, + }; + + // Lite alternative to FieldDescriptor::Type. Must be kept in sync. + enum FieldType { + TYPE_DOUBLE = 1, + TYPE_FLOAT = 2, + TYPE_INT64 = 3, + TYPE_UINT64 = 4, + TYPE_INT32 = 5, + TYPE_FIXED64 = 6, + TYPE_FIXED32 = 7, + TYPE_BOOL = 8, + TYPE_STRING = 9, + TYPE_GROUP = 10, + TYPE_MESSAGE = 11, + TYPE_BYTES = 12, + TYPE_UINT32 = 13, + TYPE_ENUM = 14, + TYPE_SFIXED32 = 15, + TYPE_SFIXED64 = 16, + TYPE_SINT32 = 17, + TYPE_SINT64 = 18, + MAX_FIELD_TYPE = 18, + }; + + // Lite alternative to FieldDescriptor::CppType. Must be kept in sync. + enum CppType { + CPPTYPE_INT32 = 1, + CPPTYPE_INT64 = 2, + CPPTYPE_UINT32 = 3, + CPPTYPE_UINT64 = 4, + CPPTYPE_DOUBLE = 5, + CPPTYPE_FLOAT = 6, + CPPTYPE_BOOL = 7, + CPPTYPE_ENUM = 8, + CPPTYPE_STRING = 9, + CPPTYPE_MESSAGE = 10, + MAX_CPPTYPE = 10, + }; + + // Helper method to get the CppType for a particular Type. + static CppType FieldTypeToCppType(FieldType type); + + // Given a FieldSescriptor::Type return its WireType + static inline WireFormatLite::WireType WireTypeForFieldType( + WireFormatLite::FieldType type) { + return kWireTypeForFieldType[type]; + } + + // Number of bits in a tag which identify the wire type. + static const int kTagTypeBits = 3; + // Mask for those bits. + static const uint32 kTagTypeMask = (1 << kTagTypeBits) - 1; + + // Helper functions for encoding and decoding tags. (Inlined below and in + // _inl.h) + // + // This is different from MakeTag(field->number(), field->type()) in the case + // of packed repeated fields. + static uint32 MakeTag(int field_number, WireType type); + static WireType GetTagWireType(uint32 tag); + static int GetTagFieldNumber(uint32 tag); + + // Compute the byte size of a tag. For groups, this includes both the start + // and end tags. + static inline int TagSize(int field_number, WireFormatLite::FieldType type); + + // Skips a field value with the given tag. The input should start + // positioned immediately after the tag. Skipped values are simply discarded, + // not recorded anywhere. See WireFormat::SkipField() for a version that + // records to an UnknownFieldSet. + static bool SkipField(io::CodedInputStream* input, uint32 tag); + + // Reads and ignores a message from the input. Skipped values are simply + // discarded, not recorded anywhere. See WireFormat::SkipMessage() for a + // version that records to an UnknownFieldSet. + static bool SkipMessage(io::CodedInputStream* input); + +// This macro does the same thing as WireFormatLite::MakeTag(), but the +// result is usable as a compile-time constant, which makes it usable +// as a switch case or a template input. WireFormatLite::MakeTag() is more +// type-safe, though, so prefer it if possible. +#define GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(FIELD_NUMBER, TYPE) \ + static_cast( \ + ((FIELD_NUMBER) << ::google::protobuf::internal::WireFormatLite::kTagTypeBits) \ + | (TYPE)) + + // These are the tags for the old MessageSet format, which was defined as: + // message MessageSet { + // repeated group Item = 1 { + // required int32 type_id = 2; + // required string message = 3; + // } + // } + static const int kMessageSetItemNumber = 1; + static const int kMessageSetTypeIdNumber = 2; + static const int kMessageSetMessageNumber = 3; + static const int kMessageSetItemStartTag = + GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(kMessageSetItemNumber, + WireFormatLite::WIRETYPE_START_GROUP); + static const int kMessageSetItemEndTag = + GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(kMessageSetItemNumber, + WireFormatLite::WIRETYPE_END_GROUP); + static const int kMessageSetTypeIdTag = + GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(kMessageSetTypeIdNumber, + WireFormatLite::WIRETYPE_VARINT); + static const int kMessageSetMessageTag = + GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(kMessageSetMessageNumber, + WireFormatLite::WIRETYPE_LENGTH_DELIMITED); + + // Byte size of all tags of a MessageSet::Item combined. + static const int kMessageSetItemTagsSize; + + // Helper functions for converting between floats/doubles and IEEE-754 + // uint32s/uint64s so that they can be written. (Assumes your platform + // uses IEEE-754 floats.) + static uint32 EncodeFloat(float value); + static float DecodeFloat(uint32 value); + static uint64 EncodeDouble(double value); + static double DecodeDouble(uint64 value); + + // Helper functions for mapping signed integers to unsigned integers in + // such a way that numbers with small magnitudes will encode to smaller + // varints. If you simply static_cast a negative number to an unsigned + // number and varint-encode it, it will always take 10 bytes, defeating + // the purpose of varint. So, for the "sint32" and "sint64" field types, + // we ZigZag-encode the values. + static uint32 ZigZagEncode32(int32 n); + static int32 ZigZagDecode32(uint32 n); + static uint64 ZigZagEncode64(int64 n); + static int64 ZigZagDecode64(uint64 n); + + // ================================================================= + // Methods for reading/writing individual field. The implementations + // of these methods are defined in wire_format_lite_inl.h; you must #include + // that file to use these. + +// Avoid ugly line wrapping +#define input io::CodedInputStream* input +#define output io::CodedOutputStream* output +#define field_number int field_number +#define INL GOOGLE_ATTRIBUTE_ALWAYS_INLINE + + // Read fields, not including tags. The assumption is that you already + // read the tag to determine what field to read. + + // For primitive fields, we just use a templatized routine parameterized by + // the represented type and the FieldType. These are specialized with the + // appropriate definition for each declared type. + template + static inline bool ReadPrimitive(input, CType* value) INL; + + // Reads repeated primitive values, with optimizations for repeats. + // tag_size and tag should both be compile-time constants provided by the + // protocol compiler. + template + static inline bool ReadRepeatedPrimitive(int tag_size, + uint32 tag, + input, + RepeatedField* value) INL; + + // Identical to ReadRepeatedPrimitive, except will not inline the + // implementation. + template + static bool ReadRepeatedPrimitiveNoInline(int tag_size, + uint32 tag, + input, + RepeatedField* value); + + // Reads a primitive value directly from the provided buffer. It returns a + // pointer past the segment of data that was read. + // + // This is only implemented for the types with fixed wire size, e.g. + // float, double, and the (s)fixed* types. + template + static inline const uint8* ReadPrimitiveFromArray(const uint8* buffer, + CType* value) INL; + + // Reads a primitive packed field. + // + // This is only implemented for packable types. + template + static inline bool ReadPackedPrimitive(input, + RepeatedField* value) INL; + + // Identical to ReadPackedPrimitive, except will not inline the + // implementation. + template + static bool ReadPackedPrimitiveNoInline(input, RepeatedField* value); + + // Read a packed enum field. Values for which is_valid() returns false are + // dropped. + static bool ReadPackedEnumNoInline(input, + bool (*is_valid)(int), + RepeatedField* value); + + static bool ReadString(input, string* value); + static bool ReadBytes (input, string* value); + + static inline bool ReadGroup (field_number, input, MessageLite* value); + static inline bool ReadMessage(input, MessageLite* value); + + // Like above, but de-virtualize the call to MergePartialFromCodedStream(). + // The pointer must point at an instance of MessageType, *not* a subclass (or + // the subclass must not override MergePartialFromCodedStream()). + template + static inline bool ReadGroupNoVirtual(field_number, input, + MessageType* value); + template + static inline bool ReadMessageNoVirtual(input, MessageType* value); + + // Write a tag. The Write*() functions typically include the tag, so + // normally there's no need to call this unless using the Write*NoTag() + // variants. + static inline void WriteTag(field_number, WireType type, output) INL; + + // Write fields, without tags. + static inline void WriteInt32NoTag (int32 value, output) INL; + static inline void WriteInt64NoTag (int64 value, output) INL; + static inline void WriteUInt32NoTag (uint32 value, output) INL; + static inline void WriteUInt64NoTag (uint64 value, output) INL; + static inline void WriteSInt32NoTag (int32 value, output) INL; + static inline void WriteSInt64NoTag (int64 value, output) INL; + static inline void WriteFixed32NoTag (uint32 value, output) INL; + static inline void WriteFixed64NoTag (uint64 value, output) INL; + static inline void WriteSFixed32NoTag(int32 value, output) INL; + static inline void WriteSFixed64NoTag(int64 value, output) INL; + static inline void WriteFloatNoTag (float value, output) INL; + static inline void WriteDoubleNoTag (double value, output) INL; + static inline void WriteBoolNoTag (bool value, output) INL; + static inline void WriteEnumNoTag (int value, output) INL; + + // Write fields, including tags. + static void WriteInt32 (field_number, int32 value, output); + static void WriteInt64 (field_number, int64 value, output); + static void WriteUInt32 (field_number, uint32 value, output); + static void WriteUInt64 (field_number, uint64 value, output); + static void WriteSInt32 (field_number, int32 value, output); + static void WriteSInt64 (field_number, int64 value, output); + static void WriteFixed32 (field_number, uint32 value, output); + static void WriteFixed64 (field_number, uint64 value, output); + static void WriteSFixed32(field_number, int32 value, output); + static void WriteSFixed64(field_number, int64 value, output); + static void WriteFloat (field_number, float value, output); + static void WriteDouble (field_number, double value, output); + static void WriteBool (field_number, bool value, output); + static void WriteEnum (field_number, int value, output); + + static void WriteString(field_number, const string& value, output); + static void WriteBytes (field_number, const string& value, output); + + static void WriteGroup( + field_number, const MessageLite& value, output); + static void WriteMessage( + field_number, const MessageLite& value, output); + // Like above, but these will check if the output stream has enough + // space to write directly to a flat array. + static void WriteGroupMaybeToArray( + field_number, const MessageLite& value, output); + static void WriteMessageMaybeToArray( + field_number, const MessageLite& value, output); + + // Like above, but de-virtualize the call to SerializeWithCachedSizes(). The + // pointer must point at an instance of MessageType, *not* a subclass (or + // the subclass must not override SerializeWithCachedSizes()). + template + static inline void WriteGroupNoVirtual( + field_number, const MessageType& value, output); + template + static inline void WriteMessageNoVirtual( + field_number, const MessageType& value, output); + +#undef output +#define output uint8* target + + // Like above, but use only *ToArray methods of CodedOutputStream. + static inline uint8* WriteTagToArray(field_number, WireType type, output) INL; + + // Write fields, without tags. + static inline uint8* WriteInt32NoTagToArray (int32 value, output) INL; + static inline uint8* WriteInt64NoTagToArray (int64 value, output) INL; + static inline uint8* WriteUInt32NoTagToArray (uint32 value, output) INL; + static inline uint8* WriteUInt64NoTagToArray (uint64 value, output) INL; + static inline uint8* WriteSInt32NoTagToArray (int32 value, output) INL; + static inline uint8* WriteSInt64NoTagToArray (int64 value, output) INL; + static inline uint8* WriteFixed32NoTagToArray (uint32 value, output) INL; + static inline uint8* WriteFixed64NoTagToArray (uint64 value, output) INL; + static inline uint8* WriteSFixed32NoTagToArray(int32 value, output) INL; + static inline uint8* WriteSFixed64NoTagToArray(int64 value, output) INL; + static inline uint8* WriteFloatNoTagToArray (float value, output) INL; + static inline uint8* WriteDoubleNoTagToArray (double value, output) INL; + static inline uint8* WriteBoolNoTagToArray (bool value, output) INL; + static inline uint8* WriteEnumNoTagToArray (int value, output) INL; + + // Write fields, including tags. + static inline uint8* WriteInt32ToArray( + field_number, int32 value, output) INL; + static inline uint8* WriteInt64ToArray( + field_number, int64 value, output) INL; + static inline uint8* WriteUInt32ToArray( + field_number, uint32 value, output) INL; + static inline uint8* WriteUInt64ToArray( + field_number, uint64 value, output) INL; + static inline uint8* WriteSInt32ToArray( + field_number, int32 value, output) INL; + static inline uint8* WriteSInt64ToArray( + field_number, int64 value, output) INL; + static inline uint8* WriteFixed32ToArray( + field_number, uint32 value, output) INL; + static inline uint8* WriteFixed64ToArray( + field_number, uint64 value, output) INL; + static inline uint8* WriteSFixed32ToArray( + field_number, int32 value, output) INL; + static inline uint8* WriteSFixed64ToArray( + field_number, int64 value, output) INL; + static inline uint8* WriteFloatToArray( + field_number, float value, output) INL; + static inline uint8* WriteDoubleToArray( + field_number, double value, output) INL; + static inline uint8* WriteBoolToArray( + field_number, bool value, output) INL; + static inline uint8* WriteEnumToArray( + field_number, int value, output) INL; + + static inline uint8* WriteStringToArray( + field_number, const string& value, output) INL; + static inline uint8* WriteBytesToArray( + field_number, const string& value, output) INL; + + static inline uint8* WriteGroupToArray( + field_number, const MessageLite& value, output) INL; + static inline uint8* WriteMessageToArray( + field_number, const MessageLite& value, output) INL; + + // Like above, but de-virtualize the call to SerializeWithCachedSizes(). The + // pointer must point at an instance of MessageType, *not* a subclass (or + // the subclass must not override SerializeWithCachedSizes()). + template + static inline uint8* WriteGroupNoVirtualToArray( + field_number, const MessageType& value, output) INL; + template + static inline uint8* WriteMessageNoVirtualToArray( + field_number, const MessageType& value, output) INL; + +#undef output +#undef input +#undef INL + +#undef field_number + + // Compute the byte size of a field. The XxSize() functions do NOT include + // the tag, so you must also call TagSize(). (This is because, for repeated + // fields, you should only call TagSize() once and multiply it by the element + // count, but you may have to call XxSize() for each individual element.) + static inline int Int32Size ( int32 value); + static inline int Int64Size ( int64 value); + static inline int UInt32Size (uint32 value); + static inline int UInt64Size (uint64 value); + static inline int SInt32Size ( int32 value); + static inline int SInt64Size ( int64 value); + static inline int EnumSize ( int value); + + // These types always have the same size. + static const int kFixed32Size = 4; + static const int kFixed64Size = 8; + static const int kSFixed32Size = 4; + static const int kSFixed64Size = 8; + static const int kFloatSize = 4; + static const int kDoubleSize = 8; + static const int kBoolSize = 1; + + static inline int StringSize(const string& value); + static inline int BytesSize (const string& value); + + static inline int GroupSize (const MessageLite& value); + static inline int MessageSize(const MessageLite& value); + + // Like above, but de-virtualize the call to ByteSize(). The + // pointer must point at an instance of MessageType, *not* a subclass (or + // the subclass must not override ByteSize()). + template + static inline int GroupSizeNoVirtual (const MessageType& value); + template + static inline int MessageSizeNoVirtual(const MessageType& value); + + private: + // A helper method for the repeated primitive reader. This method has + // optimizations for primitive types that have fixed size on the wire, and + // can be read using potentially faster paths. + template + static inline bool ReadRepeatedFixedSizePrimitive( + int tag_size, + uint32 tag, + google::protobuf::io::CodedInputStream* input, + RepeatedField* value) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + + static const CppType kFieldTypeToCppTypeMap[]; + static const WireFormatLite::WireType kWireTypeForFieldType[]; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(WireFormatLite); +}; + +// A class which deals with unknown values. The default implementation just +// discards them. WireFormat defines a subclass which writes to an +// UnknownFieldSet. This class is used by ExtensionSet::ParseField(), since +// ExtensionSet is part of the lite library but UnknownFieldSet is not. +class LIBPROTOBUF_EXPORT FieldSkipper { + public: + FieldSkipper() {} + virtual ~FieldSkipper() {} + + // Skip a field whose tag has already been consumed. + virtual bool SkipField(io::CodedInputStream* input, uint32 tag); + + // Skip an entire message or group, up to an end-group tag (which is consumed) + // or end-of-stream. + virtual bool SkipMessage(io::CodedInputStream* input); + + // Deal with an already-parsed unrecognized enum value. The default + // implementation does nothing, but the UnknownFieldSet-based implementation + // saves it as an unknown varint. + virtual void SkipUnknownEnum(int field_number, int value); +}; + +// inline methods ==================================================== + +inline WireFormatLite::CppType +WireFormatLite::FieldTypeToCppType(FieldType type) { + return kFieldTypeToCppTypeMap[type]; +} + +inline uint32 WireFormatLite::MakeTag(int field_number, WireType type) { + return GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(field_number, type); +} + +inline WireFormatLite::WireType WireFormatLite::GetTagWireType(uint32 tag) { + return static_cast(tag & kTagTypeMask); +} + +inline int WireFormatLite::GetTagFieldNumber(uint32 tag) { + return static_cast(tag >> kTagTypeBits); +} + +inline int WireFormatLite::TagSize(int field_number, + WireFormatLite::FieldType type) { + int result = io::CodedOutputStream::VarintSize32( + field_number << kTagTypeBits); + if (type == TYPE_GROUP) { + // Groups have both a start and an end tag. + return result * 2; + } else { + return result; + } +} + +inline uint32 WireFormatLite::EncodeFloat(float value) { + union {float f; uint32 i;}; + f = value; + return i; +} + +inline float WireFormatLite::DecodeFloat(uint32 value) { + union {float f; uint32 i;}; + i = value; + return f; +} + +inline uint64 WireFormatLite::EncodeDouble(double value) { + union {double f; uint64 i;}; + f = value; + return i; +} + +inline double WireFormatLite::DecodeDouble(uint64 value) { + union {double f; uint64 i;}; + i = value; + return f; +} + +// ZigZag Transform: Encodes signed integers so that they can be +// effectively used with varint encoding. +// +// varint operates on unsigned integers, encoding smaller numbers into +// fewer bytes. If you try to use it on a signed integer, it will treat +// this number as a very large unsigned integer, which means that even +// small signed numbers like -1 will take the maximum number of bytes +// (10) to encode. ZigZagEncode() maps signed integers to unsigned +// in such a way that those with a small absolute value will have smaller +// encoded values, making them appropriate for encoding using varint. +// +// int32 -> uint32 +// ------------------------- +// 0 -> 0 +// -1 -> 1 +// 1 -> 2 +// -2 -> 3 +// ... -> ... +// 2147483647 -> 4294967294 +// -2147483648 -> 4294967295 +// +// >> encode >> +// << decode << + +inline uint32 WireFormatLite::ZigZagEncode32(int32 n) { + // Note: the right-shift must be arithmetic + return (n << 1) ^ (n >> 31); +} + +inline int32 WireFormatLite::ZigZagDecode32(uint32 n) { + return (n >> 1) ^ -static_cast(n & 1); +} + +inline uint64 WireFormatLite::ZigZagEncode64(int64 n) { + // Note: the right-shift must be arithmetic + return (n << 1) ^ (n >> 63); +} + +inline int64 WireFormatLite::ZigZagDecode64(uint64 n) { + return (n >> 1) ^ -static_cast(n & 1); +} + +} // namespace internal +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_WIRE_FORMAT_LITE_H__ diff --git a/depends/protobuf/google/protobuf/wire_format_lite_inl.h b/depends/protobuf/google/protobuf/wire_format_lite_inl.h new file mode 100644 index 0000000000..103b0bd0ca --- /dev/null +++ b/depends/protobuf/google/protobuf/wire_format_lite_inl.h @@ -0,0 +1,774 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// wink@google.com (Wink Saville) (refactored from wire_format.h) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_WIRE_FORMAT_LITE_INL_H__ +#define GOOGLE_PROTOBUF_WIRE_FORMAT_LITE_INL_H__ + +#include +#include +#include +#include +#include +#include +#include + + +namespace google { +namespace protobuf { +namespace internal { + +// Implementation details of ReadPrimitive. + +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + int32* value) { + uint32 temp; + if (!input->ReadVarint32(&temp)) return false; + *value = static_cast(temp); + return true; +} +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + int64* value) { + uint64 temp; + if (!input->ReadVarint64(&temp)) return false; + *value = static_cast(temp); + return true; +} +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + uint32* value) { + return input->ReadVarint32(value); +} +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + uint64* value) { + return input->ReadVarint64(value); +} +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + int32* value) { + uint32 temp; + if (!input->ReadVarint32(&temp)) return false; + *value = ZigZagDecode32(temp); + return true; +} +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + int64* value) { + uint64 temp; + if (!input->ReadVarint64(&temp)) return false; + *value = ZigZagDecode64(temp); + return true; +} +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + uint32* value) { + return input->ReadLittleEndian32(value); +} +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + uint64* value) { + return input->ReadLittleEndian64(value); +} +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + int32* value) { + uint32 temp; + if (!input->ReadLittleEndian32(&temp)) return false; + *value = static_cast(temp); + return true; +} +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + int64* value) { + uint64 temp; + if (!input->ReadLittleEndian64(&temp)) return false; + *value = static_cast(temp); + return true; +} +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + float* value) { + uint32 temp; + if (!input->ReadLittleEndian32(&temp)) return false; + *value = DecodeFloat(temp); + return true; +} +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + double* value) { + uint64 temp; + if (!input->ReadLittleEndian64(&temp)) return false; + *value = DecodeDouble(temp); + return true; +} +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + bool* value) { + uint32 temp; + if (!input->ReadVarint32(&temp)) return false; + *value = temp != 0; + return true; +} +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + int* value) { + uint32 temp; + if (!input->ReadVarint32(&temp)) return false; + *value = static_cast(temp); + return true; +} + +template <> +inline const uint8* WireFormatLite::ReadPrimitiveFromArray< + uint32, WireFormatLite::TYPE_FIXED32>( + const uint8* buffer, + uint32* value) { + return io::CodedInputStream::ReadLittleEndian32FromArray(buffer, value); +} +template <> +inline const uint8* WireFormatLite::ReadPrimitiveFromArray< + uint64, WireFormatLite::TYPE_FIXED64>( + const uint8* buffer, + uint64* value) { + return io::CodedInputStream::ReadLittleEndian64FromArray(buffer, value); +} +template <> +inline const uint8* WireFormatLite::ReadPrimitiveFromArray< + int32, WireFormatLite::TYPE_SFIXED32>( + const uint8* buffer, + int32* value) { + uint32 temp; + buffer = io::CodedInputStream::ReadLittleEndian32FromArray(buffer, &temp); + *value = static_cast(temp); + return buffer; +} +template <> +inline const uint8* WireFormatLite::ReadPrimitiveFromArray< + int64, WireFormatLite::TYPE_SFIXED64>( + const uint8* buffer, + int64* value) { + uint64 temp; + buffer = io::CodedInputStream::ReadLittleEndian64FromArray(buffer, &temp); + *value = static_cast(temp); + return buffer; +} +template <> +inline const uint8* WireFormatLite::ReadPrimitiveFromArray< + float, WireFormatLite::TYPE_FLOAT>( + const uint8* buffer, + float* value) { + uint32 temp; + buffer = io::CodedInputStream::ReadLittleEndian32FromArray(buffer, &temp); + *value = DecodeFloat(temp); + return buffer; +} +template <> +inline const uint8* WireFormatLite::ReadPrimitiveFromArray< + double, WireFormatLite::TYPE_DOUBLE>( + const uint8* buffer, + double* value) { + uint64 temp; + buffer = io::CodedInputStream::ReadLittleEndian64FromArray(buffer, &temp); + *value = DecodeDouble(temp); + return buffer; +} + +template +inline bool WireFormatLite::ReadRepeatedPrimitive(int, // tag_size, unused. + uint32 tag, + io::CodedInputStream* input, + RepeatedField* values) { + CType value; + if (!ReadPrimitive(input, &value)) return false; + values->Add(value); + int elements_already_reserved = values->Capacity() - values->size(); + while (elements_already_reserved > 0 && input->ExpectTag(tag)) { + if (!ReadPrimitive(input, &value)) return false; + values->AddAlreadyReserved(value); + elements_already_reserved--; + } + return true; +} + +template +inline bool WireFormatLite::ReadRepeatedFixedSizePrimitive( + int tag_size, + uint32 tag, + io::CodedInputStream* input, + RepeatedField* values) { + GOOGLE_DCHECK_EQ(UInt32Size(tag), tag_size); + CType value; + if (!ReadPrimitive(input, &value)) + return false; + values->Add(value); + + // For fixed size values, repeated values can be read more quickly by + // reading directly from a raw array. + // + // We can get a tight loop by only reading as many elements as can be + // added to the RepeatedField without having to do any resizing. Additionally, + // we only try to read as many elements as are available from the current + // buffer space. Doing so avoids having to perform boundary checks when + // reading the value: the maximum number of elements that can be read is + // known outside of the loop. + const void* void_pointer; + int size; + input->GetDirectBufferPointerInline(&void_pointer, &size); + if (size > 0) { + const uint8* buffer = reinterpret_cast(void_pointer); + // The number of bytes each type occupies on the wire. + const int per_value_size = tag_size + sizeof(value); + + int elements_available = min(values->Capacity() - values->size(), + size / per_value_size); + int num_read = 0; + while (num_read < elements_available && + (buffer = io::CodedInputStream::ExpectTagFromArray( + buffer, tag)) != NULL) { + buffer = ReadPrimitiveFromArray(buffer, &value); + values->AddAlreadyReserved(value); + ++num_read; + } + const int read_bytes = num_read * per_value_size; + if (read_bytes > 0) { + input->Skip(read_bytes); + } + } + return true; +} + +// Specializations of ReadRepeatedPrimitive for the fixed size types, which use +// the optimized code path. +#define READ_REPEATED_FIXED_SIZE_PRIMITIVE(CPPTYPE, DECLARED_TYPE) \ +template <> \ +inline bool WireFormatLite::ReadRepeatedPrimitive< \ + CPPTYPE, WireFormatLite::DECLARED_TYPE>( \ + int tag_size, \ + uint32 tag, \ + io::CodedInputStream* input, \ + RepeatedField* values) { \ + return ReadRepeatedFixedSizePrimitive< \ + CPPTYPE, WireFormatLite::DECLARED_TYPE>( \ + tag_size, tag, input, values); \ +} + +READ_REPEATED_FIXED_SIZE_PRIMITIVE(uint32, TYPE_FIXED32); +READ_REPEATED_FIXED_SIZE_PRIMITIVE(uint64, TYPE_FIXED64); +READ_REPEATED_FIXED_SIZE_PRIMITIVE(int32, TYPE_SFIXED32); +READ_REPEATED_FIXED_SIZE_PRIMITIVE(int64, TYPE_SFIXED64); +READ_REPEATED_FIXED_SIZE_PRIMITIVE(float, TYPE_FLOAT); +READ_REPEATED_FIXED_SIZE_PRIMITIVE(double, TYPE_DOUBLE); + +#undef READ_REPEATED_FIXED_SIZE_PRIMITIVE + +template +bool WireFormatLite::ReadRepeatedPrimitiveNoInline( + int tag_size, + uint32 tag, + io::CodedInputStream* input, + RepeatedField* value) { + return ReadRepeatedPrimitive( + tag_size, tag, input, value); +} + +template +inline bool WireFormatLite::ReadPackedPrimitive(io::CodedInputStream* input, + RepeatedField* values) { + uint32 length; + if (!input->ReadVarint32(&length)) return false; + io::CodedInputStream::Limit limit = input->PushLimit(length); + while (input->BytesUntilLimit() > 0) { + CType value; + if (!ReadPrimitive(input, &value)) return false; + values->Add(value); + } + input->PopLimit(limit); + return true; +} + +template +bool WireFormatLite::ReadPackedPrimitiveNoInline(io::CodedInputStream* input, + RepeatedField* values) { + return ReadPackedPrimitive(input, values); +} + + +inline bool WireFormatLite::ReadGroup(int field_number, + io::CodedInputStream* input, + MessageLite* value) { + if (!input->IncrementRecursionDepth()) return false; + if (!value->MergePartialFromCodedStream(input)) return false; + input->DecrementRecursionDepth(); + // Make sure the last thing read was an end tag for this group. + if (!input->LastTagWas(MakeTag(field_number, WIRETYPE_END_GROUP))) { + return false; + } + return true; +} +inline bool WireFormatLite::ReadMessage(io::CodedInputStream* input, + MessageLite* value) { + uint32 length; + if (!input->ReadVarint32(&length)) return false; + if (!input->IncrementRecursionDepth()) return false; + io::CodedInputStream::Limit limit = input->PushLimit(length); + if (!value->MergePartialFromCodedStream(input)) return false; + // Make sure that parsing stopped when the limit was hit, not at an endgroup + // tag. + if (!input->ConsumedEntireMessage()) return false; + input->PopLimit(limit); + input->DecrementRecursionDepth(); + return true; +} + +// We name the template parameter something long and extremely unlikely to occur +// elsewhere because a *qualified* member access expression designed to avoid +// virtual dispatch, C++03 [basic.lookup.classref] 3.4.5/4 requires that the +// name of the qualifying class to be looked up both in the context of the full +// expression (finding the template parameter) and in the context of the object +// whose member we are accessing. This could potentially find a nested type +// within that object. The standard goes on to require these names to refer to +// the same entity, which this collision would violate. The lack of a safe way +// to avoid this collision appears to be a defect in the standard, but until it +// is corrected, we choose the name to avoid accidental collisions. +template +inline bool WireFormatLite::ReadGroupNoVirtual( + int field_number, io::CodedInputStream* input, + MessageType_WorkAroundCppLookupDefect* value) { + if (!input->IncrementRecursionDepth()) return false; + if (!value-> + MessageType_WorkAroundCppLookupDefect::MergePartialFromCodedStream(input)) + return false; + input->DecrementRecursionDepth(); + // Make sure the last thing read was an end tag for this group. + if (!input->LastTagWas(MakeTag(field_number, WIRETYPE_END_GROUP))) { + return false; + } + return true; +} +template +inline bool WireFormatLite::ReadMessageNoVirtual( + io::CodedInputStream* input, MessageType_WorkAroundCppLookupDefect* value) { + uint32 length; + if (!input->ReadVarint32(&length)) return false; + if (!input->IncrementRecursionDepth()) return false; + io::CodedInputStream::Limit limit = input->PushLimit(length); + if (!value-> + MessageType_WorkAroundCppLookupDefect::MergePartialFromCodedStream(input)) + return false; + // Make sure that parsing stopped when the limit was hit, not at an endgroup + // tag. + if (!input->ConsumedEntireMessage()) return false; + input->PopLimit(limit); + input->DecrementRecursionDepth(); + return true; +} + +// =================================================================== + +inline void WireFormatLite::WriteTag(int field_number, WireType type, + io::CodedOutputStream* output) { + output->WriteTag(MakeTag(field_number, type)); +} + +inline void WireFormatLite::WriteInt32NoTag(int32 value, + io::CodedOutputStream* output) { + output->WriteVarint32SignExtended(value); +} +inline void WireFormatLite::WriteInt64NoTag(int64 value, + io::CodedOutputStream* output) { + output->WriteVarint64(static_cast(value)); +} +inline void WireFormatLite::WriteUInt32NoTag(uint32 value, + io::CodedOutputStream* output) { + output->WriteVarint32(value); +} +inline void WireFormatLite::WriteUInt64NoTag(uint64 value, + io::CodedOutputStream* output) { + output->WriteVarint64(value); +} +inline void WireFormatLite::WriteSInt32NoTag(int32 value, + io::CodedOutputStream* output) { + output->WriteVarint32(ZigZagEncode32(value)); +} +inline void WireFormatLite::WriteSInt64NoTag(int64 value, + io::CodedOutputStream* output) { + output->WriteVarint64(ZigZagEncode64(value)); +} +inline void WireFormatLite::WriteFixed32NoTag(uint32 value, + io::CodedOutputStream* output) { + output->WriteLittleEndian32(value); +} +inline void WireFormatLite::WriteFixed64NoTag(uint64 value, + io::CodedOutputStream* output) { + output->WriteLittleEndian64(value); +} +inline void WireFormatLite::WriteSFixed32NoTag(int32 value, + io::CodedOutputStream* output) { + output->WriteLittleEndian32(static_cast(value)); +} +inline void WireFormatLite::WriteSFixed64NoTag(int64 value, + io::CodedOutputStream* output) { + output->WriteLittleEndian64(static_cast(value)); +} +inline void WireFormatLite::WriteFloatNoTag(float value, + io::CodedOutputStream* output) { + output->WriteLittleEndian32(EncodeFloat(value)); +} +inline void WireFormatLite::WriteDoubleNoTag(double value, + io::CodedOutputStream* output) { + output->WriteLittleEndian64(EncodeDouble(value)); +} +inline void WireFormatLite::WriteBoolNoTag(bool value, + io::CodedOutputStream* output) { + output->WriteVarint32(value ? 1 : 0); +} +inline void WireFormatLite::WriteEnumNoTag(int value, + io::CodedOutputStream* output) { + output->WriteVarint32SignExtended(value); +} + +// See comment on ReadGroupNoVirtual to understand the need for this template +// parameter name. +template +inline void WireFormatLite::WriteGroupNoVirtual( + int field_number, const MessageType_WorkAroundCppLookupDefect& value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_START_GROUP, output); + value.MessageType_WorkAroundCppLookupDefect::SerializeWithCachedSizes(output); + WriteTag(field_number, WIRETYPE_END_GROUP, output); +} +template +inline void WireFormatLite::WriteMessageNoVirtual( + int field_number, const MessageType_WorkAroundCppLookupDefect& value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output); + output->WriteVarint32( + value.MessageType_WorkAroundCppLookupDefect::GetCachedSize()); + value.MessageType_WorkAroundCppLookupDefect::SerializeWithCachedSizes(output); +} + +// =================================================================== + +inline uint8* WireFormatLite::WriteTagToArray(int field_number, + WireType type, + uint8* target) { + return io::CodedOutputStream::WriteTagToArray(MakeTag(field_number, type), + target); +} + +inline uint8* WireFormatLite::WriteInt32NoTagToArray(int32 value, + uint8* target) { + return io::CodedOutputStream::WriteVarint32SignExtendedToArray(value, target); +} +inline uint8* WireFormatLite::WriteInt64NoTagToArray(int64 value, + uint8* target) { + return io::CodedOutputStream::WriteVarint64ToArray( + static_cast(value), target); +} +inline uint8* WireFormatLite::WriteUInt32NoTagToArray(uint32 value, + uint8* target) { + return io::CodedOutputStream::WriteVarint32ToArray(value, target); +} +inline uint8* WireFormatLite::WriteUInt64NoTagToArray(uint64 value, + uint8* target) { + return io::CodedOutputStream::WriteVarint64ToArray(value, target); +} +inline uint8* WireFormatLite::WriteSInt32NoTagToArray(int32 value, + uint8* target) { + return io::CodedOutputStream::WriteVarint32ToArray(ZigZagEncode32(value), + target); +} +inline uint8* WireFormatLite::WriteSInt64NoTagToArray(int64 value, + uint8* target) { + return io::CodedOutputStream::WriteVarint64ToArray(ZigZagEncode64(value), + target); +} +inline uint8* WireFormatLite::WriteFixed32NoTagToArray(uint32 value, + uint8* target) { + return io::CodedOutputStream::WriteLittleEndian32ToArray(value, target); +} +inline uint8* WireFormatLite::WriteFixed64NoTagToArray(uint64 value, + uint8* target) { + return io::CodedOutputStream::WriteLittleEndian64ToArray(value, target); +} +inline uint8* WireFormatLite::WriteSFixed32NoTagToArray(int32 value, + uint8* target) { + return io::CodedOutputStream::WriteLittleEndian32ToArray( + static_cast(value), target); +} +inline uint8* WireFormatLite::WriteSFixed64NoTagToArray(int64 value, + uint8* target) { + return io::CodedOutputStream::WriteLittleEndian64ToArray( + static_cast(value), target); +} +inline uint8* WireFormatLite::WriteFloatNoTagToArray(float value, + uint8* target) { + return io::CodedOutputStream::WriteLittleEndian32ToArray(EncodeFloat(value), + target); +} +inline uint8* WireFormatLite::WriteDoubleNoTagToArray(double value, + uint8* target) { + return io::CodedOutputStream::WriteLittleEndian64ToArray(EncodeDouble(value), + target); +} +inline uint8* WireFormatLite::WriteBoolNoTagToArray(bool value, + uint8* target) { + return io::CodedOutputStream::WriteVarint32ToArray(value ? 1 : 0, target); +} +inline uint8* WireFormatLite::WriteEnumNoTagToArray(int value, + uint8* target) { + return io::CodedOutputStream::WriteVarint32SignExtendedToArray(value, target); +} + +inline uint8* WireFormatLite::WriteInt32ToArray(int field_number, + int32 value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_VARINT, target); + return WriteInt32NoTagToArray(value, target); +} +inline uint8* WireFormatLite::WriteInt64ToArray(int field_number, + int64 value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_VARINT, target); + return WriteInt64NoTagToArray(value, target); +} +inline uint8* WireFormatLite::WriteUInt32ToArray(int field_number, + uint32 value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_VARINT, target); + return WriteUInt32NoTagToArray(value, target); +} +inline uint8* WireFormatLite::WriteUInt64ToArray(int field_number, + uint64 value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_VARINT, target); + return WriteUInt64NoTagToArray(value, target); +} +inline uint8* WireFormatLite::WriteSInt32ToArray(int field_number, + int32 value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_VARINT, target); + return WriteSInt32NoTagToArray(value, target); +} +inline uint8* WireFormatLite::WriteSInt64ToArray(int field_number, + int64 value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_VARINT, target); + return WriteSInt64NoTagToArray(value, target); +} +inline uint8* WireFormatLite::WriteFixed32ToArray(int field_number, + uint32 value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_FIXED32, target); + return WriteFixed32NoTagToArray(value, target); +} +inline uint8* WireFormatLite::WriteFixed64ToArray(int field_number, + uint64 value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_FIXED64, target); + return WriteFixed64NoTagToArray(value, target); +} +inline uint8* WireFormatLite::WriteSFixed32ToArray(int field_number, + int32 value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_FIXED32, target); + return WriteSFixed32NoTagToArray(value, target); +} +inline uint8* WireFormatLite::WriteSFixed64ToArray(int field_number, + int64 value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_FIXED64, target); + return WriteSFixed64NoTagToArray(value, target); +} +inline uint8* WireFormatLite::WriteFloatToArray(int field_number, + float value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_FIXED32, target); + return WriteFloatNoTagToArray(value, target); +} +inline uint8* WireFormatLite::WriteDoubleToArray(int field_number, + double value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_FIXED64, target); + return WriteDoubleNoTagToArray(value, target); +} +inline uint8* WireFormatLite::WriteBoolToArray(int field_number, + bool value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_VARINT, target); + return WriteBoolNoTagToArray(value, target); +} +inline uint8* WireFormatLite::WriteEnumToArray(int field_number, + int value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_VARINT, target); + return WriteEnumNoTagToArray(value, target); +} + +inline uint8* WireFormatLite::WriteStringToArray(int field_number, + const string& value, + uint8* target) { + // String is for UTF-8 text only + // WARNING: In wire_format.cc, both strings and bytes are handled by + // WriteString() to avoid code duplication. If the implementations become + // different, you will need to update that usage. + target = WriteTagToArray(field_number, WIRETYPE_LENGTH_DELIMITED, target); + target = io::CodedOutputStream::WriteVarint32ToArray(value.size(), target); + return io::CodedOutputStream::WriteStringToArray(value, target); +} +inline uint8* WireFormatLite::WriteBytesToArray(int field_number, + const string& value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_LENGTH_DELIMITED, target); + target = io::CodedOutputStream::WriteVarint32ToArray(value.size(), target); + return io::CodedOutputStream::WriteStringToArray(value, target); +} + + +inline uint8* WireFormatLite::WriteGroupToArray(int field_number, + const MessageLite& value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_START_GROUP, target); + target = value.SerializeWithCachedSizesToArray(target); + return WriteTagToArray(field_number, WIRETYPE_END_GROUP, target); +} +inline uint8* WireFormatLite::WriteMessageToArray(int field_number, + const MessageLite& value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_LENGTH_DELIMITED, target); + target = io::CodedOutputStream::WriteVarint32ToArray( + value.GetCachedSize(), target); + return value.SerializeWithCachedSizesToArray(target); +} + +// See comment on ReadGroupNoVirtual to understand the need for this template +// parameter name. +template +inline uint8* WireFormatLite::WriteGroupNoVirtualToArray( + int field_number, const MessageType_WorkAroundCppLookupDefect& value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_START_GROUP, target); + target = value.MessageType_WorkAroundCppLookupDefect + ::SerializeWithCachedSizesToArray(target); + return WriteTagToArray(field_number, WIRETYPE_END_GROUP, target); +} +template +inline uint8* WireFormatLite::WriteMessageNoVirtualToArray( + int field_number, const MessageType_WorkAroundCppLookupDefect& value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_LENGTH_DELIMITED, target); + target = io::CodedOutputStream::WriteVarint32ToArray( + value.MessageType_WorkAroundCppLookupDefect::GetCachedSize(), target); + return value.MessageType_WorkAroundCppLookupDefect + ::SerializeWithCachedSizesToArray(target); +} + +// =================================================================== + +inline int WireFormatLite::Int32Size(int32 value) { + return io::CodedOutputStream::VarintSize32SignExtended(value); +} +inline int WireFormatLite::Int64Size(int64 value) { + return io::CodedOutputStream::VarintSize64(static_cast(value)); +} +inline int WireFormatLite::UInt32Size(uint32 value) { + return io::CodedOutputStream::VarintSize32(value); +} +inline int WireFormatLite::UInt64Size(uint64 value) { + return io::CodedOutputStream::VarintSize64(value); +} +inline int WireFormatLite::SInt32Size(int32 value) { + return io::CodedOutputStream::VarintSize32(ZigZagEncode32(value)); +} +inline int WireFormatLite::SInt64Size(int64 value) { + return io::CodedOutputStream::VarintSize64(ZigZagEncode64(value)); +} +inline int WireFormatLite::EnumSize(int value) { + return io::CodedOutputStream::VarintSize32SignExtended(value); +} + +inline int WireFormatLite::StringSize(const string& value) { + return io::CodedOutputStream::VarintSize32(value.size()) + + value.size(); +} +inline int WireFormatLite::BytesSize(const string& value) { + return io::CodedOutputStream::VarintSize32(value.size()) + + value.size(); +} + + +inline int WireFormatLite::GroupSize(const MessageLite& value) { + return value.ByteSize(); +} +inline int WireFormatLite::MessageSize(const MessageLite& value) { + int size = value.ByteSize(); + return io::CodedOutputStream::VarintSize32(size) + size; +} + +// See comment on ReadGroupNoVirtual to understand the need for this template +// parameter name. +template +inline int WireFormatLite::GroupSizeNoVirtual( + const MessageType_WorkAroundCppLookupDefect& value) { + return value.MessageType_WorkAroundCppLookupDefect::ByteSize(); +} +template +inline int WireFormatLite::MessageSizeNoVirtual( + const MessageType_WorkAroundCppLookupDefect& value) { + int size = value.MessageType_WorkAroundCppLookupDefect::ByteSize(); + return io::CodedOutputStream::VarintSize32(size) + size; +} + +} // namespace internal +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_WIRE_FORMAT_LITE_INL_H__ diff --git a/depends/protobuf/testHashMap.cpp.in b/depends/protobuf/testHashMap.cpp.in new file mode 100644 index 0000000000..91187869ab --- /dev/null +++ b/depends/protobuf/testHashMap.cpp.in @@ -0,0 +1,6 @@ +#include <@header@> +int main() +{ + const @namespace@::@HASH_MAP_CLASS@ t; + return t.find(5) == t.end(); +} diff --git a/depends/sizecheck/CMakeLists.txt b/depends/sizecheck/CMakeLists.txt new file mode 100644 index 0000000000..b0d723631f --- /dev/null +++ b/depends/sizecheck/CMakeLists.txt @@ -0,0 +1,6 @@ +project(sizecheck) +add_library(sizecheck SHARED sizecheck.cpp) +ide_folder(sizecheck "Depends") +install(TARGETS sizecheck + LIBRARY DESTINATION ${DFHACK_LIBRARY_DESTINATION} + RUNTIME DESTINATION ${DFHACK_LIBRARY_DESTINATION}) diff --git a/depends/sizecheck/sizecheck.cpp b/depends/sizecheck/sizecheck.cpp new file mode 100644 index 0000000000..cd38ae9554 --- /dev/null +++ b/depends/sizecheck/sizecheck.cpp @@ -0,0 +1,76 @@ +// adapted from https://github.com/mifki/df-sizecheck/blob/master/b.cpp +// usage: +// linux: PRELOAD_LIB=hack/libsizecheck.so ./dfhack + +#include +#include +#include +#include +#include + +using namespace std; + +const uint32_t MAGIC = 0xdfdf4ac8; +bool initialized = false; +int perturb = -1; + +void init() { +#ifndef _LINUX + if (getenv("MALLOC_PERTURB_")) { + perturb = atoi(getenv("MALLOC_PERTURB_")); + } +#endif + initialized = true; +} + +#ifdef _WIN32 +static int posix_memalign(void **ptr, size_t alignment, size_t size) +{ + if ((*ptr = _aligned_malloc(size, alignment))) + { + return 0; + } + + return errno; +} +#endif + +void* alloc(size_t n) { + if (!initialized) { + init(); + } + void* addr; + if (posix_memalign(&addr, 32, n + 16) != 0) { + return addr; + } + memset(addr, 0, 16); + *(size_t*)addr = n; + *(uint32_t*)((uint8_t*)addr + 8) = MAGIC; + if (perturb > 0) { + memset((uint8_t*)addr + 16, ~(perturb & 0xff), n); + } + return (uint8_t*)addr + 16; +} + +void dealloc(void* addr) { + if (!initialized) { + init(); + } + if (uintptr_t(addr) % 32 == 16 && *(uint32_t*)((uint8_t*)addr - 8) == MAGIC) { + addr = (void*)((uint8_t*)addr - 16); + memset((uint8_t*)addr + 16, perturb & 0xff, *(size_t*)addr); + } + free(addr); +} + +void* operator new (size_t n, const nothrow_t& tag) { + return alloc(n); +} + +void* operator new (size_t n) { + return alloc(n); +} + +void operator delete (void* addr) { + return dealloc(addr); +} diff --git a/depends/tinyxml/CMakeLists.txt b/depends/tinyxml/CMakeLists.txt new file mode 100644 index 0000000000..b3c2902e44 --- /dev/null +++ b/depends/tinyxml/CMakeLists.txt @@ -0,0 +1,5 @@ +if(NOT TinyXML_FOUND) + project(dfhack-tinyxml) + add_library(dfhack-tinyxml STATIC EXCLUDE_FROM_ALL tinystr.cpp tinyxml.cpp tinyxmlerror.cpp tinyxmlparser.cpp) + ide_folder(dfhack-tinyxml "Depends") +endif() diff --git a/library/depends/tinyxml/tinystr.cpp b/depends/tinyxml/tinystr.cpp similarity index 96% rename from library/depends/tinyxml/tinystr.cpp rename to depends/tinyxml/tinystr.cpp index 681250714b..0665768205 100644 --- a/library/depends/tinyxml/tinystr.cpp +++ b/depends/tinyxml/tinystr.cpp @@ -1,6 +1,5 @@ /* www.sourceforge.net/projects/tinyxml -Original file by Yves Berquin. This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -22,10 +21,6 @@ must not be misrepresented as being the original software. distribution. */ -/* - * THIS FILE WAS ALTERED BY Tyge Lvset, 7. April 2005. - */ - #ifndef TIXML_USE_STL diff --git a/library/depends/tinyxml/tinystr.h b/depends/tinyxml/tinystr.h similarity index 93% rename from library/depends/tinyxml/tinystr.h rename to depends/tinyxml/tinystr.h index 3c2aa9d54d..89cca33415 100644 --- a/library/depends/tinyxml/tinystr.h +++ b/depends/tinyxml/tinystr.h @@ -1,6 +1,5 @@ /* www.sourceforge.net/projects/tinyxml -Original file by Yves Berquin. This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -22,17 +21,6 @@ must not be misrepresented as being the original software. distribution. */ -/* - * THIS FILE WAS ALTERED BY Tyge Lovset, 7. April 2005. - * - * - completely rewritten. compact, clean, and fast implementation. - * - sizeof(TiXmlString) = pointer size (4 bytes on 32-bit systems) - * - fixed reserve() to work as per specification. - * - fixed buggy compares operator==(), operator<(), and operator>() - * - fixed operator+=() to take a const ref argument, following spec. - * - added "copy" constructor with length, and most compare operators. - * - added swap(), clear(), size(), capacity(), operator+(). - */ #ifndef TIXML_USE_STL @@ -106,13 +94,11 @@ class TiXmlString quit(); } - // = operator TiXmlString& operator = (const char * copy) { return assign( copy, (size_type)strlen(copy)); } - // = operator TiXmlString& operator = (const TiXmlString & copy) { return assign(copy.start(), copy.length()); diff --git a/library/depends/tinyxml/tinyxml.cpp b/depends/tinyxml/tinyxml.cpp similarity index 81% rename from library/depends/tinyxml/tinyxml.cpp rename to depends/tinyxml/tinyxml.cpp index 5de21f6dec..9c161dfcb9 100644 --- a/library/depends/tinyxml/tinyxml.cpp +++ b/depends/tinyxml/tinyxml.cpp @@ -1,6 +1,6 @@ /* www.sourceforge.net/projects/tinyxml -Original code (2.0 and earlier )copyright (c) 2000-2006 Lee Thomason (www.grinninglizard.com) +Original code by Lee Thomason (www.grinninglizard.com) This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -31,6 +31,7 @@ distribution. #include "tinyxml.h" +FILE* TiXmlFOpen( const char* filename, const char* mode ); bool TiXmlBase::condenseWhiteSpace = true; @@ -161,6 +162,7 @@ void TiXmlNode::CopyTo( TiXmlNode* target ) const { target->SetValue (value.c_str() ); target->userData = userData; + target->location = location; } @@ -186,10 +188,11 @@ TiXmlNode* TiXmlNode::LinkEndChild( TiXmlNode* node ) assert( node->parent == 0 || node->parent == this ); assert( node->GetDocument() == 0 || node->GetDocument() == this->GetDocument() ); - if ( node->Type() == TiXmlNode::DOCUMENT ) + if ( node->Type() == TiXmlNode::TINYXML_DOCUMENT ) { delete node; - if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); + if ( GetDocument() ) + GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); return 0; } @@ -210,9 +213,10 @@ TiXmlNode* TiXmlNode::LinkEndChild( TiXmlNode* node ) TiXmlNode* TiXmlNode::InsertEndChild( const TiXmlNode& addThis ) { - if ( addThis.Type() == TiXmlNode::DOCUMENT ) + if ( addThis.Type() == TiXmlNode::TINYXML_DOCUMENT ) { - if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); + if ( GetDocument() ) + GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); return 0; } TiXmlNode* node = addThis.Clone(); @@ -228,9 +232,10 @@ TiXmlNode* TiXmlNode::InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& if ( !beforeThis || beforeThis->parent != this ) { return 0; } - if ( addThis.Type() == TiXmlNode::DOCUMENT ) + if ( addThis.Type() == TiXmlNode::TINYXML_DOCUMENT ) { - if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); + if ( GetDocument() ) + GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); return 0; } @@ -260,9 +265,10 @@ TiXmlNode* TiXmlNode::InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& a if ( !afterThis || afterThis->parent != this ) { return 0; } - if ( addThis.Type() == TiXmlNode::DOCUMENT ) + if ( addThis.Type() == TiXmlNode::TINYXML_DOCUMENT ) { - if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); + if ( GetDocument() ) + GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); return 0; } @@ -289,9 +295,20 @@ TiXmlNode* TiXmlNode::InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& a TiXmlNode* TiXmlNode::ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis ) { + if ( !replaceThis ) + return 0; + if ( replaceThis->parent != this ) return 0; + if ( withThis.ToDocument() ) { + // A document can never be a child. Thanks to Noam. + TiXmlDocument* document = GetDocument(); + if ( document ) + document->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return 0; + } + TiXmlNode* node = withThis.Clone(); if ( !node ) return 0; @@ -317,6 +334,10 @@ TiXmlNode* TiXmlNode::ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& wit bool TiXmlNode::RemoveChild( TiXmlNode* removeThis ) { + if ( !removeThis ) { + return false; + } + if ( removeThis->parent != this ) { assert( 0 ); @@ -502,7 +523,7 @@ const TiXmlDocument* TiXmlNode::GetDocument() const TiXmlElement::TiXmlElement (const char * _value) - : TiXmlNode( TiXmlNode::ELEMENT ) + : TiXmlNode( TiXmlNode::TINYXML_ELEMENT ) { firstChild = lastChild = 0; value = _value; @@ -511,7 +532,7 @@ TiXmlElement::TiXmlElement (const char * _value) #ifdef TIXML_USE_STL TiXmlElement::TiXmlElement( const std::string& _value ) - : TiXmlNode( TiXmlNode::ELEMENT ) + : TiXmlNode( TiXmlNode::TINYXML_ELEMENT ) { firstChild = lastChild = 0; value = _value; @@ -520,17 +541,18 @@ TiXmlElement::TiXmlElement( const std::string& _value ) TiXmlElement::TiXmlElement( const TiXmlElement& copy) - : TiXmlNode( TiXmlNode::ELEMENT ) + : TiXmlNode( TiXmlNode::TINYXML_ELEMENT ) { firstChild = lastChild = 0; copy.CopyTo( this ); } -void TiXmlElement::operator=( const TiXmlElement& base ) +TiXmlElement& TiXmlElement::operator=( const TiXmlElement& base ) { ClearThis(); base.CopyTo( this ); + return *this; } @@ -564,9 +586,9 @@ const char* TiXmlElement::Attribute( const char* name ) const #ifdef TIXML_USE_STL const std::string* TiXmlElement::Attribute( const std::string& name ) const { - const TiXmlAttribute* node = attributeSet.Find( name ); - if ( node ) - return &node->ValueStr(); + const TiXmlAttribute* attrib = attributeSet.Find( name ); + if ( attrib ) + return &attrib->ValueStr(); return 0; } #endif @@ -574,195 +596,202 @@ const std::string* TiXmlElement::Attribute( const std::string& name ) const const char* TiXmlElement::Attribute( const char* name, int* i ) const { - const char* s = Attribute( name ); - if ( i ) - { - if ( s ) { - *i = atoi( s ); - } - else { - *i = 0; + const TiXmlAttribute* attrib = attributeSet.Find( name ); + const char* result = 0; + + if ( attrib ) { + result = attrib->Value(); + if ( i ) { + attrib->QueryIntValue( i ); } } - return s; + return result; } #ifdef TIXML_USE_STL const std::string* TiXmlElement::Attribute( const std::string& name, int* i ) const { - const std::string* s = Attribute( name ); - if ( i ) - { - if ( s ) { - *i = atoi( s->c_str() ); - } - else { - *i = 0; + const TiXmlAttribute* attrib = attributeSet.Find( name ); + const std::string* result = 0; + + if ( attrib ) { + result = &attrib->ValueStr(); + if ( i ) { + attrib->QueryIntValue( i ); } } - return s; + return result; } #endif const char* TiXmlElement::Attribute( const char* name, double* d ) const { - const char* s = Attribute( name ); - if ( d ) - { - if ( s ) { - *d = atof( s ); - } - else { - *d = 0; + const TiXmlAttribute* attrib = attributeSet.Find( name ); + const char* result = 0; + + if ( attrib ) { + result = attrib->Value(); + if ( d ) { + attrib->QueryDoubleValue( d ); } } - return s; + return result; } #ifdef TIXML_USE_STL const std::string* TiXmlElement::Attribute( const std::string& name, double* d ) const { - const std::string* s = Attribute( name ); - if ( d ) - { - if ( s ) { - *d = atof( s->c_str() ); - } - else { - *d = 0; + const TiXmlAttribute* attrib = attributeSet.Find( name ); + const std::string* result = 0; + + if ( attrib ) { + result = &attrib->ValueStr(); + if ( d ) { + attrib->QueryDoubleValue( d ); } } - return s; + return result; } #endif int TiXmlElement::QueryIntAttribute( const char* name, int* ival ) const +{ + const TiXmlAttribute* attrib = attributeSet.Find( name ); + if ( !attrib ) + return TIXML_NO_ATTRIBUTE; + return attrib->QueryIntValue( ival ); +} + + +int TiXmlElement::QueryUnsignedAttribute( const char* name, unsigned* value ) const { const TiXmlAttribute* node = attributeSet.Find( name ); if ( !node ) return TIXML_NO_ATTRIBUTE; - return node->QueryIntValue( ival ); + + int ival = 0; + int result = node->QueryIntValue( &ival ); + *value = (unsigned)ival; + return result; } -#ifdef TIXML_USE_STL -int TiXmlElement::QueryIntAttribute( const std::string& name, int* ival ) const +int TiXmlElement::QueryBoolAttribute( const char* name, bool* bval ) const { const TiXmlAttribute* node = attributeSet.Find( name ); if ( !node ) return TIXML_NO_ATTRIBUTE; - return node->QueryIntValue( ival ); + + int result = TIXML_WRONG_TYPE; + if ( StringEqual( node->Value(), "true", true, TIXML_ENCODING_UNKNOWN ) + || StringEqual( node->Value(), "yes", true, TIXML_ENCODING_UNKNOWN ) + || StringEqual( node->Value(), "1", true, TIXML_ENCODING_UNKNOWN ) ) + { + *bval = true; + result = TIXML_SUCCESS; + } + else if ( StringEqual( node->Value(), "false", true, TIXML_ENCODING_UNKNOWN ) + || StringEqual( node->Value(), "no", true, TIXML_ENCODING_UNKNOWN ) + || StringEqual( node->Value(), "0", true, TIXML_ENCODING_UNKNOWN ) ) + { + *bval = false; + result = TIXML_SUCCESS; + } + return result; +} + + + +#ifdef TIXML_USE_STL +int TiXmlElement::QueryIntAttribute( const std::string& name, int* ival ) const +{ + const TiXmlAttribute* attrib = attributeSet.Find( name ); + if ( !attrib ) + return TIXML_NO_ATTRIBUTE; + return attrib->QueryIntValue( ival ); } #endif int TiXmlElement::QueryDoubleAttribute( const char* name, double* dval ) const { - const TiXmlAttribute* node = attributeSet.Find( name ); - if ( !node ) + const TiXmlAttribute* attrib = attributeSet.Find( name ); + if ( !attrib ) return TIXML_NO_ATTRIBUTE; - return node->QueryDoubleValue( dval ); + return attrib->QueryDoubleValue( dval ); } #ifdef TIXML_USE_STL int TiXmlElement::QueryDoubleAttribute( const std::string& name, double* dval ) const { - const TiXmlAttribute* node = attributeSet.Find( name ); - if ( !node ) + const TiXmlAttribute* attrib = attributeSet.Find( name ); + if ( !attrib ) return TIXML_NO_ATTRIBUTE; - return node->QueryDoubleValue( dval ); + return attrib->QueryDoubleValue( dval ); } #endif void TiXmlElement::SetAttribute( const char * name, int val ) { - char buf[64]; - #if defined(TIXML_SNPRINTF) - TIXML_SNPRINTF( buf, sizeof(buf), "%d", val ); - #else - sprintf( buf, "%d", val ); - #endif - SetAttribute( name, buf ); + TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); + if ( attrib ) { + attrib->SetIntValue( val ); + } } #ifdef TIXML_USE_STL void TiXmlElement::SetAttribute( const std::string& name, int val ) { - std::ostringstream oss; - oss << val; - SetAttribute( name, oss.str() ); + TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); + if ( attrib ) { + attrib->SetIntValue( val ); + } } #endif void TiXmlElement::SetDoubleAttribute( const char * name, double val ) { - char buf[256]; - #if defined(TIXML_SNPRINTF) - TIXML_SNPRINTF( buf, sizeof(buf), "%f", val ); - #else - sprintf( buf, "%f", val ); - #endif - SetAttribute( name, buf ); + TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); + if ( attrib ) { + attrib->SetDoubleValue( val ); + } } -void TiXmlElement::SetAttribute( const char * cname, const char * cvalue ) -{ - #ifdef TIXML_USE_STL - TIXML_STRING _name( cname ); - TIXML_STRING _value( cvalue ); - #else - const char* _name = cname; - const char* _value = cvalue; - #endif - - TiXmlAttribute* node = attributeSet.Find( _name ); - if ( node ) - { - node->SetValue( _value ); - return; +#ifdef TIXML_USE_STL +void TiXmlElement::SetDoubleAttribute( const std::string& name, double val ) +{ + TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); + if ( attrib ) { + attrib->SetDoubleValue( val ); } +} +#endif - TiXmlAttribute* attrib = new TiXmlAttribute( cname, cvalue ); - if ( attrib ) - { - attributeSet.Add( attrib ); - } - else - { - TiXmlDocument* document = GetDocument(); - if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN ); + +void TiXmlElement::SetAttribute( const char * cname, const char * cvalue ) +{ + TiXmlAttribute* attrib = attributeSet.FindOrCreate( cname ); + if ( attrib ) { + attrib->SetValue( cvalue ); } } #ifdef TIXML_USE_STL -void TiXmlElement::SetAttribute( const std::string& name, const std::string& _value ) +void TiXmlElement::SetAttribute( const std::string& _name, const std::string& _value ) { - TiXmlAttribute* node = attributeSet.Find( name ); - if ( node ) - { - node->SetValue( _value ); - return; - } - - TiXmlAttribute* attrib = new TiXmlAttribute( name, _value ); - if ( attrib ) - { - attributeSet.Add( attrib ); - } - else - { - TiXmlDocument* document = GetDocument(); - if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN ); + TiXmlAttribute* attrib = attributeSet.FindOrCreate( _name ); + if ( attrib ) { + attrib->SetValue( _value ); } } #endif @@ -881,14 +910,14 @@ const char* TiXmlElement::GetText() const } -TiXmlDocument::TiXmlDocument() : TiXmlNode( TiXmlNode::DOCUMENT ) +TiXmlDocument::TiXmlDocument() : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT ) { tabsize = 4; useMicrosoftBOM = false; ClearError(); } -TiXmlDocument::TiXmlDocument( const char * documentName ) : TiXmlNode( TiXmlNode::DOCUMENT ) +TiXmlDocument::TiXmlDocument( const char * documentName ) : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT ) { tabsize = 4; useMicrosoftBOM = false; @@ -898,7 +927,7 @@ TiXmlDocument::TiXmlDocument( const char * documentName ) : TiXmlNode( TiXmlNode #ifdef TIXML_USE_STL -TiXmlDocument::TiXmlDocument( const std::string& documentName ) : TiXmlNode( TiXmlNode::DOCUMENT ) +TiXmlDocument::TiXmlDocument( const std::string& documentName ) : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT ) { tabsize = 4; useMicrosoftBOM = false; @@ -908,49 +937,33 @@ TiXmlDocument::TiXmlDocument( const std::string& documentName ) : TiXmlNode( TiX #endif -TiXmlDocument::TiXmlDocument( const TiXmlDocument& copy ) : TiXmlNode( TiXmlNode::DOCUMENT ) +TiXmlDocument::TiXmlDocument( const TiXmlDocument& copy ) : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT ) { copy.CopyTo( this ); } -void TiXmlDocument::operator=( const TiXmlDocument& copy ) +TiXmlDocument& TiXmlDocument::operator=( const TiXmlDocument& copy ) { Clear(); copy.CopyTo( this ); + return *this; } bool TiXmlDocument::LoadFile( TiXmlEncoding encoding ) { - // See STL_STRING_BUG below. - //StringToBuffer buf( value ); - return LoadFile( Value(), encoding ); } bool TiXmlDocument::SaveFile() const { - // See STL_STRING_BUG below. -// StringToBuffer buf( value ); -// -// if ( buf.buffer && SaveFile( buf.buffer ) ) -// return true; -// -// return false; return SaveFile( Value() ); } bool TiXmlDocument::LoadFile( const char* _filename, TiXmlEncoding encoding ) { - // There was a really terrifying little bug here. The code: - // value = filename - // in the STL case, cause the assignment method of the std::string to - // be called. What is strange, is that the std::string had the same - // address as it's c_str() method, and so bad things happen. Looks - // like a bug in the Microsoft STL implementation. - // Add an extra string to avoid the crash. TIXML_STRING filename( _filename ); value = filename; @@ -995,11 +1008,6 @@ bool TiXmlDocument::LoadFile( FILE* file, TiXmlEncoding encoding ) return false; } - // If we have a file, assume it is all one big XML file, and read it in. - // The document parser may decide the document ends sooner than the entire file, however. - TIXML_STRING data; - data.reserve( length ); - // Subtle bug here. TinyXml did use fgets. But from the XML spec: // 2.11 End-of-Line Handling // @@ -1030,58 +1038,46 @@ bool TiXmlDocument::LoadFile( FILE* file, TiXmlEncoding encoding ) return false; } - const char* lastPos = buf; - const char* p = buf; + // Process the buffer in place to normalize new lines. (See comment above.) + // Copies from the 'p' to 'q' pointer, where p can advance faster if + // a newline-carriage return is hit. + // + // Wikipedia: + // Systems based on ASCII or a compatible character set use either LF (Line feed, '\n', 0x0A, 10 in decimal) or + // CR (Carriage return, '\r', 0x0D, 13 in decimal) individually, or CR followed by LF (CR+LF, 0x0D 0x0A)... + // * LF: Multics, Unix and Unix-like systems (GNU/Linux, AIX, Xenix, Mac OS X, FreeBSD, etc.), BeOS, Amiga, RISC OS, and others + // * CR+LF: DEC RT-11 and most other early non-Unix, non-IBM OSes, CP/M, MP/M, DOS, OS/2, Microsoft Windows, Symbian OS + // * CR: Commodore 8-bit machines, Apple II family, Mac OS up to version 9 and OS-9 + + const char* p = buf; // the read head + char* q = buf; // the write head + const char CR = 0x0d; + const char LF = 0x0a; buf[length] = 0; while( *p ) { assert( p < (buf+length) ); - if ( *p == 0xa ) { - // Newline character. No special rules for this. Append all the characters - // since the last string, and include the newline. - data.append( lastPos, (p-lastPos+1) ); // append, include the newline - ++p; // move past the newline - lastPos = p; // and point to the new buffer (may be 0) - assert( p <= (buf+length) ); - } - else if ( *p == 0xd ) { - // Carriage return. Append what we have so far, then - // handle moving forward in the buffer. - if ( (p-lastPos) > 0 ) { - data.append( lastPos, p-lastPos ); // do not add the CR - } - data += (char)0xa; // a proper newline - - if ( *(p+1) == 0xa ) { - // Carriage return - new line sequence - p += 2; - lastPos = p; - assert( p <= (buf+length) ); - } - else { - // it was followed by something else...that is presumably characters again. - ++p; - lastPos = p; - assert( p <= (buf+length) ); + assert( q <= (buf+length) ); + assert( q <= p ); + + if ( *p == CR ) { + *q++ = LF; + p++; + if ( *p == LF ) { // check for CR+LF (and skip LF) + p++; } } else { - ++p; + *q++ = *p++; } } - // Handle any left over characters. - if ( p-lastPos ) { - data.append( lastPos, p-lastPos ); - } - delete [] buf; - buf = 0; + assert( q <= (buf+length) ); + *q = 0; - Parse( data.c_str(), 0, encoding ); + Parse( buf, 0, encoding ); - if ( Error() ) - return false; - else - return true; + delete [] buf; + return !Error(); } @@ -1220,7 +1216,7 @@ void TiXmlAttribute::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) cons if (value.find ('\"') == TIXML_STRING::npos) { if ( cfile ) { - fprintf (cfile, "%s=\"%s\"", n.c_str(), v.c_str() ); + fprintf (cfile, "%s=\"%s\"", n.c_str(), v.c_str() ); } if ( str ) { (*str) += n; (*str) += "=\""; (*str) += v; (*str) += "\""; @@ -1228,7 +1224,7 @@ void TiXmlAttribute::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) cons } else { if ( cfile ) { - fprintf (cfile, "%s='%s'", n.c_str(), v.c_str() ); + fprintf (cfile, "%s='%s'", n.c_str(), v.c_str() ); } if ( str ) { (*str) += n; (*str) += "='"; (*str) += v; (*str) += "'"; @@ -1266,9 +1262,9 @@ void TiXmlAttribute::SetDoubleValue( double _value ) { char buf [256]; #if defined(TIXML_SNPRINTF) - TIXML_SNPRINTF( buf, sizeof(buf), "%lf", _value); + TIXML_SNPRINTF( buf, sizeof(buf), "%g", _value); #else - sprintf (buf, "%lf", _value); + sprintf (buf, "%g", _value); #endif SetValue (buf); } @@ -1284,16 +1280,17 @@ double TiXmlAttribute::DoubleValue() const } -TiXmlComment::TiXmlComment( const TiXmlComment& copy ) : TiXmlNode( TiXmlNode::COMMENT ) +TiXmlComment::TiXmlComment( const TiXmlComment& copy ) : TiXmlNode( TiXmlNode::TINYXML_COMMENT ) { copy.CopyTo( this ); } -void TiXmlComment::operator=( const TiXmlComment& base ) +TiXmlComment& TiXmlComment::operator=( const TiXmlComment& base ) { Clear(); base.CopyTo( this ); + return *this; } @@ -1382,7 +1379,7 @@ TiXmlNode* TiXmlText::Clone() const TiXmlDeclaration::TiXmlDeclaration( const char * _version, const char * _encoding, const char * _standalone ) - : TiXmlNode( TiXmlNode::DECLARATION ) + : TiXmlNode( TiXmlNode::TINYXML_DECLARATION ) { version = _version; encoding = _encoding; @@ -1394,7 +1391,7 @@ TiXmlDeclaration::TiXmlDeclaration( const char * _version, TiXmlDeclaration::TiXmlDeclaration( const std::string& _version, const std::string& _encoding, const std::string& _standalone ) - : TiXmlNode( TiXmlNode::DECLARATION ) + : TiXmlNode( TiXmlNode::TINYXML_DECLARATION ) { version = _version; encoding = _encoding; @@ -1404,16 +1401,17 @@ TiXmlDeclaration::TiXmlDeclaration( const std::string& _version, TiXmlDeclaration::TiXmlDeclaration( const TiXmlDeclaration& copy ) - : TiXmlNode( TiXmlNode::DECLARATION ) + : TiXmlNode( TiXmlNode::TINYXML_DECLARATION ) { copy.CopyTo( this ); } -void TiXmlDeclaration::operator=( const TiXmlDeclaration& copy ) +TiXmlDeclaration& TiXmlDeclaration::operator=( const TiXmlDeclaration& copy ) { Clear(); copy.CopyTo( this ); + return *this; } @@ -1548,9 +1546,9 @@ void TiXmlAttributeSet::Remove( TiXmlAttribute* removeMe ) #ifdef TIXML_USE_STL -const TiXmlAttribute* TiXmlAttributeSet::Find( const std::string& name ) const +TiXmlAttribute* TiXmlAttributeSet::Find( const std::string& name ) const { - for( const TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) + for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) { if ( node->name == name ) return node; @@ -1558,23 +1556,22 @@ const TiXmlAttribute* TiXmlAttributeSet::Find( const std::string& name ) const return 0; } -/* -TiXmlAttribute* TiXmlAttributeSet::Find( const std::string& name ) +TiXmlAttribute* TiXmlAttributeSet::FindOrCreate( const std::string& _name ) { - for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) - { - if ( node->name == name ) - return node; + TiXmlAttribute* attrib = Find( _name ); + if ( !attrib ) { + attrib = new TiXmlAttribute(); + Add( attrib ); + attrib->SetName( _name ); } - return 0; + return attrib; } -*/ #endif -const TiXmlAttribute* TiXmlAttributeSet::Find( const char* name ) const +TiXmlAttribute* TiXmlAttributeSet::Find( const char* name ) const { - for( const TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) + for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) { if ( strcmp( node->name.c_str(), name ) == 0 ) return node; @@ -1582,17 +1579,18 @@ const TiXmlAttribute* TiXmlAttributeSet::Find( const char* name ) const return 0; } -/* -TiXmlAttribute* TiXmlAttributeSet::Find( const char* name ) + +TiXmlAttribute* TiXmlAttributeSet::FindOrCreate( const char* _name ) { - for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) - { - if ( strcmp( node->name.c_str(), name ) == 0 ) - return node; + TiXmlAttribute* attrib = Find( _name ); + if ( !attrib ) { + attrib = new TiXmlAttribute(); + Add( attrib ); + attrib->SetName( _name ); } - return 0; + return attrib; } -*/ + #ifdef TIXML_USE_STL std::istream& operator>> (std::istream & in, TiXmlNode & base) diff --git a/library/depends/tinyxml/tinyxml.h b/depends/tinyxml/tinyxml.h similarity index 95% rename from library/depends/tinyxml/tinyxml.h rename to depends/tinyxml/tinyxml.h index c6f40cc27a..a3589e5b26 100644 --- a/library/depends/tinyxml/tinyxml.h +++ b/depends/tinyxml/tinyxml.h @@ -1,6 +1,6 @@ /* www.sourceforge.net/projects/tinyxml -Original code (2.0 and earlier )copyright (c) 2000-2006 Lee Thomason (www.grinninglizard.com) +Original code by Lee Thomason (www.grinninglizard.com) This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -63,21 +63,19 @@ distribution. #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) // Microsoft visual studio, version 2005 and higher. #define TIXML_SNPRINTF _snprintf_s - #define TIXML_SNSCANF _snscanf_s #define TIXML_SSCANF sscanf_s #elif defined(_MSC_VER) && (_MSC_VER >= 1200 ) // Microsoft visual studio, version 6 and higher. //#pragma message( "Using _sn* functions." ) #define TIXML_SNPRINTF _snprintf - #define TIXML_SNSCANF _snscanf #define TIXML_SSCANF sscanf #elif defined(__GNUC__) && (__GNUC__ >= 3 ) // GCC version 3 and higher.s //#warning( "Using sn* functions." ) #define TIXML_SNPRINTF snprintf - #define TIXML_SNSCANF snscanf #define TIXML_SSCANF sscanf #else + #define TIXML_SNPRINTF snprintf #define TIXML_SSCANF sscanf #endif #endif @@ -92,8 +90,8 @@ class TiXmlDeclaration; class TiXmlParsingData; const int TIXML_MAJOR_VERSION = 2; -const int TIXML_MINOR_VERSION = 5; -const int TIXML_PATCH_VERSION = 3; +const int TIXML_MINOR_VERSION = 6; +const int TIXML_PATCH_VERSION = 2; /* Internal structure for tracking location of items in the XML file. @@ -109,10 +107,11 @@ struct TiXmlCursor /** + Implements the interface to the "Visitor pattern" (see the Accept() method.) If you call the Accept() method, it requires being passed a TiXmlVisitor class to handle callbacks. For nodes that contain other nodes (Document, Element) you will get called with a VisitEnter/VisitExit pair. Nodes that are always leaves - are simple called with Visit(). + are simply called with Visit(). If you return 'true' from a Visit method, recursive parsing will continue. If you return false, no children of this node or its sibilings will be Visited. @@ -147,7 +146,7 @@ class TiXmlVisitor virtual bool Visit( const TiXmlText& /*text*/ ) { return true; } /// Visit a comment node virtual bool Visit( const TiXmlComment& /*comment*/ ) { return true; } - /// Visit an unknow node + /// Visit an unknown node virtual bool Visit( const TiXmlUnknown& /*unknown*/ ) { return true; } }; @@ -267,7 +266,6 @@ class TiXmlBase TIXML_NO_ERROR = 0, TIXML_ERROR, TIXML_ERROR_OPENING_FILE, - TIXML_ERROR_OUT_OF_MEMORY, TIXML_ERROR_PARSING_ELEMENT, TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME, TIXML_ERROR_READING_ELEMENT_VALUE, @@ -288,6 +286,7 @@ class TiXmlBase protected: static const char* SkipWhiteSpace( const char*, TiXmlEncoding encoding ); + inline static bool IsWhiteSpace( char c ) { return ( isspace( (unsigned char) c ) || c == '\n' || c == '\r' ); @@ -462,13 +461,13 @@ class TiXmlNode : public TiXmlBase */ enum NodeType { - DOCUMENT, - ELEMENT, - COMMENT, - UNKNOWN, - TEXT, - DECLARATION, - TYPECOUNT + TINYXML_DOCUMENT, + TINYXML_ELEMENT, + TINYXML_COMMENT, + TINYXML_UNKNOWN, + TINYXML_TEXT, + TINYXML_DECLARATION, + TINYXML_TYPECOUNT }; virtual ~TiXmlNode(); @@ -679,8 +678,8 @@ class TiXmlNode : public TiXmlBase #endif /** Query the type (as an enumerated value, above) of this node. - The possible types are: DOCUMENT, ELEMENT, COMMENT, - UNKNOWN, TEXT, and DECLARATION. + The possible types are: TINYXML_DOCUMENT, TINYXML_ELEMENT, TINYXML_COMMENT, + TINYXML_UNKNOWN, TINYXML_TEXT, and TINYXML_DECLARATION. */ int Type() const { return type; } @@ -915,17 +914,14 @@ class TiXmlAttributeSet const TiXmlAttribute* Last() const { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; } TiXmlAttribute* Last() { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; } - const TiXmlAttribute* Find( const char* _name ) const; - TiXmlAttribute* Find( const char* _name ) { - return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttributeSet* >(this))->Find( _name ) ); - } - #ifdef TIXML_USE_STL - const TiXmlAttribute* Find( const std::string& _name ) const; - TiXmlAttribute* Find( const std::string& _name ) { - return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttributeSet* >(this))->Find( _name ) ); - } + TiXmlAttribute* Find( const char* _name ) const; + TiXmlAttribute* FindOrCreate( const char* _name ); + +# ifdef TIXML_USE_STL + TiXmlAttribute* Find( const std::string& _name ) const; + TiXmlAttribute* FindOrCreate( const std::string& _name ); +# endif - #endif private: //*ME: Because of hidden/disabled copy-construktor in TiXmlAttribute (sentinel-element), @@ -954,7 +950,7 @@ class TiXmlElement : public TiXmlNode TiXmlElement( const TiXmlElement& ); - void operator=( const TiXmlElement& base ); + TiXmlElement& operator=( const TiXmlElement& base ); virtual ~TiXmlElement(); @@ -987,6 +983,13 @@ class TiXmlElement : public TiXmlNode does not exist, then TIXML_NO_ATTRIBUTE is returned. */ int QueryIntAttribute( const char* name, int* _value ) const; + /// QueryUnsignedAttribute examines the attribute - see QueryIntAttribute(). + int QueryUnsignedAttribute( const char* name, unsigned* _value ) const; + /** QueryBoolAttribute examines the attribute - see QueryIntAttribute(). + Note that '1', 'true', or 'yes' are considered true, while '0', 'false' + and 'no' are considered false. + */ + int QueryBoolAttribute( const char* name, bool* _value ) const; /// QueryDoubleAttribute examines the attribute - see QueryIntAttribute(). int QueryDoubleAttribute( const char* name, double* _value ) const; /// QueryFloatAttribute examines the attribute - see QueryIntAttribute(). @@ -1000,11 +1003,21 @@ class TiXmlElement : public TiXmlNode } #ifdef TIXML_USE_STL + /// QueryStringAttribute examines the attribute - see QueryIntAttribute(). + int QueryStringAttribute( const char* name, std::string* _value ) const { + const char* cstr = Attribute( name ); + if ( cstr ) { + *_value = std::string( cstr ); + return TIXML_SUCCESS; + } + return TIXML_NO_ATTRIBUTE; + } + /** Template form of the attribute query which will try to read the attribute into the specified type. Very easy, very powerful, but be careful to make sure to call this with the correct type. - NOTE: This method doesn't work correctly for 'string' types. + NOTE: This method doesn't work correctly for 'string' types that contain spaces. @return TIXML_SUCCESS, TIXML_WRONG_TYPE, or TIXML_NO_ATTRIBUTE */ @@ -1020,13 +1033,8 @@ class TiXmlElement : public TiXmlNode return TIXML_SUCCESS; return TIXML_WRONG_TYPE; } - /* - This is - in theory - a bug fix for "QueryValueAtribute returns truncated std::string" - but template specialization is hard to get working cross-compiler. Leaving the bug for now. - - // The above will fail for std::string because the space character is used as a seperator. - // Specialize for strings. Bug [ 1695429 ] QueryValueAtribute returns truncated std::string - template<> int QueryValueAttribute( const std::string& name, std::string* outValue ) const + + int QueryValueAttribute( const std::string& name, std::string* outValue ) const { const TiXmlAttribute* node = attributeSet.Find( name ); if ( !node ) @@ -1034,7 +1042,6 @@ class TiXmlElement : public TiXmlNode *outValue = node->ValueStr(); return TIXML_SUCCESS; } - */ #endif /** Sets an attribute of name to a given value. The attribute @@ -1053,6 +1060,8 @@ class TiXmlElement : public TiXmlNode void SetAttribute( const std::string& name, const std::string& _value ); ///< STL std::string form. void SetAttribute( const std::string& name, int _value ); + ///< STL std::string form. + void SetDoubleAttribute( const std::string& name, double value ); #endif /** Sets an attribute of name to a given value. The attribute @@ -1144,7 +1153,6 @@ class TiXmlElement : public TiXmlNode const char* ReadValue( const char* in, TiXmlParsingData* prevData, TiXmlEncoding encoding ); private: - TiXmlAttributeSet attributeSet; }; @@ -1155,13 +1163,13 @@ class TiXmlComment : public TiXmlNode { public: /// Constructs an empty comment. - TiXmlComment() : TiXmlNode( TiXmlNode::COMMENT ) {} + TiXmlComment() : TiXmlNode( TiXmlNode::TINYXML_COMMENT ) {} /// Construct a comment from text. - TiXmlComment( const char* _value ) : TiXmlNode( TiXmlNode::COMMENT ) { + TiXmlComment( const char* _value ) : TiXmlNode( TiXmlNode::TINYXML_COMMENT ) { SetValue( _value ); } TiXmlComment( const TiXmlComment& ); - void operator=( const TiXmlComment& base ); + TiXmlComment& operator=( const TiXmlComment& base ); virtual ~TiXmlComment() {} @@ -1175,8 +1183,8 @@ class TiXmlComment : public TiXmlNode */ virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); - virtual const TiXmlComment* ToComment() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - virtual TiXmlComment* ToComment() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + virtual const TiXmlComment* ToComment() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + virtual TiXmlComment* ToComment() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. /** Walk the XML tree visiting this node and all of its children. */ @@ -1209,7 +1217,7 @@ class TiXmlText : public TiXmlNode normal, encoded text. If you want it be output as a CDATA text element, set the parameter _cdata to 'true' */ - TiXmlText (const char * initValue ) : TiXmlNode (TiXmlNode::TEXT) + TiXmlText (const char * initValue ) : TiXmlNode (TiXmlNode::TINYXML_TEXT) { SetValue( initValue ); cdata = false; @@ -1218,15 +1226,15 @@ class TiXmlText : public TiXmlNode #ifdef TIXML_USE_STL /// Constructor. - TiXmlText( const std::string& initValue ) : TiXmlNode (TiXmlNode::TEXT) + TiXmlText( const std::string& initValue ) : TiXmlNode (TiXmlNode::TINYXML_TEXT) { SetValue( initValue ); cdata = false; } #endif - TiXmlText( const TiXmlText& copy ) : TiXmlNode( TiXmlNode::TEXT ) { copy.CopyTo( this ); } - void operator=( const TiXmlText& base ) { base.CopyTo( this ); } + TiXmlText( const TiXmlText& copy ) : TiXmlNode( TiXmlNode::TINYXML_TEXT ) { copy.CopyTo( this ); } + TiXmlText& operator=( const TiXmlText& base ) { base.CopyTo( this ); return *this; } // Write this text object to a FILE stream. virtual void Print( FILE* cfile, int depth ) const; @@ -1278,7 +1286,7 @@ class TiXmlDeclaration : public TiXmlNode { public: /// Construct an empty declaration. - TiXmlDeclaration() : TiXmlNode( TiXmlNode::DECLARATION ) {} + TiXmlDeclaration() : TiXmlNode( TiXmlNode::TINYXML_DECLARATION ) {} #ifdef TIXML_USE_STL /// Constructor. @@ -1293,7 +1301,7 @@ class TiXmlDeclaration : public TiXmlNode const char* _standalone ); TiXmlDeclaration( const TiXmlDeclaration& copy ); - void operator=( const TiXmlDeclaration& copy ); + TiXmlDeclaration& operator=( const TiXmlDeclaration& copy ); virtual ~TiXmlDeclaration() {} @@ -1346,11 +1354,11 @@ class TiXmlDeclaration : public TiXmlNode class TiXmlUnknown : public TiXmlNode { public: - TiXmlUnknown() : TiXmlNode( TiXmlNode::UNKNOWN ) {} + TiXmlUnknown() : TiXmlNode( TiXmlNode::TINYXML_UNKNOWN ) {} virtual ~TiXmlUnknown() {} - TiXmlUnknown( const TiXmlUnknown& copy ) : TiXmlNode( TiXmlNode::UNKNOWN ) { copy.CopyTo( this ); } - void operator=( const TiXmlUnknown& copy ) { copy.CopyTo( this ); } + TiXmlUnknown( const TiXmlUnknown& copy ) : TiXmlNode( TiXmlNode::TINYXML_UNKNOWN ) { copy.CopyTo( this ); } + TiXmlUnknown& operator=( const TiXmlUnknown& copy ) { copy.CopyTo( this ); return *this; } /// Creates a copy of this Unknown and returns it. virtual TiXmlNode* Clone() const; @@ -1359,8 +1367,8 @@ class TiXmlUnknown : public TiXmlNode virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); - virtual const TiXmlUnknown* ToUnknown() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - virtual TiXmlUnknown* ToUnknown() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + virtual const TiXmlUnknown* ToUnknown() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + virtual TiXmlUnknown* ToUnknown() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. /** Walk the XML tree visiting this node and all of its children. */ @@ -1396,7 +1404,7 @@ class TiXmlDocument : public TiXmlNode #endif TiXmlDocument( const TiXmlDocument& copy ); - void operator=( const TiXmlDocument& copy ); + TiXmlDocument& operator=( const TiXmlDocument& copy ); virtual ~TiXmlDocument() {} @@ -1423,14 +1431,10 @@ class TiXmlDocument : public TiXmlNode #ifdef TIXML_USE_STL bool LoadFile( const std::string& filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ) ///< STL std::string version. { -// StringToBuffer f( filename ); -// return ( f.buffer && LoadFile( f.buffer, encoding )); return LoadFile( filename.c_str(), encoding ); } bool SaveFile( const std::string& filename ) const ///< STL std::string version. { -// StringToBuffer f( filename ); -// return ( f.buffer && SaveFile( f.buffer )); return SaveFile( filename.c_str() ); } #endif @@ -1638,7 +1642,7 @@ class TiXmlHandle TiXmlHandle( TiXmlNode* _node ) { this->node = _node; } /// Copy constructor TiXmlHandle( const TiXmlHandle& ref ) { this->node = ref.node; } - TiXmlHandle operator=( const TiXmlHandle& ref ) { this->node = ref.node; return *this; } + TiXmlHandle operator=( const TiXmlHandle& ref ) { if ( &ref != this ) this->node = ref.node; return *this; } /// Return a handle to the first child node. TiXmlHandle FirstChild() const; @@ -1799,4 +1803,3 @@ class TiXmlPrinter : public TiXmlVisitor #endif #endif - diff --git a/library/depends/tinyxml/tinyxmlerror.cpp b/depends/tinyxml/tinyxmlerror.cpp similarity index 94% rename from library/depends/tinyxml/tinyxmlerror.cpp rename to depends/tinyxml/tinyxmlerror.cpp index d24f63b2e5..538c21d0bd 100644 --- a/library/depends/tinyxml/tinyxmlerror.cpp +++ b/depends/tinyxml/tinyxmlerror.cpp @@ -31,12 +31,11 @@ distribution. // It also cleans up the code a bit. // -const char* TiXmlBase::errorString[ TIXML_ERROR_STRING_COUNT ] = +const char* TiXmlBase::errorString[ TiXmlBase::TIXML_ERROR_STRING_COUNT ] = { "No error", "Error", "Failed to open file", - "Memory allocation failed.", "Error parsing Element.", "Failed to read Element name", "Error reading Element value.", diff --git a/library/depends/tinyxml/tinyxmlparser.cpp b/depends/tinyxml/tinyxmlparser.cpp similarity index 96% rename from library/depends/tinyxml/tinyxmlparser.cpp rename to depends/tinyxml/tinyxmlparser.cpp index 5793f05286..81b7eae96b 100644 --- a/library/depends/tinyxml/tinyxmlparser.cpp +++ b/depends/tinyxml/tinyxmlparser.cpp @@ -1,6 +1,6 @@ /* www.sourceforge.net/projects/tinyxml -Original code (2.0 and earlier )copyright (c) 2000-2002 Lee Thomason (www.grinninglizard.com) +Original code by Lee Thomason (www.grinninglizard.com) This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -40,7 +40,7 @@ distribution. // Note tha "PutString" hardcodes the same list. This // is less flexible than it appears. Changing the entries // or order will break putstring. -TiXmlBase::Entity TiXmlBase::entity[ NUM_ENTITY ] = +TiXmlBase::Entity TiXmlBase::entity[ TiXmlBase::NUM_ENTITY ] = { { "&", 5, '&' }, { "<", 4, '<' }, @@ -174,7 +174,7 @@ class TiXmlParsingData public: void Stamp( const char* now, TiXmlEncoding encoding ); - const TiXmlCursor& Cursor() { return cursor; } + const TiXmlCursor& Cursor() const { return cursor; } private: // Only used by the document! @@ -346,7 +346,7 @@ const char* TiXmlBase::SkipWhiteSpace( const char* p, TiXmlEncoding encoding ) continue; } - if ( IsWhiteSpace( *p ) || *p == '\n' || *p =='\r' ) // Still using old rules for white space. + if ( IsWhiteSpace( *p ) ) // Still using old rules for white space. ++p; else break; @@ -354,7 +354,7 @@ const char* TiXmlBase::SkipWhiteSpace( const char* p, TiXmlEncoding encoding ) } else { - while ( (*p && IsWhiteSpace( *p )) || *p == '\n' || *p =='\r' ) + while ( *p && IsWhiteSpace( *p ) ) ++p; } @@ -631,9 +631,9 @@ const char* TiXmlBase::ReadText( const char* p, } } } - if ( p ) + if ( p && *p ) p += strlen( endTag ); - return p; + return ( p && *p ) ? p : 0; } #ifdef TIXML_USE_STL @@ -825,7 +825,6 @@ TiXmlNode* TiXmlNode::Identify( const char* p, TiXmlEncoding encoding ) return 0; } - TiXmlDocument* doc = GetDocument(); p = SkipWhiteSpace( p, encoding ); if ( !p || !*p ) @@ -896,11 +895,6 @@ TiXmlNode* TiXmlNode::Identify( const char* p, TiXmlEncoding encoding ) // Set the parent, so it can report errors returnNode->parent = this; } - else - { - if ( doc ) - doc->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN ); - } return returnNode; } @@ -1083,7 +1077,6 @@ const char* TiXmlElement::Parse( const char* p, TiXmlParsingData* data, TiXmlEnc TIXML_STRING endTag (""; // Check for and read attributes. Also look for an empty // tag or an end tag. @@ -1122,10 +1115,20 @@ const char* TiXmlElement::Parse( const char* p, TiXmlParsingData* data, TiXmlEnc } // We should find the end tag now + // note that: + // and + // + // are both valid end tags. if ( StringEqual( p, endTag.c_str(), false, encoding ) ) { p += endTag.length(); - return p; + p = SkipWhiteSpace( p, encoding ); + if ( p && *p && *p == '>' ) { + ++p; + return p; + } + if ( document ) document->SetError( TIXML_ERROR_READING_END_TAG, p, data, encoding ); + return 0; } else { @@ -1139,7 +1142,6 @@ const char* TiXmlElement::Parse( const char* p, TiXmlParsingData* data, TiXmlEnc TiXmlAttribute* attrib = new TiXmlAttribute(); if ( !attrib ) { - if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, pErr, data, encoding ); return 0; } @@ -1162,7 +1164,7 @@ const char* TiXmlElement::Parse( const char* p, TiXmlParsingData* data, TiXmlEnc #endif if ( node ) { - node->SetValue( attrib->Value() ); + if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, pErr, data, encoding ); delete attrib; return 0; } @@ -1191,8 +1193,7 @@ const char* TiXmlElement::ReadValue( const char* p, TiXmlParsingData* data, TiXm if ( !textNode ) { - if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, encoding ); - return 0; + return 0; } if ( TiXmlBase::IsWhiteSpaceCondensed() ) @@ -1297,9 +1298,10 @@ const char* TiXmlUnknown::Parse( const char* p, TiXmlParsingData* data, TiXmlEnc if ( !p ) { - if ( document ) document->SetError( TIXML_ERROR_PARSING_UNKNOWN, 0, 0, encoding ); + if ( document ) + document->SetError( TIXML_ERROR_PARSING_UNKNOWN, 0, 0, encoding ); } - if ( *p == '>' ) + if ( p && *p == '>' ) return p+1; return p; } @@ -1349,7 +1351,8 @@ const char* TiXmlComment::Parse( const char* p, TiXmlParsingData* data, TiXmlEnc if ( !StringEqual( p, startTag, false, encoding ) ) { - document->SetError( TIXML_ERROR_PARSING_COMMENT, p, data, encoding ); + if ( document ) + document->SetError( TIXML_ERROR_PARSING_COMMENT, p, data, encoding ); return 0; } p += strlen( startTag ); @@ -1379,7 +1382,7 @@ const char* TiXmlComment::Parse( const char* p, TiXmlParsingData* data, TiXmlEnc value.append( p, 1 ); ++p; } - if ( p ) + if ( p && *p ) p += strlen( endTag ); return p; @@ -1391,10 +1394,6 @@ const char* TiXmlAttribute::Parse( const char* p, TiXmlParsingData* data, TiXmlE p = SkipWhiteSpace( p, encoding ); if ( !p || !*p ) return 0; -// int tabsize = 4; -// if ( document ) -// tabsize = document->TabSize(); - if ( data ) { data->Stamp( p, encoding ); @@ -1446,7 +1445,7 @@ const char* TiXmlAttribute::Parse( const char* p, TiXmlParsingData* data, TiXmlE // its best, even without them. value = ""; while ( p && *p // existence - && !IsWhiteSpace( *p ) && *p != '\n' && *p != '\r' // whitespace + && !IsWhiteSpace( *p ) // whitespace && *p != '/' && *p != '>' ) // tag end { if ( *p == SINGLE_QUOTE || *p == DOUBLE_QUOTE ) { @@ -1515,7 +1514,8 @@ const char* TiXmlText::Parse( const char* p, TiXmlParsingData* data, TiXmlEncodi if ( !StringEqual( p, startTag, false, encoding ) ) { - document->SetError( TIXML_ERROR_PARSING_CDATA, p, data, encoding ); + if ( document ) + document->SetError( TIXML_ERROR_PARSING_CDATA, p, data, encoding ); return 0; } p += strlen( startTag ); @@ -1539,7 +1539,7 @@ const char* TiXmlText::Parse( const char* p, TiXmlParsingData* data, TiXmlEncodi const char* end = "<"; p = ReadText( p, &value, ignoreWhite, end, false, encoding ); - if ( p ) + if ( p && *p ) return p-1; // don't truncate the '<' return 0; } diff --git a/depends/xlsxio b/depends/xlsxio new file mode 160000 index 0000000000..e3ed11f6b4 --- /dev/null +++ b/depends/xlsxio @@ -0,0 +1 @@ +Subproject commit e3ed11f6b40bf68b48afc8fc3131ea2b4a22d5b1 diff --git a/depends/zlib/include/zconf.h b/depends/zlib/include/zconf.h new file mode 100644 index 0000000000..57465e07ff --- /dev/null +++ b/depends/zlib/include/zconf.h @@ -0,0 +1,430 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2010 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#ifndef ZCONF_H +#define ZCONF_H +/* #undef Z_PREFIX */ +/* #undef Z_HAVE_UNISTD_H */ + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + * Even better than compiling with -DZ_PREFIX would be to use configure to set + * this permanently in zconf.h using "./configure --zprefix". + */ +#ifdef Z_PREFIX /* may be set to #if 1 by ./configure */ + +/* all linked symbols */ +# define _dist_code z__dist_code +# define _length_code z__length_code +# define _tr_align z__tr_align +# define _tr_flush_block z__tr_flush_block +# define _tr_init z__tr_init +# define _tr_stored_block z__tr_stored_block +# define _tr_tally z__tr_tally +# define adler32 z_adler32 +# define adler32_combine z_adler32_combine +# define adler32_combine64 z_adler32_combine64 +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# define crc32 z_crc32 +# define crc32_combine z_crc32_combine +# define crc32_combine64 z_crc32_combine64 +# define deflate z_deflate +# define deflateBound z_deflateBound +# define deflateCopy z_deflateCopy +# define deflateEnd z_deflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateInit_ z_deflateInit_ +# define deflateParams z_deflateParams +# define deflatePrime z_deflatePrime +# define deflateReset z_deflateReset +# define deflateSetDictionary z_deflateSetDictionary +# define deflateSetHeader z_deflateSetHeader +# define deflateTune z_deflateTune +# define deflate_copyright z_deflate_copyright +# define get_crc_table z_get_crc_table +# define gz_error z_gz_error +# define gz_intmax z_gz_intmax +# define gz_strwinerror z_gz_strwinerror +# define gzbuffer z_gzbuffer +# define gzclearerr z_gzclearerr +# define gzclose z_gzclose +# define gzclose_r z_gzclose_r +# define gzclose_w z_gzclose_w +# define gzdirect z_gzdirect +# define gzdopen z_gzdopen +# define gzeof z_gzeof +# define gzerror z_gzerror +# define gzflush z_gzflush +# define gzgetc z_gzgetc +# define gzgets z_gzgets +# define gzoffset z_gzoffset +# define gzoffset64 z_gzoffset64 +# define gzopen z_gzopen +# define gzopen64 z_gzopen64 +# define gzprintf z_gzprintf +# define gzputc z_gzputc +# define gzputs z_gzputs +# define gzread z_gzread +# define gzrewind z_gzrewind +# define gzseek z_gzseek +# define gzseek64 z_gzseek64 +# define gzsetparams z_gzsetparams +# define gztell z_gztell +# define gztell64 z_gztell64 +# define gzungetc z_gzungetc +# define gzwrite z_gzwrite +# define inflate z_inflate +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define inflateBackInit_ z_inflateBackInit_ +# define inflateCopy z_inflateCopy +# define inflateEnd z_inflateEnd +# define inflateGetHeader z_inflateGetHeader +# define inflateInit2_ z_inflateInit2_ +# define inflateInit_ z_inflateInit_ +# define inflateMark z_inflateMark +# define inflatePrime z_inflatePrime +# define inflateReset z_inflateReset +# define inflateReset2 z_inflateReset2 +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateUndermine z_inflateUndermine +# define inflate_copyright z_inflate_copyright +# define inflate_fast z_inflate_fast +# define inflate_table z_inflate_table +# define uncompress z_uncompress +# define zError z_zError +# define zcalloc z_zcalloc +# define zcfree z_zcfree +# define zlibCompileFlags z_zlibCompileFlags +# define zlibVersion z_zlibVersion + +/* all zlib typedefs in zlib.h and zconf.h */ +# define Byte z_Byte +# define Bytef z_Bytef +# define alloc_func z_alloc_func +# define charf z_charf +# define free_func z_free_func +# define gzFile z_gzFile +# define gz_header z_gz_header +# define gz_headerp z_gz_headerp +# define in_func z_in_func +# define intf z_intf +# define out_func z_out_func +# define uInt z_uInt +# define uIntf z_uIntf +# define uLong z_uLong +# define uLongf z_uLongf +# define voidp z_voidp +# define voidpc z_voidpc +# define voidpf z_voidpf + +/* all zlib structs in zlib.h and zconf.h */ +# define gz_header_s z_gz_header_s +# define internal_state z_internal_state + +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_UNISTD_H +#endif + +#ifdef STDC +# include /* for off_t */ +#endif + +/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and + * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even + * though the former does not conform to the LFS document), but considering + * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as + * equivalently requesting no 64-bit operations + */ +#if -_LARGEFILE64_SOURCE - -1 == 1 +# undef _LARGEFILE64_SOURCE +#endif + +#if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) +# include /* for SEEK_* and off_t */ +# ifdef VMS +# include /* for off_t */ +# endif +# ifndef z_off_t +# define z_off_t off_t +# endif +#endif + +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif + +#ifndef z_off_t +# define z_off_t long +#endif + +#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 +# define z_off64_t off64_t +#else +# define z_off64_t z_off_t +#endif + +#if defined(__OS400__) +# define NO_vsnprintf +#endif + +#if defined(__MVS__) +# define NO_vsnprintf +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) + #pragma map(deflateInit_,"DEIN") + #pragma map(deflateInit2_,"DEIN2") + #pragma map(deflateEnd,"DEEND") + #pragma map(deflateBound,"DEBND") + #pragma map(inflateInit_,"ININ") + #pragma map(inflateInit2_,"ININ2") + #pragma map(inflateEnd,"INEND") + #pragma map(inflateSync,"INSY") + #pragma map(inflateSetDictionary,"INSEDI") + #pragma map(compressBound,"CMBND") + #pragma map(inflate_table,"INTABL") + #pragma map(inflate_fast,"INFA") + #pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/depends/zlib/include/zlib.h b/depends/zlib/include/zlib.h new file mode 100644 index 0000000000..bfbba83e8e --- /dev/null +++ b/depends/zlib/include/zlib.h @@ -0,0 +1,1613 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.5, April 19th, 2010 + + Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler + + 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 acknowledgment 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. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.2.5" +#define ZLIB_VERNUM 0x1250 +#define ZLIB_VER_MAJOR 1 +#define ZLIB_VER_MINOR 2 +#define ZLIB_VER_REVISION 5 +#define ZLIB_VER_SUBREVISION 0 + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed data. + This version of the library supports only one compression method (deflation) + but other algorithms will be added later and will have the same stream + interface. + + Compression can be done in a single step if the buffers are large enough, + or can be done by repeated calls of the compression function. In the latter + case, the application must provide more input and/or consume the output + (providing more output space) before each call. + + The compressed data format used by default by the in-memory functions is + the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped + around a deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + This library can optionally read and write gzip streams in memory as well. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never crash + even in case of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total nb of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total nb of bytes output so far */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: binary or text */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + gzip header information passed to and from zlib routines. See RFC 1952 + for more details on the meanings of these fields. +*/ +typedef struct gz_header_s { + int text; /* true if compressed data believed to be text */ + uLong time; /* modification time */ + int xflags; /* extra flags (not used when writing a gzip file) */ + int os; /* operating system */ + Bytef *extra; /* pointer to extra field or Z_NULL if none */ + uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ + uInt extra_max; /* space at extra (only when reading header) */ + Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ + uInt name_max; /* space at name (only when reading header) */ + Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ + uInt comm_max; /* space at comment (only when reading header) */ + int hcrc; /* true if there was or will be a header crc */ + int done; /* true when done reading gzip header (not used + when writing a gzip file) */ +} gz_header; + +typedef gz_header FAR *gz_headerp; + +/* + The application must update next_in and avail_in when avail_in has dropped + to zero. It must update next_out and avail_out when avail_out has dropped + to zero. The application must initialize zalloc, zfree and opaque before + calling the init function. All other fields are set by the compression + library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this if + the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, pointers + returned by zalloc for objects of exactly 65536 bytes *must* have their + offset normalized to zero. The default allocation function provided by this + library ensures this (see zutil.c). To reduce memory requirements and avoid + any allocation of 64K objects, at the expense of compression ratio, compile + the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or progress + reports. After compression, total_in holds the total size of the + uncompressed data and may be saved for use in the decompressor (particularly + if the decompressor wants to decompress everything in a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +#define Z_TREES 6 +/* Allowed flush values; see deflate() and inflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative values + * are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_FIXED 4 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_TEXT 1 +#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ +#define Z_UNKNOWN 2 +/* Possible values of the data_type field (though see inflate()) */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is not + compatible with the zlib.h header file used by the application. This check + is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. If + zalloc and zfree are set to Z_NULL, deflateInit updates them to use default + allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at all + (the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION + requests a default compromise between speed and compression (currently + equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if level is not a valid compression level, or + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). msg is set to null + if there is no error message. deflateInit does not perform any compression: + this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). Some + output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming more + output, and updating avail_in or avail_out accordingly; avail_out should + never be zero before the call. The application can consume the compressed + output when it wants, for example when the output buffer is full (avail_out + == 0), or after each call of deflate(). If deflate returns Z_OK and with + zero avail_out, it must be called again after making room in the output + buffer because there might be more output pending. + + Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to + decide how much data to accumulate before producing output, in order to + maximize compression. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In + particular avail_in is zero after the call if enough output space has been + provided before the call.) Flushing may degrade compression for some + compression algorithms and so it should be used only when necessary. This + completes the current deflate block and follows it with an empty stored block + that is three bits plus filler bits to the next byte, followed by four bytes + (00 00 ff ff). + + If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the + output buffer, but the output is not aligned to a byte boundary. All of the + input data so far will be available to the decompressor, as for Z_SYNC_FLUSH. + This completes the current deflate block and follows it with an empty fixed + codes block that is 10 bits long. This assures that enough bytes are output + in order for the decompressor to finish the block before the empty fixed code + block. + + If flush is set to Z_BLOCK, a deflate block is completed and emitted, as + for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to + seven bits of the current block are held to be written as the next byte after + the next deflate block is completed. In this case, the decompressor may not + be provided enough bits at this point in order to complete decompression of + the data provided so far to the compressor. It may need to wait for the next + block to be emitted. This is for advanced applications that need to control + the emission of deflate blocks. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six to avoid repeated flush markers due to + avail_out == 0 on return. + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there was + enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the stream + are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least the + value returned by deflateBound (see below). If deflate does not return + Z_STREAM_END, then it must be called again as described above. + + deflate() sets strm->adler to the adler32 checksum of all input read + so far (that is, total_in bytes). + + deflate() may update strm->data_type if it can make a good guess about + the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered + binary. This field is only for information purposes and does not affect the + compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was Z_NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not + fatal, and deflate() can be called again with more input and more output + space to continue compressing. +*/ + + +ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any pending + output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, msg + may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the + exact value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller, or Z_STREAM_ERROR if the parameters are + invalid, such as a null pointer to the structure. msg is set to null if + there is no error message. inflateInit does not perform any decompression + apart from possibly reading the zlib header if present: actual decompression + will be done by inflate(). (So next_in and avail_in may be modified, but + next_out and avail_out are unused and unchanged.) The current implementation + of inflateInit() does not process any header information -- that is deferred + until inflate() is called. +*/ + + +ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing will + resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there is + no more input data or no more space in the output buffer (see below about + the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming more + output, and updating the next_* and avail_* values accordingly. The + application can consume the uncompressed output when it wants, for example + when the output buffer is full (avail_out == 0), or after each call of + inflate(). If inflate returns Z_OK and with zero avail_out, it must be + called again after making room in the output buffer because there might be + more output pending. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH, + Z_BLOCK, or Z_TREES. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() + stop if and when it gets to the next deflate block boundary. When decoding + the zlib or gzip format, this will cause inflate() to return immediately + after the header and before the first block. When doing a raw inflate, + inflate() will go ahead and process the first block, and will return when it + gets to the end of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + Also to assist in this, on return inflate() will set strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 if + inflate() is currently decoding the last block in the deflate stream, plus + 128 if inflate() returned immediately after decoding an end-of-block code or + decoding the complete header up to just before the first byte of the deflate + stream. The end-of-block will not be indicated until all of the uncompressed + data from that block has been written to strm->next_out. The number of + unused bits may in general be greater than seven, except when bit 7 of + data_type is set, in which case the number of unused bits will be less than + eight. data_type is set as noted here every time inflate() returns for all + flush options, and so can be used to determine the amount of currently + consumed input in bits. + + The Z_TREES option behaves as Z_BLOCK does, but it also returns when the + end of each deflate block header is reached, before any actual data in that + block is decoded. This allows the caller to determine the length of the + deflate block header for later use in random access within a deflate block. + 256 is added to the value of strm->data_type when inflate() returns + immediately after reaching the end of the deflate block header. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step (a + single call of inflate), the parameter flush should be set to Z_FINISH. In + this case all pending input is processed and all pending output is flushed; + avail_out must be large enough to hold all the uncompressed data. (The size + of the uncompressed data may have been saved by the compressor for this + purpose.) The next operation on this stream must be inflateEnd to deallocate + the decompression state. The use of Z_FINISH is never required, but can be + used to inform inflate that a faster approach may be used for the single + inflate() call. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the only effect of the flush parameter in this implementation + is on the return value of inflate(), as noted below, or when it returns early + because Z_BLOCK or Z_TREES is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm->adler to the adler32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the adler32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed adler32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() can decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically, if requested when + initializing with inflateInit2(). Any information contained in the gzip + header is not retained, so applications that need that information should + instead use raw inflate, see inflateInit2() below, or inflateBack() and + perform their own processing of the gzip header and trailer. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect check + value), Z_STREAM_ERROR if the stream structure was inconsistent (for example + next_in or next_out was Z_NULL), Z_MEM_ERROR if there was not enough memory, + Z_BUF_ERROR if no progress is possible or if there was not enough room in the + output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may + then call inflateSync() to look for a good compression block if a partial + recovery of the data is desired. +*/ + + +ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any pending + output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by the + caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute an adler32 check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), no + header crc, and the operating system will be set to 255 (unknown). If a + gzip stream is being written, strm->adler is a crc32 instead of an adler32. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but is + slow and reduces compression ratio; memLevel=9 uses maximum memory for + optimal speed. The default value is 8. See zconf.h for total memory usage + as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). Filtered data consists mostly of small values with a somewhat + random distribution. In this case, the compression algorithm is tuned to + compress them better. The effect of Z_FILTERED is to force more Huffman + coding and less string matching; it is somewhat intermediate between + Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as + fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data. The + strategy parameter only affects the compression ratio but not the + correctness of the compressed output even if it is not set appropriately. + Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler + decoder for special applications. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid + method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is + incompatible with the version assumed by the caller (ZLIB_VERSION). msg is + set to null if there is no error message. deflateInit2 does not perform any + compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. This function must be called + immediately after deflateInit, deflateInit2 or deflateReset, before any call + of deflate. The compressor and decompressor must use exactly the same + dictionary (see inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size + provided in deflateInit or deflateInit2. Thus the strings most likely to be + useful should be put at the end of the dictionary, not at the front. In + addition, the current implementation of deflate will use at most the window + size minus 262 bytes of the provided dictionary. + + Upon return of this function, strm->adler is set to the adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) If a raw deflate was requested, then the + adler32 value is not computed and strm->adler is not set. + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if the compression method is bsort). deflateSetDictionary does not + perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and can + consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being Z_NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. The + stream will keep the same compression level and any other attributes that + may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different strategy. + If the compression level is changed, the input available so far is + compressed with the old level (and may be flushed); the new level will take + effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to be + compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR if + strm->avail_out was zero. +*/ + +ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, + int good_length, + int max_lazy, + int nice_length, + int max_chain)); +/* + Fine tune deflate's internal compression parameters. This should only be + used by someone who understands the algorithm used by zlib's deflate for + searching for the best matching string, and even then only by the most + fanatic optimizer trying to squeeze out the last compressed bit for their + specific input data. Read the deflate.c source code for the meaning of the + max_lazy, good_length, nice_length, and max_chain parameters. + + deflateTune() can be called after deflateInit() or deflateInit2(), and + returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. + */ + +ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, + uLong sourceLen)); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() or + deflateInit2(), and after deflateSetHeader(), if used. This would be used + to allocate an output buffer for deflation in a single pass, and so would be + called before deflate(). +*/ + +ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the bits + leftover from a previous deflate stream when appending to it. As such, this + function can only be used for raw deflate, and must be used before the first + deflate() call after a deflateInit2() or deflateReset(). bits must be less + than or equal to 16, and that many of the least significant bits of value + will be inserted in the output. + + deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, + gz_headerp head)); +/* + deflateSetHeader() provides gzip header information for when a gzip + stream is requested by deflateInit2(). deflateSetHeader() may be called + after deflateInit2() or deflateReset() and before the first call of + deflate(). The text, time, os, extra field, name, and comment information + in the provided gz_header structure are written to the gzip header (xflag is + ignored -- the extra flags are set according to the compression level). The + caller must assure that, if not Z_NULL, name and comment are terminated with + a zero byte, and that if extra is not Z_NULL, that extra_len bytes are + available there. If hcrc is true, a gzip header crc is included. Note that + the current versions of the command-line version of gzip (up through version + 1.3.x) do not support header crc's, and will report that it is a "multi-part + gzip file" and give up. + + If deflateSetHeader is not used, the default gzip header has text false, + the time set to zero, and os set to 255, with no extra, name, or comment + fields. The gzip header is returned to the default state by deflateReset(). + + deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. + + windowBits can also be zero to request that inflate use the window size in + the zlib header of the compressed stream. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an adler32 or a crc32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a + crc32 instead of an adler32. + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller, or Z_STREAM_ERROR if the parameters are + invalid, such as a null pointer to the structure. msg is set to null if + there is no error message. inflateInit2 does not perform any decompression + apart from possibly reading the zlib header if present: actual decompression + will be done by inflate(). (So next_in and avail_in may be modified, but + next_out and avail_out are unused and unchanged.) The current implementation + of inflateInit2() does not process any header information -- that is + deferred until inflate() is called. +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate, + if that call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the adler32 value returned by that call of inflate. + The compressor and decompressor must use exactly the same dictionary (see + deflateSetDictionary). For raw inflate, this function can be called + immediately after inflateInit2() or inflateReset() and before any call of + inflate() to set the dictionary. The application must insure that the + dictionary that was used for compression is provided. + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a full flush point (see above the + description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR + if no more input was provided, Z_DATA_ERROR if no flush point has been + found, or Z_STREAM_ERROR if the stream structure was inconsistent. In the + success case, the application may save the current current value of total_in + which indicates where valid compressed data was found. In the error case, + the application may repeatedly call inflateSync, providing more input each + time, until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being Z_NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. The + stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL). +*/ + +ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm, + int windowBits)); +/* + This function is the same as inflateReset, but it also permits changing + the wrap and window size requests. The windowBits parameter is interpreted + the same as it is for inflateInit2. + + inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL), or if + the windowBits parameter is invalid. +*/ + +ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + This function inserts bits in the inflate input stream. The intent is + that this function is used to start inflating at a bit position in the + middle of a byte. The provided bits will be used before any bytes are used + from next_in. This function should only be used with raw inflate, and + should be used before the first inflate() call after inflateInit2() or + inflateReset(). bits must be less than or equal to 16, and that many of the + least significant bits of value will be inserted in the input. + + If bits is negative, then the input stream bit buffer is emptied. Then + inflatePrime() can be called again to put bits in the buffer. This is used + to clear out bits leftover after feeding inflate a block description prior + to feeding inflate codes. + + inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm)); +/* + This function returns two values, one in the lower 16 bits of the return + value, and the other in the remaining upper bits, obtained by shifting the + return value down 16 bits. If the upper value is -1 and the lower value is + zero, then inflate() is currently decoding information outside of a block. + If the upper value is -1 and the lower value is non-zero, then inflate is in + the middle of a stored block, with the lower value equaling the number of + bytes from the input remaining to copy. If the upper value is not -1, then + it is the number of bits back from the current bit position in the input of + the code (literal or length/distance pair) currently being processed. In + that case the lower value is the number of bytes already emitted for that + code. + + A code is being processed if inflate is waiting for more input to complete + decoding of the code, or if it has completed decoding but is waiting for + more output space to write the literal or match data. + + inflateMark() is used to mark locations in the input data for random + access, which may be at bit positions, and to note those cases where the + output of a code may span boundaries of random access blocks. The current + location in the input stream can be determined from avail_in and data_type + as noted in the description for the Z_BLOCK flush parameter for inflate. + + inflateMark returns the value noted above or -1 << 16 if the provided + source stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, + gz_headerp head)); +/* + inflateGetHeader() requests that gzip header information be stored in the + provided gz_header structure. inflateGetHeader() may be called after + inflateInit2() or inflateReset(), and before the first call of inflate(). + As inflate() processes the gzip stream, head->done is zero until the header + is completed, at which time head->done is set to one. If a zlib stream is + being decoded, then head->done is set to -1 to indicate that there will be + no gzip header information forthcoming. Note that Z_BLOCK or Z_TREES can be + used to force inflate() to return immediately after header processing is + complete and before any actual data is decompressed. + + The text, time, xflags, and os fields are filled in with the gzip header + contents. hcrc is set to true if there is a header CRC. (The header CRC + was valid if done is set to one.) If extra is not Z_NULL, then extra_max + contains the maximum number of bytes to write to extra. Once done is true, + extra_len contains the actual extra field length, and extra contains the + extra field, or that field truncated if extra_max is less than extra_len. + If name is not Z_NULL, then up to name_max characters are written there, + terminated with a zero unless the length is greater than name_max. If + comment is not Z_NULL, then up to comm_max characters are written there, + terminated with a zero unless the length is greater than comm_max. When any + of extra, name, or comment are not Z_NULL and the respective field is not + present in the header, then that field is set to Z_NULL to signal its + absence. This allows the use of deflateSetHeader() with the returned + structure to duplicate the header. However if those fields are set to + allocated memory, then the application will need to save those pointers + elsewhere so that they can be eventually freed. + + If inflateGetHeader is not used, then the header information is simply + discarded. The header is always checked for validity, including the header + CRC if present. inflateReset() will reset the process to discard the header + information. The application would need to call inflateGetHeader() again to + retrieve the header from the next gzip stream. + + inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, + unsigned char FAR *window)); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the paramaters are invalid, Z_MEM_ERROR if the internal state could not be + allocated, or Z_VERSION_ERROR if the version of the library does not match + the version of the header file. +*/ + +typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); +typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); + +ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is more efficient than inflate() for + file i/o applications in that it avoids copying between the output and the + sliding window by simply making the window itself the output buffer. This + function trusts the application to not change the output buffer passed by + the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free the + allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects only + the raw deflate stream to decompress. This is different from the normal + behavior of inflate(), which expects either a zlib or gzip header and + trailer around the deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero--buf is ignored in that + case--and inflateBack() will return a buffer error. inflateBack() will call + out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() + should return zero on success, or non-zero on failure. If out() returns + non-zero, inflateBack() will return with an error. Neither in() nor out() + are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format error + in the deflate stream (in which case strm->msg is set to indicate the nature + of the error), or Z_STREAM_ERROR if the stream was not properly initialized. + In the case of Z_BUF_ERROR, an input or output error can be distinguished + using strm->next_in which will be Z_NULL only if in() returned an error. If + strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning + non-zero. (in() will always be called before out(), so strm->next_in is + assured to be defined if out() returns non-zero.) Note that inflateBack() + cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + + + /* utility functions */ + +/* + The following utility functions are implemented on top of the basic + stream-oriented functions. To simplify the interface, some default options + are assumed (compression level and memory usage, standard memory allocation + functions). The source code of these utility functions can be modified if + you need special options. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total size + of the destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before a + compress() or compress2() call to allocate the destination buffer. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total size + of the destination buffer, which must be large enough to hold the entire + uncompressed data. (The size of the uncompressed data must have been saved + previously by the compressor and transmitted to the decompressor by some + mechanism outside the scope of this compression library.) Upon exit, destLen + is the actual size of the uncompressed buffer. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. +*/ + + + /* gzip file access functions */ + +/* + This library supports reading and writing files in gzip (.gz) format with + an interface similar to that of stdio, using the functions that start with + "gz". The gzip format is different from the zlib format. gzip is a gzip + wrapper, documented in RFC 1952, wrapped around a deflate stream. +*/ + +typedef voidp gzFile; /* opaque gzip file descriptor */ + +/* +ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); + + Opens a gzip (.gz) file for reading or writing. The mode parameter is as + in fopen ("rb" or "wb") but can also include a compression level ("wb9") or + a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only + compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F' + for fixed code compression as in "wb9F". (See the description of + deflateInit2 for more information about the strategy parameter.) Also "a" + can be used instead of "w" to request that the gzip stream that will be + written be appended to the file. "+" will result in an error, since reading + and writing to the same gzip file is not supported. + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. + + gzopen returns NULL if the file could not be opened, if there was + insufficient memory to allocate the gzFile state, or if an invalid mode was + specified (an 'r', 'w', or 'a' was not provided, or '+' was provided). + errno can be checked to determine if the reason gzopen failed was that the + file could not be opened. +*/ + +ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +/* + gzdopen associates a gzFile with the file descriptor fd. File descriptors + are obtained from calls like open, dup, creat, pipe or fileno (if the file + has been previously opened with fopen). The mode parameter is as in gzopen. + + The next call of gzclose on the returned gzFile will also close the file + descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor + fd. If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd, + mode);. The duplicated descriptor should be saved to avoid a leak, since + gzdopen does not close fd if it fails. + + gzdopen returns NULL if there was insufficient memory to allocate the + gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not + provided, or '+' was provided), or if fd is -1. The file descriptor is not + used until the next gz* read, write, seek, or close operation, so gzdopen + will not detect if fd is invalid (unless fd is -1). +*/ + +ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size)); +/* + Set the internal buffer size used by this library's functions. The + default buffer size is 8192 bytes. This function must be called after + gzopen() or gzdopen(), and before any other calls that read or write the + file. The buffer memory allocation is always deferred to the first read or + write. Two buffers are allocated, either both of the specified size when + writing, or one of the specified size and the other twice that size when + reading. A larger buffer size of, for example, 64K or 128K bytes will + noticeably increase the speed of decompression (reading). + + The new buffer size also affects the maximum length for gzprintf(). + + gzbuffer() returns 0 on success, or -1 on failure, such as being called + too late. +*/ + +ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. If + the input file was not in gzip format, gzread copies the given number of + bytes into the buffer. + + After reaching the end of a gzip stream in the input, gzread will continue + to read, looking for another gzip stream, or failing that, reading the rest + of the input file directly without decompression. The entire input file + will be read if gzread is called until it returns less than the requested + len. + + gzread returns the number of uncompressed bytes actually read, less than + len for end of file, or -1 for error. +*/ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + voidpc buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes written or 0 in case of + error. +*/ + +ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the arguments to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written, or 0 in case of error. The number of + uncompressed bytes written is limited to 8191, or one less than the buffer + size given to gzbuffer(). The caller should assure that this limit is not + exceeded. If it is exceeded, then gzprintf() will return an error (0) with + nothing written. In this case, there may also be a buffer overflow with + unpredictable consequences, which is possible only if zlib was compiled with + the insecure functions sprintf() or vsprintf() because the secure snprintf() + or vsnprintf() functions were not available. This can be determined using + zlibCompileFlags(). +*/ + +ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or a + newline character is read and transferred to buf, or an end-of-file + condition is encountered. If any characters are read or if len == 1, the + string is terminated with a null character. If no characters are read due + to an end-of-file or len < 1, then the buffer is left untouched. + + gzgets returns buf which is a null-terminated string, or it returns NULL + for end-of-file or in case of error. If there was an error, the contents at + buf are indeterminate. +*/ + +ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. gzputc + returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte or -1 + in case of end of file or error. +*/ + +ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +/* + Push one character back onto the stream to be read as the first character + on the next read. At least one character of push-back is allowed. + gzungetc() returns the character pushed, or -1 on failure. gzungetc() will + fail if c is -1, and may fail if a character has been pushed but not read + yet. If gzungetc is used immediately after gzopen or gzdopen, at least the + output buffer size of pushed characters is allowed. (See gzbuffer above.) + The pushed character will be discarded if the stream is repositioned with + gzseek() or gzrewind(). +*/ + +ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter flush + is as in the deflate() function. The return value is the zlib error number + (see function gzerror below). gzflush is only permitted when writing. + + If the flush parameter is Z_FINISH, the remaining data is written and the + gzip stream is completed in the output. If gzwrite() is called again, a new + gzip stream will be started in the output. gzread() is able to read such + concatented gzip streams. + + gzflush should be called only when strictly necessary because it will + degrade compression if called too often. +*/ + +/* +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t offset, int whence)); + + Sets the starting position for the next gzread or gzwrite on the given + compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +/* +ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); + + Returns the starting position for the next gzread or gzwrite on the given + compressed file. This position represents a number of bytes in the + uncompressed data stream, and is zero when starting, even if appending or + reading a gzip stream from the middle of a file using gzdopen(). + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +/* +ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file)); + + Returns the current offset in the file being read or written. This offset + includes the count of bytes that precede the gzip stream, for example when + appending or when using gzdopen() for reading. When reading, the offset + does not include as yet unused buffered input. This information can be used + for a progress indicator. On error, gzoffset() returns -1. +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns true (1) if the end-of-file indicator has been set while reading, + false (0) otherwise. Note that the end-of-file indicator is set only if the + read tried to go past the end of the input, but came up short. Therefore, + just like feof(), gzeof() may return false even if there is no more data to + read, in the event that the last read request was for the exact number of + bytes remaining in the input file. This will happen if the input file size + is an exact multiple of the buffer size. + + If gzeof() returns true, then the read functions will return no more data, + unless the end-of-file indicator is reset by gzclearerr() and the input file + has grown since the previous end of file was detected. +*/ + +ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); +/* + Returns true (1) if file is being copied directly while reading, or false + (0) if file is a gzip stream being decompressed. This state can change from + false to true while reading the input file if the end of a gzip stream is + reached, but is followed by data that is not another gzip stream. + + If the input file is empty, gzdirect() will return true, since the input + does not contain a gzip stream. + + If gzdirect() is used immediately after gzopen() or gzdopen() it will + cause buffers to be allocated to allow reading the file to determine if it + is a gzip file. Therefore if gzbuffer() is used, it should be called before + gzdirect(). +*/ + +ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file and + deallocates the (de)compression state. Note that once file is closed, you + cannot call gzerror with file, since its structures have been deallocated. + gzclose must not be called more than once on the same file, just as free + must not be called more than once on the same allocation. + + gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a + file operation error, or Z_OK on success. +*/ + +ZEXTERN int ZEXPORT gzclose_r OF((gzFile file)); +ZEXTERN int ZEXPORT gzclose_w OF((gzFile file)); +/* + Same as gzclose(), but gzclose_r() is only for use when reading, and + gzclose_w() is only for use when writing or appending. The advantage to + using these instead of gzclose() is that they avoid linking in zlib + compression or decompression code that is not used when only reading or only + writing respectively. If gzclose() is used, then both compression and + decompression code will be included the application when linking to a static + zlib library. +*/ + +ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the given + compressed file. errnum is set to zlib error number. If an error occurred + in the file system and not in the compression library, errnum is set to + Z_ERRNO and the application may consult errno to get the exact error code. + + The application must not modify the returned string. Future calls to + this function may invalidate the previously returned string. If file is + closed, then the string previously returned by gzerror will no longer be + available. + + gzerror() should be used to distinguish errors from end-of-file for those + functions above that do not distinguish those cases in their return values. +*/ + +ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); +/* + Clears the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the compression + library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is Z_NULL, this function returns the + required initial value for the checksum. + + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. + + Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +/* +ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, + z_off_t len2)); + + Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 + and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for + each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of + seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running CRC-32 with the bytes buf[0..len-1] and return the + updated CRC-32. If buf is Z_NULL, this function returns the required + initial value for the for the crc. Pre- and post-conditioning (one's + complement) is performed within this function so it shouldn't be done by the + application. + + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + +/* +ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); + + Combine two CRC-32 check values into one. For two sequences of bytes, + seq1 and seq2 with lengths len1 and len2, CRC-32 check values were + calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 + check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and + len2. +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size)); +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) +#define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, sizeof(z_stream)) + +/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or + * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if + * both are true, the application gets the *64 functions, and the regular + * functions are changed to 64 bits) -- in case these are set on systems + * without large file support, _LFS64_LARGEFILE must also be true + */ +#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 + ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); + ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); + ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); + ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t)); + ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t)); +#endif + +#if !defined(ZLIB_INTERNAL) && _FILE_OFFSET_BITS-0 == 64 && _LFS64_LARGEFILE-0 +# define gzopen gzopen64 +# define gzseek gzseek64 +# define gztell gztell64 +# define gzoffset gzoffset64 +# define adler32_combine adler32_combine64 +# define crc32_combine crc32_combine64 +# ifdef _LARGEFILE64_SOURCE + ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); + ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int)); + ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile)); + ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); +# endif +#else + ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *)); + ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int)); + ZEXTERN z_off_t ZEXPORT gztell OF((gzFile)); + ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); +#endif + +/* hack for buggy compilers */ +#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) + struct internal_state {int dummy;}; +#endif + +/* undocumented functions */ +ZEXTERN const char * ZEXPORT zError OF((int)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp)); +ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); +ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int)); + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/depends/zlib/lib/.gitignore b/depends/zlib/lib/.gitignore new file mode 100644 index 0000000000..683bf139fb --- /dev/null +++ b/depends/zlib/lib/.gitignore @@ -0,0 +1 @@ +*.lib diff --git a/dfhack-python/__init__.py b/dfhack-python/__init__.py deleted file mode 100644 index f6d2a2d31f..0000000000 --- a/dfhack-python/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -import context - -__all__ = [ "buildings", - "constructions", - "context", - "creatures", - "dftypes", - "flags", - "gui", - "items", - "maps", - "materials", - "vegetation" ] \ No newline at end of file diff --git a/dfhack-python/buildings.py b/dfhack-python/buildings.py deleted file mode 100644 index d58b928400..0000000000 --- a/dfhack-python/buildings.py +++ /dev/null @@ -1,34 +0,0 @@ -from ctypes import * -from dftypes import * -import util - -libdfhack.Buildings_GetCustomWorkshopType.argtypes = [ c_void_p, POINTER(CustomWorkshop) ] - -class Buildings(object): - def __init__(self, ptr): - self._b_ptr = ptr - - def start(self): - num = c_uint() - - if libdfhack.Buildings_Start(self._b_ptr, byref(num)) > 0: - return int(num.value) - else: - return -1 - - def finish(self): - return libdfhack.Buildings_Finish(self._b_ptr) > 0 - - def read(self, index): - b = Building() - - if libdfhack.Buildings_Read(self._b_ptr, c_uint(index), byref(b)) > 0: - return b - else: - return None - - def read_custom_workshop_types(self): - return libdfhack.Buildings_ReadCustomWorkshopTypes(self._b_ptr) - - def get_custom_workshop_type(self, custom_workshop): - return libdfhack.Buildings_GetCustomWorkshopType(self._b_ptr, byref(custom_workshop)) diff --git a/dfhack-python/constructions.py b/dfhack-python/constructions.py deleted file mode 100644 index f822a54fa5..0000000000 --- a/dfhack-python/constructions.py +++ /dev/null @@ -1,25 +0,0 @@ -from ctypes import c_uint, byref -from dftypes import libdfhack, Construction - -class Constructions(object): - def __init__(self, ptr): - self._c_ptr = ptr - - def start(self): - num = c_uint() - - if libdfhack.Constructions_Start(self._c_ptr, byref(num)) > 0: - return int(num.value) - else: - return -1 - - def finish(self): - return libdfhack.Constructions_Finish(self._c_ptr) > 0 - - def read(self, index): - c = Construction() - - if libdfhack.Constructions_Read(self._c_ptr, c_uint(index), byref(c)) > 0: - return c - else: - return None diff --git a/dfhack-python/context.py b/dfhack-python/context.py deleted file mode 100644 index b2459af464..0000000000 --- a/dfhack-python/context.py +++ /dev/null @@ -1,191 +0,0 @@ -from ctypes import * -from dftypes import * - -libdfhack.ContextManager_Alloc.restype = c_void_p -libdfhack.ContextManager_Free.argtypes = [ c_void_p ] - -libdfhack.ContextManager_getContext.restype = c_void_p -libdfhack.ContextManager_getSingleContext.restype = c_void_p - -libdfhack.Context_Free.argtypes = [ c_void_p ] - -libdfhack.Context_getMemoryInfo.restype = c_void_p -libdfhack.Context_getProcess.restype = c_void_p - -libdfhack.Context_getCreatures.restype = c_void_p -libdfhack.Context_getMaps.restype = c_void_p -libdfhack.Context_getGui.restype = c_void_p -libdfhack.Context_getMaterials.restype = c_void_p -libdfhack.Context_getTranslation.restype = c_void_p -libdfhack.Context_getVegetation.restype = c_void_p -libdfhack.Context_getBuildings.restype = c_void_p -libdfhack.Context_getConstructions.restype = c_void_p -libdfhack.Context_getItems.restype = c_void_p -libdfhack.Context_getWorld.restype = c_void_p -libdfhack.Context_getWindowIO.restype = c_void_p - -class ContextManager(object): - def __init__(self, memory_path): - self._cm_ptr = libdfhack.ContextManager_Alloc(create_string_buffer(memory_path)) - - def __del__(self): - libdfhack.ContextManager_Free(self._cm_ptr) - - def refresh(self): - return libdfhack.ContextManager_Refresh(self._cm_ptr) > 0 - - def purge(self): - libdfhack.ContextManager_purge(self._cm_ptr) - - def get_context(self, index): - p = libdfhack.ContextManager_getContext(self._cm_ptr, index) - - if p: - return Context(p) - else: - return None - - def get_single_context(self): - p = libdfhack.ContextManager_getSingleContext(self._cm_ptr) - - if p: - return Context(p) - else: - return None - -class Context(object): - def __init__(self, ptr): - self._c_ptr = ptr - - self._mat_obj = None - self._map_obj = None - self._veg_obj = None - self._build_obj = None - self._con_obj = None - self._gui_obj = None - self._tran_obj = None - self._item_obj = None - self._creature_obj = None - self._world_obj = None - self._window_io_obj = None - - def __del__(self): - libdfhack.Context_Free(self._c_ptr) - - def attach(self): - return libdfhack.Context_Attach(self._c_ptr) > 0 - - def detach(self): - self._mat_obj = None - self._map_obj = None - self._veg_obj = None - self._build_obj = None - self._con_obj = None - self._gui_obj = None - self._tran_obj = None - self._item_obj = None - self._creature_obj = None - self._world_obj = None - self._window_io_obj = None - - return libdfhack.Context_Detach(self._c_ptr) > 0 - - def suspend(self): - return libdfhack.Context_Suspend(self._c_ptr) > 0 - - def resume(self): - return libdfhack.Context_Resume(self._c_ptr) > 0 - - def force_resume(self): - return libdfhack.Context_ForceResume(self._c_ptr) > 0 - - def async_suspend(self): - return libdfhack.Context_AsyncSuspend(self._c_ptr) > 0 - - @property - def is_attached(self): - return libdfhack.Context_isAttached(self._c_ptr) > 0 - - @property - def is_suspended(self): - return libdfhack.Context_isSuspended(self._c_ptr) > 0 - - @property - def materials(self): - import materials - if self._mat_obj is None: - self._mat_obj = materials.Materials(libdfhack.Context_getMaterials(self._c_ptr)) - - return self._mat_obj - - @property - def maps(self): - import maps - if self._map_obj is None: - self._map_obj = maps.Maps(libdfhack.Context_getMaps(self._c_ptr)) - - return self._map_obj - - @property - def vegetation(self): - import vegetation - if self._veg_obj is None: - self._veg_obj = vegetation.Vegetation(libdfhack.Context_getVegetation(self._c_ptr)) - - return self._veg_obj - - @property - def buildings(self): - import buildings - if self._build_obj is None: - self._build_obj = buildings.Buildings(libdfhack.Context_getBuildings(self._c_ptr)) - - return self._build_obj - - @property - def creatures(self): - import creatures - if self._creature_obj is None: - self._creature_obj = creatures.Creatures(libdfhack.Context_getCreatures(self._c_ptr)) - - return self._creature_obj - - @property - def gui(self): - import gui - if self._gui_obj is None: - self._gui_obj = gui.Gui(libdfhack.Context_getGui(self._c_ptr)) - - return self._gui_obj - - @property - def items(self): - import items - if self._item_obj is None: - self._item_obj = items.Items(libdfhack.Context_getItems(self._c_ptr)) - - return self._item_obj - - @property - def translation(self): - import translation - if self._tran_obj is None: - self._tran_obj = translation.Translation(libdfhack.Context_getTranslation(self._c_ptr)) - - return self._tran_obj - - @property - def world(self): - import world - if self._world_obj is None: - self._world_obj = world.World(libdfhack.Context_getWorld(self._c_ptr)) - - return self._world_obj - - @property - def window_io(self): - import window_io - if self._window_io_obj is None: - self._window_io_obj = window_io.WindowIO(libdfhack.Context_getWindowIO(self._c_ptr)) - - return self._window_io_obj \ No newline at end of file diff --git a/dfhack-python/creatures.py b/dfhack-python/creatures.py deleted file mode 100644 index b4a51a4b5b..0000000000 --- a/dfhack-python/creatures.py +++ /dev/null @@ -1,73 +0,0 @@ -from ctypes import * -from dftypes import libdfhack, Creature, Material -import util - -libdfhack.Creatures_WriteLabors.argtypes = [ c_void_p, c_uint, POINTER(c_ubyte) ] - -libdfhack.Creatures_ReadJob.restype = POINTER(Material) -libdfhack.Creatures_ReadInventoryIdx.restype = POINTER(c_uint) -libdfhack.Creatures_ReadInventoryPtr.restype = POINTER(c_uint) - -class Creatures(object): - def __init__(self, ptr): - print ptr - self._c_ptr = ptr - - self._d_race_index = None - self._d_civ_id = None - - def start(self): - n = c_uint(0) - - if libdfhack.Creatures_Start(self._c_ptr, byref(n)) > 0: - return int(n.value) - else: - return -1 - - def finish(self): - return libdfhack.Creatures_Finish(self._c_ptr) > 0 - - def read_creature(self, index): - c = Creature() - - if libdfhack.Creatures_ReadCreature(self._c_ptr, c_int(index), byref(c)) > 0: - return c - else: - return None - - def read_creature_in_box(self, index, pos1, pos2): - c = Creature() - - x1, y1, z1 = c_uint(pos1[0]), c_uint(pos1[1]), c_uint(pos1[2]) - x2, y2, z2 = c_uint(pos2[0]), c_uint(pos2[1]), c_uint(pos2[2]) - - retval = libdfhack.Creatures_ReadCreatureInBox(self._c_ptr, byref(c), x1, y1, z1, x2, y2, z2) - - return (retval, c) - - def write_labors(self, index, labors): - return libdfhack.Creatures_WriteLabors(self._c_ptr, c_uint(index), labors) > 0 - - def read_job(self, creature): - job_ptr = libdfhack.Creatures_ReadJob(self._c_ptr, byref(creature)) - jobs = None - - if id(job_ptr) in dftypes.pointer_dict: - jobs = dftypes.pointer_dict[id(job_ptr)][1] - del dftypes.pointer_dict[id(job_ptr)] - - return jobs - - @property - def dwarf_race_index(self): - if self._d_race_index is None: - self._d_race_index =libdfhack.Creatures_GetDwarfRaceIndex(self._c_ptr) - - return self._d_race_index - - @property - def dwarf_civ_id(self): - if self._d_civ_id is None: - self._d_civ_id = libdfhack.Creatures_GetDwarfCivId(self._c_ptr) - - return self._d_civ_id diff --git a/dfhack-python/dfhack_api_ctypes.py b/dfhack-python/dfhack_api_ctypes.py deleted file mode 100644 index 185746e3b0..0000000000 --- a/dfhack-python/dfhack_api_ctypes.py +++ /dev/null @@ -1,152 +0,0 @@ -from ctypes import * -from pydftypes import * - - -libdfhack.API_Alloc.restype = c_void_p -libdfhack.API_Free.argtypes = [ c_void_p ] - -libdfhack.API_getMemoryInfo.restype = c_void_p -libdfhack.API_getProcess.restype = c_void_p -libdfhack.API_getWindow.restype = c_void_p - -libdfhack.API_getCreatures.restype = c_void_p -libdfhack.API_getMaps.restype = c_void_p -libdfhack.API_getGui.restype = c_void_p -libdfhack.API_getMaterials.restype = c_void_p -libdfhack.API_getTranslation.restype = c_void_p -libdfhack.API_getVegetation.restype = c_void_p -libdfhack.API_getBuildings.restype = c_void_p -libdfhack.API_getConstructions.restype = c_void_p -libdfhack.API_getItems.restype = c_void_p - -class API(object): - def __init__(self, memory_path): - self._api_ptr = libdfhack.API_Alloc(create_string_buffer(memory_path)) - - self._mat_obj = None - self._map_obj = None - self._veg_obj = None - self._build_obj = None - self._con_obj = None - self._gui_obj = None - self._tran_obj = None - self._item_obj = None - self._creature_obj = None - - def __del__(self): - libdfhack.API_Free(self._api_ptr) - - def attach(self): - return libdfhack.API_Attach(self._api_ptr) > 0 - - def detach(self): - return libdfhack.API_Detach(self._api_ptr) > 0 - - def suspend(self): - return libdfhack.API_Suspend(self._api_ptr) > 0 - - def resume(self): - return libdfhack.API_Resume(self._api_ptr) > 0 - - def force_resume(self): - return libdfhack.API_ForceResume(self._api_ptr) > 0 - - def async_suspend(self): - return libdfhack.API_AsyncSuspend(self._api_ptr) > 0 - - @property - def is_attached(self): - return libdfhack.API_isAttached(self._api_ptr) > 0 - - @property - def is_suspended(self): - return libdfhack.API_isSuspended(self._api_ptr) > 0 - - @property - def materials(self): - import materials - if self._mat_obj is None: - self._mat_obj = materials.Materials(libdfhack.API_getMaterials(self._api_ptr)) - - return self._mat_obj - - @property - def maps(self): - import maps - if self._map_obj is None: - self._map_obj = maps.Maps(libdfhack.API_getMaps(self._api_ptr)) - - return self._map_obj - - @property - def vegetation(self): - import vegetation - if self._veg_obj is None: - self._veg_obj = vegetation.Vegetation(libdfhack.API_getVegetation(self._api_ptr)) - - return self._veg_obj - - @property - def buildings(self): - import buildings - if self._build_obj is None: - self._build_obj = buildings.Buildings(libdfhack.API_getBuildings(self._api_ptr)) - - return self._build_obj - - @property - def creatures(self): - import creatures - if self._creature_obj is None: - self._creature_obj = creatures.Creatures(libdfhack.API_getCreatures(self._api_ptr)) - - return self._creature_obj - - @property - def gui(self): - import gui - if self._gui_obj is None: - self._gui_obj = gui.Gui(libdfhack.API_getGui(self._api_ptr)) - - return self._gui_obj - - @property - def items(self): - import items - if self._item_obj is None: - self._item_obj = items.Items(libdfhack.API_getItems(self._api_ptr)) - - return self._item_obj - - @property - def translation(self): - import translation - if self._tran_obj is None: - self._tran_obj = translation.Translation(libdfhack.API_getTranslation(self._api_ptr)) - - return self._tran_obj - -def reveal(): - df = API("Memory.xml") - df.attach() - - m = df.maps - - m.start() - - m_x, m_y, m_z = m.size - - for x in xrange(m_x): - for y in xrange(m_y): - for z in xrange(m_z): - if m.is_valid_block(x, y, z): - d = m.read_designations(x, y, z) - - for i in d: - for j in i: - j.bits.hidden = 0 - - m.write_designations(x, y, z, d) - - m.finish() - df.detach() diff --git a/dfhack-python/dftypes.py b/dfhack-python/dftypes.py deleted file mode 100644 index 729f7cdff7..0000000000 --- a/dfhack-python/dftypes.py +++ /dev/null @@ -1,637 +0,0 @@ -from ctypes import * -from flags import * -from enum import * -import util -from util import * - -libdfhack = cdll.libdfhack - -def _register_callback(name, func): - ptr = c_void_p.in_dll(libdfhack, name) - ptr.value = cast(func, c_void_p).value - -_register_callback("alloc_byte_buffer_callback", alloc_byte_buffer) -_register_callback("alloc_ubyte_buffer_callback", alloc_ubyte_buffer) -_register_callback("alloc_short_buffer_callback", alloc_short_buffer) -_register_callback("alloc_ushort_buffer_callback", alloc_ushort_buffer) -_register_callback("alloc_int_buffer_callback", alloc_int_buffer) -_register_callback("alloc_uint_buffer_callback", alloc_uint_buffer) -_register_callback("alloc_char_buffer_callback", alloc_char_buffer) - -_arr_create_func = CFUNCTYPE(c_void_p, c_int) -_dfhack_string = (c_char * 128) - -TileTypes40d = ((c_int * 16) * 16) -BiomeIndices40d = c_ubyte * 16 -Temperatures = ((c_ushort * 16) * 16) -Designations40d = ((DesignationFlags * 16) * 16) -Occupancies40d = ((OccupancyFlags * 16) * 16) - -def wall_terrain_check(terrain): - return libdfhack.DFHack_isWallTerrain(terrain) > 0 - -def floor_terrain_check(terrain): - return libdfhack.DFHack_isFloorTerrain(terrain) > 0 - -def ramp_terrain_check(terrain): - return libdfhack.DFHack_isRampTerrain(terrain) > 0 - -def stair_terrain_check(terrain): - return libdfhack.DFHack_isStairTerrain(terrain) > 0 - -def open_terrain_check(terrain): - return libdfhack.DFHack_isOpenTerrain(terrain) > 0 - -def get_vegetation_type(terrain): - return libdfhack.DFHack_getVegetationType(terrain) - -class Position2D(Structure): - _fields_ = [("x", c_ushort), - ("y", c_ushort)] - -class Position3D(Structure): - _fields_ = [("x", c_ushort), - ("y", c_ushort), - ("z", c_uint)] - -class PlaneCoord(Union): - _fields_ = [("xyz", Position3D), - ("dim", Position2D), - ("comparate", c_ulong)] - - def __cmp__(self, other): - if isinstance(other, PlaneCoord): - return self.comparate - other.comparate - else: - raise TypeError("argument must be of type %s" % type(self)) - -class Feature(Structure): - _fields_ = [("type", FeatureType), - ("main_material", c_short), - ("sub_material", c_short), - ("discovered", c_byte), - ("origin", c_uint)] - -class FeatureMapNode(Structure): - _fields_ = [("coordinate", PlaneCoord), - ("features", POINTER(Feature)), - ("feature_length", c_uint)] - -def _alloc_featuremap_buffer_callback(ptr, fmap_list, count): - arr_list = [] - arr = (FeatureMapNode * count)() - - for i, v in enumerate(arr): - f_count = int(fmap_list[i]) - f_arr = (Feature * f_count)() - - f_p = cast(f_arr, POINTER(Feature)) - v.features = f_p - - arr_list.extend((f_arr, f_p)) - - p = cast(arr, POINTER(FeatureMapNode)) - ptr[0] = p - - pointer_dict[addressof(arr)] = (ptr, arr, p, arr_list) - - return 1 - -_alloc_featuremap_buffer_functype = CFUNCTYPE(c_int, POINTER(POINTER(FeatureMapNode)), uint_ptr, c_uint) -_alloc_featuremap_buffer_func = _alloc_featuremap_buffer_functype(_alloc_featuremap_buffer_callback) -_register_callback("alloc_featuremap_buffer_callback", _alloc_featuremap_buffer_func) - -class Vein(Structure): - _fields_ = [("vtable", c_uint), - ("type", c_int), - ("assignment", c_short * 16), - ("flags", c_uint), - ("address_of", c_uint)] - -_vein_ptr = POINTER(Vein) - -def _alloc_vein_buffer_callback(ptr, count): - return util._allocate_array(ptr, Vein, count) - -_vein_functype = CFUNCTYPE(c_int, POINTER(_vein_ptr), c_uint) -_vein_func = _vein_functype(_alloc_vein_buffer_callback) -_register_callback("alloc_vein_buffer_callback", _vein_func) - -class FrozenLiquidVein(Structure): - _fields_ = [("vtable", c_uint), - ("tiles", TileTypes40d), - ("address_of", c_uint)] - -_frozenvein_ptr = POINTER(FrozenLiquidVein) - -def _alloc_frozenliquidvein_buffer_callback(ptr, count): - return util._allocate_array(ptr, FrozenLiquidVein, count) - -_frozenliquidvein_functype = CFUNCTYPE(c_int, POINTER(_frozenvein_ptr), c_uint) -_frozenliquidvein_func = _frozenliquidvein_functype(_alloc_frozenliquidvein_buffer_callback) -_register_callback("alloc_frozenliquidvein_buffer_callback", _frozenliquidvein_func) - -class SpatterVein(Structure): - _fields_ = [("vtable", c_uint), - ("mat1", c_ushort), - ("unk1", c_ushort), - ("mat2", c_uint), - ("mat3", c_ushort), - ("intensity", ((c_ubyte * 16) * 16)), - ("address_of", c_uint)] - -_spattervein_ptr = POINTER(SpatterVein) - -def _alloc_spattervein_buffer_callback(ptr, count): - return util._allocate_array(ptr, SpatterVein, count) - -_spattervein_functype = CFUNCTYPE(c_int, POINTER(_spattervein_ptr), c_uint) -_spattervein_func = _spattervein_functype(_alloc_spattervein_buffer_callback) -_register_callback("alloc_spattervein_buffer_callback", _spattervein_func) - -class GrassVein(Structure): - _fields_ = [("vtable", c_uint), - ("material", c_uint), - ("intensity", ((c_ubyte * 16) * 16)), - ("address_of", c_uint)] - -_grassvein_ptr = POINTER(GrassVein) - -def _alloc_grassvein_buffer_callback(ptr, count): - return util._allocate_array(ptr, GrassVein, count) - -_grassvein_functype = CFUNCTYPE(c_int, POINTER(_grassvein_ptr), c_uint) -_grassvein_func = _grassvein_functype(_alloc_grassvein_buffer_callback) -_register_callback("alloc_grassvein_buffer_callback", _grassvein_func) - -class WorldConstruction(Structure): - _fields_ = [("vtable", c_uint), - ("material", c_uint), - ("assignment", c_ushort * 16), - ("address_of", c_uint)] - -_worldconstruction_ptr = POINTER(WorldConstruction) - -def _alloc_worldconstruction_buffer_callback(ptr, count): - return util._allocate_array(ptr, WorldConstruction, count) - -_worldconstruction_functype = CFUNCTYPE(c_int, POINTER(_worldconstruction_ptr), c_uint) -_worldconstruction_func = _worldconstruction_functype(_alloc_worldconstruction_buffer_callback) -_register_callback("alloc_worldconstruction_buffer_callback", _worldconstruction_func) - -class MapBlock40d(Structure): - _fields_ = [("tiletypes", TileTypes40d), - ("designation", Designations40d), - ("occupancy", Occupancies40d), - ("biome_indices", BiomeIndices40d), - ("origin", c_uint), - ("blockflags", BlockFlags), - ("global_feature", c_short), - ("local_feature", c_short)] - - -class ViewScreen(Structure): - _fields_ = [("type", c_int)] - -class Matgloss(Structure): - _fields_ = [("id", _dfhack_string), - ("fore", c_byte), - ("back", c_byte), - ("bright", c_byte), - ("name", _dfhack_string)] - -_matgloss_ptr = POINTER(Matgloss) - -def _alloc_matgloss_buffer_callback(ptr, count): - return util._allocate_array(ptr, Matgloss, count) - -_matgloss_functype = CFUNCTYPE(c_int, POINTER(_matgloss_ptr), c_uint) -_matgloss_func = _matgloss_functype(_alloc_matgloss_buffer_callback) -_register_callback("alloc_matgloss_buffer_callback", _matgloss_func) - -class MatglossPair(Structure): - _fields_ = [("type", c_short), - ("index", c_int)] - -class DescriptorColor(Structure): - _fields_ = [("id", _dfhack_string), - ("r", c_float), - ("v", c_float), - ("b", c_float), - ("name", _dfhack_string)] - -def _alloc_descriptor_buffer_callback(ptr, count): - return util._allocate_array(ptr, DescriptorColor, count) - -_descriptor_functype = CFUNCTYPE(c_int, POINTER(POINTER(DescriptorColor)), c_uint) -_descriptor_func = _descriptor_functype(_alloc_descriptor_buffer_callback) -_register_callback("alloc_descriptor_buffer_callback", _descriptor_func) - -class MatglossPlant(Structure): - _fields_ = [("id", _dfhack_string), - ("fore", c_ubyte), - ("back", c_ubyte), - ("bright", c_ubyte), - ("name", _dfhack_string), - ("drink_name", _dfhack_string), - ("food_name", _dfhack_string), - ("extract_name", _dfhack_string)] - -class MatglossOther(Structure): - _fields_ = [("rawname", c_char * 128)] - -def _alloc_matgloss_other_buffer_callback(ptr, count): - return util._allocate_array(ptr, MatglossOther, count) - -_matgloss_other_functype = CFUNCTYPE(c_int, POINTER(POINTER(MatglossOther)), c_uint) -_matgloss_other_func = _matgloss_other_functype(_alloc_matgloss_other_buffer_callback) -_register_callback("alloc_matgloss_other_buffer_callback", _matgloss_other_func) - -class Building(Structure): - _fields_ = [("origin", c_uint), - ("vtable", c_uint), - ("x1", c_uint), - ("y1", c_uint), - ("x2", c_uint), - ("y2", c_uint), - ("z", c_uint), - ("material", MatglossPair), - ("type", c_uint)] - -class CustomWorkshop(Structure): - _fields_ = [("index", c_uint), - ("name", c_char * 256)] - -def _alloc_custom_workshop_buffer_callback(ptr, count): - return util._allocate_array(ptr, CustomWorkshop, count) - -_custom_workshop_functype = CFUNCTYPE(c_int, POINTER(POINTER(CustomWorkshop)), c_uint) -_custom_workshop_func = _custom_workshop_functype(_alloc_custom_workshop_buffer_callback) -_register_callback("alloc_customWorkshop_buffer_callback", _custom_workshop_func) - -class Construction(Structure): - _fields_ = [("x", c_ushort), - ("y", c_ushort), - ("z", c_ushort), - ("form", c_ushort), - ("unk_8", c_ushort), - ("mat_type", c_ushort), - ("mat_idx", c_uint), - ("unk3", c_ushort), - ("unk4", c_ushort), - ("unk5", c_ushort), - ("unk6", c_uint), - ("origin", c_uint)] - -class Tree(Structure): - _fields_ = [("type", c_ushort), - ("material", c_ushort), - ("x", c_ushort), - ("y", c_ushort), - ("z", c_ushort), - ("address", c_uint)] - - def __str__(self): - water = "" - tree_type = "tree" - - if self.type == 1 or self.type == 3: - water = "near-water" - if self.type == 2 or self.type == 3: - tree_type = "shrub" - - s = "%d:%d = %s %s\nAddress: 0x%x\n" % (self.type, self.material, water, tree_type, self.address) - - return s - -def _alloc_tree_buffer_callback(ptr, count): - return util._allocate_array(ptr, Tree, count) - -_alloc_tree_buffer_functype = CFUNCTYPE(c_int, POINTER(POINTER(Tree)), c_uint) -_alloc_tree_buffer_func = _alloc_tree_buffer_functype(_alloc_tree_buffer_callback) -_register_callback("alloc_tree_buffer_callback", _alloc_tree_buffer_func) - -class Material(Structure): - _fields_ = [("itemType", c_short), - ("subType", c_short), - ("subIndex", c_short), - ("index", c_int), - ("flags", c_uint)] - -def _alloc_material_buffer_callback(ptr, count): - return util._allocate_array(ptr, Material, count) - -_material_functype = CFUNCTYPE(c_int, POINTER(POINTER(Material)), c_uint) -_material_func = _material_functype(_alloc_material_buffer_callback) -_register_callback("alloc_material_buffer_callback", _material_func) - -class Skill(Structure): - _fields_ = [("id", c_uint), - ("experience", c_uint), - ("rating", c_uint)] - -class Job(Structure): - _fields_ = [("active", c_byte), - ("jobId", c_uint), - ("jobType", c_ubyte), - ("occupationPtr", c_uint)] - -class Like(Structure): - _fields_ = [("type", c_short), - ("itemClass", c_short), - ("itemIndex", c_short), - ("material", MatglossPair), - ("active", c_byte)] - -class Attribute(Structure): - _fields_ = [("level", c_uint), - ("field_4", c_uint), - ("field_8", c_uint), - ("field_C", c_uint), - ("leveldiff", c_uint), - ("field_14", c_uint), - ("field_18", c_uint)] - -class Name(Structure): - _fields_ = [("first_name", _dfhack_string), - ("nickname", _dfhack_string), - ("words", (c_int * 7)), - ("parts_of_speech", (c_ushort * 7)), - ("language", c_uint), - ("has_name", c_byte)] - -class Note(Structure): - _fields_ = [("symbol", c_char), - ("foreground", c_ushort), - ("background", c_ushort), - ("name", _dfhack_string), - ("x", c_ushort), - ("y", c_ushort), - ("z", c_ushort)] - -class Settlement(Structure): - _fields_ = [("origin", c_uint), - ("name", Name), - ("world_x", c_short), - ("world_y", c_short), - ("local_x1", c_short), - ("local_x2", c_short), - ("local_y1", c_short), - ("local_y2", c_short)] - -_NUM_CREATURE_TRAITS = 30 -_NUM_CREATURE_LABORS = 102 - -class Soul(Structure): - _fields_ = [("numSkills", c_ubyte), - ("skills", (Skill * 256)), - ("traits", (c_ushort * _NUM_CREATURE_TRAITS)), - ("analytical_ability", Attribute), - ("focus", Attribute), - ("willpower", Attribute), - ("creativity", Attribute), - ("intuition", Attribute), - ("patience", Attribute), - ("memory", Attribute), - ("linguistic_ability", Attribute), - ("spatial_sense", Attribute), - ("musicality", Attribute), - ("kinesthetic_sense", Attribute), - ("empathy", Attribute), - ("social_awareness", Attribute)] - -_MAX_COLORS = 15 - -class Creature(Structure): - _fields_ = [("origin", c_uint), - ("x", c_ushort), - ("y", c_ushort), - ("z", c_ushort), - ("race", c_uint), - ("civ", c_int), - ("flags1", CreatureFlags1), - ("flags2", CreatureFlags2), - ("name", Name), - ("mood", c_short), - ("mood_skill", c_short), - ("artifact_name", Name), - ("profession", c_ubyte), - ("custom_profession", _dfhack_string), - ("labors", (c_ubyte * _NUM_CREATURE_LABORS)), - ("current_job", Job), - ("happiness", c_uint), - ("id", c_uint), - ("strength", Attribute), - ("agility", Attribute), - ("toughness", Attribute), - ("endurance", Attribute), - ("recuperation", Attribute), - ("disease_resistance", Attribute), - ("squad_leader_id", c_int), - ("sex", c_ubyte), - ("caste", c_ushort), - ("pregnancy_timer", c_uint), - ("has_default_soul", c_byte), - ("defaultSoul", Soul), - ("nbcolors", c_uint), - ("color", (c_uint * _MAX_COLORS)), - ("birth_year", c_int), - ("birth_time", c_uint)] - -class CreatureExtract(Structure): - _fields_ = [("rawname", _dfhack_string)] - -class BodyPart(Structure): - _fields_ = [("id", _dfhack_string), - ("category", _dfhack_string), - ("single", _dfhack_string), - ("plural", _dfhack_string)] - -_bodypart_ptr = POINTER(BodyPart) - -class ColorModifier(Structure): - _fields_ = [("part", _dfhack_string), - ("colorlist", POINTER(c_uint)), - ("colorlistLength", c_uint), - ("startdate", c_uint), - ("enddate", c_uint)] - - def __init__(self): - self.colorlistLength = 0 - -_colormodifier_ptr = POINTER(ColorModifier) - -class CreatureCaste(Structure): - _fields_ = [("rawname", _dfhack_string), - ("singular", _dfhack_string), - ("plural", _dfhack_string), - ("adjective", _dfhack_string), - ("color_modifier", _colormodifier_ptr), - ("color_modifier_length", c_uint), - ("bodypart", _bodypart_ptr), - ("bodypart_length", c_uint), - ("strength", Attribute), - ("agility", Attribute), - ("toughness", Attribute), - ("endurance", Attribute), - ("recuperation", Attribute), - ("disease_resistance", Attribute), - ("analytical_ability", Attribute), - ("focus", Attribute), - ("willpower", Attribute), - ("creativity", Attribute), - ("intuition", Attribute), - ("patience", Attribute), - ("memory", Attribute), - ("linguistic_ability", Attribute), - ("spatial_sense", Attribute), - ("musicality", Attribute), - ("kinesthetic_sense", Attribute)] - -_creaturecaste_ptr = POINTER(CreatureCaste) - -class TileColor(Structure): - _fields_ = [("fore", c_ushort), - ("back", c_ushort), - ("bright", c_ushort)] - -class ColorDescriptor(Structure): - _fields_ = [("colorlistLength", c_uint)] - -class CasteDescriptor(Structure): - _fields_ = [("color_descriptors", POINTER(ColorDescriptor)), - ("colorModifierLength", c_uint), - ("bodypartLength", c_uint)] - -class CreatureTypeDescriptor(Structure): - _fields_ = [("caste_descriptors", POINTER(CasteDescriptor)), - ("castesCount", c_uint), - ("extractCount", c_uint)] - -class CreatureType(Structure): - _fields_ = [("rawname", _dfhack_string), - ("castes", _creaturecaste_ptr), - ("castes_count", c_uint), - ("extract", POINTER(CreatureExtract)), - ("extract_count", c_uint), - ("tile_character", c_ubyte), - ("tilecolor", TileColor)] - -_creaturetype_ptr = POINTER(CreatureType) - -def _alloc_creaturetype_buffer(ptr, descriptors, count): - arr_list = [] - c_arr = (CreatureType * count)() - - for i, v in enumerate(c_arr): - v.castesCount = descriptors[i].castesCount - v_caste_arr = (CreatureCaste * v.castesCount)() - - for j, v_c in enumerate(v_caste_arr): - caste_descriptor = descriptors[i].caste_descriptors[j] - - v_c.colorModifierLength = caste_descriptor.colorModifierLength - c_color_arr = (ColorModifier * v_c.colorModifierLength)() - - for k, c_c in enumerate(c_color_arr): - color_descriptor = caste_descriptor.color_descriptors[k] - - c_c.colorlistLength = color_descriptor.colorlistLength - - c_color_list_arr = (c_uint * c_c.colorlistLength)() - - p = cast(c_color_list_arr, POINTER(c_uint)) - - c_c.colorlist = p - - arr_list.extend((c_color_list_arr, p)) - - c_p = cast(c_color_arr, POINTER(ColorModifier)) - v_c.colorModifier = c_p - - v_c.bodypartLength = caste_descriptor.bodypartLength - c_bodypart_arr = (BodyPart * v_c.bodypartLength)() - - b_p = cast(c_bodypart_arr, POINTER(BodyPart)) - v_c.bodypart = b_p - - arr_list.extend((c_color_arr, c_p, c_bodypart_arr, b_p)) - - v.extractCount = descriptors[i].extractCount - v_extract_arr = (CreatureExtract * v.extractCount)() - - caste_p = cast(v_caste_arr, POINTER(CreatureCaste)) - v.castes = caste_p - - extract_p = cast(v_extract_arr, POINTER(CreatureExtract)) - v.extract = extract_p - - arr_list.extend((v_caste_arr, caste_p, v_extract_arr, extract_p)) - - p = cast(c_arr, _creaturetype_ptr) - ptr[0] = p - - pointer_dict[addressof(c_arr)] = (ptr, c_arr, p, arr_list) - - return 1 - -_alloc_creaturetype_buffer_functype = CFUNCTYPE(c_int, POINTER(_creaturetype_ptr), POINTER(CreatureTypeDescriptor), c_uint) -_alloc_creaturetype_buffer_func = _alloc_creaturetype_buffer_functype(_alloc_creaturetype_buffer) -_register_callback("alloc_creaturetype_buffer_callback", _alloc_creaturetype_buffer_func) - -class GameModes(Structure): - _fields_ = [("control_mode", c_ubyte), - ("game_mode", c_ubyte)] - -class Hotkey(Structure): - _fields_ = [("name", (c_char * 10)), - ("mode", c_short), - ("x", c_int), - ("y", c_int), - ("z", c_int)] - -_hotkey_ptr = POINTER(Hotkey) - -def _alloc_hotkey_buffer_callback(ptr, count): - print "hotkey alloc: %d" % count - return util._allocate_array(ptr, Hotkey, count) - -_hotkey_functype = CFUNCTYPE(c_int, POINTER(_hotkey_ptr), c_uint) -_hotkey_func = _hotkey_functype(_alloc_hotkey_buffer_callback) -_register_callback("alloc_hotkey_buffer_callback", _hotkey_func) - -class MemRange(Structure): - _fields_ = [("start", c_ulong), - ("end", c_ulong), - ("name", (c_char * 1024)), - ("read", c_uint, 1), - ("write", c_uint, 1), - ("execute", c_uint, 1), - ("shared", c_uint, 1), - ("valid", c_ubyte), - ("buffer", POINTER(c_ubyte))] - -_memrange_ptr = POINTER(MemRange) - -def _alloc_memrange_buffer(ptr, descriptors, count): - arr_list = [] - m_arr = (MemRange * count)() - - for i, v in enumerate(m_arr): - buf_arr = (c_ubyte * int(descriptors[i]))() - buf_ptr = cast(buf_arr, POINTER(c_ubyte)) - - v.buffer = buf_ptr - - arr_list.extend((buf_arr, buf_ptr)) - - p = cast(m_arr, _memrange_ptr) - ptr[0] = p - - pointer_dict[addressof(m_arr)] = (ptr, m_arr, p, arr_list) - - return 1 - -_alloc_memrange_buffer_functype = CFUNCTYPE(c_int, POINTER(_memrange_ptr), POINTER(c_uint), c_uint) -_alloc_memrange_buffer_func = _alloc_memrange_buffer_functype(_alloc_memrange_buffer) -_register_callback("alloc_memrange_buffer_callback", _alloc_memrange_buffer_func) \ No newline at end of file diff --git a/dfhack-python/enum.py b/dfhack-python/enum.py deleted file mode 100644 index bc123a8c90..0000000000 --- a/dfhack-python/enum.py +++ /dev/null @@ -1,156 +0,0 @@ -#found this in the cookbook: http://code.activestate.com/recipes/576415/ - -from ctypes import c_uint - -class C_EnumerationType(type(c_uint)): - def __new__(metacls, name, bases, dictionary): - if not "_members_" in dictionary: - _members_ = {} - - for key, value in dictionary.iteritems(): - if not key.startswith("_"): - _members_[key] = value - - dictionary["_members_"] = _members_ - - cls = type(c_uint).__new__(metacls, name, bases, dictionary) - - for key, value in cls._members_.iteritems(): - globals()[key] = value - - return cls - - def __contains__(self, value): - return value in self._members_.values() - - def __repr__(self): - return "" % self.__name__ - -class C_Enumeration(c_uint): - __metaclass__ = C_EnumerationType - _members_ = {} - - def __init__(self, value): - for key, value in self._members_.iteritems(): - if v == value: - self.name = key - break - else: - raise ValueError("No enumeration member with value %r" % value) - - c_uint.__init__(self, value) - - def __repr__(self): - return "" % (self.name, self.value, self.__class__) - - @classmethod - def from_param(cls, param): - if isinstance(param, C_Enumeration): - if param.__class__ != cls: - raise ValueError("Cannot mix enumeration members") - else: - return param - else: - return cls(param) - -FeatureType = C_EnumerationType("FeatureType", - (c_uint,), - {"Other" : 0, - "Adamantine_Tube" : 1, - "Underworld" : 2, - "Hell_Temple" : 3}) - -BiomeOffset = C_EnumerationType("BiomeOffset", - (c_uint,), - {"NorthWest" : 0, - "North" : 1, - "NorthEast" : 2, - "West" : 3, - "Here" : 4, - "East" : 5, - "SouthWest" : 6, - "South" : 7, - "SouthEast" : 8, - "BiomeCount" : 9}) - -TrafficType = C_EnumerationType("TrafficType", - (c_uint,), - {"Normal" : 0, - "Low" : 1, - "High" : 2, - "Restricted" : 3}) - -DesignationType = C_EnumerationType("DesignationType", - (c_uint,), - {"No" : 0, - "Default" : 1, - "UD_Stair" : 2, - "Channel" : 3, - "Ramp" : 4, - "D_Stair" : 5, - "U_Stair" : 6, - "Whatever" : 7}) - -LiquidType = C_EnumerationType("LiquidType", - (c_uint,), - {"Water" : 0, - "Magma" : 1}) - -#this list must stay in the same order as the one in dfhack/library/include/dfhack/modules/WindowIO.h! -_keys = ["ENTER", - "SPACE", - "BACK_SPACE", - "TAB", - "CAPS_LOCK", - "LEFT_SHIFT", - "RIGHT_SHIFT", - "LEFT_CONTROL", - "RIGHT_CONTROL", - "ALT", - "WAIT", - "ESCAPE", - "UP", - "DOWN", - "LEFT", - "RIGHT", - "F1", - "F2", - "F3", - "F4", - "F5", - "F6", - "F7", - "F8", - "F9", - "F10", - "F11", - "F12", - "PAGE_UP", - "PAGE_DOWN", - "INSERT", - "DFK_DELETE", - "HOME", - "END", - "KEYPAD_DIVIDE", - "KEYPAD_MULTIPLY", - "KEYPAD_SUBTRACT", - "KEYPAD_ADD," - "KEYPAD_ENTER", - "KEYPAD_0", - "KEYPAD_1", - "KEYPAD_2", - "KEYPAD_3", - "KEYPAD_4", - "KEYPAD_5", - "KEYPAD_6", - "KEYPAD_7", - "KEYPAD_8", - "KEYPAD_9", - "KEYPAD_DECIMAL_POINT", - "NUM_SPECIALS"] - -_key_dict = dict([(k, i) for i, k in enumerate(_keys)]) - -KeyType = C_EnumerationType("KeyType", - (c_uint,), - _key_dict) diff --git a/dfhack-python/flags.py b/dfhack-python/flags.py deleted file mode 100644 index e058ab5112..0000000000 --- a/dfhack-python/flags.py +++ /dev/null @@ -1,201 +0,0 @@ -# -*- coding: utf-8 -*- -from ctypes import Structure, Union, c_uint -from enum import * - -class DesignationStruct(Structure): - _fields_ = [("flow_size", c_uint, 3), - ("pile", c_uint, 1), - ("dig", DesignationType, 3), - ("smooth", c_uint, 2), - ("hidden", c_uint, 1), - ("geolayer_index", c_uint, 4), - ("light", c_uint, 1), - ("subterranean", c_uint, 1), - ("skyview", c_uint, 1), - ("biome", c_uint, 4), - ("liquid_type", c_uint, 1), - ("water_table", c_uint, 1), - ("rained", c_uint, 1), - ("traffic", c_uint, 2), - ("flow_forbid", c_uint, 1), - ("liquid_static", c_uint, 1), - ("feature_local", c_uint, 1), - ("feature_global", c_uint, 1), - ("water_stagnant", c_uint, 1), - ("water_salt", c_uint, 1)] - -class DesignationFlags(Union): - _fields_ = [("whole", c_uint, 32), - ("bits", DesignationStruct)] - - def __init__(self, initial = 0): - self.whole = initial - - def __int__(self): - return self.whole - -class OccupancyStruct(Structure): - _fields_ = [("building", c_uint, 3), - ("unit", c_uint, 1), - ("unit_grounded", c_uint, 1), - ("item", c_uint, 1), - ("splatter", c_uint, 26)] - -class OccupancyFlags(Union): - _fields_ = [("whole", c_uint, 32), - ("bits", OccupancyStruct)] - - def __init__(self, initial = 0): - self.whole = initial - - def __int__(self): - return self.whole - -class CreatureStruct1(Structure): - _fields_ = [("move_state", c_uint, 1), - ("dead", c_uint, 1), - ("has_mood", c_uint, 1), - ("had_mood", c_uint, 1), - ("marauder", c_uint, 1), - ("drowning", c_uint, 1), - ("merchant", c_uint, 1), - ("forest", c_uint, 1), - ("left", c_uint, 1), - ("rider", c_uint, 1), - ("incoming", c_uint, 1), - ("diplomat", c_uint, 1), - ("zombie", c_uint, 1), - ("skeleton", c_uint, 1), - ("can_swap", c_uint, 1), - ("on_ground", c_uint, 1), - ("projectile", c_uint, 1), - ("active_invader", c_uint, 1), - ("hidden_in_ambush", c_uint, 1), - ("invader_origin", c_uint, 1), - ("coward", c_uint, 1), - ("hidden_ambusher", c_uint, 1), - ("invades", c_uint, 1), - ("check_flows", c_uint, 1), - ("ridden", c_uint, 1), - ("caged", c_uint, 1), - ("tame", c_uint, 1), - ("chained", c_uint, 1), - ("royal_guard", c_uint, 1), - ("fortress_guard", c_uint, 1), - ("suppress_wield", c_uint, 1), - ("important_historical_figure", c_uint, 1)] - -class CreatureFlags1(Union): - _fields_ = [("whole", c_uint, 32), - ("bits", CreatureStruct1)] - - def __init__(self, initial = 0): - self.whole = initial - - def __int__(self): - return self.whole - -class CreatureStruct2(Structure): - _fields_ = [("swimming", c_uint, 1), - ("sparring", c_uint, 1), - ("no_notify", c_uint, 1), - ("unused", c_uint, 1), - ("calculated_nerves", c_uint, 1), - ("calculated_bodyparts", c_uint, 1), - ("important_historical_figure", c_uint, 1), - ("killed", c_uint, 1), - ("cleanup_1", c_uint, 1), - ("cleanup_2", c_uint, 1), - ("cleanup_3", c_uint, 1), - ("for_trade", c_uint, 1), - ("trade_resolved", c_uint, 1), - ("has_breaks", c_uint, 1), - ("gutted", c_uint, 1), - ("circulatory_spray", c_uint, 1), - ("locked_in_for_trading", c_uint, 1), - ("slaughter", c_uint, 1), - ("underworld", c_uint, 1), - ("resident", c_uint, 1), - ("cleanup_4", c_uint, 1), - ("calculated_insulation", c_uint, 1), - ("visitor_uninvited", c_uint, 1), - ("visitor", c_uint, 1), - ("calculated_inventory", c_uint, 1), - ("vision_good", c_uint, 1), - ("vision_damaged", c_uint, 1), - ("vision_missing", c_uint, 1), - ("breathing_good", c_uint, 1), - ("breathing_problem", c_uint, 1), - ("roaming_wilderness_population_source", c_uint, 1), - ("roaming_wilderness_population_source_not_a_map_feature", c_uint, 1)] - -class CreatureFlags2(Union): - _fields_ = [("whole", c_uint, 32), - ("bits", CreatureStruct2)] - - def __init__(self, initial = 0): - self.whole = initial - - def __int__(self): - return self.whole - -class ItemStruct(Structure): - _fields_ = [("on_ground", c_uint, 1), - ("in_job", c_uint, 1), - ("in_inventory", c_uint, 1), - ("u_ngrd1", c_uint, 1), - ("in_workshop", c_uint, 1), - ("u_ngrd2", c_uint, 1), - ("u_ngrd3", c_uint, 1), - ("rotten", c_uint, 1), - ("unk1", c_uint, 1), - ("u_ngrd4", c_uint, 1), - ("unk2", c_uint, 1), - ("u_ngrd5", c_uint, 1), - ("unk3", c_uint, 1), - ("u_ngrd6", c_uint, 1), - ("narrow", c_uint, 1), - ("u_ngrd7", c_uint, 1), - ("worn", c_uint, 1), - ("unk4", c_uint, 1), - ("u_ngrd8", c_uint, 1), - ("forbid", c_uint, 1), - ("unk5", c_uint, 1), - ("dump", c_uint, 1), - ("on_fire", c_uint, 1), - ("melt", c_uint, 1), - ("hidden", c_uint, 1), - ("u_ngrd9", c_uint, 1), - ("unk6", c_uint, 1), - ("unk7", c_uint, 1), - ("unk8", c_uint, 1), - ("unk9", c_uint, 1), - ("unk10", c_uint, 1), - ("unk11", c_uint, 1)] - -class ItemFlags(Union): - _fields_ = [("whole", c_uint, 32), - ("bits", ItemStruct)] - - def __init__(self, initial = 0): - self.whole = initial - - def __int__(self): - return self.whole - -class BlockFlagStruct(Structure): - _fields_ = [("designated", c_uint, 1), - ("unk_1", c_uint, 1), - ("liquid_1", c_uint, 1), - ("liquid_2", c_uint, 1), - ("unk_2", c_uint, 28)] - -class BlockFlags(Union): - _fields_ = [("whole", c_uint, 32), - ("bits", BlockFlagStruct)] - - def __init__(self, inital = 0): - self.whole = initial - - def __int__(self): - return self.whole diff --git a/dfhack-python/gui.py b/dfhack-python/gui.py deleted file mode 100644 index 2a050d7824..0000000000 --- a/dfhack-python/gui.py +++ /dev/null @@ -1,73 +0,0 @@ -from ctypes import c_void_p, c_int, c_uint, byref -from dftypes import libdfhack, ViewScreen, Hotkey -from util import check_pointer_cache - -libdfhack.Gui_getViewCoords.argtypes = [ c_void_p, POINTER(c_int), POINTER(c_int), POINTER(c_int) ] -libdfhack.Gui_setViewCoords.argtypes = [ c_void_p, c_int, c_int, c_int ] - -libdfhack.Gui_getCursorCoords.argtypes = [ c_void_p, POINTER(c_int), POINTER(c_int), POINTER(c_int) ] -libdfhack.Gui_setCursorCoords.argtypes = [ c_void_p, c_int, c_int, c_int ] - -libdfhack.Gui_getWindowSize.argtypes = [ c_void_p, POINTER(c_int), POINTER(c_int) ] - -libdfhack.Gui_ReadViewScreen.argtypes = [ c_void_p, c_void_p ] - -libdfhack.Gui_ReadHotkeys.restype = c_void_p - -libdfhack.Gui_getScreenTiles.argtypes = [ c_void_p, c_int, c_int ] -libdfhack.Gui_getScreenTiles.restype = c_void_p - -class Gui(object): - def __init__(self, ptr): - self._gui_ptr = ptr - - def start(self): - return libdfhack.Gui_Start(self._gui_ptr) > 0 - - def finish(self): - return libdfhack.Gui_Finish(self._gui_ptr) > 0 - - def read_view_screen(self): - s = ViewScreen() - - if libdfhack.Gui_ReadViewScreen(self._gui_ptr, byref(s)) > 0: - return s - else: - return None - - def get_view_coords(self): - x, y, z = (0, 0, 0) - - if libdfhack.Gui_getViewCoords(self._gui_ptr, byref(x), byref(y), byref(z)) > 0: - return (x, y, z) - else: - return (-1, -1, -1) - - def set_view_coords(self, x, y, z): - libdfhack.Gui_setViewCoords(self._gui_ptr, x, y, z) - - def get_cursor_coords(self): - x, y, z = (0, 0, 0) - - if libdfhack.Gui_getCursorCoords(self._gui_ptr, byref(x), byref(y), byref(z)) > 0: - return (x, y, z) - else: - return (-1, -1, -1) - - def set_cursor_coords(self, x, y, z): - libdfhack.Gui_setCursorCoords(self._gui_ptr, x, y, z) - - def read_hotkeys(self): - return check_pointer_cache(libdfhack.Gui_ReadHotkeys(self._gui_ptr)) - - def get_screen_tiles(self, width, height): - return check_pointer_cache(libdfhack.Gui_getScreenTiles(self._gui_ptr, width, height)) - - @property - def window_size(self): - width, height = (0, 0) - - if libdfhack.Gui_getWindowSize(self._gui_ptr, byref(width), byref(height)) > 0: - return (width, height) - else: - return (-1, -1) diff --git a/dfhack-python/items.py b/dfhack-python/items.py deleted file mode 100644 index 8c5d6625ef..0000000000 --- a/dfhack-python/items.py +++ /dev/null @@ -1,33 +0,0 @@ -from ctypes import * -from dftypes import * - -libdfhack.Items_getItemDescription.argtypes = [ c_void_p, c_uint, c_void_ptr, _arr_create_func ] -libdfhack.Items_getItemDescription.restype = c_char_p -libdfhack.Items_getItemClass.argtypes = [ c_void_p, c_int, _arr_create_func ] -libdfhack.Item_getItemClass.restype = c_char_p - -class Items(object): - def __init__(self, ptr): - self._i_ptr = ptr - - def get_item_description(self, itemptr, materials): - def get_callback(count): - item_string = create_string_buffer(count) - - return byref(item_string) - - item_string = None - callback = _arr_create_func(get_callback) - - return libdfhack.Items_getItemDescription(self._i_ptr, itemptr, materials, callback) - - def get_item_class(self, index): - def get_callback(count): - item_string = create_string_buffer(count) - - return byref(item_string) - - item_string = None - callback = _arr_create_func(get_callback) - - return libdfhack.Items_getItemClass(self._i_ptr, index, callback) diff --git a/dfhack-python/maps.py b/dfhack-python/maps.py deleted file mode 100644 index 616eda056d..0000000000 --- a/dfhack-python/maps.py +++ /dev/null @@ -1,291 +0,0 @@ -from ctypes import * -from dftypes import * -from util import _uintify, int_ptr, uint_ptr, check_pointer_cache - -_MAX_DIM = 0x300 -_MAX_DIM_SQR = _MAX_DIM * _MAX_DIM - -libdfhack.Maps_getSize.argtypes = [ c_void_p, uint_ptr, uint_ptr, uint_ptr ] -libdfhack.Maps_getPosition.argtypes = [ c_void_p, int_ptr, int_ptr, int_ptr ] - -libdfhack.Maps_ReadTileTypes.argtypes = [ c_void_p, c_uint, c_uint, c_uint, POINTER(TileTypes40d) ] -libdfhack.Maps_WriteTileTypes.argtypes = [ c_void_p, c_uint, c_uint, c_uint, POINTER(TileTypes40d) ] -libdfhack.Maps_ReadDesignations.argtypes = [ c_void_p, c_uint, c_uint, c_uint, POINTER(Designations40d) ] -libdfhack.Maps_WriteDesignations.argtypes = [ c_void_p, c_uint, c_uint, c_uint, POINTER(Designations40d) ] -libdfhack.Maps_ReadTemperatures.argtypes = [ c_void_p, c_uint, c_uint, c_uint, POINTER(Temperatures) ] -libdfhack.Maps_WriteTemperatures.argtypes = [ c_void_p, c_uint, c_uint, c_uint, POINTER(Temperatures) ] -libdfhack.Maps_ReadOccupancy.argtypes = [ c_void_p, c_uint, c_uint, c_uint, POINTER(Occupancies40d) ] -libdfhack.Maps_WriteOccupancy.argtypes = [ c_void_p, c_uint, c_uint, c_uint, POINTER(Occupancies40d) ] -libdfhack.Maps_ReadRegionOffsets.argtypes = [ c_void_p, c_uint, c_uint, c_uint, POINTER(BiomeIndices40d) ] - -libdfhack.Maps_ReadVegetation.restype = c_void_p - -libdfhack.Maps_ReadStandardVeins.argtypes = [ c_void_p, c_uint, c_uint, c_uint ] -libdfhack.Maps_ReadFrozenVeins.argtypes = [ c_void_p, c_uint, c_uint, c_uint ] -libdfhack.Maps_ReadSpatterVeins.argtypes = [ c_void_p, c_uint, c_uint, c_uint ] -libdfhack.Maps_ReadGrassVeins.argtypes = [ c_void_p, c_uint, c_uint, c_uint ] -libdfhack.Maps_ReadWorldConstructions.argtypes = [ c_void_p, c_uint, c_uint, c_uint ] - -libdfhack.Maps_ReadStandardVeins.restype = c_void_p -libdfhack.Maps_ReadFrozenVeins.restype = c_void_p -libdfhack.Maps_ReadSpatterVeins.restype = c_void_p -libdfhack.Maps_ReadGrassVeins.restype = c_void_p -libdfhack.Maps_ReadWorldConstructions.restype = c_void_p - -libdfhack.Maps_ReadLocalFeatures.restype = c_void_p - -class Maps(object): - def __init__(self, ptr): - self._map_ptr = ptr - - def start(self): - return libdfhack.Maps_Start(self._map_ptr) > 0 - - def finish(self): - return libdfhack.Maps_Finish(self._map_ptr) > 0 - - def is_valid_block(self, x, y, z): - return libdfhack.Maps_isValidBlock(self._map_ptr, *_uintify(x, y, z)) > 0 - - def read_tile_types(self, x, y, z): - tt = TileTypes40d() - - ux, uy, uz = _uintify(x, y, z) - - if libdfhack.Maps_ReadTileTypes(self._map_ptr, ux, uy, uz, tt) > 0: - return tt - else: - return None - - def write_tile_types(self, x, y, z, tt): - ux, uy, uz = _uintify(x, y, z) - - return libdfhack.Maps_WriteTileTypes(self._map_ptr, ux, uy, uz, tt) > 0 - - def read_designations(self, x, y, z): - d = Designations40d() - - ux, uy, uz = _uintify(x, y, z) - - if libdfhack.Maps_ReadDesignations(self._map_ptr, ux, uy, uz, byref(d)) > 0: - return d - else: - return None - - def write_designations(self, x, y, z, d): - ux, uy, uz = _uintify(x, y, z) - - return libdfhack.Maps_WriteDesignations(self._map_ptr, ux, uy, uz, byref(d)) > 0 - - def read_temperatures(self, x, y, z): - t = Temperatures() - - ux, uy, uz = _uintify(x, y, z) - - if libdfhack.Maps_ReadDesignations(self._map_ptr, ux, uy, uz, t) > 0: - return t - else: - return None - - def write_temperatures(self, x, y, z, t): - ux, uy, uz = _uintify(x, y, z) - - return libdfhack.Maps_WriteDesignations(self._map_ptr, ux, uy, uz, t) > 0 - - def read_occupancy(self, x, y, z): - o = Occupancies40d() - - ux, uy, uz = _uintify(x, y, z) - - if libdfhack.Maps_ReadDesignations(self._map_ptr, ux, uy, uz, o) > 0: - return o - else: - return None - - def write_occupancy(self, x, y, z, o): - ux, uy, uz = _uintify(x, y, z) - - return libdfhack.Maps_WriteDesignations(self._map_ptr, ux, uy, uz, byref(o)) > 0 - - def read_dirty_bit(self, x, y, z): - bit = c_int(0) - - ux, uy, uz = _uintify(x, y, z) - - if libdfhack.Maps_ReadDirtyBit(self._map_ptr, ux, uy, uz, byref(bit)) > 0: - if bit > 0: - return True - else: - return False - else: - return None - - def write_dirty_bit(self, x, y, z, dirty): - ux, uy, uz = _uintify(x, y, z) - - return libdfhack.Maps_WriteDirtyBit(self._map_ptr, ux, uy, uz, c_int(dirty)) > 0 - - def read_features(self, x, y, z): - lf = c_short() - gf = c_short() - - ux, uy, uz = _uintify(x, y, z) - - libdfhack.Maps_ReadFeatures(self._map_ptr, ux, uy, uz, byref(lf), byref(fg)) - - return (lf, gf) - - def write_local_feature(self, x, y, z, local_feature = -1): - ux, uy, uz = _uintify(x, y, z) - - return libdfhack.Maps_WriteLocalFeature(self._map_ptr, ux, uy, uz, c_short(local_feature)) > 0 - - def write_global_feature(self, x, y, z, global_feature = -1): - ux, uy, uz = _uintify(x, y, z) - - return libdfhack.Maps_WriteGlobalFeature(self._map_ptr, ux, uy, uz, c_short(global_feature)) > 0 - - def read_block_flags(self, x, y, z): - bf = BlockFlags() - - ux, uy, uz = _uintify(x, y, z) - - if libdfhack.Maps_ReadBlockFlags(self._map_ptr, ux, uy, uz, byref(bf)) > 0: - return bf - else: - return None - - def write_block_flags(self, x, y, z, block_flags): - ux, uy, uz = _uintify(x, y, z) - - return libdfhack.Maps_WriteBlockFlags(self._map_ptr, ux, uy, uz, block_flags) > 0 - - def read_region_offsets(self, x, y, z): - bi = BiomeIndices40d() - - ux, uy, uz = _uintify(x, y, z) - - if libdfhack.Maps_ReadRegionOffsets(self._map_ptr, ux, uy, uz, byref(bi)) > 0: - return bi - else: - return None - - def read_veins(self, x, y, z): - ux, uy, uz = _uintify(x, y, z) - - return check_pointer_cache(libdfhack.Maps_ReadStandardVeins(self._map_ptr, ux, uy, uz)) - - def read_frozen_veins(self, x, y, z): - ux, uy, uz = _uintify(x, y, z) - - return check_pointer_cache(libdfhack.Maps_ReadFrozenVeins(self._map_ptr, ux, uy, uz)) - - def read_spatter_veins(self, x, y, z): - ux, uy, uz = _uintify(x, y, z) - - return check_pointer_cache(libdfhack.Maps_ReadSpatterVeins(self._map_ptr, ux, uy, uz)) - - def read_grass_veins(self, x, y, z): - ux, uy, uz = _uintify(x, y, z) - - return check_pointer_cache(libdfhack.Maps_ReadGrassVeins(self._map_ptr, ux, uy, uz)) - - def read_world_constructions(self, x, y, z): - ux, uy, uz = _uintify(x, y, z) - - return check_pointer_cache(libdfhack.Maps_ReadWorldConstructions(self._map_ptr, ux, uy, uz)) - - def read_vegetation(self, x, y, z): - ux, uy, uz = _uintify(x, y, z) - - return check_pointer_cache(libdfhack.Maps_ReadVegetation(self._map_ptr, ux, uy, uz)) - - def read_local_features(self): - f = libdfhack.Maps_ReadLocalFeatures(self._map_ptr) - feature_dict = {} - f_arr = check_pointer_cache(f, False) - - if f_arr is not None: - for node in f_arr: - c = node.coordinate.xyz - coord = MapPoint(c.x, c.y, c.z) - f_list = [node.features[i] for i in xrange(node.feature_length)] - feature_dict[coord] = f_list - - return feature_dict - - @property - def size(self): - x, y, z = (c_uint(0), c_uint(0), c_uint(0)) - - retval = libdfhack.Maps_getSize(self._map_ptr, byref(x), byref(y), byref(z)) - - return (int(x.value), int(y.value), int(z.value)) - - @property - def position(self): - x, y, z = (c_int(0), c_int(0), c_int(0)) - - libdfhack.Maps_getPosition(self._map_ptr, byref(x), byref(y), byref(z)) - - return (int(x.value), int(y.value), int(z.value)) - -class MapPoint(object): - __slots__ = ["_x", "_y", "_z", "_cmp_val"] - - def __init__(self, x = 0, y = 0, z = 0): - self._x, self._y, self._z = x, y, z - - self._cmp_val = self._get_cmp_value() - - def _val_set(self, which, val): - if which == 0: - self._x = val - elif which == 1: - self._y = val - elif which == 2: - self._z = val - - self._cmp_val = self._get_cmp_value() - - x = property(fget = lambda self: self._x, fset = lambda self, v: self._val_set(0, v)) - y = property(fget = lambda self: self._y, fset = lambda self, v: self._val_set(1, v)) - z = property(fget = lambda self: self._z, fset = lambda self, v: self._val_set(2, v)) - - def _get_cmp_value(self): - return (self.z * _MAX_DIM_SQR) + (self.y * _MAX_DIM) + self.x - - #comparison operators - def __eq__(self, other): - return self.x == other.x and self.y == other.y and self.z == other.z - - def __ne__(self, other): - return not self == other - - def __lt__(self, other): - return self._cmp_val < other._cmp_val - - def __le__(self, other): - return self < other or self == other - - def __gt__(self, other): - return self._cmp_val > other._cmp_val - - def __ge__(self, other): - return self > other or self == other - - #arithmetic operators - def __add__(self, num): - return MapPoint(self.x, self.y, self.z + num) - - def __sub__(self, num): - return MapPoint(self.x, self.y, self.z - num) - - def __div__(self, num): - return MapPoint(self.x / num, self.y / num, self.z) - - def __mul__(self, num): - return MapPoint(self.x * num, self.y * num, self.z) - - def __mod__(self, num): - return MapPoint(self.x % num, self.y % num, self.z) \ No newline at end of file diff --git a/dfhack-python/materials.py b/dfhack-python/materials.py deleted file mode 100644 index 37bfcf2ff6..0000000000 --- a/dfhack-python/materials.py +++ /dev/null @@ -1,166 +0,0 @@ -from ctypes import * -import dftypes -from dftypes import libdfhack, Matgloss, CreatureType, DescriptorColor, MatglossOther -from util import check_pointer_cache - -libdfhack.Materials_getInorganic.restype = c_void_p -libdfhack.Materials_getOrganic.restype = c_void_p -libdfhack.Materials_getTree.restype = c_void_p -libdfhack.Materials_getPlant.restype = c_void_p -libdfhack.Materials_getRace.restype = c_void_p -libdfhack.Materials_getRaceEx.restype = c_void_p -libdfhack.Materials_getColor.restype = c_void_p -libdfhack.Materials_getOther.restype = c_void_p -libdfhack.Materials_getAllDesc.restype = c_void_p - -class Materials(object): - def __init__(self, ptr): - self._mat_ptr = ptr - - self.inorganic = None - self.organic = None - self.tree = None - self.plant = None - self.race = None - self.race_ex = None - self.color = None - self.other = None - - def _get_inorganic(self): - self.inorganic = check_pointer_cache(libdfhack.Materials_getInorganic(self._mat_ptr)) - - def _get_organic(self): - self.organic = check_pointer_cache(libdfhack.Materials_getOrganic(self._mat_ptr)) - - def _get_tree(self): - self.tree = check_pointer_cache(libdfhack.Materials_getTree(self._mat_ptr)) - - def _get_plant(self): - self.plant = check_pointer_cache(libdfhack.Materials_getPlant(self._mat_ptr)) - - def _get_race(self): - self.race = check_pointer_cache(libdfhack.Materials_getRace(self._mat_ptr)) - - def _get_race_ex(self): - self.race_ex = check_pointer_cache(libdfhack.Materials_getRaceEx(self._mat_ptr)) - - def _get_color(self): - self.color = check_pointer_cache(libdfhack.Materials_getColor(self._mat_ptr)) - - def _get_other(self): - self.other = check_pointer_cache(libdfhack.Materials_getOther(self._mat_ptr)) - - def _get_all(self): - self._get_inorganic() - self._get_organic() - self._get_tree() - self._get_plant() - self._get_race() - self._get_race_ex() - self._get_color() - self._get_other() - def _clear_all(self): - self.inorganic = None - self.organic = None - self.tree = None - self.plant = None - self.race = None - self.race_ex = None - self.color = None - self.other = None - - def read_inorganic(self): - result = libdfhack.Materials_ReadInorganicMaterials(self._mat_ptr) > 0 - - if result == True: - self._get_inorganic() - else: - self.inorganic = None - - return result - - def read_organic(self): - result = libdfhack.Materials_ReadOrganicMaterials(self._mat_ptr) > 0 - - if result == True: - self._get_organic() - else: - self.organic = None - - return result - - def read_tree(self): - result = libdfhack.Materials_ReadWoodMaterials(self._mat_ptr) > 0 - - if result == True: - self._get_tree() - else: - self.tree = None - - return result - - def read_plant(self): - result = libdfhack.Materials_ReadPlantMaterials(self._mat_ptr) > 0 - - if result == True: - self._get_plant() - else: - self.plant = None - - return result - - def read_creature_types(self): - result = libdfhack.Materials_ReadCreatureTypes(self._mat_ptr) > 0 - - if result == True: - self._get_race() - else: - self.race = None - - return result - - def read_creature_types_ex(self): - result = libdfhack.Materials_ReadCreatureTypesEx(self._mat_ptr) > 0 - - if result == True: - self._get_race_ex() - else: - self.race_ex = None - - return result - - def read_descriptor_colors(self): - result = libdfhack.Materials_ReadDescriptorColors(self._mat_ptr) > 0 - - if result == True: - self._get_color() - else: - self.color = None - - return result - - def read_others(self): - result = libdfhack.Materials_ReadOthers(self._mat_ptr) > 0 - - if result == True: - self._get_other() - else: - self.other = None - - return result - - def read_all(self): - result = libdfhack.Materials_ReadAllMaterials(self._mat_ptr) > 0 - - if result == True: - self._get_all() - else: - self._clear_all() - - return result - - def get_type(self, material): - return libdfhack.Materials_getType(self._mat_ptr, byref(material)) - - def get_description(self, material): - return libdfhack.Materials_getDescription(self._mat_ptr, byref(material)) \ No newline at end of file diff --git a/dfhack-python/process.py b/dfhack-python/process.py deleted file mode 100644 index b9ac200b6c..0000000000 --- a/dfhack-python/process.py +++ /dev/null @@ -1,135 +0,0 @@ -from ctypes import * -from dftypes import libdfhack -from util import check_pointer_cache - -libdfhack.Process_readQuad.argtypes = [ c_void_p, c_uint, POINTER(c_ulong) ] -libdfhack.Process_writeQuad.argtypes = [ c_void_p, c_uint, c_ulong ] - -libdfhack.Process_readDWord.argtypes = [ c_void_p, c_uint, POINTER(c_uint) ] -libdfhack.Process_writeDWord.argtypes = [ c_void_p, c_uint, c_uint ] - -libdfhack.Process_readWord.argtypes = [ c_void_p, c_uint, POINTER(c_ushort) ] -libdfhack.Process_writeWord.argtypes = [ c_void_p, c_uint, c_ushort ] - -libdfhack.Process_readByte.argtypes = [ c_void_p, c_uint, POINTER(c_ubyte) ] -libdfhack.Process_writeByte.argtypes = [ c_void_p, c_uint, c_ubyte ] - -libdfhack.Process_readFloat.argtypes = [ c_void_p, c_uint, POINTER(c_float) ] - -libdfhack.Process_read.argtypes = [ c_void_p, c_uint, c_uint ] -libdfhack.Process_read.restype = c_void_p - -libdfhack.Process_write.argtypes = [ c_void_p, c_uint, c_uint, POINTER(c_ubyte) ] - -libdfhack.Process_getThreadIDs.restype = c_void_p - -class Process(object): - def __init__(self, ptr): - self._p_ptr = ptr - - def attach(self): - return libdfhack.Process_attach(self._p_ptr) > 0 - - def detach(self): - return libdfhack.Process_detach(self._p_ptr) > 0 - - def suspend(self): - return libdfhack.Process_suspend(self._p_ptr) > 0 - - def async_suspend(self): - return libdfhack.Process_asyncSuspend(self._p_ptr) > 0 - - def resume(self): - return libdfhack.Process_resume(self._p_ptr) > 0 - - def force_resume(self): - return libdfhack.Process_forceresume(self._p_ptr) > 0 - - def read_quad(self, address): - q = c_ulong(0) - - if libdfhack.Process_readQuad(self._p_ptr, address, byref(q)) > 0: - return long(q.value) - else: - return -1 - - def write_quad(self, address, value): - return libdfhack.Process_writeQuad(self._p_ptr, address, value) > 0 - - def read_dword(self, address): - d = c_uint(0) - - if libdfhack.Process_readDWord(self._p_ptr, address, byref(d)) > 0: - return int(d.value) - else: - return -1 - - def write_dword(self, address, value): - return libdfhack.Process_writeDWord(self._p_ptr, address, value) > 0 - - def read_word(self, address): - s = c_ushort(0) - - if libdfhack.Process_readWord(self._p_ptr, address, byref(s)) > 0: - return int(s.value) - else: - return -1 - - def write_word(self, address, value): - return libdfhack.Process_writeWord(self._p_ptr, address, value) > 0 - - def read_byte(self, address): - b = c_ubyte(0) - - if libdfhack.Process_readByte(self._p_ptr, address, byref(b)) > 0: - return int(b.value) - else: - return -1 - - def write_byte(self, address, value): - return libdfhack.Process_writeByte(self._p_ptr, address, value) > 0 - - def read_float(self, address): - f = c_float(0) - - if libdfhack.Process_readFloat(self._p_ptr, address, byref(f)) > 0: - return float(f.value) - else: - return -1 - - def read(self, address, length): - return check_pointer_cache(libdfhack.Process_read(self._p_ptr, address, length)) - - def write(self, address, length, buffer): - libdfhack.Process_write(self._p_ptr, address, length, byref(buffer)) - - def get_thread_ids(self): - return check_pointer_cache(libdfhack.Process_getThreadIDs(self._p_ptr)) - - def set_and_wait(self, state): - return libdfhack.Process_SetAndWait(self._p_ptr, state) > 0 - - @property - def is_suspended(self): - return libdfhack.Process_isSuspended(self._p_ptr) > 0 - - @property - def is_attached(self): - return libdfhack.Process_isAttached(self._p_ptr) > 0 - - @property - def is_identified(self): - return libdfhack.Process_isIdentified(self._p_ptr) > 0 - - @property - def is_snapshot(self): - return libdfhack.Process_isSnapshot(self._p_ptr) > 0 - - @property - def pid(self): - p = c_int(0) - - if libdfhack.Process_getPID(self._p_ptr, byref(p)) > 0: - return int(p.value) - else: - return -1 \ No newline at end of file diff --git a/dfhack-python/util.py b/dfhack-python/util.py deleted file mode 100644 index 40fd990a1c..0000000000 --- a/dfhack-python/util.py +++ /dev/null @@ -1,88 +0,0 @@ -from ctypes import * - -int_ptr = POINTER(c_int) -uint_ptr = POINTER(c_uint) - -short_ptr = POINTER(c_short) -ushort_ptr = POINTER(c_ushort) - -byte_ptr = POINTER(c_byte) -ubyte_ptr = POINTER(c_ubyte) - -pointer_dict = {} - -def check_pointer_cache(address, return_as_list = True): - arr = None - - if address in pointer_dict: - arr = pointer_dict[address][1] - del pointer_dict[address] - - if return_as_list == True: - arr = [i for i in arr] - - return arr - -def _uintify(x, y, z): - return (c_uint(x), c_uint(y), c_uint(z)) - -def _allocate_array(ptr, t_type, count): - arr = (t_type * count)() - - p = cast(arr, POINTER(t_type)) - - ptr[0] = p - - pointer_dict[addressof(arr)] = (ptr, arr, p) - - return 1 - -def _alloc_int_buffer(ptr, count): - return _allocate_array(ptr, c_int, count) - -_int_functype = CFUNCTYPE(c_int, POINTER(POINTER(c_int)), c_uint) -alloc_int_buffer = _int_functype(_alloc_int_buffer) - -def _alloc_uint_buffer(ptr, count): - return _allocate_array(ptr, c_uint, count) - -_uint_functype = CFUNCTYPE(c_int, POINTER(POINTER(c_uint)), c_uint) -alloc_uint_buffer = _uint_functype(_alloc_uint_buffer) - -def _alloc_short_buffer(ptr, count): - return _allocate_array(ptr, c_short, count) - -_short_functype = CFUNCTYPE(c_int, POINTER(POINTER(c_short)), c_uint) -alloc_short_buffer = _short_functype(_alloc_short_buffer) - -def _alloc_ushort_buffer(ptr, count): - return _allocate_array(ptr, c_ushort, count) - -_ushort_functype = CFUNCTYPE(c_int, POINTER(POINTER(c_ushort)), c_uint) -alloc_ushort_buffer = _ushort_functype(_alloc_ushort_buffer) - -def _alloc_byte_buffer(ptr, count): - return _allocate_array(ptr, c_byte, count) - -_byte_functype = CFUNCTYPE(c_int, POINTER(POINTER(c_byte)), c_uint) -alloc_byte_buffer = _byte_functype(_alloc_byte_buffer) - -def _alloc_ubyte_buffer(ptr, count): - return _allocate_array(ptr, c_ubyte, count) - -_ubyte_functype = CFUNCTYPE(c_int, POINTER(POINTER(c_ubyte)), c_uint) -alloc_ubyte_buffer = _ubyte_functype(_alloc_ubyte_buffer) - -def _alloc_char_buffer(ptr, count): - c = create_string_buffer(count) - - p = cast(c, POINTER(c_char)) - - ptr[0] = p - - pointer_dict[id(ptr[0])] = (ptr, c, p) - - return 1 - -_char_functype = CFUNCTYPE(c_int, POINTER(POINTER(c_char)), c_uint) -alloc_char_buffer = _char_functype(_alloc_char_buffer) diff --git a/dfhack-python/vegetation.py b/dfhack-python/vegetation.py deleted file mode 100644 index ca1f12bd6b..0000000000 --- a/dfhack-python/vegetation.py +++ /dev/null @@ -1,25 +0,0 @@ -from ctypes import * -from dftypes import libdfhack, Tree - -class Vegetation(object): - def __init__(self, ptr): - self._v_ptr = ptr - - def start(self): - n = c_uint(0) - - if libdfhack.Vegetation_Start(self._v_ptr, byref(n)) > 0: - return int(n.value) - else: - return -1 - - def finish(self): - return libdfhack.Vegetation_Finish(self._v_ptr) > 0 - - def read(self, index): - t = Tree() - - if libdfhack.Vegetation_Read(self._v_ptr, c_uint(index), byref(t)) > 0: - return t - else: - return None diff --git a/dfhack-python/window_io.py b/dfhack-python/window_io.py deleted file mode 100644 index 0e29b86fc2..0000000000 --- a/dfhack-python/window_io.py +++ /dev/null @@ -1,26 +0,0 @@ -from ctypes import * -from dftypes import libdfhack - -libdfhack.WindowIO_TypeStr.argtypes = [ c_void_p, c_char_p, c_uint, c_byte ] -libdfhack.WindowIO_TypeSpecial.argtypes = [ c_void_p, c_uint, c_uint, c_uint, c_uint ] - -class WindowIO(object): - def __init__(self, ptr): - self._window_io_ptr = ptr - - def type_str(self, s, delay = 0, use_shift = False): - c_shift = c_byte(0) - c_delay = c_uint(delay) - c_s = c_char_p(s) - - if use_shift is True: - c_shift = c_byte(1) - - return libdfhack.WindowIO_TypeStr(self._window_io_ptr, c_s, c_delay, c_shift) > 0 - - def type_special(self, command, count = 1, delay = 0): - c_command = c_uint(command) - c_count = c_uint(count) - c_delay = c_uint(delay) - - return libdfhack.WindowIO_TypeSpecial(self._window_io_ptr, c_command, c_count, c_delay) > 0 \ No newline at end of file diff --git a/dfhack-python/world.py b/dfhack-python/world.py deleted file mode 100644 index 5a6e798b0a..0000000000 --- a/dfhack-python/world.py +++ /dev/null @@ -1,80 +0,0 @@ -from ctypes import * -from dftypes import libdfhack, GameModes -from util import _uintify, uint_ptr - -libdfhack.World_ReadGameMode.argtypes = [ c_void_p, POINTER(GameModes) ] - -class World(object): - def __init__(self, ptr): - self._world_ptr = ptr - - def start(self): - return libdfhack.World_Start(self._world_ptr) > 0 - - def finish(self): - return libdfhack.World_Finish(self._world_ptr) > 0 - - def read_pause_state(self): - return libdfhack.World_ReadPauseState(self._world_ptr) > 0 - - def set_pause_state(self, pause_state): - p = c_byte(0) - - if pause_state is not None and pause_state is not False: - p.value = 1 - - return libdfhack.World_SetPauseState(self._world_ptr, p) > 0 - - def read_current_tick(self): - tick = c_uint(0) - - if libdfhack.World_ReadCurrentTick(self._world_ptr, byref(tick)) > 0: - return int(tick) - else: - return -1 - - def read_current_year(self): - year = c_uint(0) - - if libdfhack.World_ReadCurrentYear(self._world_ptr, byref(year)) > 0: - return int(year) - else: - return -1 - - def read_current_month(self): - month = c_uint(0) - - if libdfhack.World_ReadCurrentMonth(self._world_ptr, byref(month)) > 0: - return int(month) - else: - return -1 - - def read_current_day(self): - day = c_uint(0) - - if libdfhack.World_ReadCurrentDay(self._world_ptr, byref(day)) > 0: - return int(day) - else: - return -1 - - def read_current_weather(self): - weather = c_ubyte(0) - - if libdfhack.World_ReadCurrentWeather(self._world_ptr, byref(weather)) > 0: - return int(weather) - else: - return -1 - - def write_current_weather(self, weather): - return libdfhack.World_WriteCurrentWeather(self._world_ptr, c_ubyte(weather)) - - def read_game_mode(self): - game_modes = GameModes() - - if libdfhack.World_ReadGameMode(self._world_ptr, byref(game_modes)) > 0: - return game_modes - else: - return None - - def write_game_mode(self, game_mode): - return libdfhack.World_WriteGameMode(self._world_ptr, game_modes) > 0 \ No newline at end of file diff --git a/dfhack.kdev4 b/dfhack.kdev4 deleted file mode 100644 index 771cc037c0..0000000000 --- a/dfhack.kdev4 +++ /dev/null @@ -1,3 +0,0 @@ -[Project] -Manager=KDevCMakeManager -Name=dfhack diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt deleted file mode 100644 index aad02a2038..0000000000 --- a/doc/CMakeLists.txt +++ /dev/null @@ -1,60 +0,0 @@ -# repurposed from libnoise: http://github.com/qknight/libnoise/tree/master/doc/ -# following code and comments is by the original author, with some changes by -# me (peterix) -# ------------------------------------------------------------------------------ -# -# many thanks go to Philippe Poilbarbe for writing the code this file is based on -# http://www.cmake.org/pipermail/cmake/2006-August/010794.html -# -# much later i also found this: -# http://tobias.rautenkranz.ch/cmake/doxygen/ -# but it is hard to understand... - -FIND_PACKAGE(Doxygen QUIET) - -IF(DOXYGEN_FOUND) - SET(DOXYGEN_LANGUAGE "English" CACHE STRING "Language used by doxygen") - MARK_AS_ADVANCED(DOXYGEN_LANGUAGE) - - # you could also set the version with this, see Doxygen.in - # there you will find a line like this: - # PROJECT_NUMBER = @DFHACK_VERSION@ - # @DFHACK_VERSION@ is then replaced by our global DFHACK_VERSION - # - # for instance you could uncomment the next 3 lines and change the version for testing - # SET(DFHACK_VERSION - # "1.2.3-foo500" - # ) - - # doxygen can reference external images with IMAGE_PATH, this is how we set it dynamically - SET( CMAKE_DOXYGEN_IMAGE_PATH - "${CMAKE_CURRENT_SOURCE_DIR}/img" - ) - - # doxygen searches for source code (defined in FILE_PATTERNS, for example: *.cpp *.h) - # with DOXYGEN_SOURCE_DIR we fill a list of directories and later we write it into - # the Doxyfile with a REGEX REPLACE (see below) - SET( DOXYGEN_SOURCE_DIR - "${dfhack_SOURCE_DIR}/doc/index.dxgen" - "${dfhack_SOURCE_DIR}/library/include" - "${dfhack_SOURCE_DIR}/library/include/dfhack" - "${dfhack_SOURCE_DIR}/library/include/dfhack/modules" - "${dfhack_SOURCE_DIR}/library/include/dfhack-c" - "${dfhack_SOURCE_DIR}/library/include/dfhack-c/modules" - ) - - STRING(REGEX REPLACE ";" " " CMAKE_DOXYGEN_INPUT_LIST "${DOXYGEN_SOURCE_DIR}") - set(DOXYFILE_DOT "NO") - if(DOXYGEN_DOT_EXECUTABLE) - set(DOXYFILE_DOT "YES") - endif() - CONFIGURE_FILE(Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) - ADD_CUSTOM_TARGET(doxygen ALL - ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile - DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) - - INSTALL( DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/html/" DESTINATION ${DFHACK_DOXYGEN_DESTINATION} ) - INSTALL( FILES "Doxygen.html" DESTINATION ${DFHACK_DEVDOC_DESTINATION}) -ELSE(DOXYGEN_FOUND) - MESSAGE (WARNING "Doxygen binary couldn't be found. Can't build development documentation.'") -ENDIF(DOXYGEN_FOUND) \ No newline at end of file diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in deleted file mode 100644 index a08f3f3551..0000000000 --- a/doc/Doxyfile.in +++ /dev/null @@ -1,1554 +0,0 @@ -# Doxyfile 1.6.3 - -# This file describes the settings to be used by the documentation system -# doxygen (www.doxygen.org) for a project -# -# All text after a hash (#) is considered a comment and will be ignored -# The format is: -# TAG = value [value, ...] -# For lists items can also be appended using: -# TAG += value [value, ...] -# Values that contain spaces should be placed between quotes (" ") - -#--------------------------------------------------------------------------- -# Project related configuration options -#--------------------------------------------------------------------------- - -# This tag specifies the encoding used for all characters in the config file -# that follow. The default is UTF-8 which is also the encoding used for all -# text before the first occurrence of this tag. Doxygen uses libiconv (or the -# iconv built into libc) for the transcoding. See -# http://www.gnu.org/software/libiconv for the list of possible encodings. - -DOXYFILE_ENCODING = UTF-8 - -# The PROJECT_NAME tag is a single word (or a sequence of words surrounded -# by quotes) that should identify the project. - -PROJECT_NAME = dfhack - -# The PROJECT_NUMBER tag can be used to enter a project or revision number. -# This could be handy for archiving the generated documentation or -# if some version control system is used. - -PROJECT_NUMBER = "@DFHACK_VERSION@" - -# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) -# base path where the generated documentation will be put. -# If a relative path is entered, it will be relative to the location -# where doxygen was started. If left blank the current directory will be used. - -OUTPUT_DIRECTORY = html -# @DOXYGEN_OUTPUT_DIR@ - -# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create -# 4096 sub-directories (in 2 levels) under the output directory of each output -# format and will distribute the generated files over these directories. -# Enabling this option can be useful when feeding doxygen a huge amount of -# source files, where putting all generated files in the same directory would -# otherwise cause performance problems for the file system. - -CREATE_SUBDIRS = NO - -# The OUTPUT_LANGUAGE tag is used to specify the language in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all constant output in the proper language. -# The default language is English, other supported languages are: -# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, -# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, -# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English -# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, -# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, -# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. - -OUTPUT_LANGUAGE = @DOXYGEN_LANGUAGE@ - -# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will -# include brief member descriptions after the members that are listed in -# the file and class documentation (similar to JavaDoc). -# Set to NO to disable this. - -BRIEF_MEMBER_DESC = YES - -# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend -# the brief description of a member or function before the detailed description. -# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the -# brief descriptions will be completely suppressed. - -REPEAT_BRIEF = YES - -# This tag implements a quasi-intelligent brief description abbreviator -# that is used to form the text in various listings. Each string -# in this list, if found as the leading text of the brief description, will be -# stripped from the text and the result after processing the whole list, is -# used as the annotated text. Otherwise, the brief description is used as-is. -# If left blank, the following values are used ("$name" is automatically -# replaced with the name of the entity): "The $name class" "The $name widget" -# "The $name file" "is" "provides" "specifies" "contains" -# "represents" "a" "an" "the" - -ABBREVIATE_BRIEF = - -# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# Doxygen will generate a detailed section even if there is only a brief -# description. - -ALWAYS_DETAILED_SEC = NO - -# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all -# inherited members of a class in the documentation of that class as if those -# members were ordinary class members. Constructors, destructors and assignment -# operators of the base classes will not be shown. - -INLINE_INHERITED_MEMB = NO - -# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full -# path before files name in the file list and in the header files. If set -# to NO the shortest path that makes the file name unique will be used. - -FULL_PATH_NAMES = NO - -# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag -# can be used to strip a user-defined part of the path. Stripping is -# only done if one of the specified strings matches the left-hand part of -# the path. The tag can be used to show relative paths in the file list. -# If left blank the directory from which doxygen is run is used as the -# path to strip. - -STRIP_FROM_PATH = - -# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of -# the path mentioned in the documentation of a class, which tells -# the reader which header file to include in order to use a class. -# If left blank only the name of the header file containing the class -# definition is used. Otherwise one should specify the include paths that -# are normally passed to the compiler using the -I flag. - -STRIP_FROM_INC_PATH = - -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter -# (but less readable) file names. This can be useful is your file systems -# doesn't support long names like on DOS, Mac, or CD-ROM. - -SHORT_NAMES = NO - -# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen -# will interpret the first line (until the first dot) of a JavaDoc-style -# comment as the brief description. If set to NO, the JavaDoc -# comments will behave just like regular Qt-style comments -# (thus requiring an explicit @brief command for a brief description.) - -JAVADOC_AUTOBRIEF = YES - -# If the QT_AUTOBRIEF tag is set to YES then Doxygen will -# interpret the first line (until the first dot) of a Qt-style -# comment as the brief description. If set to NO, the comments -# will behave just like regular Qt-style comments (thus requiring -# an explicit \brief command for a brief description.) - -QT_AUTOBRIEF = NO - -# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen -# treat a multi-line C++ special comment block (i.e. a block of //! or /// -# comments) as a brief description. This used to be the default behaviour. -# The new default is to treat a multi-line C++ comment block as a detailed -# description. Set this tag to YES if you prefer the old behaviour instead. - -MULTILINE_CPP_IS_BRIEF = NO - -# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented -# member inherits the documentation from any documented member that it -# re-implements. - -INHERIT_DOCS = YES - -# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce -# a new page for each member. If set to NO, the documentation of a member will -# be part of the file/class/namespace that contains it. - -SEPARATE_MEMBER_PAGES = NO - -# The TAB_SIZE tag can be used to set the number of spaces in a tab. -# Doxygen uses this value to replace tabs by spaces in code fragments. - -TAB_SIZE = 4 - -# This tag can be used to specify a number of aliases that acts -# as commands in the documentation. An alias has the form "name=value". -# For example adding "sideeffect=\par Side Effects:\n" will allow you to -# put the command \sideeffect (or @sideeffect) in the documentation, which -# will result in a user-defined paragraph with heading "Side Effects:". -# You can put \n's in the value part of an alias to insert newlines. - -ALIASES = - -# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C -# sources only. Doxygen will then generate output that is more tailored for C. -# For instance, some of the names that are used will be different. The list -# of all members will be omitted, etc. - -OPTIMIZE_OUTPUT_FOR_C = NO - -# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java -# sources only. Doxygen will then generate output that is more tailored for -# Java. For instance, namespaces will be presented as packages, qualified -# scopes will look different, etc. - -OPTIMIZE_OUTPUT_JAVA = NO - -# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran -# sources only. Doxygen will then generate output that is more tailored for -# Fortran. - -OPTIMIZE_FOR_FORTRAN = NO - -# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL -# sources. Doxygen will then generate output that is tailored for -# VHDL. - -OPTIMIZE_OUTPUT_VHDL = NO - -# Doxygen selects the parser to use depending on the extension of the files it parses. -# With this tag you can assign which parser to use for a given extension. -# Doxygen has a built-in mapping, but you can override or extend it using this tag. -# The format is ext=language, where ext is a file extension, and language is one of -# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP, -# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat -# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran), -# use: inc=Fortran f=C. Note that for custom extensions you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. - -EXTENSION_MAPPING = - -# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want -# to include (a tag file for) the STL sources as input, then you should -# set this tag to YES in order to let doxygen match functions declarations and -# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. -# func(std::string) {}). This also make the inheritance and collaboration -# diagrams that involve STL classes more complete and accurate. - -BUILTIN_STL_SUPPORT = YES - -# If you use Microsoft's C++/CLI language, you should set this option to YES to -# enable parsing support. - -CPP_CLI_SUPPORT = NO - -# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. -# Doxygen will parse them like normal C++ but will assume all classes use public -# instead of private inheritance when no explicit protection keyword is present. - -SIP_SUPPORT = NO - -# For Microsoft's IDL there are propget and propput attributes to indicate getter -# and setter methods for a property. Setting this option to YES (the default) -# will make doxygen to replace the get and set methods by a property in the -# documentation. This will only work if the methods are indeed getting or -# setting a simple type. If this is not the case, or you want to show the -# methods anyway, you should set this option to NO. - -IDL_PROPERTY_SUPPORT = YES - -# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first -# member in the group (if any) for the other members of the group. By default -# all members of a group must be documented explicitly. - -DISTRIBUTE_GROUP_DOC = NO - -# Set the SUBGROUPING tag to YES (the default) to allow class member groups of -# the same type (for instance a group of public functions) to be put as a -# subgroup of that type (e.g. under the Public Functions section). Set it to -# NO to prevent subgrouping. Alternatively, this can be done per class using -# the \nosubgrouping command. - -SUBGROUPING = YES - -# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum -# is documented as struct, union, or enum with the name of the typedef. So -# typedef struct TypeS {} TypeT, will appear in the documentation as a struct -# with name TypeT. When disabled the typedef will appear as a member of a file, -# namespace, or class. And the struct will be named TypeS. This can typically -# be useful for C code in case the coding convention dictates that all compound -# types are typedef'ed and only the typedef is referenced, never the tag name. - -TYPEDEF_HIDES_STRUCT = NO - -# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to -# determine which symbols to keep in memory and which to flush to disk. -# When the cache is full, less often used symbols will be written to disk. -# For small to medium size projects (<1000 input files) the default value is -# probably good enough. For larger projects a too small cache size can cause -# doxygen to be busy swapping symbols to and from disk most of the time -# causing a significant performance penality. -# If the system has enough physical memory increasing the cache will improve the -# performance by keeping more symbols in memory. Note that the value works on -# a logarithmic scale so increasing the size by one will rougly double the -# memory usage. The cache size is given by this formula: -# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, -# corresponding to a cache size of 2^16 = 65536 symbols - -SYMBOL_CACHE_SIZE = 0 - -#--------------------------------------------------------------------------- -# Build related configuration options -#--------------------------------------------------------------------------- - -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in -# documentation are documented, even if no documentation was available. -# Private class members and static file members will be hidden unless -# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES - -EXTRACT_ALL = YES - -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class -# will be included in the documentation. - -EXTRACT_PRIVATE = NO - -# If the EXTRACT_STATIC tag is set to YES all static members of a file -# will be included in the documentation. - -EXTRACT_STATIC = NO - -# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) -# defined locally in source files will be included in the documentation. -# If set to NO only classes defined in header files are included. - -EXTRACT_LOCAL_CLASSES = NO - -# This flag is only useful for Objective-C code. When set to YES local -# methods, which are defined in the implementation section but not in -# the interface are included in the documentation. -# If set to NO (the default) only methods in the interface are included. - -EXTRACT_LOCAL_METHODS = NO - -# If this flag is set to YES, the members of anonymous namespaces will be -# extracted and appear in the documentation as a namespace called -# 'anonymous_namespace{file}', where file will be replaced with the base -# name of the file that contains the anonymous namespace. By default -# anonymous namespace are hidden. - -EXTRACT_ANON_NSPACES = NO - -# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all -# undocumented members of documented classes, files or namespaces. -# If set to NO (the default) these members will be included in the -# various overviews, but no documentation section is generated. -# This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_MEMBERS = NO - -# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all -# undocumented classes that are normally visible in the class hierarchy. -# If set to NO (the default) these classes will be included in the various -# overviews. This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_CLASSES = NO - -# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all -# friend (class|struct|union) declarations. -# If set to NO (the default) these declarations will be included in the -# documentation. - -HIDE_FRIEND_COMPOUNDS = NO - -# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any -# documentation blocks found inside the body of a function. -# If set to NO (the default) these blocks will be appended to the -# function's detailed documentation block. - -HIDE_IN_BODY_DOCS = NO - -# The INTERNAL_DOCS tag determines if documentation -# that is typed after a \internal command is included. If the tag is set -# to NO (the default) then the documentation will be excluded. -# Set it to YES to include the internal documentation. - -INTERNAL_DOCS = NO - -# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate -# file names in lower-case letters. If set to YES upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows -# and Mac users are advised to set this option to NO. - -CASE_SENSE_NAMES = YES - -# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen -# will show members with their full class and namespace scopes in the -# documentation. If set to YES the scope will be hidden. - -HIDE_SCOPE_NAMES = NO - -# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen -# will put a list of the files that are included by a file in the documentation -# of that file. - -SHOW_INCLUDE_FILES = YES - -# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen -# will list include files with double quotes in the documentation -# rather than with sharp brackets. - -FORCE_LOCAL_INCLUDES = NO - -# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] -# is inserted in the documentation for inline members. - -INLINE_INFO = YES - -# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen -# will sort the (detailed) documentation of file and class members -# alphabetically by member name. If set to NO the members will appear in -# declaration order. - -SORT_MEMBER_DOCS = YES - -# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the -# brief documentation of file, namespace and class members alphabetically -# by member name. If set to NO (the default) the members will appear in -# declaration order. - -SORT_BRIEF_DOCS = NO - -# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the (brief and detailed) documentation of class members so that constructors and destructors are listed first. If set to NO (the default) the constructors will appear in the respective orders defined by SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. - -SORT_MEMBERS_CTORS_1ST = NO - -# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the -# hierarchy of group names into alphabetical order. If set to NO (the default) -# the group names will appear in their defined order. - -SORT_GROUP_NAMES = NO - -# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be -# sorted by fully-qualified names, including namespaces. If set to -# NO (the default), the class list will be sorted only by class name, -# not including the namespace part. -# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. -# Note: This option applies only to the class list, not to the -# alphabetical list. - -SORT_BY_SCOPE_NAME = NO - -# The GENERATE_TODOLIST tag can be used to enable (YES) or -# disable (NO) the todo list. This list is created by putting \todo -# commands in the documentation. - -GENERATE_TODOLIST = YES - -# The GENERATE_TESTLIST tag can be used to enable (YES) or -# disable (NO) the test list. This list is created by putting \test -# commands in the documentation. - -GENERATE_TESTLIST = YES - -# The GENERATE_BUGLIST tag can be used to enable (YES) or -# disable (NO) the bug list. This list is created by putting \bug -# commands in the documentation. - -GENERATE_BUGLIST = YES - -# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or -# disable (NO) the deprecated list. This list is created by putting -# \deprecated commands in the documentation. - -GENERATE_DEPRECATEDLIST= YES - -# The ENABLED_SECTIONS tag can be used to enable conditional -# documentation sections, marked by \if sectionname ... \endif. - -ENABLED_SECTIONS = - -# The MAX_INITIALIZER_LINES tag determines the maximum number of lines -# the initial value of a variable or define consists of for it to appear in -# the documentation. If the initializer consists of more lines than specified -# here it will be hidden. Use a value of 0 to hide initializers completely. -# The appearance of the initializer of individual variables and defines in the -# documentation can be controlled using \showinitializer or \hideinitializer -# command in the documentation regardless of this setting. - -MAX_INITIALIZER_LINES = 30 - -# Set the SHOW_USED_FILES tag to NO to disable the list of files generated -# at the bottom of the documentation of classes and structs. If set to YES the -# list will mention the files that were used to generate the documentation. - -SHOW_USED_FILES = YES - -# If the sources in your project are distributed over multiple directories -# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy -# in the documentation. The default is NO. - -SHOW_DIRECTORIES = YES - -# Set the SHOW_FILES tag to NO to disable the generation of the Files page. -# This will remove the Files entry from the Quick Index and from the -# Folder Tree View (if specified). The default is YES. - -SHOW_FILES = YES - -# Set the SHOW_NAMESPACES tag to NO to disable the generation of the -# Namespaces page. -# This will remove the Namespaces entry from the Quick Index -# and from the Folder Tree View (if specified). The default is YES. - -SHOW_NAMESPACES = YES - -# The FILE_VERSION_FILTER tag can be used to specify a program or script that -# doxygen should invoke to get the current version for each file (typically from -# the version control system). Doxygen will invoke the program by executing (via -# popen()) the command , where is the value of -# the FILE_VERSION_FILTER tag, and is the name of an input file -# provided by doxygen. Whatever the program writes to standard output -# is used as the file version. See the manual for examples. - -FILE_VERSION_FILTER = - -# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by -# doxygen. The layout file controls the global structure of the generated output files -# in an output format independent way. The create the layout file that represents -# doxygen's defaults, run doxygen with the -l option. You can optionally specify a -# file name after the option, if omitted DoxygenLayout.xml will be used as the name -# of the layout file. - -LAYOUT_FILE = - -#--------------------------------------------------------------------------- -# configuration options related to warning and progress messages -#--------------------------------------------------------------------------- - -# The QUIET tag can be used to turn on/off the messages that are generated -# by doxygen. Possible values are YES and NO. If left blank NO is used. - -QUIET = YES - -# The WARNINGS tag can be used to turn on/off the warning messages that are -# generated by doxygen. Possible values are YES and NO. If left blank -# NO is used. - -WARNINGS = YES - -# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings -# for undocumented members. If EXTRACT_ALL is set to YES then this flag will -# automatically be disabled. - -WARN_IF_UNDOCUMENTED = YES - -# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some -# parameters in a documented function, or documenting parameters that -# don't exist or using markup commands wrongly. - -WARN_IF_DOC_ERROR = YES - -# This WARN_NO_PARAMDOC option can be abled to get warnings for -# functions that are documented, but have no documentation for their parameters -# or return value. If set to NO (the default) doxygen will only warn about -# wrong or incomplete parameter documentation, but not about the absence of -# documentation. - -WARN_NO_PARAMDOC = NO - -# The WARN_FORMAT tag determines the format of the warning messages that -# doxygen can produce. The string should contain the $file, $line, and $text -# tags, which will be replaced by the file and line number from which the -# warning originated and the warning text. Optionally the format may contain -# $version, which will be replaced by the version of the file (if it could -# be obtained via FILE_VERSION_FILTER) - -WARN_FORMAT = "$file:$line: $text" - -# The WARN_LOGFILE tag can be used to specify a file to which warning -# and error messages should be written. If left blank the output is written -# to stderr. - -WARN_LOGFILE = - -#--------------------------------------------------------------------------- -# configuration options related to the input files -#--------------------------------------------------------------------------- - -# The INPUT tag can be used to specify the files and/or directories that contain -# documented source files. You may enter file names like "myfile.cpp" or -# directories like "/usr/src/myproject". Separate the files or directories -# with spaces. - -INPUT = @CMAKE_DOXYGEN_INPUT_LIST@ - -# This tag can be used to specify the character encoding of the source files -# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is -# also the default input encoding. Doxygen uses libiconv (or the iconv built -# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for -# the list of possible encodings. - -INPUT_ENCODING = UTF-8 - -# If the value of the INPUT tag contains directories, you can use the -# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank the following patterns are tested: -# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx -# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 - -FILE_PATTERNS = *.cpp \ - *.h \ - *.dxgen - -# The RECURSIVE tag can be used to turn specify whether or not subdirectories -# should be searched for input files as well. Possible values are YES and NO. -# If left blank NO is used. - -RECURSIVE = NO - -# The EXCLUDE tag can be used to specify files and/or directories that should -# excluded from the INPUT source files. This way you can easily exclude a -# subdirectory from a directory tree whose root is specified with the INPUT tag. - -EXCLUDE = - -# The EXCLUDE_SYMLINKS tag can be used select whether or not files or -# directories that are symbolic links (a Unix filesystem feature) are excluded -# from the input. - -EXCLUDE_SYMLINKS = NO - -# If the value of the INPUT tag contains directories, you can use the -# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -# certain files from those directories. Note that the wildcards are matched -# against the file with absolute path, so to exclude all test directories -# for example use the pattern */test/* - -EXCLUDE_PATTERNS = - -# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names -# (namespaces, classes, functions, etc.) that should be excluded from the -# output. The symbol name can be a fully qualified name, a word, or if the -# wildcard * is used, a substring. Examples: ANamespace, AClass, -# AClass::ANamespace, ANamespace::*Test - -EXCLUDE_SYMBOLS = - -# The EXAMPLE_PATH tag can be used to specify one or more files or -# directories that contain example code fragments that are included (see -# the \include command). - -EXAMPLE_PATH = - -# If the value of the EXAMPLE_PATH tag contains directories, you can use the -# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank all files are included. - -EXAMPLE_PATTERNS = - -# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be -# searched for input files to be used with the \include or \dontinclude -# commands irrespective of the value of the RECURSIVE tag. -# Possible values are YES and NO. If left blank NO is used. - -EXAMPLE_RECURSIVE = NO - -# The IMAGE_PATH tag can be used to specify one or more files or -# directories that contain image that are included in the documentation (see -# the \image command). - -IMAGE_PATH = @CMAKE_DOXYGEN_IMAGE_PATH@ - -# The INPUT_FILTER tag can be used to specify a program that doxygen should -# invoke to filter for each input file. Doxygen will invoke the filter program -# by executing (via popen()) the command , where -# is the value of the INPUT_FILTER tag, and is the name of an -# input file. Doxygen will then use the output that the filter program writes -# to standard output. -# If FILTER_PATTERNS is specified, this tag will be -# ignored. - -INPUT_FILTER = - -# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern -# basis. -# Doxygen will compare the file name with each pattern and apply the -# filter if there is a match. -# The filters are a list of the form: -# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further -# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER -# is applied to all files. - -FILTER_PATTERNS = - -# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER) will be used to filter the input files when producing source -# files to browse (i.e. when SOURCE_BROWSER is set to YES). - -FILTER_SOURCE_FILES = NO - -#--------------------------------------------------------------------------- -# configuration options related to source browsing -#--------------------------------------------------------------------------- - -# If the SOURCE_BROWSER tag is set to YES then a list of source files will -# be generated. Documented entities will be cross-referenced with these sources. -# Note: To get rid of all source code in the generated output, make sure also -# VERBATIM_HEADERS is set to NO. - -SOURCE_BROWSER = NO - -# Setting the INLINE_SOURCES tag to YES will include the body -# of functions and classes directly in the documentation. - -INLINE_SOURCES = NO - -# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct -# doxygen to hide any special comment blocks from generated source code -# fragments. Normal C and C++ comments will always remain visible. - -STRIP_CODE_COMMENTS = YES - -# If the REFERENCED_BY_RELATION tag is set to YES -# then for each documented function all documented -# functions referencing it will be listed. - -REFERENCED_BY_RELATION = YES - -# If the REFERENCES_RELATION tag is set to YES -# then for each documented function all documented entities -# called/used by that function will be listed. - -REFERENCES_RELATION = YES - -# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) -# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from -# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will -# link to the source code. -# Otherwise they will link to the documentation. - -REFERENCES_LINK_SOURCE = YES - -# If the USE_HTAGS tag is set to YES then the references to source code -# will point to the HTML generated by the htags(1) tool instead of doxygen -# built-in source browser. The htags tool is part of GNU's global source -# tagging system (see http://www.gnu.org/software/global/global.html). You -# will need version 4.8.6 or higher. - -USE_HTAGS = NO - -# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen -# will generate a verbatim copy of the header file for each class for -# which an include is specified. Set to NO to disable this. - -VERBATIM_HEADERS = YES - -#--------------------------------------------------------------------------- -# configuration options related to the alphabetical class index -#--------------------------------------------------------------------------- - -# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index -# of all compounds will be generated. Enable this if the project -# contains a lot of classes, structs, unions or interfaces. - -ALPHABETICAL_INDEX = NO - -# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then -# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns -# in which this list will be split (can be a number in the range [1..20]) - -COLS_IN_ALPHA_INDEX = 5 - -# In case all classes in a project start with a common prefix, all -# classes will be put under the same header in the alphabetical index. -# The IGNORE_PREFIX tag can be used to specify one or more prefixes that -# should be ignored while generating the index headers. - -IGNORE_PREFIX = - -#--------------------------------------------------------------------------- -# configuration options related to the HTML output -#--------------------------------------------------------------------------- - -# If the GENERATE_HTML tag is set to YES (the default) Doxygen will -# generate HTML output. - -GENERATE_HTML = YES - -# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `html' will be used as the default path. - -HTML_OUTPUT = . - -# The HTML_FILE_EXTENSION tag can be used to specify the file extension for -# each generated HTML page (for example: .htm,.php,.asp). If it is left blank -# doxygen will generate files with .html extension. - -HTML_FILE_EXTENSION = .html - -# The HTML_HEADER tag can be used to specify a personal HTML header for -# each generated HTML page. If it is left blank doxygen will generate a -# standard header. - -HTML_HEADER = - -# The HTML_FOOTER tag can be used to specify a personal HTML footer for -# each generated HTML page. If it is left blank doxygen will generate a -# standard footer. - -HTML_FOOTER = - -# The HTML_STYLESHEET tag can be used to specify a user-defined cascading -# style sheet that is used by each HTML page. It can be used to -# fine-tune the look of the HTML output. If the tag is left blank doxygen -# will generate a default style sheet. Note that doxygen will try to copy -# the style sheet file to the HTML output directory, so don't put your own -# stylesheet in the HTML output directory as well, or it will be erased! - -HTML_STYLESHEET = - -# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML -# page will contain the date and time when the page was generated. Setting -# this to NO can help when comparing the output of multiple runs. - -HTML_TIMESTAMP = YES - -# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, -# files or namespaces will be aligned in HTML using tables. If set to -# NO a bullet list will be used. - -HTML_ALIGN_MEMBERS = YES - -# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML -# documentation will contain sections that can be hidden and shown after the -# page has loaded. For this to work a browser that supports -# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox -# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). - -HTML_DYNAMIC_SECTIONS = NO - -# If the GENERATE_DOCSET tag is set to YES, additional index files -# will be generated that can be used as input for Apple's Xcode 3 -# integrated development environment, introduced with OSX 10.5 (Leopard). -# To create a documentation set, doxygen will generate a Makefile in the -# HTML output directory. Running make will produce the docset in that -# directory and running "make install" will install the docset in -# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find -# it at startup. -# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. - -GENERATE_DOCSET = NO - -# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the -# feed. A documentation feed provides an umbrella under which multiple -# documentation sets from a single provider (such as a company or product suite) -# can be grouped. - -DOCSET_FEEDNAME = "Doxygen generated docs" - -# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that -# should uniquely identify the documentation set bundle. This should be a -# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen -# will append .docset to the name. - -DOCSET_BUNDLE_ID = org.doxygen.Project - -# If the GENERATE_HTMLHELP tag is set to YES, additional index files -# will be generated that can be used as input for tools like the -# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) -# of the generated HTML documentation. - -GENERATE_HTMLHELP = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can -# be used to specify the file name of the resulting .chm file. You -# can add a path in front of the file if the result should not be -# written to the html output directory. - -CHM_FILE = - -# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can -# be used to specify the location (absolute path including file name) of -# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run -# the HTML help compiler on the generated index.hhp. - -HHC_LOCATION = - -# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag -# controls if a separate .chi index file is generated (YES) or that -# it should be included in the master .chm file (NO). - -GENERATE_CHI = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING -# is used to encode HtmlHelp index (hhk), content (hhc) and project file -# content. - -CHM_INDEX_ENCODING = - -# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag -# controls whether a binary table of contents is generated (YES) or a -# normal table of contents (NO) in the .chm file. - -BINARY_TOC = NO - -# The TOC_EXPAND flag can be set to YES to add extra items for group members -# to the contents of the HTML help documentation and to the tree view. - -TOC_EXPAND = NO - -# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER -# are set, an additional index file will be generated that can be used as input for -# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated -# HTML documentation. - -GENERATE_QHP = NO - -# If the QHG_LOCATION tag is specified, the QCH_FILE tag can -# be used to specify the file name of the resulting .qch file. -# The path specified is relative to the HTML output folder. - -QCH_FILE = - -# The QHP_NAMESPACE tag specifies the namespace to use when generating -# Qt Help Project output. For more information please see -# http://doc.trolltech.com/qthelpproject.html#namespace - -QHP_NAMESPACE = org.doxygen.Project - -# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating -# Qt Help Project output. For more information please see -# http://doc.trolltech.com/qthelpproject.html#virtual-folders - -QHP_VIRTUAL_FOLDER = doc - -# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add. -# For more information please see -# http://doc.trolltech.com/qthelpproject.html#custom-filters - -QHP_CUST_FILTER_NAME = - -# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see -# Qt Help Project / Custom Filters. - -QHP_CUST_FILTER_ATTRS = - -# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's -# filter section matches. -# Qt Help Project / Filter Attributes. - -QHP_SECT_FILTER_ATTRS = - -# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can -# be used to specify the location of Qt's qhelpgenerator. -# If non-empty doxygen will try to run qhelpgenerator on the generated -# .qhp file. - -QHG_LOCATION = - -# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files -# will be generated, which together with the HTML files, form an Eclipse help -# plugin. To install this plugin and make it available under the help contents -# menu in Eclipse, the contents of the directory containing the HTML and XML -# files needs to be copied into the plugins directory of eclipse. The name of -# the directory within the plugins directory should be the same as -# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before the help appears. - -GENERATE_ECLIPSEHELP = NO - -# A unique identifier for the eclipse help plugin. When installing the plugin -# the directory name containing the HTML and XML files should also have -# this name. - -ECLIPSE_DOC_ID = org.doxygen.Project - -# The DISABLE_INDEX tag can be used to turn on/off the condensed index at -# top of each HTML page. The value NO (the default) enables the index and -# the value YES disables it. - -DISABLE_INDEX = NO - -# This tag can be used to set the number of enum values (range [1..20]) -# that doxygen will group on one line in the generated HTML documentation. - -ENUM_VALUES_PER_LINE = 8 - -# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index -# structure should be generated to display hierarchical information. -# If the tag value is set to YES, a side panel will be generated -# containing a tree-like index structure (just like the one that -# is generated for HTML Help). For this to work a browser that supports -# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). -# Windows users are probably better off using the HTML help feature. - -GENERATE_TREEVIEW = NO - -# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, -# and Class Hierarchy pages using a tree view instead of an ordered list. - -USE_INLINE_TREES = NO - -# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be -# used to set the initial width (in pixels) of the frame in which the tree -# is shown. - -TREEVIEW_WIDTH = 250 - -# Use this tag to change the font size of Latex formulas included -# as images in the HTML documentation. The default is 10. Note that -# when you change the font size after a successful doxygen run you need -# to manually remove any form_*.png images from the HTML output directory -# to force them to be regenerated. - -FORMULA_FONTSIZE = 10 - -# When the SEARCHENGINE tag is enabled doxygen will generate a search box for the HTML output. The underlying search engine uses javascript -# and DHTML and should work on any modern browser. Note that when using HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) there is already a search function so this one should -# typically be disabled. For large projects the javascript based search engine -# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. - -SEARCHENGINE = NO - -# When the SERVER_BASED_SEARCH tag is enabled the search engine will be implemented using a PHP enabled web server instead of at the web client using Javascript. Doxygen will generate the search PHP script and index -# file to put on the web server. The advantage of the server based approach is that it scales better to large projects and allows full text search. The disadvances is that it is more difficult to setup -# and does not have live searching capabilities. - -SERVER_BASED_SEARCH = NO - -#--------------------------------------------------------------------------- -# configuration options related to the LaTeX output -#--------------------------------------------------------------------------- - -# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will -# generate Latex output. - -GENERATE_LATEX = NO - -# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `latex' will be used as the default path. - -LATEX_OUTPUT = latex - -# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be -# invoked. If left blank `latex' will be used as the default command name. -# Note that when enabling USE_PDFLATEX this option is only used for -# generating bitmaps for formulas in the HTML output, but not in the -# Makefile that is written to the output directory. - -LATEX_CMD_NAME = latex - -# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to -# generate index for LaTeX. If left blank `makeindex' will be used as the -# default command name. - -MAKEINDEX_CMD_NAME = makeindex - -# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact -# LaTeX documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_LATEX = NO - -# The PAPER_TYPE tag can be used to set the paper type that is used -# by the printer. Possible values are: a4, a4wide, letter, legal and -# executive. If left blank a4wide will be used. - -PAPER_TYPE = a4wide - -# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX -# packages that should be included in the LaTeX output. - -EXTRA_PACKAGES = - -# The LATEX_HEADER tag can be used to specify a personal LaTeX header for -# the generated latex document. The header should contain everything until -# the first chapter. If it is left blank doxygen will generate a -# standard header. Notice: only use this tag if you know what you are doing! - -LATEX_HEADER = - -# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated -# is prepared for conversion to pdf (using ps2pdf). The pdf file will -# contain links (just like the HTML output) instead of page references -# This makes the output suitable for online browsing using a pdf viewer. - -PDF_HYPERLINKS = NO - -# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of -# plain latex in the generated Makefile. Set this option to YES to get a -# higher quality PDF documentation. - -USE_PDFLATEX = NO - -# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. -# command to the generated LaTeX files. This will instruct LaTeX to keep -# running if errors occur, instead of asking the user for help. -# This option is also used when generating formulas in HTML. - -LATEX_BATCHMODE = NO - -# If LATEX_HIDE_INDICES is set to YES then doxygen will not -# include the index chapters (such as File Index, Compound Index, etc.) -# in the output. - -LATEX_HIDE_INDICES = NO - -# If LATEX_SOURCE_CODE is set to YES then doxygen will include source code with syntax highlighting in the LaTeX output. Note that which sources are shown also depends on other settings such as SOURCE_BROWSER. - -LATEX_SOURCE_CODE = NO - -#--------------------------------------------------------------------------- -# configuration options related to the RTF output -#--------------------------------------------------------------------------- - -# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output -# The RTF output is optimized for Word 97 and may not look very pretty with -# other RTF readers or editors. - -GENERATE_RTF = NO - -# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `rtf' will be used as the default path. - -RTF_OUTPUT = rtf - -# If the COMPACT_RTF tag is set to YES Doxygen generates more compact -# RTF documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_RTF = NO - -# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated -# will contain hyperlink fields. The RTF file will -# contain links (just like the HTML output) instead of page references. -# This makes the output suitable for online browsing using WORD or other -# programs which support those fields. -# Note: wordpad (write) and others do not support links. - -RTF_HYPERLINKS = NO - -# Load stylesheet definitions from file. Syntax is similar to doxygen's -# config file, i.e. a series of assignments. You only have to provide -# replacements, missing definitions are set to their default value. - -RTF_STYLESHEET_FILE = - -# Set optional variables used in the generation of an rtf document. -# Syntax is similar to doxygen's config file. - -RTF_EXTENSIONS_FILE = - -#--------------------------------------------------------------------------- -# configuration options related to the man page output -#--------------------------------------------------------------------------- - -# If the GENERATE_MAN tag is set to YES (the default) Doxygen will -# generate man pages - -GENERATE_MAN = NO - -# The MAN_OUTPUT tag is used to specify where the man pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `man' will be used as the default path. - -MAN_OUTPUT = man - -# The MAN_EXTENSION tag determines the extension that is added to -# the generated man pages (default is the subroutine's section .3) - -MAN_EXTENSION = .3 - -# If the MAN_LINKS tag is set to YES and Doxygen generates man output, -# then it will generate one additional man file for each entity -# documented in the real man page(s). These additional files -# only source the real man page, but without them the man command -# would be unable to find the correct page. The default is NO. - -MAN_LINKS = NO - -#--------------------------------------------------------------------------- -# configuration options related to the XML output -#--------------------------------------------------------------------------- - -# If the GENERATE_XML tag is set to YES Doxygen will -# generate an XML file that captures the structure of -# the code including all documentation. - -GENERATE_XML = NO - -# The XML_OUTPUT tag is used to specify where the XML pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `xml' will be used as the default path. - -XML_OUTPUT = xml - -# The XML_SCHEMA tag can be used to specify an XML schema, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_SCHEMA = - -# The XML_DTD tag can be used to specify an XML DTD, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_DTD = - -# If the XML_PROGRAMLISTING tag is set to YES Doxygen will -# dump the program listings (including syntax highlighting -# and cross-referencing information) to the XML output. Note that -# enabling this will significantly increase the size of the XML output. - -XML_PROGRAMLISTING = YES - -#--------------------------------------------------------------------------- -# configuration options for the AutoGen Definitions output -#--------------------------------------------------------------------------- - -# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will -# generate an AutoGen Definitions (see autogen.sf.net) file -# that captures the structure of the code including all -# documentation. Note that this feature is still experimental -# and incomplete at the moment. - -GENERATE_AUTOGEN_DEF = NO - -#--------------------------------------------------------------------------- -# configuration options related to the Perl module output -#--------------------------------------------------------------------------- - -# If the GENERATE_PERLMOD tag is set to YES Doxygen will -# generate a Perl module file that captures the structure of -# the code including all documentation. Note that this -# feature is still experimental and incomplete at the -# moment. - -GENERATE_PERLMOD = NO - -# If the PERLMOD_LATEX tag is set to YES Doxygen will generate -# the necessary Makefile rules, Perl scripts and LaTeX code to be able -# to generate PDF and DVI output from the Perl module output. - -PERLMOD_LATEX = NO - -# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be -# nicely formatted so it can be parsed by a human reader. -# This is useful -# if you want to understand what is going on. -# On the other hand, if this -# tag is set to NO the size of the Perl module output will be much smaller -# and Perl will parse it just the same. - -PERLMOD_PRETTY = YES - -# The names of the make variables in the generated doxyrules.make file -# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. -# This is useful so different doxyrules.make files included by the same -# Makefile don't overwrite each other's variables. - -PERLMOD_MAKEVAR_PREFIX = - -#--------------------------------------------------------------------------- -# Configuration options related to the preprocessor -#--------------------------------------------------------------------------- - -# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will -# evaluate all C-preprocessor directives found in the sources and include -# files. - -ENABLE_PREPROCESSING = YES - -# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro -# names in the source code. If set to NO (the default) only conditional -# compilation will be performed. Macro expansion can be done in a controlled -# way by setting EXPAND_ONLY_PREDEF to YES. - -MACRO_EXPANSION = NO - -# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES -# then the macro expansion is limited to the macros specified with the -# PREDEFINED and EXPAND_AS_DEFINED tags. - -EXPAND_ONLY_PREDEF = NO - -# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files -# in the INCLUDE_PATH (see below) will be search if a #include is found. - -SEARCH_INCLUDES = NO - -# The INCLUDE_PATH tag can be used to specify one or more directories that -# contain include files that are not input files but should be processed by -# the preprocessor. - -INCLUDE_PATH = - -# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard -# patterns (like *.h and *.hpp) to filter out the header-files in the -# directories. If left blank, the patterns specified with FILE_PATTERNS will -# be used. - -INCLUDE_FILE_PATTERNS = - -# The PREDEFINED tag can be used to specify one or more macro names that -# are defined before the preprocessor is started (similar to the -D option of -# gcc). The argument of the tag is a list of macros of the form: name -# or name=definition (no spaces). If the definition and the = are -# omitted =1 is assumed. To prevent a macro definition from being -# undefined via #undef or recursively expanded use the := operator -# instead of the = operator. - -PREDEFINED = DOXYGEN_SHOULD_SKIP_THIS - -# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then -# this tag can be used to specify a list of macro names that should be expanded. -# The macro definition that is found in the sources will be used. -# Use the PREDEFINED tag if you want to use a different macro definition. - -EXPAND_AS_DEFINED = - -# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then -# doxygen's preprocessor will remove all function-like macros that are alone -# on a line, have an all uppercase name, and do not end with a semicolon. Such -# function macros are typically used for boiler-plate code, and will confuse -# the parser if not removed. - -SKIP_FUNCTION_MACROS = YES - -#--------------------------------------------------------------------------- -# Configuration::additions related to external references -#--------------------------------------------------------------------------- - -# The TAGFILES option can be used to specify one or more tagfiles. -# Optionally an initial location of the external documentation -# can be added for each tagfile. The format of a tag file without -# this location is as follows: -# -# TAGFILES = file1 file2 ... -# Adding location for the tag files is done as follows: -# -# TAGFILES = file1=loc1 "file2 = loc2" ... -# where "loc1" and "loc2" can be relative or absolute paths or -# URLs. If a location is present for each tag, the installdox tool -# does not have to be run to correct the links. -# Note that each tag file must have a unique name -# (where the name does NOT include the path) -# If a tag file is not located in the directory in which doxygen -# is run, you must also specify the path to the tagfile here. - -TAGFILES = - -# When a file name is specified after GENERATE_TAGFILE, doxygen will create -# a tag file that is based on the input files it reads. - -GENERATE_TAGFILE = - -# If the ALLEXTERNALS tag is set to YES all external classes will be listed -# in the class index. If set to NO only the inherited external classes -# will be listed. - -ALLEXTERNALS = NO - -# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed -# in the modules index. If set to NO, only the current project's groups will -# be listed. - -EXTERNAL_GROUPS = YES - -# The PERL_PATH should be the absolute path and name of the perl script -# interpreter (i.e. the result of `which perl'). - -PERL_PATH = /usr/bin/perl - -#--------------------------------------------------------------------------- -# Configuration options related to the dot tool -#--------------------------------------------------------------------------- - -# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will -# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base -# or super classes. Setting the tag to NO turns the diagrams off. Note that -# this option is superseded by the HAVE_DOT option below. This is only a -# fallback. It is recommended to install and use dot, since it yields more -# powerful graphs. - -CLASS_DIAGRAMS = YES - -# You can define message sequence charts within doxygen comments using the \msc -# command. Doxygen will then run the mscgen tool (see -# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the -# documentation. The MSCGEN_PATH tag allows you to specify the directory where -# the mscgen tool resides. If left empty the tool is assumed to be found in the -# default search path. - -MSCGEN_PATH = - -# If set to YES, the inheritance and collaboration graphs will hide -# inheritance and usage relations if the target is undocumented -# or is not a class. - -HIDE_UNDOC_RELATIONS = YES - -# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is -# available from the path. This tool is part of Graphviz, a graph visualization -# toolkit from AT&T and Lucent Bell Labs. The other options in this section -# have no effect if this option is set to NO (the default) - -HAVE_DOT = @DOXYFILE_DOT@ - -# By default doxygen will write a font called FreeSans.ttf to the output -# directory and reference it in all dot files that doxygen generates. This -# font does not include all possible unicode characters however, so when you need -# these (or just want a differently looking font) you can specify the font name -# using DOT_FONTNAME. You need need to make sure dot is able to find the font, -# which can be done by putting it in a standard location or by setting the -# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory -# containing the font. - -DOT_FONTNAME = FreeSans - -# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. -# The default size is 10pt. - -DOT_FONTSIZE = 10 - -# By default doxygen will tell dot to use the output directory to look for the -# FreeSans.ttf font (which doxygen will put there itself). If you specify a -# different font using DOT_FONTNAME you can set the path where dot -# can find it using this tag. - -DOT_FONTPATH = - -# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect inheritance relations. Setting this tag to YES will force the -# the CLASS_DIAGRAMS tag to NO. - -CLASS_GRAPH = YES - -# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect implementation dependencies (inheritance, containment, and -# class references variables) of the class with other documented classes. - -COLLABORATION_GRAPH = YES - -# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for groups, showing the direct groups dependencies - -GROUP_GRAPHS = YES - -# If the UML_LOOK tag is set to YES doxygen will generate inheritance and -# collaboration diagrams in a style similar to the OMG's Unified Modeling -# Language. - -UML_LOOK = NO - -# If set to YES, the inheritance and collaboration graphs will show the -# relations between templates and their instances. - -TEMPLATE_RELATIONS = YES - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT -# tags are set to YES then doxygen will generate a graph for each documented -# file showing the direct and indirect include dependencies of the file with -# other documented files. - -INCLUDE_GRAPH = YES - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and -# HAVE_DOT tags are set to YES then doxygen will generate a graph for each -# documented header file showing the documented files that directly or -# indirectly include this file. - -INCLUDED_BY_GRAPH = YES - -# If the CALL_GRAPH and HAVE_DOT options are set to YES then -# doxygen will generate a call dependency graph for every global function -# or class method. Note that enabling this option will significantly increase -# the time of a run. So in most cases it will be better to enable call graphs -# for selected functions only using the \callgraph command. - -CALL_GRAPH = YES - -# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then -# doxygen will generate a caller dependency graph for every global function -# or class method. Note that enabling this option will significantly increase -# the time of a run. So in most cases it will be better to enable caller -# graphs for selected functions only using the \callergraph command. - -CALLER_GRAPH = NO - -# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen -# will graphical hierarchy of all classes instead of a textual one. - -GRAPHICAL_HIERARCHY = YES - -# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES -# then doxygen will show the dependencies a directory has on other directories -# in a graphical way. The dependency relations are determined by the #include -# relations between the files in the directories. - -DIRECTORY_GRAPH = YES - -# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images -# generated by dot. Possible values are png, jpg, or gif -# If left blank png will be used. - -DOT_IMAGE_FORMAT = png - -# The tag DOT_PATH can be used to specify the path where the dot tool can be -# found. If left blank, it is assumed the dot tool can be found in the path. - -DOT_PATH = "@DOXYGEN_DOT_PATH@" - -# The DOTFILE_DIRS tag can be used to specify one or more directories that -# contain dot files that are included in the documentation (see the -# \dotfile command). - -DOTFILE_DIRS = - -# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of -# nodes that will be shown in the graph. If the number of nodes in a graph -# becomes larger than this value, doxygen will truncate the graph, which is -# visualized by representing a node as a red box. Note that doxygen if the -# number of direct children of the root node in a graph is already larger than -# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note -# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. - -DOT_GRAPH_MAX_NODES = 50 - -# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the -# graphs generated by dot. A depth value of 3 means that only nodes reachable -# from the root by following a path via at most 3 edges will be shown. Nodes -# that lay further from the root node will be omitted. Note that setting this -# option to 1 or 2 may greatly reduce the computation time needed for large -# code bases. Also note that the size of a graph can be further restricted by -# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. - -MAX_DOT_GRAPH_DEPTH = 0 - -# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent -# background. This is disabled by default, because dot on Windows does not -# seem to support this out of the box. Warning: Depending on the platform used, -# enabling this option may lead to badly anti-aliased labels on the edges of -# a graph (i.e. they become hard to read). - -DOT_TRANSPARENT = NO - -# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output -# files in one run (i.e. multiple -o and -T options on the command line). This -# makes dot run faster, but since only newer versions of dot (>1.8.10) -# support this, this feature is disabled by default. - -DOT_MULTI_TARGETS = YES - -# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will -# generate a legend page explaining the meaning of the various boxes and -# arrows in the dot generated graphs. - -GENERATE_LEGEND = YES - -# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will -# remove the intermediate dot files that are used to generate -# the various graphs. - -DOT_CLEANUP = YES diff --git a/doc/Doxygen.html b/doc/Doxygen.html deleted file mode 100644 index da9a6fb655..0000000000 --- a/doc/Doxygen.html +++ /dev/null @@ -1,9 +0,0 @@ - - - -REDIRECT! - - -This is a redirect to the doxygen stuff. - - diff --git a/doc/index.dxgen b/doc/index.dxgen deleted file mode 100644 index bfb6b23123..0000000000 --- a/doc/index.dxgen +++ /dev/null @@ -1,42 +0,0 @@ -/******************************************************************************* -www.sourceforge.net/projects/dfhack -Copyright (c) 2009 Petr Mrázek (peterix) - -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 acknowledgment 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. -*/ - -/*! \page index -

-\htmlonly -

DFHack

- -\endhtmlonly -
- -

Introduction

-DFHack is a Dwarf Fortress memory access library and a set of basic tools using -this library. The library is a work in progress, so things might change as more -tools are written for it. - -It is an attempt to unite the various ways tools access DF memory and allow for -easier development of new tools. In general, you can use it to move memory -objects in and out of Dwarf Fortress really fast, regardless of DF version or OS. -*/ - diff --git a/docs/Core.rst b/docs/Core.rst new file mode 100644 index 0000000000..b386e5ea04 --- /dev/null +++ b/docs/Core.rst @@ -0,0 +1,471 @@ +.. _dfhack-core: + +########### +DFHack Core +########### + +.. contents:: Contents + :local: + :depth: 2 + + +Command implementation +====================== +DFHack commands can be implemented in any of three ways: + +:builtin: commands are implemented by the core of DFHack. They manage + other DFHack tools, interpret commands, and control basic + aspects of DF (force pause or quit). + +:plugins: are stored in ``hack/plugins/`` and must be compiled with the + same version of DFHack. They are less flexible than scripts, + but used for complex or ongoing tasks because they run faster. + +:scripts: are Lua scripts stored in ``hack/scripts/`` or other + directories in the `script-paths`. Because they don't need to + be compiled, scripts are more flexible about versions, and + they are easier to distribute. Most third-party DFHack addons + are scripts. + +All tools distributed with DFHack are documented `here `. + +Using DFHack commands +===================== +DFHack commands can be executed in a number of ways: + +#. Typing the command into the DFHack console (see below) +#. From the OS terminal (see below) +#. Pressing a key combination set up with `keybinding` +#. From one of several `init-files`, automatically +#. Using `script` to run a batch of commands from a file +#. From an in-game command launcher interface like `gui/launcher`, the + `hotkeys` overlay widget, or `gui/quickcmd`. + +The DFHack console +------------------ +The command line has some nice line editing capabilities, including history +that's preserved between different runs of DF - use :kbd:`↑` and :kbd:`↓` +to go through the history. + +To include whitespace in the argument/s to some command, quote it in +double quotes. To include a double quote character, use ``\"``. + +If the first non-whitespace character is ``:``, the command is parsed in +an alternative mode. The non-whitespace characters following the ``:`` are +the command name, and the remaining part of the line is used verbatim as +the first argument. This is very useful for the `lua` command. +As an example, the following two command lines are exactly equivalent:: + + :foo a b "c d" e f + foo "a b \"c d\" e f" + +Using an OS terminal +-------------------- +DFHack commands can be run from an OS terminal at startup, using '+ args', +or at any other time using the ``dfhack-run`` executable. + +If DF/DFHack is started with arguments beginning with ``+``, the remaining +text is treated as a command in the DFHack console. It is possible to use +multiple such commands, which are split on ``+``. For example: + +.. code-block:: shell + + ./dfhack +load-save region1 + "Dwarf Fortress.exe" +devel/print-args Hello! +enable workflow + +The first example (\*nix), `load-save`, skips the main menu and loads +``region1`` immediately. The second (Windows) example prints +:guilabel:`Hello!` in the DFHack console, and `enables ` `workflow`. +Note that the ``:foo`` syntax for whitespace in arguments is not compatible \ +with '+ args'. + + +.. _dfhack-run: + +dfhack-run +.......... + +If DF and DFHack are already running, calling ``dfhack-run my command`` +in an external terminal is equivalent to calling ``my command`` in the +DFHack console. Direct use of the DFHack console is generally easier, +but ``dfhack-run`` can be useful in a variety of circumstances: + +- if the console is unavailable + + - with the init setting ``PRINT_MODE:TEXT`` + - while running an interactive command (e.g. `liquids` or `tiletypes`) + +- from external programs or scripts +- if DF or DFHack are not responding + +Examples: + +.. code-block:: shell + + ./dfhack-run cursecheck + dfhack-run kill-lua + +The first (\*nix) example `checks for vampires `; the +second (Windows) example uses `kill-lua` to stop a Lua script. + +.. note:: + + ``dfhack-run`` attempts to connect to a server on TCP port 5000. If DFHack + was unable to start this server, ``dfhack-run`` will not be able to connect. + This could happen if you have other software listening on port 5000, or if + you have multiple copies of DF running simultaneously. To assign a different + port, see `remote-server-config`. + +.. _dfhack-config: + +Configuration files +=================== + +Most DFHack settings can be changed by modifying files in the ``dfhack-config`` +folder (which is in the DF folder). The default versions of these files, if they +exist, are in ``dfhack-config/default`` and are installed when DFHack starts if +necessary. + +.. _init-files: + +Init files +---------- + +.. contents:: + :local: + +DFHack allows users to automatically run commonly-used DFHack commands +when DF is first loaded, when a world is loaded, when a map is loaded, when a +map is unloaded, and when a world is unloaded. + +Init scripts function the same way they would if the user manually typed +in their contents, but are much more convenient. In order to facilitate +savegave portability, mod merging, and general organization of init files, +DFHack supports multiple init files both in the main DF directory and +save-specific init files in the save folders. + +DFHack looks for init files in two places each time they could be run: + +#. The :file:`dfhack-config/init` subdirectory in the main DF directory and +#. :file:`save/{world}/init`, where ``{world}`` is the current save + +For each of those directories, all matching init files will be executed in +alphabetical order. + +Before running matched init scripts in any of those locations, the +:file:`dfhack-config/init/default.*` file that matches the event will be run to +load DFHack defaults. Only the :file:`dfhack-config/init` directory is checked +for this file, not any :file:`save` directories. If you want DFHack to load +without running any of its default configuration commands, edit the +:file:`dfhack-config/init/default.*` files and comment out the commands you see +there. + +When reading commands from the init files or with the `script` command, if the +final character on a line is a backslash then the next uncommented line is +considered a continuation of that line, with the backslash deleted. Commented +lines are skipped, so it is possible to comment out parts of a command with the +``#`` character. + +.. _dfhack.init: + +dfhack\*.init +............. +On startup, DFHack looks for files of the form ``dfhack*.init`` (where ``*`` is +a placeholder for any string, including the empty string). + +These files are best used for keybindings and enabling persistent tools +which do not require a world to be loaded. + + +.. _onLoad.init: + +onLoad\*.init +............. +When a world is loaded, DFHack looks for files of the form ``onLoad*.init``, +where ``*`` can be any string, including the empty string. + +A world being loaded can mean a fortress, an adventurer, or legends mode. + +These files are best used for non-persistent commands, such as setting +a `bugfix-tag-index` script to run on `repeat`. + + +.. _onMapLoad.init: + +onMapLoad\*.init +................ +When a map is loaded, either in adventure or fort mode, DFHack looks for files +of the form ``onMapLoad*.init``, where ``*`` can be any string, including the +empty string. + +These files are best used for commands that are only relevant once there is a +game map loaded. + + +.. _onMapUnload.init: +.. _onUnload.init: + +onMapUnload\*.init and onUnload\*.init +...................................... +When a map or world is unloaded, DFHack looks for files of the form +``onMapUnload*.init`` or ``onUnload*.init``, respectively. + +Modders often use unload init scripts to disable tools which should not run +after a modded save is unloaded. + + +.. _other_init_files: + +init.d/\*.lua +............. + +Any lua script named ``init.d/*.lua``, in the save or main DF directory, +will be run when any world or that save is loaded. + + +.. _script-paths: + +Script paths +------------ + +Script paths are folders that DFHack searches to find a script when a command is +run. By default, the following folders are searched, in order (relative to the +root DF folder): + +#. :file:`dfhack-config/scripts` +#. :file:`save/{world}/scripts` (only if a save is loaded) +#. :file:`hack/scripts` +#. :file:`data/installed_mods/...` (see below) + +For example, if ``teleport`` is run, these folders are searched in order for +``teleport.lua``, and the first matching file is run. + +Scripts in installed mods +......................... + +Scripts in mods are automatically added to the script path. The following +directories are searched for mods:: + + ../../workshop/content/975370/ (the DF Steam workshop directory) + mods/ + data/installed_mods/ + +Each mod can have two directories that contain scripts: + +- ``scripts_modactive/`` is added to the script path if and only if the mod is + active in the loaded world. +- ``scripts_modinstalled/`` is added to the script path as long as the mod is + installed in one of the searched mod directories. + +Multiple versions of a mod may be installed at the same time. If a mod is +active in a loaded world, then the scripts for the version of the mod that is +active will be added to the script path. Otherwise, the latest version of each +mod is added to the script path. + +Scripts for active mods take precedence according to their load order when you +generated the current world. + +Scripts for non-active mods are ordered by their containing mod's ID. + +For example, the search paths for mods might look like this:: + + activemod_last_in_load_order/scripts_modactive + activemod_last_in_load_order/scripts_modinstalled + activemod_second_to_last_in_load_order/scripts_modactive + activemod_second_to_last_in_load_order/scripts_modinstalled + ... + inactivemod1/scripts_modinstalled + inactivemod2/scripts_modinstalled + ... + +Not all mods will have script directories, of course, and those mods will not be +added to the script search path. Mods are re-scanned whenever a world is loaded +or unloaded. For more information on scripts and mods, check out the +`modding-guide`. + +Custom script paths +................... + +Script paths can be added by modifying :file:`dfhack-config/script-paths.txt`. +Each line should start with one of these characters: + +- ``+``: adds a script path that is searched *before* the default paths (above) +- ``-``: adds a script path that is searched *after* the default paths +- ``#``: a comment (the line is ignored) + +Paths can be absolute or relative - relative paths are interpreted relative to +the root DF folder. + +.. admonition:: Tip + + When developing scripts in the :source-scripts:`dfhack/scripts repo <>`, + it may be useful to add the path to your local copy of the repo with ``+``. + This will allow you to make changes in the repo and have them take effect + immediately, without needing to re-install or copy scripts over manually. + +Note that ``script-paths.txt`` is only read at startup, but the paths can also be +modified programmatically at any time through the `Lua API `. + +Commandline options +=================== + +In addition to `Using an OS terminal`_ to execute commands on startup, DFHack +also recognizes a few commandline options. + +Options passed to Dwarf Fortress +-------------------------------- + +These options can be passed to Dwarf Fortress and will be intercepted by +DFHack. If you are launching Dwarf Fortress from Steam, you can set your +options in the "Launch Options" text box in the properties for the Dwarf +Fortress app (**NOT the DFHack app**). Note that these launch options will be +used regardless of whether you run Dwarf Fortress from its own app or DFHack's. + +- ``--disable-dfhack``: If set, then DFHack will be disabled for the session. + You will have to restart Dwarf Fortress without specifying this option in + order to use DFHack. Note that even if DFHack is disabled, :file:`stdout.txt` + and :file:`stderr.txt` will still be redirected to :file:`stdout.log` and + :file:`stderr.log`, respectively. + +- ``--nosteam-dfhack``: If set, then the DFHack stub launcher will not execute + when you launch DF from its own app in the Steam client. This will prevent + your settings from being restored or backed up with Steam Cloud Save. This is + probably not what you want. If you want to just not have the DFHack playtime + counted towards your hours, see the DFHack stub launcher ``--nowait`` option + below. + +- ``--skip-size-check``: DFHack normally verifies the sizes of important game + on startup and shuts down if a discrepancy is detected. This is intended to + reduce the risk of misalignments in these structures leading to crashes or + other misbehavior. This option bypasses the check. This option should + normally only be used to facilitate DFHack development. This option will + **not** enable DFHack to be used usefully with a version of DF with which + DFHack has not been aligned. + +Options passed to the DFHack Steam stub launcher +------------------------------------------------ + +These options can be passed to the DFHack stub launcher that executes when you +run the DFHack app from the Steam client. You can set your options in the +"Launch Options" text box in the properties for the DFHack app (**NOT the Dwarf +Fortress app**). Note that these launch options will be used regardless of +whether you run Dwarf Fortress from its own app or DFHack's. + +- ``--nowait``: If set, the DFHack stub launcher will not wait for DF to exit + before exiting itself. This may be desired by players who do not want their + playtime "double counted". However, using this option means that your DFHack + settings that get backed up to the cloud will always be out of sync. The stub + launcher normally downloads updated settings from Steam Cloud Save when DF + launches, and then backs up changed settings when DF exits. If this option is + used, then your settings will still be reconciled when DF launches, but + changes made during your play session will not be saved when DF exits. Please + use with caution -- you may lose data. + +.. _env-vars: + +Environment variables +===================== + +DFHack's behavior can be adjusted with some environment variables. For example, +on UNIX-like systems: + +.. code-block:: shell + + DFHACK_SOME_VAR=1 ./dfhack + +- ``DFHACK_DISABLE``: if set, DFHack will not initialize, not even to redirect + standard output or standard error. This is provided as an alternative + to the ``--disable-dfhack`` commandline parameter above for when environment + variables are more convenient. + +- ``DFHACK_PORT``: the port to use for the RPC server (used by ``dfhack-run`` + and `remotefortressreader` among others) instead of the default ``5000``. As + with the default, if this port cannot be used, the server is not started. + See `remote` for more details. + +- ``DFHACK_DISABLE_CONSOLE``: if set, DFHack's external console is not set up. + This is the default behavior if ``PRINT_MODE:TEXT`` is set in + ``data/init/init.txt``. Intended for situations where DFHack cannot run in a + terminal window. + +- ``DFHACK_HEADLESS``: if set, and ``PRINT_MODE:TEXT`` is set, DF's display will + be hidden, and the console will be started unless ``DFHACK_DISABLE_CONSOLE`` + is also set. Intended for non-interactive gameplay only. + +- ``DFHACK_NO_GLOBALS``, ``DFHACK_NO_VTABLES``: ignores all global or vtable + addresses in ``symbols.xml``, respectively. Intended for development use - + e.g. to make sure tools do not crash when these addresses are missing. + +- ``DFHACK_NO_DEV_PLUGINS``: if set, any plugins from the plugins/devel folder + that are built and installed will not be loaded on startup. + +- ``DFHACK_LOG_MEM_RANGES`` (macOS only): if set, logs memory ranges to + ``stderr.log``. Note that `devel/lsmem` can also do this. + +- ``DFHACK_ENABLE_LUACOV``: if set, enables coverage analysis of Lua scripts. + Use the `devel/luacov` script to generate coverage reports from the collected + metrics. + +Other (non-DFHack-specific) variables that affect DFHack: + +- ``TERM``: if this is set to ``dumb`` or ``cons25`` on \*nix, the console will + not support any escape sequences (arrow keys, etc.). + +- ``LANG``, ``LC_CTYPE``: if either of these contain "UTF8" or "UTF-8" (not case + sensitive), ``DF2CONSOLE()`` will produce UTF-8-encoded text. Note that this + should be the case in most UTF-8-capable \*nix terminal emulators already. + +Core preferences +================ + +Settings that control DFHack's runtime behavior can be changed dynamically via +the "Preferences" tab in `gui/control-panel` or on the commandline with +`control-panel`. The two most important settings for the core are: + +- ``HIDE_CONSOLE_ON_STARTUP``: On Windows, this controls whether to hide the + external DFHack terminal window on startup. The console is hidden by default + so it does not get in the way of gameplay, but it can be useful to enable for + debugging purposes or if you just prefer to use the external console instead + of the in-game `gui/launcher`. When you change this setting, the new behavior + will take effect the next time you start the game. If you are running the + native Linux version of DF (and DFHack), the terminal that you run the game + from becomes the DFHack console and this setting has no effect. + +- ``HIDE_ARMOK_TOOLS``: Whether to hide "armok" tools in command lists. Also + known as "Mortal mode", this setting keeps god-mode tools out of sight and + out of mind. Highly recommended for players who would prefer if the god-mode + tools were not quite as obvious and accessible. + +.. _performance-monitoring: + +Performance monitoring +====================== + +Though DFHack tools are generally performant, they do take some amount of time +to run. DFHack tracks its impact on DF game speed so the DFHack team can be +aware of (and fix) tools that are taking more than their fair share of +processing time. + +The target threshold for DFHack CPU utilization during unpaused gameplay with +all overlays and automation tools enabled is 10%. This is about the level where +players would notice the impact. In general, DFHack will have even less impact +for most players, since it is not common for every single DFHack tool to be +enabled at once. + +DFHack will record a performance report with the savegame files named +``dfhack-perf-counters.dat``. The report contains measurements from when the +game was loaded to the time when it was saved. By default, only unpaused time is +measured (since processing done while the game is paused doesn't slow anything +down from the player's perspective). You can display a live report at any time +by running:: + + :lua require('script-manager').print_timers() + +You can reset the timers to start a new measurement session by running:: + + :lua dfhack.internal.resetPerfCounters() + +If you want to record performance over all elapsed time, not just unpaused +time, then instead run:: + + :lua dfhack.internal.resetPerfCounters(true) diff --git a/docs/Installing.rst b/docs/Installing.rst new file mode 100644 index 0000000000..a687498e7e --- /dev/null +++ b/docs/Installing.rst @@ -0,0 +1,174 @@ +.. _installing: + +========== +Installing +========== + +.. contents:: + :local: + +Requirements +============ + +DFHack supports all operating systems and platforms that Dwarf Fortress itself +supports, which at the moment is the 64-bit versions of Windows and Linux. +The Windows build of DFHack also works well under ``wine`` for platforms that +can't run a native version. When running via ``wine``, use the following commandline:: + + wine64 explorer Dwarf\ Fortress.exe + +.. _installing-df-version: + +DFHack releases generally only support the version of Dwarf Fortress that they +are named after. For example, DFHack 50.05 only supported DF 50.05. DFHack +releases *never* support newer versions of DF -- DFHack requires data about DF +that is only possible to obtain after DF has been released. Occasionally, +DFHack releases will be able to maintain support for older versions of DF - for +example, DFHack 0.34.11-r5 supported both DF 0.34.11 and 0.34.10. For maximum +stability, you should use the latest versions of both DF and DFHack. + +.. _downloading: + +Downloading DFHack +================== + +Stable builds of DFHack are available on +`Steam `__ +or from our `GitHub `__. Either +location will give you exactly the same package. + +On Steam, note that DFHack is a separate app, not a DF Steam Workshop mod. You +can run DF with DFHack by launching either the DFHack app or the original Dwarf +Fortress app. + +Even if you have a non-Steam version of DF (i.e. Itch or Classic), you can +still install DFHack from Steam to get the benefits of automatic updates and +Steam cloud backups. In this case, install DFHack from Steam and then move your +DF installation into the Steam-created ``Dwarf Fortress`` directory. You have +to run DF via the DFHack app in the Steam client in order to benefit from the +Steam cloud backup features. + +If you download from GitHub, downloads are available at the bottom of the +release notes for each release, under a section named "Assets" (which you may +have to expand). The name of the file indicates which DF version, platform, and +architecture the build supports - the platform and architecture (64-bit or +32-bit) **must** match your build of DF. The DF version should also match your +DF version - see `above ` for details. For example: + +* ``dfhack-50.07-r1-Windows-64bit.zip`` supports 64-bit DF on Windows + +.. warning:: + + Do *not* download the source code from GitHub, either from the releases page + or by clicking "Download ZIP" on the repo homepage. This will give you an + incomplete copy of the DFHack source code, which will not work as-is. (If + you want to compile DFHack instead of using a pre-built release, please see + `building-dfhack-index` for instructions.) + +Beta releases +------------- + +In between stable releases, we may create beta releases to test new features. +These are available via the ``beta`` release channel on Steam or from our +regular Github page as a pre-release tagged with a "beta" or "rc" ("release +candidate") suffix. + +Development builds +------------------ + +If you are actively working with the DFHack team on testing a feature, you may +want to download and install a development build. They are available via the +``testing`` release channel on Steam or can be downloaded from the build +artifact list on GitHub for specific repository commits. + +To download a development build from GitHub: + +- Ensure you are logged into your GitHub account +- Go to https://github.com/DFHack/dfhack/actions/workflows/build.yml?query=branch%3Adevelop+event%3Apush+is%3Asuccess +- Click on the first entry (it should have a green checkmark next to it) +- Click the number under "Artifacts" (or scroll down) +- Click on the ``dfhack-*-build-*`` artifact for your platform to download + +The artifacts are "double-zipped". That is, you will have to extract the +initial zip file to get to the package archive. You can extract this second +package the same as if you are doing a manual install (see the next section). + +Older releases +-------------- + +If you are downloading DFHack for very old versions of DF, the binaries for +0.40.15-r1 to 0.34.11-r4 are on DFFD_. Even older versions are available here_. + +.. _DFFD: https://dffd.bay12games.com/search.php?string=DFHack&id=15&limit=1000 +.. _here: https://dethware.org/dfhack/download + +Installing DFHack +================= + +If you are installing from Steam, this is handled for you automatically. The +instructions here are for manual installs. + +When you `download DFHack `, you will end up with a release archive +(a ``.zip`` file on Windows, or a ``.tar.bz2`` file on other platforms). Your +operating system should have built-in utilities capable of extracting files from +these archives. + +.. note:: + + If you are on Windows, please remember to right click on the file after + downloading, open the file properties, and select the "Unblock" checkbox. + This will prevent issues with Windows antivirus programs. + +The release archives contain a ``hack`` folder where DFHack binary and system +data is stored, a ``stonesense`` folder that contains data specific to the +`stonesense` 3d renderer, and various libraries and executable files. To +install DFHack, copy all of the files from the DFHack archive into the root DF +folder, which should already include a ``data`` folder and a ``save`` folder, +among other things. Some redistributions of Dwarf Fortress may place DF in +another folder, so ensure that the ``hack`` folder ends up next to the ``data`` +folder, and you'll be fine. + +Installing into a wineskin on Mac +--------------------------------- + +Until DF (and DFHack) is natively available for Mac, you'll have to run the +Windows version under emulation. Here are the instructions for adding DFHack to +a wineskin that has DF installed in it: + +#. Find the location of your existing Dwarf Fortress app (default is + ``/user/applications/Wineskin/``). Control + click and select "Show package + contents" from the menu. +#. Find the location of the ``Dwarf Fortress`` folder inside the package + contents (default is ``/drive_c/Program Files/``) +#. Copy the contents of the unzipped DFHack folder (Windows version) into the + ``Dwarf Fortress`` folder inside the package. + +These instructions were last tested on Mac Sonoma 14.1.2. + +Uninstalling DFHack +=================== + +Just renaming or removing the ``dfhooks`` library files is enough to disable +DFHack. If you would like to remove all DFHack files, consult the DFHack install +archive to see the list of files and remove the corresponding files in the Dwarf +Fortress folder. Any DFHack files left behind will not negatively affect DF. + +On Steam, uninstalling DFHack will cleanly remove everything that was installed +with DFHack, so there is nothing else for you to do. + +Note that Steam will leave behind the ``dfhack-config`` folder, which contains +all your personal DFHack-related settings and data. If you keep this folder, +all your settings will be restored when you reinstall DFHack later. + +Upgrading DFHack +================ + +Again, if you have installed from Steam, your copy of DFHack will automatically +be kept up to date. This section is for manual installers. + +First, remove the ``hack`` and ``stonesense`` folders in their entirety. This +ensures that files that don't exist in the latest version are properly removed +and don't affect your new installation. + +Then, follow the instructions in the `Installing DFHack`_ section above, making +sure to choose to overwrite any remaining top-level files when extracting. diff --git a/docs/Introduction.rst b/docs/Introduction.rst new file mode 100644 index 0000000000..8f3506dad5 --- /dev/null +++ b/docs/Introduction.rst @@ -0,0 +1,111 @@ +.. _introduction: + +######################### +Introduction and overview +######################### + +DFHack is a Dwarf Fortress memory access library, distributed with +a wide variety of useful scripts and plugins. + +The project is hosted `on GitHub `__, +and can be downloaded from `the releases page `__ +-- see `installing` for installation instructions. This is also where the +`DFHack bug tracker `__ is hosted. If you would like +to download the DFHack documentation for offline viewing, you can do so by clicking +the expansion panel in the lower right corner of our +`online documentation `__ and selecting your desired format from +the "Downloads" section. + +New releases are announced in the +`DF subreddit `__, the +`DFHack Discord `__, and the +`Bay12 forums thread `__. Discussion and questions are also +welcome in each of these venues. + +For users, DFHack provides a significant suite of bugfixes and interface +enhancements by default, and more features can be enabled as desired. There are +also many tools (such as `autofarm`) which automate aspects of gameplay many players +find toilsome. You can even add third-party scripts and plugins to do almost anything! + +For modders, DFHack makes many things possible. Custom reactions, new +interactions, magic creature abilities, and more can be set through `tools` +and custom raws. 3rd party DFHack scripts can be distributed `in mods ` +via the DF Steam Workshop or on the forums. + +For developers, DFHack unites the various ways tools access DF memory and +allows easier development of new tools. As an open-source project under +`various open-source licenses `, contributions are welcome. + + +.. contents:: Contents + :local: + + +Getting started +=============== + +See `installing` for details about installing DFHack. + +Once DFHack is installed, it extends DF with a console that can be used to run +commands. The in-game version of this console is called `gui/launcher`, and you +can bring it up at any time by hitting the backtick (\`) key (on most keyboards +this is the same as the tilde (~) key). There are also external consoles you can +open in a separate window. On Windows, you can show this console with the `show` +command. On Linux and macOS, you will need to run the ``dfhack`` script from a +terminal, and that terminal will be used as the DFHack console. + +Basic interaction with DFHack involves entering commands into the console. To +learn what commands are available, you can keep reading this documentation or +skip ahead and use the `ls` and `help` commands. The first command you should +run is likely `gui/control-panel` so you can set up which tools you would like +to enable now and which tools you want automatically started for new games. + +Another way to interact with DFHack is to set in-game `keybindings ` +to run commands in response to a hotkey. If you have specific commands that you +run frequently and that don't already have default keybindings, this can be a +better option than adding the command to the `gui/quickcmd` list. + +Commands can also run at startup via `init files `, or in batches +at other times with the `script` command. + +Finally, some commands are persistent once enabled, and will sit in the +background managing or changing some aspect of the game if you `enable` them. + +.. note:: + In order to avoid user confusion, as a matter of policy all GUI tools + display the word :guilabel:`DFHack` on the screen somewhere while active. + + When that is not appropriate because they merely add keybinding hints to + existing DF screens, they surround the added text or clickable buttons in red + square brackets. + +For a more thorough introduction and guide through DFHack's capabilities, please see +the `quickstart`. + +.. _support: + +Getting help +============ + +DFHack has several ways to get help online, including: + +- The `DFHack Discord server `__ +- GitHub: + - for bugs, use the :issue:`issue tracker <>` + - for more open-ended questions, use the `discussion board + `__. Note that this is a + relatively-new feature as of 2021, but maintainers should still be + notified of any discussions here. +- The `DFHack thread on the Bay 12 Forum `__ +- The `/r/dwarffortress `__ questions thread on Reddit + +When reaching out to any support channels regarding problems with DFHack, please +remember to provide enough details for others to identify the issue. For +instance, specific error messages (copied text or screenshots) are helpful, as +well as any steps you can follow to reproduce the problem. Log output from +``stderr.log`` in the DF folder can often help point to the cause of issues. + +Some common questions may also be answered in documentation, including: + +- This documentation (`online here `__; search functionality available `here `) +- :wiki:`The DF wiki <>` diff --git a/docs/NEWS-dev.rst b/docs/NEWS-dev.rst new file mode 100644 index 0000000000..f77b1b4f51 --- /dev/null +++ b/docs/NEWS-dev.rst @@ -0,0 +1,20 @@ +.. comment + This is the changelog for development releases. Entries are included from + changelog.txt. + +.. _dev-changelog: + +##################### +Development changelog +##################### + +This file contains changes grouped by the release (stable or development) in +which they first appeared. See `build-changelog` for more information. + +See `changelog` for a list of changes grouped by stable releases. + +.. contents:: Contents + :local: + :depth: 1 + +.. include:: /docs/changelogs/news-dev.rst diff --git a/docs/NEWS.rst b/docs/NEWS.rst new file mode 100644 index 0000000000..41e64b339b --- /dev/null +++ b/docs/NEWS.rst @@ -0,0 +1,27 @@ +.. comment + This is the changelog for stable releases. Entries are included from + changelog.txt. + +.. _changelog: + +######### +Changelog +######### + +This file contains changes grouped by the stable release in which they first +appeared. See `build-changelog` for more information. + +See `dev-changelog` for a list of changes grouped by development releases. + +.. contents:: Contents + :local: + :depth: 1 + +.. include:: /docs/changelogs/news.rst + + +Older Changelogs +================ +Are kept in a separate file: `History` + +.. that's ``docs/about/History.rst``, if you're reading the raw text. diff --git a/docs/Quickstart.rst b/docs/Quickstart.rst new file mode 100644 index 0000000000..10d64e0bef --- /dev/null +++ b/docs/Quickstart.rst @@ -0,0 +1,239 @@ +.. _quickstart: + +Quickstart guide +================ + +Welcome to DFHack! This guide will help get you oriented with the DFHack system +and teach you how to find and use the tools productively. If you're reading this +in the in-game `quickstart-guide` reader, hit the right arrow key or click on +the hotkey hint in the lower right corner of the window to go to the next page. + +What is DFHack? +--------------- + +DFHack is an add-on for Dwarf Fortress that enables mods and tools to +significantly extend the game. The default DFHack distribution contains a wide +variety of these mods and tools, including bugfixes, interface improvements, +automation agents, design blueprints, modding building blocks, and more. +Third-party tools (e.g. mods downloaded from Steam Workshop or the forums) can +also seamlessly integrate with the DFHack framework and extend the game far +beyond what can be done by just modding the raws. + +DFHack's mission is to provide tools and interfaces for players and modders to: + +- expand the bounds of what is possible in Dwarf Fortress +- reduce the impact of game bugs +- give the player more agency and control over the game +- provide alternatives to toilsome or frustrating aspects of gameplay +- **make the game more fun** + +What can I do with DFHack tools? +-------------------------------- + +DFHack has been around for a long time -- almost as long as Dwarf Fortress +itself. Many of the game's rough edges have been smoothed with DFHack tools. +Here are some common tasks people use DFHack tools to accomplish: + +- Automatically chop trees when log stocks are low +- Mark all damaged items for trade in a single click +- Copy and paste fort layouts +- Import and export lists of manager orders +- Clean contaminants from map squares that dwarves can't reach +- Automatically butcher excess livestock so you don't become overrun with + animals +- Promote time-sensitive job types (e.g. food hauling) so they are done + expediently +- Quickly scan the map for visible ores of specific types so you can focus + your mining efforts + +Some tools are one-shot commands. For example, you can run +`unforbid all ` to claim all (reachable) items on the map after a +messy siege. + +Other tools must be `enabled ` once and then they will run in the +background. For example, once enabled, `seedwatch` will start monitoring your +stocks of seeds and prevent your chefs from cooking seeds that you need for +planting. Tools that are enabled in the context of a fort will save their state +with that fort, and they will remember that they are enabled the next time you +load your save. You can see which tools you have enabled and toggle their states +in `gui/control-panel`. + +A third class of tools adds information to the screen or provides new integrated +functionality via the DFHack `overlay` framework. For example, the `sort` tool +adds widgets to the squad member selection screen that allow you to sort and +filter the list of military candidates. You don't have to run any command to get +the benefits of the tool, it appears automatically when you're on the relevant +screen. + +How can I figure out which commands to run? +------------------------------------------- + +There are several ways to scan DFHack tools and find the ones you need right +now. + +The first place to check is the DFHack logo menu. It's in the upper left corner +of the screen by default, though you can move it anywhere you want with the +`gui/overlay` configuration UI. + +When you click on the logo (or hit the Ctrl-Shift-C keyboard shortcut), a short +list of popular, relevant DFHack tools comes up. These are the tools that have +been assigned hotkeys that are active in the current context. For example, when +you're looking at a fort map, the list will contain fortress design tools like +`gui/quickfort` and `gui/design`. You can click on the tools in the list, or +note the hotkeys listed next to them and maybe use them to launch the tool next +time without even opening the logo menu. + +The second place to check is the DFHack control panel: `gui/control-panel`. It +will give you an overview of which tools are currently enabled, and will allow +you to toggle tools on or off, see help text for them, or launch their +dedicated configuration UIs. You can open the control panel from anywhere with +the Ctrl-Shift-E hotkey or by selecting it from the logo menu list. + +In the control panel, you can also select which tools you'd like to be +automatically enabled and popular commands you'd like to run when you start a +new fort. On the "Preferences" tab, there are settings you can change, like +"mortal mode" (you'll learn more about this in the next section) or whether you +want DFHack windows to pause the game when they come up. + +Finally, you can explore the full extent of the DFHack catalog in +`gui/launcher`, which is always listed first in the DFHack logo menu list. You +can bring up the launcher by tapping the backtick key (\`) or hitting +Ctrl-Shift-D. In the launcher, you can quickly autocomplete any command name by +selecting it in the list on the right side of the window. You can filter the list +by command tag, for example, you can see only productivity tools by setting the +"productivity" tag to "include" in the filter panel. Commands are ordered by how +often you run them, so your favorite commands will always be on top. You can +also pull full commandlines out of your history with Alt-S or by clicking on the +"history search" button. + +Once you have typed (or autocompleted, or searched for) a command, other +commands related to the one you have selected will appear in the right-hand +panel. Scanning through that list is a great way to learn about new tools that +you might find useful. + +The bottom panel will show the full help text for the command you are running, +allowing you to refer to the usage documentation and examples when you are +typing your command. After you run a command, the bottom panel switches to +command output mode, but you can get back to the help text by hitting Ctrl-T or +clicking on the ``Help`` tab. + +What if I don't want to be tempted by god-mode tools? +----------------------------------------------------- + +DFHack can give you god-like powers over the game. Sometimes, this is necessary +to recover from game-breaking bugs. Sometimes, this is desirable so players can +create specific role playing environments and situations. Sometimes, this is just +fun : ) + +But sometimes the knowledge that you can just "Armok" your way out of trouble +detracts from the game experience. If this is the way you feel, you can hide +DFHack's god-mode tools -- they all have the tag "armok" -- from the game. Open +`gui/control-panel` and go to the "Preferences" tab. Enable "Mortal mode" to +hide all "armok" tools. You can still access them in `gui/launcher` if you type +their names in full, but they won't show up in autocomplete lists, in the output +of `ls`, or anywhere else. Any global hotkeys that run "armok" tools will be +disabled. + +How do DFHack in-game windows work? +----------------------------------- + +Many DFHack tools have graphical interfaces that appear in-game. You can tell +which windows belong to DFHack tools because they will have the word "DFHack" +printed across their bottom frame edge. DFHack provides an advanced windowing +system that gives the player a lot of control over where the windows appear and +whether they capture keyboard and mouse input. + +The DFHack windowing system allows multiple overlapping windows to be active at +once. The one with the highlighted title bar has focus and will receive anything +you type at the keyboard. Hit Esc or right click to close the window or cancel +the current action. You can click anywhere on the screen that is not a DFHack +window to unfocus the window and let it just sit in the background. It won't +respond to key presses or mouse clicks until you click on it again to give it +focus. If no DFHack windows are focused, you can right click directly on a +window to close it without left clicking to focus it first. + +DFHack windows are draggable from the title bar or from anywhere on the window +that doesn't have a mouse-clickable widget on it. Many are resizable as well +(if the tool window has components that can reasonably be resized). + +You can generally use DFHack tools without interrupting the game. That is, if +the game is unpaused, it can continue to run while a DFHack window is open. If +configured to do so in `gui/control-panel`, tools will initially pause the game +to let you focus on the task at hand, but you can unpause like normal if you +want. You can also interact with the map, scrolling it with the keyboard or +mouse and selecting units, buildings, and items. Some tools, like +`gui/blueprint`, will intercept all mouse clicks to allow you to select regions +of the map. When these tools have focus, you will not be able to use the mouse +to interact with map elements or pause/unpause the game. Therefore, these tools +will pause the game when they open, regardless of your settings in +`gui/control-panel`. You can still unpause with the keyboard (spacebar by +default), though. + +Where do I go next? +------------------- + +To recap: + +You can get to popular, relevant tools for the current context by clicking on +the DFHack logo or by hitting Ctrl-Shift-C. + +You can enable DFHack tools and configure settings with `gui/control-panel`, +which you can open from the DFHack logo or access directly with the +Ctrl-Shift-E hotkey. + +You can get to the launcher and its integrated autocomplete, history search, +and help text by hitting backtick (\`) or Ctrl-Shift-D, or, of course, by +running it from the logo menu list. + +With those three interfaces, you have the complete DFHack tool suite at your +fingertips. So what to run first? Here are a few examples to get you started. + +First, let's import some useful manager orders to keep your fort stocked with +basic necessities. Run ``orders import library/basic``. If you go to your +manager orders screen, you can see all the orders that have been created for +you. Note that you could have imported the orders directly from this screen as +well, using the DFHack `overlay` widget at the bottom of the manager orders +panel. + +Next, try setting up `autochop` to automatically designate trees for chopping +when you get low on usable logs. Run `gui/control-panel` and enable +``autochop`` in the ``Automation`` -> ``Enabled`` tab. Click on the button to +the left of the name or hit Enter to enable it. You can then click on the +configure button (the gear icon) to launch `gui/autochop` if you'd like to +customize its settings (the defaults are usually fine). If you have the extra +screen space, you can go ahead and set the `gui/autochop` window to minimal +mode (click on the button near the upper right corner of the window or hit +Alt-M) and click on the map so the window loses keyboard focus. As you play +the game, you can glance at the live status panel to check on your stocks of +wood. + +Finally, let's do some fort design copy-pasting. Go to some bedrooms that you +have set up in your fort. Run `gui/blueprint`, set a name for your blueprint by +clicking on the name field (or hitting the 'n' hotkey). Type "rooms" (or +whatever) and hit Enter to set. Then draw a box around the target area by +clicking with the mouse. When you select the second corner, the blueprint will +be saved to your ``dfhack-config/blueprints`` subfolder. + +Now open up `gui/quickfort` (the hotkey is Ctrl-Shift-Q). You can search for the +blueprint you just created by typing its name, but it should be up near the top +already. If you copied a dug-out area with furniture in it, you will see two +blueprints with the labels "/dig" and "/build". Click on the "/dig" blueprint or +select it with the keyboard arrow keys and hit Enter. You can rotate or flip the +blueprint around if you need to with the transform hotkeys. You'll see a preview +of where the blueprint will be applied as you move the mouse cursor around the +map. Red outlines mean that the blueprint may fail to fully apply at that +location, so be sure to choose a spot where all the preview tiles are shown with +green diamonds. Click the mouse or hit Enter to apply the blueprint and +designate the tiles for digging. Your dwarves will come and dig it out as if you +had designated the tiles yourself. + +Once the area is dug out, run `gui/quickfort` again and select the "/build" +blueprint this time. Hit ``o`` to generate manager orders for the required +furniture. Click to apply the blueprint in the dug-out area, and your furniture +will be designated. It's just that easy! Note that `quickfort` uses +`buildingplan` to place buildings, so you don't even need to have the relevant +furniture or building materials in stock yet. The planned furniture/buildings +will get built whenever you are able to produce the building materials. + +There are many, many more tools to explore. Poke around or ask other player for +advice. Have fun, and dig deep! diff --git a/docs/Tags.rst b/docs/Tags.rst new file mode 100644 index 0000000000..55bfde977b --- /dev/null +++ b/docs/Tags.rst @@ -0,0 +1,52 @@ +:orphan: + +.. _tag-list: + +DFHack tool tags +================ + +A tool often has at least one tag per group, encompassing when you use the tool, +why you might want to use it, and what kind of thing you're trying to affect. + +See https://docs.google.com/spreadsheets/d/1hiDlo8M_bB_1jE-5HRs2RrrA_VZ4cRu9VXaTctX_nwk/edit#gid=1774645373 +for the tag assignment spreadsheet. + +"when" tags +----------- +- `adventure `: Tools that are useful while in adventure mode. +- `dfhack `: Tools that you use to run DFHack commands or interact with the DFHack or DF system. +- `embark `: Tools that are useful while on the fort embark screen or while creating an adventurer. +- `fort `: Tools that are useful while in fort mode. +- `legends `: Tools that are useful while in legends mode. + +"why" tags +---------- +- `armok `: Tools which give the player god-like powers or the ability to access information the game intentionally keeps hidden. Players that do not wish to see these tools can hide them in the ``Preferences`` tab of `gui/control-panel`. +- `auto `: Tools that run in the background and automatically manage routine, toilsome aspects of your fortress. +- `bugfix `: Tools that fix specific bugs, either permanently or on-demand. +- `design `: Tools that help you with fort layout. +- `dev `: Tools that are useful when debugging or developing mods. +- `fps `: Tools that help you prevent impact to your FPS. +- `gameplay `: Tools that introduce new gameplay elements. +- `inspection `: Tools that let you view information that is otherwise difficult to find. +- `productivity `: Tools that help you perform common tasks quickly and easily. + +"what" tags +----------- +- `animals `: Tools that interact with animals. +- `buildings `: Tools that interact with buildings and furniture. +- `graphics `: Tools that interact with game graphics. +- `interface `: Tools that interact with or extend the DF user interface. +- `items `: Tools that interact with in-game items. +- `jobs `: Tools that interact with jobs. +- `labors `: Tools that deal with labor assignment. +- `map `: Tools that interact with the game map. +- `military `: Tools that interact with the military. +- `plants `: Tools that interact with grass, trees, shrubs, and crops. +- `stockpiles `: Tools that interact with stockpiles. +- `units `: Tools that interact with units. +- `workorders `: Tools that interact with workorders. + +"misc" tags +----------- +- `unavailable `: Tools that are not yet available for the current release. diff --git a/docs/Tools.rst b/docs/Tools.rst new file mode 100644 index 0000000000..67d7edc54b --- /dev/null +++ b/docs/Tools.rst @@ -0,0 +1,69 @@ +.. _tools: + +DFHack tools +============ + +DFHack comes with **a lot** of tools. This page attempts to make it clearer +what they are, how they work, and how to find the ones you want. + +.. contents:: Contents + :local: + +What tools are and how they work +-------------------------------- + +DFHack is a Dwarf Fortress memory access and modification framework, so DFHack +tools normally access Dwarf Fortress internals and make some specific changes. + +Some tools just make a targeted change when you run them, like `unforbid`, which +scans through all your items and removes the ``forbidden`` flag from each of +them. + +Some tools need to be enabled, and then they run in the background and make +changes to the game on your behalf, like `autobutcher`, which monitors your +livestock population and automatically marks excess animals for butchering. + +And some tools just exist to give you information that is otherwise hard to +come by, like `gui/petitions`, which shows you the active petitions for +guildhalls and temples that you have agreed to. + +Finding the tool you need +------------------------- + +DFHack tools are tagged with categories to make them easier to find. These +categories are listed in the next few sections. Note that a tool can belong to +more than one category. If you already know what you're looking for, try the +`search` or Ctrl-F on this page. If you'd like to see the full list of tools in +one flat list, please refer to the `annotated index `. + +Some tools are part of our back catalog and haven't been updated yet for v50 of +Dwarf Fortress. These tools are tagged as +`unavailable `. They will still appear in the +alphabetical list at the bottom of this page, but unavailable tools will not +listed in any of the indices. + +DFHack tools by game mode +------------------------- + +.. include:: tags/bywhen.rst + +DFHack tools by theme +--------------------- + +.. include:: tags/bywhy.rst + +DFHack tools by what they affect +-------------------------------- + +.. include:: tags/bywhat.rst + +All DFHack tools alphabetically +------------------------------- + +.. toctree:: + :glob: + :maxdepth: 1 + :titlesonly: + + tools/* + tools/*/* diff --git a/docs/about/Authors.rst b/docs/about/Authors.rst new file mode 100644 index 0000000000..a154d314b6 --- /dev/null +++ b/docs/about/Authors.rst @@ -0,0 +1,274 @@ +List of authors +=============== +The following is a list of people who have contributed to DFHack, in +alphabetical order. + +If you should be here and aren't, please get in touch on Discord or the forums, +or make a pull request! + +======================= ======================= =========================== +Name Github Other +======================= ======================= =========================== +8Z 8Z +Abel abstern +acwatkins acwatkins +Aleksandr Glotov glotov4 +Alex Blamey Cubittus +Alexander Collins gearsix +Alexander Gavrilov angavrilov ag +Amber Brown hawkowl +Amostubal Amostubal +Andrea Cattaneo acattaneo88 +AndreasPK AndreasPK +Andriel Chaoti AndrielChaoti +Angus Mezick amezick +Antalia tamarakorr +Anuradha Dissanayake falconne +Ariphaos Ariphaos +arzyu arzyu +Atkana Atkana +AtomicChicken AtomicChicken +Batt Mush hobotron-df +Bearskie Bearskie +belal jimhester +Ben Lubar BenLubar +Ben Rosser TC01 +Benjamin McKenna britishben +Benjamin Seiller bseiller RedDwarfStepper +billw2012 billw2012 +BrickViking brickviking +brndd brndd burneddi +Caldfir caldfir +Cameron Ewell Ozzatron +Carter Bray Qartar +Chris Dombroski cdombroski +Chris Parsons chrismdp +Christian Doczkal chdoc +cjhammel cjhammel +Clayton Hughes +Clément Vuchener cvuchener +Corey CoreyJ87 +daedsidog daedsidog +Dan Amlund danamlund +Daniel Brooks db48x +David Nilsolm +David Corbett dscorbett +David Seguin dseguin +David Timm dtimm +Dean Golden LightHardt +Deon +dhthwy dhthwy +dikbutdagrate Tjudge1 +Dmitrii Kurkin Kurkin +DoctorVanGogh DoctorVanGogh +Donald Ruegsegger hashaash +doomchild doomchild +Droseran Droseran +dvantwisk dvantwisk +DwarvenM DwarvenM +Eamon Bode eamondo2 Baron Von Munchhausen +EarthPulseAcademy EarthPulseAcademy +ElMendukol ElMendukol +ElsaTheHobo ElsaTheHobo Elsa +enjia2000 +Eric Wald eswald +Erik Youngren Artanis +Espen Wiborg +expwnent expwnent +Feng +figment figment +Gabe Rau gaberau +Gaelmare Gaelmare +gchristopher gchristopher +George Murray GitOnUp +grubsteak grubsteak +Guilherme Abraham GuilhermeAbraham +Harlan Playford playfordh +Hayati Ayguen hayguen +Herwig Hochleitner bendlas +Hevlikn Hevlikn +Ian S kremlin- +IndigoFenix +Jacek Konieczny Jajcus +James 20k +James Gilles kazimuth +James Logsdon jlogsdon +Janeene Beeforth dawnmist +Jared Adams +Jeremy Apthorp nornagon +Jim Lisi stonetoad +Jimbo Whales jimbowhales +jimcarreer jimcarreer +jj jjyg jj\`\` +Joel Meador janxious +John Beisley huin +John Cosker johncosker +John Shade gsvslto +Johnny Fisher jfisher446 JohnnyWing +Jonas Ask +Jonathan Clark AridTag +Josh Cooper cppcooper coope +jowario jowario +kane-t kane-t +Kelly Kinkade ab9rf +Kelvie Wong kelvie +Kib Arekatír arekatir +KlonZK KlonZK +Kris Parker kaypy +Kristjan Moore kristjanmoore +Kromtec Kromtec +Kurik Amudnil +Kévin Boissonneault KABoissonneault +Lethosor lethosor +LordGolias LordGolias +Mark Nielson pseudodragon +Mason11987 Mason11987 +Matt Regul mattregul +Matthew Cline +Matthew Lindner mlindner +Matthew Taylor ymber yutna +Max maxthyme Max^TM +Maxim Verkhov nibirubingus +McArcady McArcady +melkor217 melkor217 +Meneth32 +Meph +Michael Casadevall NCommander +Michael Crouch creidieki +Michon van Dooren MaienM +miffedmap miffedmap +Mike Stewart thewonderidiot +Mikhail Panov Halifay +Mikko Juola Noeda Adeon +Milo Christiansen milochristiansen +MithrilTuxedo MithrilTuxedo +mizipzor mizipzor +moversti moversti +mrrho mrrho +Murad Beybalaev Erquint +Myk Taylor myk002 +Najeeb Al-Shabibi master-spike +napagokc napagokc +Neil Little nmlittle +Nicholas McDaniel NicksWorld +Nick Rart nickrart comestible +Nicolas Ayala nicolasayala +Nik Nyby nikolas +Nikolay Amiantov abbradar +nocico nocico +NotRexButCaesar NotRexButCaesar +Nuno Fernandes UnknowableCoder +nuvu vallode +Omniclasm +Ong Ying Gao ong-yinggao98 +oorzkws oorzkws +OwnageIsMagic OwnageIsMagic +pajawojciech pajawojciech +palenerd dlmarquis +PassionateAngler PassionateAngler +Patrik Lundell PatrikLundell +Paul Fenwick pjf +PeridexisErrant PeridexisErrant +Peter Hansen previsualconsent +Petr Mrázek peterix +Pfhreak Pfhreak +Pierre Lulé plule +Pierre-David Bélanger pierredavidbelanger +PopnROFL PopnROFL +potato +ppaawwll ppaawwll 🐇🐇🐇🐇 +Priit Laes plaes +Przemysław Skrobot frogi16 +psychowico wiktor-obrebski +Putnam Putnam3145 +quarque2 quarque2 +Quietust quietust _Q +Rafał Karczmarczyk CarabusX +Raidau Raidau +Ralph Bisschops ralpha +Ramblurr Ramblurr +rampaging-poet +Raoul van Putten +Raoul XQ raoulxq +reverb +Rich Rauenzahn rrauenza +Rinin Rinin +rndmvar rndmvar +Rob Bailey actionninja +Rob Goodberry robob27 +Robert Heinrich rh73 +Robert Janetzko robertjanetzko +Rocco Moretti roccomoretti +RocheLimit +rofl0r rofl0r +root +Rose RosaryMala +Roses Pheosics +Ross M RossM +rout +Roxy TealSeer gallowsCalibrator +rubybrowncoat rubybrowncoat +Rumrusher rumrusher +RusAnon RusAnon +Ryan Bennitt ryanbennitt +Ryan Dwyer ToxicBananaParty Jimdude2435 +Ryan Williams Bumber64 Bumber +sami +scamtank scamtank +Scott Ellis StormCrow42 +Sebastian Wolfertz Enkrod +SeerSkye SeerSkye +seishuuu seishuuu +Seth Woodworth sethwoodworth +shevernitskiy shevernitskiy +Shim Panze Shim-Panze +Silver silverflyone +simon +Simon Jackson sizeak +Simon Lees simotek +Squid Coder realSquidCoder +stolencatkarma +Stoyan Gaydarov sgayda2 +Su Moth-Tolias +suokko suokko shrieker +sv-esk sv-esk +Tachytaenius wolfboyft +Tacomagic +tatoyoda600 tatoyoda600 +TaxiService TaxiService +terribleperson terribleperson +thefriendlyhacker thefriendlyhacker +TheHologram TheHologram +Theo Kalfas teolandon +therahedwig therahedwig +ThiagoLira ThiagoLira +thurin thurin +Tim Siegel softmoth +Tim Walberg twalberg +Timothy Collett danaris +Timothy Torres timothymtorres +Timur Kelman TymurGubayev +Tom Jobbins TheBloke +Tom Prince +Tommy R tommy +TotallyGatsby TotallyGatsby +Travis Hoppe thoppe orthographic-pedant +txtsd txtsd +U-glouglou\\simon +Valentin Ochs Cat-Ion +Varnavskii Aleksandr Crystalwarrior +Vitaly Pronkin pronvit mifki +ViTuRaS ViTuRaS +Vjek vjek +Vladimir Florov foxxelias +Warmist warmist +Wes Malone wesQ3 +Will H TSM-EVO +Will Rogers wjrogers +WoosterUK WoosterUK +XianMaeve XianMaeve +ZechyW ZechyW +Zhentar Zhentar +zilpin zilpin +Zishi Wu zishiwu123 +======================= ======================= =========================== diff --git a/docs/about/History.rst b/docs/about/History.rst new file mode 100644 index 0000000000..4bd4ec6429 --- /dev/null +++ b/docs/about/History.rst @@ -0,0 +1,3979 @@ +:orphan: + +.. _History: + +##################### +Historical changelogs +##################### + +This file is where old changelogs live, so the `current changelog ` +doesn't get too long. Some of these changelogs are also formatted differently +from current changelogs and would be difficult for the current `changelog +generation system ` to handle. + +.. contents:: Contents + :local: + :depth: 1 + +DFHack 0.47.05-r8 +================= + +New Plugins +----------- +- `channel-safely`: auto-manage channel designations to keep dwarves safe +- `overlay`: plugin is transformed from a single line of text that runs `gui/launcher` on click to a fully-featured overlay injection framework. It now houses a popup menu for keybindings relevant to the current DF screen, all the widgets previously provided by `dwarfmonitor` (e.g. the current date and number of happy/unhappy dwarves), the overlay that highlights suspended buildings when you pause, and others. See `overlay-dev-guide` for details. + +New Scripts +----------- +- `gui/overlay`: configuration interface for the DFHack overlays and overlay widgets. includes a click-and-drag interface for repositioning widgets! + +Fixes +----- +- Core: ensure ``foo.init`` always runs before ``foo.*.init`` (e.g. ``dfhack.init`` should always run before ``dfhack.something.init``) +- `autofarm`: flush output so status text is visible immediately after running the command +- `autolabor`, `autohauler`: properly handle jobs 241, 242, and 243 +- `automaterial`: + - fix the cursor jumping up a z level when clicking quickly after box select + - fix rendering errors with box boundary markers +- `buildingplan`: fix crash when canceling out of placement mode for a building with planning mode enabled and subsequently attempting to place a building that does not have planning mode enabled and that has no pertinent materials available +- `dwarf-op`: fixed error when matching dwarves by name +- `gui/create-item`: prevent materials list filter from intercepting sublist hotkeys +- `gui/gm-unit`: fixed behavior of ``+`` and ``-`` to adjust skill values instead of populating the search field +- `hotkeys`: correctly detect hotkeys bound to number keys, F11, and F12 +- `labormanager`: associate quern construction with the correct labor +- `mousequery`: fix the cursor jumping up z levels sometimes when using TWBT +- `tiletypes`: no longer resets dig priority to the default when updating other properties of a tile +- `warn-stealers`: + - register callback with correct event name so that units entering the map are detected + - announce thieving creatures that spawn already revealed + - cache unit IDs instead of unit objects to avoid referencing stale pointers +- `workorder`: fix interpretation of json-specified orders that set the ``item_type`` field +- ``EventManager``: + - fix a segmentation fault with the ``REPORT`` event + - fix the ``JOB_STARTED`` event only sending events to the first handler listed instead of all registered handlers + +Misc Improvements +----------------- +- UX: + - List widgets now have mouse-interactive scrollbars + - You can now hold down the mouse button on a scrollbar to make it scroll multiple times. + - You can now drag the scrollbar up and down to scroll to a specific spot +- `autolabor`, `autohauler`: refactored to use DFHack's messaging system for info/debug/trace messages +- `blueprint`: + - new ``--smooth`` option for recording all smoothed floors and walls instead of just the ones that require smoothing for later carving + - record built constructions in blueprints + - record stockpile/building/zone names in blueprints + - record room sizes in blueprints + - generate meta blueprints to reduce the number of blueprints you have to apply + - support splitting the output file into phases grouped by when they can be applied + - when splitting output files, number them so they sort into the order you should apply them in +- `digtype`: new ``-z`` option for digtype to restrict designations to the current z-level and down +- `dwarfmonitor`: widgets have been ported to the overlay framework and can be enabled and configured via the `gui/overlay` UI +- `gui/blueprint`: support new blueprint phases and options +- `gui/cp437-table`: new global keybinding for the clickable on-screen keyboard for players with keyboard layouts that prevent them from using certain keys: Ctrl-Shift-K +- `gui/create-item`: restrict materials to those normally allowed by the game by default, introduce new ``--unrestricted`` option for full freedom in choosing materials +- `gui/launcher`: show help for commands that start with ':' (like ``:lua``) +- `gui/quantum`: add option to allow corpses and refuse in your quantum stockpile +- `hotkeys`: + - hotkey screen has been transformed into an interactive `overlay` widget that you can bring up by moving the mouse cursor over the hotspot (in the upper left corner of the screen by default). Enable/disable/reposition the hotspot in the `gui/overlay` UI. Even if the hotspot is disabled, the menu can be brought up at any time with the Ctrl-Shift-C hotkey. + - now supports printing active hotkeys to the console with ``hotkeys list`` +- `ls`: + - indent tag listings and wrap them in the rightmost column for better readability + - new ``--exclude`` option for hiding matched scripts from the output. this can be especially useful for modders who don't want their mod scripts to be included in ``ls`` output. +- `modtools/create-unit`: better unit naming, more argument checks, assign nemesis save data for units without civilization so they can be properly saved when offloaded +- `orders`: replace shell craft orders in the standard orders list you get with ``orders import library/basic`` with orders for shell leggings. They have a slightly higher trade price. Also, "shleggings" is just hilarious. +- `quickfort-library-guide`: improved layout of marksdwarf barracks in the example Dreamfort blueprints +- `spectate`: + - new ``auto-unpause`` option for auto-dismissal of announcement pause events (e.g. sieges). + - new ``auto-disengage`` option for auto-disengagement of plugin through player interaction whilst unpaused. + - new ``tick-threshold`` option for specifying the maximum time to follow the same dwarf + - new ``animals`` option for sometimes following animals + - new ``hostiles`` option for sometimes following hostiles + - new ``visiting`` option for sometimes following visiting merchants, diplomats or plain visitors + - added persistent configuration of the plugin settings +- `unsuspend`: new `overlay` for displaying status of suspended buildings (functionality migrated from removed `resume` plugin) + +Documentation +------------- +- `overlay-dev-guide`: documentation and guide for injecting functionality into DF viewscreens from Lua scripts and creating interactive overlay widgets +- ``dfhack.gui.revealInDwarfmodeMap``: document ``center`` bool for Lua API + +Removed +------- +- `gui/create-item`: removed ``--restricted`` option. it is now the default behavior +- `resume`: functionality (including suspended building overlay) has moved to `unsuspend` + +API +--- +- Constructions module: added ``insert()`` to insert constructions into the game's sorted list. +- MiscUtils: added the following string transformation functions (refactored from ``uicommon.h``): ``int_to_string``, ``ltrim``, ``rtrim``, and ``trim``; added ``string_to_int`` +- Units module: + - added new predicates for: + - ``isUnitInBox()`` + - ``isAnimal()`` + - ``isVisiting()`` any visiting unit (diplomat, merchant, visitor) + - ``isVisitor()`` ie. not merchants or diplomats + - ``isInvader()`` + - ``isDemon()`` returns true for unique/regular demons + - ``isTitan()`` + - ``isMegabeast()`` + - ``isGreatDanger()`` returns true if unit is a demon, titan, or megabeast + - ``isSemiMegabeast()`` + - ``isNightCreature()`` + - ``isDanger()`` returns true if is a 'GreatDanger', semi-megabeast, night creature, undead, or invader + - modified predicates: + - ``isUndead()`` now optionally ignores vampires instead of always ignoring vampires + - ``isCitizen()`` now optionally ignores insane citizens instead of always ignoring insane citizens + - new action timer API for speeding up of slowing down units +- ``Gui::anywhere_hotkey``: for plugin commands bound to keybindings that can be invoked on any screen +- ``Gui::autoDFAnnouncement``, ``Gui::pauseRecenter``: added functionality reverse-engineered from announcement code +- ``Gui::revealInDwarfmodeMap``: Now enforce valid view bounds when pos invalid, add variant accepting x, y, z +- ``Lua::Push()``: now handles maps with otherwise supported keys and values +- ``Lua::PushInterfaceKeys()``: transforms viewscreen ``feed()`` keys into something that can be interpreted by lua-based widgets + +Internals +--------- +- Constructions module: ``findAtTile`` now uses a binary search instead of a linear search +- MSVC warning level upped to /W3, and /WX added to make warnings cause compilations to fail. + +Lua +--- +- Lua mouse events now conform to documented behavior in `lua-api` -- ``_MOUSE_L_DOWN`` will be sent exactly once per mouse click and ``_MOUSE_L`` will be sent repeatedly as long as the button is held down. Similarly for right mouse button events. +- ``dfhack.constructions.findAtTile()``: exposed preexisting function to Lua. +- ``dfhack.constructions.insert()``: exposed new function to Lua. +- ``gui.Screen.show()``: now returns ``self`` as a convenience +- ``gui.View.getMousePos()`` now takes an optional ``ViewRect`` parameter in case the caller wants to get the mouse pos relative to a rect that is not the frame_body (such as the frame_rect that includes the frame itself) +- ``widgets.EditField``: now allows other widgets to process characters that the ``on_char`` callback rejects. +- ``widgets.FilteredList``: now provides a useful default search key for list items made up of text tokens instead of plain text +- ``widgets.HotkeyLabel``: now ignores mouse clicks when ``on_activate`` is not defined +- ``widgets.List``: + - new ``getIdxUnderMouse()`` function for detecting the list index under the active mouse cursor. this allows for "selection follows mouse" behavior + - shift-clicking now triggers the ``submit2`` attribute function if it is defined +- ``widgets.Panel``: new ``frame_style`` and ``frame_title`` attributes for drawing frames around groups of widgets +- ``widgets.ResizingPanel``: now accounts for frame inset when calculating frame size +- ``widgets.Scrollbar``: new scrollbar widget that can be paired with an associated scrollable widget. Integrated with ``widgets.Label`` and ``widgets.List``. + +Structures +---------- +- ``general_refst``: type virtual union member for ``ITEM_GENERAL`` +- ``historical_figure_info.T_reputation.unk_2c``: identify ``year`` + ``year_ticks`` +- ``itemst``: identify two vmethods related to adding thread improvements to items made of cloth, and label several previously unknown return types +- ``proj_magicst``: correct structure fields (to match 40d) +- ``unit_action_type_group``: added enum and tagged ``unit_action_type`` entries with its groups for DFHack's new action timer API. +- ``world``: identify type of a vector (still not known what it's for, but it's definitely an item vector) + + +DFHack 0.47.05-r7 +================= + +New Plugins +----------- +- `autobutcher`: split off from `zone` into its own plugin. Note that to enable, the command has changed from ``autobutcher start`` to ``enable autobutcher``. +- `autonestbox`: split off from `zone` into its own plugin. Note that to enable, the command has changed from ``autonestbox start`` to ``enable autonestbox``. +- `overlay`: display a "DFHack" button in the lower left corner that you can click to start the new GUI command launcher. The `dwarfmonitor` weather display had to be moved to make room for the button. If you are seeing the weather indicator rendered over the overlay button, please remove the ``dfhack-config/dwarfmonitor.json`` file to fix the weather indicator display offset. + +New Scripts +----------- +- `gui/kitchen-info`: adds more info to the Kitchen screen +- `gui/launcher`: in-game command launcher with autocomplete, history, and context-sensitive help +- `gui/workorder-details`: adjusts work orders' input item, material, traits +- `max-wave`: dynamically limit the next immigration wave, can be set to repeat +- `pop-control`: persistent per fortress population cap, `hermit`, and `max-wave` management +- `warn-stealers`: warn when creatures that may steal your food, drinks, or items become visible + +New Internal Commands +--------------------- +- `tags`: new built-in command to list the tool category tags and their definitions. tags associated with each tool are visible in the tool help and in the output of `ls`. + +Fixes +----- +- `autochop`: designate largest trees for chopping first, instead of the smallest +- `devel/query`: fixed error when --tile is specified +- `dig-now`: Fix direction of smoothed walls when adjacent to a door or floodgate +- `dwarf-op`: fixed error when applying the Miner job to dwarves +- `emigration`: fix emigrant logic so unhappy dwarves leave as designed +- `gui/gm-unit`: allow ``+`` and ``-`` to adjust skill values as intended instead of letting the filter intercept the characters +- `gui/unit-info-viewer`: fix logic for displaying undead creature names +- `gui/workflow`: restore functionality to the add/remove/order hotkeys on the workflow status screen +- `modtools/moddable-gods`: fixed an error when assigning spheres +- `quickfort`: `Dreamfort ` blueprint set: declare the hospital zone before building the coffer; otherwise DF fails to stock the hospital with materials +- `view-item-info`: fixed a couple errors when viewing items without materials +- ``dfhack.buildings.findCivzonesAt``: no longer return duplicate civzones after loading a save with existing civzones +- ``dfhack.run_script``: ensure the arguments passed to scripts are always strings. This allows other scripts to call ``run_script`` with numeric args and it won't break parameter parsing. +- ``job.removeJob()``: ensure jobs are removed from the world list when they are canceled + +Misc Improvements +----------------- +- History files: ``dfhack.history``, ``tiletypes.history``, ``lua.history``, and ``liquids.history`` have moved to the ``dfhack-config`` directory. If you'd like to keep the contents of your current history files, please move them to ``dfhack-config``. +- Init scripts: ``dfhack.init`` and other init scripts have moved to ``dfhack-config/init/``. If you have customized your ``dfhack.init`` file and want to keep your changes, please move the part that you have customized to the new location at ``dfhack-config/init/dfhack.init``. If you do not have changes that you want to keep, do not copy anything, and the new defaults will be used automatically. +- UX: + - You can now move the cursor around in DFHack text fields in ``gui/`` scripts (e.g. `gui/blueprint`, `gui/quickfort`, or `gui/gm-editor`). You can move the cursor by clicking where you want it to go with the mouse or using the Left/Right arrow keys. Ctrl+Left/Right will move one word at a time, and Alt+Left/Right will move to the beginning/end of the text. + - You can now click on the hotkey hint text in many ``gui/`` script windows to activate the hotkey, like a button. Not all scripts have been updated to use the clickable widget yet, but you can try it in `gui/blueprint` or `gui/quickfort`. + - Label widget scroll icons are replaced with scrollbars that represent the percentage of text on the screen and move with the position of the visible text, just like web browser scrollbars. +- `devel/query`: + - inform the user when a query has been truncated due to ``--maxlength`` being hit. + - increased default maxlength value from 257 to 2048 +- `do-job-now`: new global keybinding for boosting the priority of the jobs associated with the selected building/work order/unit/item etc.: Alt-N +- `dwarf-op`: replaces [ a b c ] option lists with a,b,c option lists +- `gui/gm-unit`: don't clear the list filter when you adjust a skill value +- `gui/quickfort`: + - better formatting for the generated manager orders report + - you can now click on the map to move the blueprint anchor point to that tile instead of having to use the cursor movement keys + - display an error message when the blueprints directory cannot be found +- `gui/workorder-details`: new keybinding on the workorder details screen: ``D`` +- `keybinding`: support backquote (\`) as a hotkey (and assign the hotkey to the new `gui/launcher` interface) +- `ls`: can now filter tools by substring or tag. note that dev scripts are hidden by default. pass the ``--dev`` option to show them. +- `manipulator`: + - add a library of useful default professions + - move professions configuration from ``professions/`` to ``dfhack-config/professions/`` to keep it together with other dfhack configuration. If you have saved professions that you would like to keep, please manually move them to the new folder. +- `orders`: added useful library of manager orders. see them with ``orders list`` and import them with, for example, ``orders import library/basic`` +- `prioritize`: new ``defaults`` keyword to prioritize the list of jobs that the community agrees should generally be prioritized. Run ``prioritize -a defaults`` to try it out in your fort! +- `prospect`: add new ``--show`` option to give the player control over which report sections are shown. e.g. ``prospect all --show ores`` will just show information on ores. +- `quickfort`: + - `Dreamfort ` blueprint set improvements: set traffic designations to encourage dwarves to eat cooked food instead of raw ingredients + - library blueprints are now included by default in ``quickfort list`` output. Use the new ``--useronly`` (or just ``-u``) option to filter out library blueprints. + - better error message when the blueprints directory cannot be found +- `seedwatch`: ``seedwatch all`` now adds all plants with seeds to the watchlist, not just the "basic" crops. +- ``materials.ItemTraitsDialog``: added a default ``on_select``-handler which toggles the traits. + +Documentation +------------- +- Added `modding-guide` +- Group DFHack tools by `tag ` so similar tools are grouped and easy to find +- Update all DFHack tool documentation (300+ pages) with standard syntax formatting, usage examples, and overall clarified text. + +Removed +------- +- `fix/build-location`: The corresponding DF bug (5991) was fixed in DF 0.40.05 +- `fix/diplomats`: DF bug 3295 fixed in 0.40.05 +- `fix/fat-dwarves`: DF bug 5971 fixed in 0.40.05 +- `fix/feeding-timers`: DF bug 2606 is fixed in 0.40.12 +- `fix/merchants`: DF bug that prevents humans from making trade agreements has been fixed +- `gui/assign-rack`: No longer useful in current DF versions +- `gui/hack-wish`: Replaced by `gui/create-item` +- `gui/no-dfhack-init`: No longer useful since players don't have to create their own ``dfhack.init`` files anymore + +API +--- +- Removed "egg" ("eggy") hook support (Linux only). The only remaining method of hooking into DF is by interposing SDL calls, which has been the method used by all binary releases of DFHack. +- Removed ``Engravings`` module (C++-only). Access ``world.engravings`` directly instead. +- Removed ``Notes`` module (C++-only). Access ``ui.waypoints.points`` directly instead. +- Removed ``Windows`` module (C++-only) - unused. +- ``Constructions`` module (C++-only): removed ``t_construction``, ``isValid()``, ``getCount()``, ``getConstruction()``, and ``copyConstruction()``. Access ``world.constructions`` directly instead. +- ``Gui::getSelectedItem()``, ``Gui::getAnyItem()``: added support for the artifacts screen +- ``Units::teleport()``: now sets ``unit.idle_area`` to discourage units from walking back to their original location (or teleporting back, if using `fastdwarf`) + +Lua +--- +- Added ``dfhack.screen.hideGuard()``: exposes the C++ ``Screen::Hide`` to Lua +- History: added ``dfhack.getCommandHistory(history_id, history_filename)`` and ``dfhack.addCommandToHistory(history_id, history_filename, command)`` so gui scripts can access a commandline history without requiring a terminal. +- ``helpdb``: database and query interface for DFHack tool help text +- ``tile-material``: fix the order of declarations. The ``GetTileMat`` function now returns the material as intended (always returned nil before). Also changed the license info, with permission of the original author. +- ``utils.df_expr_to_ref()``: fixed some errors that could occur when navigating tables +- ``widgets.CycleHotkeyLabel``: clicking on the widget will now cycle the options and trigger ``on_change()``. This also applies to the ``ToggleHotkeyLabel`` subclass. +- ``widgets.EditField``: + - new ``onsubmit2`` callback attribute is called when the user hits Shift-Enter. + - new function: ``setCursor(position)`` sets the input cursor. + - new attribute: ``ignore_keys`` lets you ignore specified characters if you want to use them as hotkeys +- ``widgets.FilteredList``: new attribute: ``edit_ignore_keys`` gets passed to the filter EditField as ``ignore_keys`` +- ``widgets.HotkeyLabel``: clicking on the widget will now call ``on_activate()``. +- ``widgets.Label``: ``scroll`` function now interprets the keywords ``+page``, ``-page``, ``+halfpage``, and ``-halfpage`` in addition to simple positive and negative numbers. + +Structures +---------- +- Eliminate all "anon_X" names from structure fields +- ``army``: change ``squads`` vector type to ``world_site_inhabitant``, identify ``min_smell_trigger``+``max_odor_level``+``max_low_light_vision``+``sense_creature_classes`` +- ``cave_column_rectangle``: identify coordinates +- ``cave_column``: identify Z coordinates +- ``embark_profile``: identify reclaim fields, add missing pet_count vector +- ``entity_population``: identify ``layer_id`` +- ``feature``: identify "shiftCoords" vmethod, ``irritation_level`` and ``irritation_attacks`` fields +- ``flow_guide``: identify "shiftCoords" vmethod +- ``general_refst``: name parameters on ``getLocation`` and ``setLocation`` vmethods +- ``general_ref_locationst``: name member fields +- ``historical_entity``: confirm ``hostility_level`` and ``siege_tier`` +- ``item``: identify method ``notifyCreatedMasterwork`` that is called when a masterwork is created. +- ``language_name_type``: identify ``ElfTree`` and ``SymbolArtifice`` thru ``SymbolFood`` +- ``misc_trait_type``: update auto-decrement markers, remove obsolete references +- ``timed_event``: identify ``layer_id`` +- ``ui_advmode``: identify several fields as containing coordinates +- ``ui_build_selector``: identify ``cur_walk_tag`` and ``min_weight_races``+``max_weight_races`` +- ``ui``: identify actual contents of ``unk5b88`` field, identify infiltrator references +- ``unitst``: identify ``histeventcol_id`` field inside status2 +- ``viewscreen_barterst``: name member fields +- ``viewscreen_tradegoodsst``: rename trade_reply ``OffendedAnimal``+``OffendedAnimalAlt`` to ``OffendedBoth``+``OffendedAnimal`` +- ``world_site_inhabitant``: rename ``outcast_id`` and ``founder_outcast_entity_id``, identify ``interaction_id`` and ``interaction_effect_idx`` + + +DFHack 0.47.05-r6 +================= + +New Scripts +----------- +- `assign-minecarts`: automatically assign minecarts to hauling routes that don't have one +- `deteriorate`: combines, replaces, and extends previous `deteriorateclothes`, `deterioratecorpses`, and `deterioratefood` scripts. +- `gui/petitions`: shows petitions. now you can see which guildhall/temple you agreed to build! +- `gui/quantum`: point-and-click tool for creating quantum stockpiles +- `gui/quickfort`: shows blueprint previews on the live map so you can apply them interactively +- `modtools/fire-rate`: allows modders to adjust the rate of fire for ranged attacks + +Fixes +----- +- `build-now`: walls built above other walls can now be deconstructed like regularly-built walls +- `eventful`: + - fix ``eventful.registerReaction`` to correctly pass ``call_native`` argument thus allowing canceling vanilla item creation. Updated related documentation. + - renamed NEW_UNIT_ACTIVE event to UNIT_NEW_ACTIVE to match the ``EventManager`` event name + - fixed UNIT_NEW_ACTIVE event firing too often +- `gui/dfstatus`: no longer count items owned by traders +- `gui/unit-info-viewer`: fix calculation/labeling of unit size +- ``job.removeJob()``: fixes regression in DFHack 0.47.05-r5 where items/buildings associated with the job were not getting disassociated when the job is removed. Now `build-now` can build buildings and `gui/mass-remove` can cancel building deconstruction again +- ``widgets.CycleHotkeyLabel``: allow initial option values to be specified as an index instead of an option value + +Misc Improvements +----------------- +- `build-now`: buildings that were just designated with `buildingplan` are now built immediately (as long as there are items available to build the buildings with) instead of being skipped until buildingplan gets around to doing its regular scan +- `caravan`: new ``unload`` command, fixes endless unloading at the depot by reconnecting merchant pack animals that were disconnected from their owners +- `confirm`: + - added a confirmation dialog for removing manager orders + - allow players to pause the confirmation dialog until they exit the current screen +- `deteriorate`: new ``now`` command immediately deteriorates items of the specified types +- `dfhack-examples-guide`: + - refine food preparation orders so meal types are chosen intelligently according to the amount of meals that exist and the number of available items to cook with + - reduce required stock of dye for "Dye cloth" orders + - fix material conditions for making jugs and pots + - make wooden jugs by default to differentiate them from other stone tools. this allows players to more easily select jugs out with a properly-configured stockpile (i.e. the new ``woodentools`` alias) +- `list-agreements`: now displays translated guild names, worshipped deities, petition age, and race-appropriate professions (e.g. "Craftsdwarf" instead of "Craftsman") +- `quickfort-alias-guide`: + - new aliases: ``forbidsearch``, ``permitsearch``, and ``togglesearch`` use the `search-plugin` plugin to alter the settings for a filtered list of item types when configuring stockpiles + - new aliases: ``stonetools`` and ``woodentools``. the ``jugs`` alias is deprecated. please use ``stonetools`` instead, which is the same as the old ``jugs`` alias. + - new aliases: ``usablehair``, ``permitusablehair``, and ``forbidusablehair`` alter settings for the types of hair/wool that can be made into cloth: sheep, llama, alpaca, and troll. The ``craftrefuse`` aliases have been altered to use this alias as well. + - new aliases: ``forbidthread``, ``permitthread``, ``forbidadamantinethread``, ``permitadamantinethread``, ``forbidcloth``, ``permitcloth``, ``forbidadamantinecloth``, and ``permitadamantinecloth`` give you more control how adamantine-derived items are stored +- `quickfort`: + - `Dreamfort ` blueprint set improvements: automatically create tavern, library, and temple locations (restricted to residents only by default), automatically associate the rented rooms with the tavern + - `Dreamfort ` blueprint set improvements: new design for the services level, including were-bitten hospital recovery rooms and an appropriately-themed interrogation room next to the jail! Also fits better in a 1x1 embark for minimalist players. +- `workorder`: a manager is no longer required for orders to be created (matching behavior in the game itself) + +Removed +------- +- `deteriorateclothes`: please use ``deteriorate --types=clothes`` instead +- `deterioratecorpses`: please use ``deteriorate --types=corpses`` instead +- `deterioratefood`: please use ``deteriorate --types=food`` instead +- `devel/unforbidall`: please use `unforbid` instead. You can silence the output with ``unforbid all --quiet`` + +API +--- +- ``word_wrap``: argument ``bool collapse_whitespace`` converted to enum ``word_wrap_whitespace_mode mode``, with valid modes ``WSMODE_KEEP_ALL``, ``WSMODE_COLLAPSE_ALL``, and ``WSMODE_TRIM_LEADING``. + +Lua +--- +- ``gui.View``: all ``View`` subclasses (including all ``Widgets``) can now acquire keyboard focus with the new ``View:setFocus()`` function. See docs for details. +- ``materials.ItemTraitsDialog``: new dialog to edit item traits (where "item" is part of a job or work order or similar). The list of traits is the same as in vanilla work order conditions "``t`` change traits". +- ``widgets.EditField``: + - the ``key_sep`` string is now configurable + - can now display an optional string label in addition to the activation key + - views that have an ``EditField`` subview no longer need to manually manage the ``EditField`` activation state and input routing. This is now handled automatically by the new ``gui.View`` keyboard focus subsystem. +- ``widgets.HotkeyLabel``: the ``key_sep`` string is now configurable + +Structures +---------- +- ``art_image_elementst``: identify vmethod ``markDiscovered`` and second parameter for ``getName2`` +- ``art_image_propertyst``: identify parameters for ``getName`` +- ``building_handler``: fix vmethod ``get_machine_hookup_list`` parameters +- ``vermin``: identify ``category`` field as new enum +- ``world.unk_26a9a8``: rename to ``allow_announcements`` + + +DFHack 0.47.05-r5 +================= + +New Plugins +----------- +- `spectate`: "spectator mode" -- automatically follows dwarves doing things in your fort + +New Scripts +----------- +- `devel/eventful-client`: useful for testing eventful events + +New Tweaks +---------- +- `tweak`: ``partial-items`` displays percentage remaining for partially-consumed items such as hospital cloth + +Fixes +----- +- `autofarm`: removed restriction on only planting "discovered" plants +- `cxxrandom`: fixed exception when calling ``bool_distribution`` +- `devel/query`: + - fixed a problem printing parents when the starting path had lua pattern special characters in it + - fixed a crash when trying to iterate over linked lists +- `gui/advfort`: encrust and stud jobs no longer consume reagents without actually improving the target item +- `luasocket`: return correct status code when closing socket connections so clients can know when to retry +- `quickfort`: constructions and bridges are now properly placed over natural ramps +- `setfps`: keep internal ratio of processing FPS to graphics FPS in sync when updating FPS + +Misc Improvements +----------------- +- `autochop`: + - only designate the amount of trees required to reach ``max_logs`` + - preferably designate larger trees over smaller ones +- `autonick`: + - now displays help instead of modifying dwarf nicknames when run without parameters. use ``autonick all`` to rename all dwarves. + - added ``--quiet`` and ``--help`` options +- `blueprint`: + - ``track`` phase renamed to ``carve`` + - carved fortifications and (optionally) engravings are now captured in generated blueprints +- `cursecheck`: new option, ``--ids`` prints creature and race IDs of the cursed creature +- `debug`: + - DFHack log messages now have configurable headers (e.g. timestamp, origin plugin name, etc.) via the ``debugfilter`` command of the `debug` plugin + - script execution log messages (e.g. "Loading script: dfhack_extras.init" can now be controlled with the ``debugfilter`` command. To hide the messages, add this line to your ``dfhack.init`` file: ``debugfilter set Warning core script`` +- `dfhack-examples-guide`: + - add mugs to ``basic`` manager orders + - ``onMapLoad_dreamfort.init`` remove "cheaty" commands and new tweaks that are now in the default ``dfhack.init-example`` file +- `dig-now`: handle fortification carving +- `EventManager`: + - add new event type ``JOB_STARTED``, triggered when a job first gains a worker + - add new event type ``UNIT_NEW_ACTIVE``, triggered when a new unit appears on the active list +- `gui/blueprint`: support new `blueprint` options and phases +- `gui/create-item`: Added "(chain)" annotation text for armours with the [CHAIN_METAL_TEXT] flag set +- `manipulator`: tweak colors to make the cursor easier to locate +- `quickfort`: + - support transformations for blueprints that use expansion syntax + - adjust direction affinity when transforming buildings (e.g. bridges that open to the north now open to the south when rotated 180 degrees) + - automatically adjust cursor movements on the map screen in ``#query`` and ``#config`` modes when the blueprint is transformed. e.g. ``{Up}`` will be played back as ``{Right}`` when the blueprint is rotated clockwise and the direction key would move the map cursor + - new blueprint mode: ``#config``; for playing back key sequences that don't involve the map cursor (like configuring hotkeys, changing standing orders, or modifying military uniforms) + - API function ``apply_blueprint`` can now take ``data`` parameters that are simple strings instead of coordinate maps. This allows easier application of blueprints that are just one cell. +- `stocks`: allow search terms to match the full item label, even when the label is truncated for length +- `tweak`: ``stable-cursor`` now keeps the cursor stable even when the viewport moves a small amount +- ``dfhack.init-example``: recently-added tweaks added to example ``dfhack.init`` file + +Documentation +------------- +- add more examples to the plugin example skeleton files so they are more informative for a newbie +- update download link and installation instructions for Visual C++ 2015 build tools on Windows +- update information regarding obtaining a compatible Windows build environment +- `confirm`: correct the command name in the plugin help text +- `cxxrandom`: added usage examples +- `lua-string`: document DFHack string extensions (``startswith()``, ``endswith()``, ``split()``, ``trim()``, ``wrap()``, and ``escape_pattern()``) +- `quickfort-blueprint-guide`: added screenshots to the Dreamfort case study and overall clarified text +- `remote-client-libs`: add new Rust client library +- ``Lua API.rst``: added ``isHidden(unit)``, ``isFortControlled(unit)``, ``getOuterContainerRef(unit)``, ``getOuterContainerRef(item)`` + +API +--- +- add functions reverse-engineered from ambushing unit code: ``Units::isHidden()``, ``Units::isFortControlled()``, ``Units::getOuterContainerRef()``, ``Items::getOuterContainerRef()`` +- ``Job::removeJob()``: use the job cancel vmethod graciously provided by The Toady One in place of a synthetic method derived from reverse engineering + +Lua +--- +- `custom-raw-tokens`: library for accessing tokens added to raws by mods +- ``dfhack.units``: Lua wrappers for functions reverse-engineered from ambushing unit code: ``isHidden(unit)``, ``isFortControlled(unit)``, ``getOuterContainerRef(unit)``, ``getOuterContainerRef(item)`` +- ``dialogs``: ``show*`` functions now return a reference to the created dialog +- ``dwarfmode.enterSidebarMode()``: passing ``df.ui_sidebar_mode.DesignateMine`` now always results in you entering ``DesignateMine`` mode and not ``DesignateChopTrees``, even when you looking at the surface (where the default designation mode is ``DesignateChopTrees``) +- ``dwarfmode.MenuOverlay``: + - if ``sidebar_mode`` attribute is set, automatically manage entering a specific sidebar mode on show and restoring the previous sidebar mode on dismiss + - new class function ``renderMapOverlay`` to assist with painting tiles over the visible map +- ``ensure_key``: new global function for retrieving or dynamically creating Lua table mappings +- ``safe_index``: now properly handles lua sparse tables that are indexed by numbers +- ``string``: new function ``escape_pattern()`` escapes regex special characters within a string +- ``widgets``: + - unset values in ``frame_inset`` table default to ``0`` + - ``FilteredList`` class now allows all punctuation to be typed into the filter and can match search keys that start with punctuation + - minimum height of ``ListBox`` dialog is now calculated correctly when there are no items in the list (e.g. when a filter doesn't match anything) + - if ``autoarrange_subviews`` is set, ``Panel``\s will now automatically lay out widgets vertically according to their current height. This allows you to have widgets dynamically change height or become visible/hidden and you don't have to worry about recalculating frame layouts + - new class ``ResizingPanel`` (subclass of ``Panel``) automatically recalculates its own frame height based on the size, position, and visibility of its subviews + - new class ``HotkeyLabel`` (subclass of ``Label``) that displays and reacts to hotkeys + - new class ``CycleHotkeyLabel`` (subclass of ``Label``) allows users to cycle through a list of options by pressing a hotkey + - new class ``ToggleHotkeyLabel`` (subclass of ``CycleHotkeyLabel``) toggles between ``On`` and ``Off`` states + - new class ``WrappedLabel`` (subclass of ``Label``) provides autowrapping of text + - new class ``TooltipLabel`` (subclass of ``WrappedLabel``) provides tooltip-like behavior + +Structures +---------- +- ``adventure_optionst``: add missing ``getUnitContainer`` vmethod +- ``historical_figure.T_skills``: add ``account_balance`` field +- ``job``: add ``improvement`` field (union with ``hist_figure_id`` and ``race``) +- ``report_init.flags``: rename ``sparring`` flag to ``hostile_combat`` +- ``viewscreen_loadgamest``: add missing ``LoadingImageSets`` and ``LoadingDivinationSets`` enum values to ``cur_step`` field + + +DFHack 0.47.05-r4 +================= + +Fixes +----- +- `blueprint`: + - fixed passing incorrect parameters to `gui/blueprint` when you run ``blueprint gui`` with optional params + - key sequences for constructed walls and down stairs are now correct +- `exportlegends`: fix issue where birth year was outputted as birth seconds +- `quickfort`: + - produce a useful error message instead of a code error when a bad query blueprint key sequence leaves the game in a mode that does not have an active cursor + - restore functionality to the ``--verbose`` commandline flag + - don't designate tiles for digging if they are within the bounds of a planned or constructed building + - allow grates, bars, and hatches to be built on flat floor (like DF itself allows) + - allow tracks to be built on hard, natural rock ramps + - allow dig priority to be properly set for track designations + - fix incorrect directions for tracks that extend south or east from a track segment pair specified with expansion syntax (e.g. T(4x4)) + - fix parsing of multi-part extended zone configs (e.g. when you set custom supply limits for hospital zones AND set custom flags for a pond) + - fix error when attempting to set a custom limit for plaster powder in a hospital zone +- `tailor`: fixed some inconsistencies (and possible crashes) when parsing certain subcommands, e.g. ``tailor help`` +- `tiletypes-here`, `tiletypes-here-point`: fix crash when running from an unsuspended core context + +Misc Improvements +----------------- +- Core: DFHack now prints the name of the init script it is running to the console and stderr +- `automaterial`: ensure construction tiles are laid down in order when using `buildingplan` to plan the constructions +- `blueprint`: + - all blueprint phases are now written to a single file, using `quickfort` multi-blueprint file syntax. to get the old behavior of each phase in its own file, pass the ``--splitby=phase`` parameter to ``blueprint`` + - you can now specify the position where the cursor should be when the blueprint is played back with `quickfort` by passing the ``--playback-start`` parameter + - generated blueprints now have labels so `quickfort` can address them by name + - all building types are now supported + - multi-type stockpiles are now supported + - non-rectangular stockpiles and buildings are now supported + - blueprints are no longer generated for phases that have nothing to do (unless those phases are explicitly enabled on the commandline or gui) + - new "track" phase that discovers and records carved tracks + - new "zone" phase that discovers and records activity zones, including custom configuration for ponds, gathering, and hospitals +- `dig-now`: no longer leaves behind a designated tile when a tile was designated beneath a tile designated for channeling +- `gui/blueprint`: + - support the new ``--splitby`` and ``--format`` options for `blueprint` + - hide help text when the screen is too short to display it +- `orders`: added ``list`` subcommand to show existing exported orders +- `quickfort-library-guide`: added light aquifer tap and pump stack blueprints (with step-by-step usage guides) to the quickfort blueprint library +- `quickfort`: + - Dreamfort blueprint set improvements: added iron and flux stock level indicators on the industry level and a prisoner processing quantum stockpile in the surface barracks. also added help text for how to manage sieges and how to manage prisoners after a siege. + - add ``quickfort.apply_blueprint()`` API function that can be called directly by other scripts + - by default, don't designate tiles for digging that have masterwork engravings on them. quality level to preserve is configurable with the new ``--preserve-engravings`` param + - implement single-tile track aliases so engraved tracks can be specified tile-by-tile just like constructed tracks + - allow blueprints to jump up or down multiple z-levels with a single command (e.g. ``#>5`` goes down 5 levels) + - blueprints can now be repeated up and down a specified number of z-levels via ``repeat`` markers in meta blueprints or the ``--repeat`` commandline option + - blueprints can now be rotated, flipped, and shifted via ``transform`` and ``shift`` markers in meta blueprints or the corresponding commandline options +- `quickfort`, `dfhack-examples-guide`: Dreamfort blueprint set improvements based on playtesting and feedback. includes updated profession definitions. + +Removed +------- +- `digfort`: please use `quickfort` instead +- `fortplan`: please use `quickfort` instead + +API +--- +- ``Buildings::findCivzonesAt()``: lookups now complete in constant time instead of linearly scanning through all civzones in the game + +Lua +--- +- ``argparse.processArgsGetopt()``: you can now have long form parameters that are not an alias for a short form parameter. For example, you can now have a parameter like ``--longparam`` without needing to have an equivalent one-letter ``-l`` param. +- ``dwarfmode.enterSidebarMode()``: ``df.ui_sidebar_mode.DesignateMine`` is now a supported target sidebar mode + +Structures +---------- +- ``historical_figure_info.spheres``: give spheres vector a usable name +- ``unit.enemy``: fix definition of ``enemy_status_slot`` and add ``combat_side_id`` + + +DFHack 0.47.05-r3 +================= + +New Plugins +----------- +- `dig-now`: instantly completes dig designations (including smoothing and carving tracks) + +New Scripts +----------- +- `autonick`: gives dwarves unique nicknames +- `build-now`: instantly completes planned building constructions +- `do-job-now`: makes a job involving current selection high priority +- `prioritize`: automatically boosts the priority of current and/or future jobs of specified types, such as hauling food, tanning hides, or pulling levers +- `reveal-adv-map`: exposes/hides all world map tiles in adventure mode + +Fixes +----- +- Core: ``alt`` keydown state is now cleared when DF loses and regains focus, ensuring the ``alt`` modifier state is not stuck on for systems that don't send standard keyup events in response to ``alt-tab`` window manager events +- Lua: ``memscan.field_offset()``: fixed an issue causing `devel/export-dt-ini` to crash sometimes, especially on Windows +- `autofarm`: autofarm will now count plant growths as well as plants toward its thresholds +- `autogems`: no longer assigns gem cutting jobs to workshops with gem cutting prohibited in the workshop profile +- `devel/export-dt-ini`: fixed incorrect vtable address on Windows +- `quickfort`: + - allow machines (e.g. screw pumps) to be built on ramps just like DF allows + - fix error message when the requested label is not found in the blueprint file + +Misc Improvements +----------------- +- `assign-beliefs`, `assign-facets`: now update needs of units that were changed +- `buildingplan`: now displays which items are attached and which items are still missing for planned buildings +- `devel/query`: + - updated script to v3.2 (i.e. major rewrite for maintainability/readability) + - merged options ``-query`` and ``-querykeys`` into ``-search`` + - merged options ``-depth`` and ``-keydepth`` into ``-maxdepth`` + - replaced option ``-safer`` with ``-excludetypes`` and ``-excludekinds`` + - improved how tile data is dealt with identification, iteration, and searching + - added option ``-findvalue`` + - added option ``-showpaths`` to print full data paths instead of nested fields + - added option ``-nopointers`` to disable printing values with memory addresses + - added option ``-alignto`` to set the value column's alignment + - added options ``-oneline`` and alias ``-1`` to avoid using two lines for fields with metadata + - added support for matching multiple patterns + - added support for selecting the highlighted job, plant, building, and map block data + - added support for selecting a Lua script (e.g. `dorf_tables`) + - added support for selecting a Json file (e.g. dwarf_profiles.json) + - removed options ``-listall``, ``-listfields``, and ``-listkeys`` - these are now simply default behaviour + - ``-table`` now accepts the same abbreviations (global names, ``unit``, ``screen``, etc.) as `lua` and `gui/gm-editor` +- `dorf_tables`: integrated `devel/query` to show the table definitions when requested with ``-list`` +- `geld`: fixed ``-help`` option +- `gui/gm-editor`: made search case-insensitive +- `orders`: + - support importing and exporting reaction-specific item conditions, like "lye-containing" for soap production orders + - new ``sort`` command. sorts orders according to their repeat frequency. this prevents daily orders from blocking other orders for similar items from ever getting completed. +- `quickfort`: + - Dreamfort blueprint set improvements: extensive revision based on playtesting and feedback. includes updated ``onMapLoad_dreamfort.init`` settings file, enhanced automation orders, and premade profession definitions. see full changelog at https://github.com/DFHack/dfhack/pull/1921 and https://github.com/DFHack/dfhack/pull/1925 + - accept multiple commands, list numbers, and/or blueprint labels on a single commandline +- `tailor`: allow user to specify which materials to be used, and in what order +- `tiletypes-here`, `tiletypes-here-point`: add ``--cursor`` and ``--quiet`` options to support non-interactive use cases +- `unretire-anyone`: replaced the 'undead' descriptor with 'reanimated' to make it more mod-friendly +- `warn-starving`: added an option to only check sane dwarves + +Documentation +------------- +- `dfhack-examples-guide`: documentation for all of `dreamfort`'s supporting files (useful for all forts, not just Dreamfort!) +- `quickfort-library-guide`: updated dreamfort documentation and added screenshots + +API +--- +- The ``Items`` module ``moveTo*`` and ``remove`` functions now handle projectiles + +Internals +--------- +- Install tests in the scripts repo into hack/scripts/test/scripts when the CMake variable BUILD_TESTS is defined + +Lua +--- +- new global function: ``safe_pairs(iterable[, iterator_fn])`` will iterate over the ``iterable`` (a table or iterable userdata) with the ``iterator_fn`` (``pairs`` if not otherwise specified) if iteration is possible. If iteration is not possible or would throw an error, for example if ``nil`` is passed as the ``iterable``, the iteration is just silently skipped. + +Structures +---------- +- ``cursed_tomb``: new struct type +- ``job_item``: identified several fields +- ``ocean_wave_maker``: new struct type +- ``worldgen_parms``: moved to new struct type + + +DFHack 0.47.05-r2 +================= + +New Scripts +----------- +- `clear-webs`: removes all webs on the map and/or frees any webbed creatures +- `devel/block-borders`: overlay that displays map block borders +- `devel/luacov`: generate code test coverage reports for script development. Define the ``DFHACK_ENABLE_LUACOV=1`` environment variable to start gathering coverage metrics. +- `fix/drop-webs`: causes floating webs to fall to the ground +- `gui/blueprint`: interactive frontend for the `blueprint` plugin (with mouse support!) +- `gui/mass-remove`: mass removal/suspension tool for buildings and constructions +- `reveal-hidden-sites`: exposes all undiscovered sites +- `set-timeskip-duration`: changes the duration of the "Updating World" process preceding the start of a new game, enabling you to jump in earlier or later than usual + +Fixes +----- +- Fixed an issue preventing some external scripts from creating zones and other abstract buildings (see note about room definitions under "Internals") +- Fixed an issue where scrollable text in Lua-based screens could prevent other widgets from scrolling +- `bodyswap`: + - stopped prior party members from tagging along after bodyswapping and reloading the map + - made companions of bodyswapping targets get added to the adventurer party - they can now be viewed using the in-game party system +- `buildingplan`: + - fixed an issue where planned constructions designated with DF's sizing keys (``umkh``) would sometimes be larger than requested + - fixed an issue preventing other plugins like `automaterial` from planning constructions if the "enable all" buildingplan setting was turned on + - made navigation keys work properly in the materials selection screen when alternate keybindings are used +- `color-schemes`: fixed an error in the ``register`` subcommand when the DF path contains certain punctuation characters +- `command-prompt`: fixed issues where overlays created by running certain commands (e.g. `gui/liquids`, `gui/teleport`) would not update the parent screen correctly +- `dwarfvet`: fixed a crash that could occur with hospitals overlapping with other buildings in certain ways +- `embark-assistant`: fixed faulty early exit in first search attempt when searching for waterfalls +- `gui/advfort`: fixed an issue where starting a workshop job while not standing at the center of the workshop required advancing time manually +- `gui/unit-info-viewer`: fixed size description displaying unrelated values instead of size +- `orders`: fixed crash when importing orders with malformed IDs +- `quickfort`: + - comments in blueprint cells no longer prevent the rest of the row from being read. A cell with a single '#' marker in it, though, will still stop the parser from reading further in the row. + - fixed an off-by-one line number accounting in blueprints with implicit ``#dig`` modelines + - changed to properly detect and report an error on sub-alias params with no values instead of just failing to apply the alias later (if you really want an empty value, use ``{Empty}`` instead) + - improved handling of non-rectangular and non-solid extent-based structures (like fancy-shaped stockpiles and farm plots) + - fixed conversion of numbers to DF keycodes in ``#query`` blueprints + - fixed various errors with cropping across the map edge + - properly reset config to default values in ``quickfort reset`` even if if the ``dfhack-config/quickfort/quickfort.txt`` config file doesn't mention all config vars. Also now works even if the config file doesn't exist. +- `stonesense`: fixed a crash that could occur when ctrl+scrolling or closing the Stonesense window +- ``quickfortress.csv`` blueprint: fixed refuse stockpile config and prevented stockpiles from covering stairways + +Misc Improvements +----------------- +- Added adjectives to item selection dialogs, used in tools like `gui/create-item` - this makes it possible to differentiate between different types of high/low boots, shields, etc. (some of which are procedurally generated) +- `blueprint`: + - made ``depth`` and ``name`` parameters optional. ``depth`` now defaults to ``1`` (current level only) and ``name`` defaults to "blueprint" + - ``depth`` can now be negative, which will result in the blueprints being written from the highest z-level to the lowest. Before, blueprints were always written from the lowest z-level to the highest. + - added the ``--cursor`` option to set the starting coordinate for the generated blueprints. A game cursor is no longer necessary if this option is used. +- `devel/annc-monitor`: added ``report enable|disable`` subcommand to filter combat reports +- `embark-assistant`: slightly improved performance of surveying and improved code a little +- `gui/advfort`: added workshop name to workshop UI +- `quickfort`: + - the Dreamfort blueprint set can now be comfortably built in a 1x1 embark + - added the ``--cursor`` option for running a blueprint at specific coordinates instead of starting at the game cursor position + - added more helpful error messages for invalid modeline markers + - added support for extra space characters in blueprints + - added a warning when an invalid alias is encountered instead of silently ignoring it + - made more quiet when the ``--quiet`` parameter is specified +- `setfps`: improved error handling +- `stonesense`: sped up startup time +- `tweak` hide-priority: changed so that priorities stay hidden (or visible) when exiting and re-entering the designations menu +- `unretire-anyone`: the historical figure selection list now includes the ``SYN_NAME`` (necromancer, vampire, etc) of figures where applicable + +Documentation +------------- +- Added more client library implementations to the `remote interface docs ` + +API +--- +- Added ``dfhack.maps.getPlantAtTile(x, y, z)`` and ``dfhack.maps.getPlantAtTile(pos)``, and updated ``dfhack.gui.getSelectedPlant()`` to use it +- Added ``dfhack.units.teleport(unit, pos)`` + +Internals +--------- +- Room definitions and extents are now created for abstract buildings so callers don't have to initialize the room structure themselves +- The DFHack test harness is now much easier to use for iterative development. Configuration can now be specified on the commandline, there are more test filter options, and the test harness can now easily rerun tests that have been run before. +- The ``test/main`` command to invoke the test harness has been renamed to just ``test`` +- Unit tests can now use ``delay_until(predicate_fn, timeout_frames)`` to delay until a condition is met +- Unit tests must now match any output expected to be printed via ``dfhack.printerr()`` +- Unit tests now support fortress mode (allowing tests that require a fortress map to be loaded) - note that these tests are skipped by continuous integration for now, pending a suitable test fortress + +Lua +--- +- new library: ``argparse`` is a collection of commandline argument processing functions +- new string utility functions: + - ``string:wrap(width)`` wraps a string at space-separated word boundaries + - ``string:trim()`` removes whitespace characters from the beginning and end of the string + - ``string:split(delimiter, plain)`` splits a string with the given delimiter and returns a table of substrings. if ``plain`` is specified and set to ``true``, ``delimiter`` is interpreted as a literal string instead of as a pattern (the default) +- new utility function: ``utils.normalizePath()``: normalizes directory slashes across platforms to ``/`` and coalesces adjacent directory separators +- `reveal`: now exposes ``unhideFlood(pos)`` functionality to Lua +- `xlsxreader`: added Lua class wrappers for the xlsxreader plugin API +- ``argparse.processArgsGetopt()`` (previously ``utils.processArgsGetopt()``): + - now returns negative numbers (e.g. ``-10``) in the list of positional parameters instead of treating it as an option string equivalent to ``-1 -0`` + - now properly handles ``--`` like GNU ``getopt`` as a marker to treat all further parameters as non-options + - now detects when required arguments to long-form options are missing +- ``gui.dwarfmode``: new function: ``enterSidebarMode(sidebar_mode, max_esc)`` which uses keypresses to get into the specified sidebar mode from whatever the current screen is +- ``gui.Painter``: fixed error when calling ``viewport()`` method + +Structures +---------- +- Identified remaining rhythm beat enum values +- ``ui_advmode.interactions``: identified some fields related to party members +- ``ui_advmode_menu``: identified several enum items +- ``ui_advmode``: + - identified several fields + - renamed ``wait`` to ``rest_mode`` and changed to an enum with correct values +- ``viewscreen_legendsst.cur_page``: added missing ``Books`` enum item, which fixes some other values + + +DFHack 0.47.05-r1 +================= + +Fixes +----- +- `confirm`: stopped exposing alternate names when convicting units +- `prospector`: improved pre embark rough estimates, particularly for small clusters + +Misc Improvements +----------------- +- `autohauler`: allowed the ``Alchemist`` labor to be enabled in `manipulator` and other labor screens so it can be used for its intended purpose of flagging that no hauling labors should be assigned to a dwarf. Before, the only way to set the flag was to use an external program like Dwarf Therapist. +- `embark-assistant`: slightly improved performance of surveying +- `gui/no-dfhack-init`: clarified how to dismiss dialog that displays when no ``dfhack.init`` file is found +- `quickfort`: + - Dreamfort blueprint set improvements: `significant `_ refinements across the entire blueprint set. Dreamfort is now much faster, much more efficient, and much easier to use. The `checklist `__ now includes a mini-walkthrough for quick reference. The spreadsheet now also includes `embark profile suggestions `__ + - added aliases for configuring masterwork and artifact core quality for all stockpile categories that have them; made it possible to take from multiple stockpiles in the ``quantumstop`` alias + - an active cursor is no longer required for running #notes blueprints (like the dreamfort walkthrough) + - you can now be in any mode with an active cursor when running ``#query`` blueprints (before you could only be in a few "approved" modes, like look, query, or place) + - refined ``#query`` blueprint sanity checks: cursor should still be on target tile at end of configuration, and it's ok for the screen ID to change if you are destroying (or canceling destruction of) a building + - now reports how many work orders were added when generating manager orders from blueprints in the gui dialog + - added ``--dry-run`` option to process blueprints but not change any game state + - you can now specify the number of desired barrels, bins, and wheelbarrows for individual stockpiles when placing them + - ``quickfort orders`` on a ``#place`` blueprint will now enqueue manager orders for barrels, bins, or wheelbarrows that are explicitly set in the blueprint. + - you can now add alias definitions directly to your blueprint files instead of having to put them in a separate aliases.txt file. makes sharing blueprints with custom alias definitions much easier. + +Documentation +------------- +- `digfort`: added deprecation warnings - digfort has been replaced by `quickfort` +- `fortplan`: added deprecation warnings - fortplan has been replaced by `quickfort` + +Structures +---------- +- Identified scattered enum values (some rhythm beats, a couple of corruption unit thoughts, and a few language name categories) +- ``viewscreen_loadgamest``: renamed ``cur_step`` enumeration to match style of ``viewscreen_adopt_regionst`` and ``viewscreen_savegamest`` +- ``viewscreen_savegamest``: identified ``cur_step`` enumeration + + +DFHack 0.47.05-beta1 +==================== + +Fixes +----- +- `embark-assistant`: fixed bug in soil depth determination for ocean tiles +- `orders`: don't crash when importing orders with malformed JSON +- `quickfort`: raw numeric `quickfort-dig-priorities` (e.g. ``3``, which is a valid shorthand for ``d3``) now works when used in .xlsx blueprints + +Misc Improvements +----------------- +- `quickfort`: new commandline options for setting the initial state of the gui dialog. for example: ``quickfort gui -l dreamfort notes`` will start the dialog filtered for the dreamfort walkthrough blueprints + +Structures +---------- +- Dropped support for 0.47.03-0.47.04 + + +DFHack 0.47.04-r5 +================= + +New Scripts +----------- +- `gui/quickfort`: fast access to the quickfort interactive dialog +- `workorder-recheck`: resets the selected work order to the ``Checking`` state + +Fixes +----- +- `embark-assistant`: + - fixed order of factors when calculating min temperature + - improved performance of surveying +- `quickfort`: + - fixed eventual crashes when creating zones + - fixed library aliases for tallow and iron, copper, and steel weapons + - zones are now created in the active state by default + - solve rare crash when changing UI modes +- `search-plugin`: fixed crash when searching the ``k`` sidebar and navigating to another tile with certain keys, like ``<`` or ``>`` +- `seedwatch`: fixed an issue where the plugin would disable itself on map load +- `stockflow`: fixed ``j`` character being intercepted when naming stockpiles +- `stockpiles`: no longer outputs hotkey help text beneath `stockflow` hotkey help text + +Misc Improvements +----------------- +- Lua label widgets (used in all standard message boxes) are now scrollable with Up/Down/PgUp/PgDn keys +- `autofarm`: now fallows farms if all plants have reached the desired count +- `buildingplan`: + - added ability to set global settings from the console, e.g. ``buildingplan set boulders false`` + - added "enable all" option for buildingplan (so you don't have to enable all building types individually). This setting is not persisted (just like quickfort_mode is not persisted), but it can be set from onMapLoad.init + - modified ``Planning Mode`` status in the UI to show whether the plugin is in quickfort mode, "enable all" mode, or whether just the building type is enabled. +- `quickfort`: + - Dreamfort blueprint set improvements: added a streamlined checklist for all required dreamfort commands and gave names to stockpiles, levers, bridges, and zones + - added aliases for bronze weapons and armor + - added alias for tradeable crafts + - new blueprint mode: ``#ignore``, useful for scratch space or personal notes + - implement ``{Empty}`` keycode for use in quickfort aliases; useful for defining blank-by-default alias values + - more flexible commandline parsing allowing for more natural parameter ordering (e.g. where you used to have to write ``quickfort list dreamfort -l`` you can now write ``quickfort list -l dreamfort``) + - print out blueprint names that a ``#meta`` blueprint is applying so it's easier to understand what meta blueprints are doing + - whitespace is now allowed between a marker name and the opening parenthesis in blueprint modelines. for example, ``#dig start (5; 5)`` is now valid (you used to be required to write ``#dig start(5; 5)``) + +Documentation +------------- +- Added documentation for Lua's ``dfhack.run_command()`` and variants + +Lua +--- +- ``dfhack.run_command()``: changed to interface directly with the console when possible, which allows interactive commands and commands that detect the console encoding to work properly +- ``processArgsGetopt()`` added to utils.lua, providing a callback interface for parameter parsing and getopt-like flexibility for parameter ordering and combination (see docs in ``library/lua/utils.lua`` and ``library/lua/3rdparty/alt_getopt.lua`` for details). + +Structures +---------- +- ``job``: identified ``order_id`` field + + +DFHack 0.47.04-r4 +================= + +New Scripts +----------- +- `fix/corrupt-equipment`: fixes some military equipment-related corruption issues that can cause DF crashes + +Fixes +----- +- Fixed an issue on some Linux systems where DFHack installed through a package manager would attempt to write files to a non-writable folder (notably when running `exportlegends` or `gui/autogems`) +- `adaptation`: fixed handling of units with no cave adaptation suffered yet +- `assign-goals`: fixed error preventing new goals from being created +- `assign-preferences`: fixed handling of preferences for flour +- `buildingplan`: + - fixed an issue preventing artifacts from being matched when the maximum item quality is set to ``artifacts`` + - stopped erroneously matching items to buildings while the game is paused + - fixed a crash when pressing 0 while having a noble room selected +- `deathcause`: fixed an error when inspecting certain corpses +- `dwarfmonitor`: fixed a crash when opening the ``prefs`` screen if units have vague preferences +- `dwarfvet`: fixed a crash that could occur when discharging patients +- `embark-assistant`: + - fixed an issue causing incursion resource matching (e.g. sand/clay) to skip some tiles if those resources were provided only through incursions + - corrected river size determination by performing it at the MLT level rather than the world tile level +- `quickfort`: + - fixed handling of modifier keys (e.g. ``{Ctrl}`` or ``{Alt}``) in query blueprints + - fixed misconfiguration of nest boxes, hives, and slabs that were preventing them from being built from build blueprints + - fixed valid placement detection for floor hatches, floor grates, and floor bars (they were erroneously being rejected from open spaces and staircase tops) + - fixed query blueprint statistics being added to the wrong metric when both a query and a zone blueprint are run by the same meta blueprint + - added missing blueprint labels in gui dialog list + - fixed occupancy settings for extent-based structures so that stockpiles can be placed within other stockpiles (e.g. in a checkerboard or bullseye pattern) +- `search-plugin`: fixed an issue where search options might not display if screens were destroyed and recreated programmatically (e.g. with `quickfort`) +- `unsuspend`: now leaves buildingplan-managed buildings alone and doesn't unsuspend underwater tasks +- `workflow`: fixed an error when creating constraints on "mill plants" jobs and some other plant-related jobs +- `zone`: fixed an issue causing the ``enumnick`` subcommand to run when attempting to run ``assign``, ``unassign``, or ``slaughter`` + +Misc Improvements +----------------- +- `buildingplan`: + - added support for all buildings, furniture, and constructions (except for instruments) + - added support for respecting building job_item filters when matching items, so you can set your own programmatic filters for buildings before submitting them to buildingplan + - changed default filter setting for max quality from ``artifact`` to ``masterwork`` + - changed min quality adjustment hotkeys from 'qw' to 'QW' to avoid conflict with existing hotkeys for setting roller speed - also changed max quality adjustment hotkeys from 'QW' to 'AS' to make room for the min quality hotkey changes + - added a new global settings page accessible via the ``G`` hotkey when on any building build screen; ``Quickfort Mode`` toggle for legacy Python Quickfort has been moved to this page + - added new global settings for whether generic building materials should match blocks, boulders, logs, and/or bars - defaults are everything but bars +- `devel/export-dt-ini`: updated for Dwarf Therapist 41.2.0 +- `embark-assistant`: split the lair types displayed on the local map into mound, burrow, and lair +- `gui/advfort`: added support for linking to hatches and pressure plates with mechanisms +- `modtools/add-syndrome`: added support for specifying syndrome IDs instead of names +- `probe`: added more output for designations and tile occupancy +- `quickfort`: + - The Dreamfort sample blueprints now have complete walkthroughs for each fort level and importable orders that automate basic fort stock management + - added more blueprints to the blueprints library: several bedroom layouts, the Saracen Crypts, and the complete fortress example from Python Quickfort: TheQuickFortress + - query blueprint aliases can now accept parameters for dynamic expansion - see dfhack-config/quickfort/aliases.txt for details + - alias names can now include dashes and underscores (in addition to letters and numbers) + - improved speed of first call to ``quickfort list`` significantly, especially for large blueprint libraries + - added ``query_unsafe`` setting to disable query blueprint error checking - useful for query blueprints that send unusual key sequences + - added support for bookcases, display cases, and offering places (altars) + - added configuration support for zone pit/pond, gather, and hospital sub-menus in zone blueprints + - removed ``buildings_use_blocks`` setting and replaced it with more flexible functionality in `buildingplan` + - added support for creating uninitialized stockpiles with :kbd:`c` + +Documentation +------------- +- `quickfort-alias-guide`: alias syntax and alias standard library documentation for `quickfort` blueprints +- `quickfort-library-guide`: overview of the quickfort blueprint library + +API +--- +- `buildingplan`: added Lua interface API +- ``Buildings::setSize()``: changed to reuse existing extents when possible +- ``dfhack.job.isSuitableMaterial()``: added an item type parameter so the ``non_economic`` flag can be properly handled (it was being matched for all item types instead of just boulders) + +Lua +--- +- ``utils.addressof()``: fixed for raw userdata + +Structures +---------- +- ``building_extents_type``: new enum, used for ``building_extents.extents`` +- ``world_mountain_peak``: new struct (was previously inline) - used in ``world_data.mountain_peaks`` + + +DFHack 0.47.04-r3 +================= + +New Plugins +----------- +- `xlsxreader`: provides an API for Lua scripts to read Excel spreadsheets + +New Scripts +----------- +- `quickfort`: DFHack-native implementation of quickfort with many new features and integrations - see the `quickfort-user-guide` for details +- `timestream`: controls the speed of the calendar and creatures +- `uniform-unstick`: prompts units to reevaluate their uniform, by removing/dropping potentially conflicting worn items + +Fixes +----- +- `ban-cooking`: fixed an error in several subcommands +- `buildingplan`: fixed handling of buildings that require buckets +- `getplants`: fixed a crash that could occur on some maps +- `search-plugin`: fixed an issue causing item counts on the trade screen to display inconsistently when searching +- `stockpiles`: + - fixed a crash when loading food stockpiles + - fixed an error when saving furniture stockpiles + +Misc Improvements +----------------- +- `createitem`: + - added support for plant growths (fruit, berries, leaves, etc.) + - added an ``inspect`` subcommand to print the item and material tokens of existing items, which can be used to create additional matching items +- `embark-assistant`: added support for searching for taller waterfalls (up to 50 z-levels tall) +- `search-plugin`: added support for searching for names containing non-ASCII characters using their ASCII equivalents +- `stocks`: added support for searching for items containing non-ASCII characters using their ASCII equivalents +- `unretire-anyone`: made undead creature names appear in the historical figure list +- `zone`: + - added an ``enumnick`` subcommand to assign enumerated nicknames (e.g "Hen 1", "Hen 2"...) + - added slaughter indication to ``uinfo`` output + +Documentation +------------- +- Fixed syntax highlighting of most code blocks to use the appropriate language (or no language) instead of Python + +API +--- +- Added ``DFHack::to_search_normalized()`` (Lua: ``dfhack.toSearchNormalized()``) to convert non-ASCII alphabetic characters to their ASCII equivalents + +Structures +---------- +- ``history_event_masterpiece_createdst``: fixed alignment, including subclasses, and identified ``skill_at_time`` +- ``item_body_component``: fixed some alignment issues and identified some fields (also applies to subclasses like ``item_corpsest``) +- ``stockpile_settings``: removed ``furniture.sand_bags`` (no longer present) + + +DFHack 0.47.04-r2 +================= + +New Scripts +----------- +- `animal-control`: helps manage the butchery and gelding of animals +- `devel/kill-hf`: kills a historical figure +- `geld`: gelds or ungelds animals +- `list-agreements`: lists all guildhall and temple agreements +- `list-waves`: displays migration wave information for citizens/units +- `ungeld`: ungelds animals (wrapper around `geld`) + +New Tweaks +---------- +- `tweak` do-job-now: adds a job priority toggle to the jobs list +- `tweak` reaction-gloves: adds an option to make reactions produce gloves in sets with correct handedness + +Fixes +----- +- Fixed a segfault when attempting to start a headless session with a graphical PRINT_MODE setting +- Fixed an issue with the macOS launcher failing to un-quarantine some files +- Fixed ``Units::isEggLayer``, ``Units::isGrazer``, ``Units::isMilkable``, ``Units::isTrainableHunting``, ``Units::isTrainableWar``, and ``Units::isTamable`` ignoring the unit's caste +- Linux: fixed ``dfhack.getDFPath()`` (Lua) and ``Process::getPath()`` (C++) to always return the DF root path, even if the working directory has changed +- `digfort`: + - fixed y-line tracking when .csv files contain lines with only commas + - fixed an issue causing blueprints touching the southern or eastern edges of the map to be rejected (northern and western edges were already allowed). This allows blueprints that span the entire embark area. +- `embark-assistant`: fixed a couple of incursion handling bugs. +- `embark-skills`: fixed an issue with structures causing the ``points`` option to do nothing +- `exportlegends`: + - fixed an issue where two different ```` tags could be included in a ```` + - stopped including some tags with ``-1`` values which don't provide useful information +- `getplants`: fixed issues causing plants to be collected even if they have no growths (or unripe growths) +- `gui/advfort`: fixed "operate pump" job +- `gui/load-screen`: fixed an issue causing longer timezones to be cut off +- `labormanager`: + - fixed handling of new jobs in 0.47 + - fixed an issue preventing custom furnaces from being built +- `modtools/moddable-gods`: + - fixed an error when creating the historical figure + - removed unused ``-domain`` and ``-description`` arguments + - made ``-depictedAs`` argument work +- `names`: + - fixed an error preventing the script from working + - fixed an issue causing renamed units to display their old name in legends mode and some other places +- `pref-adjust`: fixed some compatibility issues and a potential crash +- `RemoteFortressReader`: + - fixed a couple crashes that could result from decoding invalid enum items (``site_realization_building_type`` and ``improvement_type``) + - fixed an issue that could cause block coordinates to be incorrect +- `rendermax`: fixed a hang that could occur when enabling some renderers, notably on Linux +- `stonesense`: + - fixed a crash when launching Stonesense + - fixed some issues that could cause the splash screen to hang + +Misc Improvements +----------------- +- Linux/macOS: Added console keybindings for deleting words (Alt+Backspace and Alt+d in most terminals) +- `add-recipe`: + - added tool recipes (minecarts, wheelbarrows, stepladders, etc.) + - added a command explanation or error message when entering an invalid command +- `armoks-blessing`: added adjustments to values and needs +- `blueprint`: + - now writes blueprints to the ``blueprints/`` subfolder instead of the df root folder + - now automatically creates folder trees when organizing blueprints into subfolders (e.g. ``blueprint 30 30 1 rooms/dining dig`` will create the file ``blueprints/rooms/dining-dig.csv``); previously it would fail if the ``blueprints/rooms/`` directory didn't already exist +- `confirm`: added a confirmation dialog for convicting dwarves of crimes +- `devel/query`: added many new query options +- `digfort`: + - handled double quotes (") at the start of a string, allowing .csv files exported from spreadsheets to work without manual modification + - documented that removing ramps, cutting trees, and gathering plants are indeed supported + - added a ``force`` option to truncate blueprints if the full blueprint would extend off the edge of the map +- `dwarf-op`: + - added ability to select dwarves based on migration wave + - added ability to protect dwarves based on symbols in their custom professions +- `exportlegends`: + - changed some flags to be represented by self-closing tags instead of true/false strings (e.g. ````) - note that this may require changes to other XML-parsing utilities + - changed some enum values from numbers to their string representations + - added ability to save all files to a subfolder, named after the region folder and date by default +- `gui/advfort`: added support for specifying the entity used to determine available resources +- `gui/gm-editor`: added support for automatically following ref-targets when pressing the ``i`` key +- `manipulator`: added a new column option to display units' goals +- `modtools/moddable-gods`: added support for ``neuter`` gender +- `pref-adjust`: + - added support for adjusting just the selected dwarf + - added a new ``goth`` profile +- `remove-stress`: added a ``-value`` argument to enable setting stress level directly +- `workorder`: changed default frequency from "Daily" to "OneTime" + +Documentation +------------- +- Added some new dev-facing pages, including dedicated pages about the remote API, memory research, and documentation +- Expanded the installation guide +- Made a couple theme adjustments + +API +--- +- Added ``Filesystem::mkdir_recursive`` +- Extended ``Filesystem::listdir_recursive`` to optionally make returned filenames relative to the start directory +- ``Units``: added goal-related functions: ``getGoalType()``, ``getGoalName()``, ``isGoalAchieved()`` + +Internals +--------- +- Added support for splitting scripts into multiple files in the ``scripts/internal`` folder without polluting the output of `ls` + +Lua +--- +- Added a ``ref_target`` field to primitive field references, corresponding to the ``ref-target`` XML attribute +- Made ``dfhack.units.getRaceNameById()``, ``dfhack.units.getRaceBabyNameById()``, and ``dfhack.units.getRaceChildNameById()`` available to Lua + +Ruby +---- +- Updated ``item_find`` and ``building_find`` to use centralized logic that works on more screens + +Structures +---------- +- Added a new ````, which allows ``world.*.other`` collections of vectors to use the correct subtypes for items +- ``creature_raw``: renamed ``gender`` to ``sex`` to match the field in ``unit``, which is more frequently used +- ``crime``: identified ``witnesses``, which contains the data held by the old field named ``reports`` +- ``intrigue``: new type (split out from ``historical_figure_relationships``) +- ``items_other_id``: removed ``BAD``, and by extension, ``world.items.other.BAD``, which was overlapping with ``world.items.bad`` +- ``job_type``: added job types new to 0.47 +- ``plant_raw``: material_defs now contains arrays rather than loose fields +- ``pronoun_type``: new enum (previously documented in field comments) +- ``setup_character_info``: fixed a couple alignment issues (needed by `embark-skills`) +- ``ui_advmode_menu``: identified some new enum items + + +DFHack 0.47.04-r1 +================= + +Fixes +----- +- Fixed a crash in ``find()`` for some types when no world is loaded +- Fixed translation of certain types of in-game names +- `autogems`: fixed an issue with binned gems being ignored in linked stockpiles +- `catsplosion`: fixed error when handling races with only one caste (e.g. harpies) +- `exportlegends`: fixed error when exporting maps +- `spawnunit`: fixed an error when forwarding some arguments but not a location to `modtools/create-unit` +- `stocks`: fixed display of book titles +- `tweak` embark-profile-name: fixed handling of the native shift+space key + +Misc Improvements +----------------- +- `exportlegends`: + - made interaction export more robust and human-readable + - removed empty ```` and ```` tags +- `getplants`: added switches for designations for farming seeds and for max number designated per plant +- `manipulator`: added intrigue to displayed skills +- `modtools/create-unit`: + - added ``-equip`` option to equip created units + - added ``-skills`` option to give skills to units + - added ``-profession`` and ``-customProfession`` options to adjust unit professions +- `search-plugin`: added support for the fortress mode justice screen +- ``dfhack.init-example``: enabled `autodump` + +API +--- +- Added ``Items::getBookTitle`` to get titles of books. Catches titles buried in improvements, unlike getDescription. + +Lua +--- +- ``pairs()`` now returns available class methods for DF types + +Structures +---------- +- Added globals: ``cur_rain``, ``cur_rain_counter``, ``cur_snow``, ``cur_snow_counter``, ``weathertimer``, ``jobvalue``, ``jobvalue_setter``, ``interactitem``, ``interactinvslot``, ``handleannounce``, ``preserveannounce``, ``updatelightstate`` +- ``agreement_details_data_plot_sabotage``: new struct type, along with related ``agreement_details_type.PlotSabotage`` +- ``architectural_element``: new enum +- ``battlefield``: new struct type +- ``breed``: new struct type +- ``creature_handler``: identified vmethods +- ``crime``: removed fields of ``reports`` that are no longer present +- ``dance_form``: identified most fields +- ``history_event_context``: identified fields +- ``identity_type``: new enum +- ``identity``: renamed ``civ`` to ``entity_id``, identified ``type`` +- ``image_set``: new struct type +- ``interrogation_report``: new struct type +- ``itemdef_flags``: new enum, with ``GENERATED`` flag +- ``justification``: new enum +- ``lever_target_type``: identified ``LeverMechanism`` and ``TargetMechanism`` values +- ``musical_form``: identified fields, including some renames. Also identified fields in ``scale`` and ``rhythm`` +- ``region_weather``: new struct type +- ``squad_order_cause_trouble_for_entityst``: identified fields +- ``unit_thought_type``: added several new thought types +- ``viewscreen_workquota_detailsst``: identified fields + + +DFHack 0.47.04-beta1 +==================== + +New Scripts +----------- +- `color-schemes`: manages color schemes +- `devel/print-event`: prints the description of an event by ID or index +- `gui/color-schemes`: an in-game interface for `color-schemes` +- `light-aquifers-only`: changes heavy aquifers to light aquifers +- `on-new-fortress`: runs DFHack commands only in a new fortress +- `once-per-save`: runs DFHack commands unless already run in the current save +- `resurrect-adv`: brings your adventurer back to life +- `reveal-hidden-units`: exposes all sneaking units +- `workorder`: allows queuing manager jobs; smart about shear and milk creature jobs + +Fixes +----- +- Fixed a crash when starting DFHack in headless mode with no terminal +- `devel/visualize-structure`: fixed padding detection for globals +- `exportlegends`: + - added UTF-8 encoding and XML escaping for more fields + - added checking for unhandled structures to avoid generating invalid XML + - fixed missing fields in ``history_event_assume_identityst`` export +- `full-heal`: + - when resurrected by specifying a corpse, units now appear at the location of the corpse rather than their location of death + - resurrected units now have their tile occupancy set (and are placed in the prone position to facilitate this) + +Misc Improvements +----------------- +- Added "bit" suffix to downloads (e.g. 64-bit) +- Tests: + - moved from DF folder to hack/scripts folder, and disabled installation by default + - made test runner script more flexible +- `devel/export-dt-ini`: updated some field names for DT for 0.47 +- `devel/visualize-structure`: added human-readable lengths to containers +- `dfhack-run`: added color output support +- `embark-assistant`: + - updated embark aquifer info to show all aquifer kinds present + - added neighbor display, including kobolds (SKULKING) and necro tower count + - updated aquifer search criteria to handle the new variation + - added search criteria for embark initial tree cover + - added search criteria for necro tower count, neighbor civ count, and specific neighbors. Should handle additional entities, but not tested +- `exportlegends`: + - added evilness and force IDs to regions + - added profession and weapon info to relevant entities + - added support for many new history events in 0.47 + - added historical event relationships and supplementary data +- `full-heal`: + - made resurrection produce a historical event viewable in Legends mode + - made error messages more explanatory +- `install-info`: added DFHack build ID to report +- `modtools/create-item`: added ``-matchingGloves`` and ``-matchingShoes`` arguments +- `modtools/create-unit`: + - added ``-duration`` argument to make the unit vanish after some time + - added ``-locationRange`` argument to allow spawning in a random position within a defined area + - added ``-locationType`` argument to specify the type of location to spawn in +- `unretire-anyone`: added ``-dead`` argument to revive and enable selection of a dead historical figure to use as an adventurer in adv mode + +Internals +--------- +- Added separate changelogs in the scripts and df-structures repos +- Improved support for tagged unions, allowing tools to access union fields more safely +- Moved ``reversing`` scripts to df_misc repo + +Structures +---------- +- Added an XML schema for validating df-structures syntax +- Added ``divination_set_next_id`` and ``image_set_next_id`` globals +- ``activity_entry_type``: new enum type +- ``adventure_optionst``: identified many vmethods +- ``agreement_details``: identified most fields of most sub-structs +- ``artifact_claim``: identified several fields +- ``artifact_record``: identified several fields +- ``caste_raw_flags``: renamed and identified many flags to match information from Toady +- ``creature_raw_flags``: renamed and identified many flags to match information from Toady +- ``crime_type``: new enum type +- ``dfhack_room_quality_level``: added enum attributes for names of rooms of each quality +- ``entity_site_link_type``: new enum type +- ``export_map_type``: new enum type +- ``historical_entity.flags``: identified several flags +- ``historical_entity.relations``: renamed from ``unknown1b`` and identified several fields +- ``historical_figure.vague_relationships``: identified +- ``historical_figure_info.known_info``: renamed from ``secret``, identified some fields +- ``historical_figure``: renamed ``unit_id2`` to ``nemesis_id`` +- ``history_event_circumstance_info``: new struct type (and changed several ``history_event`` subclasses to use this) +- ``history_event_reason_info``: new struct type (and changed several ``history_event`` subclasses to use this) +- ``honors_type``: identified several fields +- ``interaction_effect_create_itemst``: new struct type +- ``interaction_effect_summon_unitst``: new struct type +- ``item``: identified several vmethods +- ``layer_type``: new enum type +- ``plant.damage_flags``: added ``is_dead`` +- ``plot_role_type``: new enum type +- ``plot_strategy_type``: new enum type +- ``relationship_event_supplement``: new struct type +- ``relationship_event``: new struct type +- ``specific_ref``: moved union data to ``data`` field +- ``ui_look_list``: moved union fields to ``data`` and renamed to match ``type`` enum +- ``ui_sidebar_menus.location``: added new profession-related fields, renamed and fixed types of deity-related fields +- ``ui_sidebar_mode``: added ``ZonesLocationInfo`` +- ``unit_action``: rearranged as tagged union with new sub-types; existing code should be compatible +- ``vague_relationship_type``: new enum type +- ``vermin_flags``: identified ``is_roaming_colony`` +- ``viewscreen_justicest``: identified interrogation-related fields +- ``world_data.field_battles``: identified and named several fields + + +DFHack 0.47.03-beta1 +==================== + +New Scripts +----------- +- `devel/sc`: checks size of structures +- `devel/visualize-structure`: displays the raw memory of a structure + +Fixes +----- +- `adv-max-skills`: fixed for 0.47 +- `deep-embark`: + - prevented running in non-fortress modes + - ensured that only the newest wagon is deconstructed +- `full-heal`: + - fixed issues with removing corpses + - fixed resurrection for non-historical figures +- `modtools/create-unit`: added handling for arena tame setting +- `teleport`: fixed setting new tile occupancy + +Misc Improvements +----------------- +- `deep-embark`: + - improved support for using directly from the DFHack console + - added a ``-clear`` option to cancel +- `exportlegends`: + - added identity information + - added creature raw names and flags +- `gui/prerelease-warning`: updated links and information about nightly builds +- `modtools/syndrome-trigger`: enabled simultaneous use of ``-synclass`` and ``-syndrome`` +- `repeat`: added ``-list`` option + +Structures +---------- +- Dropped support for 0.44.12-0.47.02 +- ``abstract_building_type``: added types (and subclasses) new to 0.47 +- ``agreement_details_type``: added enum +- ``agreement_details``: added struct type (and many associated data types) +- ``agreement_party``: added struct type +- ``announcement_type``: added types new to 0.47 +- ``artifact_claim_type``: added enum +- ``artifact_claim``: added struct type +- ``breath_attack_type``: added ``SHARP_ROCK`` +- ``building_offering_placest``: new class +- ``building_type``: added ``OfferingPlace`` +- ``caste_raw_flags``: renamed many items to match DF names +- ``creature_interaction_effect``: added subclasses new to 0.47 +- ``creature_raw_flags``: + - identified several more items + - renamed many items to match DF names +- ``d_init``: added settings new to 0.47 +- ``entity_name_type``: added ``MERCHANT_COMPANY``, ``CRAFT_GUILD`` +- ``entity_position_responsibility``: added values new to 0.47 +- ``fortress_type``: added enum +- ``general_ref_type``: added ``UNIT_INTERROGATEE`` +- ``ghost_type``: added ``None`` value +- ``goal_type``: added goals types new to 0.47 +- ``histfig_site_link``: added subclasses new to 0.47 +- ``history_event_collection``: added subtypes new to 0.47 +- ``history_event_context``: added lots of new fields +- ``history_event_reason``: + - added captions for all items + - added items new to 0.47 +- ``history_event_type``: added types for events new to 0.47, as well as corresponding ``history_event`` subclasses (too many to list here) +- ``honors_type``: added struct type +- ``interaction_effect``: added subtypes new to 0.47 +- ``interaction_source_experimentst``: added class type +- ``interaction_source_usage_hint``: added values new to 0.47 +- ``interface_key``: added items for keys new to 0.47 +- ``job_skill``: added ``INTRIGUE``, ``RIDING`` +- ``lair_type``: added enum +- ``monument_type``: added enum +- ``next_global_id``: added enum +- ``poetic_form_action``: added ``Beseech`` +- ``setup_character_info``: expanded significantly in 0.47 +- ``text_system``: added layout for struct +- ``tile_occupancy``: added ``varied_heavy_aquifer`` +- ``tool_uses``: added items: ``PLACE_OFFERING``, ``DIVINATION``, ``GAMES_OF_CHANCE`` +- ``viewscreen_counterintelligencest``: new class (only layout identified so far) + + +DFHack 0.44.12-r3 +================= + +New Plugins +----------- +- `autoclothing`: automatically manage clothing work orders +- `autofarm`: replaces the previous Ruby script of the same name, with some fixes +- `map-render`: allows programmatically rendering sections of the map that are off-screen +- `tailor`: automatically manages keeping your dorfs clothed + +New Scripts +----------- +- `assign-attributes`: changes the attributes of a unit +- `assign-beliefs`: changes the beliefs of a unit +- `assign-facets`: changes the facets (traits) of a unit +- `assign-goals`: changes the goals of a unit +- `assign-preferences`: changes the preferences of a unit +- `assign-profile`: sets a dwarf's characteristics according to a predefined profile +- `assign-skills`: changes the skills of a unit +- `combat-harden`: sets a unit's combat-hardened value to a given percent +- `deep-embark`: allows embarking underground +- `devel/find-twbt`: finds a TWBT-related offset needed by the new `map-render` plugin +- `dwarf-op`: optimizes dwarves for fort-mode work; makes managing labors easier +- `forget-dead-body`: removes emotions associated with seeing a dead body +- `gui/create-tree`: creates a tree at the selected tile +- `linger`: takes over your killer in adventure mode +- `modtools/create-tree`: creates a tree +- `modtools/pref-edit`: add, remove, or edit the preferences of a unit +- `modtools/set-belief`: changes the beliefs (values) of units +- `modtools/set-need`: sets and edits unit needs +- `modtools/set-personality`: changes the personality of units +- `modtools/spawn-liquid`: spawns water or lava at the specified coordinates +- `set-orientation`: edits a unit's orientation +- `unretire-anyone`: turns any historical figure into a playable adventurer + +Fixes +----- +- Fixed a crash in the macOS/Linux console when the prompt was wider than the screen width +- Fixed inconsistent results from ``Units::isGay`` for asexual units +- Fixed some cases where Lua filtered lists would not properly intercept keys, potentially triggering other actions on the same screen +- `autofarm`: + - fixed biome detection to properly determine crop assignments on surface farms + - reimplemented as a C++ plugin to make proper biome detection possible +- `bodyswap`: fixed companion list not being updated often enough +- `cxxrandom`: removed some extraneous debug information +- `digfort`: now accounts for z-level changes when calculating maximum y dimension +- `embark-assistant`: + - fixed bug causing crash on worlds without generated metals (as well as pruning vectors as originally intended). + - fixed bug causing mineral matching to fail to cut off at the magma sea, reporting presence of things that aren't (like DF does currently). + - fixed bug causing half of the river tiles not to be recognized. + - added logic to detect some river tiles DF doesn't generate data for (but are definitely present). +- `eventful`: fixed invalid building ID in some building events +- `exportlegends`: now escapes special characters in names properly +- `getplants`: fixed designation of plants out of season (note that picked plants are still designated incorrectly) +- `gui/autogems`: fixed error when no world is loaded +- `gui/companion-order`: + - fixed error when resetting group leaders + - ``leave`` now properly removes companion links +- `gui/create-item`: fixed module support - can now be used from other scripts +- `gui/stamper`: + - stopped "invert" from resetting the designation type + - switched to using DF's designation keybindings instead of custom bindings + - fixed some typos and text overlapping +- `modtools/create-unit`: + - fixed an error associating historical entities with units + - stopped recalculating health to avoid newly-created citizens triggering a "recover wounded" job + - fixed units created in arena mode having blank names + - fixed units created in arena mode having the wrong race and/or interaction effects applied after creating units manually in-game + - stopped units from spawning with extra items or skills previously selected in the arena + - stopped setting some unneeded flags that could result in glowing creature tiles + - set units created in adventure mode to have no family, instead of being related to the first creature in the world +- `modtools/reaction-product-trigger`: + - fixed an error dealing with reactions in adventure mode + - blocked ``\\BUILDING_ID`` for adventure mode reactions + - fixed ``-clear`` to work without passing other unneeded arguments +- `modtools/reaction-trigger`: + - fixed a bug when determining whether a command was run + - fixed handling of ``-resetPolicy`` +- `mousequery`: fixed calculation of map dimensions, which was sometimes preventing scrolling the map with the mouse when TWBT was enabled +- `RemoteFortressReader`: fixed a crash when a unit's path has a length of 0 +- `stonesense`: fixed crash due to wagons and other soul-less creatures +- `tame`: now sets the civ ID of tamed animals (fixes compatibility with `autobutcher`) +- `title-folder`: silenced error when ``PRINT_MODE`` is set to ``TEXT`` + +Misc Improvements +----------------- +- Added a note to `dfhack-run` when called with no arguments (which is usually unintentional) +- On macOS, the launcher now attempts to un-quarantine the rest of DFHack +- `bodyswap`: added arena mode support +- `combine-drinks`: added more default output, similar to `combine-plants` +- `createitem`: added a list of valid castes to the "invalid caste" error message, for convenience +- `devel/export-dt-ini`: added more size information needed by newer Dwarf Therapist versions +- `dwarfmonitor`: enabled widgets to access other scripts and plugins by switching to the core Lua context +- `embark-assistant`: + - added an in-game option to activate on the embark screen + - changed waterfall detection to look for level drop rather than just presence + - changed matching to take incursions, i.e. parts of other biomes, into consideration when evaluating tiles. This allows for e.g. finding multiple biomes on single tile embarks. + - changed overlay display to show when incursion surveying is incomplete + - changed overlay display to show evil weather + - added optional parameter "fileresult" for crude external harness automated match support + - improved focus movement logic to go to only required world tiles, increasing speed of subsequent searches considerably +- `exportlegends`: added rivers to custom XML export +- `exterminate`: added support for a special ``enemy`` caste +- `gui/gm-unit`: + - added support for editing: + - added attribute editor + - added orientation editor + - added editor for bodies and body parts + - added color editor + - added belief editor + - added personality editor +- `modtools/create-item`: documented already-existing ``-quality`` option +- `modtools/create-unit`: + - added the ability to specify ``\\LOCAL`` for the fort group entity + - now enables the default labours for adult units with CAN_LEARN. + - now sets historical figure orientation. + - improved speed of creating multiple units at once + - made the script usable as a module (from other scripts) +- `modtools/reaction-trigger`: + - added ``-ignoreWorker``: ignores the worker when selecting the targets + - changed the default behavior to skip inactive/dead units; added ``-dontSkipInactive`` to include creatures that are inactive + - added ``-range``: controls how far eligible targets can be from the workshop + - syndromes now are applied before commands are run, not after + - if both a command and a syndrome are given, the command only runs if the syndrome could be applied +- `mousequery`: made it more clear when features are enabled +- `RemoteFortressReader`: + - added a basic framework for controlling and reading the menus in DF (currently only supports the building menu) + - added support for reading item raws + - added a check for whether or not the game is currently saving or loading, for utilities to check if it's safe to read from DF + - added unit facing direction estimate and position within tiles + - added unit age + - added unit wounds + - added tree information + - added check for units' current jobs when calculating the direction they are facing + +API +--- +- Added new ``plugin_load_data`` and ``plugin_save_data`` events for plugins to load/save persistent data +- Added ``Maps::GetBiomeType`` and ``Maps::GetBiomeTypeByRef`` to infer biome types properly +- Added ``Units::getPhysicalDescription`` (note that this depends on the ``unit_get_physical_description`` offset, which is not yet available for all DF builds) + +Internals +--------- +- Added new Persistence module +- Cut down on internal DFHack dependencies to improve build times +- Improved concurrency in event and server handlers +- Persistent data is now stored in JSON files instead of historical figures - existing data will be migrated when saving +- `stonesense`: fixed some OpenGL build issues on Linux + +Lua +--- +- Exposed ``gui.dwarfmode.get_movement_delta`` and ``gui.dwarfmode.get_hotkey_target`` +- ``dfhack.run_command`` now returns the command's return code + +Ruby +---- +- Made ``unit_ishostile`` consistently return a boolean + +Structures +---------- +- Added ``unit_get_physical_description`` function offset on some platforms +- Added/identified types: + - ``assume_identity_mode`` + - ``musical_form_purpose`` + - ``musical_form_style`` + - ``musical_form_pitch_style`` + - ``musical_form_feature`` + - ``musical_form_vocals`` + - ``musical_form_melodies`` + - ``musical_form_interval`` + - ``unit_emotion_memory`` +- ``need_type``: fixed ``PrayOrMeditate`` typo +- ``personality_facet_type``, ``value_type``: added ``NONE`` values +- ``twbt_render_map``: added for 64-bit 0.44.12 (for `map-render`) + + +DFHack 0.44.12-r2 +================= + +New Plugins +----------- +- `debug`: manages runtime debug print category filtering +- `nestboxes`: automatically scan for and forbid fertile eggs incubating in a nestbox + +New Scripts +----------- +- `devel/query`: searches for field names in DF objects +- `extinguish`: puts out fires +- `tame`: sets tamed/trained status of animals + +Fixes +----- +- `building-hacks`: fixed error when dealing with custom animation tables +- `devel/test-perlin`: fixed Lua error (``math.pow()``) +- `embark-assistant`: fixed crash when entering finder with a 16x16 embark selected, and added 16 to dimension choices +- `embark-skills`: fixed missing ``skill_points_remaining`` field +- `full-heal`: + - stopped wagon resurrection + - fixed a minor issue with post-resurrection hostility +- `gui/companion-order`: + - fixed issues with printing coordinates + - fixed issues with move command + - fixed cheat commands (and removed "Power up", which was broken) +- `gui/gm-editor`: fixed reinterpret cast (``r``) +- `gui/pathable`: fixed error when sidebar is hidden with ``Tab`` +- `labormanager`: + - stopped assigning labors to ineligible dwarves, pets, etc. + - stopped assigning invalid labors + - added support for crafting jobs that use pearl + - fixed issues causing cleaning jobs to not be assigned + - added support for disabling management of specific labors +- `prospector`: (also affected `embark-tools`) - fixed a crash when prospecting an unusable site (ocean, mountains, etc.) with a large default embark size in d_init.txt (e.g. 16x16) +- `siege-engine`: fixed a few Lua errors (``math.pow()``, ``unit.relationship_ids``) +- `tweak`: fixed ``hotkey-clear`` + +Misc Improvements +----------------- +- `armoks-blessing`: improved documentation to list all available arguments +- `devel/export-dt-ini`: + - added viewscreen offsets for DT 40.1.2 + - added item base flags offset + - added needs offsets +- `embark-assistant`: + - added match indicator display on the right ("World") map + - changed 'c'ancel to abort find if it's under way and clear results if not, allowing use of partial surveys. + - added Coal as a search criterion, as well as a coal indication as current embark selection info. +- `full-heal`: + - added ``-all``, ``-all_civ`` and ``-all_citizens`` arguments + - added module support + - now removes historical figure death dates and ghost data +- `growcrops`: added ``all`` argument to grow all crops +- `gui/load-screen`: improved documentation +- `labormanager`: now takes nature value into account when assigning jobs +- `open-legends`: added warning about risk of save corruption and improved related documentation +- `points`: added support when in ``viewscreen_setupdwarfgamest`` and improved error messages +- `siren`: removed break handling (relevant ``misc_trait_type`` was no longer used - see "Structures" section) + +API +--- +- New debug features related to `debug` plugin: + - Classes (C++ only): ``Signal``, ``DebugCategory``, ``DebugManager`` + - Macros: ``TRACE``, ``DEBUG``, ``INFO``, ``WARN``, ``ERR``, ``DBG_DECLARE``, ``DBG_EXTERN`` + +Internals +--------- +- Added a usable unit test framework for basic tests, and a few basic tests +- Added ``CMakeSettings.json`` with intellisense support +- Changed ``plugins/CMakeLists.custom.txt`` to be ignored by git and created (if needed) at build time instead +- Core: various thread safety and memory management improvements +- Fixed CMake build dependencies for generated header files +- Fixed custom ``CMAKE_CXX_FLAGS`` not being passed to plugins +- Linux/macOS: changed recommended build backend from Make to Ninja (Make builds will be significantly slower now) + +Lua +--- +- ``utils``: new ``OrderedTable`` class + +Structures +---------- +- Win32: added missing vtables for ``viewscreen_storesst`` and ``squad_order_rescue_hfst`` +- ``activity_event_performancest``: renamed poem as written_content_id +- ``body_part_status``: identified ``gelded`` +- ``dance_form``: named musical_form_id and musical_written_content_id +- ``incident_sub6_performance.participants``: named performance_event and role_index +- ``incident_sub6_performance``: + - made performance_event an enum + - named poetic_form_id, musical_form_id, and dance_form_id +- ``misc_trait_type``: removed ``LikesOutdoors``, ``Hardened``, ``TimeSinceBreak``, ``OnBreak`` (all unused by DF) +- ``musical_form_instruments``: named minimum_required and maximum_permitted +- ``musical_form``: named voices field +- ``plant_tree_info``: identified ``extent_east``, etc. +- ``plant_tree_tile``: gave connection bits more meaningful names (e.g. ``connection_east`` instead of ``thick_branches_1``) +- ``poetic_form``: identified many fields and related enum/bitfield types +- ``setup_character_info``: identified ``skill_points_remaining`` (for `embark-skills`) +- ``ui.main``: identified ``fortress_site`` +- ``ui.squads``: identified ``kill_rect_targets_scroll`` +- ``ui``: fixed alignment of ``main`` and ``squads`` (fixes `tweak` hotkey-clear and DF-AI) +- ``unit_action.attack``: + - identified ``attack_skill`` + - added ``lightly_tap`` and ``spar_report`` flags +- ``unit_flags3``: identified ``marked_for_gelding`` +- ``unit_personality``: identified ``stress_drain``, ``stress_boost``, ``likes_outdoors``, ``combat_hardened`` +- ``unit_storage_status``: newly identified type, stores noble holdings information (used in ``viewscreen_layer_noblelistst``) +- ``unit_thought_type``: added new expulsion thoughts from 0.44.12 +- ``viewscreen_layer_arena_creaturest``: identified item- and name-related fields +- ``viewscreen_layer_militaryst``: identified ``equip.assigned.assigned_items`` +- ``viewscreen_layer_noblelistst``: identified ``storage_status`` (see ``unit_storage_status`` type) +- ``viewscreen_new_regionst``: + - identified ``rejection_msg``, ``raw_folder``, ``load_world_params`` + - changed many ``int8_t`` fields to ``bool`` +- ``viewscreen_setupadventurest``: identified some nemesis and personality fields, and ``page.ChooseHistfig`` +- ``world_data``: added ``mountain_peak_flags`` type, including ``is_volcano`` +- ``world_history``: identified names and/or types of some fields +- ``world_site``: identified names and/or types of some fields +- ``written_content``: named poetic_form + + +DFHack 0.44.12-r1 +================= + +Fixes +----- +- Console: fixed crash when entering long commands on Linux/macOS +- Fixed special characters in `command-prompt` and other non-console in-game outputs on Linux/macOS (in tools using ``df2console``) +- Removed jsoncpp's ``include`` and ``lib`` folders from DFHack builds/packages +- `die`: fixed Windows crash in exit handling +- `dwarfmonitor`, `manipulator`: fixed stress cutoffs +- `modtools/force`: fixed a bug where the help text would always be displayed and nothing useful would happen +- `ruby`: fixed calling conventions for vmethods that return strings (currently ``enabler.GetKeyDisplay()``) +- `startdwarf`: fixed on 64-bit Linux + +Misc Improvements +----------------- +- Reduced time for designation jobs from tools like `digv` to be assigned workers +- `embark-assistant`: + - Switched to standard scrolling keys, improved spacing slightly + - Introduced scrolling of Finder search criteria, removing requirement for 46 lines to work properly (Help/Info still formatted for 46 lines). + - Added Freezing search criterion, allowing searches for NA/Frozen/At_Least_Partial/Partial/At_Most_Partial/Never Freezing embarks. +- `rejuvenate`: + - Added ``-all`` argument to apply to all citizens + - Added ``-force`` to include units under 20 years old + - Clarified documentation + +API +--- +- Added to ``Units`` module: + - ``getStressCategory(unit)`` + - ``getStressCategoryRaw(level)`` + - ``stress_cutoffs`` (Lua: ``getStressCutoffs()``) + +Internals +--------- +- Added documentation for all RPC functions and a build-time check +- Added support for build IDs to development builds +- Changed default build architecture to 64-bit +- Use ``dlsym(3)`` to find vtables from libgraphics.so + +Structures +---------- +- Added ``start_dwarf_count`` on 64-bit Linux again and fixed scanning script +- ``army_controller``: added new vector from 0.44.11 +- ``belief_system``: new type, few fields identified +- ``mental_picture``: new type, some fields identified +- ``mission_report``: + - new type (renamed, was ``mission`` before) + - identified some fields +- ``mission``: new type (used in ``viewscreen_civlistst``) +- ``spoils_report``: new type, most fields identified +- ``viewscreen_civlistst``: + - split ``unk_20`` into 3 pointers + - identified new pages + - identified new messenger-related fields +- ``viewscreen_image_creatorst``: + - fixed layout + - identified many fields +- ``viewscreen_reportlistst``: added new mission and spoils report-related fields (fixed layout) +- ``world.languages``: identified (minimal information; whole languages stored elsewhere) +- ``world.status``: + - ``mission_reports``: renamed, was ``missions`` + - ``spoils_reports``: identified +- ``world.unk_131ec0``, ``world.unk_131ef0``: researched layout +- ``world.worldgen_status``: identified many fields +- ``world``: ``belief_systems``: identified + + +DFHack 0.44.12-alpha1 +===================== + +Fixes +----- +- macOS: fixed ``renderer`` vtable address on x64 (fixes `rendermax`) +- `stonesense`: fixed ``PLANT:DESERT_LIME:LEAF`` typo + +API +--- +- Added C++-style linked list interface for DF linked lists + +Structures +---------- +- Dropped 0.44.11 support +- ``ui.squads``: Added fields new in 0.44.12 + + +DFHack 0.44.11-beta2.1 +====================== + +Internals +--------- +- `stonesense`: fixed build + + +DFHack 0.44.11-beta2 +==================== + +Fixes +----- +- Windows: Fixed console failing to initialize +- `command-prompt`: added support for commands that require a specific screen to be visible, e.g. `spotclean` +- `gui/workflow`: fixed advanced constraint menu for crafts + +API +--- +- Added ``Screen::Hide`` to temporarily hide screens, like `command-prompt` + + +DFHack 0.44.11-beta1 +==================== + +Fixes +----- +- Fixed displayed names (from ``Units::getVisibleName``) for units with identities +- Fixed potential memory leak in ``Screen::show()`` +- `fix/dead-units`: fixed script trying to use missing isDiplomat function + +Misc Improvements +----------------- +- Console: + - added support for multibyte characters on Linux/macOS + - made the console exit properly when an interactive command is active (`liquids`, `mode`, `tiletypes`) +- Linux: added automatic support for GCC sanitizers in ``dfhack`` script +- Made the ``DFHACK_PORT`` environment variable take priority over ``remote-server.json`` +- `dfhack-run`: added support for port specified in ``remote-server.json``, to match DFHack's behavior +- `digfort`: added better map bounds checking +- `remove-stress`: + - added support for ``-all`` as an alternative to the existing ``all`` argument for consistency + - sped up significantly + - improved output/error messages + - now removes tantrums, depression, and obliviousness +- `ruby`: sped up handling of onupdate events + +API +--- +- Exposed ``Screen::zoom()`` to C++ (was Lua-only) +- New functions: ``Units::isDiplomat(unit)`` + +Internals +--------- +- jsoncpp: updated to version 1.8.4 and switched to using a git submodule + +Lua +--- +- Added ``printall_recurse`` to print tables and DF references recursively. It can be also used with ``^`` from the `lua` interpreter. +- ``gui.widgets``: ``List:setChoices`` clones ``choices`` for internal table changes + +Structures +---------- +- ``history_event_entity_expels_hfst``: added (new in 0.44.11) +- ``history_event_site_surrenderedst``: added (new in 0.44.11) +- ``history_event_type``: added ``SITE_SURRENDERED``, ``ENTITY_EXPELS_HF`` (new in 0.44.11) +- ``syndrome``: identified a few fields +- ``viewscreen_civlistst``: fixed layout and identified many fields + + +DFHack 0.44.11-alpha1 +===================== + +Structures +---------- +- Added support for automatically sizing arrays indexed with an enum +- Dropped 0.44.10 support +- Removed stale generated CSV files and DT layouts from pre-0.43.05 +- ``announcement_type``: new in 0.44.11: ``NEW_HOLDING``, ``NEW_MARKET_LINK`` +- ``breath_attack_type``: added ``OTHER`` +- ``historical_figure_info.relationships.list``: added ``unk_3a``-``unk_3c`` fields at end +- ``interface_key``: added bindings new in 0.44.11 +- ``occupation_type``: new in 0.44.11: ``MESSENGER`` +- ``profession``: new in 0.44.11: ``MESSENGER`` +- ``ui_sidebar_menus``: + - ``unit.in_squad``: renamed to ``unit.squad_list_opened``, fixed location + - ``unit``: added ``expel_error`` and other unknown fields new in 0.44.11 + - ``hospital``: added, new in 0.44.11 + - ``num_speech_tokens``, ``unk_17d8``: moved out of ``command_line`` to fix layout on x64 +- ``viewscreen_civlistst``: added a few new fields (incomplete) +- ``viewscreen_locationsst``: identified ``edit_input`` + + +DFHack 0.44.10-r2 +================= + +New Plugins +----------- +- `cxxrandom`: exposes some features of the C++11 random number library to Lua + +New Scripts +----------- +- `add-recipe`: adds unknown crafting recipes to the player's civ +- `gui/stamper`: allows manipulation of designations by transforms such as translations, reflections, rotations, and inversion + +Fixes +----- +- Fixed many tools incorrectly using the ``dead`` unit flag (they should generally check ``flags2.killed`` instead) +- Fixed many tools passing incorrect arguments to printf-style functions, including a few possible crashes (`changelayer`, `follow`, `forceequip`, `generated-creature-renamer`) +- Fixed several bugs in Lua scripts found by static analysis (df-luacheck) +- Fixed ``-g`` flag (GDB) in Linux ``dfhack`` script (particularly on x64) +- `autochop`, `autodump`, `autogems`, `automelt`, `autotrade`, `buildingplan`, `dwarfmonitor`, `fix-unit-occupancy`, `fortplan`, `stockflow`: fix issues with periodic tasks not working for some time after save/load cycles +- `autogems`: + - stop running repeatedly when paused + - fixed crash when furnaces are linked to same stockpiles as jeweler's workshops +- `autogems`, `fix-unit-occupancy`: stopped running when a fort isn't loaded (e.g. while embarking) +- `autounsuspend`: now skips planned buildings +- `ban-cooking`: fixed errors introduced by kitchen structure changes in 0.44.10-r1 +- `buildingplan`, `fortplan`: stopped running before a world has fully loaded +- `deramp`: fixed deramp to find designations that already have jobs posted +- `dig`: fixed "Inappropriate dig square" announcements if digging job has been posted +- `fixnaked`: fixed errors due to emotion changes in 0.44 +- `remove-stress`: fixed an error when running on soul-less units (e.g. with ``-all``) +- `revflood`: stopped revealing tiles adjacent to tiles above open space inappropriately +- `stockpiles`: ``loadstock`` now sets usable and unusable weapon and armor settings +- `stocks`: stopped listing carried items under stockpiles where they were picked up from + +Misc Improvements +----------------- +- Added script name to messages produced by ``qerror()`` in Lua scripts +- Fixed an issue in around 30 scripts that could prevent edits to the files (adding valid arguments) from taking effect +- Linux: Added several new options to ``dfhack`` script: ``--remotegdb``, ``--gdbserver``, ``--strace`` +- `bodyswap`: improved error handling +- `buildingplan`: added max quality setting +- `caravan`: documented (new in 0.44.10-alpha1) +- `deathcause`: added "slaughtered" to descriptions +- `embark-assistant`: + - changed region interaction matching to search for evil rain, syndrome rain, and reanimation rather than interaction presence (misleadingly called evil weather), reanimation, and thralling + - gave syndrome rain and reanimation wider ranges of criterion values +- `fix/dead-units`: added a delay of around 1 month before removing units +- `fix/retrieve-units`: now re-adds units to active list to counteract `fix/dead-units` +- `modtools/create-unit`: + - added quantity argument + - now selects a caste at random if none is specified +- `mousequery`: + - migrated several features from TWBT's fork + - added ability to drag with left/right buttons + - added depth display for TWBT (when multilevel is enabled) + - made shift+click jump to lower levels visible with TWBT +- `title-version`: added version to options screen too +- ``item-descriptions``: fixed several grammatical errors + +API +--- +- New functions (also exposed to Lua): + - ``Units::isKilled()`` + - ``Units::isActive()`` + - ``Units::isGhost()`` +- Removed Vermin module (unused and obsolete) + +Internals +--------- +- Added build option to generate symbols for large generated files containing df-structures metadata +- Added fallback for YouCompleteMe database lookup failures (e.g. for newly-created files) +- Improved efficiency and error handling in ``stl_vsprintf`` and related functions +- jsoncpp: fixed constructor with ``long`` on Linux + +Lua +--- +- Added ``profiler`` module to measure lua performance +- Enabled shift+cursor movement in WorkshopOverlay-derived screens + +Structures +---------- +- ``incident_sub6_performance``: identified some fields +- ``item_body_component``: fixed location of ``corpse_flags`` +- ``job_handler``: fixed static array layout +- ``job_type``: added ``is_designation`` attribute +- ``unit_flags1``: renamed ``dead`` to ``inactive`` to better reflect its use +- ``unit_personality``: fixed location of ``current_focus`` and ``undistracted_focus`` +- ``unit_thought_type``: added ``SawDeadBody`` (new in 0.44.10) + + +DFHack 0.44.10-r1 +================= + +New Scripts +----------- +- `bodyswap`: shifts player control over to another unit in adventure mode + +New Tweaks +---------- +- `tweak` kitchen-prefs-all: adds an option to toggle cook/brew for all visible items in kitchen preferences +- `tweak` stone-status-all: adds an option to toggle the economic status of all stones + +Fixes +----- +- Lua: registered ``dfhack.constructions.designateRemove()`` correctly +- `prospector`: fixed crash due to invalid vein materials +- `tweak` max-wheelbarrow: fixed conflict with building renaming +- `view-item-info`: stopped appending extra newlines permanently to descriptions + +Misc Improvements +----------------- +- Added logo to documentation +- Documented several missing ``dfhack.gui`` Lua functions +- `adv-rumors`: bound to Ctrl-A +- `command-prompt`: added support for ``Gui::getSelectedPlant()`` +- `gui/advfort`: bound to Ctrl-T +- `gui/room-list`: added support for ``Gui::getSelectedBuilding()`` +- `gui/unit-info-viewer`: bound to Alt-I +- `modtools/create-unit`: made functions available to other scripts +- `search-plugin`: + - added support for stone restrictions screen (under ``z``: Status) + - added support for kitchen preferences (also under ``z``) + +API +--- +- New functions (all available to Lua as well): + - ``Buildings::getRoomDescription()`` + - ``Items::checkMandates()`` + - ``Items::canTrade()`` + - ``Items::canTradeWithContents()`` + - ``Items::isRouteVehicle()`` + - ``Items::isSquadEquipment()`` + - ``Kitchen::addExclusion()`` + - ``Kitchen::findExclusion()`` + - ``Kitchen::removeExclusion()`` +- syndrome-util: added ``eraseSyndromeData()`` + +Internals +--------- +- Fixed compiler warnings on all supported build configurations +- Windows build scripts now work with non-C system drives + +Structures +---------- +- ``dfhack_room_quality_level``: new enum +- ``glowing_barrier``: identified ``triggered``, added comments +- ``item_flags2``: renamed ``has_written_content`` to ``unk_book`` +- ``kitchen_exc_type``: new enum (for ``ui.kitchen``) +- ``mandate.mode``: now an enum +- ``unit_personality.emotions.flags.memory``: identified +- ``viewscreen_kitchenprefst.forbidden``, ``possible``: now a bitfield, ``kitchen_pref_flag`` +- ``world_data.feature_map``: added extensive documentation (in XML) + + +DFHack 0.44.10-beta1 +==================== + +New Scripts +----------- +- `devel/find-primitive`: finds a primitive variable in memory + +Fixes +----- +- Units::getAnyUnit(): fixed a couple problematic conditions and potential segfaults if global addresses are missing +- `autodump`, `automelt`, `autotrade`, `stocks`, `stockpiles`: fixed conflict with building renaming +- `exterminate`: fixed documentation of ``this`` option +- `full-heal`: + - units no longer have a tendency to melt after being healed + - healed units are no longer treated as patients by hospital staff + - healed units no longer attempt to clean themselves unsuccessfully + - wounded fliers now regain the ability to fly upon being healing + - now heals suffocation, numbness, infection, spilled guts and gelding +- `modtools/create-unit`: + - creatures of the appropriate age are now spawned as babies or children where applicable + - fix: civ_id is now properly assigned to historical_figure, resolving several hostility issues (spawned pets are no longer attacked by fortress military!) + - fix: unnamed creatures are no longer spawned with a string of numbers as a first name +- `stockpiles`: stopped sidebar option from overlapping with `autodump` +- `tweak` block-labors: fixed two causes of crashes related in the v-p-l menu + +Misc Improvements +----------------- +- `blueprint`: added a basic Lua API +- `devel/export-dt-ini`: added tool offsets for DT 40 +- `devel/save-version`: added current DF version to output +- `install-info`: added information on tweaks + +Internals +--------- +- Added function names to DFHack's NullPointer and InvalidArgument exceptions +- Added ``Gui::inRenameBuilding()`` +- Linux: required plugins to have symbols resolved at link time, for consistency with other platforms + + +DFHack 0.44.10-alpha1 +===================== + +New Scripts +----------- +- `caravan`: adjusts properties of caravans +- `gui/autogems`: a configuration UI for the `autogems` plugin + +Fixes +----- +- Fixed uninitialized pointer being returned from ``Gui::getAnyUnit()`` in rare cases +- `autohauler`, `autolabor`, `labormanager`: fixed fencepost error and potential crash +- `dwarfvet`: fixed infinite loop if an animal is not accepted at a hospital +- `liquids`: fixed "range" command to default to 1 for dimensions consistently +- `search-plugin`: fixed 4/6 keys in unit screen search +- `view-item-info`: fixed an error with some armor + +Misc Improvements +----------------- +- `autogems`: can now blacklist arbitrary gem types (see `gui/autogems`) +- `exterminate`: added more words for current unit, removed warning +- `fpause`: now pauses worldgen as well + +Internals +--------- +- Added some build scripts for Sublime Text +- Changed submodule URLs to relative URLs so that they can be cloned consistently over different protocols (e.g. SSH) + + +DFHack 0.44.09-r1 +================= + +Fixes +----- +- `modtools/item-trigger`: fixed token format in help text + +Misc Improvements +----------------- +- Reorganized changelogs and improved changelog editing process +- `modtools/item-trigger`: added support for multiple type/material/contaminant conditions + +Internals +--------- +- OS X: Can now build with GCC 7 (or older) + +Structures +---------- +- ``army``: added vector new in 0.44.07 +- ``building_type``: added human-readable ``name`` attribute +- ``furnace_type``: added human-readable ``name`` attribute +- ``renderer``: fixed vtable addresses on 64-bit OS X +- ``site_reputation_report``: named ``reports`` vector +- ``workshop_type``: added human-readable ``name`` attribute + + +DFHack 0.44.09-alpha1 +===================== + +Fixes +----- +- `digtype`: stopped designating non-vein tiles (open space, trees, etc.) +- `labormanager`: fixed crash due to dig jobs targeting some unrevealed map blocks + + +DFHack 0.44.08-alpha1 +===================== + +Fixes +----- +- `fix/dead-units`: fixed a bug that could remove some arriving (not dead) units + + +DFHack 0.44.07-beta1 +==================== + +Misc Improvements +----------------- +- `modtools/item-trigger`: added the ability to specify inventory mode(s) to trigger on + +Structures +---------- +- Added symbols for Toady's `0.44.07 Linux test build `_ to fix :bug:`10615` +- ``world_site``: fixed alignment + + +DFHack 0.44.07-alpha1 +===================== + +Fixes +----- +- Fixed some CMake warnings (CMP0022) +- Support for building on Ubuntu 18.04 +- `embark-assistant`: fixed detection of reanimating biomes + +Misc Improvements +----------------- +- `embark-assistant`: + - Added search for adamantine + - Now supports saving/loading profiles +- `fillneeds`: added ``-all`` option to apply to all units +- `remotefortressreader`: added flows, instruments, tool names, campfires, ocean waves, spiderwebs + +Structures +---------- +- Several new names in instrument raw structures +- ``identity``: identified ``profession``, ``civ`` +- ``manager_order_template``: fixed last field type +- ``viewscreen_createquotast``: fixed layout +- ``world.language``: moved ``colors``, ``shapes``, ``patterns`` to ``world.descriptors`` +- ``world.reactions``, ``world.reaction_categories``: moved to new compound, ``world.reactions``. Requires renaming: + - ``world.reactions`` to ``world.reactions.reactions`` + - ``world.reaction_categories`` to ``world.reactions.reaction_categories`` + + +DFHack 0.44.05-r2 +================= + +New Plugins +----------- +- `embark-assistant`: adds more information and features to embark screen + +New Scripts +----------- +- `adv-fix-sleepers`: fixes units in adventure mode who refuse to wake up (:bug:`6798`) +- `hermit`: blocks caravans, migrants, diplomats (for hermit challenge) + +New Features +------------ +- With ``PRINT_MODE:TEXT``, setting the ``DFHACK_HEADLESS`` environment variable will hide DF's display and allow the console to be used normally. (Note that this is intended for testing and is not very useful for actual gameplay.) + +Fixes +----- +- `devel/export-dt-ini`: fix language_name offsets for DT 39.2+ +- `devel/inject-raws`: fixed gloves and shoes (old typo causing errors) +- `remotefortressreader`: fixed an issue with not all engravings being included +- `view-item-info`: fixed an error with some shields + +Misc Improvements +----------------- +- `adv-rumors`: added more keywords, including names +- `autochop`: can now exclude trees that produce fruit, food, or cookable items +- `remotefortressreader`: added plant type support + + +DFHack 0.44.05-r1 +================= + +New Scripts +----------- +- `break-dance`: Breaks up a stuck dance activity +- `fillneeds`: Use with a unit selected to make them focused and unstressed +- `firestarter`: Lights things on fire: items, locations, entire inventories even! +- `flashstep`: Teleports adventurer to cursor +- `ghostly`: Turns an adventurer into a ghost or back +- `questport`: Sends your adventurer to the location of your quest log cursor +- `view-unit-reports`: opens the reports screen with combat reports for the selected unit + +Fixes +----- +- `devel/inject-raws`: now recognizes spaces in reaction names +- `dig`: added support for designation priorities - fixes issues with designations from ``digv`` and related commands having extremely high priority +- `dwarfmonitor`: + - fixed display of creatures and poetic/music/dance forms on ``prefs`` screen + - added "view unit" option + - now exposes the selected unit to other tools +- `names`: fixed many errors +- `quicksave`: fixed an issue where the "Saving..." indicator often wouldn't appear + +Misc Improvements +----------------- +- `binpatch`: now reports errors for empty patch files +- `force`: now provides useful help +- `full-heal`: + - can now select corpses to resurrect + - now resets body part temperatures upon resurrection to prevent creatures from freezing/melting again + - now resets units' vanish countdown to reverse effects of `exterminate` +- `gui/gm-unit`: + - added a profession editor + - misc. layout improvements +- `launch`: can now ride creatures +- `names`: can now edit names of units +- `remotefortressreader`: + - support for moving adventurers + - support for vehicles, gem shapes, item volume, art images, item improvements + +Removed +------- +- `tweak`: ``kitchen-keys``: :bug:`614` fixed in DF 0.44.04 + +Internals +--------- +- ``Gui::getAnyUnit()`` supports many more screens/menus + +Structures +---------- +- New globals: ``soul_next_id`` + + +DFHack 0.44.05-alpha1 +===================== + +Misc Improvements +----------------- +- `gui/liquids`: added more keybindings: 0-7 to change liquid level, P/B to cycle backwards + +Structures +---------- +- ``incident``: re-aligned again to match disassembly + + +DFHack 0.44.04-alpha1 +===================== + +Fixes +----- +- `devel/inject-raws`: now recognizes spaces in reaction names +- `exportlegends`: fixed an error that could occur when exporting empty lists + +Structures +---------- +- ``artifact_record``: fixed layout (changed in 0.44.04) +- ``incident``: fixed layout (changed in 0.44.01) - note that many fields have moved + + +DFHack 0.44.03-beta1 +==================== + +Fixes +----- +- `autolabor`, `autohauler`, `labormanager`: added support for "put item on display" jobs and building/destroying display furniture +- `gui/gm-editor`: fixed an error when editing primitives in Lua tables + +Misc Improvements +----------------- +- `devel/dump-offsets`: now ignores ``index`` globals +- `gui/pathable`: added tile types to sidebar +- `modtools/skill-change`: + - now updates skill levels appropriately + - only prints output if ``-loud`` is passed + +Structures +---------- +- Added ``job_type.PutItemOnDisplay`` +- Added ``twbt_render_map`` code offset on x64 +- Fixed an issue preventing ``enabler`` from being allocated by DFHack +- Found ``renderer`` vtable on osx64 +- New globals: + - ``version`` + - ``min_load_version`` + - ``movie_version`` + - ``basic_seed`` + - ``title`` + - ``title_spaced`` + - ``ui_building_resize_radius`` +- ``adventure_movement_optionst``, ``adventure_movement_hold_tilest``, ``adventure_movement_climbst``: named coordinate fields +- ``mission``: added type +- ``unit``: added 3 new vmethods: ``getCreatureTile``, ``getCorpseTile``, ``getGlowTile`` +- ``viewscreen_assign_display_itemst``: fixed layout on x64 and identified many fields +- ``viewscreen_reportlistst``: fixed layout, added ``mission_id`` vector +- ``world.status``: named ``missions`` vector + + +DFHack 0.44.03-alpha1 +===================== + +Lua +--- +- Improved ``json`` I/O error messages +- Stopped a crash when trying to create instances of classes whose vtable addresses are not available + + +DFHack 0.44.02-beta1 +==================== + +New Scripts +----------- +- `devel/check-other-ids`: Checks the validity of "other" vectors in the ``world`` global +- `gui/cp437-table`: An in-game CP437 table + +Fixes +----- +- Fixed issues with the console output color affecting the prompt on Windows +- `createitem`: stopped items from teleporting away in some forts +- `gui/gm-unit`: can now edit mining skill +- `gui/quickcmd`: stopped error from adding too many commands +- `modtools/create-unit`: fixed error when domesticating units + +Misc Improvements +----------------- +- The console now provides suggestions for built-in commands +- `devel/export-dt-ini`: avoid hardcoding flags +- `exportlegends`: + - reordered some tags to match DF's order + - added progress indicators for exporting long lists +- `gui/gm-editor`: added enum names to enum edit dialogs +- `gui/gm-unit`: made skill search case-insensitive +- `gui/rename`: added "clear" and "special characters" options +- `remotefortressreader`: + - includes item stack sizes + - some performance improvements + +Removed +------- +- `warn-stuck-trees`: :bug:`9252` fixed in DF 0.44.01 + +Lua +--- +- Exposed ``get_vector()`` (from C++) for all types that support ``find()``, e.g. ``df.unit.get_vector() == df.global.world.units.all`` + +Structures +---------- +- Added ``buildings_other_id.DISPLAY_CASE`` +- Fixed ``unit`` alignment +- Fixed ``viewscreen_titlest.start_savegames`` alignment +- Identified ``historical_entity.unknown1b.deities`` (deity IDs) +- Located ``start_dwarf_count`` offset for all builds except 64-bit Linux; `startdwarf` should work now + + +DFHack 0.44.02-alpha1 +===================== + +New Scripts +----------- +- `devel/dump-offsets`: prints an XML version of the global table included in in DF + +Fixes +----- +- Fixed a crash that could occur if a symbol table in symbols.xml had no content + +Lua +--- +- Added a new ``dfhack.console`` API +- API can now wrap functions with 12 or 13 parameters + +Structures +---------- +- The former ``announcements`` global is now a field in ``d_init`` +- The ``ui_menu_width`` global is now a 2-byte array; the second item is the former ``ui_area_map_width`` global, which is now removed +- ``world`` fields formerly beginning with ``job_`` are now fields of ``world.jobs``, e.g. ``world.job_list`` is now ``world.jobs.list`` + + +DFHack 0.43.05-r3 +================= + +Internals +--------- +- Fixed an uncommon crash that could occur when printing text to the console +- Added lots of previously-missing DF classes +- More names for fields: https://github.com/DFHack/df-structures/compare/0.43.05-r2...0.43.05 + +Fixes +----- +- Linux: fixed argument to ``setarch`` in the ``dfhack`` launcher script +- Ruby: fixed an error that occurred when the DF path contained an apostrophe +- `diggingInvaders` now compiles again and is included +- `labormanager`: + + - stopped waiting for on-duty military dwarves with minor injuries to obtain care + - stopped waiting for meetings when participant(s) are dead + - fixed a crash for dwarves with no cultural identity + +- `luasocket`: fixed ``receive()`` with a byte count +- `orders`: fixed an error when importing orders with material categories +- `siren`: fixed an error +- `stockpiles`: fixed serialization of barrel and bin counts +- `view-item-info`: fixed a ``CHEESE_MAT``-related error + +Misc Improvements +----------------- +- `devel/export-dt-ini`: added more offsets for new DT versions +- `digfort`: added support for changing z-levels +- `exportlegends`: suppressed ABSTRACT_BUILDING warning +- `gui/dfstatus`: excluded logs in constructions +- `labormanager`: + + - stopped assigning woodcutting jobs to elves + - "recover wounded" jobs now weighted based on altruism + +- `remotefortressreader`: added support for buildings, grass, riders, and + hair/beard styles + + +DFHack 0.43.05-r2 +================= + +Internals +--------- +- Rebuilding DFHack can be faster if nothing Git-related has changed +- Plugins can now hook Screen::readTile() +- Improved Lua compatibility with plugins that hook into GUI functions (like TWBT) +- Expanded focus strings for jobmanagement and workquota_condition viewscreens +- ``Gui::getAnyUnit()``: added support for viewscreen_unitst, + viewscreen_textviewerst, viewscreen_layer_unit_relationshipst +- Fixed (limited) keybinding support in PRINT_MODE:TEXT on macOS +- Added a new standardized ``Gui::refreshSidebar()`` function to fix behavior of + some plugins on the lowest z-level +- New ``Buildings`` module functions: ``markedForRemoval()``, ``getCageOccupants()`` +- Limited recursive command invocations to 20 to prevent crashes +- Added an ``onLoad.init-example`` file + +Lua +--- +- Improved C++ exception handling for some native functions that aren't direct + wrappers around C++ functions (in this case, error messages could be nil and + cause the Lua interpreter to quit) +- Added support for a ``key_pen`` option in Label widgets +- Fixed ``to_first`` argument to ``dfhack.screen.dismiss()`` +- Added optional ``map`` parameters to some screen functions +- Exposed some more functions to Lua: + + - ``dfhack.gui.refreshSidebar()`` + - ``dfhack.gui.getAnyUnit()`` + - ``dfhack.gui.getAnyBuilding()`` + - ``dfhack.gui.getAnyItem()`` + - ``dfhack.gui.getAnyPlant()`` + - ``dfhack.gui.getDepthAt()`` + - ``dfhack.units.getUnitsInBox()`` + - ``dfhack.units.isVisible()`` + - ``dfhack.maps.isTileVisible()`` + - ``dfhack.buildings.markedForRemoval()`` + - ``dfhack.buildings.getCageOccupants()`` + - ``dfhack.internal.md5()`` + - ``dfhack.internal.md5File()`` + - ``dfhack.internal.threadid()`` + +- New function: ``widgets.Pages:getSelectedPage()`` +- Added a ``key`` option to EditField and FilteredList widgets +- Fixed an issue preventing ``repeatUtil.cancel()`` from working when called + from the callback + +Ruby +---- +- Fixed a crash when creating new instances of DF virtual classes (e.g. fixes a + `lever` crash) +- Ruby scripts can now be loaded from any script paths specified (from script- + paths.txt or registered through the Lua API) +- ``unit_find()`` now uses ``Gui::getSelectedUnit()`` and works in more places + (e.g. `exterminate` now works from more screens, like `command-prompt`) + +New Internal Commands +--------------------- +- `alias`: allows configuring aliases for other commands + +New Plugins +----------- +- `orders`: Manipulate manager orders +- `pathable`: Back-end for `gui/pathable` + +New Scripts +----------- +- `clear-smoke`: Removes all smoke from the map +- `empty-bin`: Empty a bin onto the floor +- `fix/retrieve-units`: Spawns stuck invaders/guests +- `fix/stuck-merchants`: Dismisses stuck merchants that haven't entered the map yet +- `gui/pathable`: View whether tiles on the map can be pathed to +- `gui/teleport`: A front-end for the `teleport` script +- `warn-stuck-trees`: Detects citizens stuck in trees + +New Tweaks +---------- +- `tweak` burrow-name-cancel: Implements the "back" option when renaming a + burrow, which currently does nothing (:bug:`1518`) +- `tweak` cage-butcher: Adds an option to butcher units when viewing cages with "q" + +Fixes +----- +- Enforced use of ``stdout.log`` and ``stderr.log`` (instead of their ``.txt`` + counterparts) on Windows +- Fixed ``getItemBaseValue()`` for cheese, sheets and instruments +- Fixed alignment in: + + - ``viewscreen_choose_start_sitest`` + - ``viewscreen_export_graphical_mapst`` + - ``viewscreen_setupadventurest`` + - ``viewscreen_setupdwarfgamest`` + +- `adv-max-skills`: fixed error due to viewscreen changes +- `autolabor`: fixed a crash when assigning haulers while traders are active +- `buildingplan`: fixed an issue that prevented certain numbers from being used + in building names +- `confirm`: + + - dialogs are now closed permanently when disabled from the settings UI + - fixed an issue that could have prevented closing dialogs opened by pressing "s" + +- `embark-tools`: stopped the sand indicator from overlapping dialogs +- `exportlegends`: fixed some crashes and site map issues +- `devel/find-offsets`: fixed ``current_weather`` scan +- `gui/extended-status`: fixed an error when no beds are available +- `gui/family-affairs`: fixed issues with assigning lovers +- `gui/gm-editor`: + + - made keybinding display order consistent + - stopped keys from performing actions in help screen + +- `gui/manager-quantity`: + + - now allows orders with a limit of 0 + - fixed screen detection + +- `gui/mechanisms`, `gui/room-list`: fixed an issue when recentering the map when exiting +- `lever`: prevented pulling non-lever buildings, which can cause crashes +- `markdown`: fixed file encoding +- `modtools/create-unit`: + + - fixed when popup announcements are present + - added checks to ensure that the current game mode is restored + +- `resume`: stopped drawing on the map border +- `show-unit-syndromes`: fixed an error when handling some syndromes +- `strangemood`: fixed some issues with material searches +- `view-item-info`: fixed a color-related error for some materials + +Misc Improvements +----------------- +- Docs: prevented automatic hyphenation in some browsers, which was producing + excessive hyphenation sometimes +- `command-prompt`: invoking ``command-prompt`` a second time now hides the prompt +- `gui/extended-status`: added an option to assign/replace the manager +- `gui/load-screen`: + + - adjusted dialog width for long folder names + - added modification times and DF versions to dialog + +- `gui/mechanisms`, `gui/room-list`, `gui/siege-engine`: add and list "exit to map" options +- `lever`: added support for pulling levers at high priority +- `markdown`: now recognizes ``-n`` in addition to ``/n`` +- `remotefortressreader`: more data exported, used by Armok Vision v0.17.0 +- `resume`, `siege-engine`: improved compatibility with GUI-hooking plugins (like TWBT) +- `sc-script`: improved help text +- `teleport`: can now be used as a module +- `tweak` embark-profile-name: now enabled in ``dfhack.init-example`` +- `tweak` hotkey-clear: fixed display on larger screens + + +DFHack 0.43.05-r1 +================= + +Internals +--------- +- 64-bit support on all platforms +- Several structure fixes to match 64-bit DF's memory layout +- Added ``DFHack::Job::removeJob()`` function +- New module: ``Designations`` - handles designation creation (currently for plants only) +- Added ``Gui::getSelectedPlant()`` +- Added ``Units::getMainSocialActivity()``, ``Units::getMainSocialEvent()`` +- Visual Studio 2015 now required to build on Windows instead of 2010 +- GCC 4.8 or newer required to build on Linux and OS X (and now supported on OS X) +- Updated TinyXML from 2.5.3 to 2.6.2 +- Added the ability to download files manually before building + +Lua +--- +- Lua has been updated to 5.3 - see https://www.lua.org/manual/5.3/readme.html for details + + - Floats are no longer implicitly converted to integers in DFHack API calls + +- ``df.new()`` supports more types: ``char``, ``intptr_t``, ``uintptr_t``, ``long``, ``unsigned long`` +- String representations of vectors and a few other containers now include their lengths +- Added a ``tile-material`` module +- Added a ``Painter:key_string()`` method +- Made ``dfhack.gui.revealInDwarfmodeMap()`` available + +Ruby +---- +- Added support for loading ruby 2.x libraries + +New Plugins +----------- +- `dwarfvet` enables animal caretaking +- `generated-creature-renamer`: Renames generated creature IDs for use with graphics packs +- `labormanager` (formerly autolabor2): a more advanced alternative to `autolabor` +- `misery`: re-added and updated for the 0.4x series +- `title-folder`: shows DF folder name in window title bar when enabled + +New Scripts +----------- +- `adv-rumors`: improves the "Bring up specific incident or rumor" menu in adventure mode +- `fix/tile-occupancy`: Clears bad occupancy flags on the selected tile. +- `install-info`: Logs basic troubleshooting information about the current DFHack installation +- `load-save`: loads a save non-interactively +- `modtools/change-build-menu`: Edit the build mode sidebar menus +- `modtools/if-entity`: Run a command if the current entity matches a given ID +- `season-palette`: Swap color palettes with the changes of the seasons +- `unforbid`: Unforbids all items + +New Tweaks +---------- +- `tweak condition-material `: fixes a crash in the work order condition material list +- `tweak hotkey-clear `: adds an option to clear bindings from DF hotkeys + +Fixes +----- +- The DF path on OS X can now contain spaces and ``:`` characters +- Buildings::setOwner() changes now persist properly when saved +- ``ls`` now lists scripts in folders other than ``hack/scripts``, when applicable +- Fixed ``plug`` output alignment for plugins with long names +- `add-thought`: fixed support for emotion names +- `autochop`: + + - fixed several issues with job creation and removal + - stopped designating the center tile (unreachable) for large trees + - stopped options from moving when enabling and disabling burrows + - fixed display of unnamed burrows + +- `devel/find-offsets`: fixed a crash when vtables used by globals aren't available +- `getplants`: + + - fixed several issues with job creation and removal + - stopped designating the center tile (unreachable) for large trees + +- `gui/workflow`: added extra keybinding to work with `gui/extended-status` +- `manipulator`: + + - Fixed crash when selecting a profession from an empty list + - Custom professions are now sorted alphabetically more reliably + +- `modtools/create-item`: + + - made gloves usable by specifying handedness + - now creates pairs of boots and gloves + +- `modtools/create-unit`: + + - stopped permanently overwriting the creature creation menu in arena mode + - now uses non-English names + - added ``-setUnitToFort`` option to make a unit a civ/group member more easily + - fixed some issues where units would appear in unrevealed areas of the map + +- `modtools/item-trigger`: fixed errors with plant growths +- `remotefortressreader`: fixed a crash when serializing the local map +- `ruby`: fixed a crash when unloading the plugin on Windows +- `stonesense`: disabled overlay in STANDARD-based print modes to prevent crashes +- `title-version`: now hidden when loading an arena + +Misc Improvements +----------------- +- Documented all default keybindings (from :file:`dfhack.init-example`) in the + docs for the relevant commands; updates enforced by build system. +- `autounsuspend`: reduced update frequency to address potential performance issues +- `gui/extended-status`: added a feature to queue beds +- `lua` and `gui/gm-editor` now support the same aliases (``scr``, ``unit``, etc.) +- `manipulator`: added social activities to job column +- `remotefortressreader`: Added support for + + - world map snow coverage + - spatters + - wall info + - site towers, world buildings + - surface material + - building items + - DF version info + +- `title-version`: Added a prerelease indicator +- `workflow`: Re-added ``Alt-W`` keybindings + + +DFHack 0.43.05-beta2 +==================== + +Fixes +----- +- Fixed Buildings::updateBuildings(), along with building creation/deletion events +- Fixed ``plug`` output alignment for plugins with long names +- Fixed a crash that happened when a ``LUA_PATH`` environment variable was set +- `add-thought`: fixed number conversion +- `gui/workflow`: fixed range editing producing the wrong results for certain numbers +- `modtools/create-unit`: now uses non-English names +- `modtools/item-trigger`: fixed errors with plant growths +- `remotefortressreader`: fixed a crash when serializing the local map +- `stockflow`: fixed an issue with non-integer manager order limits +- `title-folder`: fixed compatibility issues with certain SDL libraries on macOS + +Structures +---------- +- Added some missing renderer VTable addresses on macOS +- ``entity.resources.organic``: identified ``parchment`` +- ``entity_sell_category``: added ``Parchment`` and ``CupsMugsGoblets`` +- ``ui_advmode_menu``: added ``Build`` +- ``ui_unit_view_mode``: added ``PrefOccupation`` +- ``unit_skill``: identified ``natural_skill_lvl`` (was ``unk_1c``) +- ``viewscreen_jobmanagementst``: identified ``max_workshops`` +- ``viewscreen_overallstatusst``: made ``visible_pages`` an enum +- ``viewscreen_pricest``: identified fields +- ``viewscreen_workquota_conditionst``: gave some fields ``unk`` names + +API Changes +----------- +- Allowed the Lua API to accept integer-like floats and strings when expecting an integer +- Lua: New ``Painter:key_string()`` method +- Lua: Added ``dfhack.getArchitecture()`` and ``dfhack.getArchitectureName()`` + +Additions/Removals: +------------------- +- Added `adv-rumors` script: improves the "Bring up specific incident or rumor" menu in adventure mode +- Added `install-info` script for basic troubleshooting +- Added `tweak condition-material `: fixes a crash in the work order condition material list +- Added `tweak hotkey-clear `: adds an option to clear bindings from DF hotkeys +- `autofarm`: reverted local biome detection (from 0.43.05-alpha3) + +Other Changes +------------- +- Added a DOWNLOAD_RUBY CMake option, to allow use of a system/external ruby library +- Added the ability to download files manually before building +- `gui/extended-status`: added a feature to queue beds +- `remotefortressreader`: added building items, DF version info +- `stonesense`: Added support for 64-bit macOS and Linux + +DFHack 0.43.05-beta1 +==================== + +Fixes +----- +- Fixed various crashes on 64-bit Windows related to DFHack screens, notably `manipulator` +- Fixed addresses of next_id globals on 64-bit Linux (fixes an `automaterial`/box-select crash) +- ``ls`` now lists scripts in folders other than ``hack/scripts``, when applicable +- `modtools/create-unit`: stopped permanently overwriting the creature creation + menu in arena mode +- `season-palette`: fixed an issue where only part of the screen was redrawn + after changing the color scheme +- `title-version`: now hidden when loading an arena + +Structures +---------- +- ``file_compressorst``: fixed field sizes on x64 +- ``historical_entity``: fixed alignment on x64 +- ``ui_sidebar_menus.command_line``: fixed field sizes on x64 +- ``viewscreen_choose_start_sitest``: added 3 missing fields, renamed ``in_embark_only_warning`` +- ``viewscreen_layer_arena_creaturest``: identified more fields +- ``world.math``: identified +- ``world.murky_pools``: identified + +Additions/Removals +------------------ +- `generated-creature-renamer`: Renames generated creature IDs for use with graphics packs + +Other Changes +------------- +- `title-version`: Added a prerelease indicator + +DFHack 0.43.05-alpha4 +===================== + +Fixes +----- +- Fixed an issue with uninitialized bitfields that was causing several issues + (disappearing buildings in `buildingplan`'s planning mode, strange behavior in + the extended `stocks` screen, and likely other problems). This issue was + introduced in 0.43.05-alpha3. +- `stockflow`: Fixed an "integer expected" error + +Structures +---------- +- Located several globals on 64-bit Linux: flows, timed_events, ui_advmode, + ui_building_assign_type, ui_building_assign_is_marked, + ui_building_assign_units, ui_building_assign_items, and ui_look_list. This + fixes `search-plugin`, `zone`, and `force`, among others. +- ``ui_sidebar_menus``: Fixed some x64 alignment issues + +Additions/Removals +------------------ +- Added `fix/tile-occupancy`: Clears bad occupancy flags on the selected tile. + Useful for fixing blocked tiles introduced by the above buildingplan issue. +- Added a Lua ``tile-material`` module + +Other Changes +------------- +- `labormanager`: Add support for shell crafts +- `manipulator`: Custom professions are now sorted alphabetically more reliably + +DFHack 0.43.05-alpha3 +===================== + +Fixes +----- +- `add-thought`: fixed support for emotion names +- `autofarm`: Made surface farms detect local biome +- `devel/export-dt-ini`: fixed squad_schedule_entry size +- `labormanager`: + + - Now accounts for unit attributes + - Made instrument-building jobs work (constructed instruments) + - Fixed deconstructing constructed instruments + - Fixed jobs in bowyer's shops + - Fixed trap component jobs + - Fixed multi-material construction jobs + - Fixed deconstruction of buildings containing items + - Fixed interference caused by "store item in vehicle" jobs + +- `manipulator`: Fixed crash when selecting a profession from an empty list +- `ruby`: + + - Fixed crash on Win64 due to truncated global addresses + - Fixed compilation on Win64 + - Use correct raw string length with encodings + +Structures +---------- +- Changed many ``comment`` XML attributes with version numbers to use new + ``since`` attribute instead +- ``activity_event_conflictst.sides``: named many fields +- ``building_def.build_key``: fixed size on 64-bit Linux and OS X +- ``historical_kills``: + + - ``unk_30`` -> ``killed_underground_region`` + - ``unk_40`` -> ``killed_region`` + +- ``historical_kills.killed_undead``: removed ``skeletal`` flag +- ``ui_advmode``: aligned enough so that it doesn't crash (64-bit OS X/Linux) +- ``ui_advmode.show_menu``: changed from bool to enum +- ``unit_personality.emotions.flags``: now a bitfield + +API Changes +----------- +- Added ``DFHack::Job::removeJob()`` function +- C++: Removed bitfield constructors that take an initial value. These kept + bitfields from being used in unions. Set ``bitfield.whole`` directly instead. +- Lua: ``bitfield.whole`` now returns an integer, not a decimal + +Additions/Removals +------------------ +- Removed source for treefarm plugin (wasn't built) +- Added `modtools/change-build-menu`: Edit the build mode sidebar menus +- Added `modtools/if-entity`: Run a command if the current entity matches a + given ID +- Added `season-palette`: Swap color palettes with the changes of the seasons + +Other changes +------------- +- Changed minimum GCC version to 4.8 on OS X and Linux (earlier versions + wouldn't have worked on Linux anyway) +- Updated TinyXML from 2.5.3 to 2.6.2 + +DFHack 0.43.03-r1 +================= + +Lua +--- +- Label widgets can now easily register handlers for mouse clicks + +New Features +------------ +- `add-thought`: allow syndrome name as ``-thought`` argument +- `gui/gm-editor` + + - Added ability to insert default types into containers. For primitive types leave the type entry empty, and for references use ``*``. + - Added ``shift-esc`` binding to fully exit from editor + - Added ``gui/gm-editor toggle`` command to toggle editor visibility (saving position) + +- `modtools/create-unit`: + + - Added an option to attach units to an existing wild animal population + - Added an option to attach units to a map feature + +Fixes +----- +- `autofarm`: Can now handle crops that grow for more than a season +- `combine-plants`: Fixed recursion into sub-containers +- `createitem`: Now moves multiple created items to cursor correctly +- `exportlegends`: Improved handling of unknown enum items (fixes many errors) +- `gui/create-item`: Fixed quality when creating multiple items +- `gui/mod-manager`: Fixed error when mods folder doesn't exist +- `modtools/item-trigger`: Fixed handling of items with subtypes +- `reveal`: ``revflood`` now handles constructed stairs with floors in generated fortresses +- `stockflow`: + + - Can order metal mechanisms + - Fixed material category of thread-spinning jobs + +Misc Improvements +----------------- +- The built-in ``ls`` command now wraps the descriptions of commands +- `catsplosion`: now a lua script instead of a plugin +- `fix/diplomats`: replaces ``fixdiplomats`` +- `fix/merchants`: replaces ``fixmerchants`` +- `prefchange`: added a ``help`` option +- `probe`: now displays raw tiletype names +- Unified script documentation and in-terminal help options + +Removed +------- +- `tweak` manager-quantity: no longer needed + +DFHack 0.42.06-r1 +================= + +Internals +--------- +- Commands to run on startup can be specified on the command line with ``+`` + + Example:: + + ./dfhack +devel/print-args example + "Dwarf Fortress.exe" +devel/print-args example + +- Prevented plugins with active viewscreens from being unloaded and causing a crash +- Additional script search paths can be specified in dfhack-config/script-paths.txt + +Lua +--- +- `building-hacks` now supports ``auto_gears`` flags. It automatically finds and animates gears in building definition +- Changed how `eventful` triggers reaction complete. Now it has ``onReactionComplete`` and ``onReactionCompleting``. Second one can be canceled + +New Plugins +----------- +- `autogems`: Creates a new Workshop Order setting, automatically cutting rough gems + +New Scripts +----------- +- `devel/save-version`: Displays DF version information about the current save +- `modtools/extra-gamelog`: replaces ``log-region``, ``soundsense-season``, and ``soundsense`` + +New Features +------------ +- `buildingplan`: Support for floodgates, grates, and bars +- `colonies`: new ``place`` subcommand and supports any vermin (default honey bees) +- `confirm`: Added a confirmation for retiring locations +- `exportlegends`: Exports more information (poetic/musical/dance forms, written/artifact content, landmasses, extra histfig information, and more) +- `search-plugin`: Support for new screens: + + - location occupation assignment + - civilization animal training knowledge + - animal trainer assignment + +- `tweak`: + + - ``tweak block-labors``: Prevents labors that can't be used from being toggled + - ``tweak hide-priority``: Adds an option to hide designation priority indicators + - ``tweak title-start-rename``: Adds a safe rename option to the title screen "Start Playing" menu + +- `zone`: + + - Added ``unassign`` subcommand + - Added ``only`` option to ``assign`` subcommand + +Fixes +----- +- Fixed a crash bug caused by the historical figures DFHack uses to store persistent data. +- More plugins should recognize non-dwarf citizens +- Fixed a possible crash from cloning jobs +- moveToBuilding() now sets flags for items that aren't a structural part of the building properly +- `autotrade`, `stocks`: Made trading work when multiple caravans are present but only some can trade +- `confirm` note-delete: No longer interferes with name entry +- `exportlegends`: Handles entities without specific races, and a few other fixes for things new to v0.42 +- `fastdwarf`: Fixed a bug involving teleporting mothers but not the babies they're holding. +- `gaydar`: Fixed text display on OS X/Linux and failure with soul-less creatures +- `manipulator`: + + - allowed editing of non-dwarf citizens + - stopped ghosts and visitors from being editable + - fixed applying last custom profession + +- `modtools/create-unit`: Stopped making units without civs historical figures +- `modtools/force`: + + - Removed siege option + - Prevented a crash resulting from a bad civilization option + +- `showmood`: Fixed name display on OS X/Linux +- `view-item-info`: Fixed density units + +Misc Improvements +----------------- +- `autochop`: Can now edit log minimum/maximum directly and remove limit entirely +- `autolabor`, `autohauler`, `manipulator`: Added support for new jobs/labors/skills +- `colonies`: now implemented by a script +- `createitem`: Can now create items anywhere without specifying a unit, as long as a unit exists on the map +- `devel/export-dt-ini`: Updated for 0.42.06 +- `devel/find-offsets`: Automated several more scans +- `gui/gm-editor`: Now supports finding some items with a numeric ID (with ``i``) +- `lua`: Now supports some built-in variables like `gui/gm-editor`, e.g. ``unit``, ``screen`` +- `remotefortressreader`: Can now trigger keyboard events +- `stockflow`: Now offers better control over individual craft jobs +- `weather`: now implemented by a script +- `zone`: colored output + +Removed +------- +- DFusion: legacy script system, obsolete or replaced by better alternatives + + +DFHack 0.40.24-r5 +================= + +New Features +------------ +- `confirm`: + + - Added a ``uniform-delete`` option for military uniform deletion + - Added a basic in-game configuration UI + +Fixes +----- +- Fixed a rare crash that could result from running `keybinding` in onLoadWorld.init +- Script help that doesn't start with a space is now recognized correctly +- `confirm`: Fixed issues with haul-delete, route-delete, and squad-disband confirmations intercepting keys too aggressively +- `emigration` should work now +- `fix-unit-occupancy`: Significantly optimized - up to 2,000 times faster in large fortresses +- `gui/create-item`: Allow exiting quantity prompt +- `gui/family-affairs`: Fixed an issue where lack of relationships wasn't recognized and other issues +- `modtools/create-unit`: Fixed a possible issue in reclaim fortress mode +- `search-plugin`: Fixed a crash on the military screen +- `tweak` max-wheelbarrow: Fixed a minor display issue with large numbers +- `workflow`: Fixed a crash related to job postings (and added a fix for existing, broken jobs) + +Misc Improvements +----------------- +- Unrecognized command feedback now includes more information about plugins +- `fix/dry-buckets`: replaces the ``drybuckets`` plugin +- `feature`: now implemented by a script + +DFHack 0.40.24-r4 +================= + +Internals +--------- +- A method for caching screen output is now available to Lua (and C++) +- Developer plugins can be ignored on startup by setting the ``DFHACK_NO_DEV_PLUGINS`` environment variable +- The console on Linux and OS X now recognizes keyboard input between prompts +- JSON libraries available (C++ and Lua) +- More DFHack build information used in plugin version checks and available to plugins and lua scripts +- Fixed a rare overflow issue that could cause crashes on Linux and OS X +- Stopped DF window from receiving input when unfocused on OS X +- Fixed issues with keybindings involving :kbd:`Ctrl`:kbd:`A` and :kbd:`Ctrl`:kbd:`Z`, + as well as :kbd:`Alt`:kbd:`E`/:kbd:`U`/:kbd:`N` on OS X +- Multiple contexts can now be specified when adding keybindings +- Keybindings can now use :kbd:`F10`-:kbd:`F12` and :kbd:`0`-:kbd:`9` +- Plugin system is no longer restricted to plugins that exist on startup +- :file:`dfhack.init` file locations significantly generalized + +Lua +--- +- Scripts can be enabled with the built-in `enable`/`disable ` commands +- A new function, ``reqscript()``, is available as a safer alternative to ``script_environment()`` +- Lua viewscreens can choose not to intercept the OPTIONS keybinding + +New internal commands +--------------------- +- `kill-lua`: Interrupt running Lua scripts +- `type`: Show where a command is implemented + +New plugins +----------- +- `confirm`: Adds confirmation dialogs for several potentially dangerous actions +- `fix-unit-occupancy`: Fixes issues with unit occupancy, such as faulty "unit blocking tile" messages (:bug:`3499`) +- `title-version` (formerly ``vshook``): Display DFHack version on title screen + +New scripts +----------- +- `armoks-blessing`: Adjust all attributes, personality, age and skills of all dwarves in play +- `brainwash`: brainwash a dwarf (modifying their personality) +- `burial`: sets all unowned coffins to allow burial ("-pets" to allow pets too) +- `deteriorateclothes`: make worn clothes on the ground wear far faster to boost FPS +- `deterioratecorpses`: make body parts wear away far faster to boost FPS +- `deterioratefood`: make food vanish after a few months if not used +- `elevate-mental`: elevate all the mental attributes of a unit +- `elevate-physical`: elevate all the physical attributes of a unit +- `emigration`: stressed dwarves may leave your fortress if they see a chance +- `fix-ster`: changes fertility/sterility of animals or dwarves +- `gui/family-affairs`: investigate and alter romantic relationships +- `make-legendary`: modify skill(s) of a single unit +- `modtools/create-unit`: create new units from nothing +- `modtools/equip-item`: a script to equip items on units +- `points`: set number of points available at embark screen +- `pref-adjust`: Adjust all preferences of all dwarves in play +- `rejuvenate`: make any "old" dwarf 20 years old +- `starvingdead`: make undead weaken after one month on the map, and crumble after six +- `view-item-info`: adds information and customisable descriptions to item viewscreens +- `warn-starving`: check for starving, thirsty, or very drowsy units and pause with warning if any are found + +New tweaks +---------- +- embark-profile-name: Allows the use of lowercase letters when saving embark profiles +- kitchen-keys: Fixes DF kitchen meal keybindings +- kitchen-prefs-color: Changes color of enabled items to green in kitchen preferences +- kitchen-prefs-empty: Fixes a layout issue with empty kitchen tabs + +Fixes +----- +- Plugins with vmethod hooks can now be reloaded on OS X +- Lua's ``os.system()`` now works on OS X +- Fixed default arguments in Lua gametype detection functions +- Circular lua dependencies (reqscript/script_environment) fixed +- Prevented crash in ``Items::createItem()`` +- `buildingplan`: Now supports hatch covers +- `gui/create-item`: fixed assigning quality to items, made :kbd:`Esc` work properly +- `gui/gm-editor`: handles lua tables properly +- `help`: now recognizes built-in commands, like ``help`` +- `manipulator`: fixed crash when selecting custom professions when none are found +- `remotefortressreader`: fixed crash when attempting to send map info when no map was loaded +- `search-plugin`: fixed crash in unit list after cancelling a job; fixed crash when disabling stockpile category after searching in a subcategory +- `stockpiles`: now checks/sanitizes filenames when saving +- `stocks`: fixed a crash when right-clicking +- `steam-engine`: fixed a crash on arena load; number keys (e.g. 2/8) take priority over cursor keys when applicable +- tweak fps-min fixed +- tweak farm-plot-select: Stopped controls from appearing when plots weren't fully built +- `workflow`: Fixed some issues with stuck jobs. Existing stuck jobs must be cancelled and re-added +- `zone`: Fixed a crash when using ``zone set`` (and a few other potential crashes) + +Misc Improvements +----------------- +- DFHack documentation: + + - massively reorganised, into files of more readable size + - added many missing entries + - indexes, internal links, offline search all documents + - includes documentation of linked projects (df-structures, third-party scripts) + - better HTML generation with Sphinx + - documentation for scripts now located in source files + +- `autolabor`: + + - Stopped modification of labors that shouldn't be modified for brokers/diplomats + - Prioritize skilled dwarves more efficiently + - Prevent dwarves from running away with tools from previous jobs + +- `automaterial`: Fixed several issues with constructions being allowed/disallowed incorrectly when using box-select +- `dwarfmonitor`: + + - widgets' positions, formats, etc. are now customizable + - weather display now separated from the date display + - New mouse cursor widget + +- `gui/dfstatus`: Can enable/disable individual categories and customize metal bar list +- `full-heal`: ``-r`` option removes corpses +- `gui/gm-editor` + + - Pointers can now be displaced + - Added some useful aliases: "item" for the selected item, "screen" for the current screen, etc. + - Now avoids errors with unrecognized types + +- `gui/hack-wish`: renamed to `gui/create-item` +- `keybinding list ` accepts a context +- `lever`: + + - Lists lever names + - ``lever pull`` can be used to pull the currently-selected lever + +- ``memview``: Fixed display issue +- `modtools/create-item`: arguments are named more clearly, and you can specify the creator to be the unit with id ``df.global.unit_next_id-1`` (useful in conjunction with `modtools/create-unit`) +- ``nyan``: Can now be stopped with dfhack-run +- `plug`: lists all plugins; shows state and number of commands in plugins +- `prospect`: works from within command-prompt +- `quicksave`: Restricted to fortress mode +- `remotefortressreader`: Exposes more information +- `search-plugin`: + + - Supports noble suggestion screen (e.g. suggesting a baron) + - Supports fortress mode loo[k] menu + - Recognizes ? and ; keys + +- `stocks`: can now match beginning and end of item names +- `teleport`: Fixed cursor recognition +- `tidlers`, `twaterlvl`: now implemented by scripts instead of a plugin +- `tweak`: + + - debug output now logged to stderr.log instead of console - makes DFHack start faster + - farm-plot-select: Fixed issues with selecting undiscovered crops + +- `workflow`: Improved handling of plant reactions + +Removed +------- +- `embark-tools` nano: 1x1 embarks are now possible in vanilla 0.40.24 + +DFHack 0.40.24-r3 +================= + +Internals +--------- +- Ruby library now included on OS X - Ruby scripts should work on OS X 10.10 +- libstdc++ should work with older versions of OS X +- Added support for `onMapLoad.init / onMapUnload.init ` scripts +- game type detection functions are now available in the World module +- The ``DFHACK_LOG_MEM_RANGES`` environment variable can be used to log information to ``stderr.log`` on OS X +- Fixed adventure mode menu names +- Fixed command usage information for some commands + +Lua +--- +- Lua scripts will only be reloaded if necessary +- Added a ``df2console()`` wrapper, useful for printing DF (CP437-encoded) text to the console in a portable way +- Added a ``strerror()`` wrapper + +New Internal Commands +--------------------- +- `hide`, `show`: hide and show the console on Windows +- `sc-script`: Allows additional scripts to be run when certain events occur (similar to `onLoad.init` scripts) + +New Plugins +----------- +- `autohauler`: A hauling-only version of autolabor + +New Scripts +----------- +- `modtools/reaction-product-trigger`: triggers callbacks when products are produced (contrast with when reactions complete) + +New Tweaks +---------- +- `fps-min `: Fixes the in-game minimum FPS setting +- `shift-8-scroll `: Gives Shift+8 (or ``*``) priority when scrolling menus, instead of scrolling the map +- `tradereq-pet-gender `: Displays pet genders on the trade request screen + +Fixes +----- +- Fixed game type detection in `3dveins`, `gui/create-item`, `reveal`, `seedwatch` +- ``PRELOAD_LIB``: More extensible on Linux +- `add-spatter`, `eventful`: Fixed crash on world load +- `add-thought`: Now has a proper subthought arg. +- `building-hacks`: Made buildings produce/consume correct amount of power +- `fix-armory`: compiles and is available again (albeit with issues) +- `gui/gm-editor`: Added search option (accessible with "s") +- `hack-wish `: Made items stack properly. +- `modtools/skill-change`: Made level granularity work properly. +- `show-unit-syndromes`: should work +- `stockflow`: + + - Fixed error message in Arena mode + - no longer checks the DF version + - fixed ballistic arrow head orders + - convinces the bookkeeper to update records more often + +- `zone`: Stopped crash when scrolling cage owner list + +Misc Improvements +----------------- +- `autolabor`: A negative pool size can be specified to use the most unskilled dwarves +- `building-hacks`: + + - Added a way to allow building to work even if it consumes more power than is available. + - Added setPower/getPower functions. + +- `catsplosion`: Can now trigger pregnancies in (most) other creatures +- `exportlegends`: ``info`` and ``all`` options export ``legends_plus.xml`` with more data for legends utilities +- `manipulator`: + + - Added ability to edit nicknames/profession names + - added "Job" as a View Type, in addition to "Profession" and "Squad" + - added custom profession templates with masking + +- `remotefortressreader`: Exposes more information + + +DFHack 0.40.24-r2 +================= + +Internals +--------- +- Lua scripts can set environment variables of each other with ``dfhack.run_script_with_env`` +- Lua scripts can now call each others internal nonlocal functions with ``dfhack.script_environment(scriptName).functionName(arg1,arg2)`` +- `eventful`: Lua reactions no longer require LUA_HOOK as a prefix; you can register a callback for the completion of any reaction with a name +- Filesystem module now provides file access/modification times and can list directories (normally and recursively) +- Units Module: New functions:: + + isWar + isHunter + isAvailableForAdoption + isOwnCiv + isOwnRace + getRaceName + getRaceNamePlural + getRaceBabyName + getRaceChildName + isBaby + isChild + isAdult + isEggLayer + isGrazer + isMilkable + isTrainableWar + isTrainableHunting + isTamable + isMale + isFemale + isMerchant + isForest + isMarkedForSlaughter + +- Buildings Module: New Functions:: + + isActivityZone + isPenPasture + isPitPond + isActive + findPenPitAt + +Fixes +----- +- ``dfhack.run_script`` should correctly find save-specific scripts now. +- `add-thought`: updated to properly affect stress. +- `hfs-pit`: should work now +- `autobutcher`: takes gelding into account +- :file:`init.lua` existence checks should be more reliable (notably when using non-English locales) + +Misc Improvements +----------------- +Multiline commands are now possible inside dfhack.init scripts. See :file:`dfhack.init-example` for example usage. + + +DFHack 0.40.24-r1 +================= + +Internals +--------- +CMake shouldn't cache DFHACK_RELEASE anymore. People may need to manually update/delete their CMake cache files to get rid of it. + + +DFHack 0.40.24-r0 +================= + +Internals +--------- +- `EventManager`: fixed crash error with EQUIPMENT_CHANGE event. +- key modifier state exposed to Lua (ie :kbd:`Ctrl`, :kbd:`Alt`, :kbd:`Shift`) + +Fixes +----- +``dfhack.sh`` can now be run from other directories on OS X + +New Plugins +----------- +- `blueprint`: export part of your fortress to quickfort .csv files + +New Scripts +----------- +- `hotkey-notes`: print key, name, and jump position of hotkeys + +Removed +------- +- needs_porting/* + +Misc Improvements +----------------- +- Added support for searching more lists + +DFHack 0.40.23-r1 +================= + +Internals +--------- +- plugins will not be loaded if globals they specify as required are not located (should prevent some crashes) + +Fixes +----- +- Fixed numerous (mostly Lua-related) crashes on OS X by including a more up-to-date libstdc++ +- :kbd:`Alt` should no longer get stuck on Windows (and perhaps other platforms as well) +- `gui/advfort` works again +- `autobutcher`: takes sexualities into account +- devel/export-dt-ini: Updated for 0.40.20+ +- `digfort`: now checks file type and existence +- `exportlegends`: Fixed map export +- `full-heal`: Fixed a problem with selecting units in the GUI +- `gui/hack-wish`: Fixed restrictive material filters +- `mousequery`: Changed box-select key to Alt+M +- `dwarfmonitor`: correct date display (month index, separator) +- `putontable`: added to the readme +- `siren` should work again +- stderr.log: removed excessive debug output on OS X +- `trackstop`: No longer prevents cancelling the removal of a track stop or roller. +- Fixed a display issue with ``PRINT_MODE:TEXT`` +- Fixed a symbol error (MapExtras::BiomeInfo::MAX_LAYERS) when compiling DFHack in Debug mode + +New Plugins +----------- +- `fortplan`: designate construction of (limited) buildings from .csv file, quickfort-style + +New Scripts +----------- +- `gui/stockpiles`: an in-game interface for saving and loading stockpile settings files. +- `position`: Reports the current date, time, month, and season, plus some location info. Port/update of position.py +- `hfs-pit`: Digs a hole to hell under the cursor. Replaces needs_porting/hellhole.cpp + +Removed +------- +- embark.lua: Obsolete, use `embark-tools` + +New tweaks +---------- +- `eggs-fertile `: Displays an egg fertility indicator on nestboxes +- `max-wheelbarrow `: Allows assigning more than 3 wheelbarrows to a stockpile + +Misc Improvements +----------------- +- `embark-tools`: Added basic mouse support on the local map +- Made some adventure mode keybindings in :file:`dfhack.init-example` only work in adventure mode +- `gui/companion-order`: added a default keybinding +- further work on needs_porting + + +DFHack 0.40.19-r1 +================= + +Fixes +----- +- `modtools/reaction-trigger`: fixed typo +- `modtools/item-trigger`: should now work with item types + +New plugins +----------- +- `savestock, loadstock `: save and load stockpile settings across worlds and saves + +New scripts +----------- +- `remove-stress`: set selected or all units unit to -1,000,000 stress (this script replaces removebadthoughts) + +Misc improvements +----------------- +- `command-prompt`: can now access selected items, units, and buildings +- `autolabor`: add an optional talent pool parameter + + +DFHack 0.40.16-r1 +================= + +Internals +--------- +- `EventManager` should handle INTERACTION triggers a little better. It still can get confused about who did what but only rarely. +- `EventManager` should no longer trigger REPORT events for old reports after loading a save. +- lua/persist-table: a convenient way of using persistent tables of arbitrary structure and dimension in Lua + +Fixes +----- +- `mousequery`: Disabled when linking levers +- `stocks`: Melting should work now +- `full-heal`: Updated with proper argument handling +- `modtools/reaction-trigger-transition`: should produce the correct syntax now +- `superdwarf`: should work better now +- `forum-dwarves`: update for new df-structures changes + +New Scripts +----------- +- `adaptation`: view or set the cavern adaptation level of your citizens +- `add-thought`: allows the user to add thoughts to creatures. +- `gaydar`: detect the sexual orientation of units on the map +- `markdown`: Save a copy of a text screen in markdown (for reddit among others). +- devel/all-bob: renames everyone Bob to help test interaction-trigger + +Misc Improvements +----------------- +- `autodump`: Can now mark a stockpile for auto-dumping (similar to `automelt` and `autotrade`) +- `buildingplan`: Can now auto-allocate rooms to dwarves with specific positions (e.g. expedition leader, mayor) +- `dwarfmonitor`: now displays a weather indicator and date +- lua/syndrome-util, `modtools/add-syndrome`: now you can remove syndromes by SYN_CLASS +- No longer write empty :file:`.history` files + + +DFHack 0.40.15-r1 +================= + +Fixes +----- +- mousequery: Fixed behavior when selecting a tile on the lowest z-level + +Misc Improvements +----------------- +- `EventManager`: deals with frame_counter getting reset properly now. +- `modtools/item-trigger`: fixed equip/unequip bug and corrected minor documentation error +- `teleport`: Updated with proper argument handling and proper unit-at-destination handling. +- `autotrade`: Removed the newly obsolete :guilabel:`Mark all` functionality. +- `search-plugin`: Adapts to the new trade screen column width +- `tweak fast-trade `: Switching the fast-trade keybinding to Shift-Up/Shift-Down, due to Select All conflict + + +DFHack 0.40.14-r1 +================= + +Internals +--------- +- The DFHack console can now be disabled by setting the DFHACK_DISABLE_CONSOLE environment variable: ``DFHACK_DISABLE_CONSOLE=1 ./dfhack`` + +Fixes +----- +- Stopped duplicate load/unload events when unloading a world +- Stopped ``-e`` from being echoed when DFHack quits on Linux +- `automelt`: now uses a faster method to locate items +- `autotrade`: "Mark all" no longer double-marks bin contents +- `drain-aquifer`: new script replaces the buggy plugin +- `embark-tools`: no longer conflicts with keys on the notes screen +- `fastdwarf`: Fixed problems with combat/attacks +- `forum-dwarves`: should work now +- `manipulator`: now uses a stable sort, allowing sorting by multiple categories +- `rendermax`: updated to work with 0.40 + +New Plugins +----------- +- `trackstop`: Shows track stop friction and dump direction in its :kbd:`q` menu + +New Tweaks +---------- +- farm-plot-select: Adds "Select all" and "Deselect all" options to farm plot menus +- import-priority-category: Allows changing the priority of all goods in a category when discussing an import agreement with the liaison +- manager-quantity: Removes the limit of 30 jobs per manager order +- civ-view-agreement: Fixes overlapping text on the "view agreement" screen +- nestbox-color: Fixes the color of built nestboxes + +Misc Improvements +----------------- +- `exportlegends`: can now handle site maps + + +DFHack 0.40.13-r1 +================= + +Internals +--------- +- unified spatter structs +- added ruby df.print_color(color, string) method for dfhack console + +Fixes +----- +- no more ``-e`` after terminating +- fixed `superdwarf` + + +DFHack 0.40.12-r1 +================= + +Internals +--------- +- support for global `onLoad.init` and `onUnload.init` files, called when loading and unloading a world +- Close file after loading a `binary patch `. + +New Plugins +----------- +- `hotkeys`: Shows in-game viewscreen with all dfhack keybindings active in current mode. +- `automelt`: allows marking stockpiles so any items placed in them will be designated for melting + +Fixes +----- +- possible crash fixed for `gui/hack-wish` +- `search-plugin`: updated to not conflict with BUILDJOB_SUSPEND +- `workflow`: job_material_category -> dfhack_material_category + +Misc Improvements +----------------- +- now you can use ``@`` to print things in interactive Lua with subtly different semantics +- optimizations for stockpiles for `autotrade` and `stockflow` +- updated `exportlegends` to work with new maps, dfhack 40.11 r1+ + + +DFHack 0.40.11-r1 +================= + +Internals +--------- +- Plugins on OS X now use ``.plug.dylib`` as an extension instead of ``.plug.so`` + +Fixes +----- +- `3dveins`: should no longer hang/crash on specific maps +- `autotrade`, `search-plugin`: fixed some layout issues +- `deathcause`: updated +- `gui/hack-wish`: should work now +- `reveal`: no longer allocates data for nonexistent map blocks +- Various documentation fixes and updates + + +DFHack v0.40.10-r1 +================== + +A few bugfixes. + +DFHack v0.40.08-r2 +================== + +Internals +--------- +- supported per save script folders +- Items module: added createItem function +- Sorted CMakeList for plugins and plugins/devel +- `diggingInvaders` no longer builds if plugin building is disabled +- `EventManager`: EQUIPMENT_CHANGE now triggers for new units. New events:: + + ON_REPORT + UNIT_ATTACK + UNLOAD + INTERACTION + +New Scripts +----------- +- lua/repeat-util: makes it easier to make things repeat indefinitely +- lua/syndrome-util: makes it easier to deal with unit syndromes +- `forum-dwarves`: helps copy df viewscreens to a file +- `full-heal`: fully heal a unit +- `remove-wear`: removes wear from all items in the fort +- `repeat`: repeatedly calls a script or a plugin +- ShowUnitSyndromes: shows syndromes affecting units and other relevant info +- `teleport`: teleports units +- `devel/print-args` +- `fix/blood-del`: makes it so civs don't bring barrels full of blood ichor or goo +- `fix/feeding-timers`: reset the feeding timers of all units +- `gui/hack-wish`: creates items out of any material +- `gui/unit-info-viewer`: displays information about units +- `modtools/add-syndrome`: add a syndrome to a unit or remove one +- `modtools/anonymous-script`: execute an lua script defined by a string. Useful for the ``*-trigger`` scripts. +- `modtools/force`: forces events: caravan, migrants, diplomat, megabeast, curiousbeast, mischievousbeast, flier, siege, nightcreature +- `modtools/item-trigger`: triggers commands based on equipping, unequipping, and wounding units with items +- `modtools/interaction-trigger`: triggers commands when interactions happen +- `modtools/invader-item-destroyer`: destroys invaders' items when they die +- `modtools/moddable-gods`: standardized version of Putnam's moddable gods script +- `modtools/projectile-trigger`: standardized version of projectileExpansion +- `modtools/reaction-trigger`: trigger commands when custom reactions complete; replaces autoSyndrome +- `modtools/reaction-trigger-transition`: a tool for converting mods from autoSyndrome to reaction-trigger +- `modtools/random-trigger`: triggers random scripts that you register +- `modtools/skill-change`: for incrementing and setting skills +- `modtools/spawn-flow`: creates flows, like mist or dragonfire +- `modtools/syndrome-trigger`: trigger commands when syndromes happen +- `modtools/transform-unit`: shapeshifts a unit, possibly permanently + +Misc improvements +----------------- +- new function in utils.lua for standardized argument processing + +Removed +------- +- digmat.rb: digFlood does the same functionality with less FPS impact +- invasionNow: `modtools/force` does it better +- autoSyndrome replaced with `modtools/reaction-trigger` +- syndromeTrigger replaced with `modtools/syndrome-trigger` +- devel/printArgs plugin converted to `devel/print-args` +- outsideOnly plugin replaced by `modtools/outside-only` + + +DFHack v0.40.08-r1 +================== + +Was a mistake. Don't use it. + +DFHack v0.34.11-r5 +================== + +Internals +--------- +- support for calling a lua function via a protobuf request (demonstrated by dfhack-run --lua). +- support for basic filesystem operations (e.g. chdir, mkdir, rmdir, stat) in C++ and Lua +- Lua API for listing files in directory. Needed for `gui/mod-manager` +- Lua API for creating unit combat reports and writing to gamelog. +- Lua API for running arbitrary DFHack commands +- support for multiple ``raw/init.d/*.lua`` init scripts in one save. +- eventful now has a more friendly way of making custom sidebars +- on Linux and OS X the console now supports moving the cursor back and forward by a whole word. + +New scripts +----------- +- `gui/mod-manager`: allows installing/uninstalling mods into df from ``df/mods`` directory. +- `gui/clone-uniform`: duplicates the currently selected uniform in the military screen. +- `fix/build-location`: partial work-around for :bug:`5991` (trying to build wall while standing on it) +- `undump-buildings`: removes dump designation from materials used in buildings. +- `exportlegends`: exports data from legends mode, allowing a set-and-forget export of large worlds. +- log-region: each time a fort is loaded identifying information will be written to the gamelog. +- `dfstatus `: show an overview of critical stock quantities, including food, drinks, wood, and bars. +- `command-prompt`: a dfhack command prompt in df. + +New plugins +----------- +- `rendermax`: replace the renderer with something else, eg ``rendermax light``- a lighting engine +- `automelt`: allows marking stockpiles for automelt (i.e. any items placed in stockpile will be designated for melting) +- `embark-tools`: implementations of Embark Anywhere, Nano Embark, and a few other embark-related utilities +- `building-hacks`: Allows to add custom functionality and/or animations to buildings. +- `petcapRemover`: triggers pregnancies in creatures so that you can effectively raise the default pet population cap +- `plant create `: spawn a new shrub under the cursor + +New tweaks +---------- +- craft-age-wear: make crafted items wear out with time like in old versions (:bug:`6003`) +- adamantine-cloth-wear: stop adamantine clothing from wearing out (:bug:`6481`) +- confirm-embark: adds a prompt before embarking (on the "prepare carefully" screen) + +Misc improvements +----------------- +- `plant`: move the 'grow', 'extirpate' and 'immolate' commands as 'plant' subcommands +- `digfort`: improved csv parsing, add start() comment handling +- `exterminate`: allow specifying a caste (exterminate gob:male) +- `createitem`: in adventure mode it now defaults to the controlled unit as maker. +- `autotrade`: adds "(Un)mark All" options to both panes of trade screen. +- `mousequery`: several usability improvements; show live overlay (in menu area) of what's on the tile under the mouse cursor. +- `search-plugin`: workshop profile search added. +- `dwarfmonitor`: add screen to summarise preferences of fortress dwarfs. +- `getplants`: add autochop function to automate woodcutting. +- `stocks`: added more filtering and display options. + +- `siege-engine`: + + - engine quality and distance to target now affect accuracy + - firing the siege engine at a target produces a combat report + - improved movement speed computation for meandering units + - operators in Prepare To Fire mode are released from duty once hungry/thirsty if there is a free replacement + + +DFHack v0.34.11-r4 +================== + +New commands +------------ +- `diggingInvaders` - allows invaders to dig and/or deconstruct walls and buildings in order to get at your dwarves. +- `digFlood` - automatically dig out specified veins as they are revealed +- `enable, disable ` - Built-in commands that can be used to enable/disable many plugins. +- `restrictice` - Restrict traffic on squares above visible ice. +- `restrictliquids` - Restrict traffic on every visible square with liquid. +- treefarm - automatically chop trees and dig obsidian + +New Scripts +----------- +- `autobutcher`: A GUI front-end for the autobutcher plugin. +- invasionNow: trigger an invasion, or many +- `locate-ore`: scan the map for unmined ore veins +- `masspit`: designate caged creatures in a zone for pitting +- `multicmd`: run a sequence of dfhack commands, separated by ';' +- `startdwarf`: change the number of dwarves for a new embark +- digmat: dig veins/layers tile by tile, as discovered + +Misc improvements +----------------- +- autoSyndrome: + + - disable by default + - reorganized special tags + - minimized error spam + - reset policies: if the target already has an instance of the syndrome you can skip, + add another instance, reset the timer, or add the full duration to the time remaining + +- core: fix SC_WORLD_(UN)LOADED event for arena mode +- `exterminate`: renamed from slayrace, add help message, add butcher mode +- `fastdwarf`: fixed bug involving fastdwarf and teledwarf being on at the same time +- magmasource: rename to `source`, allow water/magma sources/drains +- Add df.dfhack_run "somecommand" to Ruby +- syndromeTrigger: replaces and extends trueTransformation. Can trigger things when syndromes are added for any reason. +- `tiletypes`: support changing tile material to arbitrary stone. +- `workNow`: can optionally look for jobs when jobs are completed + +New tweaks +---------- +- hive-crash: Prevent crash if bees die in a hive with ungathered products (:bug:`6368`). + +New plugins +----------- +- `3dveins`: Reshapes all veins on the map in a way that flows between Z levels. May be unstable. Backup before using. +- `autotrade`: Automatically send items in marked stockpiles to trade depot, when trading is possible. +- `buildingplan`: Place furniture before it's built +- `dwarfmonitor`: Records dwarf activity to measure fort efficiency +- `mousequery`: Look and poke at the map elements with the mouse. +- outsideOnly: make raw-specified buildings impossible to build inside +- `resume`: A plugin to help display and resume suspended constructions conveniently +- `stocks`: An improved stocks display screen. + +Internals +--------- +- Core: there is now a per-save dfhack.init file for when the save is loaded, and another for when it is unloaded +- EventManager: fixed job completion detection, fixed removal of TICK events, added EQUIPMENT_CHANGE event +- Lua API for a better `random number generator ` and perlin noise functions. +- Once: easy way to make sure something happens once per run of DF, such as an error message + + +DFHack v0.34.11-r3 +================== + +Internals +--------- +- support for displaying active keybindings properly. +- support for reusable widgets in lua screen library. +- Maps::canStepBetween: returns whether you can walk between two tiles in one step. +- EventManager: monitors various in game events centrally so that individual plugins + don't have to monitor the same things redundantly. +- Now works with OS X 10.6.8 + +Notable bugfixes +---------------- +- `autobutcher` can be re-enabled again after being stopped. +- stopped `Dwarf Manipulator ` from unmasking vampires. +- `stonesense` is now fixed on OS X + +Misc improvements +----------------- +- `fastdwarf`: new mode using debug flags, and some internal consistency fixes. +- added a small stand-alone utility for applying and removing `binary patches `. +- removebadthoughts: add --dry-run option +- `superdwarf`: work in adventure mode too +- `tweak` stable-cursor: carries cursor location from/to Build menu. +- `deathcause`: allow selection from the unitlist screen +- slayrace: allow targeting undeads +- `workflow` plugin: + + - properly considers minecarts assigned to routes busy. + - code for deducing job outputs rewritten in lua for flexibility. + - logic fix: collecting webs produces silk, and ungathered webs are not thread. + - items assigned to squads are considered busy, even if not in inventory. + - shearing and milking jobs are supported, but only with generic MILK or YARN outputs. + - workflow announces when the stock level gets very low once a season. + +- Auto syndrome plugin: A way of automatically applying boiling rock syndromes and calling dfhack commands controlled by raws. +- `infiniteSky` plugin: Create new z-levels automatically or on request. +- True transformation plugin: A better way of doing permanent transformations that allows later transformations. +- `workNow` plugin: Makes the game assign jobs every time you pause. + +New tweaks +---------- +- tweak military-training: speed up melee squad training up to 10x (normally 3-5x). + +New scripts +----------- +- `binpatch`: the same as the stand-alone binpatch.exe, but works at runtime. +- region-pops: displays animal populations of the region and allows tweaking them. +- `lua`: lua interpreter front-end converted to a script from a native command. +- dfusion: misc scripts with a text based menu. +- embark: lets you embark anywhere. +- `lever`: list and pull fort levers from the dfhack console. +- `stripcaged`: mark items inside cages for dumping, eg caged goblin weapons. +- soundsense-season: writes the correct season to gamelog.txt on world load. +- create-items: spawn items +- fix/cloth-stockpile: fixes :bug:`5739`; needs to be run after savegame load every time. + +New GUI scripts +--------------- +- `gui/guide-path`: displays the cached path for minecart Guide orders. +- `gui/workshop-job`: displays inputs of a workshop job and allows tweaking them. +- `gui/workflow`: a front-end for the workflow plugin (part inspired by falconne). +- `gui/assign-rack`: works together with a binary patch to fix weapon racks. +- `gui/gm-editor`: an universal editor for lots of dfhack things. +- `gui/companion-order`: a adventure mode command interface for your companions. +- `gui/advfort`: a way to do jobs with your adventurer (e.g. build fort). + +New binary patches +------------------ +(for use with `binpatch`) + +- armorstand-capacity: doubles the capacity of armor stands. +- custom-reagent-size: lets custom reactions use small amounts of inputs. +- deconstruct-heapfall: stops some items still falling on head when deconstructing. +- deconstruct-teleport: stops items from 16x16 block teleporting when deconstructing. +- hospital-overstocking: stops hospital overstocking with supplies. +- training-ammo: lets dwarves with quiver full of combat-only ammo train. +- weaponrack-unassign: fixes bug that negates work done by gui/assign-rack. + +New Plugins +----------- +- `fix-armory`: Together with a couple of binary patches and the `gui/assign-rack` script, this plugin makes weapon racks, armor stands, chests and cabinets in properly designated barracks be used again for storage of squad equipment. +- `search-plugin`: Adds an incremental search function to the Stocks, Trading, Stockpile and Unit List screens. +- `automaterial`: Makes building constructions (walls, floors, fortifications, etc) a little bit easier by saving you from having to trawl through long lists of materials each time you place one. +- Dfusion: Reworked to make use of lua modules, now all the scripts can be used from other scripts. +- Eventful: A collection of lua events, that will allow new ways to interact with df world. + +DFHack v0.34.11-r2 +================== + +Internals +--------- +- full support for Mac OS X. +- a plugin that adds scripting in `ruby `. +- support for interposing virtual methods in DF from C++ plugins. +- support for creating new interface screens from C++ and lua. +- added various other API functions. + +Notable bugfixes +---------------- +- better terminal reset after exit on linux. +- `seedwatch` now works on reclaim. +- the sort plugin won't crash on cages anymore. + +Misc improvements +----------------- +- `autodump`: can move items to any walkable tile, not just floors. +- `stripcaged`: by default keep armor, new dumparmor option. +- `zone`: allow non-domesticated birds in nestboxes. +- `workflow`: quality range in constraints. +- cleanplants: new command to remove rain water from plants. +- `liquids`: can paint permaflow, i.e. what makes rivers power water wheels. +- `prospect`: pre-embark prospector accounts for caves & magma sea in its estimate. +- `rename`: supports renaming stockpiles, workshops, traps, siege engines. +- `fastdwarf`: now has an additional option to make dwarves teleport to their destination. +- `autolabor`: + + - can set nonidle hauler percentage. + - broker excluded from all labors when needed at depot. + - likewise, anybody with a scheduled diplomat meeting. + +New commands +------------ +- misery: multiplies every negative thought gained (2x by default). +- `digtype`: designates every tile of the same type of vein on the map for 'digging' (any dig designation). + +New tweaks +---------- +- tweak stable-cursor: keeps exact cursor position between d/k/t/q/v etc menus. +- tweak patrol-duty: makes Train orders reduce patrol timer, like the binary patch does. +- tweak readable-build-plate: fix unreadable truncation in unit pressure plate build ui. +- tweak stable-temp: fixes bug 6012; may improve FPS by 50-100% on a slow item-heavy fort. +- tweak fast-heat: speeds up item heating & cooling, thus making stable-temp act faster. +- tweak fix-dimensions: fixes subtracting small amounts from stacked liquids etc. +- tweak advmode-contained: fixes UI bug in custom reactions with container inputs in advmode. +- tweak fast-trade: Shift-Enter for selecting items quickly in Trade and Move to Depot screens. +- tweak military-stable-assign: Stop rightmost list of military->Positions from jumping to top. +- tweak military-color-assigned: In same list, color already assigned units in brown & green. + +New scripts +----------- +- `fixnaked`: removes thoughts about nakedness. +- `setfps`: set FPS cap at runtime, in case you want slow motion or speed-up. +- `siren`: wakes up units, stops breaks and parties - but causes bad thoughts. +- `fix/population-cap`: run after every migrant wave to prevent exceeding the cap. +- `fix/stable-temp`: counts items with temperature updates; does instant one-shot stable-temp. +- `fix/loyaltycascade`: fix units allegiance, eg after ordering a dwarf merchant kill. +- `deathcause`: shows the circumstances of death for a given body. +- `digfort`: designate areas to dig from a csv file. +- `drain-aquifer`: remove aquifers from the map. +- `growcrops`: cheat to make farm crops instantly grow. +- magmasource: continuously spawn magma from any map tile. +- removebadthoughts: delete all negative thoughts from your dwarves. +- slayrace: instakill all units of a given race, optionally with magma. +- `superdwarf`: per-creature `fastdwarf`. +- `gui/mechanisms`: browse mechanism links of the current building. +- `gui/room-list`: browse other rooms owned by the unit when assigning one. +- `gui/liquids`: a GUI front-end for the liquids plugin. +- `gui/rename`: renaming stockpiles, workshops and units via an in-game dialog. +- `gui/power-meter`: front-end for the Power Meter plugin. +- `gui/siege-engine`: front-end for the Siege Engine plugin. +- `gui/choose-weapons`: auto-choose matching weapons in the military equip screen. + +New Plugins +----------- +- `manipulator`: a Dwarf Therapist like UI in the game (:kbd:`u`:kbd:`l`) +- `steam-engine`: an alternative to Water Reactors which make more sense. + See ``hack/raw/*_steam_engine.txt`` for the necessary raw definitions. +- `power-meter`: a pressure plate modification to detect powered gear + boxes on adjacent tiles. `gui/power-meter` implements + the build configuration UI. +- `siege-engine`: massive overhaul for siege engines, configured via `gui/siege-engine` +- `add-spatter`: allows poison coatings via raw reactions, among other things. diff --git a/docs/about/Removed.rst b/docs/about/Removed.rst new file mode 100644 index 0000000000..bf3d0118df --- /dev/null +++ b/docs/about/Removed.rst @@ -0,0 +1,406 @@ +############# +Removed tools +############# + +This page lists tools (plugins or scripts) that were previously included in +DFHack but have been removed. It exists primarily so that internal links still +work (e.g. links from the `changelog`). + +.. contents:: Contents + :local: + :depth: 1 + +.. _adv-rumors: + +adv-rumors +========== +Converted to an `overlay` and merged into `advtools`. + +.. _adv-fix-sleepers: + +adv-fix-sleepers +================ +Renamed to `fix/sleepers`. + +.. _autohauler: + +autohauler +========== +An automated labor management tool that only addressed hauling labors, leaving the assignment +of skilled labors entirely up to the player. Fundamentally incompatible with the work detail +system of labor management in v50 of Dwarf Fortress. + +.. _automaterial: + +automaterial +============ +Moved frequently used materials to the top of the materials list when building +buildings. Also offered extended options when building constructions. All +functionality has been merged into `buildingplan`. + +.. _automelt: + +automelt +======== +Automatically mark items for melting when they are brought to a monitored +stockpile. Merged into `logistics`. + +.. _autotrade: + +autotrade +========= +Automatically mark items for trading when they are brought to a monitored +stockpile. Merged into `logistics`. + +.. _autounsuspend: + +autounsuspend +============= +Replaced by `suspendmanager`. + +.. _combine-drinks: + +combine-drinks +============== +Replaced by the new `combine` script. Run +``combine here --types=drink`` + +.. _combine-plants: + +combine-plants +============== +Replaced by the new `combine` script. Run +``combine here --types=plants`` + +.. _command-prompt: + +command-prompt +============== +Replaced by `gui/launcher --minimal `. + +.. _create-items: + +create-items +============ +Replaced by `gui/create-item`. + +.. _deteriorateclothes: + +deteriorateclothes +================== +Replaced by the new combined `deteriorate` script. Run +``deteriorate --types=clothes``. + +.. _deterioratecorpses: + +deterioratecorpses +================== +Replaced by the new combined `deteriorate` script. Run +``deteriorate --types=corpses``. + +.. _deterioratefood: + +deterioratefood +=============== +Replaced by the new combined `deteriorate` script. Run +``deteriorate --types=food``. + +.. _devel/find-offsets: + +devel/find-offsets +================== +Used in pre-v50 times for memory structure analysis. No longer useful post-v50. + +.. _devel/find-twbt: + +devel/find-twbt +=============== +Used in pre-v50 times for memory structure analysis. No longer useful post-v50. + +.. _devel/prepare-save: + +devel/prepare-save +================== +Used in pre-v50 times for memory structure analysis. No longer useful post-v50. + +.. _devel/unforbidall: + +devel/unforbidall +================= +Replaced by the `unforbid` script. Run ``unforbid all --quiet`` to match the +behavior of the original ``devel/unforbidall`` script. + +.. _digfort: + +digfort +======= +A script to designate an area for digging according to a plan in csv format. +Please use DFHack's more powerful `quickfort` script instead. You can use your +existing .csv files. Just move them to the ``blueprints`` folder in your DF +installation, and instead of ``digfort file.csv``, run +``quickfort run file.csv``. + +.. _drain-aquifer: + +drain-aquifer +============= +Replaced by `aquifer` and `gui/aquifer`. + +.. _embark-tools: + +embark-tools +============ +Replaced by `gui/embark-anywhere`. Other functionality was replaced by the DF +v50 UI. + +.. _faststart: + +faststart +========= +Sped up the initial DF load sequence. Removed since Bay 12 rewrote the startup +sequence and it is now sufficiently fast on its own. + +.. _fix-armory: + +fix-armory +========== +Allowed the military to store equipment in barracks containers. Removed because +it required a binary patch to DF in order to function, and no such patch has +existed since DF 0.34.11. + +.. _fix/build-location: + +fix/build-location +================== +The corresponding DF :bug:`5991` was fixed in DF 0.40.05. + +.. _fix/diplomats: + +fix/diplomats +============= +The corresponding DF :bug:`3295` was fixed in DF 0.40.05. + +.. _fix/fat-dwarves: + +fix/fat-dwarves +=============== +The corresponding DF :bug:`5971` was fixed in DF 0.40.05. + +.. _fix/feeding-timers: + +fix/feeding-timers +================== +The corresponding DF :bug:`2606` was fixed in DF 0.40.12. + +.. _fix/item-occupancy: + +fix/item-occupancy +================== +Merged into `fix/occupancy`. + +.. _fix/merchants: + +fix/merchants +============= +Humans can now make trade agreements. This fix is no longer necessary. + +.. _fix/tile-occupancy: + +fix/tile-occupancy +================== +Merged into `fix/occupancy`. + +.. _fix-unit-occupancy: + +fix-unit-occupancy +================== +Merged into `fix/occupancy`. + +.. _fortplan: + +fortplan +======== +Designates furniture for building according to a ``.csv`` file with +quickfort-style syntax. Please use DFHack's more powerful `quickfort` +script instead. You can use your existing .csv files. Just move them to the +``blueprints`` folder in your DF installation, and instead of +``fortplan file.csv`` run ``quickfort run file.csv``. + +.. _gui/assign-rack: + +gui/assign-rack +=============== +This script is no longer useful in current DF versions. The script required a +binpatch `, which has not been available since DF +0.34.11. + +.. _gui/automelt: + +gui/automelt +============ +Replaced by the `stockpiles` overlay and the gui for `logistics`. + +.. _gui/create-tree: + +gui/create-tree +=============== +Replaced by `gui/sandbox`. + +.. _gui/dig: + +gui/dig +======= +Renamed to `gui/design`. + +.. _gui/hack-wish: + +gui/hack-wish +============= +Replaced by `gui/create-item`. + +.. _gui/logcleaner: + +gui/logcleaner +============== +Removed because changes to Dwarf Fortress internals made the functionality +impossible to implement safely. + +.. _gui/manager-quantity: + +gui/manager-quantity +==================== +Ability to modify manager order quantities has been added to the vanilla UI. + +.. _gui/mechanisms: + +gui/mechanisms +============== +Linked building interface has been added to the vanilla UI. + +.. _gui/no-dfhack-init: + +gui/no-dfhack-init +================== +Tool that warned the user when the ``dfhack.init`` file did not exist. Now that +``dfhack.init`` is autogenerated in ``dfhack-config/init``, this warning is no +longer necessary. + +.. _logcleaner: + +logcleaner +=============== +Removed because changes to Dwarf Fortress internals made the functionality +impossible to implement safely. + +.. _masspit: + +masspit +======= +Replaced with a GUI version: `gui/masspit`. + +.. _max-wave: + +max-wave +======== +Set population cap based on parameters. Merged into `pop-control`. + +.. _modtools/force: + +modtools/force +============== +Merged into `force`. + +.. _mousequery: + +mousequery +========== +Functionality superseded by vanilla v50 interface. + +.. _petcapRemover: + +petcapRemover +============= +Renamed to `pet-uncapper`. + +.. _plants: + +plants +====== +Renamed to `plant`. + +.. _rename: + +rename +====== +Superseded by vanilla rename capabilities and `gui/rename`. + +.. _resume: + +resume +====== +Allowed you to resume suspended jobs and displayed an overlay indicating +suspended building construction jobs. Replaced by `unsuspend` script. + +.. _ruby: +.. _rb: + +ruby +==== +Support for the Ruby language in DFHack scripts was removed due to the issues +the Ruby library causes when used as an embedded language. + +.. _search-plugin: + +search +====== +Functionality was merged into `sort`. + +.. _show-unit-syndromes: + +show-unit-syndromes +=================== +Replaced with a GUI version: `gui/unit-syndromes`. + +.. _stocksettings: + +stocksettings +============= +Along with ``copystock``, ``loadstock`` and ``savestock``, replaced with the new +`stockpiles` API. + +.. _title-version: + +title-version +============= +Replaced with an `overlay`. + +.. _unsuspend: + +unsuspend +========= +Merged into `suspendmanager`. + +.. _warn-starving: + +warn-starving +============= +Functionality was merged into `gui/notify`. + +.. _warn-stealers: + +warn-stealers +============= +Functionality was merged into `gui/notify`. + +.. _warn-stuck-trees: + +warn-stuck-trees +================ +The corresponding DF :bug:`9252` was fixed in DF 0.44.01. + +.. _workorder-recheck: + +workorder-recheck +================= +Tool to set 'Checking' status of the selected work order, allowing conditions +to be reevaluated. Merged into `orders`. diff --git a/docs/about/index.rst b/docs/about/index.rst new file mode 100644 index 0000000000..e8dede969c --- /dev/null +++ b/docs/about/index.rst @@ -0,0 +1,13 @@ +============ +About DFHack +============ + +These pages contain information about the general DFHack project. + +.. toctree:: + :maxdepth: 1 + + /docs/about/Authors + /LICENSE + /docs/about/Removed + /docs/NEWS diff --git a/docs/api/Maps.rst b/docs/api/Maps.rst new file mode 100644 index 0000000000..f6a0a98826 --- /dev/null +++ b/docs/api/Maps.rst @@ -0,0 +1,59 @@ +.. include:: + +======== +Maps API +======== + +DFHack offers several ways to access and manipulate map data. + +* C++: the ``Maps`` and ``MapCache`` modules +* Lua: the `dfhack.maps module` +* All languages: the ``map`` field of the ``world`` global contains raw map data + when the world is loaded. + +.. note:: + + This page will eventually go into more detail about the available APIs. + For now, it is just an overview of how DF map data is structured. + +.. contents:: Contents + :local: + +Tiles +===== + +The DF map has several types of tiles: + +- **Local tiles** are at the smallest scale. In regular fortress/adventure mode + play, the cursor takes up 1 local tile. + + Objects that use local tile coordinates include: + + - Units + - Items + - Projectiles + +- **Blocks** are 16 |times| 16 |times| 1 groups of local tiles. Internally, many + tile details are stored at the block level for space-efficiency reasons. + Blocks are visible during zoomed-in fast travel in adventure mode. + + Objects that use block coordinates include: + + - Armies + +- **Region tiles** are 3 |times| 3 groups of columns of blocks (they span the + entire z-axis), or 48 |times| 48 columns of local tiles. DF sometimes refers + to these as "mid-level tiles" (MLTs). Region tiles are visible when resizing + a fortress before embarking, or in zoomed-out fast travel in adventure mode. + +- **World tiles** are + + - 16 |times| 16 groups of region tiles, or + - 48 |times| 48 groups of columns of blocks, or + - 768 |times| 768 groups of columns of local tiles + + World tiles are visible on the world map before embarking, as well as in the + civilization map in fortress mode and the quest log in adventure mode. + +- Some map features are stored in 16 |times| 16 groups of world tiles, sometimes + referred to as "feature shells". diff --git a/docs/api/index.rst b/docs/api/index.rst new file mode 100644 index 0000000000..e0748be2c5 --- /dev/null +++ b/docs/api/index.rst @@ -0,0 +1,8 @@ +=================== +DFHack API concepts +=================== + +.. toctree:: + :maxdepth: 1 + + /docs/api/Maps diff --git a/docs/build.py b/docs/build.py new file mode 100755 index 0000000000..bf0dd9e488 --- /dev/null +++ b/docs/build.py @@ -0,0 +1,106 @@ +#!/usr/bin/env python3 + +# for help, run: python3 build.py --help + +import argparse +import os +import subprocess +import sys + +class SphinxOutputFormat: + def __init__(self, name, pre_args): + self.name = str(name) + self.pre_args = tuple(pre_args) + + @property + def args(self): + output_dir = os.path.join('docs', self.name) + artifacts_dir = os.path.join('build', 'docs', self.name) # for artifacts not part of the final documentation + os.makedirs(artifacts_dir, mode=0o755, exist_ok=True) + return [ + *self.pre_args, + '.', # source dir + output_dir, + '-d', artifacts_dir, + '-w', os.path.join(artifacts_dir, 'sphinx-warnings.txt'), + ] + +OUTPUT_FORMATS = { + 'html': SphinxOutputFormat('html', pre_args=['-b', 'html']), + 'text': SphinxOutputFormat('text', pre_args=['-b', 'text']), + 'pdf': SphinxOutputFormat('pdf', pre_args=['-M', 'latexpdf']), + 'xml': SphinxOutputFormat('xml', pre_args=['-b', 'xml']), + 'pseudoxml': SphinxOutputFormat('pseudoxml', pre_args=['-b', 'pseudoxml']), +} + +def _parse_known_args(parser, source_args): + # pass along any arguments after '--' + ignored_args = [] + if '--' in source_args: + source_args, ignored_args = source_args[:source_args.index('--')], source_args[source_args.index('--')+1:] + args, forward_args = parser.parse_known_args(source_args) + forward_args += ignored_args + return args, forward_args + +def parse_args(source_args): + def output_format(s): + if s in OUTPUT_FORMATS: + return s + raise ValueError + + parser = argparse.ArgumentParser(usage='%(prog)s [{} ...] [options] [--] [sphinx_options]'.format('|'.join(OUTPUT_FORMATS.keys())), description=''' + DFHack wrapper around sphinx-build. + + Any unrecognized options are passed directly to sphinx-build, as well as any + options following a '--' argument, if specified. + ''') + parser.add_argument('format', nargs='*', type=output_format, action='append', + help='Documentation format(s) to build - choose from {}'.format(', '.join(OUTPUT_FORMATS.keys()))) + parser.add_argument('-E', '--clean', action='store_true', + help='Re-read all input files') + parser.add_argument('--sphinx', type=str, default=os.environ.get('SPHINX', 'sphinx-build'), + help='Sphinx executable to run [environment variable: SPHINX; default: "sphinx-build"]') + parser.add_argument('-j', '--jobs', type=str, default=os.environ.get('JOBS', 'auto'), + help='Number of Sphinx threads to run [environment variable: JOBS; default: "auto"]') + parser.add_argument('-q', '--quiet', action='store_true', + help='Disable most output on stdout (also passed to sphinx-build)') + parser.add_argument('--debug', action='store_true', + help='Log commands that are run, etc.') + parser.add_argument('--offline', action='store_true', + help='Disable network connections') + args, forward_args = _parse_known_args(parser, source_args) + + # work around weirdness with list args + args.format = args.format[0] + if not args.format: + args.format = ['html'] + + return args, forward_args + +if __name__ == '__main__': + os.chdir(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + if not os.path.isfile('conf.py'): + print('Could not find conf.py', file=sys.stderr) + exit(1) + + args, forward_args = parse_args(sys.argv[1:]) + + sphinx_env = os.environ.copy() + if args.offline: + sphinx_env['DFHACK_DOCS_BUILD_OFFLINE'] = '1' + + for format_name in args.format: + command = [args.sphinx] + OUTPUT_FORMATS[format_name].args + ['-j', args.jobs] + if args.clean: + command += ['-E'] + if args.quiet: + command += ['-q'] + command += forward_args + + if args.debug: + print('Building:', format_name) + print('Running:', command) + subprocess.run(command, check=True, env=sphinx_env) + + if not args.quiet: + print('') diff --git a/docs/builtins/alias.rst b/docs/builtins/alias.rst new file mode 100644 index 0000000000..69ca42ba0d --- /dev/null +++ b/docs/builtins/alias.rst @@ -0,0 +1,36 @@ +alias +===== + +.. dfhack-tool:: + :summary: Configure helper aliases for other DFHack commands. + :tags: dfhack + +Aliases are resolved immediately after built-in commands, which means that an +alias cannot override a built-in command, but can override a command implemented +by a plugin or script. + +Usage +----- + +``alias list`` + Lists all configured aliases +``alias add [arguments...]`` + Adds an alias +``alias replace [arguments...]`` + Replaces an existing alias with a new command, or adds the alias if it does + not already exist +``alias delete `` + Removes the specified alias + +Aliases can be given additional arguments when created and invoked, which will +be passed to the underlying command in order. + +Example +------- + +:: + + [DFHack]# alias add pargs devel/print-args example + [DFHack]# pargs text + example + text diff --git a/docs/builtins/cls.rst b/docs/builtins/cls.rst new file mode 100644 index 0000000000..a5fc391cdd --- /dev/null +++ b/docs/builtins/cls.rst @@ -0,0 +1,16 @@ +cls +=== + +.. dfhack-tool:: + :summary: Clear the terminal screen. + :tags: dfhack + +Can also be invoked as ``clear``. Note that this command does not delete command +history. It just clears the text on the screen. + +Usage +----- + +:: + + cls diff --git a/docs/builtins/devel/dump-rpc.rst b/docs/builtins/devel/dump-rpc.rst new file mode 100644 index 0000000000..957233b628 --- /dev/null +++ b/docs/builtins/devel/dump-rpc.rst @@ -0,0 +1,15 @@ +devel/dump-rpc +============== + +.. dfhack-tool:: + :summary: Dump RPC endpoint info. + :tags: dev + +Write RPC endpoint information to the specified file. + +Usage +----- + +:: + + devel/dump-rpc diff --git a/docs/builtins/die.rst b/docs/builtins/die.rst new file mode 100644 index 0000000000..3b9a083802 --- /dev/null +++ b/docs/builtins/die.rst @@ -0,0 +1,15 @@ +die +=== + +.. dfhack-tool:: + :summary: Instantly exit DF without saving. + :tags: dfhack + +Use to exit DF quickly and safely. + +Usage +----- + +:: + + die diff --git a/docs/builtins/disable.rst b/docs/builtins/disable.rst new file mode 100644 index 0000000000..7c64f4b39e --- /dev/null +++ b/docs/builtins/disable.rst @@ -0,0 +1,15 @@ +disable +======= + +.. dfhack-tool:: + :summary: Deactivate a DFHack tool that has some persistent effect. + :tags: dfhack + +See the `enable` command for more info. + +Usage +----- + +:: + + disable [ ...] diff --git a/docs/builtins/enable.rst b/docs/builtins/enable.rst new file mode 100644 index 0000000000..8525214b3c --- /dev/null +++ b/docs/builtins/enable.rst @@ -0,0 +1,36 @@ +enable +====== + +.. dfhack-tool:: + :summary: Activate a DFHack tool that has some persistent effect. + :tags: dfhack + +Many plugins and scripts can be in a distinct enabled or disabled state. Some +of them activate and deactivate automatically depending on the contents of the +world raws. Others store their state in world data. However a number of them +have to be enabled globally, and the init file is the right place to do it. + +Most such plugins or scripts support the built-in ``enable`` and `disable` +commands. Calling them at any time without arguments prints a list of enabled +and disabled plugins, and shows whether that can be changed through the same +commands. Passing plugin names to these commands will enable or disable the +specified plugins. + +If you are a script developer, see `script-enable-api` for how to expose whether +your script is currently enabled or disabled. + +Usage +----- + +:: + + enable + enable [ ...] + +Examples +-------- + +``enable manipulator`` + Enable the ``manipulator`` plugin. +``enable manipulator search`` + Enable multiple plugins at once. diff --git a/docs/builtins/fpause.rst b/docs/builtins/fpause.rst new file mode 100644 index 0000000000..ed5a40cad1 --- /dev/null +++ b/docs/builtins/fpause.rst @@ -0,0 +1,15 @@ +fpause +====== + +.. dfhack-tool:: + :summary: Forces DF to pause. + :tags: dfhack + +This is useful when your FPS drops below 1 and you lose control of the game. + +Usage +----- + +:: + + fpause diff --git a/docs/builtins/help.rst b/docs/builtins/help.rst new file mode 100644 index 0000000000..a744e8d69c --- /dev/null +++ b/docs/builtins/help.rst @@ -0,0 +1,29 @@ +help +==== + +.. dfhack-tool:: + :summary: Display help about a command or plugin. + :tags: dfhack + +Can also be invoked as ``?`` or ``man`` (short for "manual"). + +Usage +----- + +:: + + help|?|man + help|?|man + +Examples +-------- + +:: + + help blueprint + man blueprint + +Both examples above will display the help text for the `blueprint` command. + +Some commands also take ``help`` or ``?`` as an option on their command line +for the same effect -- e.g. ``blueprint help``. diff --git a/docs/builtins/hide.rst b/docs/builtins/hide.rst new file mode 100644 index 0000000000..037679d69c --- /dev/null +++ b/docs/builtins/hide.rst @@ -0,0 +1,18 @@ +hide +==== + +.. dfhack-tool:: + :summary: Hide the DFHack terminal window. + :tags: dfhack + +You can show it again with the `show` command, though you'll need to use it from +a `keybinding` set beforehand or the in-game `command-prompt`. + +Only available on Windows. + +Usage +----- + +:: + + hide diff --git a/docs/builtins/keybinding.rst b/docs/builtins/keybinding.rst new file mode 100644 index 0000000000..e8f206848d --- /dev/null +++ b/docs/builtins/keybinding.rst @@ -0,0 +1,84 @@ +keybinding +========== + +.. dfhack-tool:: + :summary: Create hotkeys that will run DFHack commands. + :tags: dfhack + +Like any other command, it can be used at any time from the console, but +bindings are not remembered between runs of the game unless re-created in +:file:`dfhack-config/init/dfhack.init`. + +Hotkeys can be any combinations of Ctrl/Alt/Super/Shift with any key recognized by SDL. +You can also represent mouse buttons beyond the first three with ``MOUSE4`` +through ``MOUSE15``. + +Usage +----- + +``keybinding`` + Show some useful information, including the current game context. +``keybinding list `` + List bindings active for the key combination. +``keybinding clear [...]`` + Remove bindings for the specified keys. +``keybinding add "" ["" ...]`` + Add bindings for the specified key. +``keybinding set "" ["" ...]`` + Clear, and then add bindings for the specified key. + +The ```` parameter above has the following case-insensitive syntax:: + + [Ctrl-][Alt-][Super-][Shift-]KEY[@context[|context...]] + +where the ``KEY`` part can be any recognized key and :kbd:`[`:kbd:`]` denote +optional parts. It is important to note that the key is the non-shifted version +of the key. For example ``!`` would be defined as ``Shift-0``. + +DFHack commands can advertise the contexts in which they can be usefully run. +For example, a command that acts on a selected unit can tell `keybinding` that +it is not "applicable" in the current context if a unit is not actively +selected. + +When multiple commands are bound to the same key combination, DFHack selects +the first applicable one. Later ``add`` commands, and earlier entries within one +``add`` command have priority. Commands that are not specifically intended for +use as a hotkey are always considered applicable. + +The ``context`` part in the key specifier above can be used to explicitly +restrict the UI state where the binding would be applicable. + +Only bindings with a ``context`` tag that either matches the current context +fully, or is a prefix ending at a ``/`` boundary would be considered for +execution, i.e. when in context ``foo/bar/baz``, keybindings restricted to any +of ``@foo/bar/baz``, ``@foo/bar``, ``@foo``, or none will be active. + +Multiple contexts can be specified by separating them with a pipe (``|``) - for +example, ``@foo|bar|baz/foo`` would match anything under ``@foo``, ``@bar``, or +``@baz/foo``. + +Commands like `liquids` or `tiletypes` cannot be used as hotkeys since they +require the console for interactive input. + +Examples +-------- + +Bind Ctrl-Shift-C to run the `hotkeys` command on any screen at any time:: + + keybinding add Ctrl-Shift-C hotkeys + +Bind Ctrl-M to run `gui/mass-remove`, but only when on the main map with +nothing else selected:: + + keybinding add Ctrl-M@dwarfmode/Default gui/mass-remove + +Bind the fourth mouse button to launch `gui/teleport` when a unit is selected +or `gui/autodump` when an item is selected:: + + keybinding add MOUSE4@dwarfmode/ViewSheets/UNIT gui/teleport + keybinding add MOUSE4@dwarfmode/ViewSheets/ITEM gui/autodump + +Bind Shift + the fifth mouse button to toggle the keyboard cursor in fort or +adventure mode:: + + keybinding add Shift-MOUSE5@dwarfmode|dungeonmode toggle-kbd-cursor diff --git a/docs/builtins/kill-lua.rst b/docs/builtins/kill-lua.rst new file mode 100644 index 0000000000..4cb3e203c4 --- /dev/null +++ b/docs/builtins/kill-lua.rst @@ -0,0 +1,18 @@ +kill-lua +======== + +.. dfhack-tool:: + :summary: Gracefully stop any currently-running Lua scripts. + :tags: dfhack + +Use this command to stop a misbehaving script that appears to be stuck. + +Usage +----- + +:: + + kill-lua + kill-lua force + +Use ``kill-lua force`` if just ``kill-lua`` doesn't seem to work. diff --git a/docs/builtins/load.rst b/docs/builtins/load.rst new file mode 100644 index 0000000000..a913162625 --- /dev/null +++ b/docs/builtins/load.rst @@ -0,0 +1,19 @@ +load +==== + +.. dfhack-tool:: + :summary: Load and register a plugin library. + :tags: dfhack + +Also see `unload` and `reload` for related actions. + +Usage +----- + +:: + + load [ ...] + load -a|--all + +You can load individual named plugins or all plugins at once. Note that plugins +are disabled after loading/reloading until you explicitly `enable` them. diff --git a/docs/builtins/ls.rst b/docs/builtins/ls.rst new file mode 100644 index 0000000000..cd6bc41261 --- /dev/null +++ b/docs/builtins/ls.rst @@ -0,0 +1,44 @@ +ls +== + +.. dfhack-tool:: + :summary: List available DFHack commands. + :tags: dfhack + +In order to group related commands, each command is associated with a list of +tags. You can filter the listed commands by a tag or a substring of the +command name. Can also be invoked as ``dir``. + +Usage +----- + +``ls []`` + Lists all available commands and the tags associated with them. +``ls []`` + Shows only commands that have the given tag. Use the `tags` command to see + the list of available tags. +``ls []`` + Shows commands that include the given string. E.g. ``ls quick`` will show + all the commands with "quick" in their names. If the string is also the + name of a tag, then it will be interpreted as a tag name. + +Examples +-------- + +``ls quick`` + List all commands that match the substring "quick". +``ls adventure`` + List all commands with the ``adventure`` tag. +``ls --dev trigger`` + List all commands, including developer and modding commands, that match the + substring "trigger". + +Options +------- + +``--notags`` + Don't print out the tags associated with each command. +``--dev`` + Include commands intended for developers and modders. +``--exclude [,...]`` + Exclude commands that match any of the given strings. diff --git a/docs/builtins/plug.rst b/docs/builtins/plug.rst new file mode 100644 index 0000000000..8df378d3c8 --- /dev/null +++ b/docs/builtins/plug.rst @@ -0,0 +1,16 @@ +plug +==== + +.. dfhack-tool:: + :summary: List available plugins and whether they are enabled. + :tags: dfhack + +Usage +----- + +:: + + plug [ [ ...]] + +If run with parameters, it lists only the named plugins. Otherwise it will list +all available plugins. diff --git a/docs/builtins/reload.rst b/docs/builtins/reload.rst new file mode 100644 index 0000000000..9ee9061a2b --- /dev/null +++ b/docs/builtins/reload.rst @@ -0,0 +1,21 @@ +reload +====== + +.. dfhack-tool:: + :summary: Reload a loaded plugin. + :tags: dfhack + +Developers use this command to reload a plugin that they are actively modifying. +Also see `load` and `unload` for related actions. + +Usage +----- + +:: + + reload [ ...] + reload -a|--all + +You can reload individual named plugins or all plugins at once. Note that +plugins are disabled after loading/reloading until you explicitly `enable` +them. diff --git a/docs/builtins/sc-script.rst b/docs/builtins/sc-script.rst new file mode 100644 index 0000000000..f66aeb412c --- /dev/null +++ b/docs/builtins/sc-script.rst @@ -0,0 +1,26 @@ +sc-script +========= + +.. dfhack-tool:: + :summary: Run commands when game state changes occur. + :tags: dfhack + +This is similar to the static `init-files` but is slightly more flexible since +it can be set dynamically. + +Usage +----- + +``sc-script [help]`` + Show the list of valid event names. +``sc-script list []`` + List the currently registered files for all events or the specified event. +``sc-script add|remove [ ...]`` + Register or unregister a file to be run for the specified event. + +Example +------- + +``sc-script add SC_MAP_LOADED spawn_extra_monsters.init`` + Registers the ``spawn_extra_monsters.init`` file to be run whenever a new + map is loaded. diff --git a/docs/builtins/script.rst b/docs/builtins/script.rst new file mode 100644 index 0000000000..0c4ca8c3d5 --- /dev/null +++ b/docs/builtins/script.rst @@ -0,0 +1,26 @@ +script +====== + +.. dfhack-tool:: + :summary: Execute a batch file of DFHack commands. + :tags: dfhack + +It reads a text file and runs each line as a DFHack command as if it had been +typed in by the user -- treating the input like `an init file `. + +Some other tools, such as `autobutcher` and `workflow`, export their settings as +the commands to create them - which can later be reloaded with ``script``. + +Usage +----- + +:: + + script + +Example +------- + +``script startup.txt`` + Executes the commands in ``startup.txt``, which exists in your DF game + directory. diff --git a/docs/builtins/show.rst b/docs/builtins/show.rst new file mode 100644 index 0000000000..cbfa3a386d --- /dev/null +++ b/docs/builtins/show.rst @@ -0,0 +1,19 @@ +show +==== + +.. dfhack-tool:: + :summary: Unhides the DFHack terminal window. + :tags: dfhack + +Useful if you have hidden the terminal with `hide` and you want it back. Since +the terminal window won't be available to run this command, you'll need to use +it from a `keybinding` set beforehand or the in-game `command-prompt`. + +Only available on Windows. + +Usage +----- + +:: + + show diff --git a/docs/builtins/tags.rst b/docs/builtins/tags.rst new file mode 100644 index 0000000000..698323ffe6 --- /dev/null +++ b/docs/builtins/tags.rst @@ -0,0 +1,26 @@ +tags +==== + +.. dfhack-tool:: + :summary: List the categories of DFHack tools or the tools with those tags. + :tags: dfhack + +DFHack tools are labeled with tags so you can find groups of related commands. +This builtin command lists the tags that you can explore, or, if called with the +name of a tag, lists the tools that have that tag. + +Usage +----- + +``tags`` + List the categories of DFHack tools and a description of those categories. +``tags `` + List the tools that are tagged with the given tag. + +Examples +-------- + +``tags`` + List the defined tags. +``tags design`` + List all the tools that have the ``design`` tag. diff --git a/docs/builtins/type.rst b/docs/builtins/type.rst new file mode 100644 index 0000000000..1bf86e588c --- /dev/null +++ b/docs/builtins/type.rst @@ -0,0 +1,17 @@ +type +==== + +.. dfhack-tool:: + :summary: Describe how a command is implemented. + :tags: dfhack + +DFHack commands can be provided by plugins, scripts, or by the core library +itself. The ``type`` command can tell you which is the source of a particular +command. + +Usage +----- + +:: + + type diff --git a/docs/builtins/unload.rst b/docs/builtins/unload.rst new file mode 100644 index 0000000000..6fa52ea9e0 --- /dev/null +++ b/docs/builtins/unload.rst @@ -0,0 +1,18 @@ +unload +====== + +.. dfhack-tool:: + :summary: Unload a plugin from memory. + :tags: dfhack + +Also see `load` and `reload` for related actions. + +Usage +----- + +:: + + unload [ ...] + unload -a|--all + +You can unload individual named plugins or all plugins at once. diff --git a/docs/changelog-placeholder.txt b/docs/changelog-placeholder.txt new file mode 100644 index 0000000000..86ffbcaeb6 --- /dev/null +++ b/docs/changelog-placeholder.txt @@ -0,0 +1,11 @@ +DFHack's changelog is no longer stored at this location. + +- For a local copy, see hack/docs/docs/NEWS.html + (this requires offline docs to be installed) +- For an online copy, see https://dfhack.readthedocs.org/en/stable/docs/NEWS.html + + +--- + +Note to maintainers: this file is installed to hack/changelog.txt - for details, +see https://github.com/DFHack/dfhack/issues/1775 diff --git a/docs/changelog.txt b/docs/changelog.txt new file mode 100644 index 0000000000..7d51a61dad --- /dev/null +++ b/docs/changelog.txt @@ -0,0 +1,2245 @@ +=== Scroll down for changes + +===[[[ +For information on how to edit/build the changelogs, see `docs/html/docs/dev/Documentation.html` or `docs/dev/Documentation.rst`. + +The text between the `syntax-reference` markers is included in `docs/dev/Documentation.rst`, so it must be valid RST. +It is kept in this file as a quick syntax reference. + +===syntax-reference-start + +The changelogs use a syntax similar to RST, with a few special sequences: + +- ``===`` indicates the start of a comment +- ``#`` indicates the start of a release name (do not include "DFHack") +- ``##`` indicates the start of a section name (which must be listed in ``docs/sphinx_extensions/dfhack/changelog.py``) +- ``-`` indicates the start of a changelog entry. **Note:** an entry currently must be only one line. +- ``:`` (followed by space) separates the name of a feature from a description of a change to that feature. + - Changes made to the same feature are grouped if they end up in the same section. +- ``:\`` (followed by space) avoids the above behavior +- ``- @`` (the space is optional) indicates the start of an entry that should only be displayed in ``NEWS-dev.rst``. + - Use this sparingly, e.g. for immediate fixes to one development build in another development build that + are not of interest to users of stable builds only. +- Three ``[`` characters indicate the start of a block (possibly a comment) that + spans multiple lines. Three ``]`` characters indicate the end of such a block. +- ``!`` immediately before a configured replacement (see ``docs/sphinx_extensions/dfhack/changelog.py``) stops that occurrence from being replaced. + +===syntax-reference-end + +Template for new versions: + +## New Tools + +## New Features + +## Fixes + +## Misc Improvements + +## Documentation + +## API + +## Lua + +## Removed + +]]] + +================================================================================ +======== IMPORTANT: rename this, and add a new "Future" section, BEFORE ======== +======== making a new DFHack release, even if the only changes made ======== +======== were in submodules with their own changelogs! ======== +================================================================================ + +# Future + +## New Tools + +## New Features + +## Fixes + +## Misc Improvements + +## Documentation + +## API + +## Lua + +## Removed + +# 53.15-r2 + +## New Tools + +## New Features +- `buildingplan`: add a ``Pull`` button next to linked levers on a building's "Show linked buildings" tab so you can queue a high-priority pull-lever job (or cancel a queued one) without navigating to the lever + +## Fixes +- `autoclothing`: correct defect in validating material specification on command line +- `autolabor`: Fix running 1 tick less frequently than intended. +- `buildingplan`: fixed non-clickable pressure plates's triggers (issue #5736) +- `getplants`: added protective code to avoid misoperation when a plant has an invalid material (which should never happen, but...) + +## Misc Improvements +- `buildingplan`: added a slider on the weapontrap overlay +- `buildingplan`: added a small tooltip text about renaming favorites in the UI +- `buildingplan`: buildingplan can now generate work orders +- `orders`: exported orders now include a human-readable ``name`` field + +## Documentation + +## API +- Core: added ``getConfigPath()`` API for obtaining the path to user-specific configuration files +- ``widgets.RadioButton``: New button widget resembling those used in ``gui/control-panel`` + +## Lua +- Added ``dfhack.getConfigPath()`` API, proxying ``Core::getConfigPath`` + +## Removed + +# 53.15-r1 + +## New Tools + +## New Features + +## Fixes +- `autoclothing`: will no longer count gloves and pants as if they were helms +- `timestream`: do not skip ticks when a caravan is loading or unloading, and be more careful about skipping ticks when flows are active + +## Misc Improvements + +## Documentation + +## API + +## Lua + +## Removed + +# 53.14-r2 + +## New Tools + +## New Features + +## Fixes + +## Misc Improvements +- Core: attempts to delete a pool-allocated DF object will now throw an exception instead of corrupting the heap + +## Documentation + +## API + +## Lua + +## Removed +- `logcleaner`: Removed (cannot be safely implemented at this time) + +# 53.14-r1 + +## New Tools + +## New Features +- Compatibility with Dwarf Fortress 53.14 + +## Fixes + +## Misc Improvements + +## Documentation + +## API + +## Lua + +## Removed + +# 53.13-r2 + +## New Tools + +## New Features + +## Fixes +- ``Gui::makeAnnoucement``, ``Gui::showPopupAnnouncement`, and ``Gui::autoDFAnnouncement`` will no longer attempt to cull the DF announcement vector + +## Misc Improvements + +## Documentation + +## API + +## Lua + +## Removed + +# 53.13-r1 + +## New Tools + +## New Features + +## Fixes + +## Misc Improvements + +## Documentation +- updated documentation for ``autofarm`` for more clarity + +## API +- add flexible casting to ``enum_field`` to enable explicit casting to more types +- Handle units without current soul in ``Units::getFocusPenalty`` + +## Lua + +## Removed + +# 53.12-r1 + +## New Tools + +## New Features +- Compatibility with Dwarf Fortress 53.12 + +## Fixes +- Stockpile definitions in the default library will be correctly found and used (fixed missing path separator) + +## Misc Improvements + +## Documentation + +## API + +## Lua + +## Removed + +# 53.11-r3 + +## New Tools + +## New Features + +## Fixes +- Core: Windows console will always use UTF-8 regardless of system code page settings +- Steam launcher: Switch to injection strategy, allowing Dwarf Fortress and DFHack to be installed in disparate locations + +## Misc Improvements +- Make DFHack relocatable so that it doesn't depend on being fully co-installed with Dwarf Fortress + +## Documentation + +## API + +## Lua + +## Removed + +# 53.11-r2 + +## New Tools + +## New Features + +## Fixes +- `autoclothing`, `autoslab`, `tailor`: orders will no longer be created with a repetition frequency of ``NONE`` + +## Misc Improvements +- General: DFHack will unconditionally use UTF-8 for the console on Windows, now that DF forces the process effective system code page to 65001 during startup + +## Documentation + +## API + +## Lua + +## Removed + +# 53.11-r1 + +## New Tools + +## New Features + +## Fixes +- `sort`: correct misspelling of ``PERSEVERENCE``; fixes "hates combat" filter in squad selection screen + +## Misc Improvements + +## Documentation + +## API + +## Lua + +## Removed + +# 53.10-r2 + +## New Tools +- ``logcleaner``: New plugin for time-triggered clearing of combat, sparring, and hunting reports with configurable filtering and overlay UI. + +## New Features +- `orders`: added search overlay to find and navigate to matching manager orders with arrow indicators +- `sort`: added ``Uniformed`` filter to squad assignment screen to filter dwarves with mining, woodcutting, or hunting labors +- `sort`: Add death cause button to dead/missing tab in the creatures screen + +## Fixes + +## Misc Improvements +- Core: DFHack now validates vtable pointers in objects read from memory and will throw an exception instead of crashing when an invalid vtable pointer is encountered. This makes it easier to identify which DF data structure contains corrupted data when this manifests in the form of a bad vtable pointer, and shifts blame for such crashes from DFHack to DF. + +## Documentation + +## API +- Added ``Items::pickGrowthPrint``: given a plant material and a growth index, returns the print variant corresponding to the current in-game time. +- Added ``Items::useStandardMaterial``: given an item type, returns true if the item is made of a specific material and false if it has a race and caste instead. +- Added ``Maps::addItemSpatter``: add a spatter of the specified item + material + growth print to the indicated tile, returning whatever amount wouldn't fit in the tile. +- Added ``Maps::addMaterialSpatter``: add a spatter of the specified material + state to the indicated tile, returning whatever amount wouldn't fit in the tile. + +## Lua +- Added ``Maps::addItemSpatter`` as ``dfhack.maps.addItemSpatter``. +- Added ``Maps::addMaterialSpatter`` as ``dfhack.maps.addMaterialSpatter``. + +## Removed + +# 53.10-r1 + +## New Tools + +## New Features + +## Fixes +- `autochop`: the report will no longer throw a C++ exception when burrows are defined. +- `suspendmanager`: Fix the overlay appearing where it should not when following a unit + +## Misc Improvements + +## Documentation + +## API +- Added ``Burrows::getName``: obtains the name of a burrow, or the same placeholder name that DF would show if the burrow is unnamed. + +## Lua +- Added ``Burrows::getName`` as ``dfhack.burrows.getName``. + +## Removed + +# 53.09-r1 + +## New Tools + +## New Features +- `tweak`: ``drawbridge-tiles``: Make it so raised bridges render with different tiles in ASCII mode to make it more obvious that they ARE raised (and to indicate their direction) + +## Fixes +- ``Filesystem::as_string`` now always uses UTF-8 encoding rather than using the system locale encoding + +## Misc Improvements + +## Documentation + +## API +- ``dfhack.job.getManagerOrderName``: New function to get the display name of a manager order + +## Lua + +## Removed + +# 53.08-r1 + +## New Tools + +## New Features +- compatibility with DF 53.08 + +## Fixes + +## Misc Improvements + +## Documentation + +## API + +## Lua + +## Removed + +# 53.07-r1 + +## New Tools +- ``edgescroll``: Introduced plugin to pan the view automatically when the mouse reaches the screen border. +- `infinite-sky`: Re-enabled with compatibility with new siege map data. + +## New Features +- `sort`: Places search widget can search "Siege engines" subtab by name, loaded status, and operator status + +## Fixes +- `sort`: Using the squad unit selector will no longer cause Dwarf Fortress to crash on exit +- `sort`: Places search widget moved to account for DF's new "Siege engines" subtab + +## Misc Improvements +- `createitem`: created items can now be placed onto/into tables, nests, bookcases, display cases, and altars +- The ``fpause`` console command can now be used to force world generation to pause (as it did prior to version 50). +- `keybinding`: keybinds may now include the super key, and are no longer limited to particular keys ranges of keys, allowing any recognized by SDL. + +## Documentation + +## API +- ``Hotkey``: New module for hotkey functionality + +## Lua +- The ``Lua interactive interpreter`` banner now documents keywords such as ``unit`` and ``item`` which reference the currently-selected object in the DF UI. +- ``dfhack.hotkey.addKeybind``: Creates new keybindings +- ``dfhack.hotkey.removeKeybind``: Removes existing keybindings +- ``dfhack.hotkey.listActiveKeybinds``: Lists all keybinds for the current context +- ``dfhack.hotkey.listAllKeybinds``: Lists all keybinds for all contexts +- ``dfhack.hotkey.requestKeybindingInput``: Requests the next keybind-compatible input is saved +- ``dfhack.hotkey.getKeybindingInput``: Reads the input saved in response to a request. + +## Removed + +# 53.06-r1 + +## New Tools + +## New Features + +## Fixes + +## Misc Improvements + +## Documentation + +## API + +## Lua + +## Removed +- `infiniteSky`: Temporarily disabled due to incompatibility with changes made as part of DF's siege update + +# 53.05-r1 + +## New Tools + +## New Features +- compatibility with 53.05 + +## Fixes +- `sort`: Using the squad unit selector will no longer cause Dwarf Fortress to crash on exit + +## Misc Improvements + +## Documentation + +## API + +## Lua + +## Removed + +# 53.04-r1.1 + +## New Tools + +## New Features + +## Fixes +- fixed misalignment in ``widgets::unit_list`` + +## Misc Improvements + +## Documentation + +## API + +## Lua + +## Removed + +# 53.04-r1 + +## New Tools + +## New Features + +## Fixes +- `buildingplan`: Bolt throwers will no longer be constructed using populated bins. +- `RemoteFortressReader`: updated siege engine facing enums for new diagonal directions +- `suspendmanager`: treat reinforced walls as a blocking construction and buildable platform + +## Misc Improvements +- `autolabor`: support for new dying and siege-related labors +- `blueprint`: support for reinforced walls and bolt throwers + +## Documentation + +## API + +## Lua + +## Removed + +# 53.03-r1 + +## New Tools + +## New Features + +## Fixes + +## Misc Improvements +- Release builds for Linux are now compiled with gcc 11 + +## Documentation + +## API + +## Lua + +## Removed + +# 53.02-r2 + +## New Tools + +## New Features + +## Fixes +- `buildingplan`: Building costs for reinforced walls are now correct. +- `cleanconst`: do not attempt to clean Reinforced constructions + +## Misc Improvements +- `buildingplan`: Added support for bolt throwers and siege engine rotation. + +## Documentation + +## API + +## Lua + +## Removed + +# 53.02-r1 + +## New Tools + +## New Features + +## Fixes + +## Misc Improvements +- Core: added ``gps`` (``graphicst``) to the set of globals whose sizes must agree for DFHack to pass initialization checks + +## Documentation + +## API + +## Lua + +## Removed + +# 53.01-r1 + +## New Tools + +## New Features + +## Fixes + +## Misc Improvements +- `stockpiles`: add support for managing the dyed, undyed, and color filter settings. + +## Documentation + +## API + +## Lua + +## Removed + +# 52.05-r2 + +## New Tools + +## New Features + +## Fixes +- `script-manager`: the ``scripts_modactive`` and ``scripts_modinstalled`` folders of a script-enabled mod will be properly added to the script path search list + +## Misc Improvements + +## Documentation +- added a clarification link to DF's Lua API documentation to the DFHack Lua API documentation, as a way to reduce end-user confusion + +## API + +## Lua + +## Removed + +# 52.05-r1 + +## New Tools + +## New Features + +## Fixes +- improved file system handling: gracefully handle errors from operations, preventing crashes. +- `zone`: animal assignment dialog now tolerates corrupt animal-to-pasture links. + +## Misc Improvements + +## Documentation + +## API + +## Lua + +## Removed + +# 52.04-r1 + +## New Tools + +## New Features +- Compatibility with DF 52.04 + +## Fixes + +## Misc Improvements + +## Documentation + +## API + +## Lua + +## Removed + +# 52.03-r2 + +## New Tools + +## New Features +- `nestboxes`: allow limiting egg protection to nestboxes inside a designated burrow +- `tailor`: tailor now provides optional dye automation + +## Fixes +- ``Units::getReadableName`` will no longer append a comma to the names of histfigs with no profession +- `stockpiles`: fixed off-by-one error in exporting furniture stockpiles + +## Misc Improvements + +## Documentation + +## API +- ``Job``: new functions ``createLinked`` and ``assignToWorkshop`` +- ``Units``: new functions ``getFocusPenalty``, ``unbailableSocialActivity``, ``isJobAvailable`` + +## Lua +- New functions: ``dfhack.jobs.createLinked``, ``dfhack.jobs.assignToWorkshop``, ``dfhack.units.getFocusPenalty``, ``dfhack.units.unbailableSocialActivity``, and ``dfhack.units.isJobAvailable`` + +## Removed + +# 52.03-r1.1 + +## New Tools + +## New Features + +## Fixes +- job descriptions of mix dye job will display proper dye names + +## Misc Improvements + +## Documentation + +## API + +## Lua + +## Removed + +# 52.03-r1 + +## New Tools + +## New Features + +## Fixes +- `preserve-rooms` will no longer hang on startup in the presence of a cycle in the replacement relationship of noble positions + +## Misc Improvements + +## Documentation + +## API +- Adjusted the logic inside ``Military::removeFromSquad`` to more closely match the game's own behavior + +## Lua + +## Removed + +# 52.02-r2 + +## New Tools + +## New Features + +## Fixes +- Several fixes related to changes in file system handling in DF 52.01 +- `dig-now`: don't allow UNDIGGABLE stones to be excavated + +## Misc Improvements +- `autoclothing`: added a ``clear`` option to unset previously set orders + +## Documentation + +## API +- Added GUI focus strings for new_arena: ``/Loading`` and ``/Mods`` +- ``Filesystem::getBaseDir`` and ``Filesystem::getInstallDir`` added (and made available in Lua) +- Expanded the partial implementations of ``Military::addToSquad`` and ``Military::removeFromSquad`` + +## Lua +- Inserting values into STL containers containing nonprimitive types is now supported + +## Removed + +# 52.02-r1 + +## New Tools + +## New Features + +## Fixes +- Honor the "portable mode" preference setting for locating save folders. Fixes DFHack cosaves not working in most cases. + +## Misc Improvements + +## Documentation + +## API + +## Lua + +## Removed + +# 52.01-r1 + +## New Tools + +## New Features +- `tweak`: ``animaltrap-reuse``: make it so built animal traps automatically unload the vermin they catch into stockpiled animal traps, so that they can be automatically re-baited and reused + +## Fixes + +## Misc Improvements + +## Documentation + +## API + +## Lua +- ``widgets.Slider``: new mouse-controlled single-headed slider widget + +## Removed + +# 51.13-r1 + +## New Features + +- Compatibility with DF 51.13 + +# 51.12-r1.1 + +## New Features + +- Compatibility with Itch release of DF 51.12 + +# 51.12-r1 + +## Fixes +- `getplants`: will no longer crash when faced with plants with growths that do not drop seeds when processed +- `getplants`: use updated formula for calculating whether plant growths are ripe +- `getplants`: fix logic for determining whether plant growths have been picked +- `gui/teleport`: adapt to new behavior in DF 51.11 to avoid a crash when teleporting items into mid-air +- `script-manager`: fix lua scripts in mods not being reloaded properly upon entering a saved world on Windows +- `preserve-rooms`: don't warn when a room is assigned to a non-existent unit. this is now common behavior for DF when it keeps a room for an unloaded unit +- fixed an overly restrictive type constraint that resulted in some object types being glossed as a boolean when passed as an argument from C++ to Lua +- `plants`: will no longer generate a traceback when a filter is used +- `createitem`: multiple items should be properly created in stacks again + +## Misc Improvements +- All places where units are listed in DFHack tools now show the translated English name in addition to the native name. In particular, this makes units searchable by English name in `gui/sitemap`. +- `dig`: ASCII overlay now displays priority of digging designations +- `spectate`: added prefer nicknamed units +- `blueprint`: support for recording zones +- `blueprint`: support for recording stockpile properties like names and stockpile links; does not yet support recording detailed contents configuration +- `strangemood`: support added for specifying unit id instead of selected unit or random one. + +## API +- ``Random`` module: added ``SplitmixRNG`` class, implements the Splitmix64 RNG used by Dwarf Fortress for "simple" randomness +- ``Items::getDescription``: fixed display of quality levels, now displays ALL item designations (in correct order) and obeys vanilla SHOW_IMP_QUALITY setting +- ``cuboid::forCoord``, ``Maps::forCoord``: take additional parameter to control whether iteration goes in column major or row major order + +## Lua +- ``script-manager``: new ``get_active_mods()`` function for getting information on active mods +- ``script-manager``: new ``get_mod_info_metadata()`` function for getting information out of mod ``info.txt`` files + +## Removed +- removed historically unused ``Core::RegisterData``/``Core::GetData`` API and associated internal data structures + +# 51.11-r1.2 + +## Fixes +- `preserve-tombs`: will no longer crash when a tomb is assigned to a unit that does not exist + +# 51.11-r1.1 + +## Fixes +- `preserve-rooms`: will no longer crash when a civzone is assigned to a unit that does not exist +- `gui/design`: fix misaligned shape icons + +# 51.11-r1 + +## Fixes +- `spectate`: don't show a hover tooltip for hidden units (e.g. invisible snatchers) +- `stockpiles`: fix one-off error in item type when importing furniture stockpile settings +- `dig-now`: fix cases where boulders/rough gems of incorrect material were being generated when digging through walls +- `dig-now`: properly generate ice boulders when digging through ice walls +- `gui/teleport`: now properly handles teleporting units that are currently falling or being flung +- `unload`: fix recent regression where `unload` would immediately `reload` the target +- ``Buildings`` module: do not crash if a ``map_block`` unexpectedly contains an item that is not on the master item vector +- `suspendmanager`: fix walls being treated as potential suitable access if another wall is built underneath +- text widgets no longer lose their cursor when the Ctrl-a (select all) hotkey is pressed when there is no text to select + +## Misc Improvements +- `spectate`: show dwarves' activities (like prayer) + +## API +- ``Military`` module: added ``addToSquad`` function +- ``Units`` module: added ``get_cached_unit_by_global_id`` to emulate how DF handles unit vector index caching (used in civzones and in general references) +- ``Buildings`` module: add ``getOwner`` (using the ``Units::get_cached_unit_by_global_id`` mechanic) to reflect changes in 51.11 +- ``Units::teleport``: projectile information is now cleared for teleported units +- ``Buildings::setOwner``: updated for changes in 51.11 + +## Lua +- ``dfhack.military.addToSquad``: expose Military API function +- ``dfhack.buildings.getOwner``: make new Buildings API available to Lua + +# 51.10-r1 + +## Misc Improvements +- Compatibility with DF 51.10 + +# 51.09-r1 + +## New Features +- `gui/journal`: Ctrl-j hotkey to launch `gui/journal` now works in adventure mode! + +## Fixes +- Fix processing error in the overlay that displays unit preferences in the baron selection list + +## API +- ``Filesystem`` module: rewritten to use C++ standard library components, for better portability + +# 51.08-r1 + +## Misc Improvements +- Compatibility update for DF 51.08 + +# 51.07-r1 + +## New Features +- `spectate`: can now specify number of seconds (in real time) before switching to follow a new unit +- `spectate`: new "cinematic-action" mode that dynamically speeds up perspective switches based on intensity of conflict +- `spectate`: new global keybinding for toggling spectate mode: Ctrl-Shift-S +- `spectate`: new overlay panel that allows you to cycle through following next/previous units (regardless of whether spectate mode is enabled) +- `gui/sitemap`: is now the official "go to" tool. new global hotkey for fort and adventure mode: Ctrl-G + +## Fixes +- Windows console: fix possible hang if the console returns a too-small window width (for any reason) +- `createitem`: produced items will now end up at the look cursor position (if it is active) +- `spectate`: don't allow temporarily modified announcement settings to be written to disk when "auto-unpause" mode is enabled +- `changevein`: fix a crash that could occur when attempting to change a vein into itself +- `overlay`: reset draw context between rendering widgets so context changes can't propagate from widget to widget +- `suspendmanager`: in ASCII mode, building planning mode overlay now only displays when viewing the default map, reducing issues with showing through the UI + +## Misc Improvements +- `spectate`: player-set configuration is now stored globally instead of per-fort +- `autobutcher`: treat animals on restraints as unavailable for slaughter +- `stockpiles`: add property filters for brewable, millable, and processable (e.g. at a Farmer's workshop) organic materials +- `quickfort`: redesigned ``library/aquifer_tap.cav`` to improve the water fill rate + +## Documentation +- `stonesense-art-guide`: guide for making sprite art for Stonesense + +## API +- ``Military::removeFromSquad``: removes unit from any squad assignments +- ``Buildings::checkFreeTiles``: now takes a building instead of a pointer to the building extents +- ``Units::isUnitInBox``, ``Units::getUnitsInBox``: don't include inactive units +- ``Items::getItemBaseValue``: adjust to the reduced value of prepared meals (changed in DF 51.06) +- ``Items::getValue``: magical powers now correctly contribute to item value + +## Lua +- ``dfhack.units.setAutomaticProfessions``: sets unit labors according to current work detail settings +- ``dfhack.military.removeFromSquad``: Lua API for ``Military::removeFromSquad`` +- ``gui.dwarfmode``: adventure mode cursor now supported in ``getCursorPos``, ``setCursorPos``, and ``clearCursorPos`` funcitons +- ``dfhack.buildings.checkFreeTiles``: now takes a building pointer instead of an extents parameter +- ``overlay.isOverlayEnabled``: new API for querying whether a given overlay is enabled +- ``overlay``: widgets can now declare ``overlay_onenable`` and ``overlay_ondisable`` functions to hook enable/disable + +## Removed +- `orders`: MakeCheese job removed from library/basic orders set. Please use `autocheese` instead! + +# 51.06-r1 + +## Misc Improvements +- Compatibility with DF 51.06 + +# 51.05-r1 + +## Misc Improvements +- Compatibility with DF 51.05 + +# 51.04-r1.1 + +## Fixes +- `gui/launcher`: ensure commandline is fully visible when searching through history and switching from a very long command to a short command +- `gui/launcher`: flatten text when pasting multi-line text from the clipboard +- Ctrl-a hotkeys have been changed to something else (Ctrl-n) for tools that also have an editable text field, where Ctrl-a is interpreted as select all text + +## API +- ``Core::getUnpausedMs``: new API for getting unpaused ms since load in a fort-mode game + +# 51.04-r1 + +## Misc Improvements +- Compatibility with Steam release of DF 51.04 + +# 51.03-r1.1 + +## Misc Improvements +- Compatibility with Itch release of DF 51.03 + +# 51.03-r1 + +## Fixes +- `gui/gm-editor`: fix Enter key not being recognized for opening the selected object + +# 51.02-r1 + +## Misc Improvements +- DFHack edit field widgets, such as the commandline editor in `gui/launcher`, now support text selection and other advanced text editing features from `gui/journal` + +# 50.15-r2 + +## New Features +- `stockpiles`: add simple import/export dialogs to stockpile overlay panel +- `orders`: add transparent overlays to the manager orders screen that allow right clicks to cancel edit of quantities or condition details instead of exiting to the main screen + +## Fixes +- `preserve-rooms`: don't erroneously release reservations for units that have returned from their missions but have not yet entered the fort map +- `preserve-rooms`: handle case where unit records are culled by DF immediately after a unit leaves the map +- `preserve-tombs`: properly re-enable after loading a game that had the tool enabled +- `zone`: assign animal to cage/restraint dialog now allows you to unassign a pet from the cage or restraint if the pet is already somehow assigned (e.g. war dog was in cage and was subsequently assigned to a dwarf) +- `stockpiles`: don't set ``use_links_only`` flag to a random value when the flag is not set to anything in the settings that are being imported +- `strangemood`: ensure generated names for artifacts match what the game itself would generate + +## Misc Improvements +- `strangemood`: add ability to choose Stone Cutting and Stone Carving as the mood skill +- `suspendmanager`: add more specific messages for submerged job sites and those managed by `buildingplan` +- `dig-now`: handle digging in pool and river tiles + +## Documentation +- Added example code for creating plugin RPC endpoints that can be used to extend the DFHack API + +## API +- ``Units::isUnitInBox``, ``Units::getUnitsInBox``: add versions accepting pos arguments +- ``Units::getVisibleName``: when acting on a unit without an impersonated identity, returns the unit's name structure instead of the associated histfig's name structure +- ``Translation::generateName``: generates in-game names, mirroring DF's internal logic +- ``Persistence::getUnsavedSeconds``: returns the number of seconds since last save or load + +## Lua +- ``dfhack.units.isUnitInBox``, ``dfhack.units.getUnitsInBox``: add versions accepting pos arguments +- ``widgets.FilteredList``: search keys for list items can now be functions that return a string +- ``dfhack.translation.generateName``: Lua API for ``Translation::generateName`` +- ``dfhack.persistent.getUnsavedSeconds``: Lua API for ``Persistence::getUnsavedSeconds`` + +## Removed +- ``dfhack.TranslateName`` has been renamed to ``dfhack.translation.translateName`` + +## Internals +- Plugin command callbacks are now called with the core suspended by default so DF memory is always safe to access without extra steps +- Errors when unloading a plugin's DLL are now checked and reported + +# 50.15-r1.2 + +## Misc Improvements + +- Updated support for Itch + +# 50.15-r1.1 + +## Misc Improvements + +- Updated support for Classic (Itch not available for analysis yet) + +# 50.15-r1 + +## Fixes + +- `gui/prerelease-warning`: don't pop up during worldgen, only after a fort has been loaded + +# 50.14-r2 + +## New Tools +- `infinite-sky`: (reinstated, renamed from ``infiniteSky``) automatically create new z-levels of sky to build in +- `forceequip`: (reinstated) forcibly move items into a unit's inventory + +## New Features +- `tweak`: ``realistic-melting``: change melting return for inorganic armor parts, shields, weapons, trap components and tools to stop smelters from creating metal, bring melt return for adamantine in line with other metals to ~95% of forging cost. wear reduces melt return by 10% per level + +## Fixes +- Fix mouse clicks bleeding through resizable DFHack windows when clicking in the space between the frame and the window content +- `autobutcher`: don't run a scanning and marking cycle on the first tick of a fortress to allow for all custom configuration to be set first +- `nestboxes`: don't consider eggs to be infertile just because the mother has left the nest; eggs can still hatch in this situation +- `timestream`: adjust the incubation counter on fertile eggs so they hatch at the expected time +- `timestream`: adjust the timeout on traps so they can be re-triggered at normal rates +- `logistics`: don't ignore rotten items when applying stockpile logistics operations (e.g. autodump, autoclaim, etc.) + +## Misc Improvements +- DFHack now verifies that critical DF data structures have known sizes and refuses to start if there is a mismatch +- DFHack text edit fields now delete the character at the cursor when you hit the Delete key +- DFHack text edit fields now move the cursor by one word left or right with Ctrl-Left and Ctrl-Right +- DFHack text edit fields now move the cursor to the beginning or end of the line with Home and End +- Quickfort blueprint library: ``aquifer_tap`` blueprint walkthough rewritten for clarity +- Quickfort blueprint library: ``aquifer_tap`` blueprint now designated at priority 3 and marks the stairway tile below the tap in "blueprint" mode to prevent drips while the drainage pipe is being prepared +- `preserve-rooms`: automatically release room reservations for captured squad members. we were kidding ourselves with our optimistic kept reservations. they're unlikely to come back : (( +- `buildingplan`: add value info to item selection dialog (effectively ungrouping items with different values) and add sorting by value +- `timestream`: improve FPS by a further 10% +- `fix/occupancy`: additionally handle the case where tile building occupancy needs to be set instead of cleared +- `orders`: ``orders sort`` now moves orders that are tied to a specific workshop to the top of the list in the global manager orders screen +- `gui/pathable`: make wagon path to depot representation more robust + +## Documentation +- Dreamfort: add link to Dreamfort tutorial youtube series: https://www.youtube.com/playlist?list=PLzXx9JcB9oXxmrtkO1y8ZXzBCFEZrKxve +- The error message that comes up if there is a version mismatch between DF and DFHack now informs you which DF versions are supported by the installed version of DFHack + +## API +- ``DFHack::Units``: new function ``setPathGoal`` +- ``Units::setAutomaticProfessions``: bay12-provided entry point to assign labors based on work details + +## Lua +- ``dfhack.units``: new function ``setPathGoal`` +- ``widgets.TabBar``: updated to allow for horizontal scrolling of tabs when there are too many to fit in the available space + +## Removed +- UI focus strings for squad panel flows combined into a single tree: ``dwarfmode/SquadEquipment`` -> ``dwarfmode/Squads/Equipment``, ``dwarfmode/SquadSchedule`` -> ``dwarfmode/Squads/Schedule`` +- `faststart`: removed since the vanilla startup sequence is now sufficiently fast + +# 50.14-r1 + +## Fixes +- `preserve-rooms`: don't reserve a room for citizens that you expel from the fort +- `autobutcher`: fix regression in ordering of butcherable animals + +# 50.13-r5 + +## New Tools +- `preserve-rooms`: manage room assignments for off-map units and noble roles. reserves rooms owned by traveling units and reinstates their ownership when they return to the site. also allows you to assign rooms to noble/administrator roles, and the rooms will be automatically assigned whenever the holder of the role changes + +## Fixes +- prevent hang when buildings in zones are destroyed in the case where the buildings were not added to the zone in the same order that they were created (uncommon) +- `buildingplan`: improved performance in forts with large numbers of items +- System clipboard: when pasting single lines from the system clipboard, replace newlines with spaces so they don't show up as strange CP437 glyphs in-game +- `exterminate`: don't kill friendly undead (unless ``--include-friendly`` is passed) when specifying ``undead`` as the target +- `gui/settings-manager`: work details overlay no longer disappears when you click on a unit in the unit list +- `buildingplan`: fixed processing errors when using quick material filter slot '0' +- DFHack screens that allow keyboard cursor and camera movement while focused now also allow diagonal and Z-change keyboard cursor keys +- `strangemood`: manually-triggered Macabre moods will now correctly request up to 3 bones/remains for the primary component instead of only 1 +- `regrass`: no longer add all compatible grass types when using ``--force`` without ``--new`` +- `regrass`: ``--mud`` now converts muddy slade to grass, consistent with normal DF behavior +- `gui/pathable`: fix hang when showing trade depot wagon access and a trade depot is submerged under water or magma +- `gui/pathable`: fix representation of wagon paths over stairs and through doors +- DFHack state for a site is now properly saved when retiring a fort +- `gui/teleport`: fix issue when teleporting units that are not prone, resulting in later issues with phantom "cannot build here: unit blocking tile" messages + +## Misc Improvements +- `sort`: can now search for stockpiles on the Places>Stockpile tab by name, number, or enabled item categories +- `gui/family-affairs`: you can start this tool by the name ``gui/pregnancy`` to start directly on the "Pregnancies" tab +- `buildingplan`: only consider building materials that can be accessed by at least one citizen/resident +- Dreamfort: integrate with `preserve-rooms` to assign relevant rooms to nobles/adimistrators +- Dreamfort: smooth tiles under statues and other large furniture that you can't easily smooth later + +## Documentation +- add documentation for ``dfhack.items.findType(string)`` and ``dfhack.items.findSubtype(string)`` +- `modding-guide`: added examples for reading and writing various types of persistent storage +- `modding-guide`: updated all code snippets for greater clarity + +## API +- ``Units``: new ``isWildlife`` and ``isAgitated`` property checks +- ``Items::createItem``: removed ``growth_print`` parameter; now determined automatically +- ``DFHack::cuboid``: ``cuboid::clampMap`` now returns the cuboid itself (instead of boolean) to allow method chaining; call ``cuboid::isValid`` to determine success + +## Lua +- ``dfhack.units``: ``isWildlife`` and ``isAgitated`` property checks +- ``dfhack.units.isDanger``: no longer unconditionally returns true for intelligent undead +- Overlay widgets can now assume their ``active`` and ``visible`` functions will only execute in a context that matches their ``viewscreens`` associations +- ``gui.simulateInput``: do not generate spurious keycode from ``_STRING`` key inputs +- ``dfhack.items.createItem``: removed ``growth_print`` parameter to match C++ API + +## Removed +- ``quickfortress.csv``: remove old sample blueprints for "The Quick Fortress", which were unmaintained and non-functional in DF v50+. Online blueprints are available at https://docs.google.com/spreadsheets/d/1WuLYZBM6S2nt-XsPS30kpDnngpOQCuIdlw4zjrcITdY if anyone is interested in giving these blueprints some love + +# 50.13-r4 + +## New Features +- `gui/journal`: new hotkey, accessible from anywhere in fort mode: Ctrl-j + +## Fixes +- `changelayer`: fix incorrect lookup of geological region in multi-region embarks +- Copy/Paste: Fix handling of multi-line text when interacting with the system clipboard on Windows +- `zone`: fix alignment of animal actions overlay panel (the one where you can click to geld/train/etc.) when the animal has a custom portrait (like named dragons) +- `autodump`: cancel any jobs that point to dumped items +- `add-spatter`: fix a crash related to unloading a savegame with add-spatter reactions, then loading a second savegame with add-spatter reactions +- `plant`: properly detect trees in a specified cuboid that only have branches/leaves in the cuboid area + +## Misc Improvements +- performance improvements for DFHack tools and infrastructure +- `gui/pathable`: give edge tiles where wagons can enter the map a special highlight to make them more identifiable. this is especially useful when the game decides that only a portion of the map edge is usable by wagons. +- `autodump`: allow dumping items into mid-air, converting them into projectiles like `gui/autodump` does + +## Documentation +- improved docs for ``dfhack.units`` module functions + +## API +- ``Units``: add overloads that take historical figures for ``getReadableName``, ``getVisibleName``, and ``getProfessionName`` +- ``Units::isUnitInBox``, ``getUnitsInBox``: add versions that take a cuboid range, add filter fn parameter for ``getUnitsInBox`` +- ``Units::getProfession``: account for units with fake identities +- ``Units::getCasteRaw``: get a caste_raw from a unit or race and caste +- ``cuboid``: construct from ``df::map_block*``, ``forBlock`` iterator to access map blocks in cuboid +- ``cuboid``: ``clamp(cuboid other)``, ``clampNew(cuboid other)`` for cuboid intersection. ``clampNew`` returns new cuboid instead of modifying. +- ``Items``: no longer need to pass MapCache parameter to ``moveToGround``, ``moveToContainer``, ``moveToBuilding``, ``moveToInventory``, ``makeProjectile``, or ``remove`` +- ``Units::isVisible``: account for units in cages +- ``Units::getReadableName``: correct display of ghost+curse names w/r/t each other and unit prof, use ``curse.name`` instead of iterating syndrome name effects +- ``setAreaAquifer``, ``removeAreaAquifer``: add overloads that take cuboid range specifiers +- ``Units::isNaked``: now only checks equipped items (including rings, for now). Setting bool ``no_items`` to true checks empty inventory like before. +- ``Units::isUndead``: bool ``include_vamps`` renamed to ``hiding_curse``. Fn now checks that instead of bloodsucker syndrome. +- ``Units::isDanger``: added bool ``hiding_curse``, passed to ``isUndead`` to avoid spoilers +- ``Units::getRaceChildName``, ``getRaceChildNameById``, ``getRaceBabyName``, ``getRaceBabyNameById``: bool ``plural`` to get plural form +- ``Units::getProfessionName``: bool ``land_title`` to append "of Sitename" where applicable, use Prisoner/Slave and noble spouse titles (controlled by ``ignore_noble``) + +## Lua +- ``gui.ZScreen``: new ``defocused`` property for starting screens without keyboard focus +- ``dfhack.units``: allow historical figures to be passed instead of units for ``getReadableName``, ``getVisibleName``, and ``getProfessionName`` +- ``dfhack.items.moveToInventory``: make ``use_mode`` and ``body_part`` args optional +- ``dfhack.units``: add ``getRaceReadableName``, ``getRaceReadableNameById``, ``getRaceNamePluralById`` + +## Removed +- The ``PRELOAD_LIB`` environment variable has been renamed to ``DF_PRELOAD`` to match the naming scheme of other environment variables used by the ``dfhack`` startup script. If you are preloading libraries (e.g. for performance testing) please define ``DF_PRELOAD`` instead of ``PRELOAD_LIB`` or ``LD_PRELOAD`` +- ``cuboid::clamp(bool block)``: renamed to ``cuboid::clampMap(bool block)``, name taken by ``cuboid::clamp(cuboid other)`` +- ``Units::MAX_COLORS``, ``Units::findIndexById``, ``Units::getNumUnits``, ``Units::getUnit``: replaced by ``DFHack::COLOR_MAX`` and the generated type-specific ``get_vector`` functions +- ``Units::getPhysicalDescription``: function requires DF call point that is no longer available. alternative is to navigate the unit info sheet and extract the description from the UI (see `markdown`) + +# 50.13-r3 + +## New Tools +- `plant`: (reinstated) tool for creating/growing/removing plants + +## New Features +- `tweak`: ``named-codices``: display book titles instead of a material description in the stocks/trade screens +- `logistics`: automatically forbid or claim items brought to a stockpile +- `plant`: can now ``remove`` shrubs and saplings; ``list`` all valid shrub/sapling raw IDs; ``grow`` can make mature trees older; many new command options +- Locale-sensitive number formatting: select your preferred format in `gui/control-panel`. prices and other large numbers in DFHack UIs can be displayed with commas (English formatting), the number formatting used by your system locale, in SI units (e.g. ``12.3k``), or even in scientific notation + +## Fixes +- ``Gui::makeAnnouncement``, ``Gui::autoDFAnnouncement``: fix case where a new announcement is created instead of adding to the count of an existing announcement if the existing announcement was the first one in the reports vector +- `regrass`: don't remove mud on regrass, consistent with vanilla behavior +- `seedwatch`: display a limit of ``-`` instead of ``0`` for a seed that is present in inventory but not being watched +- `tiletypes`: make aquifers functional when adding the ``aquifer`` property and there are no existing aquifer tiles in the same map block +- `seedwatch`: do not include unplantable tree seeds in status report +- ``Buildings::containsTile``: fix result for buildings that are solid and have no extent structures +- Mortal mode: prevent keybindings that run armok tools from being recognized when in mortal mode +- `dig`: don't leave phantom dig designations behind when autodigging warm/damp designated tiles +- `buildingplan`: properly identify appropriate construction items for modded buildings built from thread +- `overlay`: overlay positions are now adjusted according to the configured max interface width percentage in the DF settings +- `zone`: animal assignment overlay button moved to not conflict with vanilla aquarium/terrarium button on glass cages +- `zone`: allow friendly creatures to be released from cages by assigning them to a pasture zone and then unassigning them +- `autobutcher`: fix inverted ranking of which animals to butcher first + +## Misc Improvements +- `blueprint`: capture track carving designations in addition to already-carved tracks +- `changevein`: follow veins into adjacent map blocks so you can run the command once instead of once per map block that the vein crosses +- `regrass`: now accepts numerical IDs for grass raws; ``regrass --list`` replaces ``regrass --plant ""`` +- `tiletypes`: performance improvements when affecting tiles over a large area +- `tiletypes`: support for creating heavy aquifers +- `tiletypes`: new ``autocorrect`` property for autocorrecting adjacent tiles when making changes (e.g. adding ramp tops when you add a ramp) +- Dreamfort: add a full complement of beds and chests to both barracks +- Dreamfort: redesign guildhall/temple/library level for better accessibility +- Dreamfort: walkthrough documentation refresh +- Dreamfort: add milking/shearing station in surface grazing pasture +- Dreamfort: integrate building prioritization into the blueprints and remove `prioritize` checklist steps +- Dreamfort: add plumbing template for filling cisterns with running water +- `buildingplan`: add option to ignore items from a specified burrow +- `autobutcher`: do not butcher pregnant (or brooding) females +- `quickfort`: support buildable instruments +- `orders`: you can now delete your exported orders from the import dialog +- `nestboxes`: increase the scanning frequency for fertile eggs to reduce the chance that they get snarfed by eager dwarves +- `autonestbox`: wait until juveniles become adults before they are assigned to nestboxes +- `suspendmanager`: add option to ``unsuspend`` that unsuspends all jobs, regardless of potential issues (like blocking other construction jobs) +- `gui/create-item`: allow right click to cancel out of material dialog submenus + +## Documentation +- `installing`: add instructions for how to use Steam DFHack with non-Steam DF (e.g. to benefit from DFHack auto-updates and cloud backups) +- `modding-guide`: add a section on persistent storage, both for global settings and world-specific settings +- Developer's primer for DFHack's type identity system + +## API +- Focus strings have moved for stockpile states: ``dwarfmode/CustomStockpile`` is now ``dwarfmode/Stockpile/Some/Customize`` and similar for ``dwarfmode/StockpileTools`` and ``dwarfmode/StockpileLink`` +- ``Buildings::getName``: get a building's name +- ``Maps::isTileAquifer``, ``Maps::isTileHeavyAquifer``, ``Maps::setTileAquifer``, ``Maps::removeTileAquifer``, ``Maps::setAreaAquifer``, ``Maps::removeAreaAquifer``: new aquifer detection and modification API +- ``Units::create``, ``Units::makeown``: new APIs to use bay12-provided entry points for low-level operations +- ``format_number``: format numbers according to the configured player formatting preference +- ``Items::remove``: now cancels related jobs and marks the item as hidden and forbidden until it can be garbage collected +- ``Job::addGeneralRef``: new easy API for creating general references and adding them to a Job +- ``Job::addWorker``: new API function for assigning a job to unit + +## Lua +- ``dfhack.gui.getSelectedJob``: can now return the job with a destination under the keyboard cursor (e.g. digging/carving/engraving jobs) +- ``widgets.makeButtonLabelText``: create text and graphical buttons from character/color/tile maps and/or dynamically loaded tilesets +- ``widgets.DimensionsTooltip``: reusable selected dimensions tooltip that follows the mouse cursor around +- ``widgets.ButtonGroup``: subclass of CycleHotkeyLabel that additionally displays clickable graphical buttons +- ``widgets.CycleHotkeyLabel``: when the widget has both forward and backward hotkeys defined, support moving backwards by clicking on the appropriate hotkey hint +- ``safe_index``: will now return nil when attempting to index into a non-indexable object +- ``script-manager``: add ``getModSourcePath`` and ``getModStatePath`` so modders can get the directory path to their own files +- ``widgets.FilteredList``: don't restrict the player from inputting multiple successive space characters +- ``dfhack.maps.isTileAquifer``, ``dfhack.maps.isTileHeavyAquifer``, ``dfhack.maps.setTileAquifer``, ``dfhack.maps.removeTileAquifer``: access to new aquifer API +- ``plugins.tiletypes.tiletypes_setTile``: can now accept a table for access to previously unavailable options +- ``dialogs.showYesNoPrompt``: extend options so the standard dialog can be used for `gui/confirm`-style confirmation prompts +- ``dfhack.units.create``, ``dfhack.units.makeown``: Lua access to new module API +- ``dfhack.formatInt``, ``dfhack.formatFloat``: formats numbers according to the player preferences for number formatting set in `gui/control-panel` +- ``gui.get_interface_rect``, ``gui.get_interface_frame``: convenience functions for working with scaled interfaces +- ``overlay``: new attributes: ``fullscreen`` and ``full_interface`` for overlays that need access to the entire screen or the scaled interface area, respectively +- ``string:wrap``: now preserves inter-word spacing and can return the wrapped lines as a table of strings instead of a single multi-line string +- ``dfhack.internal.getClipboardTextCp437Multiline``: for retrieving multiline text from the system clipboard + +## Removed +- `plants`: renamed to `plant` +- ``gui.FramedScreen``: this class is now deprecated; please use ``gui.ZScreen`` and ``widgets.Window`` instead +- ``dfhack.HIDE_CONSOLE_ON_STARTUP`` and ``dfhack.HIDE_ARMOK_TOOLS`` are no longer directly accessible. Please use `control-panel` or `gui/control-panel` to interact with those settings. + +# 50.13-r2.1 + +## Fixes +- `suspendmanager`: stop suspending single tile stair constructions + +# 50.13-r2 + +## New Tools +- Updated for adventure mode: `reveal` + +## New Features +- `buildingplan`: quick material filter favorites on main planner panel +- DFHack and the Dwarf Fortress translation project can now both be run at the same time + +## Fixes +- `zone`: fix display of distance from cage/pit for small pets in assignment dialog +- `blueprint`: correctly define stockpile boundaries in recorded stockpile ("place") blueprints when there are adjacent non-rectangular stockpiles of identical types +- `dig`: refresh count of tiles that will be modified by "mark all designated tiles on this z-level for warm/damp dig" when the z-level changes +- `dig`: don't affect already-revealed tiles when marking z-level for warm/damp dig +- `zone`: refresh values in distance column when switching selected pastures when the assign animals dialog is open +- `logistics`: include semi-wild pets when autoretrain is enabled +- `suspendmanager`: fully suspend unbuildable dead ends (e.g. building second level of a wall when the wall top is only accessible via ramp, causing the planned wall to be pathable but not buildable) +- `prospect`: don't use scientific notation for representing large numbers + +## Misc Improvements +- `caravan`: display who is in the cages you are selecting for trade and whether they are hostile +- `regrass`: can now add grass to stairs, ramps, ashes, buildings, muddy stone, shrubs, and trees +- `regrass`: can now restrict area of effect to specified tile, block, cuboid, or z-levels +- `regrass`: can now add grass in map blocks where there hasn't been any +- `regrass`: can now choose specific grass type +- `dig`: warm/damp/aquifer status will now be shown in mining mode for tiles that your dwarves can see from the level below +- `dig`: warm/damp/aquifer status will now be shown when in smoothing/engraving modes +- `stockpiles`: support import and export "desired items" configuration for route stops +- New commandline options for controlling the Cloud Save coprocess when launching from Steam. See the `dfhack-core` documentation for details. +- `markdown`: new keybinding for triggering text export: Ctrl-t (when unit or item is selected) +- `flashstep`: new keybinding for teleporting adventurer to the mouse cursor: Ctrl-t (when adventure map is in the default state and mortal mode is disabled in DFHack preferences) +- Dreamfort: move wells on services level so brawling drunken tavern patrons are less likely to fall in +- `unretire-anyone`: new keybinding for adding a historical figure to the adventurer selection list in the adventure mode setup screen: Ctrl-a + +## Documentation +- Quickfort Blueprint Library: add demo videos for pump stack and light aquifer tap blueprints +- Update docs for dependency requirements and compilation procedures + +## API +- ``dfhack.items.getReadableDescription()``: easy API for getting a human-readable item description with useful annotations and information (like tattered markers or who is in a cage) +- ``Items::createItem``: now returns a list of item pointers rather than a single ID, moved creator parameter to beginning, added growth_print and no_floor parameters at end +- ``World::getAdventurer``: returns current adventurer unit +- ``World::ReadPauseState``: now returns true when the game is effectively paused due to a large panel obscuring the map. this aligns the return value with the visual state of the pause button when in fort mode. + +## Lua +- ``dfhack.internal.setClipboardTextCp437Multiline``: for copying multiline text to the system clipboard +- ``dfhack.world.getAdventurer``: returns current adventurer unit +- ``dfhack.items.createItem``: return value and parameters have changed as per C++ API + +# 50.13-r1.1 + +## Documentation +- Update docs on release procedures and symbol generation + +# 50.13-r1 + +## Fixes +- Fixed misidentification of visitors from your own civ as residents; affects all tools that iterate through citizens/residents +- `cursecheck`: act on selected unit only if a unit is selected +- Fixed incorrect DFHack background window texture when DF is started in ascii mode and subsequently switched to graphics mode + +## Misc Improvements +- `suspendmanager`: Account for walls planned on the z-layer below when determining accessibility to a job + +## Documentation +- `autoclothing`: add section comparing ``autoclothing`` and `tailor` to guide players choosing which to enable + +# 50.12-r3 + +## New Tools +- `aquifer`: commandline tool for creating, draining, and modifying aquifers + +## New Features +- `buildingplan`: add overlays for unlinking and freeing mechanisms from buildings +- `dig`: designate tiles for damp or warm dig, which allows you to dig through damp or warm tiles without designations being canceled +- `dig`: damp and warm tile icons now remain visible when included in the designation selection box (graphics mode) +- `dig`: aquifer tiles are now visually distinct from "just damp" tiles (graphics and ascii modes) +- `dig`: light aquifer tiles are now visually distinct from heavy aquifer tiles (graphics and ascii modes) +- `dig`: autodig designations that are marked for damp/warm dig propagate the damp/warm tag when expanding to newly exposed tiles +- `blueprint`: designations and active dig jobs are now captured in generated blueprints +- `blueprint`: warm/damp dig markers are captured in generated blueprints + +## Fixes +- fix behavior of Linux Steam launcher on systems that don't support the inotify API +- fix rendering of resize "notch" in lower right corner of resizable windows in ascii mode +- `quickfort`: stockpiles can now be placed even if there is water covering the tile, as per vanilla behavior +- `suspendmanager`: prevent cancellation spam when an item is preventing a building from being completed +- `stonesense`: fix a crash with buildings made of unusual materials (such as campsite tents made out of organic "walls") + +## Misc Improvements +- `tailor`: allow turning off automatic confiscation of tattered clothing +- aquifer_tap blueprint: now designates in damp dig mode for uninterrupted digging in a light aquifer +- pump_stack blueprint: now designates in warm and damp dig mode for uninterrupted digging through warm and damp tiles +- `keybinding`: you can now assign keybindings to mouse buttons (if your mouse has more than the three buttons already used by DF) + +## Documentation +- Lua API: documented existing ``enum:next_item(index)`` function + +## API +- ``Units::citizensRange``: c++-20 std::range filter for citizen units +- ``Units::forCitizens``: iterator callback function for citizen units +- ``Units::paintTile``, ``Units::readTile``: now takes an optional field specification for reading and writing to specific map compositing layers +- ``Buildings::checkFreeTiles``: now takes a ``allow_flow`` parameter to control whether water- or magma-filled tiles are valid + +## Lua +- ``dfhack.gui.matchFocusString``: focus string matching is now case sensitive (for performance reasons) + +# 50.12-r2.1 + +## Fixes +- `orders`: don't intercept keyboard input for setting skill or labor restrictions on workshop workers tab when the player is setting the building nickname + +# 50.12-r2 + +## New Features +- `stocks`: add button/hotkey for removing empty categories from the stocks list +- `sort`: updated and reinstated military status/squad membership/burrow membership filter for work animal assignment screen +- `logistics`: ``autoretrain`` will automatically assign trainers to your partially-trained (but not yet domesticated) livestock. this prevents children of partially-trained parents from reverting to wild if you don't notice they were born +- `orders`: add overlay for configuring labor and skill level restrictions for workshops + +## Fixes +- `autochop`: fix underestimation of log yield for cavern mushrooms +- `gui/notify`: prevent notification overlay from showing up in arena mode +- `logistics`: don't melt/trade/dump empty containers that happen to be sitting on the stockpile unless the stockpile accepts those item types +- `gui/launcher`: fix detection on Shift-Enter for running commands and autoclosing the launcher +- `logistics`: don't send autotrade items to forbidden depots +- `autoclothing`: don't produce clothes for dead units +- `caravan`: fix trade price calculations when the same item was requested for both import and export + +## Misc Improvements +- `autobutcher`: prefer butchering partially trained animals and save fully domesticated animals to assist in wildlife domestication programs +- `autodump`: can now teleport items loosely stored in buildings (clutter) +- When launched from the Steam client on Linux, both Dwarf Fortress and DFHack will be shown as "Running". This ensures that DF has proper accounting for Linux player usage. +- `suspendmanager`: improve performance when there are many active jobs +- `clean`: protect farm plots when cleaning mud +- `tweak`: add ``quiet`` option for silent enablement and disablement of tweaks +- `gui/teleport`: add global Ctrl-Shift-T keybinding (only available when DFHack mortal mode is disabled) +- Dreamfort: the four Craftsdwarf's workshops on the industry level are now specialized for Stonecrafting, Woodcrafting, Bone Carving, and miscellaneous tasks, respectively +- `dwarfvet`: automatically unassign animals from pastures when they need treatment so they can make their way to the hospital. reassign them to their original pasture when treatment is complete. +- `dwarfvet`: ignore animals assigned to cages or restraints +- Many tools that previously only worked for citizens or only for dwarves now work for all citizens and residents, e.g. `fastdwarf`, `rejuvenate`, etc. +- `buildingplan`: remember player preference for whether unavailable materials should be hidden in the filter selection dialog +- `buildingplan`: sort by available quantity by default int he filter selection dialog +- Dreamfort: update embark profile recommendations and example embark profile + +## Documentation +- `overlay-dev-guide`: updated examples and troubleshooting steps +- `introduction`: refresh getting started content +- `quickstart`: refresh quickstart guide + +## API +- ``Units::isForgottenBeast``: property check for forgotten beasts +- ``Units::isGreatDanger``: now includes forgotten beasts +- ``Units::isResident``: property check for residents (as opposed to citizens) +- ``Units::getCitizens``: now includes residents by default + +## Lua +- ``widgets.Label``: ``*pen`` attributes can now either be a pen or a function that dynamically returns a pen +- `helpdb`: ``search_entries`` now returns a match if *all* filters in the ``include`` list are matched. previous behavior was to match if *any* ``include`` filter matched. +- ``matinfo.decode``: now directly handles plant objects +- ``dfhack.units.isForgottenBeast``: make new units method available to Lua +- ``dfhack.units.getCitizens``: now includes residents by default + +# 50.12-r1.1 + +## Fixes +- `sort`: fix crash when assigning work animals to units + +## Removed +- offline HTML rendered docs are no longer distributed with DFHack since they are randomly triggering Windows Defender antivirus heuristics. If you want to download DFHack docs for offline browsing, you can still get them from the Downloads link at https://dfhack.org/docs + +# 50.12-r1 + +## Misc Improvements +- `sort`: squad assignment overlay rewritten for compatibility with new vanilla data structures and screen layouts + +## Fixes +- `gui/design`: no longer comes up when Ctrl-D is pressed but other DFHack windows have focus + +## API + +- ``Gui::getWidget``: retrieve a vanilla DF widget by name or index + +## Lua + +- ``dfhack.gui.getWidget``: retrieve a vanilla DF widget by hierarchy path, with each step specified by a widget name or index +- ``dfhack.gui.getWidgetChildren``: retrieve a list of child widgets for a given widget container + +## Removed +- `burrow`: removed overlay 3D box select since it is now provided by the vanilla UI +- `sort`: removed Search widgets for screens that now have vanilla search + +# 50.11-r7 + +## New Tools +- `tweak`: (reinstated) a collection of small bugfixes and gameplay tweaks +- `pet-uncapper`: (reinstated, renamed from ``petcapRemover``) allow pets to breed beyond the default population cap of 50 + +## New Features +- `cleanowned`: Add a "nodump" option to allow for confiscating items without dumping +- `tweak`: Add "flask-contents", makes flasks/vials/waterskins be named according to their contents + +## Fixes +- `dig`: overlay that shows damp designations in ASCII mode now properly highlights tiles that are damp because of an aquifer in the layer above +- `dig-now`: fix digging stairs in the surface sometimes creating underworld gates. +- ``Units::getVisibleName``: don't reveal the true identities of units that are impersonating other historical figures +- ``Gui::revealInDwarfmodeMap``: properly center the zoom even when the target tile is near the edge of the map +- `warn-stranded`: don't complain about units that aren't on the map (e.g. soldiers out on raids) +- `autoclothing`: Fix enabled behavior +- ``Gui::makeAnnouncement``, ``Gui::autoDFAnnouncement``: don't display popup for all announcement types +- ``gui.View:getMouseFramePos``: function now detects the correct coordinates even when the widget is nested within other frames +- `strangemood`: correctly recognize Stonecutter and Stone Carver as moodable skills, move the Mason's boosted mood chance to the Stone Carver, and select Fell/Macabre based on long-term stress + +## Misc Improvements +- `autonestbox`: assign egg layers to the nestbox they have chosen if they have already chosen a nestbox +- `regrass`: also regrow depleted cavern moss +- `probe`: act on the selected building/unit instead of requiring placement of the keyboard cursor for ``bprobe`` and ``cprobe`` +- `buildingplan`: use closest matching item rather than newest matching item +- `zone`: animal assignment dialog now shows distance to pasture/cage and allows sorting by distance +- `zone`: animal assignment dialog shows number of creatures assigned to this pasture/cage/etc. + +## API +- Gui module Announcement functions now use DF's new announcement alert system +- ``Gui::addCombatReport``, ``Gui::addCombatReportAuto``: add versions that take ``report *`` instead of report vector index +- ``Gui::MTB_clean``, ``Gui::MTB_parse``, ``Gui::MTB_set_width``: new functions for manipulating ``markup_text_boxst`` +- ``toupper_cp437(char)``, ``tolower_cp437(char)``: new ``MiscUtils`` functions, return a char with case changed, respecting CP437 +- ``toUpper``, ``toLower``: ``MiscUtils`` functions renamed to ``toUpper_cp437`` and ``toLower_cp437``, CP437 compliant +- Gui focus strings will now include ``dwarfmode/Default`` if the only other panel open is the Squads panel +- ``Gui::revealInDwarfmodeMap``: unfollow any currently followed units/items so the viewport doesn't just jump back to where it was + +## Lua +- Overlay framework now respects ``active`` and ``visible`` widget attributes +- ``dfhack.gui`` announcement functions use default arguments when omitted +- ``dfhack.units.getCitizens`` now only returns units that are on the map +- ``dfhack.upperCp437(string)``, ``dfhack.lowerCp437(string)``: new functions, return string with all chars changed, respecting CP437 code page + +# 50.11-r6 + +## New Features +- `zone`: Add overlay for toggling butchering/gelding/adoption/taming options in animal "Overview" tabs + +## Fixes +- `dig-now`: remove diagonal ramps rendered unusable by digging +- `dig-now`: fix error propagating "light" and "outside" properties to newly exposed tiles when piercing the surface +- `sort`: fix potential crash when switching between certain info tabs +- `suspendmanager`: overlays for suspended building info panels no longer disappear when another window has focus + +## Misc Improvements +- `reveal`: automatically reset saved map state when a new save is loaded +- `autonestbox`: don't automatically assign partially trained egg-layers to nestboxes if they don't have an ongoing trainer assigned since they might revert to wild +- `buildingplan`: replace ``[edit filters]`` button in planner overlay with abbreviated filter information + +## API +- ``Units::assignTrainer``: assign a trainer to a trainable animal +- ``Units::unassignTrainer``: unassign a trainer from an animal +- ``Gui::getAnyWorkshopJob``: get the first job associated with the selected workshop +- ``Gui::getAnyJob``: get the job associated with the selected game element (item, unit, workshop, etc.) + +## Lua +- ``dfhack.units.isTamable``: return false for invaders to match vanilla logic +- ``dfhack.units.assignTrainer``: expose API to Lua +- ``dfhack.units.unassignTrainer``: expose API to Lua +- ``dfhack.gui.getAnyWorkshopJob``: expose API to Lua +- ``dfhack.gui.getAnyJob``: expose API to Lua + +## Removed +- ``nopause``: functionality has moved to `spectate` + +# 50.11-r5 + +## New Tools +- `gui/embark-anywhere`: new keybinding (active when choosing an embark site): Ctrl-A + +## New Features +- `sort`: search and sort for the "choose unit to elevate to the barony" screen. units are sorted by the number of item preferences they have and the units are annotated with the items that they have preferences for +- `zone`: add button to location details page for retiring unused locations +- `gui/mass-remove`: new global keybinding: Ctrl-M while on the fort map + +## Fixes +- `reveal`: now avoids revealing blocks that contain divine treasures, encased horrors, and deep vein hollows (so the surprise triggers are not triggered prematurely) +- `sort`: fix mouse clicks falling through the squad assignment overlay panel when clicking on the panel but not on a clickable widget +- `sort`: fix potential crash when removing jobs directly from the Tasks info screen +- `misery`: fix error when changing the misery factor +- When passing map movement keys through to the map from DFHack tool windows, also pass fast z movements (shift-scroll by default) +- `getplants`: fix crash when processing mod-added plants with invalid materials +- Dreamfort: fix holes in the "Inside+" burrow on the farming level (burrow autoexpand is interrupted by the pre-dug miasma vents to the surface) +- ``Maps::getBiomeType``, ``Maps::getBiomeTypeWithRef``: fix identification of tropical oceans +- DFHack tabs (e.g. in `gui/control-panel`) are now rendered correctly when there are certain vanilla screen elements behind them +- `buildingplan`: when you save a game and load it again, newly planned buildings are now correctly placed in line after existing planned buildings of the same type +- `buildingplan`: treat items in wheelbarrows as unavailable, just as vanilla DF does. Make sure the `fix/empty-wheelbarrows` fix is enabled so those items aren't permanently unavailable! +- `buildingplan`: show correct number of materials required when laying down areas of constructions and some of those constructions are on invalid tiles +- `stonesense`: fix crash in cleanup code after mega screenshot (Ctrl-F5) completes; however, the mega screenshot will still make stonesense unresponsive. close and open the stonesense window to continue using it. +- `gui/design`: fix incorrect highlight when box selecting area in ASCII mode +- `fastdwarf`: prevent units from teleporting to inaccessible areas when in teledwarf mode +- `fastdwarf`: allow units to meander and satisfy needs when they have no current job and teledwarf mode is enabled + +## Misc Improvements +- `autochop`: better error output when target burrows are not specified on the commandline +- `autoclothing` : now does not consider worn (x) clothing as usable/available; reduces overproduction when using `tailor` at same time +- `buildingplan`: add option for preventing constructions from being planned on top of existing constructions (e.g. don't build floors on top of floors) +- `burrow`: flood fill now requires an explicit toggle before it is enabled to help prevent accidental flood fills +- wherever units are listed in DFHack tools, properties like "agitated" or (-trained-) are now shown +- `work-now`: now saves its enabled status with the fort +- `fastdwarf`: now saves its state with the fort +- `zone`: add include/only/exclude filter for juveniles to the pasture/pit/cage/restraint assignment screen +- The "PAUSE FORCED" badge will blink briefly to draw attention if the player attempts to unpause when a DFHack tool window requires the game to be paused +- `sort`: add "Toggle all filters" hotkey button to the squad assignment panel +- `sort`: rename "Weak mental fortitude" filter to "Dislikes combat", which should be more understandable +- Dreamfort: put more chairs adjacent to each other to make the tavern more "social" +- `zone`: show geld status and custom profession (if set, it's the lower editable line in creature description) in pasture/pit/cage/restraint assignment screen +- `orders`: reduce prepared meal target and raise booze target in ``basic`` importable orders in the orders library + +## Documentation +- `installing`: Add installation instructions for wineskin on Mac +- UTF-8 text in tool docs is now properly displayed in-game in `gui/launcher` (assuming that it can be converted to cp-437) +- `modding-guide`: Add examples for script-only and blueprint-only mods that you can upload to DF's Steam Workshop +- DFHack developer's guide updated, with refreshed `architectural-diagrams` + +## API +- ``random_index``, ``vector_get_random``: new ``MiscUtils`` functions, for getting a random entry in a vector +- ``capitalize_string_words``: new ``MiscUtils`` function, returns string with all words capitalized +- ``grab_token_string_pos``: new ``MiscUtils`` function, used for parsing tokens +- ``Items``: add item melting logic ``canMelt(item)``, ``markForMelting(item)``, and ``cancelMelting(item)`` +- ``World``: ``GetCurrentSiteId()`` returns the loaded fort site ID (or -1 if no site is loaded) +- ``World``: ``IsSiteLoaded()`` check to detect if a site (e.g. a player fort) is active (as opposed to the world or a map) +- ``World``: ``AddPersistentData`` and related functions replaced with ``AddPersistentSiteData`` and ``AddPersistentWorldData`` equivalents +- New plugin API for saving and loading persistent data. See plugins/examples/skeleton.cpp and plugins/examples/persistent_per_save_example.cpp for details +- Plugin ABI (binary interface) version bump! Any external plugins must be recompiled against this version of DFHack source code in order to load. +- ``Persistence``: persistent keys are now namespaced by an entity_id (e.g. a player fort site ID) +- ``Persistence``: data is now stored one file per entity ID (plus one for the global world) in the DF savegame directory +- ``Units.isDanger``: now returns true for agitated wildlife +- ``Constructions::designateRemove``: no longer designates the non-removable "pseudo" constructions that represent the top of walls + +## Lua +- ``dfhack.capitalizeStringWords``: new function, returns string with all words capitalized +- ``widgets.Divider``: linear divider to split an existing frame; configurable T-junction edges and frame style matching +- ``dfhack.persistent``: new, table-driven API for easier world- and site-associated persistent storage. See the Lua API docs for details. +- ``dfhack.isSiteLoaded``: returns whether a site (e.g. a player fort) is loaded +- ``dfhack.items``: access to ``canMelt(item)``, ``markForMelting(item)``, and ``cancelMelting(item)`` from ``Items`` module +- ``dfhack.world.getCurrentSite``: returns the ``df.world_site`` instance of the currently loaded fort + +## Removed +- ``persist-table``: replaced by new ``dfhack.persistent`` API +- `channel-safely`: (temporarily) removed due to stability issues with the underlying DF API + +# 50.11-r4 + +## Fixes +- `buildingplan`: fix choosing the wrong mechanism (or something that isn't a mechanism) when linking a lever and manually choosing a mechanism, but then canceling the selection +- RemoteServer: don't shut down the socket prematurely, allowing continuing connections from, for example, dfhack-run +- `sort`: fix potential crash when exiting and re-entering a creatures subtab with a search active +- `sort`: prevent keyboard keys from affecting the UI when search is active and multiple keys are hit at once +- `tailor`: fix corner case where existing stock was being ignored, leading to over-ordering + +## Misc Improvements +- `buildingplan`: save magma safe mechanisms for when magma safety is requested when linking levers and pressure plates to targets +- `buildingplan`: when choosing mechanisms for linking levers/pressure plates, filter out unreachable mechanisms +- `sort`: when searching on the Tasks tab, also search the names of the things the task is associated with, such as the name of the stockpile that an item will be stored in + +# 50.11-r3 + +## New Tools +- `burrow`: (reinstated) automatically expand burrows as you dig + +## New Features +- `prospect`: can now give you an estimate of resources from the embark screen. hover the mouse over a potential embark area and run `prospect`. +- `burrow`: integrated 3d box fill and 2d/3d flood fill extensions for burrow painting mode +- `buildingplan`: allow specific mechanisms to be selected when linking levers or pressure plates +- `sort`: military and burrow membership filters for the burrow assignment screen + +## Fixes +- `stockpiles`: hide configure and help buttons when the overlay panel is minimized +- `caravan`: price of vermin swarms correctly adjusted down. a stack of 10000 bees is worth 10, not 10000 +- `sort`: when filtering out already-established temples in the location assignment screen, also filter out the "No specific deity" option if a non-denominational temple has already been established +- RemoteServer: continue to accept connections as long as the listening socket is valid instead of closing the socket after the first disconnect +- `buildingplan`: overlay and filter editor gui now uses ctrl-d to delete the filter to avoid conflict with increasing the filter's minimum quality (shift-x) +- `tailor`: fix crash on Linux where scanned unit is wearing damaged non-clothing (e.g. a crown) + +## Misc Improvements +- `buildingplan`: display how many items are available on the planner panel +- `buildingplan`: make it easier to build single-tile staircases of any shape (up, down, or up/down) +- `sort`: allow searching by profession on the squad assignment page +- `sort`: add search for places screens +- `sort`: add search for work animal assignment screen; allow filtering by military/squad/civilian/burrow +- `sort`: on the squad assignment screen, make effectiveness and potential ratings use the same scale so effectiveness is always less than or equal to potential for a given unit. this way you can also tell when units are approaching their maximum potential +- `sort`: new overlay on the animal assignment screen that shows how many work animals each visible unit already has assigned to them +- `dreamfort`: Inside+ and Clearcutting burrows now automatically created and managed + +## Documentation +- Document the Lua API for the ``dfhack.world`` module + +## API +- ``Gui::revealInDwarfmodeMap``: gained ``highlight`` parameter to control setting the tile highlight on the zoom target +- ``Maps::getWalkableGroup``: get the walkability group of a tile +- ``Units::getReadableName``: now returns the *untranslated* name +- ``Burrows::setAssignedUnit``: now properly handles inactive burrows +- ``Gui::getMousePos``: now takes an optional ``allow_out_of_bounds`` parameter so coordinates can be returned for mouse positions outside of the game map (i.e. in the blank space around the map) +- ``Buildings::completebuild``: used to link a newly created building into the world + +## Lua +- ``dfhack.gui.revealInDwarfmodeMap``: gained ``highlight`` parameter to control setting the tile highlight on the zoom target +- ``dfhack.maps.getWalkableGroup``: get the walkability group of a tile +- ``dfhack.gui.getMousePos``: support new optional ``allow_out_of_bounds`` parameter +- ``gui.FRAME_THIN``: a panel frame suitable for floating tooltips +- ``dfhack.buildings.completebuild``: expose new module API + +# 50.11-r2 + +## New Tools +- `spectate`: (reinstated) automatically follow dwarves, cycling among interesting ones +- `preserve-tombs`: keep tombs assigned to units when they die + +## New Features +- `logistics`: ``automelt`` now optionally supports melting masterworks; click on gear icon on `stockpiles` overlay frame +- `sort`: new search widgets for Info panel tabs, including all "Creatures" subtabs, all "Objects" subtabs, "Tasks", candidate assignment on the "Noble" subtab, and the "Work details" subtab under "Labor" +- `sort`: new search and filter widgets for the "Interrogate" and "Convict" screens under "Justice" +- `sort`: new search widgets for location selection screen (when you're choosing what kind of guildhall or temple to dedicate) +- `sort`: new search widgets for burrow assignment screen and other unit assignment dialogs +- `sort`: new search widgets for artifacts on the world/raid screen +- `sort`: new search widgets for slab engraving menu; can filter for only units that need a slab to prevent rising as a ghost +- `stocks`: hotkey for collapsing all categories on stocks screen + +## Fixes +- `buildingplan`: remove bars of ash, coal, and soap as valid building materials to match v50 rules +- `buildingplan`: fix incorrect required items being displayed sometimes when switching the planner overlay on and off +- `zone`: races without specific child or baby names will now get generic child/baby names instead of an empty string +- `zone`: don't show animal assignment link for cages and restraints linked to dungeon zones (which aren't normally assignable) +- `sort`: don't count mercenaries as appointed officials in the squad assignment screen +- `dwarfvet`: fix invalid job id assigned to ``Rest`` job, which could cause crashes on reload + +## Misc Improvements +- `overlay`: allow ``overlay_onupdate_max_freq_seconds`` to be dynamically set to 0 for a burst of high-frequency updates +- Help icons added to several complex overlays. clicking the icon runs `gui/launcher` with the help text in the help area +- `orders`: ``recheck`` command now only resets orders that have conditions that can be rechecked +- `sort`: added help button for squad assignment search/filter/sort +- `zone`: animals trained for war or hunting are now labeled as such in animal assignment screens +- `buildingplan`: support filtering cages by whether they are occupied +- `buildingplan`: show how many items you need to make when planning buildings +- `tailor`: now adds to existing orders if possible instead of creating new ones + +## Documentation +- unavailable tools are no longer listed in the tag indices in the online docs + +## API +- added ``Items::getCapacity``, returns the capacity of an item as a container (reverse-engineered), needed for `combine` + +## Lua +- added ``GRAY`` color aliases for ``GREY`` colors +- added ``dfhack.items.getCapacity`` to expose the new module API +- ``utils.search_text``: text search routine (generalized from internal ``widgets.FilteredList`` logic) + +## Removed +- ``FILTER_FULL_TEXT``: moved from ``gui.widgets`` to ``utils``; if your full text search preference is lost, please reset it in `gui/control-panel` + +# 50.11-r1 + +## New Tools +- `tubefill`: (reinstated) replenishes mined-out adamantine + +## Fixes +- `autolabor`: ensure vanilla work details are reinstated when the fort or the plugin is unloaded +- ``dfhack.TranslateName()``: fixed crash on certain invalid names, which affected `warn-starving` +- EventManager: Unit death event no longer misfires on units leaving the map + +## Misc Improvements +- `digtype`: designate only visible tiles by default, and use "auto" dig mode for following veins +- `digtype`: added options for designating only current z-level, this z-level and above, and this z-level and below +- `hotkeys`: make the DFHack logo brighten on hover in ascii mode to indicate that it is clickable +- `hotkeys`: use vertical bars instead of "!" symbols for the DFHack logo in ascii mode to make it easier to read +- EventManager: guard against potential iterator invalidation if one of the event listeners were to modify the global data structure being iterated over +- EventManager: for ``onBuildingCreatedDestroyed`` events, changed firing order of events so destroyed events come before created events + +## Lua +- mouse key events are now aligned with internal DF semantics: ``_MOUSE_L`` indicates that the left mouse button has just been pressed and ``_MOUSE_L_DOWN`` indicates that the left mouse button is being held down. similarly for ``_MOUSE_R`` and ``_MOUSE_M``. 3rd party scripts may have to adjust. + +# 50.10-r1 + +## Fixes +- Linux launcher: allow Steam Overlay and game streaming to function +- `autobutcher`: don't ignore semi-wild units when marking units for slaughter + +## Misc Improvements +- 'sort': Improve combat skill scale thresholds + +# 50.09-r4 + +## New Features +- `dig`: new overlay for ASCII mode that visualizes designations for smoothing, engraving, carving tracks, and carving fortifications + +## Fixes +- `buildingplan`: make the construction dimensions readout visible again +- `seedwatch`: fix a crash when reading data saved by very very old versions of the plugin +- `gui/mod-manager`: don't continue to display overlay after the raws loading progress bar appears + +## Misc Improvements +- `sort`: add sort option for training need on squad assignment screen +- `sort`: filter mothers with infants, units with weak mental fortitude, and critically injured units on the squad assignment screen +- `sort`: display a rating relative to the current sort order next to the visible units on the squad assignment screen + +## Documentation +- add instructions for downloading development builds to the ``Installing`` page + +## API +- `overlay`: overlay widgets can now declare a ``version`` attribute. changing the version of a widget will reset its settings to defaults. this is useful when changing the overlay layout and old saved positions will no longer be valid. + +## Lua +- ``argparse.boolean``: convert arguments to lua boolean values. + +# 50.09-r3 + +## New Features +- `sort`: search, sort, and filter for squad assignment screen +- `zone`: advanced unit assignment screens for cages, restraints, and pits/ponds +- `buildingplan`: one-click magma/fire safety filter for planned buildings + +## Fixes +- Core: reload scripts in mods when a world is unloaded and immediately loaded again +- Core: fix text getting added to DFHack text entry widgets when Alt- or Ctrl- keys are hit +- `buildingplan`: ensure selected barrels and buckets are empty (or at least free of lye and milk) as per the requirements of the building +- `orders`: prevent import/export overlay from appearing on the create workorder screen +- `caravan`: corrected prices for cages that have units inside of them +- `tailor`: remove crash caused by clothing items with an invalid ``maker_race`` +- ``dialogs.MessageBox``: fix spacing around scrollable text +- `seedwatch`: ignore unplantable tree seeds +- `autobutcher`: fix ``ticks`` commandline option incorrectly rejecting positive integers as valid values + +## Misc Improvements +- Surround DFHack-specific UI elements with square brackets instead of red-yellow blocks for better readability +- `autobutcher`: don't mark animals for butchering if they are already marked for some kind of training (war, hunt) +- `hotkeys`: don't display DFHack logo in legends mode since it covers up important interface elements. the Ctrl-Shift-C hotkey to bring up the menu and the mouseover hotspot still function, though. +- `sort`: animals are now sortable by race on the assignment screens +- `createitem`: support creating items inside of bags + +## API +- ``Items::getValue()``: remove ``caravan_buying`` parameter since the identity of the selling party doesn't actually affect the item value +- `RemoteFortressReader`: add a ``force_reload`` option to the GetBlockList RPC API to return blocks regardless of whether they have changed since the last request +- ``Units``: new animal property check functions ``isMarkedForTraining(unit)``, ``isMarkedForTaming(unit)``, ``isMarkedForWarTraining(unit)``, and ``isMarkedForHuntTraining(unit)`` +- ``Gui``: ``getAnyStockpile`` and ``getAnyCivzone`` (along with their ``getSelected`` variants) now work through layers of ZScreens. This means that they will still return valid results even if a DFHack tool window is in the foreground. + +## Lua +- ``new()``: improved error handling so that certain errors that were previously uncatchable (creating objects with members with unknown vtables) are now catchable with ``pcall()`` +- ``dfhack.items.getValue()``: remove ``caravan_buying`` param as per C++ API change +- ``widgets.BannerPanel``: panel with distinctive border for marking DFHack UI elements on otherwise vanilla screens +- ``widgets.Panel``: new functions to override instead of setting corresponding properties (useful when subclassing instead of just setting attributes): ``onDragBegin``, ``onDragEnd``, ``onResizeBegin``, ``onResizeEnd`` +- ``dfhack.screen.readTile()``: now populates extended tile property fields (like ``top_of_text``) in the returned ``Pen`` object +- ``dfhack.units``: new animal property check functions ``isMarkedForTraining(unit)``, ``isMarkedForTaming(unit)``, ``isMarkedForWarTraining(unit)``, and ``isMarkedForHuntTraining(unit)`` +- ``dfhack.gui``: new ``getAnyCivZone`` and ``getAnyStockpile`` functions; also behavior of ``getSelectedCivZone`` and ``getSelectedStockpile`` functions has changes as per the related API notes + +# 50.09-r2 + +## New Plugins +- `3dveins`: reinstated for v50, this plugin replaces vanilla DF's blobby vein generation with veins that flow smoothly and naturally between z-levels +- `zone`: new searchable, sortable, filterable screen for assigning units to pastures +- `dwarfvet`: reinstated and updated for v50's new hospital mechanics; allow your animals to have their wounds treated at hospitals +- `dig`: new ``dig.asciiwarmdamp`` overlay that highlights warm and damp tiles when in ASCII mode. there is no effect in graphics mode since the tiles are already highlighted there + +## Fixes +- Fix extra keys appearing in DFHack text boxes when shift (or any other modifier) is released before the other key you were pressing +- `logistics`: don't autotrain domestic animals brought by invaders (they'll get attacked by friendly creatures as soon as you let them out of their cage) +- `logistics`: don't bring trade goods to depot if the only caravans present are tribute caravans +- `gui/create-item`: when choosing a citizen to create the chosen items, avoid choosing a dead citizen +- `logistics`: fix potential crash when removing stockpiles or turning off stockpile features + +## Misc Improvements +- `stockpiles`: include exotic pets in the "tameable" filter +- `logistics`: bring an autotraded bin to the depot if any item inside is tradeable instead of marking all items within the bin as untradeable if any individual item is untradeable +- `autonick`: add more variety to nicknames based on famous literary dwarves +- ``widgets.EditField``: DFHack edit fields now support cut/copy/paste with the system clipboard with Ctrl-X/Ctrl-C/Ctrl-V +- Suppress DF keyboard events when a DFHack keybinding is matched. This prevents, for example, a backtick from appearing in a textbox as text when you launch `gui/launcher` from the backtick keybinding. +- Dreamfort: give noble suites double-thick walls and add apartment doors + +## Documentation +- `misery`: rewrite the documentation to clarify the actual effects of the plugin + +## API +- ``Units::getUnitByNobleRole``, ``Units::getUnitsByNobleRole``: unit lookup API by role +- ``Items::markForTrade()``, ``Items::isRequestedTradeGood()``, ``Items::getValue``: see Lua notes below + +## Internals +- Price calculations fixed for many item types + +## Lua +- ``dfhack.units.getUnitByNobleRole``, ``dfhack.units.getUnitsByNobleRole``: unit lookup API by role +- ``dfhack.items.markForTrade``: mark items for trade +- ``dfhack.items.isRequestedTradeGood``: discover whether an item is named in a trade agreement with an active caravan +- ``dfhack.items.getValue``: gained optional ``caravan`` and ``caravan_buying`` parameters for prices that take trader races and agreements into account +- ``widgets.TextButton``: wraps a ``HotkeyLabel`` and decorates it to look more like a button + +# 50.09-r1 + +## Internals + +- Core: update SDL interface from SDL1 to SDL2 + +# 50.08-r4 + +## New Plugins +- `logistics`: automatically mark and route items or animals that come to monitored stockpiles. options are toggleable on an overlay that comes up when you have a stockpile selected. + +## Fixes +- `buildingplan`: don't include artifacts when max quality is masterful +- `dig-now`: clear item occupancy flags for channeled tiles that had items on them +- `RemoteFortressReader`: fix a crash with engravings with undefined images + +## Misc Improvements +- `autonick`: additional nicknames based on burrowing animals, colours, gems, and minerals +- `stockpiles`: added ``barrels``, ``organic``, ``artifacts``, and ``masterworks`` stockpile presets +- `orders`: only display import/export/sort/clear panel on main orders screen +- `orders`: refine order conditions for library orders to reduce cancellation spam +- Blueprint library: dreamfort: full rewrite and update for DF v50 +- Blueprint library: pump_stack: updated walkthrough and separated dig and channel steps so boulders can be cleared +- Blueprint library: aquifer_tap: updated walkthrough +- `dig-now`: can now handle digging obsidian that has been formed from magma and water + +## Documentation +- `blueprint-library-guide`: update Dreamfort screenshots and links, add ``aquifer_tap`` screenshot + +# 50.08-r3 + +## Fixes +- Fix crash for some players when they launch DF outside of the Steam client + +# 50.08-r2 + +## New Plugins +- `add-spatter`: (reinstated) allow mods to add poisons and magical effects to weapons +- `changeitem`: (reinstated) change item material, quality, and subtype +- `createitem`: (reinstated) create arbitrary items from the command line +- `deramp`: (reinstated) removes all ramps designated for removal from the map +- `flows`: (reinstated) counts map blocks with flowing liquids +- `lair`: (reinstated) mark the map as a monster lair (this avoids item scatter when the fortress is abandoned) +- `luasocket`: (reinstated) provides a Lua API for accessing network sockets +- `work-now`: (reinstated, renamed from ``workNow``) prevent dwarves from wandering aimlessly with "No job" after completing a task + +## Fixes +- DFHack screen backgrounds now use appropriate tiles in DF Classic +- RemoteServer: fix crash on malformed json in ``dfhack-config/remote-server.json`` +- `autolabor`: work detail override warning now only appears on the work details screen +- `RemoteFortressReader`: ensured names are transmitted in UTF-8 instead of CP437 + +## Misc Improvements +- `autodump`: no longer checks for a keyboard cursor before executing, so ``autodump destroy`` (which doesn't require a cursor) can still function +- Settings: recover gracefully when settings files become corrupted (e.g. by DF CTD) +- `orders`: update orders in library for prepared meals, bins, archer uniforms, and weapons +- `gui/control-panel`: new preference for whether filters in lists search for substrings in the middle of words (e.g. if set to true, then "ee" will match "steel") +- `gui/design`: Improved performance for drawing shapes +- Dreamfort: improve traffic patterns throughout the fortress +- `gui/blueprint`: recording of stockpile layouts and categories is now supported. note that detailed stockpile configurations will *not* be saved (yet) +- Core: new commandline flag/environment var: pass ``--disable-dfhack`` on the Dwarf Fortress commandline or specify ``DFHACK_DISABLE=1`` in the environment to disable DFHack for the current session. +- `overlay`: add links to the quickstart guide and the control panel on the DF title screen +- Window behavior: non-resizable windows now allow dragging by their frame edges by default +- `gui/autodump`: fort-mode keybinding: Ctrl-H (when ``armok`` tools are enabled in `gui/control-panel`) +- Window behavior: if you have multiple DFHack tool windows open, scrolling the mouse wheel while over an unfocused window will focus it and raise it to the top +- `stockpiles`: allow filtering creatures by tameability + +## Internals +- ``dfhack.internal``: added memory analysis functions: ``msizeAddress``, ``getHeapState``, ``heapTakeSnapshot``, ``isAddressInHeap``, ``isAddressActiveInHeap``, ``isAddressUsedAfterFreeInHeap``, ``getAddressSizeInHeap``, and ``getRootAddressOfHeapObject`` + +## Lua +- ``overlay.reload()``: has been renamed to ``overlay.rescan()`` so as not to conflict with the global ``reload()`` function. If you are developing an overlay, please take note of the new function name for reloading your overlay during development. +- ``gui``: changed frame naming scheme to ``FRAME_X`` rather than ``X_FRAME``, and added aliases for backwards compatibility. (for example ``BOLD_FRAME`` is now called ``FRAME_BOLD``) +- ``ensure_keys``: walks a series of keys, creating new tables for any missing values + +## Removed +- `orders`: ``library/military_include_artifact_materials`` library file removed since recent research indicates that platinum blunt weapons and silver crossbows are not more effective than standard steel. the alternate military orders file was also causing unneeded confusion. + +# 50.08-r1 + +## Fixes +- `autoclothing`: eliminate game lag when there are many inventory items in the fort +- `buildingplan`: fixed size limit calculations for rollers +- `buildingplan`: fixed items not being checked for accessibility in the filter and item selection dialogs +- `dig-now`: properly detect and complete smoothing designations that have been converted into active jobs + +## Misc Improvements +- `buildingplan`: planner panel is minimized by default and now remembers minimized state +- `buildingplan`: can now filter by gems (for gem windows) and yarn (for ropes in wells) +- ``toggle-kbd-cursor``: add hotkey for toggling the keyboard cursor (Alt-K) +- ``version``: add alias to display the DFHack help (including the version number) so something happens when players try to run "version" +- `gui/control-panel`: add preference option for hiding the terminal console on startup +- `gui/control-panel`: add preference option for hiding "armok" tools in command lists +- ``Dwarf Therapist``: add a warning to the Labors screen when Dwarf Therapist is active so players know that changes they make to that screen will have no effect. If you're starting a new embark and nobody seems to be doing anything, check your Labors tab for this warning to see if Dwarf Therapist thinks it is in control (even if it's not running). +- `overlay`: add the DFHack version string to the DF title screen + +## Lua +- ``widgets.RangeSlider``: new mouse-controlled two-headed slider widget +- ``gui.ZScreenModal``: ZScreen subclass for modal dialogs +- ``widgets.CycleHotkeyLabel``: exposed "key_sep" and "option_gap" attributes for improved stylistic control. + +## Removed +- `title-version`: replaced by an `overlay` widget + +# 50.07-r1 + +## New Plugins +- `faststart`: speeds up the "Loading..." screen so the Main Menu appears faster + +## Fixes +-@ `hotkeys`: hotkey hints on menu popup will no longer get their last character cut off by the scrollbar +-@ ``launchdf``: launch Dwarf Fortress via the Steam client so Steam Workshop is functional +- `blueprint`: interpret saplings, shrubs, and twigs as floors instead of walls +- `combine`: fix error processing stockpiles with boundaries that extend outside of the map +-@ `prospector`: display both "raw" Z levels and "cooked" elevations +- `stockpiles`: fix crash when importing settings for gems from other worlds +-@ `stockpiles`: allow numbers in saved stockpile filenames + +## Misc Improvements +-@ `buildingplan`: items in the item selection dialog should now use the same item quality symbols as the base game +-@ `buildingplan`: hide planner overlay while the DF tutorial is active so that it can detect when you have placed the carpenter's workshop and bed and allow you to finish the tutorial +- `buildingplan`: can now filter by cloth and silk materials (for ropes) +-@ `buildingplan`: rearranged elements of ``planneroverlay`` interface +-@ `buildingplan`: rearranged elements of ``itemselection`` interface +-@ Mods: scripts in mods that are only in the steam workshop directory are now accessible. this means that a script-only mod that you never mark as "active" when generating a world will still receive automatic updates and be usable from in-game +-@ Mods: scripts from only the most recent version of an installed mod are added to the script path +-@ Mods: give active mods a chance to reattach their load hooks when a world is reloaded +- `gui/control-panel`: bugfix services are now enabled by default +- Core: hide DFHack terminal console by default when running on Steam Deck + +## Documentation +- `installing`: updated to include Steam installation instructions + +## Lua +- added two new window borders: ``gui.BOLD_FRAME`` for accented elements and ``gui.INTERIOR_MEDIUM_FRAME`` for a signature-less frame that's thicker than the existing ``gui.INTERIOR_FRAME`` + +# 50.07-beta2 + +## New Plugins +- `getplants`: reinstated: designate trees for chopping and shrubs for gathering according to type +- `prospector`: reinstated: get stone, ore, gem, and other tile property counts in fort mode. + +## Fixes +-@ `buildingplan`: filters are now properly applied to planned stairs +-@ `buildingplan`: existing carved up/down stairs are now taken into account when determining which stair shape to construct +- `buildingplan`: upright spike traps are now placed extended rather than retracted +- `buildingplan`: you can no longer designate constructions on tiles with magma or deep water, mirroring the vanilla restrictions +-@ `buildingplan`: fixed material filters getting lost for planning buildings on save/reload +-@ `buildingplan`: respect building size limits (e.g. roads and bridges cannot be more than 31 tiles in any dimension) +- `tailor`: properly discriminate between dyed and undyed cloth +-@ `tailor`: no longer default to using adamantine cloth for producing clothes +- `tailor`: take queued orders into account when calculating available materials +- `tailor`: skip units who can't wear clothes +- `tailor`: identify more available items as available, solving issues with over-production + +## Misc Improvements +- `buildingplan`: filters and global settings are now ignored when manually choosing items for a building, allowing you to make custom choices independently of the filters that would otherwise be used +- `buildingplan`: if `suspendmanager` is running, then planned buildings will be left suspended when their items are all attached. `suspendmanager` will unsuspend them for construction when it is safe to do so. +- `buildingplan`: add option for autoselecting the last manually chosen item (like `automaterial` used to do) +- `confirm`: adds confirmation for removing burrows via the repaint menu +- `stockpiles`: support applying stockpile configurations with fully enabled categories to stockpiles in worlds other than the one where the configuration was exported from +- `stockpiles`: support partial application of a saved config based on dynamic filtering (e.g. disable all tallow in a food stockpile, even tallow from world-specific generated creatures) +- `stockpiles`: additive and subtractive modes when applying a second stockpile configuration on top of a first +- `stockpiles`: write player-exported stockpile configurations to the ``dfhack-config/stockpiles`` folder. If you have any stockpile configs in other directories, please move them to that folder. +- `stockpiles`: now includes a library of useful stockpile configs (see docs for details) +- `automelt`: now allows metal chests to be melted (workaround for DF bug 2493 is no longer needed) +- `orders`: add minimize button to overlay panel so you can get it out of the way to read long statue descriptions when choosing a subject in the details screen +- `orders`: add option to delete exported files from the import dialog +- `enable`: can now interpret aliases defined with the `alias` command +- Mods: scripts in mods are now automatically added to the DFHack script path. DFHack recognizes two directories in a mod's folder: ``scripts_modinstalled/`` and ``scripts_modactive/``. ``scripts_modinstalled/`` folders will always be added the script path, regardless of whether the mod is active in a world. ``scripts_modactive/`` folders will only be added to the script path when the mod is active in the current loaded world. + +## Documentation +- `modding-guide`: guide updated to include information for 3rd party script developers +- the ``untested`` tag has been renamed to ``unavailable`` to better reflect the status of the remaining unavailable tools. most of the simply "untested" tools have now been tested and marked as working. the remaining tools are known to need development work before they are available again. + +## Lua +- ``widgets.Label``: tokens can now specify a ``htile`` property to indicate the tile that should be shown when the Label is hovered over with the mouse +- ``widgets.Label``: click handlers no longer get the label itself as the first param to the click handler +- ``widgets.CycleHotkeyLabel``: options that are bare integers will no longer be interpreted as the pen color in addition to being the label and value +- ``widgets.CycleHotkeyLabel``: option labels and pens can now be functions that return a label or pen + +# 50.07-beta1 + +## Fixes +-@ `buildingplan`: items are now attached correctly to screw pumps and other multi-item buildings +-@ `buildingplan`: buildings with different material filters will no longer get "stuck" if one of the filters currently matches no items +- `showmood` properly count required number of bars and cloth when they aren't the main item for the strange mood + +## Misc Improvements +-@ `buildingplan`: can now filter by clay materials +-@ `buildingplan`: remember choice per building type for whether the player wants to choose specific items +-@ `buildingplan`: you can now attach multiple weapons to spike traps +-@ `buildingplan`: can now filter by whether a slab is engraved +-@ `buildingplan`: add "minimize" button to temporarily get the planner overlay out of the way if you would rather use the vanilla UI for placing the current building +-@ `buildingplan`: add ``buildingplan reset`` command for resetting all filters to defaults +-@ `buildingplan`: rename "Build" button to "Confirm" on the item selection dialog and change the hotkey from "B" to "C" +- `blueprint`: now writes blueprints to the ``dfhack-config/blueprints`` directory +- `blueprint-library-guide`: library blueprints have moved from ``blueprints`` to ``hack/data/blueprints`` +- `blueprint-library-guide`: player-created blueprints should now go in the ``dfhack-config/blueprints`` folder. please move your existing blueprints from ``blueprints`` to ``dfhack-config/blueprints``. you don't need to move the library blueprints -- those can be safely deleted from the old ``blueprints`` directory. +-@ `showmood`: clarify how many bars and/or cloth items are actually needed for the mood + +## Removed +-@ `buildingplan`: "heat safety" setting is temporarily removed while we investigate incorrect item matching + +# 50.07-alpha3 + +## Fixes +-@ ``widgets.HotkeyLabel``: don't trigger on click if the widget is disabled +- ``dfhack.job.isSuitableMaterial``: now properly detects lack of fire and magma safety for vulnerable materials with high melting points +- `dig-now`: fixed multi-layer channel designations only channeling every second layer + +## Misc Improvements +- `dig-now`: added handling of dig designations that have been converted into active jobs +- `buildingplan`: entirely new UI for building placement, item selection, and materials filtering! + +## API +- Gui focus strings will no longer get the "dfhack/" prefix if the string "dfhack/" already exists in the focus string +- ``Military``: New module for military functionality +- ``Military``: new ``makeSquad`` to create a squad +- ``Military``: changed ``getSquadName`` to take a squad identifier +- ``Military``: new ``updateRoomAssignments`` for assigning a squad to a barracks and archery range +- ``Maps::GetBiomeType`` renamed to ``Maps::getBiomeType`` for consistency +- ``Maps::GetBiomeTypeRef`` renamed to ``Maps::getBiomeTypeRef`` for consistency + +## Lua +- ``dfhack.job.attachJobItem()``: allows you to attach specific items to a job +- ``dfhack.screen.paintTile()``: you can now explicitly clear the interface cursor from a map tile by passing ``0`` as the tile value +- ``widgets.Label``: token ``tile`` properties can now be functions that return a value +- ``widgets.CycleHotkeyLabel``: add ``label_below`` attribute for compact 2-line output +-@ ``widgets.FilteredList``: search key matching is now case insensitive by default +-@ ``gui.INTERIOR_FRAME``: a panel frame style for use in highlighting off interior areas of a UI +- ``maps.getBiomeType``: exposed preexisting function to Lua + +## Removed +-@ ``gui.THIN_FRAME``: replaced by ``gui.INTERIOR_FRAME`` +- `automaterial`: all functionality has been merged into `buildingplan` + +# 50.07-alpha2 + +## Fixes +-@ `nestboxes`: fixed bug causing nestboxes themselves to be forbidden, which prevented citizens from using them to lay eggs. Now only eggs are forbidden. +-@ `autobutcher`: implemented work-around for Dwarf Fortress not setting nicknames properly, so that nicknames created in the in-game interface are detected & protect animals from being butchered properly. Note that nicknames for unnamed units are not currently saved by dwarf fortress - use ``enable fix/protect-nicks`` to fix any nicknames created/removed within dwarf fortress so they can be saved/reloaded when you reload the game. +-@ `seedwatch`: fix saving and loading of seed stock targets +- `autodump`: changed behaviour to only change ``dump`` and ``forbid`` flags if an item is successfully dumped. +-@ `autochop`: generate default names for burrows with no assigned names +- ``Buildings::StockpileIterator``: fix check for stockpile items on block boundary. +- `tailor`: block making clothing sized for toads; make replacement clothing orders use the size of the wearer, not the size of the garment +-@ `confirm`: fix fps drop when enabled +-@ `channel-safely`: fix an out of bounds error regarding the REPORT event listener receiving (presumably) stale id's + +## Misc Improvements +- `autobutcher`: logs activity to the console terminal instead of making disruptive in-game announcements +- DFHack tool windows that capture mouse clicks (and therefore prevent you from clicking on the "pause" button) now unconditionally pause the game when they open (but you can still unpause with the keyboard if you want to). Examples of this behavior: `gui/quickfort`, `gui/blueprint`, `gui/liquids` +- `showmood`: now shows the number of items needed for cloth and bars in addition to the technically correct but always confusing "total dimension" (150 per bar or 10,000 per cloth) +-@ Stopped mouse clicks from affecting the map when a click on a DFHack screen dismisses the window +- `confirm`: configuration data is now persisted globally. +- `tailor`: add support for adamantine cloth (off by default); improve logging + +## API +- ``Gui::any_civzone_hotkey``, ``Gui::getAnyCivZone``, ``Gui::getSelectedCivZone``: new functions to operate on the new zone system +- Units module: added new predicates for ``isGeldable()``, ``isMarkedForGelding()``, and ``isPet()`` + +## Lua +- ``dfhack.gui.getSelectedCivZone``: returns the Zone that the user has selected currently +- ``widgets.FilteredList``: Added ``edit_on_change`` optional parameter to allow a custom callback on filter edit change. +- ``widgets.TabBar``: new library widget (migrated from control-panel.lua) + +# 50.07-alpha1 + +## Fixes +- ``Units::isFortControlled``: Account for agitated wildlife +-@ Fix right click sometimes closing both a DFHack window and a vanilla panel +-@ Fixed issue with scrollable lists having some data off-screen if they were scrolled before being made visible +-@ `channel-safely`: fixed bug resulting in marker mode never being set for any designation +-@ `automelt`: fixed bug related to lua stack smashing behavior in returned stockpile configs +-@ `autochop`: fixed bug related to lua stack smashing behavior in returned stockpile configs +-@ `nestboxes`: now cancels any in-progress hauling jobs when it protects a fertile egg +-@ Fix persisted data not being written on manual save +-@ `nestboxes`: now scans for eggs more frequently and cancels any in-progress hauling jobs when it protects a fertile egg + +## Misc Improvements +-@ `automelt`: is now more resistent to vanilla savegame corruption +-@ `hotkeys`: DFHack logo is now hidden on screens where it covers important information when in the default position (e.g. when choosing an embark site) +- `misery`: now persists state with the fort +-@ `autodump`: reinstate ``autodump-destroy-item``, hotkey: Ctrl-K +- `autodump`: new hotkey for ``autodump-destroy-here``: Ctrl-H +-@ `dig`: new hotkeys for vein designation on z-level (Ctrl-V) and vein designation across z-levels (Ctrl-Shift-V) +-@ `clean`: new hotkey for `spotclean`: Ctrl-C +- `autobutcher`: changed defaults from 5 females / 1 male to 4 females / 2 males so a single unfortunate accident doesn't leave players without a mating pair +- `autobutcher`: now immediately loads races available at game start into the watchlist +-@ replaced DFHack logo used for the hover hotspot with a crisper image +-@ `orders`: recipe for silver crossbows removed from ``library/military`` as it is not a vanilla recipe, but is available in ``library/military_include_artifact_materials`` +- `stonesense`: added an ``INVERT_MOUSE_Z`` option to invert the mouse wheel direction + +## Documentation + +## API + +## Lua +- `overlay`: overlay widgets can now specify focus paths for the viewscreens they attach to so they only appear in specific contexts. see `overlay-dev-guide` for details. +- ``widgets.CycleHotkeyLabel``: Added ``key_back`` optional parameter to cycle backwards. +- ``widgets.HotkeyLabel``: Added ``setLabel`` method to allow easily updating the label text without mangling the keyboard shortcut. +- ``widgets.HotkeyLabel``: Added ``setOnActivate`` method to allow easily updating the ``on_activate`` callback. +- ``widgets.FilteredList``: Added ``case_sensitive`` optional parameter to determine if filtering is case sensitive. + +# 50.05-alpha3.1 + +## Fixes +-@ `seedwatch`: fix parameter parsing when setting targets + +# 50.05-alpha3 + +## New Plugins +- `autoslab`: automatically create work orders to engrave slabs for ghostly dwarves + +## Fixes +-@ DF screens can no longer get "stuck" on transitions when DFHack tool windows are visible. Instead, those DF screens are force-paused while DFHack windows are visible so the player can close them first and not corrupt the screen sequence. The "PAUSE FORCED" indicator will appear on these DFHack windows to indicate what is happening. +-@ allow launcher tools to launch themselves without hanging the game +-@ fix issues with clicks "passing through" some DFHack window elements to the screen below +- `getplants`: trees are now designated correctly +- `autoclothing`: fixed a crash that can happen when units are holding invalid items. +-@ `orders`: fix orders in library/basic that create bags +- `orders`: library/military now sticks to vanilla rules and does not add orders for normally-mood-only platinum weapons. A new library orders file ``library/military_include_artifact_materials`` is now offered as an alternate ``library/military`` set of orders that still includes the platinum weapons. +- `autochop`: fixed a crash when processing trees with corrupt data structures (e.g. when a trunk tile fails to fall when the rest of the tree is chopped down) + +## Misc Improvements +-@ DFHack windows can now be "defocused" by clicking somewhere not over the tool window. This has the same effect as pinning previously did, but without the extra clicking. +- `getplants`: ID values will now be accepted regardless of case +-@ Windows now display "PAUSE FORCED" on the lower border if the tool is forcing the game to pause +-@ New borders for DFHack tool windows -- tell us what you think! +-@ `autoclothing`: merged the two separate reports into the same command. +- `automelt`: stockpile configuration can now be set from the commandline +- `channel-safely`: new monitoring for cave-in prevention +-@ `gui/control-panel`: you can now configure whether DFHack tool windows should pause the game by default +- `gui/control-panel`: new global hotkey for quick access: Ctrl-Shift-E +-@ `hotkeys`: clicking on the DFHack logo no longer closes the popup menu +- `nestboxes`: now saves enabled state in your savegame +- `gui/launcher`: sped up initialization time for faster window appearance +- `orders`: orders plugin functionality is now accessible via an `overlay` widget when the manager orders screen is open +- `gui/quickcmd`: now has its own global keybinding for your convenience: Ctrl-Shift-A +- `seedwatch`: now persists enabled state in the savegame, automatically loads useful defaults, and respects reachability when counting available seeds +-@ `quickfort`: planned buildings are now properly attached to any pertinent overlapping zones + +## Documentation +- `compile`: instructions added for cross-compiling DFHack for Windows from a Linux Docker builder +-@ Quickstart guide has been updated with info on new window behavior and how to use the control panel + +## API +- ``Buildings::containsTile()``: no longer takes a ``room`` parameter since that's not how rooms work anymore. If the building has extents, the extents will be checked. otherwise, the result just depends on whether the tile is within the building's bounding box. +- ``Units::getCitizens()``: gets a list of citizens, which otherwise you'd have to iterate over all units the world to discover +- ``Screen::Pen``: now accepts ``top_of_text`` and ``bottom_of_text`` properties to support offset text in graphics mode +- `overlay`: overlay widgets can now specify a default enabled state if they are not already set in the player's overlay config file +- ``Lua::Push``: now supports ``std::unordered_map`` + +## Lua +- `helpdb`: new function: ``helpdb.refresh()`` to force a refresh of the database. Call if you are a developer adding new scripts, loading new plugins, or changing help text during play +- `helpdb`: changed from auto-refreshing every 60 seconds to only refreshing on explicit call to ``helpdb.refresh()``. docs very rarely change during a play session, and the automatic database refreshes were slowing down the startup of `gui/launcher` and anything else that displays help text. +- ``widgets.Label``: ``label.scroll()`` now understands ``home`` and ``end`` keywords for scrolling to the top or bottom +- ``widgets.List``: new callbacks for double click and shift double click +- ``dfhack.units.getCitizens()``: gets a list of citizens +-@ ``gui.ZScreen``: new attribute: ``defocusable`` for controlling whether a window loses keyboard focus when the map is clicked +- ``widgets.Label``: token ``tile`` properties can now be either pens or numeric texture ids +- `tiletypes`: now has a Lua API! ``tiletypes_setTile`` + +## Removed +- `autohauler`: no plans to port to v50, as it just doesn't make sense with the new work detail system + +# 50.05-alpha2 + +## Fixes +-@ `autofarm`: don't duplicate status line entries for crops with no current supply +-@ `orders`: allow the orders library to be listed and imported properly (if you previously copied the orders library into your ``dfhack-config/orders`` directory to work around this bug, you can remove those files now) +- `tailor`: now respects the setting of the "used dyed clothing" standing order toggle + +# 50.05-alpha1 + +## Fixes +- ``widgets.WrappedLabel``: no longer resets scroll position when window is moved or resized + +## Misc Improvements +- Scrollable widgets now react to mouse wheel events when the mouse is over the widget +- the ``dfhack-config/scripts/`` folder is now searched for scripts by default +- `hotkeys`: overlay hotspot widget now shows the DFHack logo in graphics mode and "DFHack" in text mode +- `script-paths`: removed "raw" directories from default script paths. now the default locations to search for scripts are ``dfhack-config/scripts``, ``save/*/scripts``, and ``hack/scripts`` +- ``init.d``: directories have moved from the ``raw`` subfolder (which no longer exists) to the root of the main DF folder or a savegame folder + +## Documentation +- `overlay-dev-guide`: added troubleshooting tips and common development workflows +- added DFHack architecture diagrams to the dev intro +- added DFHack Quickstart guide + +## API +- ``Gui::getDwarfmodeDims``: now only returns map viewport dimensions; menu dimensions are obsolete +- ``Gui::getDFViewscreen``: returns the topmost underlying DF viewscreen +- ``Screen::Pen``: now accepts ``keep_lower`` and ``write_to_lower`` properties to support foreground and background textures in graphics mode + +## Lua +- Removed ``os.execute()`` and ``io.popen()`` built-in functions +- ``gui.View``: ``visible`` and ``active`` can now be functions that return a boolean +- ``widgets.Panel``: new attributes to control window dragging and resizing with mouse or keyboard +- ``widgets.Window``: Panel subclass with attributes preset for top-level windows +- ``widgets.CycleHotkeyLabel``: now supports rendering option labels in the color of your choice +- ``widgets.CycleHotkeyLabel``: new functions ``setOption()`` and ``getOptionPen()`` +- ``widgets.ToggleHotkeyLabel``: now renders the ``On`` option in green text +- ``widgets.Label``: tiles can now have an associated width +- `overlay`: ``OverlayWidget`` now inherits from ``Panel`` instead of ``Widget`` to get all the frame and mouse integration goodies +- ``dfhack.gui.getDFViewscreen()``: returns the topmost underlying DF viewscreen +- ``gui.ZScreen``: Screen subclass that implements window raising, multi-viewscreen input handling, and viewscreen event pass-through so the underlying map can be interacted with and dragged around while DFHack screens are visible +- ``gui.View``: new function ``view:getMouseFramePos()`` for detecting whether the mouse is within (or over) the exterior frame of a view +- ``gui.CLEAR_PEN``: now clears the background and foreground and writes to the background (before it would always write to the foreground) +- ``gui.KEEP_LOWER_PEN``: a general use pen that writes associated tiles to the foreground while keeping the existing background + +## Removed +- ``fix-job-postings`` from the `workflow` plugin is now obsolete since affected savegames can no longer be loaded +- Ruby is no longer a supported DFHack scripting language diff --git a/docs/dev/Binpatches.rst b/docs/dev/Binpatches.rst new file mode 100644 index 0000000000..d59b1f8482 --- /dev/null +++ b/docs/dev/Binpatches.rst @@ -0,0 +1,187 @@ +.. _binpatches: + +###################### +Patching the DF binary +###################### + +Writing scripts and plugins for DFHack is not the only way to modify Dwarf +Fortress. Before DFHack, it was common for tools to manually patch the +binary to change behaviour, and DFHack still contains tools to do this via +the `binpatch` command. + +.. warning:: + + We recommend using a script or plugin instead of a raw patch if + at all possible - that way your work will work for many versions + across multiple operating systems. + +.. contents:: Contents + :local: + + +Getting a patch +=============== +There are no binary patches available for Dwarf Fortress versions after 0.34.11. + +This system is kept for the chance that someone will find it useful, so some +hints on how to write your own follow. This will require disassembly and +decent skill in `memory research `. + +* The patches are expected to be encoded in text format used by IDA. + +* See `the patches folder in commit b0e1b51 `_ for examples. + +* :issue:`546` is about the future of the binpatches, and may be useful reading. + +If you want to write a patch, the armory patches discussed here and documented +below would probably be the best place to start. + + +Using a patch +============= +There are two methods to apply a patch. + +Patching at runtime +------------------- +The `binpatch` script checks, applies or removes binary patches +directly in memory at runtime:: + + binpatch [check|apply|remove] + +If the name of the patch has no extension or directory separators, the +script uses :file:`hack/patches//.dif`, thus auto-selecting +the version appropriate for the currently loaded executable. The ``df-version`` +is the version string in the loaded symbol table. For example, if you want to +make a patch for all distributed verisons of DF 51.05, you'd provide a ``dif`` +file in each of the following directories: + +- :file:`hack/patches/v0.51.05 linux64 CLASSIC/mypatch.dif` +- :file:`hack/patches/v0.51.05 linux64 ITCH/mypatch.dif` +- :file:`hack/patches/v0.51.05 linux64 STEAM/mypatch.dif` +- :file:`hack/patches/v0.51.05 win64 CLASSIC/mypatch.dif` +- :file:`hack/patches/v0.51.05 win64 ITCH/mypatch.dif` +- :file:`hack/patches/v0.51.05 win64 STEAM/mypatch.dif` + +This is the preferred method; it's easier to debug, does not cause persistent +problems, and leaves file checksums alone. As with many other commands, users +can simply add it to `dfhack.init` to reapply the patch every time DF is run. + + +Patching on disk +---------------- + +.. warning:: + + This method of patching is deprecated, and may be removed without notice. + You should use the runtime patching option above. + +DFHack includes a small stand-alone utility for applying and removing +binary patches from the game executable. Use it from the regular operating +system console: + +``binpatch check "Dwarf Fortress.exe" patch.dif`` + Checks and prints if the patch is currently applied. + +``binpatch apply "Dwarf Fortress.exe" patch.dif`` + Applies the patch, unless it is already applied or in conflict. + +``binpatch remove "Dwarf Fortress.exe" patch.dif`` + Removes the patch, unless it is already removed. + +If you use a permanent patch under OSX or Linux, you must update +``symbols.xml`` with the new checksum of the executable. Find the relevant +section, and add a new line: + +.. code-block:: xml + + + +In order to find the correct value of the hash, look into stderr.log; +DFHack prints an error there if it does not recognize the hash. + +.. _binpatches/needs-patch: + +Tools reliant on binpatches +=========================== +Some DFHack tools require the game to be patched to work. As no patches +are currently available, the full description of each is included here. + +fix-armory +---------- +Enables a fix for storage of squad equipment in barracks. + +Specifically, it prevents your haulers from moving squad equipment +to stockpiles, and instead queues jobs to store it on weapon racks, +armor stands, and in containers. + +.. note:: + + In order to actually be used, weapon racks have to be patched and + manually assigned to a squad. See `gui/assign-rack`. + +Note that the buildings in the armory are used as follows: + +* Weapon racks (when patched) are used to store any assigned weapons. + Each rack belongs to a specific squad, and can store up to 5 weapons. + +* Armor stands belong to specific squad members and are used for + armor and shields. + +* Cabinets are used to store assigned clothing for a specific squad member. + They are **never** used to store owned clothing. + +* Chests (boxes, etc) are used for a flask, backpack or quiver assigned + to the squad member. Due to a probable bug, food is dropped out of the + backpack when it is stored. + +.. warning:: + + Although armor stands, cabinets and chests properly belong only to one + squad member, the owner of the building used to create the barracks will + randomly use any containers inside the room. Thus, it is recommended to + always create the armory from a weapon rack. + +Contrary to the common misconception, all these uses are controlled by the +*Individual Equipment* usage flag. The *Squad Equipment* flag is actually +intended for ammo, but the game does even less in that area than for armor +and weapons. This plugin implements the following rules almost from scratch: + +* Combat ammo is stored in chests inside rooms with Squad Equipment enabled. + +* If a chest is assigned to a squad member due to Individual Equipment also + being set, it is only used for that squad's ammo; otherwise, any squads + with Squad Equipment on the room will use all of the chests at random. + +* Training ammo is stored in chests inside archery ranges designated from + archery targets, and controlled by the same Train flag as archery training + itself. This is inspired by some defunct code for weapon racks. + +There are some minor traces in the game code to suggest that the first of +these rules is intended by Toady; the rest are invented by this plugin. + + +gui/assign-rack +--------------- +Bind to a key (the example config uses :kbd:`P`), and activate when viewing a weapon +rack in the :kbd:`q` mode. + +.. image:: /docs/images/assign-rack.png + +This script is part of a group of related fixes to make the armory storage +work again. The existing issues are: + +* Weapon racks have to each be assigned to a specific squad, like with + beds/boxes/armor stands and individual squad members, but nothing in + the game does this. This issue is what this script addresses. + +* Even if assigned by the script, **the game will unassign the racks again + without a binary patch**. This patch is called ``weaponrack-unassign``, + and has not been updated since 0.34.11. See :bug:`1445` for more info. + +* Haulers still take equipment stored in the armory away to the stockpiles, + unless `fix-armory` is used. + +The script interface simply lets you designate one of the squads that +are assigned to the barracks/armory containing the selected stand as +the intended user. In order to aid in the choice, it shows the number +of currently assigned racks for every valid squad. diff --git a/docs/dev/Contributing.rst b/docs/dev/Contributing.rst new file mode 100644 index 0000000000..3ab620c1f9 --- /dev/null +++ b/docs/dev/Contributing.rst @@ -0,0 +1,134 @@ +.. _contributing: + +########################### +How to contribute to DFHack +########################### + +.. contents:: Contents + :local: + +.. _contributing-code: + +Contributing Code +================= + +DFHack's source code is hosted on GitHub. To obtain the code, you do not need an +account - see the `compilation instructions ` for +details. However, to contribute code to DFHack, you will need a GitHub account +to submit pull requests. DFHack consists of several repositories, so you will +need to fork the repository (or repositories) containing the code you wish to +modify. GitHub has several documentation pages on these topics, including: + +* `An overview of forks + `__ +* `Proposing changes with pull requests + `__ + (note: see `contributing-pr-guidelines` for some DFHack-specific information) + +In general, if you are not sure where or how to make a change, or would like +advice before attempting to make a change, please see `support` for ways to +contact maintainers. If you are interested in addressing an issue reported on the +:issue:`issue tracker <>`, you can start a discussion there if you prefer. + +The sections below cover some guidelines that contributions should follow: + +.. contents:: + :local: + +General contribution guidelines +------------------------------- +* If convenient, compile on multiple platforms when changing anything that + compiles. Our CI should catch anything that fails to build, but checking in + advance can sometimes let you know of any issues sooner. +* Update documentation when applicable - see `docs-standards` for details. +* Update ``docs/changelog.txt`` and ``docs/about/Authors.rst`` when applicable. See + `build-changelog` for more information on the changelog format. +* Submit ideas and bug reports as :issue:`issues on GitHub <>`. + Posts in the forum thread or on Discord can easily get missed or forgotten. +* Work on :issue:`reported problems ` + will take priority over ideas or suggestions. + +Code format +----------- +* Four space indents for C++. Never use tabs for indentation in any language. +* LF (Unix style) line terminators +* No trailing whitespace +* UTF-8 encoding +* For C++: + + * Opening and closing braces on their own lines or opening brace at the end of the previous line + * Braces placed at original indent level if on their own lines + * ``#include`` directives should be sorted: C++ libraries first, then DFHack modules, then ``df/`` headers, + then local includes. Within each category they should be sorted alphabetically. + +General C++ code guidelines +--------------------------- +* This project is currently built at the C++20 feature level, and C++20 features should be used when appropriate. C++23 features will be allowed once all of our build platforms support them. +* NEVER use ``using namespace`` in a header file. In source files, do not use ``using namespace std``; instead, import each STL identifier you need specifically (e.g. ``using std::string;``). +* Avoid platform specific code as much as possible. +* Avoid including ``Windows.h``; if you must, ensure that ``NOMINMAX`` and ``WIN32_LEAN_AND_MEAN`` are defined before including it. +* Do not include C headers (e.g. ````); use the C++ versions (e.g. ````) instead. +* Do not use ``std::string`` (or ``char *``) for path names; always use ``std::filesystem::path``. This avoids issues with encoding, especially on the Windows platform, which is roughly 80% of our user base. +* Do not use ``printf`` or similar functions for formatting strings; use C++ streams or ``fmt::format`` instead. We use the `fmt library `__ for formatting strings; this dependency is automatically fetched by our build system. +* Avoid out parameters; prefer returning a struct, pair, or tuple, or using ``std::optional`` instead. +* Prefer range for loops to traditional for loops when iterating over a container. +* Avoid macros when possible; prefer ``constexpr`` variables for constants and functions or templates for code generation. + +.. _contributing-pr-guidelines: + +Pull request guidelines +----------------------- + +* Pull requests should be based on (and submitted to) the default branch of the + relevant repo, which is the branch you see when you access the repo on GitHub + or clone the repo without specifying a branch. As of 0.47.04-r1, this is + ``develop`` for the main DFHack repo and ``master`` for other repos. +* We often leave feedback as comments on pull requests, so be sure that you have + `notifications turned on `__ or + that you check back for feedback periodically. +* Use a new branch for each feature or bugfix so that your changes can be merged + independently (i.e. not the ``master`` or ``develop`` branch of your fork). + + * An exception: for a collection of small miscellaneous changes (e.g. + structures research), one branch instead of many small branches is fine. It + is still preferred that this branch be dedicated to this purpose, i.e. not + ``master`` or ``develop``. Your pull request may be merged at any point + unless you indicate that it isn't ready (see below), but you can continue to + push to the same branch and open new pull requests as needed. + +* Our continuous integration (CI) will perform certain automatic checks, + ensuring that your code conforms to the code format described above. It is + recommended to install `pre-commit `__ (e.g. using + your distribution's package manager, if on Linux, or using ``pip``) and enable + it by running ``pre-commit install`` from the top-level of any repository from + which you plan to create pull requests. This will perform those checks when + you create the commit locally, allowing you to fix any style issues before + creating the actual pull request. + +* Try to keep pull requests relatively small so that they are easier to review + and merge. + + * If you expect to make a large number of related additions or changes (e.g. + adding a large new plugin), multiple PRs are preferred, as they allow more + frequent (and easier) feedback. If development of this feature is expected + to take a while, we may create a dedicated branch to merge your pull + requests into instead of the repo's default branch. + +* If you plan to make additional changes to your pull request in the near + future, or if it isn't quite ready to be merged, mark it as a + `draft pull request `_ + or add "WIP" to the title. Otherwise, your pull request may be reviewed and/or + merged prematurely. + +Other ways to help +================== +DFHack is a software project, but there's a lot more to it than programming. +If you're not comfortable programming, you can help by: + +* reporting bugs and incomplete documentation +* improving the documentation (C++ api is rife) +* finding third-party scripts to add +* writing tutorials for newbies + +All those things are crucial, and often under-represented. So if that's +your thing, go get started! diff --git a/docs/dev/Dev-intro.rst b/docs/dev/Dev-intro.rst new file mode 100644 index 0000000000..92967cf15e --- /dev/null +++ b/docs/dev/Dev-intro.rst @@ -0,0 +1,124 @@ +=========================== +DFHack development overview +=========================== + +This page provides an overview of DFHack components. If you are looking to +develop a tool for DFHack, developing a script or plugin is likely the most +straightforward choice. + +Other pages that may be relevant include: + +- `building-dfhack-index` +- `contributing` +- `documentation` +- `license` + +.. contents:: Contents + :local: + +.. _architectural-diagrams: + +Architecture diagrams +--------------------- + +These two diagrams give a very high level overview of where DFHack fits into +the DF call structure and how the pieces of DFHack itself fit together: + +.. image:: https://lh3.googleusercontent.com/d/1-2yeNMC7WHgMfZ9iQsDQ0dEbLukd_xyU + :alt: DFHack logic injection diagram + :target: https://drive.google.com/file/d/1-2yeNMC7WHgMfZ9iQsDQ0dEbLukd_xyU + :align: center + +When DF loads, it looks for a "dfhooks" library file (named appropriately per +platform, e.g. ``libdfhooks.so`` on Linux). DFHack provides this library file, +and DF calls the API functions at specific points in its initialization code +and main event loop. + +In addition, DFHack can "interpose" the virtual methods of DF classes. In +particular, it intercepts calls to the interface functions of each DF +viewscreen class to provide `overlay` functionality. + +The dfhooks API is defined in DF's open source component ``g_src``: +https://github.com/Putnam3145/Dwarf-Fortress--libgraphics--/blob/master/g_src/dfhooks.h + +.. image:: https://lh3.googleusercontent.com/d/1--JoEQbzKpVUOkRKDD9HxvuCqtom780F + :alt: DFHack tool call graph + :target: https://drive.google.com/file/d/1--JoEQbzKpVUOkRKDD9HxvuCqtom780F + :align: center + +DF memory layout is encoded in the xml files of the +`df-structures `__ repository. These +XML files are converted into C++ header files during the build process. + +The functionality of the DFHack core library is grouped by `Modules`_ that +access DF memory according to the defined structures. + +The Lua API layer makes DFHack core facilities available to Lua scripts. Both +the C++ and Lua APIs have a library of convenience functions, though only the +Lua API is `well-documented `. Notably, the entire +`UI widget library` is Lua-only, though C++ plugins can easily +access it via the plugin-Lua interop layer. + +Plugins +------- + +DFHack plugins are written in C++ and located in the ``plugins`` folder. +Currently, documentation on how to write plugins is somewhat sparse. There are +templates that you can use to get started in the :source:`plugins/examples` +folder, and the source code of existing plugins is also helpful. + +If you want to compile a plugin that you have just added, you will need to add a +call to ``DFHACK_PLUGIN`` in :source:`plugins/CMakeLists.txt`. + +Plugins have the ability to make one or more commands available to users of the +DFHack console. Examples include `3dveins` (which implements the ``3dveins`` +command) and `reveal` (which implements ``reveal``, ``unreveal``, and several +other commands). + +Plugins can also register handlers to run on every tick, and can interface with +the built-in `enable` and `disable` commands. For the full plugin API, see the +example :source:`skeleton ` plugin. + +Installed plugins live in the ``hack/plugins`` folder of a DFHack installation, +and the `load` family of commands can be used to load a recompiled plugin +without restarting DF. + +Run `plug` at the DFHack prompt for a list of all plugins included in DFHack. + +Scripts +------- + +DFHack scripts are written in Lua, with a `well-documented library `. +Referring to existing scripts as well as the API documentation is very helpful +when developing new scripts. + +Scripts included in DFHack live in a separate +:source-scripts:`scripts repository <>`. This can be found in the ``scripts`` +submodule if you have `cloned DFHack `, or the +``hack/scripts`` folder of an installed copy of DFHack. + +Core +---- + +The `DFHack core ` has a variety of low-level functions. It is +responsible for implementing the dfhooks API that DF calls, it provides a +console, and it provides an interface for plugins and scripts to interact with +DF. + +Modules +------- + +A lot of shared code to interact with DF in more complicated ways is contained +in **modules**. For example, the Units module contains functions for checking +various traits of units, changing nicknames properly, and more. Generally, code +that is useful to multiple plugins and scripts should go in the appropriate +module, if there is one. + +Most modules are also `exposed to Lua `, although some +functions (and some entire modules) are currently only available in C++. + +Remote access interface +----------------------- + +DFHack provides a remote access interface that external tools can connect to and +use to interact with DF. See `remote` for more information. diff --git a/docs/dev/Documentation.rst b/docs/dev/Documentation.rst new file mode 100644 index 0000000000..0ba61c404d --- /dev/null +++ b/docs/dev/Documentation.rst @@ -0,0 +1,607 @@ +.. _documentation: + +########################### +DFHack documentation system +########################### + + +DFHack documentation, like the file you are reading now, is created as a set of +``.rst`` files in `reStructuredText (reST) `_ +format. This is a documentation format common in the Python community. It is very +similar in concept -- and in syntax -- to Markdown, as found on GitHub and many other +places. However it is more advanced than Markdown, with more features available when +compiled to HTML, such as automatic tables of contents, cross-linking, special +external links (forum, wiki, etc) and more. The documentation is compiled by a +Python tool named `Sphinx `_. + +The DFHack build process will compile and install the documentation so it can be +displayed in-game by the `help` and `ls` commands (and any other command or GUI that +displays help text), but documentation compilation is disabled by default due to the +additional Python and Sphinx requirements. If you already have a version of the docs +installed (say from a downloaded release binary), then you only need to build the docs +if you're changing them and want to see the changes reflected in your game. + +You can also build the docs if you just want a local HTML- or text-rendered copy, though +you can always read the `online version `_ too. +The active development version of the documentation is tagged with ``latest`` and +is available `here `_ + +Note that even if you do want a local copy, it is certainly not necessary to +compile the documentation in order to read it. Like Markdown, reST documents are +designed to be just as readable in a plain-text editor as they are in HTML format. +The main thing you lose in plain text format is hyperlinking. + +.. contents:: Contents + :local: + +Concepts and general guidance +============================= + +The source ``.rst`` files are compiled to HTML for viewing in a browser and to text +format for viewing in-game. For in-game help, the help text is read from its installed +location in ``hack/docs`` under the DF directory. + +When writing documentation, remember that everything should be documented! If it's not +clear *where* a particular thing should be documented, ask on Discord or in the DFHack +thread on Bay12 -- you'll not only be getting help, you'll also be providing valuable +feedback that makes it easier for future contributors to find documentation on how to +write the documentation! + +Try to keep lines within 80-100 characters so it's readable in plain text in the +terminal - Sphinx (our documentation system) will make sure paragraphs flow. + +Short descriptions +------------------ + +Each command that a user can run -- as well as every plugin -- needs to have a +short (~54 character) descriptive string associated with it. This description text is: + +- used in-game by the `ls` command and DFHack UI screens that list commands +- used in the generated index entries in the HTML docs + +Tags +---- + +To make it easier for players to find related commands, all plugins and commands are marked +with relevant tags. These are used to compile indices and generate cross-links between the +commands, both in the HTML documents and in-game. See the list of available `tag-list` and +think about which categories your new tool belongs in. + +.. _docs-links: + +Links +----- + +If it would be helpful to mention another DFHack command, don't just type the +name - add a hyperlink! Specify the link target in backticks, and it will be +replaced with the corresponding title and linked: e.g. ```autolabor``` +=> `autolabor`. Scripts and plugins have link targets that match their names +created for you automatically. + +If you want to link to a heading in your own page, you can specify it like this:: + + `Heading text exactly as written`_ + +Note that the DFHack documentation is configured so that single backticks (with +no prefix or suffix) produce links to internal link targets, such as the +``autolabor`` target shown above. This is different from the reStructuredText +default behavior of rendering such text in italics (as a reference to a title). +For alternative link behaviors, see: + +- `The reStructuredText documentation on roles `__ +- `The reStructuredText documentation on external links `__ +- `The Sphinx documentation on roles `__ + - ``:doc:`` is useful for linking to another document outside of DFHack. + +.. _docs-standards: + +Documentation standards +======================= + +.. highlight:: rst + +Whether you're adding new code or just fixing old documentation (and there's plenty), +there are a few important standards for completeness and consistent style. Treat +this section as a guide rather than iron law, match the surrounding text, and you'll +be fine. + +Where do I add the help text? +----------------------------- + +For scripts and plugins that are distributed as part of DFHack, documentation files +should be added to the :source-scripts:`scripts/docs ` and :source:`docs/plugins` directories, +respectively, in a file named after the script or plugin. For example, a script named +``gui/foobar.lua`` (which provides the ``gui/foobar`` command) should be documented +in a file named ``docs/gui/foobar.rst`` in the scripts repo. Similarly, a plugin named +``foobaz`` should be documented in a file named ``docs/plugins/foobaz.rst`` in the dfhack repo. +For plugins, all commands provided by that plugin should be documented in that same file. + +Short descriptions (the ~54 character short help) for scripts and plugins are taken from +the ``summary`` attribute of the ``dfhack-tool`` directive that each tool help document must +have (see the `Header format`_ section below). Please make this brief but descriptive! + +Short descriptions for commands provided by plugins are taken from the ``description`` +parameter passed to the ``PluginCommand`` constructor used when the command is registered +in the plugin source file. + +Header format +------------- + +The docs **must** begin with a heading which exactly matches the script or plugin name, underlined +with ``=====`` to the same length. This must be followed by a ``.. dfhack-tool:`` directive with +at least the following parameters: + +* ``:summary:`` - a short, single-sentence description of the tool +* ``:tags:`` - a space-separated list of `tags ` that apply to the tool + +By default, ``dfhack-tool`` generates both a description of a tool and a command +with the same name. For tools (specifically plugins) that do not provide exactly +1 command with the same name as the tool, pass the ``:no-command:`` parameter (with +no content after it) to prevent the command block from being generated. + +For tools that provide multiple commands, or a command by the same name but with +significantly different functionality (e.g. a plugin that can be both enabled +and invoked as a command for different results), use the ``.. dfhack-command:`` +directive for each command. This takes only a ``:summary:`` argument, with the +same meaning as above. + +For example, documentation for the ``build-now`` script might look like:: + + build-now + ========= + + .. dfhack-tool:: + :summary: Instantly completes unsuspended building construction jobs. + :tags: fort armok buildings + + By default, all buildings on the map are completed, but the area of effect is configurable. + +And documentation for the ``autodump`` plugin might look like:: + + autodump + ======== + + .. dfhack-tool:: + :summary: Automatically set items in a stockpile to be dumped. + :tags: fort armok fps productivity items stockpiles + :no-command: + + .. dfhack-command:: autodump + :summary: Teleports items marked for dumping to the cursor position. + + .. dfhack-command:: autodump-destroy-here + :summary: Destroy items marked for dumping under the cursor. + + .. dfhack-command:: autodump-destroy-item + :summary: Destroys the selected item. + + When `enabled `, this plugin adds an option to the :kbd:`q` menu for + stockpiles. + + When invoked as a command, it can instantly move all unforbidden items marked + for dumping to the tile under the cursor. + +Usage help +---------- + +The first section after the header and introductory text should be the usage section. You can +choose between two formats, based on whatever is cleaner or clearer for your syntax. The first +option is to show usage formats together, with an explanation following the block:: + + Usage + ----- + + :: + + build-now [] + build-now here [] + build-now [ []] [] + + Where the optional ```` pair can be used to specify the + coordinate bounds within which ``build-now`` will operate. If + they are not specified, ``build-now`` will scan the entire map. + If only one ```` is specified, only the building at that + coordinate is built. + + The ```` parameters can either be an ``,,`` triple + (e.g. ``35,12,150``) or the string ``here``, which means the + position of the active game cursor. + +The second option is to arrange the usage options in a list, with the full command +and arguments in monospaced font. Then indent the next line and describe the effect:: + + Usage + ----- + + ``build-now []`` + Scan the entire map and build all unsuspended constructions + and buildings. + ``build-now here []`` + Build the unsuspended construction or building under the + cursor. + ``build-now [ []] []`` + Build all unsuspended constructions within the specified + coordinate box. + + The ```` parameters are specified as... + +Note that in both options, the entire commandline syntax is written, including the command itself. +Literal text is written as-is (e.g. the word ``here`` in the above example), and text that +describes the kind of parameter that is being passed (e.g. ``pos`` or ``options``) is enclosed in +angle brackets (``<`` and ``>``). Optional elements are enclosed in square brackets (``[`` and ``]``). +If the command takes an arbitrary number of elements, use ``...``, for example:: + + prioritize [] [ ...] + quickfort [,...] [,...] [] + +Examples +-------- + +If the only way to run the command is to type the command itself, then this section is not necessary. +Otherwise, please consider adding a section that shows some real, practical usage examples. For +many users, this will be the **only** section they will read. It is so important that it is a good +idea to include the ``Examples`` section **before** you describe any extended options your command +might take. Write examples for what you expect the popular use cases will be. Also be sure to write +examples showing specific, practical values being used for any parameter that takes a value or has +tricky formatting. + +Examples should go in their own subheading. The examples themselves should be organized as in +option 2 for Usage above. Here is an example ``Examples`` section:: + + Examples + -------- + + ``build-now`` + Completes all unsuspended construction jobs on the map. + ``build-now 37,20,154 here`` + Builds the unsuspended, unconstructed buildings in the box + bounded by the coordinate x=37,y=20,z=154 and the cursor. + +Options +------- + +The options header should follow the examples, with each option in the same format as the +examples:: + + Options + ------- + + ``-h``, ``--help`` + Show help text. + ``-l``, ``--quality `` + Set the quality of the architecture for built architected + buildings. + ``-q``, ``--quiet`` + Suppress informational output (error messages are still + printed). + +Note that for parameters that have both short and long forms, any values that those options +take only need to be specified once (e.g. ````). + +External scripts and plugins +============================ + +Scripts and plugins distributed separately from DFHack's release packages don't have the +opportunity to add their documentation to the rendered HTML or text output. However, these +scripts and plugins can use a different mechanism to at least make their help text available +in-game. + +Note that since help text for external scripts and plugins is not rendered by Sphinx, +it should be written in plain text. Any reStructuredText markup will not be processed and, +if present, will be shown verbatim to the player (which is probably not what you want). + +For external scripts, the short description comes from a comment on the first line +(the comment marker and extra whitespace is stripped): + +.. code-block:: lua + + -- A short description of my cool script. + +The main help text for an external script needs to appear between two markers -- ``[====[`` +and ``]====]``. The documentation standards above still apply to external tools, but there is +no need to include backticks for links or monospaced fonts. Here is an example for an +entire script header:: + + -- Inventory management for adventurers. + -- [====[ + gui/adv-inventory + ================= + + Tags: adventure | items + + Allows you to quickly move items between containers. This + includes yourself and any followers you have. + + Usage + ----- + + gui/adv-inventory [] + + Examples + -------- + + gui/adv-inventory + Opens the GUI with nothing preselected + + gui/adv-inventory take-all + Opens the GUI with all container items already selected and + ready to move into the adventurer's inventory. + + Options + ------- + + take-all + Starts the GUI with container items pre-selected + + give-all + Starts the GUI with your own items pre-selected + ]====] + +For external plugins, help text for provided commands can be passed as the ``usage`` +parameter when registering the commands with the ``PluginCommand`` constructor. There +is currently no way for associating help text with the plugin itself, so any +information about what the plugin does when enabled should be combined into the command +help. + +Required dependencies +===================== + +.. highlight:: shell + +In order to build the documentation, you must have Python with Sphinx +version |sphinx_min_version| or later and Python 3. + +When installing Sphinx from OS package managers, be aware that there is +another program called "Sphinx", completely unrelated to documentation management. +Be sure you are installing the right Sphinx; it may be called ``python-sphinx``, +for example. To avoid doubt, ``pip`` can be used instead as detailed below. + +Once you have installed Sphinx, ``sphinx-build --version`` should report the +version of Sphinx that you have installed. If this works, CMake should also be +able to find Sphinx. + +For more detailed platform-specific instructions, see the sections below: + +.. contents:: + :local: + :backlinks: none + +Linux +----- +Most Linux distributions will include Python by default. If not, start by +installing Python 3. On Debian-based distros:: + + sudo apt install python3 + +Check your package manager to see if Sphinx |sphinx_min_version| or later is +available. On Debian-based distros, this package is named ``python3-sphinx``. +If this package is new enough, you can install it directly. If not, or if you +want to use a newer Sphinx version (which may result in faster builds), you +can install Sphinx through the ``pip`` package manager instead. On Debian-based +distros, you can install pip with:: + + sudo apt install python3-pip + +Once pip is available, you can then install Sphinx with:: + + pip3 install sphinx + +If you run this as an unprivileged user, it may install a local copy of Sphinx +for your user only. The ``sphinx-build`` executable will typically end up in +``~/.local/bin/`` in this case. Alternatively, you can install Sphinx +system-wide by running pip with ``sudo``. In any case, you will need the folder +containing ``sphinx-build`` to be in your ``$PATH``. + +macOS +----- +macOS has Python 2.7 installed by default, but it does not have the pip package manager. + +You can install Homebrew's Python 3, which includes pip, and then install the +latest Sphinx using pip:: + + brew install python3 + pip3 install sphinx + +Windows +------- +Python for Windows can be downloaded `from python.org `_. +The latest version of Python 3 includes pip already. + +You can also install Python and pip through the Chocolatey package manager. +After installing Chocolatey as outlined in the `Windows compilation instructions `, +run the following command from an elevated (admin) command prompt (e.g. ``cmd.exe``):: + + choco install python pip -y + +Once you have pip available, you can install Sphinx with the following command:: + + pip install sphinx + +Note that this may require opening a new (admin) command prompt if you just +installed pip from the same command prompt. + +.. _docs-build: + +Building the documentation +========================== + +Once the required dependencies are installed, there are multiple ways to run +Sphinx to build the docs: + +Using CMake +----------- + +See our page on `build options `. + +Using the documentation build script +------------------------------------ + +You can also build the documentation without running CMake - this is faster if +you only want to rebuild the documentation regardless of any code changes. + +The recommended approach is the ``docs/build.py`` script. This is the same +script that CMake uses internally, which wraps Sphinx with a few additional +options to handle common cases and can build multiple documentation formats with +a single invocation. + +Examples: + +* ``docs/build.py`` + Build just the HTML docs + +* ``docs/build.py html text`` + Build both the HTML and text docs + +* ``docs/build.py --clean`` + Build HTML and force a clean build (all source files are re-read) + +* ``docs/build.py --help`` + Display a full list of available options + +The resulting documentation will be stored in ``docs/html`` and/or ``docs/text`` +(or generally, a subfolder of ``docs/`` named after the requested output format(s)). + +Building a PDF version +---------------------- + +ReadTheDocs automatically builds a PDF version of the documentation (available +under the "Downloads" section when clicking on the release selector). If you +want to build a PDF version locally, you will need the ``pdflatex`` command, which is part +of a TeX distribution. The following command will then build a PDF, located in +``docs/pdf/latex/DFHack.pdf``, with default options:: + + docs/build.py pdf + +Running Sphinx manually +----------------------- + +If ``docs/build.py`` does not support what you need, you can also run Sphinx +manually. This is primarily useful for low-level debugging. + +For a good starting point, add the ``--debug`` argument to your call to +``docs/build.py``. This will cause the script to print out the Sphinx command(s) +that it is running. + +Some examples: + +* ``sphinx-build . docs/html`` + Build the HTML docs (equivalent to ``docs/build.py``) + +* ``sphinx-build -b text . docs/text`` + Build the plain text docs (equivalent to ``docs/build.py text``) + +* ``sphinx-build -M latexpdf . docs/pdf`` + Build the PDF docs + +Sphinx has many options to enable clean builds, parallel builds, logging, and +more - run ``sphinx-build --help`` for details. If you specify a different +output path, be warned that Sphinx may overwrite existing files in the output +folder. Also be aware that when running ``sphinx-build`` directly, the +``docs/html`` folder may be polluted with intermediate build files that normally +get written in the cmake ``build`` directory. + +Troubleshooting +=============== + +Sphinx errors are typically printed by Sphinx, so ensure that you are not silencing Sphinx output. + +When built with ``docs/build.py`` or CMake, errors are also logged to +``build/docs//sphinx-warnings.txt`` (for instance, if you are building +the HTML docs, ``build/docs/html/sphinx-warnings.txt``). + + +"undefined label" +----------------- + +Typical causes: + +* You have used single backticks for an inline code snippet, where double backticks should be used instead (see `docs-links`):: + + `this is an invalid inline code snippet (actually a link)` + ``this is a valid inline code snippet`` + +* You are attempting to link to a section/label, but either it does not have a label defined or you have spelled it incorrectly:: + + .. my-label: + + This is where the link should go to. + + ... + + This is `a valid link to the earlier label `. So is `my-label`. + +"toctree contains reference to document that doesn't have a title" +------------------------------------------------------------------ + +Due to the nature of our autogenerated documentation, this can sometimes occur +when switching between branches that have different autogenerated files, and can +result in autogenerated documentation (e.g. for individual tools) being missing +from the table of contents, or links failing to generate. + +The quickest resolution is a clean docs build:: + + docs/build.py --clean + +.. _build-changelog: + +Building the changelogs +======================= +If you have Python installed, you can build just the changelogs without building +the rest of the documentation by running the ``docs/gen_changelog.py`` script. +This script provides additional options, including one to build individual +changelogs for all DFHack versions - run ``python docs/gen_changelog.py --help`` +for details. + +Changelog entries are obtained from ``changelog.txt`` files in multiple repos. +This allows changes to be listed in the same repo where they were made. These +changelogs are combined as part of the changelog build process: + +* ``docs/changelog.txt`` for changes in the main ``dfhack`` repo +* ``scripts/changelog.txt`` for changes made to scripts in the ``scripts`` repo +* ``library/xml/changelog.txt`` for changes made in the ``df-structures`` repo +* ``plugins/stonesense/changelog.txt`` for changes made in the ``stonesense`` + repo + +Building the changelogs generates two files: ``docs/changelogs/news.rst`` and +``docs/changelogs/news-dev.rst``. These correspond to `changelog` and +`dev-changelog` and contain changes organized by stable and development DFHack +releases, respectively. For example, an entry listed under "0.44.05-alpha1" in +changelog.txt will be listed under that version in the development changelog as +well, but under "0.44.05-r1" in the stable changelog (assuming that is the +closest stable release after 0.44.05-alpha1). An entry listed under a stable +release like "0.44.05-r1" in changelog.txt will be listed under that release in +both the stable changelog and the development changelog. + +Changelog syntax +---------------- + +.. include:: /docs/changelog.txt + :start-after: ===syntax-reference-start + :end-before: ===syntax-reference-end + +.. _docs-ci: + +GitHub Actions +============== + +Documentation is built automatically with GitHub Actions (a GitHub-provided +continuous integration service) for all pull requests and commits in the +"dfhack" and "scripts" repositories. These builds run with strict settings, i.e. +warnings are treated as errors. If a build fails, you will see a red "x" next to +the relevant commit or pull request. You can view detailed output from Sphinx in +a few ways: + +* Click on the red "x" (or green checkmark), then click "Details" next to + the "Build / docs" entry +* For pull requests only: navigate to the "Checks" tab, then click on "Build" in + the sidebar to expand it, then "docs" under it + +Sphinx output will be visible under the step named "Build docs". If a different +step failed, or you aren't sure how to interpret the output, leave a comment +on the pull request (or commit). + +You can also download the "docs" artifact from the summary page (typically +accessible by clicking "Build") if the build succeeded. This is a way to +visually inspect what the documentation looks like when built without installing +Sphinx locally, although we recommend installing Sphinx if you are planning to +do any significant work on the documentation. diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst new file mode 100644 index 0000000000..6ec394112f --- /dev/null +++ b/docs/dev/Lua API.rst @@ -0,0 +1,7759 @@ +.. highlight:: lua + +.. _lua-api: + +######################## +DFHack Lua API Reference +######################## + +DFHack has extensive support for +the Lua_ scripting language, providing access to: + +.. _Lua: https://www.lua.org + +1. Raw data structures used by the game. +2. Many C++ functions for high-level access to these + structures, and interaction with dfhack itself. +3. Some functions exported by C++ plugins. + +Lua code can be used both for writing scripts, which +are treated by DFHack command line prompt almost as +native C++ commands, and invoked by plugins written in C++. + +This document describes native API available to Lua in detail. +It does not describe all of the utility functions +implemented by Lua files located in :file:`hack/lua/*` +(:file:`library/lua/*` in the git repo). + +.. admonition:: Is this the DF or DFHack Lua API? + :class: warning + + This document describes the Lua API provided by DFHack, not + the Lua API provided by Dwarf Fortress. For information about DF's Lua API, see + :wiki:`Lua scripting` + on the Dwarf Fortress Wiki. + +.. contents:: Contents + :local: + :depth: 2 + +.. _lua-df: + +========================= +DF data structure wrapper +========================= + +.. contents:: + :local: + +Data structures of the game are defined in XML files located in :file:`library/xml` +(and `online `_, and automatically exported +to lua code as a tree of objects and functions under the ``df`` global, which +also broadly maps to the ``df`` namespace in the headers generated for C++. + +.. warning:: + + The wrapper provides almost raw access to the memory of the game, so + mistakes in manipulating objects are as likely to crash the game as + equivalent plain C++ code would be - e.g., null pointer access is safely + detected, but dangling pointers aren't. + +Objects managed by the wrapper can be broadly classified into the following groups: + +1. Typed object pointers (references). + + References represent objects in DF memory with a known type. + + In addition to fields and methods defined by the wrapped type, + every reference has some built-in properties and methods. + +2. Untyped pointers + + Represented as lightuserdata. + + In assignment to a pointer NULL can be represented either as + ``nil``, or a NULL lightuserdata; reading a NULL pointer field + returns ``nil``. + +3. Named types + + Objects in the ``df`` tree that represent identity of struct, class, + enum and bitfield types. They host nested named types, static + methods, builtin properties & methods, and, for enums and bitfields, + the bi-directional mapping between key names and values. + +4. The ``global`` object + + ``df.global`` corresponds to the ``df::global`` namespace, and + behaves as a mix between a named type and a reference, containing + both nested types and fields corresponding to global symbols. + +In addition to the ``global`` object and top-level types the ``df`` +global also contains a few global builtin utility functions. + +Typed object references +======================= + +The underlying primitive lua object is userdata with a metatable. +Every structured field access produces a new userdata instance. + +All typed objects have the following built-in features: + +* ``ref1 == ref2``, ``tostring(ref)`` + + References implement equality by type & pointer value, and string conversion. + +* ``pairs(ref)`` + + Returns an iterator for the sequence of actual C++ field names + and values. Fields are enumerated in memory order. Methods and + lua wrapper properties are not included in the iteration. + + .. warning:: + a few of the data structures (like ui_look_list) + contain unions with pointers to different types with vtables. + Using pairs on such structs is an almost sure way to crash with + an access violation. + +* ``ref._kind`` + + Returns one of: ``primitive``, ``struct``, ``container``, + or ``bitfield``, as appropriate for the referenced object. + +* ``ref._type`` + + Returns the named type object or a string that represents + the referenced object type. + +* ``ref:sizeof()`` + + Returns *size, address* + +* ``ref:new()`` + + Allocates a new instance of the same type, and copies data + from the current object. + +* ``ref:delete()`` + + Destroys the object with the C++ ``delete`` operator. If the destructor is not + available, returns *false*. (This typically only occurs when trying to delete + an instance of a DF class with virtual methods whose vtable address has not + been found; it is impossible for ``delete()`` to determine the validity of + ``ref``.) + + .. warning:: + ``ref`` **must** be an object allocated with ``new``, like in C++. Calling + ``obj.field:delete()`` where ``obj`` was allocated with ``new`` will not + work. After ``delete()`` returns, ``ref`` remains as a dangling pointer, + like a raw C++ pointer would. Any accesses to ``ref`` after ``ref:delete()`` + has been called are undefined behavior. + +* ``ref:assign(object)`` + + Assigns data from object to ref. Object must either be another + ref of a compatible type, or a lua table; in the latter case + special recursive assignment rules are applied. + +* ``ref:_displace(index[,step])`` + + Returns a new reference with the pointer adjusted by index*step. + Step defaults to the natural object size. + +Primitive references +-------------------- + +References of the *_kind* ``'primitive'`` are used for objects +that don't fit any of the other reference types. Such +references can only appear as a value of a pointer field, +or as a result of calling the ``_field()`` method. + +They behave as structs with a ``value`` field of the right type. If the +object's XML definition has a ``ref-target`` attribute, they will also have +a read-only ``ref_target`` field set to the corresponding type object. + +To make working with numeric buffers easier, they also allow +numeric indices. Note that other than excluding negative values +no bound checking is performed, since buffer length is not available. +Index 0 is equivalent to the ``value`` field. + + +Struct references +----------------- + +Struct references are used for class and struct objects. + +They implement the following features: + +* ``ref.field``, ``ref.field = value`` + + Valid fields of the structure may be accessed by subscript. + + Primitive typed fields, i.e., numbers & strings, are converted + to/from matching lua values. The value of a pointer is a reference + to the target, or ``nil``/NULL. Complex types are represented by + a reference to the field within the structure; unless recursive + lua table assignment is used, such fields can only be read. + + .. note:: + In case of inheritance, *superclass* fields have precedence + over the subclass, but fields shadowed in this way can still + be accessed as ``ref['subclasstype.field']``. + + This shadowing order is necessary because vtable-based classes + are automatically exposed in their exact type, and the reverse + rule would make access to superclass fields unreliable. + +* ``ref:_field(field)`` + + Returns a reference to a valid field. That is, unlike regular + subscript, it returns a reference to the field within the structure + even for primitive typed fields and pointers. Fails with an error + if the field is not found. + +* ``ref:vmethod(args...)`` + + Named virtual methods are also exposed, subject to the same + shadowing rules. + +* ``pairs(ref)`` + + Enumerates all real fields (but not methods) in memory + order, which is the same as declaration order. + +Container references +-------------------- + +Containers represent vectors and arrays, possibly resizable. + +A container field can associate an enum to the container +reference, which allows accessing elements using string keys +instead of numerical indices. + +Note that two-dimensional arrays in C++ (ie pointers to pointers) +are exposed to lua as one-dimensional. The best way to handle this +is probably ``array[x].value:_displace(y)``. + +Implemented features: + +* ``ref._enum`` + + If the container has an associated enum, returns the matching + named type object. + +* ``#ref`` + + Returns the *length* of the container. + +* ``ref[index]`` + + Accesses the container element, using either a *0-based* numerical + index, or, if an enum is associated, a valid enum key string. + + Accessing an invalid index is an error, but some container types + may return a default value, or auto-resize instead for convenience. + Currently this relaxed mode is implemented by df-flagarray aka BitArray. + +* ``ref:_field(index)`` + + Like with structs, returns a pointer to the array element, if possible. + Flag and bit arrays cannot return such pointer, so it fails with an error. + +* ``pairs(ref)``, ``ipairs(ref)`` + + If the container has no associated enum, both behave identically, + iterating over numerical indices in order. Otherwise, ipairs still + uses numbers, while pairs tries to substitute enum keys whenever + possible. + +* ``ref:resize(new_size)`` + + Resizes the container if supported, or fails with an error. + +* ``ref:insert(index,item)`` + + Inserts a new item at the specified index. To add at the end, + use ``#ref``, or just ``'#'`` as index. + +* ``ref:erase(index)`` + + Removes the element at the given valid index. + +Bitfield references +------------------- + +Bitfields behave like special fixed-size containers. +Consider them to be something in between structs and +fixed-size vectors. + +The ``_enum`` property points to the bitfield type. +Numerical indices correspond to the shift value, +and if a subfield occupies multiple bits, the +``ipairs`` order would have a gap. + +Additionally, bitfields have a ``whole`` property, +which returns the value of the bitfield as an +integer. + +Since currently there is no API to allocate a bitfield +object fully in GC-managed lua heap, consider using the +lua table assignment feature outlined below in order to +pass bitfield values to dfhack API functions that need +them, e.g., ``matinfo:matches{metal=true}``. + + +Named types +=========== + +Named types are exposed in the ``df`` tree with names identical +to the C++ version, except for the ``::`` vs ``.`` difference. + +All types and the global object have the following features: + +* ``type._kind`` + + Evaluates to one of ``struct-type``, ``class-type``, ``enum-type``, + ``bitfield-type`` or ``global``. + +* ``type._identity`` + + Contains a lightuserdata pointing to the underlying + ``DFHack::type_identity`` object. + +All compound types (structs, classes, unions, and the global object) support: + +* ``type._union`` + + ``true`` if the type represents a union, otherwise ``nil``. + +* ``type._fields`` + + Contains a table mapping field names to descriptions of the type's fields, + including data members and functions. Iterating with ``pairs()`` returns data + fields in the order they are defined in the type. Functions and globals may + appear in an arbitrary order. + + Each entry contains the following fields: + + * ``name``: the name of the field (matches the ``_fields`` table key) + * ``offset``: for data members, the position of the field relative to the start of the type, in bytes + * ``count``: for arrays, the number of elements + * ``mode``: implementation detail. See ``struct_field_info::Mode`` in ``DataDefs.h``. + + Each entry may also contain the following fields, depending on its type: + + * ``type_name``: present for most fields; a string representation of the field's type + * ``type``: the type object matching the field's type; present if such an object exists + (e.g., present for DF types, absent for primitive types) + * ``type_identity``: present for most fields; a lightuserdata pointing to the field's underlying ``DFHack::type_identity`` object + * ``index_enum``, ``ref_target``: the type object corresponding to the field's similarly-named XML attribute, if present + * ``union_tag_field``, ``union_tag_attr``, ``original_name``: the string value of the field's similarly-named XML attribute, if present + +Types excluding the global object also support: + +* ``type:sizeof()`` + + Returns the size of an object of the type. + +* ``type:new()`` + + Creates a new instance of an object of the type. + +* ``type:is_instance(object)`` + + Returns true if object is same or subclass type, or a reference + to an object of same or subclass type. It is permissible to pass + ``nil``, NULL or non-wrapper value as object; in this case the + method returns ``nil``. + +Enum types support the following: + +* ``type.next_item(index)`` + + Returns the next valid numeric value of the enum. It returns the + first enum value if ``index`` is greater than or equal to the max + enum value. + +* ``type.attrs`` + + A mapping of enum keys (usually integers) and values (usually strings) to + their attributes. e.g ``df.goal_type.attrs.STAY_ALIVE`` returns + ``{ short_name: "Stay Alive", achieved_short_name: "Stayed Alive" } }`` + +* ``type._attr_entry_type`` + + Returns the named ``struct-type`` type representing the table returned + by ``type.attrs``. + +In addition to this, enum and bitfield types contain a +bi-directional mapping between key strings and values, and +also map ``_first_item`` and ``_last_item`` to the min and +max values. + +Struct and class types with an instance-vector attribute in the XML also support: + +* ``type.find(key)`` + + Returns an object from the instance vector that matches the key, where the + field is determined by the 'key-field' specified in the XML. + +* ``type.get_vector()`` + + Returns the instance vector e.g ``df.item.get_vector() == df.global.world.items.all`` + +Global functions +================ + +The ``df`` table itself contains the following functions and values: + +* ``NULL``, ``df.NULL`` + + Contains the NULL lightuserdata. + +* ``df.isnull(obj)`` + + Evaluates to true if obj is nil or NULL; false otherwise. + +* ``df.isvalid(obj[,allow_null])`` + + For supported objects returns one of ``type``, ``voidptr``, ``ref``. + + If *allow_null* is true, and obj is nil or NULL, returns ``null``. + + Otherwise returns *nil*. + +* ``df.sizeof(obj)`` + + For types and refs identical to ``obj:sizeof()``. + For lightuserdata returns *nil, address* + +* ``df.new(obj)``, ``df.delete(obj)``, ``df.assign(obj, obj2)`` + + Equivalent to using the matching methods of obj. + +* ``df._displace(obj,index[,step])`` + + For refs equivalent to the method, but also works with + lightuserdata (step is mandatory then). + +* ``df.is_instance(type,obj)`` + + Equivalent to the method, but also allows a reference as proxy for its type. + +* ``df.new(ptype[,count])`` + + Allocate a new instance, or an array of built-in types. + The ``ptype`` argument is a string from the following list: + ``string``, ``int8_t``, ``uint8_t``, ``int16_t``, ``uint16_t``, + ``int32_t``, ``uint32_t``, ``int64_t``, ``uint64_t``, ``bool``, + ``float``, ``double``. All of these except ``string`` can be + used with the count argument to allocate an array. + +* ``df.reinterpret_cast(type,ptr)`` + + Converts ptr to a ref of specified type. The type may be anything + acceptable to ``df.is_instance``. Ptr may be *nil*, a ref, + a lightuserdata, or a number. + + Returns *nil* if NULL, or a ref. + +.. _lua-api-table-assignment: + +Recursive table assignment +========================== + +Recursive assignment is invoked when a lua table is assigned +to a C++ object or field, i.e., one of: + +* ``ref:assign{...}`` +* ``ref.field = {...}`` + +The general mode of operation is that all fields of the table +are assigned to the fields of the target structure, roughly +emulating the following code:: + + function rec_assign(ref,table) + for key,value in pairs(table) do + ref[key] = value + end + end + +Since assigning a table to a field using = invokes the same +process, it is recursive. + +There are however some variations to this process depending +on the type of the field being assigned to: + +1. If the table contains an ``assign`` field, it is + applied first, using the ``ref:assign(value)`` method. + It is never assigned as a usual field. + +2. When a table is assigned to a non-NULL pointer field + using the ``ref.field = {...}`` syntax, it is applied + to the target of the pointer instead. + + If the pointer is NULL, the table is checked for a ``new`` field: + + a. If it is *nil* or *false*, assignment fails with an error. + + b. If it is *true*, the pointer is initialized with a newly + allocated object of the declared target type of the pointer. + + c. Otherwise, ``table.new`` must be a named type, or an + object of a type compatible with the pointer. The pointer + is initialized with the result of calling ``table.new:new()``. + + After this auto-vivification process, assignment proceeds + as if the pointer wasn't NULL. + + Obviously, the ``new`` field inside the table is always skipped + during the actual per-field assignment processing. + +3. If the target of the assignment is a container, a separate + rule set is used: + + a. If the table contains neither ``assign`` nor ``resize`` + fields, it is interpreted as an ordinary *1-based* lua + array. The container is resized to the #-size of the + table, and elements are assigned in numeric order:: + + ref:resize(#table); + for i=1,#table do ref[i-1] = table[i] end + + b. Otherwise, ``resize`` must be *true*, *false*, or + an explicit number. If it is not false, the container + is resized. After that the usual struct-like 'pairs' + assignment is performed. + + In case ``resize`` is *true*, the size is computed + by scanning the table for the largest numeric key. + + This means that in order to reassign only one element of + a container using this system, it is necessary to use:: + + { resize=false, [idx]=value } + +Since ``nil`` inside a table is indistinguishable from missing key, +it is necessary to use ``df.NULL`` as a null pointer value. + +This system is intended as a way to define a nested object +tree using pure lua data structures, and then materialize it in +C++ memory in one go. Note that if pointer auto-vivification +is used, an error in the middle of the recursive walk would +not destroy any objects allocated in this way, so the user +should be prepared to catch the error and do the necessary +cleanup. + +========== +DFHack API +========== + +.. contents:: + :local: + +DFHack utility functions are placed in the ``dfhack`` global tree. + +Native utilities +================ + +Input & Output +-------------- + +* ``dfhack.print(args...)`` + + Output tab-separated args as standard lua print would do, + but without a newline. + +* ``print(args...)``, ``dfhack.println(args...)`` + + A replacement of the standard library print function that + works with DFHack output infrastructure. + +* ``dfhack.printerr(args...)`` + + Same as println; intended for errors. Uses red color and logs to stderr.log. + +* ``dfhack.color([color])`` + + Sets the current output color. If color is *nil* or *-1*, resets to default. + Returns the previous color value. + +* ``dfhack.is_interactive()`` + + Checks if the thread can access the interactive console and returns *true* or *false*. + +* ``dfhack.lineedit([prompt[,history_filename]])`` + + If the thread owns the interactive console, shows a prompt + and returns the entered string. Otherwise returns *nil, error*. + + Depending on the context, this function may actually yield the + running coroutine and let the C++ code release the core suspend + lock. Using an explicit ``dfhack.with_suspend`` will prevent + this, forcing the function to block on input with lock held. + +* ``dfhack.getCommandHistory(history_id, history_filename)`` + + Returns the list of strings in the specified history. Intended to be used by + GUI scripts that don't have access to a console and so can't use + ``dfhack.lineedit``. The ``history_id`` parameter is some unique string that + the script uses to identify its command history, such as the script's name. If + this is the first time the history with the given ``history_id`` is being + accessed, it is initialized from the given file. + +* ``dfhack.addCommandToHistory(history_id, history_filename, command)`` + + Adds a command to the specified history and saves the updated history to the + specified file. + +* ``dfhack.interpreter([prompt[,history_filename[,env]]])`` + + Starts an interactive lua interpreter, using the specified prompt + string, global environment and command-line history file. + + If the interactive console is not accessible, returns *nil, error*. + + +Exception handling +------------------ + +* ``dfhack.error(msg[,level[,verbose]])`` + + Throws a dfhack exception object with location and stack trace. + The verbose parameter controls whether the trace is printed by default. + +* ``qerror(msg[,level])`` + + Calls ``dfhack.error()`` with ``verbose`` being *false*. Intended to + be used for user-caused errors in scripts, where stack traces are not + desirable. + +* ``dfhack.pcall(f[,args...])`` + + Invokes f via xpcall, using an error function that attaches + a stack trace to the error. The same function is used by SafeCall + in C++, and dfhack.safecall. + +* ``safecall(f[,args...])``, ``dfhack.safecall(f[,args...])`` + + Just like pcall, but also prints the error using printerr before + returning. Intended as a convenience function. + +* ``dfhack.saferesume(coroutine[,args...])`` + + Compares to coroutine.resume like dfhack.safecall vs pcall. + +* ``dfhack.exception`` + + Metatable of error objects used by dfhack. The objects have the + following properties: + + ``err.where`` + The location prefix string, or *nil*. + ``err.message`` + The base message string. + ``err.stacktrace`` + The stack trace string, or *nil*. + ``err.cause`` + A different exception object, or *nil*. + ``err.thread`` + The coroutine that has thrown the exception. + ``err.verbose`` + Boolean, or *nil*; specifies if where and stacktrace should be printed. + ``tostring(err)``, or ``err:tostring([verbose])`` + Converts the exception to string. + +* ``dfhack.exception.verbose`` + + The default value of the ``verbose`` argument of ``err:tostring()``. + + +Miscellaneous +------------- + +* ``dfhack.VERSION`` + + DFHack version string constant. + +* ``dfhack.curry(func,args...)``, or ``curry(func,args...)`` + + Returns a closure that invokes the function with args combined + both from the curry call and the closure call itself. I.e., + ``curry(func,a,b)(c,d)`` equals ``func(a,b,c,d)``. + + +Locking and finalization +------------------------ + +* ``dfhack.with_suspend(f[,args...])`` + + Calls ``f`` with arguments after grabbing the DF core suspend lock. + Suspending is necessary for accessing a consistent state of DF memory. + + Returned values and errors are propagated through after releasing + the lock. It is safe to nest suspends. + + Every thread is allowed only one suspend per DF frame, so it is best + to group operations together in one big critical section. A plugin + can choose to run all lua code inside a C++-side suspend lock. + +* ``dfhack.call_with_finalizer(num_cleanup_args,always,cleanup_fn[,cleanup_args...],fn[,args...])`` + + Invokes ``fn`` with ``args``, and after it returns or throws an + error calls ``cleanup_fn`` with ``cleanup_args``. Any return values from + ``fn`` are propagated, and errors are re-thrown. + + The ``num_cleanup_args`` integer specifies the number of ``cleanup_args``, + and the ``always`` boolean specifies if cleanup should be called in any case, + or only in case of an error. + +* ``dfhack.with_finalize(cleanup_fn,fn[,args...])`` + + Calls ``fn`` with arguments, then finalizes with ``cleanup_fn``. + Implemented using ``call_with_finalizer(0,true,...)``. + +* ``dfhack.with_onerror(cleanup_fn,fn[,args...])`` + + Calls ``fn`` with arguments, then finalizes with ``cleanup_fn`` on any thrown error. + Implemented using ``call_with_finalizer(0,false,...)``. + +* ``dfhack.with_temp_object(obj,fn[,args...])`` + + Calls ``fn(obj,args...)``, then finalizes with ``obj:delete()``. + +.. _persistent-api: + +Persistent configuration storage +-------------------------------- + +This api is intended for storing tool state in the world savegame directory. It +is intended for data that is world-dependent. Global state that is independent +of the loaded world should be saved into a separate file named after the tool +in the ``dfhack-config/`` directory. + +Entries are associated with the current loaded site (fortress) and are +identified by a string ``key``. The data will still be associated with a fort +if the fort is retired and then later unretired. Entries are stored as +serialized strings, but there are convenience functions for working with +arbitrary Lua tables. + +* ``dfhack.persistent.getSiteData(key[, default])`` + + Retrieves the Lua table associated with the current site and the given string + ``key``. If ``default`` is supplied, then it is returned if the key isn't + found in the current site's persistent data. + + Example usage:: + + local state = dfhack.persistent.getSiteData('my-script-name', {somedata={}}) + +* ``dfhack.persistent.getSiteDataString(key)`` + + Retrieves the underlying serialized string associated with the current site + and the given string ``key``. Returns *nil* if the key isn't found in the + current site's persistent data. Most scripts will want to use ``getSiteData`` + instead. + +* ``dfhack.persistent.saveSiteData(key, data)`` + + Persists the given ``data`` (usually a table; can be of arbitrary complexity and depth) + in the world save, associated with the current site and the given ``key``. + +* ``dfhack.persistent.saveSiteDataString(key, data_str)`` + + Persists the given string in the world save, associated with the current site + and the given ``key``. + +* ``dfhack.persistent.deleteSiteData(key)`` + + Removes the existing entry associated with the current site and the given + ``key``. Returns *true* if succeeded. + +* ``dfhack.persistent.getWorldData(key[, default])`` +* ``dfhack.persistent.getWorldDataString(key)`` +* ``dfhack.persistent.saveWorldData(key, data)`` +* ``dfhack.persistent.saveWorldDataString(key, data_str)`` +* ``dfhack.persistent.deleteWorldData(key)`` + + Same semantics as for the ``Site`` functions, but will associated the data + with the global world context. + +* ``dfhack.persistent.getUnsavedSeconds()`` + + Returns the number of seconds since last save or load of a save. + +The data is kept in memory, so no I/O occurs when getting or saving keys. It is +all written to a json file in the game save directory when the game is saved. + +Material info lookup +-------------------- + +A material info record has fields: + +* ``type``, ``index``, ``material`` + + DF material code pair, and a reference to the material object. + +* ``mode`` + + One of ``'builtin'``, ``'inorganic'``, ``'plant'``, ``'creature'``. + +* ``inorganic``, ``plant``, ``creature`` + + If the material is of the matching type, contains a reference to the raw object. + +* ``figure`` + + For a specific creature material contains a ref to the historical figure. + +Functions: + +* ``dfhack.matinfo.decode(type,index)`` + + Looks up material info for the given number pair; if not found, returns *nil*. + +* ``....decode(matinfo|item|plant|obj)`` + + Uses type-specific methods for retrieving the code pair. + +* ``dfhack.matinfo.find(token[,token...])`` + + Looks up material by a token string, or a pre-split string token sequence. + +* ``dfhack.matinfo.getToken(...)``, ``info:getToken()`` + + Applies ``decode`` and constructs a string token. + +* ``info:toString([temperature[,named]])`` + + Returns the human-readable name at the given temperature. + +* ``info:getCraftClass()`` + + Returns the classification used for craft skills. + +* ``info:matches(obj)`` + + Checks if the material matches job_material_category or job_item. + Accept dfhack_material_category auto-assign table. + +.. _lua_api_random: + +Random number generation +------------------------ + +* ``dfhack.random.new([seed[,perturb_count]])`` + + Creates a new random number generator object. Without any + arguments, the object is initialized using current time. + Otherwise, the seed must be either a non-negative integer, + or a list of such integers. The second argument may specify + the number of additional randomization steps performed to + improve the initial state. + +* ``rng:init([seed[,perturb_count]])`` + + Re-initializes an already existing random number generator object. + +* ``rng:random([limit])`` + + Returns a random integer. If ``limit`` is specified, the value + is in the range [0, limit); otherwise it uses the whole 32-bit + unsigned integer range. + +* ``rng:drandom()`` + + Returns a random floating-point number in the range [0,1). + +* ``rng:drandom0()`` + + Returns a random floating-point number in the range (0,1). + +* ``rng:drandom1()`` + + Returns a random floating-point number in the range [0,1]. + +* ``rng:unitrandom()`` + + Returns a random floating-point number in the range [-1,1]. + +* ``rng:unitvector([size])`` + + Returns multiple values that form a random vector of length 1, + uniformly distributed over the corresponding sphere surface. + The default size is 3. + +* ``fn = rng:perlin([dim]); fn(x[,y[,z]])`` + + Returns a closure that computes a classical Perlin noise function + of dimension *dim*, initialized from this random generator. + Dimension may be 1, 2 or 3 (default). + + +.. _lua-cpp-func-wrappers: + +C++ function wrappers +===================== + +.. contents:: + :local: + +Thin wrappers around C++ functions, similar to the ones for virtual methods. +One notable difference is that these explicit wrappers allow argument count +adjustment according to the usual lua rules, so trailing false/nil arguments +can be omitted. + +* ``dfhack.getOSType()`` + + Returns the OS type string from ``symbols.xml``. + +* ``dfhack.getDFVersion()`` + + Returns the DF version string from ``symbols.xml``. + +* ``dfhack.getDFHackVersion()`` +* ``dfhack.getDFHackRelease()`` +* ``dfhack.getDFHackBuildID()`` +* ``dfhack.getCompiledDFVersion()`` +* ``dfhack.getGitDescription()`` +* ``dfhack.getGitCommit()`` +* ``dfhack.getGitXmlCommit()`` +* ``dfhack.getGitXmlExpectedCommit()`` +* ``dfhack.gitXmlMatch()`` +* ``dfhack.isRelease()`` +* ``dfhack.isPrerelease()`` + + Return information about the DFHack build in use. + + .. note:: + ``getCompiledDFVersion()`` returns the DF version specified at compile time, + while ``getDFVersion()`` returns the version and typically the OS as well. + These do not necessarily match - for example, DFHack 0.34.11-r5 worked with + DF 0.34.10 and 0.34.11, so the former function would always return ``0.34.11`` + while the latter would return ``v0.34.10 `` or ``v0.34.11 ``. + +* ``dfhack.getDFPath()`` + + Returns the DF directory path. + +* ``dfhack.getHackPath()`` + + Returns the DFHack installation directory path (the folder where DFHack is installed). + This may be the ``hack`` folder within the DF installation, but you should not rely on this. + Specifically, the installation folder is extremely likely to be somewhere else when DFHack is installed from Steam. + Always use this function to get the DFHack installation directory path instead of hardcoding it. + +* ``dfhack.getConfigPath()`` + + Returns the DFHack config directory path (the folder where user-specific configuration files are stored). + This is currently the ``dfhack-config`` folder within the DF installation, but you should not rely on this as it is likely to change in the future. + Always use this function to get the DFHack config directory path instead of hardcoding it. + Avoid storing this value in a long-lived variable, as it's possible that in future versions of DFHack, it may be possible for the config directory to be changed at runtime. + +* ``dfhack.getSavePath()`` + + Returns the path to the current save directory, or *nil* if no save loaded. + +* ``dfhack.getTickCount()`` + + Returns the tick count in ms, exactly as DF ui uses. + +* ``dfhack.isWorldLoaded()`` + + Checks if the world is loaded. + +* ``dfhack.isMapLoaded()`` + + Checks if the world and map are loaded. + +* ``dfhack.isSiteLoaded()`` + + Checks if a site (e.g., a player fort) is loaded. + +* ``dfhack.df2utf(string)`` + + Convert a string from DF's CP437 encoding to UTF-8. + +* ``dfhack.df2console()`` + + Convert a string from DF's CP437 encoding to the correct encoding for the + DFHack console. + +.. warning:: + + When printing CP437-encoded text to the console (for example, names returned + from ``dfhack.units.getReadableName()``), use + ``print(dfhack.df2console(text))`` to ensure proper display on all platforms. + +* ``dfhack.utf2df(string)`` + + Convert a string from UTF-8 to DF's CP437 encoding. + +* ``dfhack.upperCp437(string)`` + + Return a version of the string with all letters capitalized. + Non-ASCII CP437 characters are capitalized if a CP437 version exists. + For example, ``ä`` is replaced by ``Ä``, but ``â`` is never capitalized. + + +* ``dfhack.lowerCp437(string)`` + + Return a version of the string with all letters in lower case. + Non-ASCII CP437 characters are downcased. For example, ``Ä`` is replaced by ``ä``. + +* ``dfhack.toSearchNormalized(string)`` + + Replace non-ASCII alphabetic characters in a CP437-encoded string with their + nearest ASCII equivalents, if possible, and returns a CP437-encoded string. + Note that the returned string may be longer than the input string. For + example, ``ä`` is replaced with ``a``, and ``æ`` is replaced with ``ae``. + +* ``dfhack.capitalizeStringWords(string)`` + + Return a version of the string with the first letter of each word capitalized. + The beginning of a word is determined by a space or quote ``"``. It is also + determined by an apostrophe ``'`` when preceded by a space or comma. + Non-ASCII CP437 characters will be capitalized if a CP437 version exists. + This function does not downcase characters. Use ``dfhack.lowerCp437`` + first, if desired. + +* ``dfhack.formatInt(num)`` + + Formats an integer value as a string according to the current system locale. + E.g., for American English, it would transform like: ``12345`` -> + ``'12,345'`` + +* ``dfhack.formatFloat(num)`` + + Formats a floating point value as a string according to the current system + locale. E.g., for American English, it would transform like: ``-12345.6789`` + -> ``'-12,345.678711'`` (because float imprecision). + +* ``dfhack.run_command(command[, ...])`` + + Run an arbitrary DFHack command, with the core suspended, and send output to + the DFHack console. The command can be passed as a table, multiple string + arguments, or a single string argument (not recommended - in this case, the + usual DFHack console tokenization is used). + + A ``command_result`` constant starting with ``CR_`` is returned, where ``CR_OK`` + indicates success. + + The following examples are equivalent:: + + dfhack.run_command({'ls', 'quick'}) + dfhack.run_command('ls', 'quick') + dfhack.run_command('ls quick') -- not recommended + +* ``dfhack.run_command_silent(command[, ...])`` + + Similar to ``run_command()``, but instead of printing to the console, + returns an ``output, command_result`` pair. ``output`` is a single string - + see ``dfhack.internal.runCommand()`` to obtain colors as well. + +Translation module +------------------ + +* ``dfhack.translation.translateName(name[,in_english[,only_last_name]])`` + + Convert a ``df.language_name`` (or only the last name part) to string. + +* ``dfhack.translation.generateName(name,language,type,major_selector,minor_selector)`` + + Dynamically generate a name using the same logic the game itself uses. + +Gui module +---------- + +Screens +~~~~~~~ + +* ``dfhack.gui.getCurViewscreen([skip_dismissed])`` + + Returns the topmost viewscreen. If ``skip_dismissed`` is *true*, + ignores screens already marked to be removed. + +* ``dfhack.gui.getFocusStrings(viewscreen)`` + + Returns a table of string representations of the current UI focuses. + The strings have a "screen/foo/bar/baz..." format e.g.:: + + [1] = "dwarfmode/Info/CREATURES/CITIZEN" + [2] = "dwarfmode/Squads" + +* ``dfhack.gui.matchFocusString(focus_string[, viewscreen])`` + + Returns ``true`` if the given ``focus_string`` is found in the current + focus strings, or as a prefix to any of the focus strings, or ``false`` + if no match is found. Matching is case insensitive. If ``viewscreen`` is + specified, gets the focus strings to match from the given viewscreen. + +* ``dfhack.gui.getCurFocus([skip_dismissed])`` + + Returns a list of focus strings for the current viewscreen. Equivalent to + ``dfhack.gui.getFocusStrings(dfhack.gui.getCurViewscreen(skip_dismissed))``. + +* ``dfhack.gui.getViewscreenByType(type[, depth])`` + + Returns the topmost viewscreen out of the top ``depth`` viewscreens with + the specified type (e.g., ``df.viewscreen_titlest``), or ``nil`` if none match. + If ``depth`` is not specified or is less than 1, all viewscreens are checked. + +* ``dfhack.gui.getDFViewscreen([skip_dismissed[, viewscreen]])`` + + Returns the topmost viewscreen not owned by DFHack. If ``skip_dismissed`` is + ``true``, ignores screens already marked to be removed. If ``viewscreen`` is + specified, starts the scan at the given viewscreen. + +* ``dfhack.gui.getWidget(container, [, ...])`` + + Returns the DF widget in the given widget container with the given name or + (zero-based) numeric index. You can follow a chain of widget containers by + passing additional names or indices. For example: + ``:lua ~dfhack.gui.getWidget(game.main_interface.info.labor, "Tabs", 0)`` + +* ``dfhack.gui.getWidgetChildren(container)`` + + Returns all the DF widgets in the given widget container. + +General-purpose selections +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +* ``dfhack.gui.getSelectedWorkshopJob([silent])`` +* ``dfhack.gui.getSelectedJob([silent])`` +* ``dfhack.gui.getSelectedUnit([silent])`` +* ``dfhack.gui.getSelectedItem([silent])`` +* ``dfhack.gui.getSelectedBuilding([silent])`` +* ``dfhack.gui.getSelectedCivZone([silent])`` +* ``dfhack.gui.getSelectedStockpile([silent])`` +* ``dfhack.gui.getSelectedPlant([silent])`` + + Returns the currently selected in-game object or the indicated thing + associated with the selected in-game object. For example, Calling + ``getSelectedJob`` when a building is selected will return the job associated + with the building (e.g., the ``ConstructBuilding`` job). If ``silent`` is + omitted or set to ``false`` and a selected object cannot be found, then an + error is printed to the console. + +* ``dfhack.gui.getAnyWorkshopJob(screen)`` +* ``dfhack.gui.getAnyJob(screen)`` +* ``dfhack.gui.getAnyUnit(screen)`` +* ``dfhack.gui.getAnyItem(screen)`` +* ``dfhack.gui.getAnyBuilding(screen)`` +* ``dfhack.gui.getAnyCivZone(screen)`` +* ``dfhack.gui.getAnyStockpile(screen)`` +* ``dfhack.gui.getAnyPlant(screen)`` + + Similar to the corresponding ``getSelected`` functions, but operate on the + given screen instead of the current screen and always return ``nil`` silently + on failure. + +Fortress mode +~~~~~~~~~~~~~ + +* ``dfhack.gui.getDwarfmodeViewDims()`` + + Returns dimensions of the displayed map viewport. See ``getPanelLayout()`` + in the ``gui.dwarfmode`` module for a more Lua-friendly version. + +* ``dfhack.gui.resetDwarfmodeView([pause])`` + + Resets the fortress mode sidebar menus and cursors to their default state. If + ``pause`` is true, also pauses the game. + +* ``dfhack.gui.pauseRecenter(pos[,pause])`` + ``dfhack.gui.pauseRecenter(x,y,z[,pause])`` + + Same as ``resetDwarfmodeView``, but also recenter if position is valid. If + ``pause`` is false, skip pausing. Respects ``RECENTER_INTERFACE_SHUTDOWN_MS`` + in DF's ``init.txt`` (the delay before input is recognized when a recenter + occurs.) + +* ``dfhack.gui.revealInDwarfmodeMap(pos[,center[,highlight]])`` + ``dfhack.gui.revealInDwarfmodeMap(x,y,z[,center[,highlight]])`` + + Centers the view on the given coordinates. If ``center`` is true, make sure + the position is in the exact center of the view, else just bring it on screen. + If ``highlight`` is true, then mark the target tile with a pulsing highlight + until the player clicks somewhere else. + + ``pos`` can be a ``df.coord`` instance or a table assignable to a ``df.coord`` + (see `lua-api-table-assignment`), + e.g.:: + + {x = 5, y = 7, z = 11} + getSelectedUnit().pos + copyall(df.global.cursor) + + If the position is invalid, the function will simply ensure the current + window position is clamped between valid values. + +* ``dfhack.gui.refreshSidebar()`` + + Refreshes the fortress mode sidebar. This can be useful when making changes to + the map, for example, because DF only updates the sidebar when the cursor + position changes. + +* ``dfhack.gui.inRenameBuilding()`` + + Returns ``true`` if a building is being renamed. + +Announcements +~~~~~~~~~~~~~ + +* ``dfhack.gui.writeToGamelog(text)`` + + Writes a string to :file:`gamelog.txt` without doing an announcement. + +* ``dfhack.gui.makeAnnouncement(type,flags,pos,text[,color[,is_bright]])`` + + Adds an announcement with given announcement_type, text, color, and brightness. + + The announcement is written to :file:`gamelog.txt`. The announcement_flags + argument provides a custom set of :file:`announcements.txt` options, + which specify if the message should actually be displayed in the + announcement list, and whether to recenter or show a popup. + + Returns the index of the new announcement in ``df.global.world.status.reports``, or -1. + +* ``dfhack.gui.addCombatReport(unit,slot,report_index[,update_alert])`` + + Adds the report with the given index (returned by makeAnnouncement) + to the specified group of the given unit. If ``update_alert`` is ``true``, + an alert badge will appear on the left side of the screen if not already visible. + Returns ``true`` on success. + +* ``dfhack.gui.addCombatReportAuto(unit,flags,report_index)`` + + Adds the report with the given index to the appropriate group(s) of the given unit + based on the unit's current job and as requested by the flags. + Always updates alert badges. Returns ``true`` on any success. + +* ``dfhack.gui.showAnnouncement(text[,color[,is_bright]])`` + + Adds a regular announcement with given text, color, and brightness. + The announcement type is always ``df.announcement_type.REACHED_PEAK``, + which uses the alert badge for ``df.announcement_alert_type.GENERAL``. + +* ``dfhack.gui.showZoomAnnouncement(type,pos,text[,color[,is_bright]])`` + + Like above, but also specifies a position you can zoom to from the announcement menu, + as well as being able to set the announcement type. + +* ``dfhack.gui.showPopupAnnouncement(text[,color[,is_bright]])`` + + Displays a megabeast-style modal announcement window. + DF is currently ignoring the color and brightness settings + (see: `bug report `_.) + Add ``[C:`` color ``:0:`` bright ``]`` (where color is 0-7 and bright is 0-1) + in front of your text string to force the popup text to be colored. + + Text is run through a parser as it is converted into a markup text box. + The parser accepts tokens in square brackets (``[`` ``]``.) + Use ``[[`` and ``]]`` to include actual square brackets in text. + + The following tokens are accepted: + + ``[R]``: (NEW_LINE) Ends the current line and begins on the next. + + ``[B]``: (BLANK_LINE) Ends the current line and adds an additional blank line, + beginning on the line after that. + + ``[P]``: (INDENT) Ends the current line and begins four spaces indented on the next. + + ``[CHAR:`` n ``]``, ``[CHAR:~`` ch ``]``: Add a single character. First version + takes a base-10 integer ``n`` representing a CP437 character. + Second version accepts a character ``ch`` instead. ``"[CHAR:154]"`` and + ``"[CHAR:~"..string.char(154).."]"`` both result in ``Ü``. Use ``[CHAR:32]`` or + ``[CHAR:~ ]`` to add extra spaces, which would normally be trimmed by the parser. + + ``[LPAGE:`` link_type ``:`` id ``]``, ``[LPAGE:`` link_type ``:`` id ``:`` subid ``]``: + Start a ``markup_text_linkst``. These are intended for Legends mode page links and + don't work in popups. The text will just be colored based on ``link_type``. + Valid link types are: ``HF`` (``HIST_FIG``,) ``SITE``, ``ARTIFACT``, ``BOOK``, + ``SR`` (``SUBREGION``,) ``FL`` (``FEATURE_LAYER``,) ``ENT`` (``ENTITY``,) + ``AB`` (``ABSTRACT_BUILDING``,) ``EPOP`` (``ENTITY_POPULATION``,) ``ART_IMAGE``, + ``ERA``, ``HEC``. + ``subid`` is only used for ``AB`` and ``ART_IMAGE``. ``[/LPAGE]`` ends the link text. + + ``[C:`` screenf ``:`` screenb ``:`` screenbright ``]``: Color text. Sets the + respective values in ``df.global.gps`` and then sets text color. + ``color`` = ``screenf``, ``bright`` = ``screenbright``, ``screenb`` does nothing + since popup backgrounds are always black. + Example: ``"Light gray, [C:4:0:0]red, [C:4:0:1]orange, [C:7:0:0]light gray."`` + + ``[KEY:`` n ``]``: Keybinding. Shows the (first) keybinding for the + ``df.interface_key`` ``n``. The keybinding will be displayed in light green, but + the previous text color will be restored afterwards. + +* ``dfhack.gui.showAutoAnnouncement(type,pos,text[,color[,is_bright[,unit_a[,unit_d]]]])`` + + Uses the type to look up options from announcements.txt, and calls the above + operations accordingly. The units are used to call ``addCombatReportAuto``. + +* ``dfhack.gui.autoDFAnnouncement(report,text)`` + ``dfhack.gui.autoDFAnnouncement(type,pos,text[,color[,is_bright[,unit_a[,unit_d[,is_sparring]]]]])`` + + Takes a ``df.announcement_infost`` (see: + `structure definition `_) + and a string and processes them just like DF does. Can also be built from parameters instead of + an ``announcement_infost``. Setting ``is_sparring`` to ``true`` means the report will be added + to sparring logs (if applicable) rather than hunting or combat. + + The announcement will not display if units are involved and the player can't see + them (or hear, for adventure mode sound announcement types.) + Returns ``true`` if a report was created or repeated. + For detailed info on why an announcement failed to display, enable + ``debugfilter set Debug core gui`` in the DFHack console. + If you want a guaranteed announcement, use ``dfhack.gui.showAutoAnnouncement`` instead. + +* ``dfhack.gui.getMousePos([allow_out_of_bounds])`` + + Returns the map coordinates of the map tile the mouse is over as a table of + ``{x, y, z}``. If the cursor is not over a valid tile, returns ``nil``. To + allow the function to return coordinates outside of the map, set + ``allow_out_of_bounds`` to ``true``. + +Other +~~~~~ + +* ``dfhack.gui.getDepthAt(x, y)`` + + Returns the distance from the z-level of the tile at map coordinates (x, y) to + the closest rendered ground z-level below. Defaults to 0, unless overridden by + plugins. + +Job module +---------- + +* ``dfhack.job.cloneJobStruct(job)`` + + Creates a deep copy of the given job. + +* ``dfhack.job.createLinked()`` + + Create a job and immediately link it into the global job list. + +* ``dfhack.job.printJobDetails(job)`` + + Prints info about the job. + +* ``dfhack.job.printItemDetails(jobitem,idx)`` + + Prints info about the job item. + +* ``dfhack.job.removeJob(job)`` + + Cancels a job, cleans up all references to it, and removes it from the world. + +* ``dfhack.job.addGeneralRef(job, type, id)`` + + Create a general reference of the given type, pointing to the object with the + specified id, and add the created general reference to the provided job. + +* ``dfhack.job.getGeneralRef(job, type)`` + + Searches for a general_ref with the given type. + +* ``dfhack.job.getSpecificRef(job, type)`` + + Searches for a specific_ref with the given type. + +* ``dfhack.job.assignToWorkshop(job, workshop)`` + + Assign job to workshop (i.e. establish the bidirectional link between the job + and the workshop). Does nothing and returns ``false`` if the workshop already + has the maximum of ten jobs. + +* ``dfhack.job.getHolder(job)`` + + Returns the building holding the job. + +* ``dfhack.job.getWorker(job)`` + + Returns the unit performing the job. + +* ``dfhack.job.setJobCooldown(building,worker,cooldown)`` + + Prevent the worker from taking jobs at the specified workshop for the + specified cooldown period (in ticks). This doesn't decrease the cooldown + period in any circumstances. + +* ``dfhack.job.addWorker(job, unit)`` + + Assign the specified job to the provided unit, unless the unit already has an + active job. Also cleans up a potential job posting for the provided job. + +* ``dfhack.job.removeWorker(job,cooldown)`` + + Removes the worker from the specified workshop job, and sets the cooldown + period (using the same logic as ``setJobCooldown``). Returns *true* on + success. + +* ``dfhack.job.checkBuildingsNow()`` + + Instructs the game to check buildings for jobs next frame and assign workers. + +* ``dfhack.job.checkDesignationsNow()`` + + Instructs the game to check designations for jobs next frame and assign workers. + +* ``dfhack.job.is_equal(job1,job2)`` + + Compares important fields in the job and nested item structures. + +* ``dfhack.job.is_item_equal(job_item1,job_item2)`` + + Compares important fields in the job item structures. + +* ``dfhack.job.linkIntoWorld(job,new_id)`` + + Adds job into ``df.global.job_list``, and if new_id + is true, then also sets its id and increases + ``df.global.job_next_id`` + +* ``dfhack.job.listNewlyCreated(first_id)`` + + Returns the current value of ``df.global.job_next_id``, and + if there are any jobs with ``first_id <= id < job_next_id``, + a lua list containing them. + +* ``dfhack.job.attachJobItem(job, item, role, filter_idx, insert_idx)`` + + Attach a real item to this job. If the item is intended to satisfy a job_item + filter, the index of that filter should be passed in ``filter_idx``; otherwise, + pass ``-1``. Similarly, if you don't care where the item is inserted, pass + ``-1`` for ``insert_idx``. The ``role`` param is a ``df.job_role_type``. + If the item needs to be brought to the job site, then the value should be + ``df.job_role_type.Hauled``. + +* ``dfhack.job.isSuitableItem(job_item, item_type, item_subtype)`` + + Does basic sanity checks to verify if the suggested item type matches + the flags in the job item. + +* ``dfhack.job.isSuitableMaterial(job_item, mat_type, mat_index, item_type)`` + + Likewise, if replacing material. + +* ``dfhack.job.getName(job)`` + + Returns the job's description, as seen in the Units and Jobs screens. + +* ``dfhack.job.getManagerOrderName(manager_order)`` + + Returns the manager order's description, as seen in the Work orders screen. + +Hotkey module +------------- + +* ``dfhack.hotkey.addKeybind(keyspec, command)`` + + Creates a new keybind with the provided keyspec (see the `keybinding` documentation + for details on format). + Returns false on failure to create keybind. + +* ``dfhack.hotkey.removeKeybind(keyspec, [match_focus=true, command])`` + + Removes keybinds matching the provided keyspec. + If match_focus is set, the focus portion of the keyspec is matched against. + If command is provided and not an empty string, the command is matched against. + Returns false if no keybinds were removed. + +* ``dfhack.hotkey.listActiveKeybinds()`` + + Returns a list of keybinds active within the current context. + The items are tables with the following attributes: + :spec: The keyspec for the hotkey + :command: The command the hotkey runs when pressed + +* ``dfhack.hotkey.listAllKeybinds()`` + + Returns a list of all keybinds currently registered. + The items are tables with the following attributes: + :spec: The keyspec for the hotkey + :command: The command the hotkey runs when pressed + +* ``dfhack.hotkey.requestKeybindingInput([cancel=false])`` + + Enqueues or cancels a request that the next hotkey-compatible input is saved + and not processed, retrievable with ``dfhack.hotkey.getKeybindingInput()``. + If cancel is true, any current request is cancelled. + +* ``dfhack.hotkey.getKeybindingInput()`` + + Reads the latest saved keybind input that was requested. + Returns a keyspec string for the input, or nil if no input has been saved. + +* ``dfhack.hotkey.isDisruptiveKeybind(keyspec)`` + + Determines if the provided keyspec could be disruptive to the game experience. + This includes the majority of standard characters and special keys such as escape, + backspace, and return when lacking modifiers other than Shift. + +Units module +------------ + +* ``dfhack.units.isActive(unit)`` + + The unit is active (non-dead and on the map). + +* ``dfhack.units.isVisible(unit)`` + + The unit is on a visible map tile. Doesn't account for sneaking. + +* ``dfhack.units.isCitizen(unit[,include_insane])`` + + The unit is a non-dead sane citizen of the fortress; wraps the + same checks the game uses to decide game-over by extinction, + with an additional sanity check. You can identify citizens, + regardless of their sanity, by passing ``true`` as the optional + second parameter. + +* ``dfhack.units.isResident(unit[,include_insane])`` + + The unit is a resident of the fortress. Same ``include_insane`` semantics as + ``isCitizen``. + +* ``dfhack.units.isFortControlled(unit)`` + + Similar to ``dfhack.units.isCitizen(unit)``, but is based on checks + for units hidden in ambush, and includes tame animals. Returns *false* + if not in fort mode. + +* ``dfhack.units.isOwnCiv(unit)`` + + The unit belongs to the player's civilization. + +* ``dfhack.units.isOwnGroup(unit)`` + + The unit belongs to the player's group. + +* ``dfhack.units.isOwnRace(unit)`` + + The unit belongs to the player's race. + +* ``dfhack.units.isAlive(unit)`` + + The unit isn't dead or undead. Naturally inorganic is okay. + +* ``dfhack.units.isDead(unit)`` + + The unit is completely dead and passive, or a ghost. Equivalent to + ``dfhack.units.isKilled(unit) or dfhack.units.isGhost(unit)``. + +* ``dfhack.units.isKilled(unit)`` + + The unit has been killed. + +* ``dfhack.units.isSane(unit)`` + + The unit is normally capable of rational action. I.e., not dead, insane, zombie, + nor crazed (unless active werebeast). + +* ``dfhack.units.isCrazed(unit)`` + + The unit is berserk and will attack all other creatures except crazed members of + its own species. (Can be modified by curses.) + +* ``dfhack.units.isGhost(unit)`` + + The unit is a ghost. + +* ``dfhack.units.isHidden(unit)`` + + The unit is hidden to the player, accounting for sneaking. Works for any game mode. + +* ``dfhack.units.isHidingCurse(unit)`` + + The unit is currently hiding a curse (i.e., vampire). + +* ``dfhack.units.isMale(unit)`` +* ``dfhack.units.isFemale(unit)`` +* ``dfhack.units.isBaby(unit)`` +* ``dfhack.units.isChild(unit)`` +* ``dfhack.units.isAdult(unit)`` + + Simple unit property checks + +* ``dfhack.units.isGay(unit)`` + + Not willing to breed. Also includes any creature caste without a gender. + +* ``dfhack.units.isNaked(unit[,no_items])`` + + Not wearing anything (including rings, etc.). Can optionally check for + empty inventory. + +* ``dfhack.units.isVisiting(unit)`` + + The unit is visiting. E.g., merchants, diplomats, and travelers. + +* ``dfhack.units.isTrainableHunting(unit)`` + + The unit is trainable for hunting. + +* ``dfhack.units.isTrainableWar(unit)`` + + The unit is trainable for war. + +* ``dfhack.units.isTrained(unit)`` + + The unit is trained for hunting or war, or is non-wild and non-domesticated. + +* ``dfhack.units.isHunter(unit)`` + + The unit is a trained hunter. + +* ``dfhack.units.isWar(unit)`` + + The unit is trained for war. + +* ``dfhack.units.isTame(unit)`` +* ``dfhack.units.isTamable(unit)`` +* ``dfhack.units.isDomesticated(unit)`` +* ``dfhack.units.isMarkedForTraining(unit)`` +* ``dfhack.units.isMarkedForTaming(unit)`` +* ``dfhack.units.isMarkedForWarTraining(unit)`` +* ``dfhack.units.isMarkedForHuntTraining(unit)`` +* ``dfhack.units.isMarkedForSlaughter(unit)`` +* ``dfhack.units.isMarkedForGelding(unit)`` +* ``dfhack.units.isGeldable(unit)`` +* ``dfhack.units.isGelded(unit)`` +* ``dfhack.units.isEggLayer(unit)`` +* ``dfhack.units.isEggLayerRace(unit)`` +* ``dfhack.units.isGrazer(unit)`` +* ``dfhack.units.isMilkable(unit)`` + + Simple unit property checks. + +* ``dfhack.units.isForest(unit)`` + + The unit is of the forest. + +* ``dfhack.units.isMischievous(unit)`` + + The unit is mischievous and will randomly pull levers, etc. + +* ``dfhack.units.isAvailableForAdoption(unit)`` + + The unit is available for adoption. + +* ``dfhack.units.isPet(unit)`` + + Unit has pet owner. + +* ``dfhack.units.hasExtravision(unit)`` +* ``dfhack.units.isOpposedToLife(unit)`` +* ``dfhack.units.isBloodsucker(unit)`` + + Simple checks of caste attributes that can be modified by curses. + +* ``dfhack.units.isDwarf(unit)`` + + The unit is of the same race for the fortress. (Includes active werebeasts.) + +* ``dfhack.units.isAnimal(unit)`` +* ``dfhack.units.isMerchant(unit)`` +* ``dfhack.units.isDiplomat(unit)`` + + Simple unit type checks. + +* ``dfhack.units.isVisitor(unit)`` + + The unit is a regular visitor with no special purpose (e.g., merchant). + +* ``dfhack.units.isWildlife(unit)`` + + The unit is surface or cavern wildlife. + +* ``dfhack.units.isAgitated(unit)`` + + The unit is an agitated creature. + +* ``dfhack.units.isInvader(unit)`` + + The unit is an active invader or marauder. + +* ``dfhack.units.isUndead(unit[,hiding_curse])`` + + The unit is undead. Pass ``true`` as the optional second parameter to + count undead hiding their curse (i.e., vampires). + +* ``dfhack.units.isNightCreature(unit)`` +* ``dfhack.units.isSemiMegabeast(unit)`` +* ``dfhack.units.isMegabeast(unit)`` +* ``dfhack.units.isTitan(unit)`` +* ``dfhack.units.isForgottenBeast(unit)`` +* ``dfhack.units.isDemon(unit)`` + + Simple enemy type checks. + +* ``dfhack.units.isDanger(unit)`` + + The unit is dangerous and probably hostile. This includes night creatures, + semi-megabeasts, invaders, agitated wildlife, crazed units, and Great Dangers + (see below). + +* ``dfhack.units.isGreatDanger(unit)`` + + The unit is of Great Danger. This includes megabeasts, titans, + forgotten beasts, and demons. + +* ``dfhack.units.isUnitInBox(unit, pos1, pos2)`` +* ``dfhack.units.isUnitInBox(unit,x1,y1,z1,x2,y2,z2)`` + + Returns true if the unit is within a box defined by the + specified coordinates. + +* ``dfhack.units.getUnitsInBox(pos1, pos2[, filter])`` +* ``dfhack.units.getUnitsInBox(x1,y1,z1,x2,y2,z2[,filter])`` + + Returns a table of all units within the specified coordinates. + If the ``filter`` argument is given, only units where ``filter(unit)`` + returns true will be included. + +* ``dfhack.units.getUnitByNobleRole(role_name)`` + + Returns the unit assigned to the given noble role, if any. + ``role_name`` must be one of the position codes associated with the + active fort or civilization government. For example: + ``CAPTAIN_OF_THE_GUARD``, ``MAYOR``, or ``BARON``. + Note that if more than one unit has the role, only the first will be + returned. See ``getUnitsByNobleRole`` below for retrieving all units + with a particular role. + +* ``dfhack.units.getUnitsByNobleRole(role_name)`` + + Returns a list of units (possibly empty) assigned to the given noble role. + +* ``dfhack.units.getCitizens([exclude_residents[,include_insane]])`` + + Returns a list of all living, sane citizens and residents that are + currently on the map. Can ``exclude_residents`` or ``include_insane`` + (both default to ``false``). + +* ``dfhack.units.getPosition(unit)`` + + Returns the true *x,y,z* of the unit, or *nil* if invalid. You should + generally use this method instead of reading *unit.pos* directly since + that field can be inaccurate when the unit is caged. + +* ``dfhack.units.teleport(unit, pos)`` + + Moves the specified unit and any riders to the target coordinates, setting + tile occupancy flags appropriately. Returns true if successful. + +* ``dfhack.units.getGeneralRef(unit, type)`` + + Searches for a ``general_ref`` with the given type. + +* ``dfhack.units.getSpecificRef(unit, type)`` + + Searches for a ``specific_ref`` with the given type. + +* ``dfhack.units.getContainer(unit)`` + + Returns the container (i.e., cage) holding the unit or *nil*. + +* ``dfhack.units.getOuterContainerRef(unit)`` + + Returns a table (in the style of a ``specific_ref`` struct) of the + outermost object that contains the unit (or one of the unit itself). + The ``type`` field contains a + ``specific_ref_type`` of ``UNIT``, ``ITEM_GENERAL``, or ``VERMIN_EVENT``. + The ``object`` field contains a pointer to a unit, item, or vermin, + respectively. + +* ``dfhack.units.getIdentity(unit)`` + + Returns the false identity of the unit if it has one, or *nil*. + +* ``dfhack.units.getNemesis(unit)`` + + Returns the nemesis record of the unit if it has one, or *nil*. + +* ``dfhack.units.setNickname(unit, nick)`` + + Sets the unit's nickname properly. + +* ``dfhack.units.getVisibleName(unit)`` + + Returns the ``language_name`` object visible in game, accounting for + false identities. + +* ``dfhack.units.assignTrainer(unit[,trainer_id])`` +* ``dfhack.units.unassignTrainer(unit)`` + + Assigns (or unassigns) a trainer for the specified trainable unit. The + trainer ID can be omitted if "any trainer" is desired. Returns a boolean + indicating whether the operation was successful. + +* ``dfhack.units.makeown(unit)`` + + Makes the selected unit a member of the current fortress and site. + Note that this operation may silently fail for any of several reasons, + so it may be prudent to check if the operation has succeeded by using + ``dfhack.units.isOwnCiv`` or another appropriate predicate on the unit + in question. + +* ``dfhack.units.setPathGoal(unit, pos, goal)`` + + Set target coordinates and goal (of type ``df.unit_path_goal``) for the given + unit. In case of a change, also clears the unit's current path. + +* ``dfhack.units.create(race, caste)`` + + Creates a new unit from scratch. The unit will be added to the + ``world.units.all`` vector, but not to the ``world.units.active`` vector. + The unit will not have an associated historical figure, nemesis record, + map position, labors, or any group associations. The unit *will* have a + race, caste, name, soul, and initialized body and mind (including + personality). The unit must be configured further as needed and put into + play by the client. + +* ``dfhack.units.getCasteRaw(unit)`` +* ``dfhack.units.getCasteRaw(race, caste)`` + + Returns the relevant ``caste_raw`` or *nil*. + +* ``dfhack.units.getPhysicalAttrValue(unit, attr_type)`` +* ``dfhack.units.getMentalAttrValue(unit, attr_type)`` + + Computes the effective attribute value, including curse effect. + +* ``dfhack.units.casteFlagSet(race, caste, flag)`` + + Returns whether the given ``df.caste_raw_flags`` flag is set for the given + race and caste. + +* ``dfhack.units.getMiscTrait(unit, type[, create])`` + + Finds (or creates if requested) a misc trait object with the given id. + +* ``dfhack.units.getRaceNameById(race)`` +* ``dfhack.units.getRaceName(unit)`` + + Get raw token name (e.g., "DWARF"). + +* ``dfhack.units.getRaceReadableNameById(race)`` +* ``dfhack.units.getRaceReadableName(unit)`` +* ``dfhack.units.getRaceNamePluralById(race)`` +* ``dfhack.units.getRaceNamePlural(unit)`` + + Get human-readable name (e.g., "dwarf" or "dwarves"). + +* ``dfhack.units.getRaceBabyNameById(race[,plural])`` +* ``dfhack.units.getRaceBabyName(unit[,plural])`` +* ``dfhack.units.getRaceChildNameById(race[,plural])`` +* ``dfhack.units.getRaceChildName(unit[,plural])`` + + Get human-readable baby or child name (e.g., "dwarven baby" or + "dwarven child"). + +* ``dfhack.units.getReadableName(unit or historical_figure[, skip_english])`` + + Returns a string that includes the native and english language name (if + ``skip_english`` is not ``true``) of the unit (if any), the race of the unit + (if different from fort), whether it is trained for war or hunting, any + syndrome-given descriptions (such as "necromancer"), the training level (if + tame), and profession or noble role. If a ``historical_figure`` is passed + instead of a unit, some information (e.g., agitation status) is not + available, and the profession may be different (e.g., "Monk") from what is + displayed in fort mode. + +* ``dfhack.units.getAge(unit[, true_age])`` + + Returns the age of the unit in years as a floating-point value. + If ``true_age`` is true, ignores false identities. + +* ``dfhack.units.getKillCount(unit)`` + + Returns the number of units the unit has killed. + +* ``dfhack.units.getNominalSkill(unit, skill[, use_rust])`` + + Retrieves the nominal skill level for the given unit. If ``use_rust`` + is *true*, subtracts the rust penalty. + +* ``dfhack.units.getEffectiveSkill(unit, skill)`` + + Computes the effective rating for the given skill, taking into account + skill rust, exhaustion, pain, etc. + +* ``dfhack.units.getExperience(unit, skill[, total])`` + + Returns the experience value for the given skill. If ``total`` is true, + adds experience implied by the current skill level. + +* ``dfhack.units.isValidLabor(unit, unit_labor)`` + + Returns whether the indicated labor is settable for the given unit. + +* ``dfhack.units.setLaborValidity(unit_labor, isValid)`` + + Sets the given labor to the given (boolean) validity for all units that are + part of your fortress civilization. Valid labors are allowed to be toggled + in the in-game labor management screens (including DFHack's `labor + manipulator screen `). + +* ``dfhack.units.setAutomaticProfessions(unit)`` + + Set appropriate labors on a unit based on current work detail settings. + +* ``dfhack.units.computeMovementSpeed(unit)`` + + Computes number of frames * 100 it takes the unit to move in its current + state of mind and body. **Currently broken due to move speed changes, + will always return 0!** + +* ``dfhack.units.computeSlowdownFactor(unit)`` + + Meandering and floundering in liquid introduces additional slowdown. + It is random, but the function computes and returns the expected mean + factor as a float. + +* ``dfhack.units.getNoblePositions(unit or historical_figure)`` + + Returns a list of tables describing noble position assignments, or *nil*. + Every table has fields ``entity``, ``assignment``, and ``position``. + +* ``dfhack.units.getProfession(unit)`` + + Returns unit's profession ID (``df.profession``), accounting for + false identity. + +* ``dfhack.units.getProfessionName(unit[,ignore_noble[,plural[,land_title]]])`` +* ``dfhack.units.getProfessionName(historical_figure[,ignore_noble[,plural[,land_title]]])`` + + Retrieves the profession name using custom profession, noble assignments, + or raws. The ``ignore_noble`` boolean disables the use of noble positions + ("Prisoner", "Slave", and noble spouse titles included). The ``land_title`` + boolean causes ``of Sitename`` to be appended when applicable. If a + ``historical_figure`` is passed instead of a unit, some information (e.g., + agitation status) is not available, and the profession may be different + (e.g., "Monk") from what is displayed in fort mode. + +* ``dfhack.units.getCasteProfessionName(race, caste, prof_id[, plural])`` + + Retrieves the profession name for the given race and caste using raws. + +* ``dfhack.units.getProfessionColor(unit[,ignore_noble])`` + + Retrieves the color associated with the profession, using noble assignments + or raws. The ``ignore_noble`` boolean disables the use of noble positions. + +* ``dfhack.units.getCasteProfessionColor(race, caste, prof_id)`` + + Retrieves the profession color for the given race and caste using raws. + +* ``dfhack.units.getGoalType(unit[,goalIndex])`` + + Retrieves the goal type of the dream that the given unit has. + By default the goal of the first dream is returned. + The ``goalIndex`` parameter may be used to retrieve additional dream goals. + Currently only one dream per unit is supported by Dwarf Fortress. + Support for multiple dreams may be added in future versions of + Dwarf Fortress. + +* ``dfhack.units.getGoalName(unit[,goalIndex])`` + + Retrieves the short name describing the goal of the dream that the given + unit has. By default the goal of the first dream is returned (see above). + +* ``dfhack.units.isGoalAchieved(unit[,goalIndex])`` + + Checks if given unit has achieved the goal of the dream. + By default the status of the goal of the first dream is returned (see above). + +* ``dfhack.units.getMainSocialActivity(unit)`` +* ``dfhack.units.getMainSocialEvent(unit)`` + + Return the ``df.activity_entry`` or ``df.activity_event`` representing the + unit's current social activity. + +* ``dfhack.units.hasUnbailableSocialActivity(unit)`` + + Unit has an uninterruptible social activity (e.g. a purple "Socialize!"). + +* ``dfhack.units.isJobAvailable(unit [, preserve_social])`` + + Check whether a unit can be assigned to (i.e. is looking for) a job. Will + return ``true`` if the unit is engaged in "green" social activities, unless + the boolean ``preserve_social`` is true. Will never interrupt uninterruptible + social activities (e.g. a purple "Socialize!"). + +* ``dfhack.units.getFocusPenalty(unit, need_type [, need_type, ...])`` + + Get largest (i.e. most negative) focus penalty associated to a collection of + ``df.need_type`` arguments. Returns a number strictly greater than 400 if the + unit does not have any of the requested needs. + +* ``dfhack.units.getStressCategory(unit)`` + + Returns a number from 0-6 indicating stress. 0 is most stressed; 6 is least. + Note that 0 is guaranteed to remain the most stressed but 6 could change in + the future. + +* ``dfhack.units.getStressCategoryRaw(stress_level)`` + + Identical to ``getStressCategory`` but takes a raw stress level instead + of a unit. + +* ``dfhack.units.getStressCutoffs()`` + + Returns a table of the cutoffs used by the above stress level functions. + +Action Timer API +~~~~~~~~~~~~~~~~ + +This is an API to allow manipulation of unit action timers, to speed them up or slow +them down. All functions in this API have overflow/underflow protection when modifying +action timers (the value will cap out). Actions with a timer of 0 (or less) will not +be modified as they are completed (or invalid in the case of negatives). +Timers will be capped to go no lower than 1. +``affectedActionType`` parameters are values from the DF enum ``unit_action_type`` +(e.g., ``df.unit_action_type.Move``). +``affectedActionTypeGroup`` parameters are values from the (custom) DF enum +``unit_action_type_group`` (see +`unit_action_type definition `_ +for which action types each group contains). They are as follows: + + * ``All`` + * ``Movement`` + * ``MovementFeet`` (affects only walking and crawling speed. If you need to + differentiate between walking and crawling, check the unit's ``flags1.on_ground`` flag, + like the Pegasus boots do in the `modding-guide`). + * ``MovementFeet`` (for walking speed, such as with pegasus boots from the `modding-guide`). + * ``Combat`` (includes bloodsucking). + * ``Work`` + +API functions: + +* ``dfhack.units.subtractActionTimers(unit, amount, affectedActionType)`` + + Subtract ``amount`` (32-bit integer) from the timers of any actions the unit is performing + of ``affectedActionType`` (usually one or zero actions in normal gameplay). Negative + amount adds to timers. + +* ``dfhack.units.subtractGroupActionTimers(unit, amount, affectedActionTypeGroup)`` + + Subtract ``amount`` (32-bit integer) from the timers of any actions the unit is performing + that match the ``affectedActionTypeGroup`` category. Negative amount adds to timers. + +* ``dfhack.units.multiplyActionTimers(unit, amount, affectedActionType)`` + + Multiply the timers of any actions of ``affectedActionType`` the unit is performing by + ``amount`` (float) (usually one or zero actions in normal gameplay). + +* ``dfhack.units.multiplyGroupActionTimers(unit, amount, affectedActionTypeGroup)`` + + Multiply the timers of any actions that match the ``affectedActionTypeGroup`` category + the unit is performing by ``amount`` (float). + +* ``dfhack.units.setActionTimers(unit, amount, affectedActionType)`` + + Set the timers of any action the unit is performing of ``affectedActionType`` to ``amount`` + (32-bit integer) (usually one or zero actions in normal gameplay). + +* ``dfhack.units.setGroupActionTimers(unit, amount, affectedActionTypeGroup)`` + + Set the timers of any action the unit is performing that match the + ``affectedActionTypeGroup`` category to ``amount`` (32-bit integer). + +Military module +--------------- + +* ``dfhack.military.makeSquad(assignment_id)`` + + Creates a new squad associated with the assignment (i.e., + ``df::entity_position_assignment``, via ``id``) and returns it. + Fails if a squad already exists that is associated with that assignment, or if + the assignment is not a fort mode player controlled squad. + Note: This function does not name the squad. Consider setting a nickname + (under ``squad.name.nickname``), and/or filling out the ``language_name`` object + at ``squad.name``. The returned squad is otherwise complete and requires no more + setup to work correctly. + +* ``dfhack.military.updateRoomAssignments(squad_id, assignment_id, squad_use_flags)`` + + Sets the sleep, train, indiv_eq, and squad_eq flags when training at a barracks. + +* ``dfhack.military.getSquadName(squad_id)`` + + Returns the name of a squad as a string. + +* ``dfhack.military.removeFromSquad(unit_id)`` + + Removes a unit from its squad. Unsets the unit's + military information (i.e., ``unit.military.squad_id`` and + ``unit.military.squad_pos``), the squad's position information (i.e., + ``squad.positions[squad_pos].occupant``), modifies the unit's entity links + to indicate former squad membership or command, and creates a corresponding + world history event. + + * ``dfhack.military.addToSquad(unit_id, squad_id, squad_pos)`` + + Adds a unit to a squad. Sets the unit's + military information (i.e., ``unit.military.squad_id`` and + ``unit.military.squad_pos``), the squad's position information (i.e., + ``squad.positions[squad_pos].occupant``), adds a unit's entity links to + indicate squad membership. Does not currently add world history events. + If ``squad_pos`` is -1, the unit will be added to the first open slot in + the squad. + + This API cannot be used to set or change the leader of a squad and will fail + if ``squad_pos`` is specified as 0 or if ``squad_pos`` is specified as -1 and + the squad leader position is currently vacant. It will also fail if + the requested squad position is already occupied, the squad does not exist, + the unit does not exist, or the requested unit is already a member of another + squad. + +Items module +------------ + +* ``dfhack.items.findType(string)`` + + Finds an item type by string and returns the ``df.item_type``. String is + case-sensitive (e.g., "TOOL"). + +* ``dfhack.items.findSubtype(string)`` + + Finds an item subtype by string and returns the subtype or *-1*. String is + case-sensitive (e.g., "TOOL:ITEM_TOOL_HIVE"). + +* ``dfhack.items.isCasteMaterial(item_type)`` + + Returns *true* if this item type uses a creature/caste pair as its material. + +* ``dfhack.items.getSubtypeCount(item_type)`` + + Returns the number of raw-defined subtypes of the given item type, or *-1* + if not applicable. + +* ``dfhack.items.getSubtypeDef(item_type, subtype)`` + + Returns the raw definition for the given item type and subtype, or *nil* + if invalid. + +* ``dfhack.items.getGeneralRef(item, type)`` + + Searches for a general_ref with the given type. + +* ``dfhack.items.getSpecificRef(item, type)`` + + Searches for a specific_ref with the given type. + +* ``dfhack.items.getOwner(item)`` + + Returns the owner unit or *nil*. + +* ``dfhack.items.setOwner(item,unit)`` + + Replaces the owner of the item. If unit is *nil*, removes ownership. + Returns *false* in case of error. + +* ``dfhack.items.getContainer(item)`` + + Returns the item's container item or *nil*. + +* ``dfhack.items.getOuterContainerRef(item)`` + + Returns a table (in the style of a ``specific_ref`` struct) of the outermost object + that contains the item (or one of the item itself.) The ``type`` field contains a + ``specific_ref_type`` of ``UNIT``, ``ITEM_GENERAL``, or ``VERMIN_EVENT``. + The ``object`` field contains a pointer to a unit, item, or vermin, respectively. + +* ``dfhack.items.getContainedItems(item)`` + + Returns a list of items contained in this one. + +* ``dfhack.items.getHolderBuilding(item)`` + + Returns the holder building or *nil*. + +* ``dfhack.items.getHolderUnit(item)`` + + Returns the holder unit or *nil*. + +* ``dfhack.items.getPosition(item)`` + + Returns the true *x,y,z* of the item, or *nil* if invalid. You should generally + use this method instead of reading *item.pos* directly since that field only stores + the last position where the item was on the ground. + +* ``dfhack.items.getBookTitle(item)`` + + Returns the title of the "book" item, or an empty string if the item isn't a "book" + or it doesn't have a title. A "book" is a codex or a tool item that has page or + writing improvements, such as scrolls and quires. + +* ``dfhack.items.getDescription(item, type[, decorate])`` + + Returns the string description of the item, as produced by the ``getItemDescription`` + method. A ``type`` of ``0`` results in a string like ``prickle berries [2]``. ``1`` + results in the singular ``prickle berry``, and ``2`` results in the plural + ``prickle berries``. If decorate is *true*, also adds markings for quality and + improvements, as well as ``(foreign)`` indicator (when applicable). + +* ``dfhack.items.getReadableDescription(item)`` + + Returns a string generally fit to usefully describe the item to the player. + When the item description appears anywhere in a script output or in the UI, + this is usually the string you should use. + +* ``dfhack.items.moveToGround(item,pos)`` + + Move the item to the ground at position. Returns *false* if impossible. + +* ``dfhack.items.moveToContainer(item,container)`` + + Move the item to the container. Returns *false* if impossible. + +* ``dfhack.items.moveToBuilding(item,building[,use_mode[,force_in_building])`` + + Move the item to the building. Returns *false* if impossible. + ``use_mode`` defaults to ``df.building_item_role_type.TEMP``. + If set to ``df.building_item_role_type.PERM``, the item will be treated as part + of the building. If ``force_in_building`` is true, the item will be considered + to be stored by the building (used for items temporarily used in traps in + vanilla DF). + +* ``dfhack.items.moveToInventory(item,unit[,use_mode[,body_part]])`` + + Move the item to the unit inventory. Returns *false* if impossible. + ``use_mode`` defaults to ``df.inv_item_role_type.Hauled``. + ``body_part`` defaults to ``-1``. + +* ``dfhack.items.remove(item[,no_uncat])`` + + Cancels any jobs associated with the item, removes the item from containers + and inventories, hides the item from the UI, and, unless ``no_uncat`` is + true, marks it for garbage collection. + +* ``dfhack.items.makeProjectile(item)`` + + Turns the item into a projectile, and returns the new object, or *nil* + if impossible. + +* ``dfhack.items.getItemBaseValue(item_type, subtype, material, mat_index)`` + + Calculates the base value for an item of the specified type and material. + +* ``dfhack.items.getValue(item[,caravan_state])`` + + Calculates the value of an item. If a ``df.caravan_state`` object is given + (from ``df.global.plotinfo.caravans`` or + ``df.global.game.main_interface.trade.mer``), then the value is modified by civ + properties and any trade agreements that might be in effect. + +* ``dfhack.items.createItem(unit, item_type, item_subtype, mat_type, mat_index, no_floor)`` + + Creates an item, similar to the `createitem` plugin. Returns a list of created + ``df.item`` objects. + +* ``dfhack.items.checkMandates(item)`` + + Returns true if the item is free from mandates, or false if mandates prevent + trading the item. + +* ``dfhack.items.canTrade(item)`` + + Checks whether the item can be traded. + +* ``dfhack.items.canTradeWithContents(item)`` + + Returns false if the item or any contained items cannot be traded. + +* ``canTradeAnyWithContents(item)`` + + Returns true if the item is empty and can be traded or if the item contains + any item that can be traded. + +* ``dfhack.items.markForTrade(item, depot)`` + + Marks the given item for trade at the given depot. + +* ``dfhack.items.isRequestedTradeGood(item[,caravan_state])`` + + Returns whether a caravan will pay extra for the given item. If caravan_state + is not given, checks all active caravans. + +* ``dfhack.items.canMelt(item[,game_ui])`` + + Returns true if the item can be melted (at a smelter). Unless ``game_ui`` is + given and true, bars, non-empty metal containers, and items in unit + inventories are not considered meltable, even though they can be designated + for melting using the game UI. + +* ``dfhack.items.markForMelting(item)`` + + Marks the given item for melting, unless already marked. Returns true if the + melting status was changed. + +* ``dfhack.items.cancelMelting(item)`` + + Removes melting designation, if present, from the given item. Returns true if + the melting status was changed. + +* ``dfhack.items.isRouteVehicle(item)`` + + Checks whether the item is an assigned hauling vehicle. + +* ``dfhack.items.isSquadEquipment(item)`` + + Checks whether the item is assigned to a squad. + +* ``dfhack.items.getCapacity(item)`` + + Returns the capacity volume of an item that can serve as a container for + other items. Return value will be ``0`` for items that cannot serve as a + container. + +.. _lua-world: + +World module +------------ + +* ``dfhack.world.ReadPauseState()`` + + Returns *true* if the game is paused. + +* ``dfhack.world.SetPauseState(paused)`` + + Sets the pause state of the game. + +* ``dfhack.world.ReadCurrentYear()`` + + Returns the current game year. + +* ``dfhack.world.ReadCurrentTick()`` + + Returns the number of game ticks (``df.global.world.frame_counter``) since the + start of the current game year. + +* ``dfhack.world.ReadCurrentMonth()`` + + Returns the current game month, ranging from 0-11. The Dwarven year has 12 months. + +* ``dfhack.world.ReadCurrentDay()`` + + Returns the current game day, ranging from 1-28. Each Dwarven month has 28 days. + +* ``dfhack.world.ReadCurrentWeather()`` + + Returns the current game weather (``df.weather_type``). + +* ``dfhack.world.SetCurrentWeather(weather)`` + + Sets the current game weather to ``weather``. + +* ``dfhack.world.ReadWorldFolder()`` + + Returns the name of the directory/folder the current saved game is under, or an + empty string if no game was loaded this session. + +* ``dfhack.world.isFortressMode([gametype])`` +* ``dfhack.world.isAdventureMode([gametype])`` +* ``dfhack.world.isArena([gametype])`` +* ``dfhack.world.isLegends([gametype])`` + + Without any arguments, returns *true* if the current gametype matches. + Optionally accepts a ``gametype`` id to match against. + +* ``dfhack.world.getCurrentSite()`` + + Returns the currently loaded ``df.world_site`` or ``nil`` if no site is loaded. + +* ``dfhack.world.getAdventurer()`` + + Returns the current adventurer unit (if in adventure mode). + +.. _lua-maps: + +Maps module +----------- + +* ``dfhack.maps.getSize()`` + + Returns map size in blocks: *x, y, z* + +* ``dfhack.maps.getTileSize()`` + + Returns map size in tiles: *x, y, z* + +* ``dfhack.maps.getBlock(x,y,z)`` + + Returns a map block object for given x,y,z in local block coordinates. + +* ``dfhack.maps.isValidTilePos(coords)``, or ``isValidTilePos(x,y,z)`` + + Checks if the given df::coord or x,y,z in local tile coordinates are valid. + +* ``dfhack.maps.isTileVisible(coords)``, or ``isTileVisible(x,y,z)`` + + Checks if the given df::coord or x,y,z in local tile coordinates is visible. + +* ``dfhack.maps.getTileBlock(coords)``, or ``getTileBlock(x,y,z)`` + + Returns a map block object for given df::coord or x,y,z in local + tile coordinates. + +* ``dfhack.maps.ensureTileBlock(coords)``, or ``ensureTileBlock(x,y,z)`` + + Like ``getTileBlock``, but if the block is not allocated, try creating it. + +* ``dfhack.maps.getTileType(coords)``, or ``getTileType(x,y,z)`` + + Returns the tile type at the given coordinates, or *nil* if invalid. + +* ``dfhack.maps.getTileFlags(coords)``, or ``getTileFlags(x,y,z)`` + + Returns designation and occupancy references for the given coordinates, or + *nil, nil* if invalid. + +* ``dfhack.maps.getRegionBiome(region_coord2d)``, or ``getRegionBiome(x,y)`` + + Returns the biome info struct for the given global map region. + + ``dfhack.maps.getBiomeType(region_coord2d)`` or ``getBiomeType(x,y)`` + + Returns the biome_type for the given global map region. + +* ``dfhack.maps.enableBlockUpdates(block[,flow[,temperature]])`` + + Enables updates for liquid flow or temperature, unless already active. + +* ``dfhack.maps.spawnFlow(pos,type,mat_type,mat_index,dimension)`` + + Spawns a new flow (i.e., steam/mist/dust/etc) at the given pos, and with + the given parameters. Returns it, or *nil* if unsuccessful. + +* ``dfhack.maps.getGlobalInitFeature(index)`` + + Returns the global feature object with the given index. + +* ``dfhack.maps.getLocalInitFeature(region_coord2d,index)`` + + Returns the local feature object with the given region coords and index. + +* ``dfhack.maps.getTileBiomeRgn(coords)``, or ``getTileBiomeRgn(x,y,z)`` + + Returns *x, y* for use with ``getRegionBiome`` and ``getBiomeType``. + +* ``dfhack.maps.getPlantAtTile(pos)``, or ``getPlantAtTile(x,y,z)`` + + Returns the plant struct that owns the tile at the specified position. + +* ``dfhack.maps.getWalkableGroup(pos)`` + + Returns the walkability group for the given tile position. A return value + of ``0`` indicates that the tile is not walkable. The data comes from a + pathfinding cache maintained by DF. + + .. note:: + This cache is only updated when the game is unpaused, and thus + can get out of date if doors are forbidden or unforbidden, or + tools like `liquids` or `tiletypes` are used. It also cannot possibly + take into account anything that depends on the actual units, like + burrows, or the presence of invaders. + +* ``dfhack.maps.canWalkBetween(pos1, pos2)`` + + Checks if both positions are walkable and also share a walkability group. + +* ``dfhack.maps.hasTileAssignment(tilemask)`` + + Checks if the tile_bitmask object is not *nil* and contains any set bits. + Returns *true* or *false*. + +* ``dfhack.maps.getTileAssignment(tilemask,x,y)`` + + Checks if the tile_bitmask object is not *nil* and has the relevant bit set. + Returns *true* or *false*. + +* ``dfhack.maps.setTileAssignment(tilemask,x,y,enable)`` + + Sets the relevant bit in the tile_bitmask object to the *enable* argument. + +* ``dfhack.maps.resetTileAssignment(tilemask[,enable])`` + + Sets all bits in the mask to the *enable* argument. + +* ``dfhack.maps.isTileAquifer(pos)``, or ``isTileAquifer(x,y,z)`` + + Checks if there's an aquifer on the given tile position. + Returns *true* or *false*. + +* ``dfhack.maps.isTileHeavyAquifer(pos)``, or ``isTileHeavyAquifer(x,y,z)`` + + Checks if there's a heavy aquifer on the given tile position. + Returns *true* or *false*. + +* ``dfhack.maps.setTileAquifer(pos[,heavy])``, or ``setTileAquifer(x,y,z[,heavy])`` + + Adds a light aquifer on the given tile position, or a heavy aquifer if the + *heavy* argument is *true*. Returns *true* or *false* depending on success. + +* ``dfhack.maps.removeTileAquifer(pos)``, or ``removeTileAquifer(x,y,z)`` + + Removes an aquifer from the given tile position. + Returns *true* or *false* depending on success. + +* ``dfhack.maps.addMaterialSpatter(pos, mat, matg, state, amount)`` + + Adds a material spatter to the specified map tile. If the tile is already + full of that spatter, returns the amount left over. + + Specifying a state of -1 (None) will automatically choose either Solid, + Liquid, or Gas based on the material properties and the tile temperature. + +* ``dfhack.maps.addItemSpatter(pos, i_type, i_subtype, subcat1, subcat2, print_variant, amount)`` + + Adds an item spatter to the specified map tile. If the tile is already + full of that spatter, returns the amount left over. + + For plant growths, specifying a print_variant of -1 will automatically + choose an appropriate value. For other item types, this field is ignored. + +Burrows module +-------------- + +* ``dfhack.burrows.getName(burrow)`` + + Returns the name of the burrow. + If the burrow has no set name, returns the same placeholder name that DF would show in the UI. + +* ``dfhack.burrows.findByName(name[, ignore_final_plus])`` + + Returns the burrow pointer or *nil*. if ``ignore_final_plus`` is ``true``, + then ``+`` characters at the end of the names are ignored, both for the + specified ``name`` and the names of the burrows that it matches against. + +* ``dfhack.burrows.clearUnits(burrow)`` + + Removes all units from the burrow. + +* ``dfhack.burrows.isAssignedUnit(burrow,unit)`` + + Checks if the unit is in the burrow. + +* ``dfhack.burrows.setAssignedUnit(burrow,unit,enable)`` + + Adds or removes the unit from the burrow. + +* ``dfhack.burrows.clearTiles(burrow)`` + + Removes all tiles from the burrow. + +* ``dfhack.burrows.listBlocks(burrow)`` + + Returns a table of map block pointers. + +* ``dfhack.burrows.isAssignedTile(burrow,tile_coord)`` + + Checks if the tile is in burrow. + +* ``dfhack.burrows.setAssignedTile(burrow,tile_coord,enable)`` + + Adds or removes the tile from the burrow. + Returns *false* if invalid coords. + +* ``dfhack.burrows.isAssignedBlockTile(burrow,block,x,y)`` + + Checks if the tile within the block is in burrow. + +* ``dfhack.burrows.setAssignedBlockTile(burrow,block,x,y,enable)`` + + Adds or removes the tile from the burrow. + Returns *false* if invalid coords. + +Buildings module +---------------- + +General +~~~~~~~ + +* ``dfhack.buildings.getGeneralRef(building, type)`` + + Searches for a general_ref with the given type. + +* ``dfhack.buildings.getSpecificRef(building, type)`` + + Searches for a specific_ref with the given type. + +* ``dfhack.buildings.getOwner(civzone)`` + + Returns the owner of the zone or *nil* if there isn't one. + +* ``dfhack.buildings.setOwner(civzone,unit)`` + + Replaces the owner of the civzone. If unit is *nil*, removes ownership. + Returns *false* in case of error. + + ``dfhack.buildings.getName(building)`` + + Returns the name of the building as it would appear in game. + +* ``dfhack.buildings.getSize(building)`` + + Returns *width, height, centerx, centery*. + +* ``dfhack.buildings.findAtTile(pos)``, or ``findAtTile(x,y,z)`` + + Scans the buildings for the one located at the given tile. + Does not work on civzones. Warning: linear scan if the map + tile indicates there are buildings at it. + +* ``dfhack.buildings.findCivzonesAt(pos)``, or ``findCivzonesAt(x,y,z)`` + + Scans civzones, and returns a lua sequence of those that touch + the given tile, or *nil* if none. + +* ``dfhack.buildings.getCorrectSize(width, height, type, subtype, custom, direction)`` + + Computes correct dimensions for the specified building type and orientation, + using width and height for flexible dimensions. + Returns *is_flexible, width, height, center_x, center_y*. + +* ``dfhack.buildings.checkFreeTiles(pos,size[,bld[,change_extents[,allow_occupied[,allow_wall[,allow_flow]]]]])`` + + Checks if the rectangle defined by ``pos`` and ``size``, and possibly the + extents associated with bld, can be used for placing a building. If + ``change_extents`` is true, bad tiles are removed from extents. If + ``allow_occupied``, the occupancy test is skipped. Set ``allow_wall`` to true + if the building is unhindered by walls (such as an activity zone). Set + ``allow_flow`` to true if the building can be built even if there is deep + water or any magma on the tile (such as abstract buildings). + +* ``dfhack.buildings.countExtentTiles(extents,defval)`` + + Returns the number of tiles included by extents, or defval. + +* ``dfhack.buildings.containsTile(building, x, y)`` + + Checks if the building contains the specified tile. If the building contains + extents, then the extents are checked. Otherwise, returns whether the x and y + map coordinates are within the building's bounding box. + +* ``dfhack.buildings.hasSupport(pos,size)`` + + Checks if a bridge constructed at specified position would have + support from terrain, and thus won't collapse if retracted. + +* ``dfhack.buildings.getStockpileContents(stockpile)`` + + Returns a list of items stored on the given stockpile. + Ignores empty bins, barrels, and wheelbarrows assigned as storage and + transport for that stockpile. + +* ``dfhack.buildings.getCageOccupants(cage)`` + + Returns a list of units in the given built cage. Note that this is different + from the list of units assigned to the cage, which can be accessed with + ``cage.assigned_units``. + +Low-level +~~~~~~~~~ +Low-level building creation functions: + +* ``dfhack.buildings.allocInstance(pos, type, subtype, custom)`` + + Creates a new building instance of given type, subtype and custom type, + at specified position. Returns the object, or *nil* in case of an error. + +* ``dfhack.buildings.setSize(building, width, height, direction)`` + + Configures an object returned by ``allocInstance``, using specified + parameters wherever appropriate. If the building has fixed size along + any dimension, the corresponding input parameter will be ignored. + Returns *false* if the building cannot be placed, or *true, width, + height, rect_area, true_area*. Returned width and height are the + final values used by the building; true_area is less than rect_area + if any tiles were removed from designation. You can specify a non-rectangular + designation for building types that support extents by setting the + ``room.extents`` bitmap before calling this function. The extents will be + reset, however, if the size returned by this function doesn't match the + input size parameter. + +* ``dfhack.buildings.constructAbstract(building)`` + + Links a fully configured object created by ``allocInstance`` into the + world. The object must be an abstract building, i.e., a stockpile or civzone. + Returns *true*, or *false* if impossible. + +* ``dfhack.buildings.constructWithItems(building, items)`` + + Links a fully configured object created by ``allocInstance`` into the + world for construction, using a list of specific items as material. + Returns *true*, or *false* if impossible. + +* ``dfhack.buildings.constructWithFilters(building, job_items)`` + + Links a fully configured object created by ``allocInstance`` into the + world for construction, using a list of job_item filters as inputs. + Returns *true*, or *false* if impossible. Filter objects are claimed + and possibly destroyed in any case. + Use a negative ``quantity`` field value to auto-compute the amount + from the size of the building. + +* ``dfhack.buildings.deconstruct(building)`` + + Destroys the building, or queues a deconstruction job. + Returns *true* if the building was destroyed and deallocated immediately. + +* ``dfhack.buildings.notifyCivzoneModified(building)`` + + Rebuilds the civzone <-> overlapping building association mapping. + Call after changing extents or modifying size in some fashion + +* ``dfhack.buildings.markedForRemoval(building)`` + + Returns *true* if the building is marked for removal (with :kbd:`x`), *false* + otherwise. + +* ``dfhack.buildings.getRoomDescription(building[, unit])`` + + If the building is a room, returns a description including quality modifiers, + e.g., "Royal Bedroom". Otherwise, returns an empty string. + + The unit argument is passed through to DF and may modify the room's value + depending on the unit given. + +* ``dfhack.buildings.completeBuild(building)`` + + Complete an unconstructed or partially-constructed building and link it into + the world. + +High-level +~~~~~~~~~~ +More high-level functions are implemented in lua and can be loaded by +``require('dfhack.buildings')``. See ``hack/lua/dfhack/buildings.lua``. + +Among them are: + +* ``dfhack.buildings.getFiltersByType(argtable,type,subtype,custom)`` + + Returns a sequence of lua structures, describing input item filters + suitable for the specified building type, or *nil* if unknown or invalid. + The returned sequence is suitable for use as the ``job_items`` argument + of ``constructWithFilters``. + Uses tables defined in ``buildings.lua``. + + Argtable members ``material`` (the default name), ``bucket``, ``barrel``, + ``chain``, ``mechanism``, ``screw``, ``pipe``, ``anvil``, ``weapon`` are used + to augment the basic attributes with more detailed information if the + building has input items with the matching name (see the tables for naming + details). Note that it is impossible to *override* any properties this way, + only supply those that are not mentioned otherwise. One exception is that + ``flags2.non_economic`` is automatically cleared if an explicit material + is specified. + +* ``dfhack.buildings.constructBuilding{...}`` + + Creates a building in one call, using options contained + in the argument table. Returns the building, or *nil, error*. + + .. note:: + Despite the name, unless the building is abstract, + the function creates it in an 'unconstructed' stage, with + a queued in-game job that will actually construct it. I.e., + the function replicates programmatically what can be done + through the construct building menu in the game ui, except + that it does less environment constraint checking. + + The following options can be used: + + - ``pos = coordinates``, or ``x = ..., y = ..., z = ...`` + + Mandatory. Specifies the left upper corner of the building. + + - ``type = df.building_type.FOO, subtype = ..., custom = ...`` + + Mandatory. Specifies the type of the building. Obviously, subtype + and custom are only expected if the type requires them. + + - ``fields = { ... }`` + + Initializes fields of the building object after creation with + ``df.assign``. If ``room.extents`` is assigned this way and this function + returns with error, the memory allocated for the extents is freed. + + - ``width = ..., height = ..., direction = ...`` + + Sets size and orientation of the building. If it is + fixed-size, specified dimensions are ignored. + + - ``full_rectangle = true`` + + For buildings like stockpiles or farm plots that can normally + accommodate individual tile exclusion, forces an error if any + tiles within the specified width*height are obstructed. + + - ``items = { item, item ... }``, or ``filters = { {...}, {...}... }`` + + Specifies explicit items or item filters to use in construction. + It is the job of the user to ensure they are correct for the building type. + + - ``abstract = true`` + + Specifies that the building is abstract and does not require construction. + Required for stockpiles and civzones; an error otherwise. + + - ``material = {...}, mechanism = {...}, ...`` + + If none of ``items``, ``filter``, or ``abstract`` is used, + the function uses ``getFiltersByType`` to compute the input + item filters, and passes the argument table through. If no filters + can be determined this way, ``constructBuilding`` throws an error. + + +Constructions module +-------------------- + +* ``dfhack.constructions.designateNew(pos,type,item_type,mat_index)`` + + Designates a new construction at given position. If there already is + a planned but not completed construction there, changes its type. + Returns *true*, or *false* if obstructed. + Note that designated constructions are technically buildings. + +* ``dfhack.constructions.designateRemove(pos)``, or ``designateRemove(x,y,z)`` + + If there is a construction or a planned construction at the specified + coordinates, designates it for removal, or instantly cancels the planned one. + Returns *true, was_only_planned* if removed; or *false* if none found. + +* ``dfhack.constructions.findAtTile(pos)``, or ``findAtTile(x,y,z)`` + + Returns the construction at the given position, or ``nil`` if there isn't one. + +* ``dfhack.constructions.insert(construction)`` + + Properly inserts the given construction into the game. Returns false and fails + to insert if there was already a construction at the position. + +Kitchen module +-------------- + +* ``dfhack.kitchen.findExclusion(type, item_type, item_subtype, mat_type, mat_index)`` + + Finds a kitchen exclusion in the vectors in ``df.global.ui.kitchen``. Returns + -1 if not found. + + * ``type`` is a ``df.kitchen_exc_type`` with exactly one flag set, i.e + ``{Cook=true}`` or ``{Brew=true}``. + * ``item_type`` is a ``df.item_type`` + * ``item_subtype``, ``mat_type``, and ``mat_index`` are all numeric + +* ``dfhack.kitchen.addExclusion(type, item_type, item_subtype, mat_type, mat_index)`` +* ``dfhack.kitchen.removeExclusion(type, item_type, item_subtype, mat_type, mat_index)`` + + Adds or removes a kitchen exclusion, using the same parameters as + ``findExclusion``. Both return ``true`` on success and ``false`` on failure, + e.g., when adding an exclusion that already exists or removing one that does + not. + +Screen API +---------- + +The screen module implements support for drawing to the tiled screen of the game. +Note that drawing only has any effect when done from callbacks, so it can only +be feasibly used in the `core context `. + +.. contents:: + :local: + +Basic painting functions +~~~~~~~~~~~~~~~~~~~~~~~~ + +Common parameters to these functions include: + +* ``x``, ``y``: screen coordinates in tiles; the upper left corner of the screen + is ``x = 0, y = 0`` +* ``pen``: a `pen object ` +* ``map``: a boolean indicating whether to draw to a separate map buffer + (defaults to false, which is suitable for off-map text or a screen that hides + the map entirely). Note that only third-party plugins like TWBT currently + implement a separate map buffer. If no such plugins are enabled, passing + ``true`` has no effect. However, this parameter should still be used to ensure + that scripts work properly with such plugins. + +Functions: + +* ``dfhack.screen.getWindowSize()`` + + Returns *width, height* of the screen. + +* ``dfhack.screen.getMousePos()`` + + Returns *x,y* of the UI interface tile the mouse is over, with the upper left + corner being ``0,0``. To get the map tile coordinate that the mouse is over, + see ``dfhack.gui.getMousePos()``. + +* ``dfhack.screen.getMousePixels()`` + + Returns *x,y* of the screen coordinates the mouse is over in pixels, with the + upper left corner being ``0,0``. + +* ``dfhack.screen.inGraphicsMode()`` + + Checks if [GRAPHICS:YES] was specified in init. + +* ``dfhack.screen.paintTile(pen,x,y[,char[,tile[,map]]])`` + + Paints a tile using given parameters. `See below ` for a + description of ``pen``. + + Returns *false* on error, e.g., if coordinates are out of bounds + +* ``dfhack.screen.readTile(x,y[,map])`` + + Retrieves the contents of the specified tile from the screen buffers. + Returns a `pen object `, or *nil* if invalid or TrueType. + +* ``dfhack.screen.paintString(pen,x,y,text[,map])`` + + Paints the string starting at *x,y*. Uses the string characters + in sequence to override the ``ch`` field of `pen `. + + Returns *true* if painting at least one character succeeded. + +* ``dfhack.screen.fillRect(pen,x1,y1,x2,y2[,map])`` + + Fills the rectangle specified by the coordinates with the given + `pen `. Returns *true* if painting at least one + character succeeded. + +* ``dfhack.screen.findGraphicsTile(pagename,x,y)`` + + Finds a tile from a graphics set (i.e., the raws used for creatures), + if in graphics mode and loaded. + + Returns: *tile, tile_grayscale*, or *nil* if not found. + The values can then be used for the *tile* field of *pen* structures. + +* ``dfhack.screen.hideGuard(screen,callback[,args...])`` + + Removes screen from the viewscreen stack, calls the callback + (with optional supplied arguments), and then restores the screen on + the top of the viewscreen stack. + +* ``dfhack.screen.clear()`` + + Fills the screen with blank background. + +* ``dfhack.screen.invalidate()`` + + Requests repaint of the screen by setting a flag. Unlike other + functions in this section, this may be used at any time. + +* ``dfhack.screen.getKeyDisplay(key)`` + + Returns the string that should be used to represent the given + logical keybinding on the screen in texts like "press Key to ...". + +* ``dfhack.screen.keyToChar(key)`` + + Returns the integer character code of the string input + character represented by the given logical keybinding, + or *nil* if not a string input key. + +* ``dfhack.screen.charToKey(charcode)`` + + Returns the keybinding representing the given string input + character, or *nil* if impossible. + +.. _lua-screen-pen: + +Pen API +~~~~~~~ + +The ``pen`` argument used by ``dfhack.screen`` functions may be represented +by a table with the following possible fields: + + ``ch`` + Provides the ordinary tile character, as either a 1-character string or a number. + Can be overridden with the ``char`` function parameter. + ``fg`` + Foreground color for the ordinary tile. Defaults to COLOR_GREY (7). + ``bg`` + Background color for the ordinary tile. Defaults to COLOR_BLACK (0). + ``bold`` + Bright/bold text flag. If *nil*, computed based on (fg & 8); fg is masked to 3 bits. + Otherwise should be *true/false*. + ``tile`` + Graphical tile id. Ignored unless [GRAPHICS:YES] was in init.txt. + ``tile_color = true`` + Specifies that the tile should be shaded with *fg/bg*. + ``tile_fg, tile_bg`` + If specified, overrides *tile_color* and supplies shading colors directly. + ``keep_lower`` + If set to true, will not overwrite the background tile when filling in + the foreground tile. + ``write_to_lower`` + If set to true, the specified ``tile`` will be written to the background + instead of the foreground. + ``top_of_text`` + If set to true, the specified ``tile`` will have the top half of the specified + ``ch`` character superimposed over the lower half of the tile. + ``bottom_of_text`` + If set to true, the specified ``tile`` will have the bottom half of the specified + ``ch`` character superimposed over the top half of the tile. + +Alternatively, it may be a pre-parsed native object with the following API: + +* ``dfhack.pen.make(base[,pen_or_fg[,bg[,bold]]])`` + + Creates a new pre-parsed pen by combining its arguments according to the + following rules: + + 1. The ``base`` argument may be a pen object, a pen table as specified above, + or a single color value. In the single value case, it is split into + ``fg`` and ``bold`` properties, and others are initialized to 0. + This argument will be converted to a pre-parsed object and returned + if there are no other arguments. + + 2. If the ``pen_or_fg`` argument is specified as a table or object, it + completely replaces the base, and is returned instead of it. + + 3. Otherwise, the non-nil subset of the optional arguments is used + to update the ``fg``, ``bg`` and ``bold`` properties of the base. + If the ``bold`` flag is *nil*, but *pen_or_fg* is a number, ``bold`` + is deduced from it like in the simple base case. + + This function always returns a new pre-parsed pen, or *nil*. + +* ``dfhack.pen.parse(base[,pen_or_fg[,bg[,bold]]])`` + + Exactly like the above function, but returns ``base`` or ``pen_or_fg`` + directly if they are already a pre-parsed native object. + +* ``pen.property``, ``pen.property = value``, ``pairs(pen)`` + + Pre-parsed pens support reading and setting their properties, + but don't behave exactly like a simple table would; for instance, + assigning to ``pen.tile_color`` also resets ``pen.tile_fg`` and + ``pen.tile_bg`` to *nil*. + +Screen management +~~~~~~~~~~~~~~~~~ + +In order to actually be able to paint to the screen, it is necessary +to create and register a viewscreen (basically a modal dialog) with +the game. + +.. warning:: + As a matter of policy, in order to avoid user confusion, all + interface screens added by dfhack should bear the "DFHack" signature. + +Screens are managed with the following functions: + +* ``dfhack.screen.show(screen[,below])`` + + Displays the given screen, possibly placing it below a different one. + The screen must not be already shown. Returns *true* if success. + +* ``dfhack.screen.dismiss(screen[,to_first])`` + + Marks the screen to be removed when the game enters its event loop. + If ``to_first`` is *true*, all screens up to the first one will be deleted. + +* ``dfhack.screen.isDismissed(screen)`` + + Checks if the screen is already marked for removal. + +Apart from a native viewscreen object, these functions accept a table +as a screen. In this case, ``show`` creates a new native viewscreen +that delegates all processing to methods stored in that table. + +.. note:: + + * The `gui.Screen class ` provides stubs for all of the + functions listed below, and its use is recommended + * Lua-implemented screens are only supported in the `core context `. + +Supported callbacks and fields are: + +* ``screen._native`` + + Initialized by ``show`` with a reference to the backing viewscreen + object, and removed again when the object is deleted. + +* ``function screen:onShow()`` + + Called by ``dfhack.screen.show`` if successful. + +* ``function screen:onDismiss()`` + + Called by ``dfhack.screen.dismiss`` if successful. + +* ``function screen:onDestroy()`` + + Called from the destructor when the viewscreen is deleted. + +* ``function screen:onResize(w, h)`` + + Called before ``onRender`` or ``onIdle`` when the window size has changed. + +* ``function screen:onRender()`` + + Called when the viewscreen should paint itself. This is the only context + where the above painting functions work correctly. + + If omitted, the screen is cleared; otherwise it should do that itself. + In order to make a dialog where portions of the parent viewscreen are still + visible in the background, call ``screen:renderParent()``. + + If artifacts are left on the parent even after this function is called, such + as when the window is dragged or is resized, any code can set + ``gui.Screen.request_full_screen_refresh`` to ``true``. Then when + ``screen.renderParent()`` is next called, it will do a full flush of the + graphics and clear the screen of artifacts. + +* ``function screen:onIdle()`` + + Called every frame when the screen is on top of the stack. + +* ``function screen:onHelp()`` + + Called when the help keybinding is activated (usually '?'). + +* ``function screen:onInput(keys)`` + + Called when keyboard or mouse events are available. + If any keys are pressed, the keys argument is a table mapping them to *true*. + Note that this refers to logical keybindings computed from real keys via + options; if multiple interpretations exist, the table will contain multiple keys. + + The table also may contain special keys: + + ``_STRING`` + Maps to an integer in range 0-255. Duplicates a separate "STRING_A???" code + for convenience. + + ``_MOUSE_L, _MOUSE_R, _MOUSE_M`` + If the left, right, and/or middle mouse button was just pressed. + + ``_MOUSE_L_DOWN, _MOUSE_R_DOWN, _MOUSE_M_DOWN`` + If the left, right, and/or middle mouse button is being held down. + + If this method is omitted, the screen is dismissed on reception of the + ``LEAVESCREEN`` key. + +* ``function screen:onGetSelectedUnit()`` +* ``function screen:onGetSelectedItem()`` +* ``function screen:onGetSelectedJob()`` +* ``function screen:onGetSelectedBuilding()`` +* ``function screen:onGetSelectedStockpile()`` +* ``function screen:onGetSelectedCivZone()`` +* ``function screen:onGetSelectedPlant()`` + + Override these if you want to provide a custom return value for the matching + ``dfhack.gui.getSelected...`` function. + + +PenArray class +-------------- + +Screens that require significant computation in their onRender() method can use +a ``dfhack.penarray`` instance to cache their output. + +* ``dfhack.penarray.new(w, h)`` + + Creates a new penarray instance with an internal buffer of ``w * h`` tiles. + These dimensions currently cannot be changed after a penarray is instantiated. + +* ``penarray:clear()`` + + Clears the internal buffer, similar to ``dfhack.screen.clear()``. + +* ``penarray:get_dims()`` + + Returns the x and y dimensions of the internal buffer. + +* ``penarray:get_tile(x, y)`` + + Returns a pen corresponding to the tile at (``x``, ``y``) in the internal buffer. + Note that indices are 0-based. + +* ``penarray:set_tile(x, y, pen)`` + + Sets the tile at (``x``, ``y``) in the internal buffer to the pen given. + +* ``penarray:draw(x, y, w, h, bufferx, buffery)`` + + Draws the contents of the internal buffer, beginning at + (``bufferx``, ``buffery``) and spanning ``w`` columns and ``h`` rows, to the + screen starting at (``x``, ``y``). Any invalid screen and buffer coordinates + are skipped. + + ``bufferx`` and ``buffery`` default to 0. + + +Textures module +--------------- + +In order for the game to render a particular tile (graphic), it needs to know the +``texpos`` - the position in the vector of the registered game textures (also the +graphical tile id passed as the ``tile`` field in a `Pen `). +Adding new textures to the vector is not difficult, but the game periodically +deletes textures that are in the vector, and that's a problem since it +invalidates the ``texpos`` value that used to point to that texture. +The ``textures`` module solves this problem by providing a stable handle instead of a +raw ``texpos``. When we need to draw a particular tile, we can look up the current +``texpos`` value via the handle. +Texture module can register textures in two ways: to reserved and dynamic ranges. +Reserved range is a limit buffer in a game texture vector, that will never be wiped. +It is good for static assets, which need to be loaded at the very beginning and will +be used during the process running. In other cases, it is better to use dynamic range. +If reserved range buffer limit has been reached, dynamic range will be used by default. + +* ``loadTileset(file, tile_px_w, tile_px_h[, reserved])`` + + Loads a tileset from the image ``file`` with give tile dimensions in pixels. The + image will be sliced in row major order. Returns an array of ``TexposHandle``. + ``reserved`` is optional boolean argument, which indicates texpos range. + ``true`` - reserved, ``false`` - dynamic (default). + + Example usage:: + + local logo_textures = dfhack.textures.loadTileset('hack/data/art/dfhack.png', 8, 12) + local first_texposhandle = logo_textures[1] + +* ``getTexposByHandle(handle)`` + + Get the current ``texpos`` for the given ``TexposHandle``. Always use this method to + get the ``texpos`` for your texture. ``texpos`` can change when game textures are + reset, but the handle will be the same. + +* ``createTile(pixels, tile_px_w, tile_px_h[, reserved])`` + + Create and register a new texture with the given tile dimensions and an array of + ``pixels`` in row major order. Each pixel is an integer representing color in packed + RBGA format (for example, #0022FF11). Returns a ``TexposHandle``. + ``reserved`` is optional boolean argument, which indicates texpos range. + ``true`` - reserved, ``false`` - dynamic (default). + +* ``createTileset(pixels, texture_px_w, texture_px_h, tile_px_w, tile_px_h[, reserved])`` + + Create and register a new texture with the given texture dimensions and an array of + ``pixels`` in row major order. Then slice it into tiles with the given tile + dimensions. Each pixel is an integer representing color in packed RBGA format (for + example #0022FF11). Returns an array of ``TexposHandle``. + ``reserved`` is optional boolean argument, which indicates texpos range. + ``true`` - reserved, ``false`` - dynamic (default). + +* ``deleteHandle(handle)`` + + ``handle`` here can be single ``TexposHandle`` or an array of ``TexposHandle``. + Deletes all metadata and texture(s) related to the given handle(s). The handles + become invalid after this call. + + +Filesystem module +----------------- + +Most of these functions return ``true`` on success and ``false`` on failure, +unless otherwise noted. + +* ``dfhack.filesystem.exists(path)`` + + Returns ``true`` if ``path`` exists. + +* ``dfhack.filesystem.isfile(path)`` + + Returns ``true`` if ``path`` exists and is a file. + +* ``dfhack.filesystem.isdir(path)`` + + Returns ``true`` if ``path`` exists and is a directory. + +* ``dfhack.filesystem.getcwd()`` + + Returns the current working directory. To retrieve the DF path, use + ``dfhack.getDFPath()`` instead. + +* ``dfhack.filesystem.chdir(path)`` + + Changes the current directory to ``path``. Use with caution. + +* ``dfhack.filesystem.restore_cwd()`` + + Restores the current working directory to what it was when DF started. + +* ``dfhack.filesystem.get_initial_cwd()`` + + Returns the value of the working directory when DF was started. + +* ``dfhack.filesystem.mkdir(path)`` + + Creates a new directory. Returns ``false`` if unsuccessful, including if + ``path`` already exists. + +* ``dfhack.filesystem.mkdir_recursive(path)`` + + Creates a new directory, including any intermediate directories that + don't exist yet. Returns ``true`` if the folder was created or already + existed, or ``false`` if unsuccessful. + +* ``dfhack.filesystem.rmdir(path)`` + + Removes a directory. Only works if the directory is already empty. + +* ``dfhack.filesystem.mtime(path)`` + + Returns the modification time (in seconds) of the file or directory + specified by ``path``, or -1 if ``path`` does not exist. + This depends on the system clock and should only be used locally. + +* ``dfhack.filesystem.listdir(path)`` + + Lists files/directories in a directory. Returns ``{}`` if ``path`` does not exist. + +* ``dfhack.filesystem.listdir_recursive(path [, depth = 10[, include_prefix = true]])`` + + Lists all files/directories in a directory and its subdirectories. All + directories are listed before their contents. Returns a table with subtables + of the format: ``{path: 'path to file', isdir: true|false}`` + + Note that ``listdir()`` returns only the base name of each directory entry, + while ``listdir_recursive()`` returns the initial path and all components + following it for each entry. Set ``include_prefix`` to false if you don't + want the ``path`` string prepended to the returned filenames. + +* ``dfhack.filesystem.getBaseDir()`` + + Returns a directory to which DF (and thus DFHack) can save files. This will either + be DF's install directory, or the path returned by ``SDLGetPrefDir``, depending on whether + DF is in "portable mode" or not. + +* ``dfhack.filesystem.getInstallDir()`` + + Returns the the directory in which DF is installed. + +Console API +----------- + +* ``dfhack.console.clear()`` + + Clears the console; equivalent to the ``cls`` built-in command. + +* ``dfhack.console.flush()`` + + Flushes all output to the console. This can be useful when printing text that + does not end in a newline but should still be displayed. + +.. _lua-api-internal: + +Internal API +------------ + +These functions are intended for the use by dfhack developers, +and are only documented here for completeness: + +* ``dfhack.internal.getPE()`` + + Returns the PE timestamp of the DF executable (only on Windows) + +* ``dfhack.internal.getMD5()`` + + Returns the MD5 of the DF executable (only on OS X and Linux) + +* ``dfhack.internal.getAddress(name)`` + + Returns the global address ``name``, or *nil*. + +* ``dfhack.internal.setAddress(name, value)`` + + Sets the global address ``name``. Returns the value of ``getAddress`` + before the change. + +* ``dfhack.internal.getVTable(name)`` + + Returns the pre-extracted vtable address ``name``, or *nil*. + +* ``dfhack.internal.getImageBase()`` + + Returns the mmap base of the executable. + +* ``dfhack.internal.getRebaseDelta()`` + + Returns the ASLR rebase offset of the DF executable. + +* ``dfhack.internal.adjustOffset(offset[,to_file])`` + + Returns the re-aligned offset, or *nil* if invalid. + If ``to_file`` is true, the offset is adjusted from memory to file. + This function returns the original value everywhere except windows. + +* ``dfhack.internal.getMemRanges()`` + + Returns a sequence of tables describing virtual memory ranges of the process. + +* ``dfhack.internal.patchMemory(dest,src,count)`` + + Like memmove below, but works even if dest is read-only memory, e.g., code. + If destination overlaps a completely invalid memory region, or another error + occurs, returns false. + +* ``dfhack.internal.patchBytes(write_table[, verify_table])`` + + The first argument must be a lua table, which is interpreted as a mapping from + memory addresses to byte values that should be stored there. The second argument + may be a similar table of values that need to be checked before writing anything. + + The function takes care to either apply all of ``write_table``, or none of it. + An empty ``write_table`` with a nonempty ``verify_table`` can be used to reasonably + safely check if the memory contains certain values. + + Returns *true* if successful, or *nil, error_msg, address* if not. + +* ``dfhack.internal.memmove(dest,src,count)`` + + Wraps the standard memmove function. Accepts both numbers and refs as pointers. + +* ``dfhack.internal.memcmp(ptr1,ptr2,count)`` + + Wraps the standard memcmp function. + +* ``dfhack.internal.memscan(haystack,count,step,needle,nsize)`` + + Searches for ``needle`` of ``nsize`` bytes in ``haystack``, + using ``count`` steps of ``step`` bytes. + Returns: *step_idx, sum_idx, found_ptr*, or *nil* if not found. + +* ``dfhack.internal.diffscan(old_data, new_data, start_idx, end_idx, eltsize[, oldval[, newval[, delta]]])`` + + Searches for differences between buffers at ptr1 and ptr2, as integers of size eltsize. + The oldval, newval or delta arguments may be used to specify additional constraints. + Returns: *found_index*, or *nil* if end reached. + +* ``dfhack.internal.cxxDemangle(mangled_name)`` + + Decodes a mangled C++ symbol name. Returns the demangled name on success, or + ``nil, error_message`` on failure. + +* ``dfhack.internal.getDir(path)`` + + Lists files/directories in a directory. + Returns: *file_names* or empty table if not found. Identical to ``dfhack.filesystem.listdir(path)``. + +* ``dfhack.internal.strerror(errno)`` + + Wraps strerror() - returns a string describing a platform-specific error code + +* ``dfhack.internal.addScriptPath(path, search_before)`` + + Registers ``path`` as a `script path `. + If ``search_before`` is passed and ``true``, the path will be searched before + the default paths (e.g., ``dfhack-config/scripts``, ``hack/scripts``); otherwise, + it will be searched after. + + Returns ``true`` if successful or ``false`` otherwise (e.g., if the path does + not exist or has already been registered). + +* ``dfhack.internal.removeScriptPath(path)`` + + Removes ``path`` from the list of `script paths ` and returns + ``true`` if successful. + +* ``dfhack.internal.getScriptPaths()`` + + Returns the list of `script paths ` in the order they are + searched, including defaults. (This can change if a world is loaded.) + +* ``dfhack.internal.findScript(name)`` + + Searches `script paths ` for the script ``name`` (which + includes the ``.lua`` extension) and returns the absolute path of the first + file found, or ``nil`` on failure. Slashes in the path are canonicalized to + forward slashes. + + .. note:: + You can use the ``dfhack.findScript()`` wrapper if you want to specify the + script name without the ``.lua`` extension. + +* ``dfhack.internal.runCommand(command[, use_console])`` + + Runs a DFHack command with the core suspended. Used internally by the + ``dfhack.run_command()`` family of functions. + + - ``command``: either a table of strings or a single string which is parsed by + the default console tokenization strategy (not recommended) + - ``use_console``: if true, output is sent directly to the DFHack console + + Returns a table with a ``status`` key set to a ``command_result`` constant + (``status = CR_OK`` indicates success). Additionally, if ``use_console`` is + not true, enumerated table entries of the form ``{color, text}`` are included, + e.g., ``result[1][0]`` is the color of the first piece of text printed (a + ``COLOR_`` constant). These entries can be iterated over with ``ipairs()``. + +* ``dfhack.internal.md5(string)`` + + Returns the MD5 hash of the given string. + +* ``dfhack.internal.md5File(filename[,first_kb])`` + + Computes the MD5 hash of the given file. Returns ``hash, length`` on success + (where ``length`` is the number of bytes read from the file), or ``nil, + error`` on failure. + + If the parameter ``first_kb`` is specified and evaluates to ``true``, and the + hash was computed successfully, a table containing the first 1024 bytes of the + file is returned as the third return value. + +* ``dfhack.internal.threadid()`` + + Returns a numeric identifier of the current thread. + +* ``dfhack.internal.msizeAddress(address)`` + + Returns the allocation size of an address. + Does not require a heap snapshot. This function will crash on an invalid pointer. + Windows only. + +* ``dfhack.internal.getHeapState()`` + + Returns the state of the heap. 0 == ok or empty, 1 == heap bad ptr, 2 == heap bad begin, + 3 == heap bad node. Does not require a heap snapshot. This may be unsafe to use directly + from lua if the heap is corrupt. Windows only. + +* ``dfhack.internal.heapTakeSnapshot()`` + + Clears any existing heap snapshot, and takes an internal heap snapshot for later + consumption. Windows only. Returns the same values as getHeapState() + +* ``dfhack.internal.isAddressInHeap(address)`` + + Checks if an address is a member of the heap. It may be dangling. + Requires a heap snapshot. + +* ``dfhack.internal.isAddressActiveInHeap(address)`` + + Checks if an address is a member of the heap, and actively in use (i.e., valid). + Requires a heap snapshot. + +* ``dfhack.internal.isAddressUsedAfterFreeInHeap(address)`` + + Checks if an address is a member of the heap, but is not currently allocated + (i.e., use after free). Requires a heap snapshot. + Note that Windows eagerly removes freed pointers from the heap, + so this is unlikely to trigger. + +* ``dfhack.internal.getAddressSizeInHeap(address)`` + + Gets the allocated size of a member of the heap. Useful for detecting misaligns, + as this does not return block size. Requires a heap snapshot. + +* ``dfhack.internal.getRootAddressOfHeapObject(address)`` + + Gets the base heap allocation address of a address that lies internally within + a piece of allocated memory. E.g., if you have a heap allocated struct and call + this function on the address of the second member, it will return the address + of the struct. Returns 0 if the address is not found. Requires a heap snapshot. + +* ``dfhack.internal.getClipboardTextCp437()`` + + Gets the system clipboard text (and converts text to CP437 encoding). + +* ``dfhack.internal.setClipboardTextCp437(text)`` + + Sets the system clipboard text from a CP437 string. + +* ``dfhack.internal.getClipboardTextCp437Multiline()`` + + Gets the system clipboard text (and converts text to CP437 encoding). + Character 0x10 is interpreted as a newline instead of the usual CP437 glyph. + The text is returned as a list of strings, one for each line of text on the + clipboard. + +* ``dfhack.internal.setClipboardTextCp437Multiline(text)`` + + Sets the system clipboard text from a CP437 string. Character 0x10 is + interpreted as a newline instead of the usual CP437 glyph. + +* ``dfhack.internal.getModifiers()`` + + Returns the state of the keyboard modifier keys in a table of string -> + boolean. The keys are ``ctrl``, ``shift``, ``super``, and ``alt``. + +* ``dfhack.internal.getSuppressDuplicateKeyboardEvents()`` +* ``dfhack.internal.setSuppressDuplicateKeyboardEvents(suppress)`` + + Gets and sets the flag for whether to suppress DF key events when a DFHack + keybinding is matched and a command is launched. + +* ``dfhack.internal.setMortalMode(value)`` +* ``dfhack.internal.setArmokTools(tool_names)`` + + Used to sync mortal mode state to DFHack Core memory for use in keybinding + checks. + +* ``dfhack.internal.setPreferredNumberFormat(value)`` +* ``dfhack.internal.getPreferredNumberFormat()`` + + Sets (gets) the preferred numeric format. ``0`` means no formatting (e.g., + ``1234567``), ``1`` means English formatting (e.g., ``1,234,567``), ``2`` + means system locale formatting (e.g., ``12.345`` on German systems, + ``12,34,567`` on Indian systems, etc.), ``3`` means SI suffix formatting + (e.g., ``12.3M``), and ``4`` means scientific notation (e.g., ``1.23457e+06``). + +For the internal preference values, be aware that setting the values via these +functions will not persist the choice across program invocations. You must set +preferences via the `control-panel` or `gui/control-panel` interfaces for that. + +.. _lua-core-context: + +Core interpreter context +======================== + +While plugins can create any number of interpreter instances, +there is one special context managed by the DFHack core. It is the +only context that can receive events from DF and plugins. + +Core context specific functions: + +* ``dfhack.is_core_context`` + + Boolean value; *true* in the core context. + +* ``dfhack.timeout(time,mode,callback)`` + + Arranges for the callback to be called once the specified + period of time passes. The ``mode`` argument specifies the + unit of time used, and may be one of ``'frames'`` (raw FPS), + ``'ticks'`` (unpaused FPS), ``'days'``, ``'months'``, + ``'years'`` (in-game time). All timers other than + ``'frames'`` are canceled when the world is unloaded, + and cannot be queued until it is loaded again. + Returns the timer id, or *nil* if unsuccessful due to + world being unloaded. + +* ``dfhack.timeout_active(id[,new_callback])`` + + Returns the active callback with the given id, or *nil* + if inactive or nil id. If called with 2 arguments, replaces + the current callback with the given value, if still active. + Using ``timeout_active(id,nil)`` cancels the timer. + +* ``dfhack.onStateChange.foo = function(code)`` + + Creates a handler for state change events. Receives the same + `SC_ codes ` as ``plugin_onstatechange()`` in C++. + + +Event type +---------- + +An event is a native object transparently wrapping a lua table, +and implementing a __call metamethod. When it is invoked, it loops +through the table with next and calls all contained values. +This is intended as an extensible way to add listeners. + +This type itself is available in any context, but only the +`core context ` has the actual events defined by C++ code. + +Features: + +* ``dfhack.event.new()`` + + Creates a new instance of an event. + +* ``event[key] = function`` + + Sets the function as one of the listeners. Assign *nil* to remove it. + + .. note:: + The ``df.NULL`` key is reserved for the use by + the C++ owner of the event; it is an error to try setting it. + +* ``#event`` + + Returns the number of non-nil listeners. + +* ``pairs(event)`` + + Iterates over all listeners in the table. + +* ``event(args...)`` + + Invokes all listeners contained in the event in an arbitrary + order using ``dfhack.safecall``. + + +=========== +Lua Modules +=========== + +.. contents:: + :local: + +DFHack sets up the lua interpreter so that the built-in ``require`` +function can be used to load shared lua code from :file:`hack/lua/`. +The ``dfhack`` namespace reference itself may be obtained via +``require('dfhack')``, although it is initially created as a +global by C++ bootstrap code. + +The following module management functions are provided: + +* ``mkmodule(name)`` + + Creates an environment table for the module. Intended to be used as:: + + local _ENV = mkmodule('foo') + ... + return _ENV + + If called the second time, returns the same table, + thus providing reload support. + +* ``reload(name)`` + + Reloads a previously ``require``-d module *"name"* from the file. + Intended as a help for module development. + +* ``dfhack.BASE_G`` + + This variable contains the root global environment table, which is + used as a base for all module and script environments. Its contents + should be kept limited to the standard Lua library and API described + in this document. + +.. _lua-globals: + +Global environment +================== + +A number of variables and functions are provided in the base global +environment by the mandatory init file dfhack.lua: + +* Color constants + + These are applicable both for ``dfhack.color()`` and color fields + in DF functions or structures:: + + COLOR_RESET, COLOR_BLACK, COLOR_BLUE, COLOR_GREEN, COLOR_CYAN, + COLOR_RED, COLOR_MAGENTA, COLOR_BROWN, COLOR_GREY, COLOR_DARKGREY, + COLOR_LIGHTBLUE, COLOR_LIGHTGREEN, COLOR_LIGHTCYAN, COLOR_LIGHTRED, + COLOR_LIGHTMAGENTA, COLOR_YELLOW, COLOR_WHITE + + ``COLOR_GREY`` and ``COLOR_DARKGREY`` can also be spelled ``COLOR_GRAY`` and + ``COLOR_DARKGRAY``. + +* State change event codes, used by ``dfhack.onStateChange`` + + Available only in the `core context `, as is the event itself: + + SC_WORLD_LOADED, SC_WORLD_UNLOADED, SC_MAP_LOADED, + SC_MAP_UNLOADED, SC_VIEWSCREEN_CHANGED, SC_CORE_INITIALIZED + +* Command result constants (equivalent to ``command_result`` in C++), used by + ``dfhack.run_command()`` and related functions: + + CR_OK, CR_LINK_FAILURE, CR_NEEDS_CONSOLE, CR_NOT_IMPLEMENTED, CR_FAILURE, + CR_WRONG_USAGE, CR_NOT_FOUND + +* Functions already described above + + safecall, qerror, mkmodule, reload + +* Miscellaneous constants + + ``NEWLINE``, ``COMMA``, ``PERIOD`` + evaluate to the relevant character strings. + ``DEFAULT_NIL`` + is an unspecified unique token used by the class module below. + +* ``printall(obj)`` + + If the argument is a lua table or DF object reference, prints all fields. + +* ``printall_recurse(obj)`` + + If the argument is a lua table or DF object reference, prints all fields recursively. + +* ``copyall(obj)`` + + Returns a shallow copy of the table or reference as a lua table. + +* ``pos2xyz(obj)`` + + The object must have fields x, y and z. Returns them as 3 values. + If obj is *nil*, or x is -30000 (the usual marker for undefined + coordinates), returns *nil*. + +* ``xyz2pos(x,y,z)`` + + Returns a table with x, y and z as fields. + +* ``same_xyz(a,b)`` + + Checks if ``a`` and ``b`` have the same x, y and z fields. + +* ``get_path_xyz(path,i)`` + + Returns ``path.x[i], path.y[i], path.z[i]``. + +* ``pos2xy(obj)``, ``xy2pos(x,y)``, ``same_xy(a,b)``, ``get_path_xy(a,b)`` + + Same as above, but for 2D coordinates. + +* ``safe_index(obj,index...)`` + + Walks a sequence of dereferences, which may be represented by numbers or strings. + Returns *nil* if any of obj or indices is *nil*, obj isn't indexable, or a numeric + index is out of array bounds. + +* ``ensure_key(t, key[, default_value])`` + + If the Lua table ``t`` doesn't include the specified ``key``, ``t[key]`` is + set to the value of ``default_value``, which defaults to ``{}`` if not set. + The new or existing value of ``t[key]`` is then returned. + +* ``ensure_keys(t, key...)`` + + Walks a series of keys, creating any missing keys as empty tables. The new or + existing table from the last specified key is returned from the function. + +.. _lua-string: + +String class extensions +----------------------- + +DFHack extends Lua's basic string class to include a number of convenience +functions. These are invoked just like standard string functions, e.g.:: + + if imastring:startswith('imaprefix') then + +* ``string:startswith(prefix)`` + + Returns ``true`` if the first ``#prefix`` characters of the string are equal + to ``prefix``. Note that ``prefix`` is not interpreted as a pattern. + +* ``string:endswith(suffix)`` + + Returns ``true`` if the last ``#suffix`` characters of the string are equal + to ``suffix``. Note that ``suffix`` is not interpreted as a pattern. + +* ``string:split([delimiter[, plain]])`` + + Split a string by the given delimiter. If no delimiter is specified, space + (``' '``) is used. The delimiter is treated as a pattern unless a ``plain`` is + specified and set to ``true``. To treat multiple successive delimiter + characters as a single delimiter, e.g., to avoid getting empty string elements, + pass a pattern like ``' +'``. Be aware that passing patterns that match empty + strings (like ``' *'``) will result in improper string splits. + +* ``string:trim()`` + + Removes spaces (i.e., everything that matches ``'%s'``) from the start and end + of a string. Spaces between non-space characters are left untouched. + +* ``string:wrap([width[, opts]])`` + + Inserts newlines into a string so no individual line exceeds the given width. + Lines are split at space-separated word boundaries. Any existing newlines are + kept in place. If a single word is longer than width, it is split over + multiple lines. If ``width`` is not specified, 72 is used. The ``opts`` + parameter can be a table with the following boolean fields specified: + + :return_as_table: if ``true``, then the function will return a table of + strings, with each string representing one wrapped line. Otherwise, a + single multi-line string is returned. + :keep_trailing_spaces: if ``true``, then spaces at the end of a wrapped + line will be kept. Normally, spaces at the end of a wrapped line are + elided. + :keep_original_newlines: if ``true`` (and ``return_as_table`` is also + ``true``), then if a newline was encountered in the original string, it + will be included in the relevant table entry. + +* ``string:escape_pattern()`` + + Escapes regex special chars in a string. E.g., ``'a+b'`` -> ``'a%+b'``. + +.. _script-manager: + +script-manager +============== + +This module contains functions useful for mods that contain DFHack scripts to +retrieve source and state paths. The value to pass as ``mod_id`` must be the +same as the mod ID in the mod's :file:`info.txt` metadata file. The returned +paths will be relative to the top level game directory and will end in a slash +(``/``). + +* ``scriptmanager.getModSourcePath(mod_id)`` + + Retrieve the source directory path for the mod with the given ID or ``nil`` + if the mod cannot be found. If multiple versions of a mod are found, the path + for the version loaded by the current world is used. If the current world + does not have the mod loaded (or if a world is not currently loaded) then the + path for the most recent version of the mod is returned. Example:: + + local scriptmanager = require('script-manager') + local path = scriptmanager.getModSourcePath('my_awesome_mod') + print(path) + + Which would print something like: ``mods/2945575779/`` or + ``data/installed_mods/my_awesome_mod (108)/``, depending on where the mod is + being loaded from. + +* ``scriptmanager.getModStatePath(mod_id)`` + + Retrieve the directory path where a mod with the given ID should store its + persistent state. Example:: + + local json = require('json') + local scriptmanager = require('script-manager') + local path = scriptmanager.getModStatePath('my_awesome_mod') + config = config or json.open(path .. 'settings.json') + + Which would open ``dfhack-config/mods/my_awesome_mod/settings.json``. After + calling ``getModStatePath``, the returned directory is guaranteed to exist. + +* ``get_active_mods()`` + + Returns a list of all active mods in the current world. The list elements are + tables containing the following fields: + + - id: mod id + - name: mod display name + - version: mod display version + - numeric_version: numeric mod version + - path: path to the mod directory + - vanilla: true if this is a vanilla mod + +* ``get_mod_info_metadata(mod_path, tags)`` + + Returns a table with the values of the given tags from the ``info.txt`` file + in the given mod directory. The ``mod_path`` argument must be a path to a mod + directory (retrieved, say, from ``get_active_mods()``). The ``tags`` argument + is a string or a list of strings representing the tags to retrieve. The + function will return a table with the tag names as keys and their values as + values. If a requested tag includes the string ``NUMERIC_``, it will return + the numeric value for that tag (e.g., ``NUMERIC_VERSION`` will return the + numeric version of the mod as a number instead of a string). + +utils +===== + +* ``utils.compare(a,b)`` + + Comparator function; returns *-1* if ab, *0* otherwise. + +* ``utils.compare_name(a,b)`` + + Comparator for names; compares empty string last. + +* ``utils.is_container(obj)`` + + Checks if obj is a container ref. + +* ``utils.make_index_sequence(start,end)`` + + Returns a lua sequence of numbers in start..end. + +* ``utils.invert(table)`` + + Returns a table where keys and values are reversed (i.e., a table containing a + ``value = key`` entry for every ``key = value`` entry in the argument). + +* ``utils.tabulate(fun, start, stop[, step])`` + + For numbers ``start``, ``stop`` and ``step``, with ``step`` defaulting to 1, + returns a lua sequence ``{ fun(start), fun(start+step), ... , fun(stop) }``. + +* ``utils.make_sort_order(data, ordering)`` + + Computes a sorted permutation of objects in data, as a table of integer + indices into the data sequence. Uses ``data.n`` as input length + if present. + + The ordering argument is a sequence of ordering specs, represented + as lua tables with following possible fields: + + ord.key = *function(value)* + Computes comparison key from input data value. Not called on nil. + If omitted, the comparison key is the value itself. + ord.key_table = *function(data)* + Computes a key table from the data table in one go. + ord.compare = *function(a,b)* + Comparison function. Defaults to ``utils.compare`` above. + Called on non-nil keys; nil sorts last. + ord.nil_first = *true/false* + If true, nil keys are sorted first instead of last. + ord.reverse = *true/false* + If true, sort non-nil keys in descending order. + + For every comparison during sorting the specs are applied in + order until an unambiguous decision is reached. Sorting is stable. + + Example of sorting a sequence by field foo:: + + local spec = { key = function(v) return v.foo end } + local order = utils.make_sort_order(data, { spec }) + local output = {} + for i = 1,#order do output[i] = data[order[i]] end + + Separating the actual reordering of the sequence in this + way enables applying the same permutation to multiple arrays. + This function is used by the sort plugin. + +* ``for link,item in utils.listpairs(list)`` + + Iterates a df-list structure, for example ``df.global.world.job_list``. + +* ``utils.assign(tgt, src)`` + + Does a recursive assignment of src into tgt. + Uses ``df.assign`` if tgt is a native object ref; otherwise + recurses into lua tables. + +* ``utils.clone(obj, deep)`` + + Performs a shallow, or semi-deep copy of the object as a lua table tree. + The deep mode recurses into lua tables and subobjects, except pointers + to other heap objects. + Null pointers are represented as ``df.NULL``. Zero-based native containers + are converted to 1-based lua sequences. + +* ``utils.clone_with_default(obj, default, force)`` + + Copies the object, using the ``default`` lua table tree + as a guide to which values should be skipped as uninteresting. + The ``force`` argument makes it always return a non-*nil* value. + +* ``utils.parse_bitfield_int(value, type_ref)`` + + Given an int ``value``, and a bitfield type in the ``df`` tree, + it returns a lua table mapping the enabled bit keys to *true*, + unless value is 0, in which case it returns *nil*. + +* ``utils.list_bitfield_flags(bitfield[, list])`` + + Adds all enabled bitfield keys to ``list`` or a newly-allocated + empty sequence, and returns it. The ``bitfield`` argument may + be *nil*. + +* ``utils.sort_vector(vector,field,cmpfun)`` + + Sorts a native vector or lua sequence using the comparator function. + If ``field`` is not *nil*, applies the comparator to the field instead + of the whole object. + +* ``utils.linear_index(vector,key[,field])`` + + Searches for ``key`` in the vector, and returns *index, found_value*, + or *nil* if none found. + +* ``utils.binsearch(vector,key,field,cmpfun,min,max)`` + + Does a binary search in a native vector or lua sequence for + ``key``, using ``cmpfun`` and ``field`` like sort_vector. + If ``min`` and ``max`` are specified, they are used as the + search subrange bounds. + + If found, returns *item, true, idx*. Otherwise returns + *nil, false, insert_idx*, where *insert_idx* is the correct + insertion point. + +* ``utils.insert_sorted(vector,item,field,cmpfun)`` + + Does a binary search, and inserts item if not found. + Returns *did_insert, vector[idx], idx*. + +* ``utils.insert_or_update(vector,item,field,cmpfun)`` + + Like ``insert_sorted``, but also assigns the item into + the vector cell if insertion didn't happen. + + As an example, you can use this to set skill values:: + + utils.insert_or_update(soul.skills, {new=true, id=..., rating=...}, 'id') + + (For an explanation of ``new=true``, see `lua-api-table-assignment`) + +* ``utils.erase_sorted_key(vector,key,field,cmpfun)`` + + Removes the item with the given key from the list. + Returns: *did_erase, vector[idx], idx*. + +* ``utils.erase_sorted(vector,item,field,cmpfun)`` + + Exactly like ``erase_sorted_key``, but if field is specified, + takes the key from ``item[field]``. + +* ``utils.search_text(text,search_tokens)`` + + Returns true if all the search tokens are found within ``text``. The text and + search tokens are normalized to lower case and special characters (e.g., ``A`` + with a circle on it) are converted to their "basic" forms (e.g., ``a``). + ``search_tokens`` can be a string or a table of strings. If it is a string, + it is split into space-separated tokens before matching. The search tokens + are treated literally, so any special regular expression characters do not + need to be escaped. If ``utils.FILTER_FULL_TEXT`` is ``true``, then the + search tokens can match any part of ``text``. If it is ``false``, then the + matches must happen at the beginning of words within ``text``. You can change + the value of ``utils.FILTER_FULL_TEXT`` in `gui/control-panel` on the + "Preferences" tab. + +* ``utils.call_with_string(obj,methodname,...)`` + + Allocates a temporary string object, calls ``obj:method(tmp,...)``, and + returns the value written into the temporary after deleting it. + +* ``utils.getBuildingName(building)`` + + Returns the string description of the given building. + +* ``utils.getBuildingCenter(building)`` + + Returns an x/y/z table pointing at the building center. + +* ``utils.split_string(string, delimiter)`` + + Splits the string by the given delimiter, and returns a sequence of results. + +* ``utils.prompt_yes_no(prompt, default)`` + + Presents a yes/no prompt to the user. If ``default`` is not *nil*, + allows just pressing Enter to submit the default choice. + If the user enters ``'abort'``, throws an error. + +* ``utils.prompt_input(prompt, checkfun, quit_str)`` + + Presents a prompt to input data, until a valid string is entered. + Once ``checkfun(input)`` returns *true, ...*, passes the values + through. If the user enters the quit_str (defaults to ``'~~~'``), + throws an error. + +* ``utils.check_number(text)`` + + A ``prompt_input`` ``checkfun`` that verifies a number input. + +argparse +======== + +The ``argparse`` module provides functions to help scripts process commandline +parameters. + +* ``argparse.processArgs(args, validArgs)`` + + A basic commandline processing function with simple syntax, useful if your + script doesn't need the more advanced features of + ``argparse.processArgsGetopt()``. + + If ``validArgs`` is specified, it should contain a set of valid option names + (without the leading dashes). For example:: + + argparse.processArgs(args, utils.invert{'opt1', 'opt2', 'opt3'}) + + ``processArgs`` returns a map of option names it found in ``args`` to: + + - the token that came after the option + - ``''`` if the next token was another option + - a list of strings if the next token was ``'['`` (see below) + + Options in ``args`` from the commandline can be prefixed with either one dash + (``'-'``) or two dashes (``'--'``). The user can add a backslash before the + dash to allow a string to be identified as an option value instead of another + option. For example: ``yourscript --opt1 \-arg1``. + + If a ``'['`` token is found in ``args``, the subsequent tokens will be + interpreted as elements of a list until the matching closing ``']'`` is found. + Brackets can be nested, but the inner brackets will be added to the list of + tokens as literal ``'['`` and ``']'`` strings. + + Example commandlines:: + + yourscript --optName --opt2 + yourscript --optName value + yourscript --optName [ list of values ] + yourscript --optName [ list of [ nested values ] [ in square brackets ] ] + yourscript --optName \--value + + Note that ``processArgs`` does not support non-option ("positional") + parameters. They are supported by ``processArgsGetopt`` (see below). + +* ``argparse.processArgsGetopt(args, optionActions)`` + + A fully-featured commandline processing function, with behavior based on the + popular ``getopt`` library. You would use this instead of the simpler + ``processArgs`` function if any of the following are true: + + * You want both short (e.g., ``-f``) and aliased long-form (e.g., + ``--filename``) options + * You have commandline components that are not arguments to options (e.g., you + want to run your script like ``yourscript command --verbose arg1 arg2 arg3`` + instead of + ``yourscript command --verbose --opt1 arg1 --opt2 arg2 --opt3 arg3)``. + * You want the convenience of combining options into shorter strings (e.g., + ``'-abcarg'`` instead of ``'-a -b -c arg``) + * You want to be able to parse and validate the option arguments as the + commandline is being processed, as opposed to validating everything after + commandline processing is complete. + + Commandlines processed by ``processArgsGetopt`` can have both "short" and + "long" options, with each short option often having a long-form alias that + behaves exactly the same as the short form. Short options have properties that + make them very easy to type quickly by users who are familiar with your script + options. Long options, on the other hand, are easily understandable by + everyone and are useful in places where clarity is more important than + brevity, e.g., in example commands. Each option can be configured to take an + argument, which will be the string token that follows the option name on the + commandline. + + Short options are a single letter long and are specified on a commandline by + prefixing them with a single dash (e.g., the short option ``a`` would appear + on the commandline as ``-a``). Multiple successive short options that do not + take arguments can be combined into a single option string (e.g., ``'-abc'`` + instead of ``'-a -b -c'``). Moreover, the argument for a short option can be + appended directly to the single-letter option without an intervening space + (e.g., ``-d param`` can be written as ``-dparam``). These two convenience + shorthand forms can be combined, allowing groups of short parameters to be + written together, as long as at most the last short option takes an argument + (e.g., combining the previous two examples into ``-abcdparam``) + + Long options focus on clarity. They are usually entire words, or several words + combined with hyphens (``-``) or underscores (``_``). If they take an + argument, the argument can be separated from the option name by a space or an + equals sign (``=``). For example, the following two commandlines are + equivalent: ``yourscript --style pretty`` and ``yourscript --style=pretty``. + + Another reason to use long options is if they represent an esoteric parameter + that you don't expect to be commonly used and that you don't want to "waste" a + single-letter option on. In this case, you can define a long option without a + corresponding short option. + + ``processArgsGetopt`` takes two parameters:: + + args: list of space-separated strings the user wrote on the commandline + optionActions: list of option specifications + + and returns a list of positional parameters -- that is, all strings that are + neither options nor arguments to options. Options and positional parameters + can appear in any order on the commandline, as long as arguments to options + immediately follow the option itself. + + Each option specification in ``optionActions`` has the following format: + ``{shortOptionName, longOptionAlias, hasArg=boolean, handler=fn}`` + + * ``shortOptionName`` is a one-character string (or ``''`` or ``nil`` if the + parameter only has a long form). Numbers cannot be short options, and + negative numbers (e.g., ``'-10'``) will be interpreted as positional + parameters and returned in the positional parameters list. + * ``longOptionAlias`` is an optional longer form of the short option name. If + no short option name is specified, then this element is required. + * ``hasArg`` indicates whether the handler function for the option takes a + parameter. + * ``handler`` is the handler function for the option. If ``hasArg`` is + ``true`` then the next token on the commandline is passed to the handler + function as an argument. + + Example usage:: + + local args = {...} + local open_readonly, filename = false, nil -- set defaults + + local positionals = argparse.processArgsGetopt(args, { + {'r', handler=function() open_readonly = true end}, + {'f', 'filename', hasArg=true, + handler=function(optarg) filename = optarg end} + }) + + In this example, if ``args`` is ``{'first', '-rf', 'fname', 'second'}`` or, + equivalently, ``{'first', '-r', '--filename', 'myfile.txt', 'second'}`` (note + the double dash in front of the long option alias), then ``open_readonly`` + will be ``true``, ``filename`` will be ``'myfile.txt'`` and ``positionals`` + will be ``{'first', 'second'}``. + +* ``argparse.stringList(arg, arg_name, list_length)`` + + Parses a comma-separated sequence of strings and returns a lua list. Leading + and trailing spaces are trimmed from the strings. If ``arg_name`` is + specified, it is used to make error messages more useful. If ``list_length`` + is specified and greater than ``0``, then exactly that number of elements must + be found or the function will error. Example:: + + stringList('hello , world,alist', 'words') => {'hello', 'world', 'alist'} + +* ``argparse.numberList(arg, arg_name, list_length)`` + + Parses a comma-separated sequence of numeric strings and returns a list of + the discovered numbers (as numbers, not strings). If ``arg_name`` is + specified, it is used to make error messages more useful. If ``list_length`` + is specified and greater than ``0``, exactly that number of elements must be + found or the function will error. Example:: + + numberList('10, -20 , 30.5') => {10, -20, 30.5} + +* ``argparse.coords(arg, arg_name, skip_validation)`` + + Parses a comma-separated coordinate string and returns a coordinate table of + ``{x, y, z}``. If the string ``'here'`` is passed, returns the coordinates of + the active game cursor, or throws an error if the cursor is not active. This + function also verifies that the coordinates are valid for the current map and + throws if they are not (unless ``skip_validation`` is set to true). + +* ``argparse.positiveInt(arg, arg_name)`` + + Throws if ``tonumber(arg)`` is not a positive integer; otherwise returns + ``tonumber(arg)``. If ``arg_name`` is specified, it is used to make error + messages more useful. + +* ``argparse.nonnegativeInt(arg, arg_name)`` + + Throws if ``tonumber(arg)`` is not a non-negative integer; otherwise returns + ``tonumber(arg)``. If ``arg_name`` is specified, it is used to make error + messages more useful. + +* ``argparse.boolean(arg, arg_name)`` + + Converts ``string.lower(arg)`` from "yes/no/on/off/true/false/etc..." to a lua + boolean. Throws if the value can't be converted, otherwise returns + ``true``/``false``. If ``arg_name`` is specified, it is used to make error + messages more useful. + +dumper +====== + +A third-party lua table dumper module from +http://lua-users.org/wiki/DataDumper. Defines one +function: + +* ``dumper.DataDumper(value, varname, fastmode, ident, indent_step)`` + + Returns ``value`` converted to a string. The ``indent_step`` + argument specifies the indentation step size in spaces. For + the other arguments see the original documentation link above. + +.. _helpdb: + +helpdb +====== + +Unified interface for DFHack tool help text. Help text is read from the rendered +text in ``hack/docs/docs/tools``. If no rendered text exists, help is read from +the script sources (for scripts) or the string passed to the ``PluginCommand`` +initializer (for plugins). See `documentation` for details on how DFHack's help +system works. + +The database is loaded when DFHack initializes, but can be explicitly refreshed +with a call to ``helpdb.refresh()`` if docs are added/changed during a play +session. + +Each entry has several properties associated with it: + +- The entry name, which is the name of a plugin, script, or command provided by + a plugin. +- The entry types, which can be ``builtin``, ``plugin``, and/or ``command``. + Entries for built-in commands (like ``ls`` or ``quicksave``) are both type + ``builtin`` and ``command``. Entries named after plugins are type ``plugin``, + and if that plugin also provides a command with the same name as the plugin, + then the entry is also type ``command``. Entry types are returned as a map + of one or more of the type strings to ``true``. +- Short help, a the ~54 character description string. +- Long help, the entire contents of the associated help file. +- A list of tags that define the groups that the entry belongs to. + +* ``helpdb.refresh()`` + + Scan for changes in available commands and their documentation. + +* ``helpdb.is_entry(str)``, ``helpdb.is_entry(list)`` + + Returns whether the given string (or list of strings) is an entry (are all + entries) in the db. + +* ``helpdb.get_entry_types(entry)`` + + Returns the set (that is, a map of string to ``true``) of entry types for the + given entry. + +* ``helpdb.get_entry_short_help(entry)`` + + Returns the short (~54 character) description for the given entry. + +* ``helpdb.get_entry_long_help(entry[, width])`` + + Returns the full help text for the given entry. If ``width`` is specified, the + text will be wrapped at that width, preserving block indents. The wrap width + defaults to 80. + +* ``helpdb.get_entry_tags(entry)`` + + Returns the set of tag names for the given entry. + +* ``helpdb.has_tag(entry, tag)`` + + Returns whether the given entry exists and has the specified tag. + +* ``helpdb.is_tag(str)``, ``helpdb.is_tag(list)`` + + Returns whether the given string (or list of strings) is a (are all) valid tag + name(s). + +* ``helpdb.get_tags()`` + + Returns the full alphabetized list of valid tag names. + +* ``helpdb.get_tag_data(tag)`` + + Returns a list of entries that have the given tag. The returned table also + has a ``description`` key that contains the string description of the tag. + +* ``helpdb.search_entries([include[, exclude]])`` + + Returns a list of names for entries that match the given filters. The list is + alphabetized by their last path component, with populated path components + coming before null path components (e.g., ``autobutcher`` will immediately + follow ``gui/autobutcher``). + The optional ``include`` and ``exclude`` filter params are maps (or lists of + maps) with the following elements: + + :str: if a string, filters by the given substring. if a table of strings, + includes entry names that match any of the given substrings. + :tag: if a string, filters by the given tag name. if a table of strings, + includes entries that match any of the given tags. + :entry_type: if a string, matches entries of the given type. if a table of + strings, includes entries that match any of the given types. + + Elements in a map are ANDed together (e.g., if both ``str`` and ``tag`` are + specified, the match is on any of the ``str`` elements AND any of the ``tag`` + elements). + + If lists of filters are passed instead of a single map, the match succeeds if + all of the filters match. + + If ``include`` is ``nil`` or empty, then all entries are included. If + ``exclude`` is ``nil`` or empty, then no entries are filtered out. + +profiler +======== + +A third-party lua profiler module from +http://lua-users.org/wiki/PepperfishProfiler. Module defines one function to +create profiler objects which can be used to profile and generate report. + +* ``profiler.newProfiler([variant[, sampling_frequency]])`` + + Returns a profile object with ``variant`` either ``'time'`` or ``'call'``. + ``'time'`` variant takes optional ``sampling_frequency`` parameter to select + lua instruction counts between samples. Default is ``'time'`` variant with + ``10*1000`` frequency. + + ``'call'`` variant has much higher runtime cost which will increase the + runtime of profiled code by factor of ten. For the extreme costs it provides + accurate function call counts that can help locate code which takes much time + in native calls. + +* ``obj:start()`` + + Resets collected statistics. Then it starts collecting new statistics. + +* ``obj:stop()`` + + Stops profile collection. + +* ``obj:report(outfile[, sort_by_total_time])`` + + Write a report from previous statistics collection to ``outfile``. + ``outfile`` should be writeable io file object (``io.open`` or + ``io.stdout``). Passing ``true`` as second parameter ``sort_by_total_time`` + switches sorting order to use total time instead of default self time order. + +* ``obj:prevent(function)`` + + Adds an ignore filter for a ``function``. It will ignore the pointed function + and all of it children. + +Examples +-------- + +:: + + local prof = profiler.newProfiler() + prof:start() + + profiledCode() + + prof:stop() + + local out = io.open( "lua-profile.txt", "w+") + prof:report(out) + out:close() + +class +===== + +Implements a trivial single-inheritance class system. + +* ``Foo = defclass(Foo[, ParentClass])`` + + Defines or updates class Foo. The ``Foo = defclass(Foo)`` syntax + is needed so that when the module or script is reloaded, the + class identity will be preserved through the preservation of + global variable values. + + The ``defclass`` function is defined as a stub in the global + namespace, and using it will auto-load the class module. + +* ``Class.super`` + + This class field is set by defclass to the parent class, and + allows a readable ``Class.super.method(self, ...)`` syntax for + calling superclass methods. + +* ``Class.ATTRS { foo = xxx, bar = yyy }`` + + Declares certain instance fields to be attributes, i.e., auto-initialized + from fields in the table used as the constructor argument. If omitted, + they are initialized with the default values specified in this declaration. + + If the default value should be *nil*, use ``ATTRS { foo = DEFAULT_NIL }``. + + Declaring an attribute is mostly the same as defining your ``init`` method + like this:: + + function Class.init(args) + self.attr1 = args.attr1 or default1 + self.attr2 = args.attr2 or default2 + ... + end + + The main difference is that attributes are processed as a separate + initialization step, before any ``init`` methods are called. They + also make the direct relation between instance fields and constructor + arguments more explicit. + +* ``new_obj = Class{ foo = arg, bar = arg, ... }`` + + Calling the class as a function creates and initializes a new instance. + Initialization happens in this order: + + 1. An empty instance table is created, and its metatable set. + 2. The ``preinit`` methods are called via ``invoke_before`` (see below) + with the table used as the argument to the class. These methods are + intended for validating and tweaking that argument table. + 3. Declared ATTRS are initialized from the argument table or their default values. + 4. The ``init`` methods are called via ``invoke_after`` with the argument table. + This is the main constructor method. + 5. The ``postinit`` methods are called via ``invoke_after`` with the argument table. + Place code that should be called after the object is fully constructed here. + +Predefined instance methods: + +* ``instance:assign{ foo = xxx }`` + + Assigns all values in the input table to the matching instance fields. + +* ``instance:callback(method_name, [args...])`` + + Returns a closure that invokes the specified method of the class, + properly passing in self, and optionally a number of initial arguments too. + The arguments given to the closure are appended to these. + +* ``instance:cb_getfield(field_name)`` + + Returns a closure that returns the specified field of the object when called. + +* ``instance:cb_setfield(field_name)`` + + Returns a closure that sets the specified field to its argument when called. + +* ``instance:invoke_before(method_name, args...)`` + + Navigates the inheritance chain of the instance starting from the most specific + class, and invokes the specified method with the arguments if it is defined in + that specific class. Equivalent to the following definition in every class:: + + function Class:invoke_before(method, ...) + if rawget(Class, method) then + rawget(Class, method)(self, ...) + end + Class.super.invoke_before(method, ...) + end + +* ``instance:invoke_after(method_name, args...)`` + + Like invoke_before, only the method is called after the recursive call to super, + i.e., invocations happen in the parent to child order. + + These two methods are inspired by the Common Lisp before and after methods, and + are intended for implementing similar protocols for certain things. The class + library itself uses them for constructors. + +To avoid confusion, these methods cannot be redefined. + +.. _custom-raw-tokens: + +custom-raw-tokens +================= + +A module for reading custom tokens added to the raws by mods. + +* ``customRawTokens.getToken(typeDefinition, token)`` + + Where ``typeDefinition`` is a type definition struct as seen in + ``df.global.world.raws`` (e.g.: ``dfhack.gui.getSelectedItem().subtype``) + and ``token`` is the name of the custom token you want read. The arguments + from the token will then be returned as strings using single or multiple + return values. If the token is not present, the result is false; if it is present + but has no arguments, the result is true. For ``creature_raw``, it checks against + no caste. For ``plant_raw``, it checks against no growth. + +* ``customRawTokens.getToken(typeInstance, token)`` + + Where ``typeInstance`` is a unit, entity, item, job, projectile, building, + plant, or interaction instance. Gets ``typeDefinition`` and then returns the same + as ``getToken(typeDefinition, token)``. For units, it gets the token from the race + or caste instead if applicable. For plant growth items, it gets the token from the + plant or plant growth instead if applicable. For plants it does the same but with + growth number -1. + +* ``customRawTokens.getToken(raceDefinition, casteNumber, token)`` + + The same as ``getToken(unit, token)`` but with a specified race and caste. + Caste number -1 is no caste. + +* ``customRawTokens.getToken(raceDefinition, casteName, token)`` + + The same as ``getToken(unit, token)`` but with a specified race and caste, using + caste name (e.g., "FEMALE") instead of number. + +* ``customRawTokens.getToken(plantDefinition, growthNumber, token)`` + + The same as ``getToken(plantGrowthItem, token)`` but with a specified plant and + growth. Growth number -1 is no growth. + +* ``customRawTokens.getToken(plantDefinition, growthName, token)`` + + The same as ``getToken(plantGrowthItem, token)`` but with a specified plant and + growth, using growth name (e.g., "LEAVES") instead of number. + +It is recommended to prefix custom raw tokens with the name of your mod to avoid +duplicate behaviour where two mods make callbacks that work on the same tag. + +Examples: + +* Using an eventful onReactionComplete hook, something for disturbing dwarven science:: + + if customRawTokens.getToken(reaction, "EXAMPLE_MOD_CAUSES_INSANITY") then + -- make unit who performed reaction go insane + +* Using an eventful onProjItemCheckMovement hook, a fast or slow-firing crossbow:: + + -- check projectile distance flown is zero, get firer, etc... + local multiplier = tonumber(customRawTokens.getToken(bow, "EXAMPLE_MOD_FIRE_RATE_MULTIPLIER")) or 1 + if firer.counters.think_counter > 0 then + firer.counters.think_counter = math.max(math.floor(firer.counters.think_counter * multiplier), 1) + end + +* Something for a script that prints help text about different types of units:: + + local unit = dfhack.gui.getSelectedUnit() + if not unit then return end + local helpText = customRawTokens.getToken(unit, "EXAMPLE_MOD_HELP_TEXT") + if helpText then print(helpText) end + +* Healing armour:: + + -- (per unit every tick) + local healAmount = 0 + for _, entry in ipairs(unit.inventory) do + if entry.mode == 2 then -- Worn + healAmount = healAmount + tonumber((customRawTokens.getToken(entry.item, "EXAMPLE_MOD_HEAL_AMOUNT")) or 0) + end + end + unit.body.blood_count = math.min(unit.body.blood_max, unit.body.blood_count + healAmount) + +.. _lua-ui-library: + +================== +In-game UI Library +================== + +.. contents:: + :local: + +A number of lua modules with names starting with ``gui`` are dedicated +to wrapping the natives of the ``dfhack.screen`` module in a way that +is easy to use. This allows relatively easily and naturally creating +dialogs that integrate in the main game UI window. + +These modules make extensive use of the ``class`` module, and define +things ranging from the basic ``Painter``, ``View`` and ``Screen`` +classes, to fully functional predefined dialogs. + +gui +=== + +This module defines the most important classes and functions for +implementing interfaces. This documents those of them that are +considered stable. + + +Misc +---- + +* ``CLEAR_PEN`` + + The black pen used to clear the screen. In graphics mode, it will clear the + foreground and set the background to the standard black tile. + +* ``TRANSPARENT_PEN`` + + A pen that will clear all textures from the UI layer, making the tile transparent. + +* ``KEEP_LOWER_PEN`` + + A pen that will write tiles over existing background tiles instead of clearing + them. + +* ``simulateInput(screen, keys...)`` + + This function wraps an undocumented native function that passes a set of + keycodes to a screen, and is the official way to do that. + + Every argument after the initial screen may be *nil*, a numeric keycode, + a string keycode, a sequence of numeric or string keycodes, or a mapping + of keycodes to *true* or *false*. For instance, it is possible to use the + table passed as argument to ``onInput``. The ``_STRING`` convenience field of + an ``onInput`` keys table will be ignored; the presence (or absence) of a + ``STRING_A???`` keycode will determine the text content of the simulated + input. + + You can send mouse clicks as well by setting the ``_MOUSE_L`` key or other + mouse-related pseudo-keys documented with the ``screen:onInput(keys)`` + function above. Note that if you are simulating a click at a specific spot on + the screen, you must set ``df.global.gps.mouse_x`` and + ``df.global.gps.mouse_y`` if you are clicking on the interface layer or + ``df.global.gps.precise_mouse_x`` and ``df.global.gps.precise_mouse_y`` if + you are clicking on the map. + +* ``mkdims_xy(x1,y1,x2,y2)`` + + Returns a table containing the arguments as fields, and also ``width`` and + ``height`` that contains the rectangle dimensions. + +* ``mkdims_wh(x1,y1,width,height)`` + + Returns the same kind of table as ``mkdims_xy``, only this time it computes + ``x2`` and ``y2``. + +* ``get_interface_rect()`` + + Returns the table rect (as per ``mkdims_xy``) for the interface area of the + screen, respecting the player's setting for ``max_interface_percentage``. + +* ``get_interface_frame()`` + + Returns the frame (as per `Widget class`_) for configuring a ``Widget`` with + a body that represents the interface area. + +* ``is_in_rect(rect,x,y)`` + + Checks if the given point is within a rectangle, represented by a table produced + by one of the ``mkdims`` functions. + +* ``blink_visible(delay)`` + + Returns *true* or *false*, with the value switching to the opposite every ``delay`` + msec. This is intended for rendering blinking interface objects. + +* ``getKeyDisplay(keycode)`` + + Wraps ``dfhack.screen.getKeyDisplay`` in order to allow using strings for + the keycode argument. + + +* ``invert_color(color, bold)`` + + This inverts the brightness of ``color``. If this color is coming from a pen's + foreground color, include ``pen.bold`` in ``bold`` for this to work properly. + + +ViewRect class +-------------- + +This class represents an on-screen rectangle with an associated independent +clip area rectangle. It is the base of the ``Painter`` class, and is used by +``Views`` to track their client area. + +* ``ViewRect{ rect = ..., clip_rect = ..., view_rect = ..., clip_view = ... }`` + + The constructor has the following arguments: + + :rect: The ``mkdims`` rectangle in screen coordinates of the logical viewport. + Defaults to the whole screen. + :clip_rect: The clip rectangle in screen coordinates. Defaults to ``rect``. + :view_rect: A ViewRect object to copy from; overrides both ``rect`` and ``clip_rect``. + :clip_view: A ViewRect object to intersect the specified clip area with. + +* ``rect:isDefunct()`` + + Returns *true* if the clip area is empty, i.e., no painting is possible. + +* ``rect:inClipGlobalXY(x,y)`` + + Checks if these global coordinates are within the clip rectangle. + +* ``rect:inClipLocalXY(x,y)`` + + Checks if these coordinates (specified relative to ``x1,y1``) are within the + clip rectangle. + +* ``rect:localXY(x,y)`` + + Converts a pair of global coordinates to local; returns *x_local,y_local*. + +* ``rect:globalXY(x,y)`` + + Converts a pair of local coordinates to global; returns *x_global,y_global*. + +* ``rect:viewport(x,y,w,h)`` or ``rect:viewport(subrect)`` + + Returns a ViewRect representing a sub-rectangle of the current one. + The arguments are specified in local coordinates; the ``subrect`` + argument must be a ``mkdims`` table. The returned object consists of + the exact specified rectangle, and a clip area produced by intersecting + it with the clip area of the original object. + + +Painter class +------------- + +The painting natives in ``dfhack.screen`` apply to the whole screen, are +completely stateless and don't implement clipping. + +The Painter class inherits from ViewRect to provide clipping and local +coordinates, and tracks current cursor position and current pen. It also +supports drawing to a separate map buffer if applicable (see ``map()`` below +for details). + +* ``Painter{ ..., pen = ..., key_pen = ... }`` + + In addition to ViewRect arguments, Painter accepts a suggestion of + the initial value for the main pen, and the keybinding pen. They + default to COLOR_GREY and COLOR_LIGHTGREEN otherwise. + + There are also some convenience functions that wrap this constructor: + + - ``Painter.new(rect,pen)`` + - ``Painter.new_view(view_rect,pen)`` + - ``Painter.new_xy(x1,y1,x2,y2,pen)`` + - ``Painter.new_wh(x1,y1,width,height,pen)`` + +* ``painter:isValidPos()`` + + Checks if the current cursor position is within the clip area. + +* ``painter:viewport(x,y,w,h)`` + + Like the superclass method, but returns a Painter object. + +* ``painter:cursor()`` + + Returns the current cursor *x,y* in screen coordinates. + +* ``painter:cursorX()`` + + Returns just the current *x* cursor coordinate + +* ``painter:cursorY()`` + + Returns just the current *y* cursor coordinate + +* ``painter:seek(x,y)`` + + Sets the current cursor position, and returns *self*. + Either of the arguments may be *nil* to keep the current value. + +* ``painter:advance(dx,dy)`` + + Adds the given offsets to the cursor position, and returns *self*. + Either of the arguments may be *nil* to keep the current value. + +* ``painter:newline([dx])`` + + Advances the cursor to the start of the next line plus the given x offset, + and returns *self*. + +* ``painter:pen(...)`` + + Sets the current pen to ``dfhack.pen.parse(old_pen,...)``, and returns *self*. + +* ``painter:color(fg[,bold[,bg]])`` + + Sets the specified colors of the current pen and returns *self*. + +* ``painter:key_pen(...)`` + + Sets the current keybinding pen to ``dfhack.pen.parse(old_pen,...)``, + and returns *self*. + +* ``painter:map(to_map)`` + + Enables or disables drawing to a separate map buffer. ``to_map`` is a boolean + that will be passed as the ``map`` parameter to any ``dfhack.screen`` functions + that accept it. Note that only third-party plugins like TWBT currently implement + a separate map buffer; if none are enabled, this function has no effect (but + should still be used to ensure proper support for such plugins). Returns *self*. + +* ``painter:clear()`` + + Fills the whole clip rectangle with ``CLEAR_PEN``, and returns *self*. + +* ``painter:fill(x1,y1,x2,y2[,...])`` or ``painter:fill(rect[,...])`` + + Fills the specified local coordinate rectangle with + ``dfhack.pen.parse(cur_pen,...)``, and returns *self*. + +* ``painter:char([char[, ...]])`` + + Paints one character using ``char`` and ``dfhack.pen.parse(cur_pen,...)``. + Returns *self*. The ``char`` argument, if not nil, is used to override the + ``ch`` property of the pen. + +* ``painter:tile([char, tile[, ...]])`` + + Like ``char()`` above, but also allows overriding the ``tile`` property on + ad-hoc basis. + +* ``painter:string(text[, ...])`` + + Paints the string with ``dfhack.pen.parse(cur_pen,...)``; returns *self*. + +* ``painter:key(keycode[, ...])`` + + Paints the description of the keycode using ``dfhack.pen.parse(cur_key_pen,...)``. + Returns *self*. + +* ``painter:key_string(keycode, text, ...)`` + + A convenience wrapper around both ``key()`` and ``string()`` that prints both + the specified keycode description and text, separated by ``:``. Any extra + arguments are passed directly to ``string()``. Returns *self*. + +Unless specified otherwise above, all Painter methods return *self*, in order to +allow chaining them like this:: + + painter:pen(foo):seek(x,y):char(1):advance(1):string('bar')... + + +View class +---------- + +This class is the common abstract base of both the stand-alone screens +and common widgets to be used inside them. It defines the basic layout, +rendering and event handling framework. + +The class defines the following attributes: + +:visible: Specifies that the view should be painted. This can be a boolean or + a function that returns a boolean. +:active: Specifies that the view should receive events, if also visible. This + can be a boolean or a function that returns a boolean. +:view_id: Specifies an identifier to easily identify the view among subviews. + This is reserved for use by script writers and should not be set by + library widgets for their internal subviews. +:on_focus: Called when the view gains keyboard focus; see ``setFocus()`` below. +:on_unfocus: Called when the view loses keyboard focus. + +It also always has the following fields: + +:subviews: Contains a table of all subviews. The sequence part of the + table is used for iteration. In addition, subviews are also + indexed under their ``view_id``, if any; see ``addviews()`` below. +:parent_view: A reference to the parent view. This field is ``nil`` until the + view is added as a subview to another view with ``addviews()``. +:focus_group: The list of widgets in a hierarchy. This table is unique and empty + when a view is initialized, but is replaced by a shared table when + the view is added to a parent via ``addviews()``. If a view in the + focus group has keyboard focus, that widget can be accessed via + ``focus_group.cur``. +:focus: A boolean indicating whether the view currently has keyboard focus. + +These fields are computed by the layout process: + +:frame_parent_rect: The ViewRect representing the client area of the parent view. +:frame_rect: The ``mkdims`` rect of the outer frame in parent-local coordinates. +:frame_body: The ViewRect representing the body part of the View's own frame. + +The class has the following methods: + +* ``view:addviews(list)`` + + Adds the views in the list to the ``subviews`` sequence. If any of the views + in the list have ``view_id`` attributes that don't conflict with existing keys + in ``subviews``, also stores them under the string keys. Finally, copies any + non-conflicting string keys from the ``subviews`` tables of the listed views. + + Thus, doing something like this:: + + self:addviews{ + Panel{ + view_id = 'panel', + subviews = { + Label{ view_id = 'label' } + } + } + } + + Would make the label accessible as both ``self.subviews.label`` and + ``self.subviews.panel.subviews.label``. + +* ``view:getWindowSize()`` + + Returns the dimensions of the ``frame_body`` rectangle. + +* ``view:getMousePos([view_rect])`` + + Returns the mouse *x,y* in coordinates local to the given ViewRect (or + ``frame_body`` if no ViewRect is passed) if it is within its clip area, or + nothing otherwise. + +* ``view:getMouseFramePos()`` + + Returns the mouse *x,y* in coordinates local to ``frame_rect`` if it is + within its clip area, or nothing otherwise. + +* ``view:updateLayout([parent_rect])`` + + Recomputes layout of the view and its subviews. If no argument is + given, re-uses the previous parent rect. The process goes as follows: + + 1. Calls ``preUpdateLayout(parent_rect)`` via ``invoke_before``. + 2. Uses ``computeFrame(parent_rect)`` to compute the desired frame. + 3. Calls ``postComputeFrame(frame_body)`` via ``invoke_after``. + 4. Calls ``updateSubviewLayout(frame_body)`` to update children. + 5. Calls ``postUpdateLayout(frame_body)`` via ``invoke_after``. + +* ``view:computeFrame(parent_rect)`` *(for overriding)* + + Called by ``updateLayout`` in order to compute the frame rectangle(s). + Should return the ``mkdims`` rectangle for the outer frame, and optionally + also for the body frame. If only one rectangle is returned, it is used + for both frames, and the margin becomes zero. + +* ``view:updateSubviewLayout(frame_body)`` + + Calls ``updateLayout`` on all children. + +* ``view:render(painter)`` + + Given the parent's painter, renders the view via the following process: + + 1. Calls ``onRenderFrame(painter, frame_rect)`` to paint the outer frame. + 2. Creates a new painter using the ``frame_body`` rect. + 3. Calls ``onRenderBody(new_painter)`` to paint the client area. + 4. Calls ``renderSubviews(new_painter)`` to paint visible children. + +* ``view:renderSubviews(painter)`` + + Calls ``render`` on all ``visible`` subviews in the order they + appear in the ``subviews`` sequence. + +* ``view:onRenderFrame(painter, rect)`` *(for overriding)* + + Called by ``render`` to paint the outer frame; by default does nothing. + +* ``view:onRenderBody(painter)`` *(for overriding)* + + Called by ``render`` to paint the client area; by default does nothing. + +* ``view:onInput(keys)`` *(for overriding)* + + Override this to handle events. By default directly calls ``inputToSubviews``. + Return a true value from this method to signal that the event has been handled + and should not be passed on to more views. + +* ``view:inputToSubviews(keys)`` + + Calls ``onInput`` on all visible active subviews, iterating the ``subviews`` + sequence in *reverse order*, so that topmost subviews get events first. + Returns ``true`` if any of the subviews handled the event. If a subview within + the view's ``focus_group`` has focus and it and all of its ancestors are + active and visible, that subview is offered the chance to handle the input + before any other subviews. + +* ``view:getPreferredFocusState()`` + + Returns ``false`` by default, but should be overridden by subclasses that may + want to take keyboard focus (if it is unclaimed) when they are added to a + parent view with ``addviews()``. + +* ``view:setFocus(focus)`` + + Sets the keyboard focus to the view if ``focus`` is ``true``, or relinquishes + keyboard focus if ``focus`` is ``false``. Views that newly acquire keyboard + focus will trigger the ``on_focus`` callback, and views that lose keyboard + focus will trigger the ``on_unfocus`` callback. While a view has focus, all + keyboard input is sent to that view before any of its siblings or parents. + Keyboard input is propagated as normal (see ``inputToSubviews()`` above) if + there is no view with focus or if the view with focus returns ``false`` from + its ``onInput()`` function. + +.. _lua-gui-screen: + +Screen class +------------ + +This is a View subclass intended for use as a stand-alone modal dialog or screen. +It adds the following methods: + +* ``screen:isShown()`` + + Returns *true* if the screen is currently in the game engine's display stack. + +* ``screen:isDismissed()`` + + Returns *true* if the screen is dismissed. + +* ``screen:isActive()`` + + Returns *true* if the screen is shown and not dismissed. + +* ``screen:invalidate()`` + + Requests a repaint. Note that currently using it is not necessary, because + repaints are constantly requested automatically, due to issues with native + screens happening otherwise. + +* ``screen:renderParent()`` + + Asks the parent native screen to render itself, or clears the screen + if impossible. + +* ``screen:sendInputToParent(...)`` + + Uses ``simulateInput`` to send keypresses to the native parent screen. + +* ``screen:show([parent])`` + + Adds the screen to the display stack with the given screen as the parent; + if parent is not specified, places this one one topmost. Before calling + ``dfhack.screen.show``, calls ``self:onAboutToShow(parent)``. Note that + ``onAboutToShow()`` can dismiss active screens, and therefore change the + potential parent. If parent is not specified, this function will re-detect + the current topmost window after ``self:onAboutToShow(parent)`` returns. + This function returns ``self`` as a convenience so you can write such code + as ``local view = MyScreen{params=val}:show()``. + +* ``screen:onAboutToShow(parent)`` *(for overriding)* + + Called when ``dfhack.screen.show`` is about to be called. + +* ``screen:onShow()`` + + Called by ``dfhack.screen.show`` once the screen is successfully shown. + +* ``screen:dismiss()`` + + Dismisses the screen. A dismissed screen does not receive any more + events or paint requests, but may remain in the display stack for + a short time until the game removes it. + +* ``screen:onDismiss()`` *(for overriding)* + + Called by ``dfhack.screen.dismiss()``. + +* ``screen:onDestroy()`` *(for overriding)* + + Called by the native code when the screen is fully destroyed and removed + from the display stack. Place code that absolutely must be called whenever + the screen is removed by any means here. + +* ``screen:onResize``, ``screen:onRender`` + + Defined as callbacks for native code. + +ZScreen class +------------- + +A screen subclass that allows multi-layer interactivity. For example, a DFHack +GUI tool implemented as a ZScreen can allow the player to interact with the +underlying map, or even other DFHack ZScreen windows! That is, even when the +DFHack tool window is visible, players will be able to use vanilla designation +tools, select units, and scan/drag the map around. + +At most one ZScreen can have input focus at a time. That ZScreen's widgets +will have a chance to handle the input before anything else. If unhandled, the +input skips all unfocused ZScreens under that ZScreen and is passed directly to +the first non-ZScreen viewscreen. There are class attributes that can be set to +control what kind of unhandled input is passed to the lower layers. + +If multiple ZScreens are visible and the player scrolls or left/right clicks on +a visible element of a non-focused ZScreen, that ZScreen will be given focus. +This allows multiple DFHack GUI tools to be usable at the same time. If the +mouse is clicked away from the ZScreen widgets, that ZScreen loses focus. If no +ZScreen has focus, all input is passed directly through to the first underlying +non-ZScreen viewscreen. + +For a ZScreen with keyboard focus, if :kbd:`Esc` or the right mouse button is +pressed, and the ZScreen widgets don't otherwise handle them, then the ZScreen +is dismissed. + +All this behavior is implemented in ``ZScreen:onInput()``, which subclasses +**must not override**. Instead, ZScreen subclasses should delegate all input +processing to subviews. Consider using a `Window class`_ widget subview as your +top level input processor. + +When rendering, the parent viewscreen is automatically rendered first, so +subclasses do not have to call ``self:renderParent()``. Calls to ``logic()`` +(a world "tick" when playing the game) are also passed through, so the game +progresses normally and can be paused/unpaused as normal by the player. Note +that passing ``logic()`` calls through to the underlying map is required for +allowing the player to drag the map with the mouse. ZScreen subclasses can set +attributes that control whether the game is paused when the ZScreen is shown and +whether the game is forced to continue being paused while the ZScreen is shown. +If pausing is forced, child ``Window`` widgets will show a force-pause indicator +to show which tool is forcing the pausing. + +ZScreen provides the following functions: + +* ``zscreen:raise()`` + + Raises the ZScreen to the top of the viewscreen stack, gives it keyboard + focus, and returns a reference to ``self``. A common pattern is to check if + a tool dialog is already active when the tool command is run and raise the + existing dialog if it exists or show a new dialog if it doesn't. See the + sample code below for an example. + +* ``zscreen:isMouseOver()`` + + The default implementation iterates over the direct subviews of the ZScreen + subclass (which usually only includes a single Window subview) and sees if + ``getMouseFramePos()`` returns a position for any of them. Subclasses can + override this function if that logic is not appropriate. + +* ``zscreen:hasFocus()`` + + Whether the ZScreen has keyboard focus. Subclasses will generally not need to + check this because they can assume if they are getting input, then they have + focus. + +ZScreen subclasses can set the following attributes: + +* ``defocusable`` (default: ``true``) + + Whether the ZScreen loses keyboard focus when the player clicks on an area + of the screen other than the tool window. If the player clicks on a different + ZScreen window, focus still transfers to that other ZScreen. + +* ``defocused`` (default: ``false``) + + Whether the ZScreen starts in a defocused state. + +* ``initial_pause`` (default: ``DEFAULT_INITIAL_PAUSE or not pass_mouse_clicks``) + + Whether to pause the game when the ZScreen is shown. If not explicitly set, + this attribute will be true if the system-wide ``DEFAULT_INITIAL_PAUSE`` is + ``true`` (which is its default value) or if the ``pass_mouse_clicks`` attribute + is ``false`` (see below). It depends on ``pass_mouse_clicks`` because if the + player normally pauses/unpauses the game with the mouse, they will not be able + to pause the game like they usually do while the ZScreen has focus. + ``DEFAULT_INITIAL_PAUSE`` can be customized permanently via `gui/control-panel` + or set for the session by running a command like:: + + :lua require('gui.widgets').DEFAULT_INITIAL_PAUSE = false + +* ``force_pause`` (default: ``false``) + + Whether to ensure the game *stays* paused while the ZScreen is shown, + regardless of whether it has input focus. + +* ``pass_pause`` (default: ``true``) + + Whether to pass the pause key to the lower viewscreens if it is not handled + by this ZScreen. + +* ``pass_movement_keys`` (default: ``false``) + + Whether to pass the map movement keys to the lower viewscreens if they are not + handled by this ZScreen. + +* ``pass_mouse_clicks`` (default: ``true``) + + Whether to pass mouse clicks to the lower viewscreens if they are not handled + by this ZScreen. + +Here is an example skeleton for a ZScreen tool window:: + + local gui = require('gui') + local widgets = require('gui.widgets') + + MyWindow = defclass(MyWindow, widgets.Window) + MyWindow.ATTRS { + frame_title='My Window', + frame={w=50, h=45}, + resizable=true, -- if resizing makes sense for your dialog + resize_min={w=50, h=20}, -- try to allow users to shrink your windows + } + + function MyWindow:init() + self:addviews{ + -- add subview widgets here + } + end + + -- implement if you need to handle custom input + --function MyWindow:onInput(keys) + -- return MyWindow.super.onInput(self, keys) + --end + + MyScreen = defclass(MyScreen, gui.ZScreen) + MyScreen.ATTRS { + focus_path='myscreen', + -- set pause and passthrough attributes as appropriate + -- (but most tools can use the defaults) + } + + function MyScreen:init() + self:addviews{MyWindow{}} + end + + function MyScreen:onDismiss() + view = nil + end + + view = view and view:raise() or MyScreen{}:show() + +ZScreenModal class +------------------ + +A ZScreen convenience subclass that sets the attributes to something +appropriate for modal dialogs. The game is force paused, and no input is passed +through to the underlying viewscreens. + +gui.widgets +=========== + +This module implements some basic widgets based on the View infrastructure. + +.. _widget: + +Widget class +------------ + +Base of all the widgets. Inherits from View and has the following attributes: + +* ``frame = {...}`` + + Specifies the constraints on the outer frame of the widget. + If omitted, the widget will occupy the whole parent rectangle. + + The frame is specified as a table with the following possible fields: + + :l: gap between the left edges of the frame and the parent. + :t: gap between the top edges of the frame and the parent. + :r: gap between the right edges of the frame and the parent. + :b: gap between the bottom edges of the frame and the parent. + :w: maximum width of the frame. + :h: maximum height of the frame. + :xalign: X alignment of the frame. + :yalign: Y alignment of the frame. + + First the ``l,t,r,b`` fields restrict the available area for + placing the frame. If ``w`` and ``h`` are not specified or + larger than the computed area, it becomes the frame. Otherwise + the smaller frame is placed within the are based on the + ``xalign/yalign`` fields. If the align hints are omitted, they + are assumed to be 0, 1, or 0.5 based on which of the ``l/r/t/b`` + fields are set. + +* ``frame_inset = {...}`` + + Specifies the gap between the outer frame, and the client area. + The attribute may be a simple integer value to specify a uniform + inset, or a table with the following fields: + + :l: left margin. + :t: top margin. + :r: right margin. + :b: bottom margin. + :x: left/right margin, if ``l`` and/or ``r`` are omitted. + :y: top/bottom margin, if ``t`` and/or ``b`` are omitted. + + Omitted fields are interpreted as having the value of 0. + +* ``frame_background = pen`` + + The pen to fill the outer frame with. Defaults to no fill. + +.. _panel: + +Panel class +----------- + +Inherits from Widget, and intended for framing and/or grouping subviews. Though +this can be used for your "main window", see the `Window class`_ below for a +more conveniently configured ``Panel`` subclass. + +Has attributes: + +* ``subviews = {}`` + + Used to initialize the subview list in the constructor. + +* ``on_render = function(painter)`` + + Called from ``onRenderBody``. + +* ``on_layout = function(frame_body)`` + + Called from ``postComputeFrame``. + +* ``draggable = bool`` (default: ``false``) +* ``drag_anchors = {}`` (default: ``{title=true, frame=false/true, body=true}``) +* ``drag_bound = 'frame' or 'body'`` (default: ``'frame'``) +* ``on_drag_begin = function()`` (default: ``nil``) +* ``on_drag_end = function(success, new_frame)`` (default: ``nil``) + + If ``draggable`` is set to ``true``, then the above attributes come into play + when the panel is dragged around the screen, either with the mouse or the + keyboard. ``drag_anchors`` sets which parts of the panel can be clicked on + with the left mouse button to start dragging. The frame is a drag anchor by + default only if ``resizable`` (below) is ``false``. ``drag_bound`` configures + whether the frame of the panel (if any) can be dragged outside the containing + parent's boundary. The body will never be draggable outside of the parent, + but you can allow the frame to cross the boundary by setting ``drag_bound`` to + ``'body'``. The boolean passed to the ``on_drag_end`` callback will be + ``true`` if the drag was "successful" (i.e., not canceled) and ``false`` + otherwise. Dragging can be canceled by right clicking while dragging with the + mouse, hitting :kbd:`Esc` (while dragging with the mouse or keyboard), or by + calling ``Panel:setKeyboardDragEnabled(false)`` (while dragging with the + keyboard). If it is more convenient to do so, you can choose to override the + ``panel:onDragBegin`` and/or the ``panel:onDragEnd`` methods instead of + setting the ``on_drag_begin`` and/or ``on_drag_end`` attributes. + +* ``resizable = bool`` (default: ``false``) +* ``resize_anchors = {}`` (default: ``{t=false, l=true, r=true, b=true}`` +* ``resize_min = {}`` (default: w and h from the ``frame``, or ``{w=5, h=5}``) +* ``on_resize_begin = function()`` (default: ``nil``) +* ``on_resize_end = function(success, new_frame)`` (default: ``nil``) + + If ``resizable`` is set to ``true``, then the player can click the mouse on + any edge specified in ``resize_anchors`` and drag the border to resize the + window. If two adjacent edges are enabled as anchors, then the tile where they + meet can be used to resize both edges at the same time. The minimum dimensions + specified in ``resize_min`` (or inherited from ``frame`` are respected when + resizing. The panel is also prevented from resizing beyond the boundaries of + its parent. When the player clicks on a valid anchor, ``on_resize_begin()`` is + called. The boolean passed to the ``on_resize_end`` callback will be ``true`` + if the drag was "successful" (i.e., not canceled) and ``false`` otherwise. + Dragging can be canceled by right clicking while resizing with the mouse, + hitting :kbd:`Esc` (while resizing with the mouse or keyboard), or by calling + ``Panel:setKeyboardResizeEnabled(false)`` (while resizing with the keyboard). + If it is more convenient to do so, you can choose to override the + ``panel:onResizeBegin`` and/or the ``panel:onResizeEnd`` methods instead of + setting the ``on_resize_begin`` and/or ``on_resize_end`` attributes. + +* ``autoarrange_subviews = bool`` (default: ``false``) +* ``autoarrange_gap = int`` (default: ``0``) + + If ``autoarrange_subviews`` is set to ``true``, the Panel will + automatically handle subview layout. Subviews are laid out vertically + according to their current height, with ``autoarrange_gap`` empty lines + between subviews. This allows you to have widgets dynamically change + height or become visible/hidden and you don't have to worry about + recalculating subview positions. + +* ``frame_style``, ``frame_title`` (default: ``nil``) + + If defined, a frame will be drawn around the panel and subviews will be + inset by 1. The following predefined frame styles are defined: + + * ``FRAME_WINDOW`` + + A frame suitable for a draggable, optionally resizable window. + + * ``FRAME_PANEL`` + + A frame suitable for a static (non-resizable) panel. + + * ``FRAME_MEDIUM`` + + A frame suitable for overlay widget panels. + + * ``FRAME_THIN`` + + A frame suitable for floating tooltip panels that need the DFHack signature. + + * ``FRAME_BOLD`` + + A frame suitable for a non-draggable panel meant to capture the user's + focus, like an important notification, confirmation dialog or error message. + + * ``FRAME_INTERIOR`` + + A frame suitable for light interior accent elements. This frame does *not* + have a visible ``DFHack`` signature on it, so it must not be used as the + external frame for a DFHack-owned UI. + + * ``FRAME_INTERIOR_MEDIUM`` + + A copy of ``FRAME_MEDIUM`` that lacks the ``DFHack`` signature. Suitable for + panels that are part of a larger widget cluster. Must *not* be used as the + external frame for a DFHack-owned UI. + + When using the predefined frame styles in the ``gui`` module, remember to + ``require`` the gui module and prefix the identifier with ``gui.``, e.g., + ``gui.FRAME_THIN``. + +* ``no_force_pause_badge`` (default: ``false``) + + If true, then don't display the PAUSE FORCED badge on the frame even if the + game has been force paused. + +Has functions: + +* ``panel:setKeyboardDragEnabled(bool)`` + + If called with ``true`` and the panel is not already in keyboard drag mode, + then any current drag or resize operations are halted where they are (not + canceled), the panel seizes input focus (see `View class`_ above for + information on the DFHack focus subsystem), and further keyboard cursor keys + move the window as if it were being dragged. Shift-cursor keys move by larger + amounts. Hit :kbd:`Enter` to commit the new window position or :kbd:`Esc` to + cancel. If dragging is canceled, then the window is moved back to its original + position. + +* ``panel:setKeyboardResizeEnabled(bool)`` + + If called with ``true`` and the panel is not already in keyboard resize mode, + then any current drag or resize operations are halted where they are (not + canceled), the panel seizes input focus (see `View class`_ above for + information on the DFHack focus subsystem), and further keyboard cursor keys + resize the window as if it were being dragged from the lower right corner. If + neither the bottom or right edge is a valid anchor, an appropriate corner will + be chosen. Shift-cursor keys move by larger amounts. Hit :kbd:`Enter` to + commit the new window size or :kbd:`Esc` to cancel. If resizing is canceled, + then the window size from before the resize operation is restored. + +* ``panel:onDragBegin()`` +* ``panel:onDragEnd(success, new_frame)`` +* ``panel:onResizeBegin()`` +* ``panel:onResizeEnd(success, new_frame)`` + +The default implementations of these methods call the associated attribute (if +set). You can override them in a subclass if that is more convenient than +setting the attributes. + +Double clicking: + +If the panel is resizable and the user double-clicks on the top edge (the frame +title, if the panel has a frame), then the panel will jump to its maximum size. +If the panel has already been maximized in this fashion, then it will jump to +its minimum size. Both jumps respect the resizable edges defined by the +``resize_anchors`` attribute. + +The time duration that a double click can span can be controlled via the +`control-panel` or `gui/control-panel` interfaces (``Mouse double click speed`` +option). It defaults to 500 ms. + +Window class +------------ + +Subclass of Panel; sets Panel attributes to useful defaults for a top-level +framed, draggable window. + +ResizingPanel class +------------------- + +Subclass of Panel; automatically adjusts its own frame height and width to the +minimum required to show its subviews. Pairs nicely with a parent Panel that has +``autoarrange_subviews`` enabled. + +It has the following attributes: + +:auto_height: Sets self.frame.h from the positions and height of its subviews + (default is ``true``). +:auto_width: Sets self.frame.w from the positions and width of its subviews + (default is ``false``). + +Pages class +----------- + +Subclass of Panel; keeps exactly one child visible. + +* ``Pages{ ..., selected = ... }`` + + Specifies which child to select initially; defaults to the first one. + +* ``pages:getSelected()`` + + Returns the selected *index, child*. + +* ``pages:setSelected(index)`` + + Selects the specified child, hiding the previous selected one. + It is permitted to use the subview object, or its ``view_id`` as index. + +Divider class +------------- + +Subclass of Widget; implements a divider line that can optionally connect to +existing frames via T-junction edges. A ``Divider`` instance is required to +have a ``frame`` that is either 1 unit tall or 1 unit wide. + +``Divider`` widgets should be a sibling with the framed ``Panel`` that they +are dividing, and they should be added to the common parent widget **after** +the ``Panel`` so that the ``Divider`` can overwrite the ``Panel`` frame with +the appropriate T-junction graphic. If the ``Divider`` will not have +T-junction edges, then it could potentially be a child of the ``Panel`` since +the ``Divider`` won't need to overwrite the ``Panel``'s frame. + +If two ``Divider`` widgets are set to cross, then you must have a third 1x1 +``Divider`` widget for the crossing tile so the other two ``Divider``\s can +be seamlessly connected. + +Attributes: + +* ``frame_style`` + + The ``gui`` ``FRAME`` instance to use for the graphical tiles. Defaults to + ``gui.FRAME_THIN``. + +* ``interior`` + + Whether the edge T-junction tiles should connect to interior lines (e.g., the + vertical or horizontal segment of another ``Divider`` instance) or the + exterior border of a ``Panel`` frame. Defaults to ``false``, meaning + exterior T-junctions will be chosen. + +* ``frame_style_t`` +* ``frame_style_b`` +* ``frame_style_l`` +* ``frame_style_r`` + + Overrides for the frame style for specific T-junctions. Note that there are + not currently any frame styles that allow borders of different weights to be + seamlessly connected. If set to ``false``, then the indicated edge will end + in a straight segment instead of a T-junction. + +* ``interior_t`` +* ``interior_b`` +* ``interior_l`` +* ``interior_r`` + + Overrides for the interior/exterior specification for specific T-junctions. + +EditField class +--------------- + +Subclass of Widget; implements a simple edit field. + +Attributes: + +:label_text: The optional text label displayed before the editable text. +:text: The current contents of the field. +:text_pen: The pen to draw the text with. +:on_char: Input validation callback; used as ``on_char(new_char,text)``. + If it returns false, the character is ignored. +:on_change: Change notification callback; used as ``on_change(new_text,old_text)``. +:on_submit: Enter key callback; if set the field will handle the key and call ``on_submit(text)``. +:key: If specified, the field is disabled until this key is pressed. Must be given as a string. +:key_sep: If specified, will be used to customize how the activation key is + displayed. See ``token.key_sep`` in the ``Label`` documentation below. +:modal: Whether the ``EditField`` should prevent input from propagating to other + widgets while it has focus. You can set this to ``true``, for example, + if you don't want a ``List`` widget to react to arrow keys while the + user is editing. +:ignore_keys: If specified, must be a list of key names that the edit field + should ignore. This is useful if you have plain string characters + that you want to use as hotkeys (like ``+``). + +An ``EditField`` will only read and process text input if it has keyboard focus. +It will automatically acquire keyboard focus when it is added as a subview to +a parent that has not already granted keyboard focus to another widget. If you +have more than one ``EditField`` on a screen, you can select which has focus by +calling ``setFocus(true)`` on the field object. + +If an activation ``key`` is specified, the ``EditField`` will manage its own +focus. It will start in the unfocused state, and pressing the activation key +will acquire keyboard focus. Pressing the Enter key will release keyboard focus +and then call the ``on_submit`` callback. Pressing the Escape key (or r-clicking +with the mouse) will also release keyboard focus, but first it will restore the +text that was displayed before the ``EditField`` gained focus and then call the +``on_change`` callback. + +The ``EditField`` cursor can be moved to where you want to insert/remove text. +You can click where you want the cursor to move or you can use any of the +following keyboard hotkeys: + +- Left/Right arrow: move the cursor one character to the left or right +- Ctrl-Left/Ctrl-Right: move the cursor one word back or forward +- Home/End: move the cursor to the beginning/end of the text + +The widget also supports integration with the system clipboard: + +- Ctrl-C: copy current text to the system clipboard +- Ctrl-X: copy current text to the system clipboard and clear text in widget +- Ctrl-V: paste text from the system clipboard (text is converted to cp437) + +The ``EditField`` class also provides the following functions: + +* ``editfield:setCursor([cursor_pos])`` + + Sets the text insert cursor to the specified position. If ``cursor_pos`` is + not specified or is past the end of the current text string, the cursor will + be set to the end of the current input (that is, ``#editfield.text + 1``). + +* ``editfield:setText(text[, cursor_pos])`` + + Sets the input text string and, optionally, the cursor position. If the + cursor position is not specified, it sets it to the end of the string. + +* ``editfield:insert(text)`` + + Inserts the given text at the current cursor position. + +TextArea class +-------------- + +Subclass of Panel; implements a multi-line text field with features such as +text wrapping, mouse control, text selection, clipboard support, history, +and typical text editor shortcuts. + +Cursor Behavior +~~~~~~~~~~~~~~~ + +The cursor in the ``TextArea`` class is index-based, starting from 1, +consistent with Lua's text indexing conventions. + +Each character, including newlines (``string.char(10)``), +occupies a single index in the text content. + +Cursor movement and position are fully aware of line breaks, +meaning they count as one unit in the offset. + +The cursor always points to the position between characters, +with 1 being the position before the first character and +``#text + 1`` representing the position after the last character. + +Cursor positions are preserved during text operations like insertion, +deletion, or replacement. If changes affect the cursor's position, +it will be adjusted to the nearest valid index. + +TextArea Attributes: + +* ``init_text``: The initial text content for the text area. + +* ``init_cursor``: The initial cursor position within the text content. + If not specified, defaults to end of the text (length of ``init_text`` + 1). + +* ``text_pen``: Optional pen used to draw the text. Default is ``COLOR_LIGHTCYAN``. + +* ``select_pen``: Optional pen used for text selection. Default is ``COLOR_CYAN``. + +* ``ignore_keys``: List of input keys to ignore. + Functions similarly to the ``ignore_keys`` attribute in the ``EditField`` class. + +* ``on_text_change``: Callback function called whenever the text changes. + The function signature should be ``on_text_change(new_text, old_text)``. + +* ``on_cursor_change``: Callback function called whenever the cursor position changes. + Expected function signature is ``on_cursor_change(new_cursor, old_cursor)``. + +* ``one_line_mode``: If set to ``true``, disables multi-line text features. + In this mode the :kbd:`Enter` key is not handled by the widget + as if it were included in ``ignore_keys``. + If multiline text (including ``\n`` chars) is pasted into the widget, newlines are removed. + +TextArea Functions: + +* ``textarea:getText()`` + + Returns the current text content of the ``TextArea`` widget as a string. + ``\n`` characters (``string.char(10)``) should be interpreted as new lines + +* ``textarea:setText(text)`` + + Sets the content of the ``TextArea`` to the specified string ``text``. + The cursor position will not be adjusted, so should be set separately. + +* ``textarea:getCursor()`` + + Returns the current cursor position within the text content. + The position is represented as a single integer, starting from 1. + +* ``textarea:setCursor(cursor)`` + + Sets the cursor position within the text content. + +* ``textarea:scrollToCursor()`` + + Scrolls the text area view to ensure that the current cursor position is visible. + This happens automatically when the user interactively moves the cursor or + pastes text into the widget, but may need to be called when ``setCursor`` is + called programmatically. + +* ``textarea:clearHistory()`` + + Clears undo/redo history of the widget. + +Functionality +~~~~~~~~~~~~~ + +The TextArea widget provides a familiar and intuitive text editing experience with baseline features such as: + +- Text Wrapping: Automatically fits text within the display area. +- Mouse and Keyboard Support: Standard keys like :kbd:`Home`, :kbd:`End`, :kbd:`Backspace`, and :kbd:`Delete` are supported, + along with gestures like double-click to select a word or triple-click to select a line. +- Clipboard Operations: copy, cut, and paste, + with intuitive defaults when no text is selected. +- Undo/Redo: :kbd:`Ctrl` + :kbd:`Z` and :kbd:`Ctrl` + :kbd:`Y` for quick changes. +- Additional features include advanced navigation, line management, + and smooth scrolling for handling long text efficiently. + +Detailed list: + +- Cursor Control: Navigate through text using arrow keys (Left, Right, Up, + and Down) for precise cursor placement. +- Mouse Control: Use the mouse to position the cursor within the text, + providing an alternative to keyboard navigation. +- Text Selection: Select text with the mouse, with support for replacing or + removing selected text. +- Select Word/Line: Use double click to select current word, or triple click to + select current line. +- Move By Word: Use :kbd:`Ctrl` + :kbd:`Left` and :kbd:`Ctrl` + :kbd:`Right` to + move the cursor one word back or forward. +- Line Navigation: :kbd:`Home` moves the cursor to the beginning of the current + line, and :kbd:`End` moves it to the end. +- Jump to Beginning/End: Quickly move the cursor to the beginning or end of the + text using :kbd:`Ctrl` + :kbd:`Home` and :kbd:`Ctrl` + :kbd:`End`. +- Longest X Position Memory: The cursor remembers the longest x position when + moving up or down, making vertical navigation more intuitive. +- New Lines: Easily insert new lines using the :kbd:`Enter` key, supporting + multiline text input. +- Text Wrapping: Text automatically wraps within the editor, ensuring lines fit + within the display without manual adjustments. +- Scrolling for long text entries. +- Backspace Support: Use the backspace key to delete characters to the left of + the cursor. +- Delete Character: :kbd:`Delete` deletes the character under the cursor. +- Delete Current Line: :kbd:`Ctrl` + :kbd:`U` deletes the entire current line + where the cursor is located. +- Delete Rest of Line: :kbd:`Ctrl` + :kbd:`K` deletes text from the cursor to + the end of the line. +- Delete Last Word: :kbd:`Ctrl` + :kbd:`W` removes the word immediately before + the cursor. +- Select All: Select entire text by :kbd:`Ctrl` + :kbd:`A`. +- Undo/Redo: Undo/Redo changes by :kbd:`Ctrl` + :kbd:`Z` / :kbd:`Ctrl` + + :kbd:`Y`. +- Clipboard Operations: Perform OS clipboard cut, copy, and paste operations on + selected text, allowing you to paste the copied content into other + applications. +- Copy Text: Use :kbd:`Ctrl` + :kbd:`C` to copy selected text. + - copy selected text, if available + - if no text is selected it copy the entire current line, including the + terminating newline if present +- Cut Text: Use :kbd:`Ctrl` + :kbd:`X` to cut selected text. + - cut selected text, if available + - if no text is selected it will cut the entire current line, including the + terminating newline if present +- Paste Text: Use :kbd:`Ctrl` + :kbd:`V` to paste text from the clipboard into + the editor. + - replace selected text, if available + - If no text is selected, paste text in the cursor position + +Scrollbar class +--------------- + +This Widget subclass implements mouse-interactive scrollbars whose bar sizes +represent the amount of content currently visible in an associated display +widget (like a `Label class`_ or a `List class`_). They are styled like scrollbars +used in vanilla DF. + +Scrollbars have the following attributes: + +:on_scroll: A callback called when the scrollbar is scrolled. If the scrollbar + is clicked, the callback will be called with one of the following string parameters: + "up_large", "down_large", "up_small", or "down_small". If the scrollbar is dragged, + the callback will be called with the value that ``top_elem`` should be set to on + the next call to ``update()`` (see below). + +The Scrollbar widget implements the following methods: + +* ``scrollbar:update(top_elem, elems_per_page, num_elems)`` + + Updates the info about the widget that the scrollbar is paired with. + The ``top_elem`` param is the (one-based) index of the first visible element. + The ``elems_per_page`` param is the maximum number of elements that can be + shown at one time. The ``num_elems`` param is the total number of elements + that the paired widget can scroll through. If ``elems_per_page`` or + ``num_elems`` is not specified, the most recently specified value for these + parameters is used. The scrollbar will adjust its scrollbar size and position + according to the values passed to this function. + +Clicking on the arrows at the top or the bottom of a scrollbar will scroll an +associated widget by a small amount. Clicking on the unfilled portion of the +scrollbar above or below the filled area will scroll by a larger amount in that +direction. The amount of scrolling done in each case in determined by the +associated widget, and after scrolling is complete, the associated widget must +call ``scrollbar:update()`` with updated new display info. + +If the mouse wheel is scrolled while the mouse is over the Scrollbar widget's +parent view, then the parent is scrolled accordingly. Holding :kbd:`Shift` +while scrolling will result in faster movement. + +You can click and drag the scrollbar to scroll to a specific spot, or you can +click and hold on the end arrows or in the unfilled portion of the scrollbar to +scroll multiple times, just like in a normal browser scrollbar. The speed of +scroll events when the mouse button is held down can be controlled +via the `control-panel` or `gui/control-panel` interfaces: + +1. The delay before the second scroll event is the ``Mouse initial scroll repeat + delay`` setting (default is 300 ms) + +2. The delay between further scroll events is the ``Mouse scroll repeat delay`` option + (default is 20 ms) + +Label class +----------- + +This Widget subclass implements flowing semi-static text. + +It has the following attributes: + +:text_pen: Specifies the pen for active text. +:text_dpen: Specifies the pen for disabled text. +:text_hpen: Specifies the pen for text hovered over by the mouse, if a click + handler is registered. By default, this will invert the foreground and + background colors. +:disabled: Boolean or a callback; if true, the label is disabled. +:enabled: Boolean or a callback; if false, the label is disabled. +:auto_height: Sets self.frame.h from the text height. +:auto_width: Sets self.frame.w from the text width. +:on_click: A callback called when the label is clicked (optional) +:on_rclick: A callback called when the label is right-clicked (optional) +:scroll_keys: Specifies which keys the label should react to as a table. The + table should map keys to the number of lines to scroll as positive or + negative integers or one of the keywords supported by the ``scroll`` + method. The default is up/down arrows scrolling by one line and page + up/down scrolling by one page. + +``text_pen``, ``text_dpen``, and ``text_hpen`` can either be a pen or a +function that dynamically returns a pen. + +The text itself is represented as a complex structure, and passed +to the object via the ``text`` argument of the constructor, or via +the ``setText`` method, as one of: + +* A simple string, possibly containing newlines. +* A sequence of tokens. + +Every token in the sequence in turn may be either a string, possibly +containing newlines (or equal to ``NEWLINE``), or a table with the following +possible fields: + +* ``token.text = ...`` + + Specifies the main text content of a token, and may be a string, or + a callback returning a string. + +* ``token.gap = ...`` + + Specifies the number of character positions to advance on the line + before rendering the token. + +* ``token.tile``, ``token.htile`` + + Specifies a pen or texture index (or a function that returns a pen or texture + index) to paint as one tile before the main part of the token. If ``htile`` + is specified, that is used instead of ``tile`` when the Label is hovered over + with the mouse. + +* ``token.width = ...`` + + If specified either as a value or a callback, the text (or tile) field is + padded or truncated to the specified number. + +* ``token.pad_char = '?'`` + + If specified together with ``width``, the padding area is filled with + this character instead of just being skipped over. + +* ``token.key = '...'`` + + Specifies the keycode associated with the token. The string description + of the key binding is added to the text content of the token. + +* ``token.key_sep = '...'`` + + Specifies the separator to place between the keybinding label produced + by ``token.key``, and the main text of the token. If the separator starts with + '()', the token is formatted as ``text..' ('..binding..sep:sub(2)``. Otherwise + it is simply ``binding..sep..text``. + +* ``token.enabled``, ``token.disabled`` + + Same as the attributes of the label itself, but applies only to the token. + +* ``token.pen``, ``token.dpen``, ``token.hpen`` + + Specify the pen, disabled pen, and hover pen to be used for the token's text. + The fields may be either the pen itself, or a callback that returns it. + +* ``token.on_activate`` + + If this field is not nil, and ``token.key`` is set, the token will actually + respond to that key binding unless disabled, and call this callback. Eventually + this may be extended with mouse click support. + +* ``token.id`` + + Specifies a unique identifier for the token. + +* ``token.line``, ``token.x1``, ``token.x2`` + + Reserved for internal use. + +The Label widget implements the following methods: + +* ``label:setText(new_text)`` + + Replaces the text currently contained in the widget. + +* ``label:itemById(id)`` + + Finds a token by its ``id`` field. + +* ``label:getTextHeight()`` + + Computes the height of the text. + +* ``label:getTextWidth()`` + + Computes the width of the text. + +* ``label:scroll(nlines)`` + + This method takes the number of lines to scroll as positive or negative + integers or one of the following keywords: ``+page``, ``-page``, + ``+halfpage``, ``-halfpage``, ``home``, or ``end``. It returns the number of + lines that were actually scrolled (negative for scrolling up). + +* ``label:shouldHover()`` + + This method returns whether or not this widget should show a hover effect, + generally you want to return ``true`` if there is some type of mouse handler + present. For example, for a ``HotKeyLabel``:: + + function HotkeyLabel:shouldHover() + -- When on_activate is set, text should also hover on mouseover + return HotkeyLabel.super.shouldHover(self) or self.on_activate + end + +The widgets module also provides the following methods for help in constructing +common text token lists that you can then pass as ``text`` to a ``Label``: + +* ``makeButtonLabelText(spec)`` + + Returns a list of ``Label`` text tokens that represent a button according + to the given ``spec``, which is a table with the following fields. Fields + that contain ``_hover`` are optional and specify alternate values to be + used when the mouse cursor is hovering over the button. + + - ``chars``, ``chars_hover``: A list of strings or a list of lists of + characters. These strings (or lists of characters) make up the ASCII + representation of the button. If a list of strings is passed, each + string must be the same length. ``chars`` is the only required element + in the spec. If ``chars_hover`` is not specified, it defaults to the + value of ``chars``. + + - ``pens``, ``pens_hover``: A color or a pen or a list of lists of colors + or pens. This controls what color and other pen properties should be + applied to the corresponding button tile position. If a single color or + pen is passed, then that color or pen will apply to all tiles of the + button. If not specified, ``pens`` defaults to ``COLOR_GRAY`` and + ``pens_hover`` defaults to ``COLOR_WHITE`` + + - ``tileset``, ``tileset_hover``: If specified, must be a tileset that was + returned from ``dfhack.textures.loadTileset``. + + - ``tileset_offset``, ``tileset_hover_offset``: The 1-based offset within + the tileset to the tile that represents the upper left corner of the + button. If not specified, defaults to ``1``. + + - ``tileset_stride``, ``tileset_hover_stride``: The number of tiles in one + row of the tileset. This is used to find the start position of + subsequent rows of tiles for the button. If not specified, defaults to + the width of a button row specified in ``chars``, which is appropriate + for a tileset that has only a single button image per logical row. + + - ``asset``, ``asset_hover``: If specified, must be a table defining a + graphic asset loaded by DF from the vanilla sprite sheets or a mod. The + table must indicate which sprite page to read and the x and y offsets + of the upper left corner of the target asset in the following format: + ``{page=pagename, x=x_offset, y=y_offset}``. + + - ``tiles_override``, ``tiles_hover_override``: A list of lists of integers + representing raw tile texpos values to be displayed at the + corresponding button position. Tiles specified here will override + corresponding tiles from ``tileset`` and ``asset``. The lists can be + sparse, so any unspecified values in the override array will fall + through to other specifiers. + + If no tile is set for a particular button position, the corresponding + pen is used without setting a ``tile`` value. + + Example 1: The civ-alert button - a text-only (no graphic tiles) button + that highlights the text on hover:: + + widgets.Label{ + text=widgets.makeButtonLabelText{ + chars={ + ' Activate ', + ' civilian ', + ' alert ', + }, + pens={fg=COLOR_BLACK, bg=COLOR_LIGHTRED}, + pens_hover={fg=COLOR_WHITE, bg=COLOR_RED}, + }, + on_click=sound_alarm, + }, + + Example 2: The DFHack logo - a graphical button in graphics mode and a text + button in ASCII mode. The ASCII colors use the default for hovering:: + + local logo_textures=dfhack.textures.loadTileset( + 'hack/data/art/logo.png', 8, 12, true), + widgets.Label{ + text=widgets.makeButtonLabelText{ + chars={ + {179, 'D', 'F', 179}, + {179, 'H', 'a', 179}, + {179, 'c', 'k', 179}, + }, + tileset=logo_textures, + tileset_offset=1, + tileset_stride=8, + tileset_hover=logo_textures, + tileset_hover_offset=5, + tileset_hover_stride=8, + }, + on_click=function() + dfhack.run_command{'hotkeys', 'menu', self.name} + end, + }, + + Example 3: One of the warm/damp toolbar buttons - similar to example 2, but + with custom colors throughout the button when in ASCII mode:: + + widgets.Label{ + text=widgets.makeButtonLabelText{ + chars={ + {218, 196, 196, 191}, + {179, '~', '~', 179}, + {192, 196, 196, 217}, + }, + pens={ + {COLOR_WHITE, COLOR_WHITE, COLOR_WHITE, COLOR_WHITE}, + {COLOR_WHITE, COLOR_RED, COLOR_GRAY, COLOR_WHITE}, + {COLOR_WHITE, COLOR_WHITE, COLOR_WHITE, COLOR_WHITE}, + }, + tileset=toolbar_textures, + tileset_offset=25, + tileset_stride=8, + }, + on_click=launch_warm_damp_dig_config, + }, + + Example 4: A copy of the mining toolbar button (except that it has a + highlight on hover), loaded from the DF assets:: + + widgets.Label{ + text=widgets.makeButtonLabelText{ + chars={ + {218, 196, 196, 191}, + {179, '-', ')', 179}, + {192, 196, 196, 217}, + }, + pens={ + {COLOR_GRAY, COLOR_GRAY, COLOR_GRAY, COLOR_GRAY}, + {COLOR_GRAY, COLOR_BROWN, COLOR_GRAY, COLOR_GRAY}, + {COLOR_GRAY, COLOR_GRAY, COLOR_GRAY, COLOR_GRAY}, + }, + pens_hover={ + {COLOR_WHITE, COLOR_WHITE, COLOR_WHITE, COLOR_WHITE}, + {COLOR_WHITE, COLOR_BROWN, COLOR_GRAY, COLOR_WHITE}, + {COLOR_WHITE, COLOR_WHITE, COLOR_WHITE, COLOR_WHITE}, + }, + asset={page='INTERFACE_BITS', x=0, y=22}, + }, + on_click=self:callback('mining_menu'), + }, + + Example 5: A copy of the mining toolbar button (except that it has a + custom hotkey hint in the upper corner), loaded from the DF assets and with + one tile overridden:: + + widgets.Label{ + text=widgets.makeButtonLabelText{ + chars={ + {218, 196, 196, self.hint_char}, + {179, '-', ')', 179}, + {192, 196, 196, 217}, + }, + pens={ + {COLOR_GRAY, COLOR_GRAY, COLOR_GRAY, COLOR_RED}, + {COLOR_GRAY, COLOR_BROWN, COLOR_GRAY, COLOR_GRAY}, + {COLOR_GRAY, COLOR_GRAY, COLOR_GRAY, COLOR_GRAY}, + }, + asset={page='INTERFACE_BITS', x=0, y=22}, + tiles_override={{[4]=string.byte(self.hint_char)}}, + }, + on_click=self:callback('mining_menu'), + }, + +WrappedLabel class +------------------ + +This Label subclass represents text that you want to be able to dynamically +wrap. This frees you from having to pre-split long strings into multiple lines +in the Label ``text`` list. + +It has the following attributes: + +:text_to_wrap: The string (or a table of strings or a function that returns a + string or a table of strings) to display. The text will be autowrapped to + the width of the widget, though any existing newlines will be kept. +:indent: The number of spaces to indent the text from the left margin. The + default is ``0``. + +The displayed text is refreshed and rewrapped whenever the widget bounds change. +To force a refresh (to pick up changes in the string that ``text_to_wrap`` +returns, for example), all ``updateLayout()`` on this widget or on a widget that +contains this widget. + +TooltipLabel class +------------------ + +This WrappedLabel subclass represents text that you want to be able to +dynamically hide, like help text in a tooltip. + +It has the following attributes: + +:show_tooltip: Boolean or a callback; if true, the widget is visible. + +The ``text_pen`` attribute of the ``Label`` class is overridden with a default +of ``COLOR_GREY`` and the ``indent`` attribute of the ``WrappedLabel`` class is +overridden with a default of ``2``. + +The text of the tooltip can be passed in the inherited ``text_to_wrap`` +attribute so it can be autowrapped, or in the basic ``text`` attribute if no +wrapping is required. + +HotkeyLabel class +----------------- + +This Label subclass is a convenience class for formatting text that responds to +a hotkey or mouse click. + +It has the following attributes: + +:key: The hotkey keycode to display, e.g., ``'CUSTOM_A'``. +:key_sep: If specified, will be used to customize how the activation key is + displayed. See ``token.key_sep`` in the ``Label`` documentation. +:label: The string (or a function that returns a string) to display after the + hotkey. +:on_activate: If specified, it is the callback that will be called whenever + the hotkey is pressed or the label is clicked. + +The HotkeyLabel widget implements the following methods: + +* ``hotkeylabel:setLabel(label)`` + + Updates the label without altering the hotkey text. + +* ``hotkeylabel:setOnActivate(on_activate)`` + + Updates the on_activate callback. + +CycleHotkeyLabel class +---------------------- + +This Label subclass represents a group of related options that the user can +cycle through by pressing a specified hotkey or clicking on the text. + +It has the following attributes: + +:key: The hotkey keycode to display, e.g., ``'CUSTOM_A'``. +:key_back: Similar to ``key``, but will cycle backwards (optional) +:key_sep: If specified, will be used to customize how the activation key is + displayed. See ``token.key_sep`` in the ``Label`` documentation. +:label: The string (or a function that returns a string) to display after the + hotkey. +:label_width: The number of spaces to allocate to the ``label`` (for use in + aligning a column of ``CycleHotkeyLabel`` labels). +:label_below: If ``true``, then the option value will appear below the label + instead of to the right of it. Defaults to ``false``. +:option_gap: The size of the gap between the label text and the option value. + Default is ``1``. If set to ``0``, there'll be no gap between the strings. + If ``label_below`` == ``true``, negative values will shift the value leftwards. +:options: A list of strings or tables of + ``{label=string or fn, value=val[, pen=pen]}``. String options use the same + string for the label and value and use the default pen. The optional ``pen`` + element could be a color like ``COLOR_RED``. +:initial_option: The value or numeric index of the initial option. +:on_change: The callback to call when the selected option changes. It is called + as ``on_change(new_option_value, old_option_value)``. + +The index of the currently selected option in the ``options`` list is kept in +the ``option_idx`` instance variable. + +The CycleHotkeyLabel widget implements the following methods: + +* ``cyclehotkeylabel:cycle([backwards])`` + + Cycles the selected option and triggers the ``on_change`` callback. + If ``backwards`` is defined and is truthy, the cycle direction will be reversed + +* ``cyclehotkeylabel:setOption(value_or_index, call_on_change)`` + + Sets the current option to the option with the specified value or + index. If ``call_on_change`` is set to ``true``, then the ``on_change`` + callback is triggered. + +* ``cyclehotkeylabel:getOptionLabel([option_idx])`` + + Retrieves the option label at the given index, or the label of the + currently selected option if no index is given. + +* ``cyclehotkeylabel:getOptionValue([option_idx])`` + + Retrieves the option value at the given index, or the value of the + currently selected option if no index is given. + +* ``cyclehotkeylabel:getOptionPen([option_idx])`` + + Retrieves the option pen at the given index, or the pen of the currently + selected option if no index is given. If an option was defined as just a + string, then this function will return ``nil`` for that option. + +ButtonGroup class +----------------- + +This is a specialized subclass of CycleHotkeyLabel that, in addition to the +regular clickable widget, displays a corresponding row of clickable graphical +buttons and synchronizes their selection state with the currently selected +option. + +It takes two additional required parameters to define the buttons: + +:button_specs: A list of specs to pass to ``makeButtonLabelText`` (defined in + `Label class`_ above). +:button_specs_selected: A list of specs that represent the buttons in their + selected state. + +ToggleHotkeyLabel class +----------------------- + +This is a specialized subclass of CycleHotkeyLabel that has two options: +``On`` (with a value of ``true``) and ``Off`` (with a value of ``false``). The +``On`` option is rendered in green. + +ConfigureButton class +--------------------- + +A 3x1 tile button with a gear symbol on it, intended to represent a configure +icon. Clicking on the icon will run the given callback. The graphics can also +be overridden to create custom buttons. + +It has the following attributes: + +:on_click: The function to run when the icon is clicked. +:pen_left: Pen or function returning a pen to overwrite the left tile of the button. +:pen_center: As above, but for the center tile (gear symbol). +:pen_right: As above, but for the right tile. + +HelpButton class +---------------- + +Subclass of ConfigureButton; a 3x1 tile button with a question mark on it, +intended to represent a help icon. Clicking on the icon will launch +`gui/launcher` with a given command string, showing the help text for that +command. + +It has the following attributes: + +:command: The command to load in `gui/launcher`. + +It also sets the ``frame`` attribute so the button appears in the upper right +corner of the parent, but you can override this to your liking if you want a +different position. + +RadioButton class +----------------- + +Subclass of ConfigureButton; a 3x1 tile button that resembles a radio button +(or check box in ASCII mode), identical to the ones found in +`gui/control-panel`. Clicking on the button will toggle its enabled state. + +It has the following attributes: + +:initial_state: Whether to start in the ``true`` or ``false`` state. Defaults to ``true``. +:on_change: Callback to call when state changes, including initialization. Called as ``on_change(val)``. + +It implements the following method: + +* ``RadioButton:setState(val)`` + + Sets the state to boolean ``val`` and calls ``on_change`` (if defined). + +BannerPanel class +----------------- + +This is a Panel subclass that prints a distinctive banner along the far left +and right columns of the widget frame. Note that this is not a "proper" frame +since it doesn't have top or bottom borders. Subviews of this panel should +inset their frames one tile from the left and right edges. + +TextButton class +---------------- + +This is a BannerPanel subclass that wraps a HotkeyLabel with some decorators on +the sides to make it look more like a button, suitable for both graphics and +ASCII modes. All HotkeyLabel parameters passed to the constructor are passed +through to the wrapped HotkeyLabel. + +List class +---------- + +The List widget implements a simple list with paging. You can click on a list +item to call the ``on_submit`` callback for that item. + +It has the following attributes: + +:text_pen: Specifies the pen for deselected list entries. +:text_hpen: Specifies the pen for entries that the mouse is hovered over. + Defaults to swapping the background/foreground colors. +:cursor_pen: Specifies the pen for the selected entry. +:inactive_pen: If specified, used for the cursor when the widget is not active. +:icon_pen: Default pen for icons. +:on_select: Selection change callback; called as ``on_select(index,choice)``. + This is also called with *nil* arguments if ``setChoices`` is called + with an empty list. +:on_submit: Enter key or mouse click callback; if specified, the list reacts to the + key/click and calls the callback as ``on_submit(index,choice)``. +:on_submit2: Shift-click callback; if specified, the list reacts to the click and + calls the callback as ``on_submit2(index,choice)``. +:on_double_click: Mouse double click callback; if specified, the list reacts to the + click and calls the callback as ``on_double_click(index,choice)``. +:on_double_click2: Shift-double click callback; if specified, the list reacts to the + click and calls the callback as ``on_double_click2(index,choice)``. +:row_height: Height of every row in text lines. +:icon_width: If not *nil*, the specified number of character columns + are reserved to the left of the list item for the icons. +:scroll_keys: Specifies which keys the list should react to as a table. + +Every list item may be specified either as a string, or as a lua table +with the following fields: + +:text: Specifies the label text in the same format as the Label text. +:text_*: Reserved for internal use. +:key: Specifies a keybinding that acts as a shortcut for the specified item. +:icon: Specifies an icon string, or a pen to paint a single character. May be a callback. +:icon_pen: When the icon is a string, used to paint it. + +The list supports the following methods: + +* ``List{ ..., choices = ..., selected = ... }`` + + Same as calling ``setChoices`` after construction. + +* ``list:setChoices(choices[, selected])`` + + Replaces the list of choices, possibly also setting the currently selected index. + +* ``list:setSelected(selected)`` + + Sets the currently selected index. Returns the index after validation. + +* ``list:getChoices()`` + + Returns the list of choices. + +* ``list:getSelected()`` + + Returns the selected *index, choice*, or nothing if the list is empty. + +* ``list:getIdxUnderMouse()`` + + Returns the index of the list item under the mouse cursor, or nothing if the + list is empty or the mouse is not over a list item. + +* ``list:getContentWidth()`` + + Returns the minimal width to draw all choices without clipping. + +* ``list:getContentHeight()`` + + Returns the minimal width to draw all choices without scrolling. + +* ``list:submit()`` + + Call the ``on_submit`` callback, as if the Enter key was handled. + +* ``list:submit2()`` + + Call the ``on_submit2`` callback, as if the Shift-Enter key was handled. + +FilteredList class +------------------ + +This widget combines List, EditField and Label into a combo-box like +construction that allows filtering the list. + +In addition to passing through all attributes supported by List, it +supports: + +:edit_pen: If specified, used instead of ``cursor_pen`` for the edit field. +:edit_below: If true, the edit field is placed below the list instead of above. +:edit_key: If specified, the edit field is disabled until this key is pressed. +:edit_ignore_keys: If specified, will be passed to the filter edit field as its ``ignore_keys`` attribute. +:edit_on_change: If specified, will be passed to the filter edit field as its ``on_change`` attribute. +:edit_on_char: If specified, will be passed to the filter edit field as its ``on_char`` attribute. +:not_found_label: Specifies the text of the label shown when no items match the filter. + +The list choices may include the following attributes: + +:search_key: If specified, used instead of **text** to match against the filter. + Can be a string or a function that returns a string. + +The widget implements: + +* ``list:setChoices(choices[, selected])`` + + Resets the filter, and passes through to the inner list. + +* ``list:getChoices()`` + + Returns the list of *all* choices. + +* ``list:getVisibleChoices()`` + + Returns the *filtered* list of choices. + +* ``list:getFilter()`` + + Returns the current filter string, and the *filtered* list of choices. + +* ``list:setFilter(filter[,pos])`` + + Sets the new filter string, filters the list, and selects the item at + index ``pos`` in the *unfiltered* list if possible. + +* ``list:canSubmit()`` + + Checks if there are currently any choices in the filtered list. + +* ``list:getSelected()``, ``list:getContentWidth()``, ``list:getContentHeight()``, ``list:submit()`` + + Same as with an ordinary list. + +Filter behavior: + +By default, the filter matches substrings that start at the beginning of a word +(or after any punctuation). You can instead configure filters to match any +substring across the full text by setting ``FILTER_FULL_TEXT`` in `gui/control-panel` +or set it for the session by running a command like:: + + :lua require('utils').FILTER_FULL_TEXT=true + +TabBar class +------------ + +This widget implements a set of one or more tabs to allow navigation between groups +of content. + +:wrap: If true, tabs automatically wrap on the width of the window and will + continue rendering on the next line(s) if all tabs cannot fit on a single line. + If false, tabs will be truncated and can be scrolled using ``scroll_key`` + and ``scroll_key_back``, mouse wheel or by clicking on the scroll labels + that will automatically appear on the left and right sides of the tab bar + as needed. When clicking on a tab or using ``key`` or ``key_back`` to switch tabs, + the selected tab will be scrolled into view if it is not already visible. + Defaults to true. +:key: Specifies a keybinding that can be used to switch to the next tab. + Defaults to ``CUSTOM_CTRL_T``. +:key_back: Specifies a keybinding that can be used to switch to the previous + tab. Defaults to ``CUSTOM_CTRL_Y``. +:labels: A table of strings; entry representing the label text for a single tab. + The order of the entries determines the order the tabs will appear in. +:on_select: Callback executed when a tab is selected. It receives the selected tab + index as an argument. The provided function should update the value of + whichever variable your script uses to keep track of the currently + selected tab. +:get_cur_page: The function used by the TabBar to determine which Tab is currently + selected. The function you provide should return an integer that + corresponds to the non-zero index of the currently selected Tab + (i.e., whatever variable you update in your ``on_select`` callback). +:active_tab_pens: A table of pens used to render active tabs. See the default + implementation in widgets.lua for an example of how to construct + the table. Leave unspecified to use the default pens. +:inactive_tab_pens: A table of pens used to render inactive tabs. See the default + implementation in widgets.lua for an example of how to + construct the table. Leave unspecified to use the default pens. +:get_pens: A function used to determine which pens should be used to render a tab. + Receives the index of the tab as the first argument and the TabBar widget + itself as the second. The default implementation, which will handle most + situations, returns ``self.active_tab_pens``, if ``self.get_cur_page() == idx``, + otherwise returns ``self.inactive_tab_pens``. +:scroll_key: Specifies a keybinding that can be used to scroll the tabs to the right. + Defaults to ``CUSTOM_ALT_T``. +:scroll_key_back: Specifies a keybinding that can be used to scroll the tabs to the left. + Defaults to ``CUSTOM_ALT_Y``. +:scroll_left_text: The text to display on the left scroll label. + Defaults to "<<<". +:scroll_right_text: The text to display on the right scroll label. + Defaults to ">>>". +:scroll_label_text_pen: The pen to use for the scroll label text. + Defaults to ``Label`` default. +:scroll_label_text_hpen: The pen to use for the scroll label text when hovered. + Defaults to ``scroll_label_text_pen`` with the background + and foreground colors swapped. +:scroll_step: The number of units to scroll tabs by. + Defaults to 10. +:fast_scroll_multiplier: The multiplier for fast scrolling (holding shift). + Defaults to 3. +:scroll_into_view_offset: After a selected tab is scrolled into view, this offset + is added to the scroll position to ensure the tab is + not flush against the edge of the tab bar, allowing + some space for the user to see the next tab. + Defaults to 5. + +Tab class +--------- + +This widget implements a single clickable tab and is the main component of the TabBar +widget. Usage of the ``TabBar`` widget does not require direct usage of ``Tab``. + +:id: The id of the tab. +:label: The text displayed on the tab. +:on_select: Callback executed when the tab is selected. +:get_pens: A function that is used during ``Tab:onRenderBody`` to determine the pens + that should be used for drawing. See the usage of ``Tab`` in + ``TabBar:init()`` for an example. See the default value of + ``active_tab_pens`` or ``inactive_tab_pens`` in ``TabBar`` + for an example of how to construct pens. + +RangeSlider class +----------------- + +This widget implements a mouse-interactable range-slider. The player can move its two +handles to set minimum and maximum values to define a range, or they can drag the bar +itself to move both handles at once. The parent widget owns the range values, and can +control them independently (e.g., with ``CycleHotkeyLabels``). If the range values +change, the ``RangeSlider`` appearance will adjust automatically. + +:num_stops: Used to specify the number of "notches" in the range slider, the places + where handles can stop. (This should match the parents' number of options.) +:get_left_idx_fn: The function used by the RangeSlider to get the notch index on which + to display the left handle. +:get_right_idx_fn: The function used by the RangeSlider to get the notch index on which + to display the right handle. +:on_left_change: Callback executed when moving the left handle. +:on_right_change: Callback executed when moving the right handle. + +Slider class +----------------- + +This widget implements a mouse-interactable slider. The player can move the handle to +set the value of the slider. The parent widget owns the slider value, and can control +it independently (e.g., with a ``CycleHotkeyLabel``). If the value changes, the ``Slider`` +appearance will adjust automatically. + +:num_stops: Used to specify the number of "notches" in the slider, the places + where the handle can stop. (This should match the parents' number of options.) +:get_idx_fn: The function used by the Slider to get the notch index on which + to display the handle. +:on_change: Callback executed when moving the handle. + +DimensionsTooltip class +----------------------- + +This widget follows the mouse cursor around and displays a string that +indicates selected 3d dimensions. It is intended to be a child widget of a +full-screen ``View``, such as a ``ZScreen``. + +:display_offset: the offset from the mouse cursor where the tooltip is + displayed. Positive offsets are down and to the right. Defaults to + ``{x=3, y=3}``. +:get_anchor_pos_fn: function that provides the other corner of the selected + area as a ``df.coord``-style table, that is, a table with ``x``, ``y``, and + ``z`` fields. Must return ``nil`` if there is no current selection. + +gui.textures +============ + +This module contains convenience methods for accessing default DFHack graphic assets. +Pass the ``offset`` in tiles (in row major position) to get a particular tile from the +asset. ``offset`` 0 is the first tile. + +* ``tp_green_pin(offset)`` tileset: ``hack/data/art/green-pin.png`` +* ``tp_red_pin(offset)`` tileset: ``hack/data/art/red-pin.png`` +* ``tp_icons(offset)`` tileset: ``hack/data/art/icons.png`` +* ``tp_on_off(offset)`` tileset: ``hack/data/art/on-off.png`` +* ``tp_control_panel(offset)`` tileset: ``hack/data/art/control-panel.png`` +* ``tp_border_thin(offset)`` tileset: ``hack/data/art/border-thin.png`` +* ``tp_border_medium(offset)`` tileset: ``hack/data/art/border-medium.png`` +* ``tp_border_bold(offset)`` tileset: ``hack/data/art/border-bold.png`` +* ``tp_border_panel(offset)`` tileset: ``hack/data/art/border-panel.png`` +* ``tp_border_window(offset)`` tileset: ``hack/data/art/order-window.png`` + +Example usage:: + + local textures = require('gui.textures') + local first_border_texpos = textures.tp_border_thin(1) + + +.. _lua-plugins: + +======= +Plugins +======= + +.. contents:: + :local: + +DFHack plugins may export native functions and events to Lua contexts. These are +exposed as ``plugins.`` modules, which can be imported with +``require('plugins.')``. The plugins listed in this section expose +functions and/or data to Lua in this way. + +In addition to any native functions documented here, plugins that can be +enabled (that is, plugins that support the `enable/disable API `) will +have the following functions defined: + +* ``isEnabled()`` returns whether the plugin is enabled. +* ``setEnabled(boolean)`` sets whether the plugin is enabled. + +For plugin developers, note that a Lua file in ``plugins/lua`` is required for +``require()`` to work, even if it contains no pure-Lua functions. This file must +contain ``mkmodule('plugins.')`` to import any native functions defined in +the plugin. See existing files in ``plugins/lua`` for examples. + +blueprint +========= + +Lua functions provided by the `blueprint` plugin to programmatically generate +blueprint files: + +* ``dig(start, end, name)`` +* ``build(start, end, name)`` +* ``place(start, end, name)`` +* ``query(start, end, name)`` + + ``start`` and ``end`` are tables containing positions (see ``xyz2pos``). + ``name`` is used as the basis for the generated filenames. + +The names of the functions are also available as the keys of the +``valid_phases`` table. + +.. _building-hacks-api: + +building-hacks +============== + +This plugin overwrites some methods in workshop df class so that mechanical workshops are +possible. Although plugin export a function it's recommended to use lua decorated function. + +.. contents:: + :local: + +Functions +--------- + +``registerBuilding(table)`` where table must contain name, as a workshop raw name, +the rest are optional: + + :name: + custom workshop id e.g., ``SOAPMAKER`` + + .. note:: this is the only mandatory field. + + :fix_impassible: + if true make impassable tiles impassable to liquids too + :consume: + how much machine power is needed to work. + Disables reactions if not supplied enough and ``needs_power==1`` + :produce: + how much machine power is produced. + :needs_power: + if produced in network < consumed stop working, default true + :gears: + a table or ``{x=?,y=?}`` of connection points for machines. + :action: + a table of number (how much ticks to skip) and a function which + gets called on shop update + :animate: + a table of frames which can be a table of: + + a. tables of 4 numbers ``{tile,fore,back,bright}`` OR + b. empty table (tile not modified) OR + c. ``{x= y= + 4 numbers like in first case}``, + this generates full frame useful for animations that change little (1-2 tiles) + + :canBeRoomSubset: + a flag if this building can be counted in room. 1 means it can, + 0 means it can't and -1 default building behaviour + :auto_gears: + a flag that automatically fills up gears and animations. + It looks over the building definition for gear icons and maps them. + + Animate table also might contain: + + :frameLength: + how many ticks does one frame take OR + :isMechanical: + a bool that says to try to match to mechanical system (i.e., how gears are turning) + +``getPower(building)`` returns two number - produced and consumed power if building can be +modified and returns nothing otherwise + +``setPower(building,produced,consumed)`` sets current power production and +consumption for a building. + +Examples +-------- + +Simple mechanical workshop:: + + require('plugins.building-hacks').registerBuilding{name="BONE_GRINDER", + consume=15, + gears={x=0,y=0}, --connection point + animate={ + isMechanical=true, --animate the same conn. point as vanilla gear + frames={ + {{x=0,y=0,42,7,0,0}}, --first frame, 1 changed tile + {{x=0,y=0,15,7,0,0}} -- second frame, same + } + } + +Or with auto_gears:: + + require('plugins.building-hacks').registerBuilding{name="BONE_GRINDER", + consume=15, + auto_gears=true + } + +buildingplan +============ + +Native functions provided by the `buildingplan` plugin: + +* ``bool isPlannableBuilding(df::building_type type, int16_t subtype, int32_t custom)`` + + Returns whether the building type is handled by buildingplan. + +* ``bool isPlanModeEnabled(df::building_type type, int16_t subtype, int32_t custom)`` + + Returns whether the buildingplan UI is enabled for the specified building type. + +* ``bool isPlannedBuilding(df::building *bld)`` + + Returns whether the given building is managed by buildingplan. + +* ``void addPlannedBuilding(df::building *bld)`` + + Suspends the building jobs and adds the building to the monitor list. + +* ``void doCycle()`` + + Runs a check for whether buildings in the monitor list can be assigned + items and unsuspended. This method runs automatically twice a game day, + so you only need to call it directly if you want buildingplan to do a + check right now. + +* ``void scheduleCycle()`` + + Schedules a cycle to be run during the next non-paused game frame. + Can be called multiple times while the game is paused and only one + cycle will be scheduled. + +.. _cxxrandom-api: + +cxxrandom +========= + +Exposes some features of the C++11 random number library to Lua. + +.. contents:: + :local: + +Native functions (exported to Lua) +---------------------------------- + +- ``GenerateEngine(seed)`` + + returns engine id + +- ``DestroyEngine(rngID)`` + + destroys corresponding engine + +- ``NewSeed(rngID, seed)`` + + re-seeds engine + +- ``rollInt(rngID, min, max)`` + + generates random integer + +- ``rollDouble(rngID, min, max)`` + + generates random double + +- ``rollNormal(rngID, avg, stddev)`` + + generates random double drawn from a normal (Gaussian) distribution + +- ``rollBool(rngID, chance)`` + + generates random boolean + +- ``MakeNumSequence(start, end)`` + + returns sequence id + +- ``AddToSequence(seqID, num)`` + + adds a number to the sequence + +- ``ShuffleSequence(seqID, rngID)`` + + shuffles the number sequence + +- ``NextInSequence(seqID)`` + + returns the next number in sequence + + +Lua plugin functions +-------------------- + +- ``MakeNewEngine(seed)`` + + returns engine id + +Lua plugin classes +------------------ + +crng +~~~~ + +- ``init(id, df, dist)``: constructor + + - ``id``: Reference ID of engine to use in RNGenerations. + - ``df`` (optional): bool indicating whether to destroy the Engine + when the crng object is garbage collected. + - ``dist`` (optional): lua number distribution to use. + +- ``changeSeed(seed)``: alters engine's seed value +- ``setNumDistrib(distrib)``: sets the number distribution crng object should use. + + - ``distrib``: number distribution object to use in RNGenerations. + +- ``next()``: returns the next number in the distribution. +- ``shuffle()``: effectively shuffles the number distribution. + +normal_distribution +~~~~~~~~~~~~~~~~~~~ + +- ``init(avg, stddev)``: constructor +- ``next(id)``: returns next number in the distribution + + - ``id``: engine ID to pass to native function + +real_distribution +~~~~~~~~~~~~~~~~~ + +- ``init(min, max)``: constructor +- ``next(id)``: returns next number in the distribution + + - ``id``: engine ID to pass to native function + +int_distribution +~~~~~~~~~~~~~~~~ + +- ``init(min, max)``: constructor +- ``next(id)``: returns next number in the distribution + + - ``id``: engine ID to pass to native function + +bool_distribution +~~~~~~~~~~~~~~~~~ + +- ``init(chance)``: constructor +- ``next(id)``: returns next boolean in the distribution + + - ``id``: engine ID to pass to native function + +num_sequence +~~~~~~~~~~~~ + +- ``init(a, b)``: constructor +- ``add(num)``: adds num to the end of the number sequence +- ``shuffle()``: shuffles the sequence of numbers +- ``next()``: returns next number in the sequence + +Usage +----- + +The randomization state is kept in an "engine". The distribution class turns +that engine state into random numbers. + +Example:: + + local rng = require('plugins.cxxrandom') + local norm_dist = rng.normal_distribution(6820, 116) -- avg, stddev + local engID = rng.MakeNewEngine(0) + print(norm_dist:next(engID)) + + -- alternate syntax + local cleanup = true -- delete engine on cleanup + local number_generator = rng.crng:new(engID, cleanup, norm_dist) + print(number_generator:next()) + + -- simplified + print(rng.rollNormal(engID, 6820, 116)) + +The number sequences are much simpler. They're intended for where you need to +randomly generate an index, perhaps in a loop for an array. You technically +don't need an engine to use it, if you don't mind never shuffling. + +Example:: + + local rng = require('plugins.cxxrandom') + local engID = rng.MakeNewEngine(0) + local g = rng.crng:new(engId, true, rng.num_sequence:new(0, table_size)) + g:shuffle() + for _ = 1, table_size do + func(array[g:next()]) + end + + +dig-now +======= + +The dig-now plugin exposes the following functions to Lua: + +* ``dig_now_tile(pos)`` or ``dig_now_tile(x,y,z)``: Runs dig-now for the + specified tile coordinate. Default options apply, as if you were running the + command ``dig-now ``. See the `dig-now` documentation for details + on default settings. + +.. _eventful-api: + +eventful +======== + +This plugin exports some events to lua thus allowing to run lua functions +on DF world events. + +.. contents:: + :local: + +List of events +-------------- + +1. ``onReactionCompleting(reaction,reaction_product,unit,input_items,input_reagents,output_items,call_native)`` + + Is called once per reaction product, before the reaction has a chance to + call native code for item creation. Setting ``call_native.value=false`` + cancels further processing: no items are created and ``onReactionComplete`` + is not called. + +2. ``onReactionComplete(reaction,reaction_product,unit,input_items,input_reagents,output_items)`` + + Is called once per reaction product, when reaction finishes and has + at least one product. + +3. ``onItemContaminateWound(item,unit,wound,number1,number2)`` + + Is called when item tries to contaminate wound (e.g., stuck in). + +4. ``onProjItemCheckMovement(projectile)`` + + Is called when projectile moves. + +5. ``onProjItemCheckImpact(projectile,somebool)`` + + Is called when projectile hits something. + +6. ``onProjUnitCheckMovement(projectile)`` + + Is called when projectile moves. + +7. ``onProjUnitCheckImpact(projectile,somebool)`` + + Is called when projectile hits something. + +8. ``onWorkshopFillSidebarMenu(workshop,callnative)`` + + Is called when viewing a workshop in 'q' mode, to populate + reactions, useful for custom viewscreens for shops. + +9. ``postWorkshopFillSidebarMenu(workshop)`` + + Is called after calling (or not) native fillSidebarMenu(). + Useful for job button tweaking (e.g., adding custom reactions) + +.. _EventManager: + +Events from EventManager +------------------------ +These events are straight from EventManager module. Each of them first needs +to be enabled. See functions for more info. If you register a listener before +the game is loaded, be aware that no events will be triggered immediately +after loading, so you might need to add another event listener for when the +game first loads in some cases. + +1. ``onBuildingCreatedDestroyed(building_id)`` + + Gets called when building is created or destroyed. + +2. ``onConstructionCreatedDestroyed(building_id)`` + + Gets called when construction is created or destroyed. + +3. ``onJobInitiated(job)`` + + Gets called when job is issued. + +4. ``onJobCompleted(job)`` + + Gets called when job is finished. The job that is passed to this function + is a copy. Requires a frequency of 0 in order to distinguish between + workshop jobs that were canceled by the user and workshop jobs that + completed successfully. + +5. ``onUnitDeath(unit_id)`` + + Gets called on unit death. + +6. ``onItemCreated(item_id)`` + + Gets called when item is created (except due to traders, migrants, + invaders, and spider webs). + +7. ``onSyndrome(unit_id,syndrome_index)`` + + Gets called when new syndrome appears on a unit. + +8. ``onInvasion(invasion_id)`` + + Gets called when new invasion happens. + +9. ``onInventoryChange(unit_id,item_id,old_equip,new_equip)`` + + Gets called when someone picks up an item, puts one down, + or changes the way they are holding it. If an item is picked up, + old_equip will be null. If an item is dropped, new_equip will be null. + If an item is re-equipped in a new way, then neither will be null. + You absolutely must NOT alter either old_equip or new_equip or you + might break other plugins. + +10. ``onReport(reportId)`` + + Gets called when a report happens. This happens more often than + you probably think, even if it doesn't show up in the announcements. + +11. ``onUnitAttack(attackerId, defenderId, woundId)`` + + Called when a unit wounds another with a weapon. + Is NOT called if blocked, dodged, deflected, or parried. + +12. ``onUnload()`` + + A convenience event in case you don't want to register for every onStateChange event. + +13. ``onInteraction(attackVerb, defendVerb, attackerId, defenderId, attackReportId, defendReportId)`` + + Called when a unit uses an interaction on another. + +Functions +--------- + +1. ``registerReaction(reaction_name,callback)`` + + Simplified way of using onReactionCompleting; the callback is function (same params as event). + +2. ``removeNative(shop_name)`` + + Removes native choice list from the building. + +3. ``addReactionToShop(reaction_name,shop_name)`` + + Add a custom reaction to the building. + +4. ``enableEvent(evType,frequency)`` + + Enable event checking for EventManager events. For event types use ``eventType`` table. + Note that different types of events require different frequencies to be effective. The + frequency is how many ticks EventManager will wait before checking if that type of event + has happened. If multiple scripts or plugins use the same event type, the smallest frequency + is the one that is used, so you might get events triggered more often than the frequency + you use here. + +5. ``registerSidebar(shop_name,callback)`` + + Enable callback when sidebar for ``shop_name`` is drawn. Useful for custom workshop views, + e.g., using gui.dwarfmode lib. Also accepts a ``class`` instead of function as callback. + Best used with ``gui.dwarfmode`` class ``WorkshopOverlay``. + +Examples +-------- +Spawn dragon breath on each item attempt to contaminate wound:: + + b=require "plugins.eventful" + b.onItemContaminateWound.one=function(item,unit,un_wound,x,y) + local flw=dfhack.maps.spawnFlow(unit.pos,6,0,0,50000) + end + +Reaction complete example:: + + b=require "plugins.eventful" + + b.registerReaction("LAY_BOMB",function(reaction,unit,in_items,in_reag,out_items,call_native) + local pos=copyall(unit.pos) + -- spawn dragonbreath after 100 ticks + dfhack.timeout(100,"ticks",function() dfhack.maps.spawnFlow(pos,6,0,0,50000) end) + --do not call real item creation code + call_native.value=false + end) + +Grenade example:: + + b=require "plugins.eventful" + b.onProjItemCheckImpact.one=function(projectile) + -- you can check if projectile.item e.g., has correct material + dfhack.maps.spawnFlow(projectile.cur_pos,6,0,0,50000) + end + +Integrated tannery:: + + b=require "plugins.eventful" + b.addReactionToShop("TAN_A_HIDE","LEATHERWORKS") + +.. _luasocket-api: + +luasocket +========= + +A way to access csocket from lua. The usage is made similar to luasocket in +vanilla lua distributions. Currently only a subset of the functions exist +and only TCP mode is implemented. + +.. contents:: + :local: + +Socket class +------------ + +This is a base class for ``client`` and ``server`` sockets. You can not create +it - it's like a virtual base class in c++. + +* ``socket:close()`` + + Closes the connection. + +* ``socket:setTimeout(sec,msec)`` + + Sets the operation timeout for this socket. It's possible to set timeout to 0. + Then it performs like a non-blocking socket. + +Client class +------------ + +Client is a connection socket to a server. You can get this object either from +``tcp:connect(address,port)`` or from ``server:accept()``. +It's a subclass of ``socket``. + +* ``client:receive(pattern)`` + + Receives data. Pattern is one of: + + :``*l``: read one line (default, if pattern is *nil*) + :: read specified number of bytes + :``*a``: read all available data + +* ``client:send(data)`` + + Sends data. Data is a string. + + +Server class +------------ + +Server is a socket that is waiting for clients. +You can get this object from ``tcp:bind(address,port)``. + +* ``server:accept()`` + + Accepts an incoming connection if it exists. + Returns a ``client`` object representing that socket. + +Tcp class +--------- + +A class with all the tcp functionality. + +* ``tcp:bind(address,port)`` + + Starts listening on that port for incoming connections. + Returns ``server`` object. + +* ``tcp:connect(address,port)`` + + Tries connecting to that address and port. Returns ``client`` object. + + +.. _map-render-api: + +map-render +========== + +A way to ask DF to render a section of the fortress mode map. +This uses a native DF rendering function so it's highly dependent +on DF settings (e.g., tileset, colors, etc.) + +Functions +--------- + +- ``render_map_rect(x,y,z,w,h)`` + + Returns a table with w*h*4 entries of rendered tiles. The format is + the same as ``df.global.gps.screen`` (tile,foreground,bright,background). + +.. _pathable-api: + +pathable +======== + +This plugin implements the back end of the `gui/pathable` script. It exports a +single Lua function, in ``hack/lua/plugins/pathable.lua``: + +* ``paintScreen(cursor[,skip_unrevealed])``: Paint each visible of the screen + green or red, depending on whether it can be pathed to from the tile at + ``cursor``. If ``skip_unrevealed`` is specified and true, do not draw + unrevealed tiles. + +reveal +====== + +Native functions provided by the `reveal` plugin: + +* ``void unhideFlood(pos)``: Unhides map tiles according to visibility rules, + starting from the given coordinates. This algorithm only processes adjacent + hidden tiles, so it must start on a hidden tile in order to have any effect. + It will not reveal hidden sections separated by already-unhidden tiles. + +Example of revealing a cavern that happens to have an open tile at the specified +coordinate:: + + unhideFlood({x=25, y=38, z=140}) + +sort +==== + +The `sort ` plugin does not export any native functions as of now. +Instead, it calls Lua code to perform the actual ordering of list items. + +tiletypes +========= + +* ``bool tiletypes_setTile(pos, shape, material, special, variant)`` where + the parameters are enum values from ``df.tiletype_shape``, + ``df.tiletype_material``, etc. Returns whether the conversion succeeded. + +* ``bool tiletypes_setTile(pos, tiletype_options)`` where + the ``tiletype_options`` parameter takes in a table, with any fields matching + the available tiletypes options. Any unspecified fields default to keeping + the value of the original tile. Returns whether the conversion succeeded. + - ``shape``: ``df.tiletype_shape`` + - ``material``: ``df.tiletype_material`` + - ``special``: ``df.tiletype_special`` + - ``variant``: ``df.tiletype_variant`` + - ``hidden``: -1, 0, or 1 + - ``light``: -1, 0, or 1 + - ``subterranean``: -1, 0, or 1 + - ``skyview``: -1, 0, or 1 + - ``aquifer``: -1, 0, 1, or 2 + - ``autocorrect``: 0 or 1 + - ``stone_material``: integer material id + - ``vein_type``: ``df.inclusion_type`` + +.. _xlsxreader-api: + +xlsxreader +========== + +Utility functions to facilitate reading .xlsx spreadsheets. It provides the +following low-level API methods: + +- ``open_xlsx_file(filename)`` returns a file_handle or nil on error +- ``close_xlsx_file(file_handle)`` closes the specified file_handle +- ``list_sheets(file_handle)`` returns a list of strings representing sheet + names +- ``open_sheet(file_handle, sheet_name)`` returns a sheet_handle. This call + always succeeds, even if the sheet doesn't exist. Non-existent sheets will + have no data, though. +- ``close_sheet(sheet_handle)`` closes the specified sheet_handle +- ``get_row(sheet_handle, max_tokens)`` returns a list of strings representing + the contents of the cells in the next row. The ``max_tokens`` parameter is + optional. If set to a number > 0, it limits the number of cells read and + returned for the row. + +The plugin also provides Lua class wrappers for ease of use: + +- ``XlsxioReader`` provides access to .xlsx files +- ``XlsxioSheetReader`` provides access to sheets within .xlsx files +- ``open(filepath)`` initializes and returns an ``XlsxioReader`` object + +The ``XlsxioReader`` class has the following methods: + +- ``XlsxioReader:close()`` closes the file. Be sure to close any open child + sheet handles first! +- ``XlsxioReader:list_sheets()`` returns a list of strings representing sheet + names +- ``XlsxioReader:open_sheet(sheet_name)`` returns an initialized + ``XlsxioSheetReader`` object + +The ``XlsxioSheetReader`` class has the following methods: + +- ``XlsxioSheetReader:close()`` closes the sheet +- ``XlsxioSheetReader:get_row(max_tokens)`` reads the next row from the sheet. + If ``max_tokens`` is specified and is a positive integer, only the first + ``max_tokens`` elements of the row are returned. + +Here is an end-to-end example:: + + local xlsxreader = require('plugins.xlsxreader') + + local function dump_sheet(reader, sheet_name) + print('reading sheet: ' .. sheet_name) + local sheet_reader = reader:open_sheet(sheet_name) + dfhack.with_finalize( + function() sheet_reader:close() end, + function() + local row_cells = sheet_reader:get_row() + while row_cells do + printall(row_cells) + row_cells = sheet_reader:get_row() + end + end + ) + end + + local filepath = 'path/to/some_file.xlsx' + local reader = xlsxreader.open(filepath) + dfhack.with_finalize( + function() reader:close() end, + function() + for _,sheet_name in ipairs(reader:list_sheets()) do + dump_sheet(reader, sheet_name) + end + end + ) + +======= +Scripts +======= + +.. contents:: + :local: + +Any files with the ``.lua`` extension placed into the :file:`hack/scripts` folder +(or any other folder in your `script-paths`) are automatically made available as +DFHack commands. The command corresponding to a script is simply the script's +filename, relative to the scripts folder, with the extension omitted. For example: + +* :file:`dfhack-config/scripts/startup.lua` is invoked as ``startup`` +* :file:`hack/scripts/gui/teleport.lua` is invoked as ``gui/teleport`` + +.. note:: + In general, scripts should be placed in subfolders in the following + situations: + + * ``devel``: scripts that are intended exclusively for DFHack development, + including examples, or scripts that are experimental and unstable + * ``fix``: fixes for specific DF issues + * ``gui``: GUI front-ends for existing tools (for example, see the + relationship between `teleport` and `gui/teleport`) + * ``modtools``: scripts that are intended to be run exclusively as part of + mods, not directly by end-users (as a rule of thumb: if someone other than + a mod developer would want to run a script from the console, it should + not be placed in this folder) + +Scripts are read from disk when run for the first time, or if they have changed +since the last time they were run. + +Each script has an isolated environment where global variables set by the script +are stored. Values of globals persist across script runs in the same DF session. +See `devel/lua-example` for an example of this behavior. Note that ``local`` +variables do *not* persist. + +Arguments are passed in to the scripts via the ``...`` built-in quasi-variable; +when the script is called by the DFHack core, they are all guaranteed to be +non-nil strings. + +Additional data about how a script is invoked is passed to the script as a +special ``dfhack_flags`` global, which is unique to each script. This table +is guaranteed to exist, but individual entries may be present or absent +depending on how the script was invoked. Flags that are present are described +in the subsections below. + +DFHack invokes the scripts in the `core context `; however it +is possible to call them from any lua code (including from other scripts) in any +context with ``dfhack.run_script()`` below. + +General script API +================== + +* ``dfhack.run_script(name[,args...])`` + + Run a Lua script in your `script-paths`, as if it were started from the + DFHack command-line. The ``name`` argument should be the name of the script + without its extension, as it would be used on the command line. + + Example: + + In DFHack prompt:: + + repeat -time 14 -timeUnits days -command [ workorder ShearCreature ] -name autoShearCreature + + In Lua script:: + + dfhack.run_script("repeat", "-time", "14", "-timeUnits", "days", "-command", "[", "workorder", "ShearCreature", "]", "-name", "autoShearCreature") + + Note that the ``dfhack.run_script()`` function allows Lua errors to propagate to the caller. + + To run other types of commands (i.e., built-in commands or commands provided by plugins), + see ``dfhack.run_command()``. Note that this is slightly slower than ``dfhack.run_script()`` + when running Lua scripts. + +* ``dfhack.script_help([name, [extension]])`` + + Returns the contents of the rendered (or embedded) `documentation` for the + specified script. ``extension`` defaults to "lua", and ``name`` defaults to + the name of the script where this function was called. For example, the + following can be used to print the current script's help text:: + + local args = {...} + if args[1] == 'help' then + print(script_help()) + return + end + +.. _reqscript: + +Importing scripts +================= + +* ``dfhack.reqscript(name)`` or ``reqscript(name)`` + + Loads a Lua script and returns its environment (i.e., a table of all global + functions and variables). This is similar to the built-in ``require()``, but + searches all `script-paths` for the first matching ``name.lua`` file instead + of searching the Lua library paths (like ``hack/lua/``). + + Most scripts can be made to support ``reqscript()`` without significant + changes (in contrast, ``require()`` requires the use of ``mkmodule()`` and + some additional boilerplate). However, because scripts can have side effects + when they are loaded (such as printing messages or modifying the game state), + scripts that intend to support being imported must satisfy some criteria to + ensure that they can be imported safely: + + 1. Include the following line - ``reqscript()`` will fail if this line is + not present:: + + --@ module = true + + In order to be recognized, this line **must** begin with ``--@`` with no + whitespace characters before it:: + + --@ module = true OK + --@module = true OK + -- @module = true NOT OK (no --@ found due to space after --) + --@module = true NOT OK (leading space, --@ is not at the beginning of the line) + ---@module = true NOT OK (leading dash, --@ is not at the beginning of the line) + + 2. Include a check for ``dfhack_flags.module``, and avoid running any code + that has side-effects if this flag is true. For instance:: + + -- (function definitions) + if dfhack_flags.module then + return + end + -- (main script code with side-effects) + + or:: + + -- (function definitions) + function main() + -- (main script code with side-effects) + end + if not dfhack_flags.module then + main() + end + + Example usage:: + + local addThought = reqscript('add-thought') + addThought.addEmotionToUnit(unit, ...) + + Circular dependencies between scripts are supported, as long as the scripts + have no side-effects at load time (which should already be the case per + the above criteria). + + .. warning:: + + Avoid caching the table returned by ``reqscript()`` beyond storing it in + a local variable as in the example above. ``reqscript()`` is fast for + scripts that have previously been loaded and haven't changed. If you retain + a reference to a table returned by an old ``reqscript()`` call, this may + lead to unintended behavior if the location of the script changes (e.g., if a + save is loaded or unloaded, or if a `script path ` is added in + some other way). + + .. admonition:: Tip + + Mods that include custom Lua modules can write these modules to support + ``reqscript()`` and distribute them as scripts in ``raw/scripts``. Since the + entire ``raw`` folder is copied into new saves, this will allow saves to be + successfully transferred to other users who do not have the mod installed + (as long as they have DFHack installed). + + .. admonition:: Backwards compatibility notes + + For backwards compatibility, ``moduleMode`` is also defined if + ``dfhack_flags.module`` is defined, and is set to the same value. + Support for this may be removed in a future version. + +* ``dfhack.script_environment(name)`` + + Similar to ``reqscript()`` but does not enforce the check for module support. + This can be used to import scripts that support being used as a module but do + not declare support as described above, although it is preferred to update + such scripts so that ``reqscript()`` can be used instead. + +.. _script-enable-api: + +Enabling and disabling scripts +============================== + +Scripts can choose to recognize the built-in ``enable`` and ``disable`` commands +by including the following line near the top of their file:: + + --@enable = true + --@module = true + +Note that enableable scripts must also be `modules ` so their +``isEnabled()`` functions can be called from outside the script. + +When the ``enable`` and ``disable`` commands are invoked, the ``dfhack_flags`` +table passed to the script will have the following fields set: + +* ``enable``: Always ``true`` if the script is being enabled *or* disabled +* ``enable_state``: ``true`` if the script is being enabled, ``false`` otherwise + +If you declare a global function named ``isEnabled`` that returns a boolean +indicating whether your script is enabled, then your script will be listed among +the other enableable scripts and plugins when the player runs the `enable` +command. + +Example usage:: + + --@enable = true + --@module = true + + enabled = enabled or false + function isEnabled() + return enabled + end + + -- (function definitions...) + + if dfhack_flags.enable then + if dfhack_flags.enable_state then + start() + enabled = true + else + stop() + enabled = false + end + end + +If the state of your script can be tied to an active savegame, then your script +should hook the appropriate events to load persisted state when a savegame is +loaded. For example:: + + local utils = require('utils') + + local GLOBAL_KEY = 'my-script-name' + + local function get_default_state() + return { + -- add default config here, e.g., + -- enabled=false, + } + end + + state = state or get_default_state() + + dfhack.onStateChange[GLOBAL_KEY] = function(sc) + if sc ~= SC_MAP_LOADED or df.global.gamemode ~= df.game_mode.DWARF then + return + end + -- retrieve state saved in game. merge with default state so config + -- saved from previous versions can pick up newer defaults. + state = get_default_state() + utils.assign(state, dfhack.persistent.getSiteData(GLOBAL_KEY, state)) + end + + -- to be called when global state changes that needs to be persisted + local function persist_state() + dfhack.persistent.saveSiteData(GLOBAL_KEY, state) + end + +The attachment to ``dfhack.onStateChange`` should appear in your script code +outside of any function. DFHack will load your script as a module just before +the ``SC_DFHACK_INITIALIZED`` state change event is sent, giving your code an +opportunity to run and attach hooks before the game is loaded. + +If an enableable script is added to a DFHack `script path ` while +DF is running, then it will miss the initial sweep that loads all the module +scripts and any ``onStateChange`` handlers the script may want to register will +not be registered until the script is loaded via some means, either by running +it or loading it as a module. If you just added new scripts that you want to +load so they can attach their ``onStateChange`` handlers, run ``enable`` without +parameters or call ``:lua require('script-manager').reload()`` to scan and load +all script modules. + +Save init script +================ + +If a save directory contains a file called ``init.lua``, it is +automatically loaded and executed every time the save is loaded. +The same applies to any files called ``init.d/*.lua``. Every +such script can define the following functions to be called by dfhack: + +* ``function onStateChange(op) ... end`` + + Automatically called from the regular onStateChange event as long + as the save is still loaded. This avoids the need to install a hook + into the global ``dfhack.onStateChange`` table, with associated + cleanup concerns. + +* ``function onUnload() ... end`` + + Called when the save containing the script is unloaded. This function + should clean up any global hooks installed by the script. Note that + when this is called, the world is already completely unloaded. + +Within the init script, the path to the save directory is available as ``SAVE_PATH``. diff --git a/docs/dev/Memory-research.rst b/docs/dev/Memory-research.rst new file mode 100644 index 0000000000..2ee47bb05b --- /dev/null +++ b/docs/dev/Memory-research.rst @@ -0,0 +1,162 @@ +.. _memory-research: + +############### +Memory research +############### + +There are a variety of tools that can be used to analyze DF memory - some are +listed here. Note that some of these may be old and unmaintained. If you aren't +sure what tool would be best for your purposes, feel free to ask for advice (on +IRC, Bay12, etc.). + +.. contents:: Contents + :local: + + +Cross-platform tools +==================== + +Ghidra +------ + +Ghidra is a cross-platform reverse-engineering framework (written in Java) +available at https://ghidra-sre.org. It supports analyzing both 32-bit and +64-bit executables for all supported DF platforms. There are some custom DFHack +Ghidra scripts available in the `df_misc`_ repo (look for ``.java`` files). + + +IDA Freeware 7.0 +---------------- + +Available from `Hex-Rays `_. +Supports analyzing both 32-bit and 64-bit executables for all supported DF platforms. +Some ``.idc`` scripts for IDA are available in the `df_misc`_ repo. + +.. _df_misc: https://github.com/DFHack/df_misc + + +Hopper +------ + +Runs on macOS and some Linux distributions; available from https://www.hopperapp.com/. +`TWBT `_ uses this to produce some patches. + + +DFHack tools +------------ + +Plugins +~~~~~~~ + +There are a few development plugins useful for low-level memory research. They +are not built by default, but can be built by setting the ``BUILD_DEVEL`` +`CMake option `. These include: + +- ``check-structures-sanity``, which performs sanity checks on the given DF + object. Note that this will crash in several cases, some intentional, so using + this with `GDB ` is recommended. +- ``memview``, which produces a hex dump of a given memory range. It also + highlights valid pointers, and can be configured to work with `sizecheck` + to auto-detect object sizes. +- ``vectors``, which can identify instances of ``std::vector`` in a given memory range. + +Scripts +~~~~~~~ + +Several `development tools ` can be useful for memory research. +These include (but are not limited to): + +- `devel/dump-offsets` +- `devel/find-offsets` +- `devel/lsmem` +- `devel/sc` (requires `sizecheck`) +- `devel/visualize-structure` +- Generally, any script starting with ``devel/find`` + +.. _sizecheck: + +Sizecheck +~~~~~~~~~ + +Sizecheck is a custom tool that hooks into the memory allocator and inserts a +header indicating the size of every object. The corresponding logic to check for +this header when freeing memory usually works, but is inherently not foolproof. +You should not count on DF being stable when using this. + +DFHack's implementation of sizecheck is currently only tested on Linux, although +it probably also works on macOS. It can be built with the ``BUILD_SIZECHECK`` +`CMake option `, which produces a ``libsizecheck`` +library installed in the ``hack`` folder. On Linux, passing ``--sc`` as the +first argument to the ``dfhack`` launcher script will load this library on +startup. On other platforms, or when passing a different argument to the +launcher (such as for `linux-gdb`), you will need to preload this library +manually, by setting ``PRELOAD_LIB`` on Linux (or ``LD_PRELOAD`` if editing the +``dfhack`` launcher script directly), or by editing the ``dfhack`` launcher +script and adding the library to ``DYLD_INSERT_LIBRARIES`` on macOS. + +There is also an older sizecheck implementation by Mifki available on +`GitHub `__ (``b.cpp`` is the main +sizecheck library, and ``win_patch.cpp`` is used for Windows support). To use +this with other DFHack tools, you will likely need to edit the header's +magic number to match what is used in `devel/sc` (search for a hexadecimal +constant starting with ``0x``). + +Legacy tools +~~~~~~~~~~~~ + +Some very old DFHack tools are available in the `legacy branch on GitHub `_. +No attempt is made to support these. + + +Linux-specific tools +==================== + +.. _linux-gdb: + +GDB +--- + +`GDB `_ is technically cross-platform, but +tends to work best on Linux, and DFHack currently only offers support for using +GDB on 64-bit Linux. To start with GDB, pass ``-g`` to the DFHack launcher +script: + +.. code-block:: shell + + ./dfhack -g + +Some basic GDB commands: + +- ``run``: starts DF from the GDB prompt. Any arguments will be passed as + command-line arguments to DF (e.g. `load-save` may be useful). +- ``bt`` will produce a backtrace if DF crashes. + +See the `official GDB documentation `_ +for more details. + +Other analysis tools +-------------------- + +The ``dfhack`` launcher script on Linux has support for launching several other +tools alongside DFHack, including Valgrind (as well as Callgrind and Helgrind) +and strace. See the script for the exact command-line option to specify. Note +that currently only one tool at a time is supported, and must be specified +with the first argument to the script. + +df-structures GUI +----------------- + +This is a tool written by Angavrilov and available on `GitHub `__. +It only supports 32-bit DF. Some assistance may be available on IRC. + + +EDB (Evan's debugger) +--------------------- + +Available on `GitHub `__. + + +Windows-specific tools +====================== + +Some people have used `Cheat Engine `__ for research in the past. diff --git a/docs/dev/Remote.rst b/docs/dev/Remote.rst new file mode 100644 index 0000000000..c98d6ae520 --- /dev/null +++ b/docs/dev/Remote.rst @@ -0,0 +1,236 @@ +.. _remote: + +======================= +DFHack remote interface +======================= + +DFHack provides a remote access interface that external tools can connect to and +use to interact with DF. This is implemented with `Google protobuf`_ messages +exchanged over a TCP socket. Both the core and plugins can define +remotely-accessible methods, or **RPC methods**. The RPC methods currently +available are not comprehensive, but can be extended with plugins. + +.. _Google protobuf: https://developers.google.com/protocol-buffers + +.. contents:: Contents + :local: + + +.. _remote-server-config: + +Server configuration +==================== + +DFHack attempts to start a TCP server to listen for remote connections on +startup. If this fails (due to the port being in use, for example), an error +message will be logged to stderr.log. + +The server can be configured by setting options in ``dfhack-config/remote-server.json``: + +- ``allow_remote`` (default: ``false``): if true, allows connections from hosts + other than the local machine. This is insecure and may allow arbitrary code + execution on your machine, so it is disabled by default. +- ``port`` (default: ``5000``): the port that the remote server listens on. + Overriding this will allow the server to work if you have multiple instances + of DF running, or if you have something else running on port 5000. Note that + the ``DFHACK_PORT`` `environment variable ` takes precedence over + this setting and may be more useful for overriding the port temporarily. + + +Developing with the remote API +============================== + +At a high level, the core and plugins define RPC methods, and external clients +can call these methods. Each method is assigned an ID internally, which clients +use to call it. These method IDs can be obtained using the special ``BindMethod`` +method, which has an ID of 0. + +Examples +-------- + +The `dfhack-run` command uses the RPC interface to invoke DFHack commands +(or Lua functions) externally. + +Plugins that implement RPC methods include: + +- `rename` +- `remotefortressreader` + +Plugins that use the RPC API include: + +- `stonesense` + +Third-party tools that use the RPC API include: + +- `Armok Vision `_ (:forums:`Bay12 forums thread <146473>`) + +.. _remote-client-libs: + +Client libraries +---------------- + +Some external libraries are available for interacting with the remote interface +from other (non-C++) languages, including: + +- `RemoteClientDF-Net `_ for C# +- `dfhackrpc `_ for Go +- `dfhack-remote `__ for JavaScript +- `dfhack-client-qt `_ for C++ with Qt +- `dfhack-client-python `_ for Python (adapted from :forums:`"Blendwarf" <178089>`) +- `dfhack-client-java `_ for Java +- `dfhack-remote `__ for Rust + + +Protocol description +==================== + +This is a low-level description of the RPC protocol, which may be useful when +developing custom clients. + +A WireShark dissector for this protocol is available in the +`df_misc repo `_. + + +Built-in messages +----------------- +These messages have hardcoded IDs; all others must be obtained through ``BindMethod``. + +=== ============ =============================== ======================= +ID Method Input Output +=== ============ =============================== ======================= + 0 BindMethod dfproto.CoreBindRequest dfproto.CoreBindReply + 1 RunCommand dfproto.CoreRunCommandRequest dfproto.EmptyMessage +=== ============ =============================== ======================= + +Conversation flow +----------------- + +* Client → Server: `handshake request`_ +* Server → Client: `handshake reply`_ +* Repeated 0 or more times: + * Client → Server: `request`_ + * Server → Client: `text`_ (0 or more times) + * Server → Client: `result`_ or `failure`_ +* Client → Server: `quit`_ + +Raw message types +----------------- + +* All numbers are little-endian +* All strings are ASCII +* A payload size of greater than 64MiB is an error +* See ``RemoteClient.h`` for definitions of constants starting with ``RPC`` + +handshake request +~~~~~~~~~~~~~~~~~ + +.. csv-table:: + :align: left + :header-rows: 1 + + Type, Name, Value + char[8], magic, ``DFHack?\n`` + int32_t, version, 1 + +handshake reply +~~~~~~~~~~~~~~~ + +.. csv-table:: + :align: left + :header-rows: 1 + + Type, Name, Value + char[8], magic, ``DFHack!\n`` + int32_t, version, 1 + +header +~~~~~~ + +**Note:** the two fields of this message are sometimes repurposed. Uses of this +message are represented as ``header(x, y)``, where ``x`` corresponds to the ``id`` +field and ``y`` corresponds to ``size``. + +.. csv-table:: + :align: left + :header-rows: 1 + + Type, Name + int16_t, id + int16_t, (padding - unused) + int32_t, size + +request +~~~~~~~ + +.. list-table:: + :align: left + :header-rows: 1 + :widths: 25 75 + + * - Type + - Description + * - `header`_ + - ``header(id, size)`` + * - buffer + - Protobuf-encoded payload of the input message type of the method specified by ``id``; length of ``size`` bytes + +text +~~~~ + +.. list-table:: + :align: left + :header-rows: 1 + :widths: 25 75 + + * - Type + - Description + * - `header`_ + - ``header(RPC_REPLY_TEXT, size)`` + * - buffer + - Protobuf-encoded payload of type ``dfproto.CoreTextNotification``; length of ``size`` bytes + +result +~~~~~~ + +.. list-table:: + :align: left + :header-rows: 1 + :widths: 25 75 + + * - Type + - Description + * - `header`_ + - ``header(RPC_REPLY_RESULT, size)`` + * - buffer + - Protobuf-encoded payload of the output message type of the oldest incomplete method call; when received, + that method call is considered completed. Length of ``size`` bytes. + +failure +~~~~~~~ + +.. list-table:: + :align: left + :header-rows: 1 + :widths: 25 75 + + * - Type + - Description + * - `header`_ + - ``header(RPC_REPLY_FAIL, command_result)`` + * - command_result + - return code of the command (a constant starting with ``CR_``; see ``RemoteClient.h``) + +quit +~~~~ + +**Note:** the server closes the connection after receiving this message. + +.. list-table:: + :align: left + :header-rows: 1 + :widths: 25 75 + + * - Type + - Description + * - `header`_ + - ``header(RPC_REQUEST_QUIT, 0)`` diff --git a/docs/dev/Structures-intro.rst b/docs/dev/Structures-intro.rst new file mode 100644 index 0000000000..8fe8d6e99b --- /dev/null +++ b/docs/dev/Structures-intro.rst @@ -0,0 +1,32 @@ +=================================== +DF data definitions (DF-structures) +=================================== + +DFHack's information about DF's data structures is stored in XML files in the +`df-structures repository `_. If you +have `obtained a local copy of the DFHack source `, +DF-structures is included as a submodule in ``library/xml``. + +Data structure layouts are described in files named with the ``df.*.xml`` +pattern. This information is transformed by a Perl script (``codegen.pl``) into +C++ headers, as well as metadata for the Lua wrapper. This ultimately allows +DFHack code to access DF data directly, with the same speed and capabilities as +DF itself, which is an advantage over the older out-of-process approach (used +by debuggers and utilities like Dwarf Therapist). The main disadvantage of this +approach is that any compiled code relying on these layouts will break when DF's +layout changes, and will need to be recompiled for every new DF version. + +Addresses of DF global objects and vtables are stored in a separate file, +:file:`symbols.xml`. Since these are only absolute addresses, they do not need +to be compiled into DFHack code, and are instead loaded at runtime. This makes +fixes and additions to global addresses possible without recompiling DFHack. +In an installed copy of DFHack, this file can be found at the root of the +``hack`` folder. + +Please see the following page for detailed information about the syntax of the +df-structures XML files: + +.. toctree:: + :titlesonly: + + /library/xml/SYNTAX diff --git a/docs/dev/compile/Compile.rst b/docs/dev/compile/Compile.rst new file mode 100644 index 0000000000..2ad2c52efb --- /dev/null +++ b/docs/dev/compile/Compile.rst @@ -0,0 +1,455 @@ +.. highlight:: shell + +.. _compile: + +########### +Compilation +########### + +DFHack builds are available for all supported platforms; see `installing` for +installation instructions. If you are a DFHack end-user, modder, or plan on +writing scripts [lua] (not plugins), it is generally recommended (and easier) to use +these `builds `_ instead of compiling DFHack from source. + +However, if you are looking to develop plugins, work on the DFHack core, make +complex changes to DF-structures, or anything else that requires compiling +DFHack from source, this document will walk you through the build process. Note +that some steps may be unconventional compared to other projects, so be sure to +pay close attention if this is your first time compiling DFHack. + +.. contents:: Contents + :local: + :depth: 2 + +.. _compile-how-to-get-the-code: + +How to get the code +=================== +DFHack uses Git for source control; instructions for installing Git can be found +in the platform-specific sections below. The code is hosted on +`GitHub `_, and can be downloaded with:: + + git clone --recursive https://github.com/DFHack/dfhack + cd dfhack + +If your version of Git does not support the ``--recursive`` flag, you will need +to omit it and run ``git submodule update --init`` after entering the dfhack +directory. + +This will check out the code on the default branch of the GitHub repo, currently +``develop``, which may be unstable. If you want code for the latest stable +release, you can check out the ``master`` branch instead:: + + git checkout master + git submodule update + +In general, a single DFHack clone is suitable for development - most Git +operations such as switching branches can be done on an existing clone. If you +find yourself cloning DFHack frequently as part of your development process, or +getting stuck on anything else Git-related, feel free to reach out to us for +assistance. + +.. admonition:: Offline builds + + If you plan to build DFHack on a machine without an internet connection (or + with an unreliable connection), see `note-offline-builds` for additional + instructions. + +.. admonition:: Working with submodules + + DFHack uses submodules extensively to manage its subprojects (including the + ``scripts`` folder and DF-structures in ``library/xml``). Failing to keep + submodules in sync when switching between branches can result in build errors + or scripts that don't work. In general, you should always update submodules + whenever you switch between branches in the main DFHack repo with + ``git submodule update``. (If you are working on bleeding-edge DFHack and + have checked out the master branch of some submodules, running ``git pull`` + in those submodules is also an option.) + + Rarely, we add or remove submodules. If there are any changes to the existence + of submodules when you switch between branches, you should run + ``git submodule update --init`` instead (adding ``--init`` to the above + command). + + Some common errors that can arise when failing to update submodules include: + + * ``fatal: does not exist`` when performing Git operations + * Build errors, particularly referring to structures in the ``df::`` namespace + or the ``library/include/df`` folder + * ``Not a known DF version`` when starting DF + * ``Run 'git submodule update --init'`` when running CMake + + Submodules are a particularly confusing feature of Git. The + `Git Book `_ has a + thorough explanation of them (as well as of many other aspects of Git) and + is a recommended resource if you run into any issues. Other DFHack developers + are also able to help with any submodule-related (or Git-related) issues + you may encounter. + +All Platforms +============= +Before you can compile the code you'll need to configure your build with cmake. Some IDEs can do this +for you, but it's more common to do it from the command line. Windows developers can refer to the +Windows section below for batch files that can be used to avoid opening a terminal/command-prompt. + +You should seek cmake's documentation online or via ``cmake --help`` to see how the command works. See +the `build-options` page for help finding the DFHack build options relevant to you. + +Before compiling code, you'll of course need code to compile. This **will include** the submodules, so +be sure you've read the section about getting the code. + +.. _compile-linux: + +Linux +===== + +Building is fairly straightforward. Enter the ``build`` folder (or create an +empty folder in the DFHack directory to use instead) and start the build like this:: + + cd build + cmake .. -G Ninja -DCMAKE_BUILD_TYPE:string=Release -DCMAKE_INSTALL_PREFIX= + ninja install # or ninja -jX install to specify the number of cores (X) to use + + should be a path to a copy of Dwarf Fortress, of the appropriate +version for the DFHack you are building. This will build the library along +with the normal set of plugins and install them into your DF folder. + +Alternatively, you can use ccmake instead of cmake:: + + cd build + ccmake .. -G Ninja + ninja install + +This will show a curses-based interface that lets you set all of the +extra options. You can also use a cmake-friendly IDE like KDevelop 4 +or the cmake-gui program. + +.. _compile-windows: + +Windows +======= +There are several different batch files in the ``win32`` and ``win64`` +subfolders in the ``build`` folder, along with a script that's used for picking +the DF path. Use the subfolder corresponding to the architecture that you want +to build for. + +First, run ``set_df_path.vbs`` and point the dialog that pops up at +a suitable DF installation which is of the appropriate version for the DFHack +you are compiling. The result is the creation of the file ``DF_PATH.txt`` in +the build directory. It contains the full path to the destination directory. +You could therefore also create this file manually - or copy in a pre-prepared +version - if you prefer. + +Next, run one of the scripts with ``generate`` prefix. These create the MSVC +solution file(s): + +* ``all`` will create a solution with everything enabled (and the kitchen sink). +* ``gui`` will pop up the CMake GUI and let you choose what to build. + This is probably what you want most of the time. Set the options you are interested + in, then hit configure, then generate. More options can appear after the configure step. +* ``minimal`` will create a minimal solution with just the bare necessities - + the main library and standard plugins. +* ``release`` will create a solution with everything that should be included in + release builds of DFHack. Note that this includes documentation, which requires + Python. + +Then you can either open the solution with MSVC or use one of the msbuild scripts. + +Visual Studio IDE +----------------- +After running the CMake generate script you will have a new folder called VC2022 +or VC2022_32, depending on the architecture you specified. Open the file +``dfhack.sln`` inside that folder. If you have multiple versions of Visual +Studio installed, make sure you open with Visual Studio 2022. + +The first thing you must then do is ensure the build type is not Debug, which +cannot be used on Windows. Debug is not binary-compatible with DF. +If you try to use a debug build with DF, you'll only get crashes and for this +reason the Windows "debug" scripts actually do RelWithDebInfo builds. +After loading the Solution, change the Build Type to either ``Release`` +or ``RelWithDebInfo``. + +Then build the ``INSTALL`` target listed under ``CMakePredefinedTargets``. + +Command Line +------------ +In the build directory you will find several ``.bat`` files: + +* Scripts with ``build`` prefix will only build DFHack. +* Scripts with ``install`` prefix will build DFHack and install it to the previously selected DF path. +* Scripts with ``package`` prefix will build and create a .zip package of DFHack. + +Compiling from the command line is generally the quickest and easiest option. +Modern Windows terminal emulators such as `Cmder `_ or +`Windows Terminal `_ provide a better +experience by providing more scrollback and larger window sizes. + +.. _compile-macos: + +macOS +===== + +NOTE: this section is currently outdated. Once DF itself can build on macOS +again, we will match DF's build environment and update the instructions here. + +DFHack functions similarly on macOS and Linux, and the majority of the +information above regarding the build process (CMake and Ninja) applies here +as well. + +DFHack can officially be built on macOS only with GCC 4.8 or 7. Anything newer than 7 +will require you to perform extra steps to get DFHack to run (see `osx-new-gcc-notes`), +and your build will likely not be redistributable. + +Building +-------- + +* Get the DFHack source as per section `compile-how-to-get-the-code`, above. +* Set environment variables + + Homebrew (if installed elsewhere, replace /usr/local with ``$(brew --prefix)``):: + + export CC=/usr/local/bin/gcc-7 + export CXX=/usr/local/bin/g++-7 + + Macports:: + + export CC=/opt/local/bin/gcc-mp-7 + export CXX=/opt/local/bin/g++-mp-7 + + Change the version numbers appropriately if you installed a different version of GCC. + + If you are confident that you have GCC in your path, you can omit the absolute paths:: + + export CC=gcc-7 + export CXX=g++-7 + + (adjust as needed for different GCC installations) + +* Build DFHack:: + + mkdir build-osx + cd build-osx + cmake .. -G Ninja -DCMAKE_BUILD_TYPE:string=Release -DCMAKE_INSTALL_PREFIX= + ninja install # or ninja -jX install to specify the number of cores (X) to use + + should be a path to a copy of Dwarf Fortress, of the appropriate + version for the DFHack you are building. + +.. _osx-new-gcc-notes: + +Notes for GCC 8+ or OS X 10.10+ users +------------------------------------- + +If you have issues building on OS X 10.10 (Yosemite) or above, try defining +the following environment variable:: + + export MACOSX_DEPLOYMENT_TARGET=10.9 + +If you build with a GCC version newer than 7, DFHack will probably crash +immediately on startup, or soon after. To fix this, you will need to replace +``hack/libstdc++.6.dylib`` with a symlink to the ``libstdc++.6.dylib`` included +in your version of GCC:: + + cd /hack && mv libstdc++.6.dylib libstdc++.6.dylib.orig && + ln -s [PATH_TO_LIBSTDC++] . + +For example, with GCC 6.3.0, ``PATH_TO_LIBSTDC++`` would be:: + + /usr/local/Cellar/gcc@6/6.3.0/lib/gcc/6/libstdc++.6.dylib # for 64-bit DFHack + /usr/local/Cellar/gcc@6/6.3.0/lib/gcc/6/i386/libstdc++.6.dylib # for 32-bit DFHack + +**Note:** If you build with a version of GCC that requires this, your DFHack +build will *not* be redistributable. (Even if you copy the ``libstdc++.6.dylib`` +from your GCC version and distribute that too, it will fail on older OS X +versions.) For this reason, if you plan on distributing DFHack, it is highly +recommended to use GCC 4.8 or 7. + +.. _osx-m1-notes: + +Notes for M1 users +------------------ + +Alongside the above, you will need to follow these additional steps to get it +running on Apple silicon. + +Install an x86 copy of ``homebrew`` alongside your existing one. `This +stackoverflow answer `__ describes the +process. + +Follow the normal macOS steps to install ``cmake`` and ``gcc`` via your x86 copy of +``homebrew``. Note that this will install a GCC version newer than 7, so see +`osx-new-gcc-notes`. + +In your terminal, ensure you have your path set to the correct homebrew in +addition to the normal ``CC`` and ``CXX`` flags above:: + + export PATH=/usr/local/bin:$PATH + +Windows cross compiling from Linux (running DF inside docker) +============================================================= + +.. highlight:: bash + +You can use docker to build DFHack for Windows. These instructions were developed +on a Linux host system. + +.. contents:: + :local: + :depth: 1 + +Step 1: prepare a build container +--------------------------------- + +On your Linux host, install and run the docker daemon and then run these commands:: + + xhost +local:root + docker run -it --env="DISPLAY" --env="QT_X11_NO_MITSHM=1" --volume=/tmp/.X11-unix:/tmp/.X11-unix --user buildmaster --name dfhack-win ghcr.io/dfhack/build-env:master + +The ``xhost`` command and ``--env`` parameters are there so you can eventually +run Dwarf Fortress from the container and have it display on your host. + +Step 2: build DFHack +-------------------- + +The ``docker run`` command above will give you a shell prompt (as the ``buildmaster`` user) in the +container. Inside the container, run the following commands:: + + git clone https://github.com/DFHack/dfhack.git + cd dfhack + git submodule update --init + cd build + dfhack-configure windows 64 Release + dfhack-make + +Inside the ``dfhack-*`` scripts there are several commands that set up the wine +server. Each invocation of a Windows tool will cause wine to run in the container. +Preloading the wineserver and telling it not to exit will speed configuration and +compilation up considerably (approx. 10x). You can configure and build DFHack +with regular ``cmake`` and ``ninja`` commands, but your build will go much slower. + +Step 3: copy Dwarf Fortress to the container +-------------------------------------------- + +First, create a directory in the container to house the Dwarf Fortress binary and +assets:: + + mkdir ~/df + +If you can just download Dwarf Fortress directly into the container, then that's fine. +Otherwise, you can do something like this in your host Linux environment to copy an +installed version to the container:: + + cd ~/.steam/steam/steamapps/common/Dwarf\ Fortress/ + docker cp . dfhack-win:df/ + +Step 4: install DFHack and run DF +--------------------------------- + +Back in the container, run the following commands:: + + cd dfhack/build + cmake .. -DCMAKE_INSTALL_PREFIX=/home/buildmaster/df + ninja install + cd ~/df + wine64 "Dwarf Fortress.exe" + +Other notes +----------- + +Closing your shell will kick you out of the container. Run this command on your Linux +host when you want to reattach:: + + docker start -ai dfhack-win + +If you edit code and need to rebuild, run ``dfhack-make`` and then ``ninja install``. +That will handle all the wineserver management for you. + +Cross-compiling windows files for running DF in Steam for Linux +=============================================================== + +.. highlight:: bash + +If you wish, you can use Docker to build just the Windows files to copy to your +existing Steam installation on Linux. + +.. contents:: + :local: + :depth: 1 + +Step 1: Get dfhack, and run the build script +-------------------------------------------- + +Check out ``dfhack`` into another directory, and run the build script:: + + git clone https://github.com/DFHack/dfhack.git + cd dfhack + git submodule update --init --recursive + cd build + ./build-win64-from-linux.sh + +The script will mount your host's ``dfhack`` directory to docker, use it to +build the artifacts in ``build/win64-cross``, and put all the files needed to +install in ``build/win64-cross/output``. + +If you need to run ``docker`` using ``sudo``, run the script using ``sudo`` +rather than directly:: + + sudo ./build-win64-from-linux.sh + +Step 2: install dfhack to your Steam DF install +----------------------------------------------- +As the script will tell you, you can then copy the files into your DF folder:: + + # Optional -- remove the old hack directory in case we leave files behind + rm ~/.local/share/Steam/steamapps/common/"Dwarf Fortress"/hack + cp -r win64-cross/output/* ~/.local/share/Steam/steamapps/common/"Dwarf Fortress"/ + +Afterward, just run DF as normal. + +.. _note-offline-builds: + +Building DFHack Offline +======================= +As of 0.43.05, DFHack downloads several files during the build process, depending +on your target OS and architecture. If your build machine's internet connection +is unreliable, or nonexistent, you can download these files in advance. + +First, you must locate the files you will need. These can be found in the +`dfhack-bin repo `_. Look for the +most recent version number *before or equal to* the DF version which you are +building for. For example, suppose "0.43.05" and "0.43.07" are listed. You should +choose "0.43.05" if you are building for 0.43.05 or 0.43.06, and "0.43.07" if +you are building for 0.43.07 or 0.43.08. + +Then, download all of the files you need, and save them to ``/CMake/downloads/``. The destination filename you choose +does not matter, as long as the files end up in the ``CMake/downloads`` folder. +You need to download all of the files for the architecture(s) you are building +for. For example, if you are building for 32-bit Linux and 64-bit Windows, +download all files starting with ``linux32`` and ``win64``. GitHub should sort +files alphabetically, so all the files you need should be next to each other. + +.. note:: + + * Any files containing "allegro" in their filename are only necessary for + building `stonesense`. If you are not building Stonesense, you don't have to + download these, as they are larger than any other listed files. + +It is recommended that you create a build folder and run CMake to verify that +you have downloaded everything at this point, assuming your download machine has +CMake installed. This involves running a "generate" batch script on Windows, or +a command starting with ``cmake .. -G Ninja`` on Linux and macOS, following the +instructions in the sections above. CMake should automatically locate files that +you placed in ``CMake/downloads``, and use them instead of attempting to +download them. + +In addition, some packages used by DFHack are managed using CMake's ``FetchContent`` +feature, which requires an online connection during builds. The simplest way to address +this is to have a connection during the first build (during which CMake will download the +dependencies), and then to use CMake's ``FETCHCONTENT_FULLY_DISCONNECTED`` or +``FETCHCONTENT_UPDATES_DISCONNECTED`` defines to control how CMake manages cached +dependencies. If you need even the first-time build be an offline build, you will need +to provide a CMake dependency provider. We do not provide one, but CMake's own documentation +includes a simple provider. For more information about CMake's ``FetchContent`` feature +and how to use it in offline builds, see the +`CMake documentation `_. diff --git a/docs/dev/compile/Dependencies.rst b/docs/dev/compile/Dependencies.rst new file mode 100644 index 0000000000..b42a833785 --- /dev/null +++ b/docs/dev/compile/Dependencies.rst @@ -0,0 +1,303 @@ +.. _build-dependencies: + +############ +Dependencies +############ + +DFHack is meant to be installed into an **existing DF folder**, so ensure that +one is ready. + +.. contents:: Contents + :local: + :depth: 2 + +Overview of Dependencies +======================== + +This section provides an overview of system dependencies that DFHack relies on. +See the platform-specific sections later in this document for specifics on how +to install these dependencies. + +DFHack also has several dependencies on libraries that are included in the +repository as Git submodules, which require no further action to install. + +System dependencies +------------------- + + +* CMake (v3.21 or newer is recommended) +* build system (e.g. gcc & ninja, or Visual Studio) +* Perl 5 (for code generation) + * XML::LibXML + * XML::LibXSLT +* Python 3 (for `documentation `) + * Sphinx +* Git (required for `contributions `_) +* ccache (**optional**, but strongly recommended to improve build times) +* OpenGL headers (**optional**: to build `stonesense`) +* zlib (compression library used for `xlsxreader-api` -> `quickfort`) + +Perl packages +------------- + +* XML::LibXML +* XML::LibXSLT + +The Perl packages are used in code generation. DF memory structures are +represented as XML in DFHack's source tree. During the configuration process +(cmake) the xml files are converted into C++ headers and Lua wrappers for use +by plugins and scripts. + +Python packages +--------------- + +* Sphinx (required to build the `documentation `) + +Installing Dependencies +======================= + +.. contents:: + :local: + :depth: 2 + +.. _linux-dependency-instructions: + +Linux +----- + +Here are some package install commands for various distributions: + +* On Arch Linux:: + + pacman -Sy gcc cmake ccache ninja git dwarffortress zlib perl-xml-libxml perl-xml-libxslt + + * The ``dwarffortress`` package provides the necessary SDL packages. + * For the required Perl modules: ``perl-xml-libxml`` and ``perl-xml-libxslt`` (or through ``cpan``) + +* On Ubuntu:: + + apt-get install gcc cmake ccache ninja-build git zlib1g-dev libsdl2-dev libxml-libxml-perl libxml-libxslt-perl + + * Other Debian-based distributions should have similar requirements. + +* On Fedora:: + + yum install gcc-c++ cmake ccache ninja-build git zlib-devel SDL2-devel perl-core perl-XML-LibXML perl-XML-LibXSLT ruby + +To build DFHack, you need GCC 10 or newer. Note that extremely new GCC versions +may not have been used to build DFHack yet, so if you run into issues with +these, please let us know (e.g. by opening a GitHub issue). + +Distributing binaries compiled with newer GCC versions may result in +compatibility issues for players with older GCC versions. This is why DFHack +builds distributables with GCC 10, which is the same GCC version that DF itself +is compiled with. + +Before you can build anything, you'll also need ``cmake``. It is advisable to +also get ``ccmake`` (the interactive configuration interface) on distributions +that split the cmake package into multiple parts. As mentioned above, ``ninja`` +is recommended as the build system (many distributions call this package +``ninja-build``), but ``make`` also works. + +You will need pthread; most systems should have this already. Note that older +CMake versions may have trouble detecting pthread, so if you run into +pthread-related errors and pthread is installed, you may need to upgrade CMake, +either by downloading it from `cmake.org `_ or +through your package manager, if possible. + +.. _windows-dependency-instructions: + +Windows +------- + +DFHack must be built with the Microsoft Visual C++ 2022 toolchain (aka MSVC v143) +for ABI compatibility with Dwarf Fortress v50. + +.. contents:: + :local: + :depth: 1 + +With Chocolatey +~~~~~~~~~~~~~~~ +Many of the dependencies are simple enough to download and install via the +`chocolatey`_ package manager on the command line. + +Here are some package install commands:: + + choco install cmake + choco install ccache + choco install strawberryperl + choco install python + choco install sphinx + + # Visual Studio + choco install visualstudio2022community --params "--add Microsoft.VisualStudio.Workload.NativeDesktop --includeRecommended" + # OR + # Build Tools for Visual Studio + choco install visualstudio2022buildtools --params "--add Microsoft.VisualStudio.Workload.NativeDesktop --includeRecommended" + +If you already have Visual Studio 2022 or the Build Tools installed, you may +need to modify the installed version to include the workload components +listed in the manual installation section, as chocolatey will not amend +the existing install. + +.. _chocolatey: https://chocolatey.org/install + +Manually +~~~~~~~~ +If you prefer to install manually rather than using Chocolatey, details and +requirements are as below. If you do install manually, **ensure that your PATH +variable is updated** to include the install locations for all tools. This can +be edited from ``Control Panel -> System -> Advanced System Settings -> +Environment Variables``. + +.. contents:: + :local: + :depth: 1 + +CMake +^^^^^ +You can get the Windows installer from `the official site `_. +It has the usual installer wizard. Make sure you let it add its binary folder +to your binary search PATH so the tool can be later run from anywhere. + +Perl / Strawberry Perl +^^^^^^^^^^^^^^^^^^^^^^ +For the code generation stage of the build process, you'll need Perl 5 with the +``XML::LibXML`` and ``XML::LibXSLT`` packages installed. +`Strawberry Perl `_ is recommended as it includes all +of the required packages in a single easy install. + +After install, ensure Perl is in your user's PATH. The following directories must be in your PATH, in this order: + +* ``\c\bin`` +* ``\perl\site\bin`` +* ``\perl\bin`` +* ``\perl\vendor\lib\auto\XML\LibXML`` (path may only be required on some systems) + +Be sure to close and re-open any existing ``cmd.exe`` windows after updating +your PATH. + +If you already have a different version of Perl installed (for example, from Cygwin), +you can run into some trouble. Either remove the other Perl install from PATH, or +install XML::LibXML and XML::LibXSLT for it using CPAN. + +Python +^^^^^^ +See the `Python`_ website. Any supported version of Python 3 will work. + +.. _Python: https://www.python.org/downloads/ + +Sphinx +^^^^^^ +See the `Sphinx`_ website. + +.. _Sphinx: https://www.sphinx-doc.org/en/master/usage/installation.html + +.. _install-visual-studio: + +Visual Studio +^^^^^^^^^^^^^ +The required toolchain can be installed as a part of either the `Visual Studio 2022 IDE`_ +or the `Build Tools for Visual Studio 2022`_. If you already have a preferred code +editor, the Build Tools will be a smaller install. You may need to log into (or create) +a Microsoft account in order to download Visual Studio. + +.. _Visual Studio 2022 IDE: https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=Community&channel=Release&version=VS2022&source=VSLandingPage&cid=2030&passive=false +.. _Build Tools for Visual Studio 2022: https://my.visualstudio.com/Downloads?q=Build%20Tools%20for%20Visual%20Studio%202022 + + +Build Tools [Without Visual Studio] +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Click `Build Tools for Visual Studio 2022`_ and you will be prompted to login to your Microsoft account. +Then you should be redirected to a page with various download options with 2022 +in their name. If this redirect doesn't occur, just copy, paste, and enter the +download link again and you should see the options. + +You want to select the most up-to-date version -- as of writing this is +"Build Tools for Visual Studio 2022 (version 17.4)". "LTSC" is an extended +support variant and is not required for our purposes. + +When installing, select the "Desktop Development with C++" workload and ensure that the following are checked: + +- MSVC v143 - VS 2022 C++ x64/x86 build tools +- C++ CMake tools for Windows +- At least one Windows SDK (for example, Windows 11 SDK 10.0.22621). + +.. _mac-dependency-instructions: + +macOS +----- + +NOTE: this section is currently outdated. Once DF itself can build on macOS +again, we will match DF's build environment and update the instructions here. + +DFHack is easiest to build on macOS with exactly GCC 4.8 or 7. Anything newer than 7 +will require you to perform extra steps to get DFHack to run (see `osx-new-gcc-notes`), +and your build will likely not be redistributable. + +#. Download and unpack a copy of the latest DF +#. Install Xcode from the Mac App Store + +#. Install the XCode Command Line Tools by running the following command:: + + xcode-select --install + +#. Install dependencies + + It is recommended to use Homebrew instead of MacPorts, as it is generally + cleaner, quicker, and smarter. For example, installing MacPort's GCC will + install more than twice as many dependencies as Homebrew's will, and all in + both 32-bit and 64-bit variants. Homebrew also doesn't require constant use + of ``sudo``. + + Using `Homebrew `_ (recommended):: + + brew tap homebrew/versions + brew install git + brew install cmake + brew install ninja + brew install gcc@7 + + Using `MacPorts `_:: + + sudo port install gcc7 +universal cmake +universal git-core +universal ninja +universal + + Macports will take some time - maybe hours. At some point it may ask + you to install a Java environment; let it do so. + +#. Install Perl dependencies + + * Using system Perl + + * ``sudo cpan`` + + If this is the first time you've run cpan, you will need to go through the setup + process. Just stick with the defaults for everything and you'll be fine. + + If you are running OS X 10.6 (Snow Leopard) or earlier, good luck! + You'll need to open a separate Terminal window and run:: + + sudo ln -s /usr/include/libxml2/libxml /usr/include/libxml + + * ``install XML::LibXML`` + * ``install XML::LibXSLT`` + + * In a separate, local Perl install + + Rather than using system Perl, you might also want to consider + the Perl manager, `Perlbrew `_. + + This manages Perl 5 locally under ``~/perl5/``, providing an easy + way to install Perl and run CPAN against it without ``sudo``. + It can maintain multiple Perl installs and being local has the + benefit of easy migration and insulation from OS issues and upgrades. + + See https://perlbrew.pl/ for more details. + +#. Install Python dependencies + + * You can choose to use a system Python 3 installation or any supported + version of Python 3 from `python.org `__. + + * Install `Sphinx`_ diff --git a/docs/dev/compile/Options.rst b/docs/dev/compile/Options.rst new file mode 100644 index 0000000000..462fd1f1ca --- /dev/null +++ b/docs/dev/compile/Options.rst @@ -0,0 +1,163 @@ +.. _build-options: + +############# +Build Options +############# + +.. contents:: Typical Options + :local: + :depth: 1 + +There are a variety of other settings which you can find in CMakeCache.txt in +your build folder or by running ``ccmake`` (or another CMake GUI). Most +DFHack-specific settings begin with ``BUILD_`` and control which parts of DFHack +are built. + +Typical usage may look like:: + + # Plugin development with updated documentation + cmake ./ -G Ninja -B builds/debug-info/ -DCMAKE_INSTALL_PREFIX= -DCMAKE_BUILD_TYPE:string=RelWithDebInfo -DBUILD_DOCS:bool=ON -DBUILD_PLUGINS=1 + # Core DFHack only + cmake ../ -G Ninja -DCMAKE_INSTALL_PREFIX= -DCMAKE_BUILD_TYPE:string=RelWithDebInfo -DBUILD_TESTS -DBUILD_DOCS:0 -DBUILD_PLUGINS=0 + +.. admonition:: Modifying Build Options + + You can typically run new cmake commands from your build directory to turn on/off options. + Of course the generator selection is not something you can change, but the rest are. + + Additionally, you can edit the build settings in CMakeCache.txt. You also have cmake's + configuration utility ``ccmake``. + +Generator +========= +For the uninitiated, the generator is what allows cmake to, of course, generate +visual studio solution & project files, a makefile, or anything else. +Your selection of generator comes down to preference and availability. + +Visual Studio +------------- +To generate visual studio project files, you'll need to select a particular version of +visual studio, and match that to your system's generator list viewed with ``cmake --help`` + +example:: + + cmake .. -G "Visual Studio 17 2022" + +Ninja +----- +The generally preferred build system where available. + +example:: + + cmake .. -G Ninja + +Install Location +================ +This is the location where DFHack will be installed. + +Variable: ``CMAKE_INSTALL_PREFIX`` + +Usage:: + + cmake .. -DCMAKE_INSTALL_PREFIX= + +The path to df will of course depend on your system. If the directory exists it is +recommended to use ``~/.dwarffortress`` to avoid permission troubles. + +Build type +========== +This is the type of build you want. This controls what information about symbols and +line numbers the debugger will have available to it. + +Variable: ``CMAKE_BUILD_TYPE`` + +Usage:: + + cmake .. -DCMAKE_BUILD_TYPE:string=RelWithDebInfo + +Options: + +* Release +* RelWithDebInfo + +Target architecture (32/64-bit) +=============================== +You can set this if you need 32-bit binaries or are looking to be explicit about +building 64-bit. + +Variable: ``DFHACK_BUILD_ARCH`` + +Usage:: + + cmake .. -DDFHACK_BUILD_ARCH=32 + +Options: + +* '32' +* '64' (default option) + +Library +======= +This will only be useful if you're looking to avoid building the library core, as it builds by default. + +Variable: ``BUILD_LIBRARY`` + +Usage:: + + cmake .. -DBUILD_LIBRARY:bool=OFF + cmake .. -DBUILD_LIBRARY=0 + +Testing +======= +Regression testing will be arriving in the future, but for now there are only tests written in lua. + +Variables: + +* ``BUILD_TESTING`` (will build unit tests, in the future) +* ``BUILD_TESTS`` (installs lua tests) + +Usage:: + + cmake .. -DBUILD_TESTS:bool=ON + cmake .. -DBUILD_TESTS=1 + +Plugins +======= +If you're doing plugin development. + +Variable: ``BUILD_PLUGINS`` + +Usage:: + + cmake .. -DBUILD_PLUGINS:bool=ON + cmake .. -DBUILD_PLUGINS=1 + +.. _building-documentation: + +Documentation +============= +If you need to build `documentation `. + +.. note:: + + These options are primarily useful for verifying that the end-to-end process + for building and packaging the documentation is working as expected. For + iterating on documentation changes, `faster alternatives ` are + available. + +Variables: + +* ``BUILD_DOCS``: enables the default documentation build +* ``BUILD_DOCS_NO_HTML``: disables the HTML documentation build (only builds the text documentation used in-game) + +Usage:: + + cmake .. -DBUILD_DOCS:bool=ON + cmake .. -DBUILD_DOCS=1 + cmake .. -DBUILD_DOCS_NO_HTML:bool=ON + cmake .. -DBUILD_DOCS_NO_HTML=1 + +The generated documentation is stored in ``docs/html`` and ``docs/text`` (respectively) +in the root DFHack folder, and they will both be installed to ``hack/docs`` when you +install DFHack. The html and txt files will intermingle, but will not interfere with +one another. diff --git a/docs/dev/compile/index.rst b/docs/dev/compile/index.rst new file mode 100644 index 0000000000..f9f6105ff6 --- /dev/null +++ b/docs/dev/compile/index.rst @@ -0,0 +1,15 @@ +.. _building-dfhack-index: + +=============== +Building DFHack +=============== + +Those seeking to compile the source code for DFHack, including core and plugins, +can refer to the following help pages. + +.. toctree:: + :maxdepth: 2 + + /docs/dev/compile/Dependencies + /docs/dev/compile/Compile + /docs/dev/compile/Options diff --git a/docs/dev/data-identity.rst b/docs/dev/data-identity.rst new file mode 100644 index 0000000000..ae7076941d --- /dev/null +++ b/docs/dev/data-identity.rst @@ -0,0 +1,246 @@ +.. _data_identity: + +########################### +DFHack Data Identity System +########################### + +This article is an attempt to describe DFHack's data identity system. +DFHack internally has a collection of C++ classes that provide metadata about the data in DF itself as well as data used +by various components of DFHack. This metadata is used primarily to enable the Lua scripting system to access data +held by Dwarf Fortress in a transparent manner, but is also used for several other purposes within DFHack, such as rerouting virtual method calls. + +The base class of the identity system is the class ``type_identity``, defined in :source:`DataDefs.h `. A ``type_identity`` object +provides information about one *type* of data object, in either Dwarf Fortress or DFHack, that can be manipulated as a discrete entity in Lua. +With one specific exception (``global_identity``, covered below), there is a one-to-one relationship between C++ types and ``type_identity`` objects. +In Lua, objects that are being managed via the data identity system are represented as a Lua userdata object. The userdata object +contains both a pointer to the C++ object itself and a pointer to a ``type_identity`` object that describes the data pointed +by that pointer. Note that the userdata object does not own the objects pointed to by these pointers, and the Lua engine is +never responsible for managing their lifetimes. + +``type_identity`` defines the following public methods: + +- ``byte_size``: returns the size, in bytes, of the object held + +- ``type``: returns an enum (of type ``identity_type``) classifying the object held. + +- ``getFullName``: returns a string that describes the type. This will usually be similar to a C++ ``typedef``, although this is not guaranteed. + +- ``lua_read``: Used by the Lua engine to "read" the data from a C++ object into the Lua state. + +- ``lua_write``: Used by the Lua engine to "write" a value from the Lua state into a C++ data object. + +- ``build_metatable``: Create a Lua metatable in the specified Lua state corresponding to this type identity. + +- ``is_primitive``: indicates that ``lua_read`` will store a *copy* of the object on the Lua stack instead of a non-owning reference to it. Used for types that have direct representations in Lua: numbers, booleans, simple strings + +- ``is_constructed``: indicates that creating a C++ instance of this type requires the use of a possibly nontrivial constructor. A type identity that is both primitive and constructed cannot be inserted into a container. At the moment the only type identity that is both primitive and constructed is ``stl_string_identity``, which wraps the C++ ``std::string`` type. + +- ``is_container``: indicates that the type is a container and thus implements the methods specific to ``container_identity`` + +- ``allocate``: allocate, and construct if necessary, a C++ instance of this type. This may fail if the type does not support construction. + +- ``copy``: copy the object at ``src`` onto ``tgt``. This uses ``memmove`` for primitive types, and C++ copy-assignment (when possible) for other types + +There are plethora of subclasses of ``type_identity``: + +* ``type_identity`` the abstract base class of all type identities + + * ``constructed_identity`` anything with an internal structure (not primitive) + + * ``compound_identity`` anything with fields + + * ``bitfield_identity`` a structure defined with fields at bit rather than byte boundaries + + * ``enum_identity`` C++ ``enum`` + + * ``struct_identity`` C++ ``class`` or ``structure`` + + * ``global_identity`` holds, as a quasiobject, handles for all of the known Dwarf Fortress program-scope static objects as if they were fields of an object called ``global`` + + * ``union_identity`` C++ ``union`` + + * ``other_vectors_identity`` special-case identity for the categorized subvectors of objects that appears in many of Dwarf Fortress's "handler" classes + + * ``virtual_identity`` polymorphic C++ ``class`` or ``structure`` having a virtual table to handle virtual dispatch + + * ``stl_string_identity`` ``std::string`` + + * ``xlsx_file_handle_identity`` special case + + * ``xlsx_sheet_handle_identity`` special case + + * ``container_identity`` "containers" generally. note that all container types are homogeneous (that is, the elements of the container must all be of the same type). abstract base class + + * ``bit_container_identity`` for containers that contain bools stored one element per *bit* (rather than per byte) + + * ``bit_array_identity`` Dwarf Fortress's ``BitArray`` type + + * ``stl_bit_vector_identity`` ``std::vector`` + + * ``buffer_container_identity`` C++ static arrays and raw C++ pointers acting as arrays of unspecified bound + + * ``enum_list_attr_identity`` (template) metaobject with metadata about a C++ enumeration; may also include additional metadata + + * ``ptr_container_identity`` containers that contain pointers + + * ``stl_ptr_container_identity`` containers that are of the form ``std::vector`` for some ``T`` + + * ``ro_stl_container_identity`` (template) "read only containers" + + * ``ro_stl_assoc_container_identity`` (template) ``std::map`` and ``std::unordered_map`` + + * ``stl_container_identity`` (template) ``std::vector`` where ``T`` is *not* a pointer (and not ``bool``) + + * ``opaque_identity`` opaque wrapper around any type, provides no functionality + + * ``stl_string_identity`` ``std::string`` + + * ``function_identity_base`` abstract base class for ``function_identity`` + + * ``function_identity`` (template) wrapper around a C++ function that can be invoked from Lua + + * ``primitive_identity`` wrapper around a primitive type. primitive types are fixed-length objects with no internal structure + + * ``bool_identity`` ``bool`` + + * ``number_identity_base`` abstract base for numeric types + + * ``float_identity_base`` abstract base for floating point types + + * ``float_identity`` (template) ``double`` and ``float`` + + * ``integer_identity_base`` abstract base for integral types + + * ``integer_identity`` (template) ``int8_t``, ``int16_t``, ``int32_t``, ``size_t``, etc. lots of these + + * ``pointer_identity`` any arbitrary C++ pointer (other than ``char*``) + + * ``ptr_string_identity`` C-style (``char *``) string + +Types marked with "(template)" are C++ template types, all parameterized by a single typename. + +Type identity object lifetime and mutability +============================================ + +*Most* instances of ``type_identity`` are statically constructed and immutable and are thus ``const static`` when constructed. +All ``type_identity`` pointers should be declared ``const``. Due to ``virtual_identity``'s role in implementing +DFHack's vmethod interpose system, it is important that there be at most one ``virtual_identity`` object per virtual class. +Having more than one ``struct_identity`` object for the same type might also potentially lead to misoperation. + +In general, there should be a one to one correspondence between ``type_identity`` objects and C++ types +(with the special case that ``global_identity`` has no corresponding type). As far as we know, for any type other than ``virtual_identity``, +violations of this constraint will not lead to misoperation, but this constraint should not be lightly violated. +The Lua/C++ interface does, in a handful of places, assume that it can compare ``type_identity`` +pointers to determine if they reference the same type, but as far as we know all of these instances will fall +back to correct behavior as long as the shadow copies are indistinguishable from one another; +that is, two copies having the same values will compare equal in all known such comparisons. +Therefore, if two ``type_identity`` objects do exist (for any reason) for the same underlying C++ type, +those objects must be indistinguishable from one another by anything other than their address. + +The ``type_identity`` object for a given C++ type can be obtained by using the ``get`` method of the ``df::identity_trait`` +trait class. +More specifically, ``identity_traits::get()`` will return a pointer to a ``type_identity`` object for the type ``T``. +Developers who create new type identities must *either* provide an specialization of ``identity_traits`` that implements +a ``get`` method that returns the correct ``type_identity`` +*or* ensure that a static instance of ``T::_identity`` exists for the type ``T`` +(which will result in a template in :source:`DataDefs.h ` providing +an implementation of ``get`` for that type). +Note that this is only possible for compound types, and is the way that the *vast* majority of +compound types have their identities specified (including all of those defined via codegen). + +Because objects in the Lua environment are constructed as a pointer to the data and +a pointer to the data's ``type_identity`` object, it is necessary for ``type_identity`` objects to have a lifetime +that exceeds the lifetime in the Lua environment of any object that exists anywhere in the Lua environment. +It is therefore advised to avoid creating ``type_identity`` objects that do *not* have program lifetime, since +predicting the lifetime of objects in the Lua environment can be difficult. +If it is necessary to create a ``type_identity`` object that will not have program lifetime, +it is incumbent on the developer to ensure that no references to that type identity object persist beyond its lifetime. + +Due to the way template types are implemented in the C++ compilers we use for Dwarf Fortress, any specialization of one +of the type identity classes noted above as a template must at present be statically constructed in the DFHack core. +This is because we export the statically constructed instances from the core library to plugins, which then imports them +from the core library instead of instantiating them locally. As a result, referencing an instance in a plugin that has +not been instantiated in the core will result in linkage errors when linking the plugin to the core library. + +We could instead *not* export the templated types, and thus their statically constructed identity objects, +and instead allow the compiler to instantiate a local copy of these instances while compiling a plugin, +but this would definitely result in a violation of the current requirement that there be at most one instance of the +type identity object for a given C++ type across the entire program (including plugins loaded as a shared library). + +For primitive and opaque types the static constructors of the identity types +are generally found in :source:`DataIdentity.h ` +or :source:`DataIdentity.cpp `. +Types defined by Dwarf Fortress are constructed in the header files and the related ``static*.inc`` files created by codegen, +which are included into DFHack via :source:`DataStatics.cpp `. + +Some plugins (e.g. :source:`blueprint `) also define their own type identities. Type identities in plugins should be used with caution, +because the DFHack plugin model allows plugins to be unloaded on request. +Since the ``type_identity`` object is constructed within the the plugin's address space, and Lua objects that reference +this ``type_identity`` object will hold a (borrowed) pointer to that object, +unloading the plugin will result in a dangling pointer reference within the Lua environment. +It is, at present, incumbent on plugin authors to ensure that they do not use plugin defined type identities on objects +that may persist in the Lua environment beyond the lifetime of the plugin. +Declaring a ``struct_identity`` in a plugin that is the child of another ``struct_identity`` will also result in +a potentially dangling reference to that identity in the ``child`` vector of the parent identity, which means this +must also be approached with caution. + +A final note: because most instances of ``type_identity`` are statically constructed +and their construction is scattered across multiple translation units, it is, in general, *not* safe to cross-reference +the contents of one statically-defined ``type_identity`` instance during the static instantiation of another, +because the order in which statically constructed objects are instantiated in C++ is unspecified for objects defined in different translation units. +Specifically, this means that the constructor for a ``type_identity`` instance must use care in using +``df::identity_traits::get`` to use values from the identity object +of some other type, because that type's identity object may not have been constructed yet. +The ``get`` operation itself is safe, but the pointer returned by ``get`` may point to not-yet-initialized data +until at-start static data initialization is fully complete. + +Namespaces +========== + +The type identity system formally lives in the ``DFHack`` namespace. +However, because the types created by the codegen process live in the ``df`` namespace, +the identities needed to describe types coming from Dwarf Fortress are also imported into the ``df`` namespace. +When defining a new ``type_identity`` class for the purposes of supporting a new category of types coming from codegen, +remember to add an appropriate ``using`` clause to the list in :source:`DataDefs.h `. + +The ``identity_traits``, ``enum_traits``, ``bitfield_traits``, and ``enum_fields`` type traits +are defined in the ``df`` namespace. + +Type traits +=========== + +``identity_traits`` +------------------- +This type trait has two members: + +* ``static const type_identity * get()``: This function returns a pointer to the ``type_identity`` for the type ``T``. +* ``is_primitive``: true if the type is a "primitive type" (except false for enums) + +While not a type trait *per se*, the ``allocate`` template function is defined for all types +as ``return (T*)identity_traits::get()->allocate()`` and provides a convenient way to +reference the allocator in a type's ``type_identity``. + +An additional note: Conceptually, ``Lua::Push`` and ``identity_traits::get->lua_read`` are equivalent, but this is aspirational rather than actual. +There are several types for which ``Lua::Push`` has specializations that do something different than what ``type_identity::lua_read`` does for the same type. + + +``enum_traits`` +--------------- +This type trait has the following members: + +* ``is_complex``: enum is a "complex enum" +* ``enum_type`` (type): the type of the enum +* ``base_type`` (type): the underlying integral type of the enum +* ``complex``: (complex enums only) an ``DFHack::enum_identity::ComplexData`` that describes the enum +* ``is_valid(base_type value)``: (simple enums only) a function that returns a bool indicating whether ``value`` is "in range" for the enum +* ``first_item``: (simple enums only) the least valid value of the enum +* ``last_item``: (simple enums only) the greatest valid value of the enum +* ``key_table``: (simple enums only) a static array of ``const char *`` strings that correspond to the possible values of the enum + +``bitfield_traits`` +------------------- +(TODO) + +``enum_fields`` +--------------- +(TODO) diff --git a/docs/dev/github-workflows.rst b/docs/dev/github-workflows.rst new file mode 100644 index 0000000000..ea71e1a2b6 --- /dev/null +++ b/docs/dev/github-workflows.rst @@ -0,0 +1,204 @@ +GitHub workflows +================ + +We run our continuous integration (CI) validation and our release automation +via GitHub workflows. This allows us to merge PRs with confidence that they +won't catastrophically break DFHack functionality. GitHub workflows also allow +us to quickly produce stable release builds with fewer manual steps. Reducing +manual steps for releases is important since it is easy for a person to forget +a small but impactful step and therefore produce a bad release that causes +trouble for our users. + +Background +---------- + +`GitHub workflows `_ run +on provisioned VMs in the cloud with stable environments that we specify. They +are free to use since DFHack is an open source project. They have proven to be +reliably available within a few seconds when our workflows are triggered. The +logic for the workflows is written in yaml, and the files that control our +workflows are stored in the :file:`.github/workflows/` directory in each of our +repos. Example: :source:`.github/workflows`. + +Each workflow contains metadata that specifies: +- when it `triggers `_ +- what `base environment `_ it uses (OS, pre-installed dependencies, etc.) +- what additional dependencies should be installed (if any) +- custom business logic + +Workflows run in the context of a single repo, but workflows defined in one +repo can inherit logic from workflows in other repos. All our common CI logic +is in the main DFHack/dfhack repo, but our submodules, like our ``scripts`` and +``df-structures`` repos, have CI workflows defined that inherit from the logic +in DFHack/dfhack. That way we can fix bugs and extend functionality in one +place and have it benefit the entire org tree. + +Caches +~~~~~~ + +GitHub also provides 10GB per repository for `caches `_. +We utilize the cache system to keep state between workflow runs, cache +downloads, and keep compiler output to speed up subsequent builds. Efficient +use of the cache system is a critical part of our workflow design. It allows us +to iterate on test failures in PRs in one minute instead of 20. It allows us to +put out an entire emergency release build in 5 minutes instead of 45. We have +tuned our build and test workflows to minimize spurious cache misses and keep +the fast path fast. + +Caches are namespaced by key prefixes, and we have one key prefix per build +context. For example, release builds on gcc-11 are kept in one cache namespace, +whereas test builds on gcc-11 are kept separate. MSVC release and test builds +similarly have their own namespaces. Each cache has a maximum size that is +enforced by the business logic that writes the cache data. + +In order to maintain consistency in a distributed environment, caches are +versioned. A workflow will read the latest version of the cache with its key +prefix, maybe modify the cache with new data, then write back a new version. +Caches that are not used for 2 weeks are purged from GitHub storage, but if a +repo goes over the 10GB limit, caches are deleted in LRU order until the repo +is under the storage limit again. + +CI workflows +------------ + +Build +~~~~~ + +The Build workflow is the main CI workflow. It runs on every PR and push to a +branch. The ``build.yml`` file is essentially an orchestration layer for the +logic in several other .yml files: + +- ``test.yml`` builds DFHack with the test suite enabled (but stonesense and + windows pdb files disabled) and runs the test suite. It is optimized for + speed and is intended to give PR authors quick feedback on their changes. + The test suite is executed in a real running DF game on both Linux and + Windows. The ``test`` job populates the ``test`` cache, which is used by many + other workflows for non-distributed builds. +- ``package.yml`` builds DFHack as it would be released: test suite disabled + but stonesense and windows pdb files enabled. The ``package`` job populates the ``release`` cache, which is used to build all distributed binaries. +- The ``docs`` target does a docs-only build of DFHack and reports any errors. + Doc errors would show up in the ``test`` and ``package`` builds anyway, but + the ``docs`` target runs very fast and can identify doc errors in less than + 1m. +- ``lint.yml`` runs the verification scripts in the ``ci`` directory. These + scripts check for common errors in the codebase that are not caught by the + compiler. The lint scripts are written in Python and shell script and are + intended to be run quickly and catch common errors. + +Check type sizes +~~~~~~~~~~~~~~~~ + +``check-type-sizes.yml`` is a df-structures-only workflow that checks for +changes in the sizes of types in the xml structures. It builds the +``xml-dump-type-sizes`` binary on both Linux and Windows for both the +structures in this PR and for the structures in the target merge branch. It +then runs the built binary on its native OS and compares the output. If any +type sizes have changed, the workflow generates a PR comment (via the +``comment-pr.yml`` workflow) with details. + +.. _workflows-release-automation: + +Release automation workflows +---------------------------- + +Watch DF Releases +~~~~~~~~~~~~~~~~~ + +This workflow runs every 8 minutes and checks the Steam metadata, the Itch +website, and the Bay 12 website for evidence of new releases. If a new release +is found, it generates an announcement in a private channel on the DFHack +Discord server. + +Inside the ``watch-df-releases.yml`` workflow, there are separate jobs for +watching Steam branches and watching the websites. For the Steam watcher, it +takes configuration for: + +- which branches to watch +- whether to kick off the Generate symbols workflow when a new release is found +- whether to autodeploy to Steam when the Generate symbols workflow completes + +The workflow has protections against concurrent runs, so if you suspect a new +release is out, you can manually trigger the workflow to check. If the cron +trigger happens to run the workflow at the same time, the second run will be +paused while the first run completes. + +Generate symbols +~~~~~~~~~~~~~~~~ + +This workflow can be triggered manually or by the Watch DF Releases workflow. +It downloads the specified DF version for the selected distribution platform(s) +and OS target(s), then updates the ``symbol-table`` entries in ``symbols.xml``. +If the distribution platform is Steam, it can also autodetect the DF version by +extracting the version string from the DF title screen data. + +For Linux, it always builds DFHack -- just the core library (no plugins) -- and +generates symbols via the `devel/dump-offsets` and `devel/scan-vtables` scripts. + +For Windows, we extract symbol data via static analysis, so the workflow only +builds DFHack if it needs to autodetect the DF version. + +Once the symbols.xml file is updated, the workflow commits the changes to the +specified df-structures branch and updates the xml submodule ref in the +specified DFHack/dfhack branch. If a deploy Steam branch is specified, it also +launches the Deploy to Steam workflow. + +Deploy to GitHub +~~~~~~~~~~~~~~~~ + +`github-release.yml `_ +can be triggered manually or automatically by creating a new release version +tag in git. It builds DFHack with the release configuration, packages the +aritifacts for GitHub, creates a new GitHub release, and uploads the packages +to the GitHub release page. + +It uses text in :source:`.github/release_template.md` to generate the release +notes, and appends the changelog contents for the tagged version. + +If you need to re-tag the release to fix a mistake, it will automatically run +again and replace the binaries attached to the GitHub release for the tagged +version. It will not overwrite the release notes, though, to preserve any edits +you may have made in the GitHub UI. If you *want* it to completely regenerate +the release notes, you can delete the release before you re-tag the version. + +GitHub releases end up here: https://github.com/DFHack/dfhack/releases. + +Deploy to Steam +~~~~~~~~~~~~~~~ + +`steam-deploy.yml `_ +can be triggered manually or automatically by creating a new release version +tag in git. It builds DFHack with the release configuration, packages the +aritifacts for Steam, and uploads them to the specified Steam branch. + +The workflow caches steamcmd to speed the deployment up by 30s or so. +Otherwise, steamcmd would have to be downloaded and updated every time the +workflow runs. + +Steam releases end up here: +https://partner.steamgames.com/apps/builds/2346660. The "version" you +specified for the workflow is used as the "description" for the build. + +Maintenance workflows +--------------------- + +Update submodules +~~~~~~~~~~~~~~~~~ + +`update-submodules.yml `_ +runs daily, or can be run manually as needed. It checks DFHack submodules for +new commits on the main branches and updates the submodule refs in the DFHack +develop branch. + +You generally should not run this workflow for anything other than the develop +branch, as it will overwrite any changes you have made to the submodule refs in +other branches. + +Clean up PR caches +~~~~~~~~~~~~~~~~~~ + +This workflow runs automatically whenever a PR is closed or merged. It removes +caches created for the PR so they don't take up quota. + +Note that if you merge a PR before all the workflows have completed, the caches +may be created after this workflow runs. In that case, the caches will be +orphaned and will be purged by GitHub's cache eviction policy after 2 weeks. diff --git a/docs/dev/index.rst b/docs/dev/index.rst new file mode 100644 index 0000000000..931b9bb006 --- /dev/null +++ b/docs/dev/index.rst @@ -0,0 +1,26 @@ + + +======================== +DFHack development guide +======================== + +These are pages relevant to people developing for DFHack. + +.. toctree:: + :maxdepth: 1 + + /docs/dev/Dev-intro + /docs/dev/compile/index + /docs/dev/Contributing + /docs/dev/Documentation + /docs/api/index + /docs/dev/Lua API + /docs/dev/overlay-dev-guide + /docs/dev/Structures-intro + /docs/dev/data-identity + /docs/dev/github-workflows + /docs/dev/release-process + /docs/dev/Memory-research + /docs/dev/Binpatches + /docs/dev/Remote + /docs/NEWS-dev diff --git a/docs/dev/overlay-dev-guide.rst b/docs/dev/overlay-dev-guide.rst new file mode 100644 index 0000000000..d87178bfff --- /dev/null +++ b/docs/dev/overlay-dev-guide.rst @@ -0,0 +1,461 @@ +.. _overlay-dev-guide: + +DFHack overlay dev guide +========================= + +.. highlight:: lua + +This guide walks you through how to build overlay widgets and register them with +the `overlay` framework for injection into Dwarf Fortress viewscreens. + +Why would I want to create an overlay widget? +--------------------------------------------- + +There are both C++ and Lua APIs for creating viewscreens and drawing to the +screen. If you need very specific low-level control, those APIs might be the +right choice for you. However, here are some reasons you might want to implement +an overlay widget instead: + +#. You can draw directly to an existing viewscreen instead of creating an + entirely new screen on the viewscreen stack. This allows the original + viewscreen to continue processing uninterrupted and keybindings bound to + that viewscreen will continue to function. This was previously only + achievable by C++ plugins. +#. You'll get a free UI for enabling/disabling your widget and repositioning it + on the screen. Widget state is saved for you and is automatically restored + when the game is restarted. +#. You don't have to manage the C++ interposing logic yourself and can focus on + the business logic, writing purely in Lua if desired. + +In general, if you are writing a plugin or script and have anything you'd like +to add to an existing screen (including live updates of map tiles while the game +is unpaused), an overlay widget is probably your easiest path to get it done. If +your plugin or script doesn't otherwise need to be enabled to function, using +the overlay allows you to avoid writing any of the enable or lifecycle +management code that would normally be required for you to show info in the UI. + +Overlay widget API +------------------ + +Overlay widgets are Lua classes that inherit from ``overlay.OverlayWidget`` +(which itself inherits from `widgets.Panel `). The regular +``onInput(keys)``, ``onRenderFrame(dc, frame_rect)``, and ``onRenderBody(dc)`` +functions work as normal, and they are called when the viewscreen that the +widget is associated with does its usual input and render processing. The widget +gets first dibs on input processing. If a widget returns ``true`` from its +``onInput()`` function, the viewscreen will not receive the input. + +Overlay widgets can contain other Widgets and be as simple or complex as you +need them to be, just like you're building a regular UI element. + +There are a few extra capabilities that overlay widgets have that take them +beyond your everyday `widgets.Widget `: + +- If an ``overlay_onupdate(viewscreen)`` function is defined, it will be called + just after the associated viewscreen's ``logic()`` function is called (i.e. + a "tick" or a (non-graphical) "frame"). For hotspot widgets, this function + will also get called after the top viewscreen's ``logic()`` function is + called, regardless of whether the widget is associated with that viewscreen. + If this function returns ``true``, then the widget's ``overlay_trigger()`` + function is immediately called. Note that the ``viewscreen`` parameter will + be ``nil`` for hotspot widgets that are not also associated with the current + viewscreen. +- If an ``overlay_trigger()`` function is defined, will be called when the + widget's ``overlay_onupdate`` callback returns true or when the player uses + the CLI (or a keybinding calling the CLI) to trigger the widget. The + function must return either ``nil`` or the ``gui.Screen`` object that the + widget code has allocated, shown, and now owns. Hotspot widgets will receive + no callbacks from unassociated viewscreens until the returned screen is + dismissed. Unbound hotspot widgets **must** allocate a Screen with this + function if they want to react to the ``onInput()`` feed or be rendered. The + widgets owned by the overlay framework must not be attached to that new + screen, but the returned screen can instantiate and configure any new views + that it wants to. See the `hotkeys` DFHack logo widget for an example. + + The ``overlay_trigger()`` function enables the activation of overlay widgets + via the command line interface (CLI) or keybindings. + For example, executing ``overlay trigger notes.map_notes add Kitchen``:: + + function MyOverlayWidget:overlay_trigger(arg1, arg2) + if arg1 == 'add' then + -- Add a new note to the map + self:addSomething(arg2) + elseif arg1 == 'delete' then + self:deleteSomething(arg2) + end + end + + This allows for dynamic updates to UI overlays directly from the CLI. +- If an ``overlay_onenable()`` function is defined, it is called when the + overlay is enabled (including when the persisted state is reloaded at DF + startup). +- If an ``overlay_ondisable()`` function is defined, it is called when the + overlay is disabled. + +If the widget can take up a variable amount of space on the screen, and you want +the widget to adjust its position according to the size of its contents, you can +modify ``self.frame.w`` and ``self.frame.h`` at any time -- in ``init()`` or in +any of the callbacks -- to indicate a new size. The overlay framework will +detect the size change and adjust the widget position and layout. + +If you don't need to dynamically resize, just set ``self.frame.w`` and +``self.frame.h`` once in ``init()`` (or just leave them at the defaults). If +you don't need to render a widget on the screen at all, set your frame width +and/or height to 0. Your ``render`` function will still be called, but no +repositioning frame will be shown for the overlay in `gui/overlay`. + +Widget attributes +***************** + +The ``overlay.OverlayWidget`` superclass defines the following class attributes: + +- ``name`` + This will be filled in with the display name of your widget, in case you + have multiple widgets with the same implementation but different + configurations. You should not set this property yourself. +- ``version`` + You can set this to any string. If the version string of a loaded widget + does not match the saved settings for that widget, then the configuration + for the widget (position, enabled status) will be reset to defaults. +- ``desc`` + A short (<100 character) description of what the overlay does. This text + will be displayed in `gui/control-panel` on the "Overlays" tab. +- ``default_pos`` (default: ``{x=-2, y=-2}``) + Override this attribute with your desired default widget position. See + the `overlay` docs for information on what positive and negative numbers + mean for the position. Players can change the widget position at any time + via the `overlay position ` command, so don't assume that your + widget will always be at the default position. +- ``default_enabled`` (default: ``false``) + Override this attribute if the overlay should be enabled by default if it + does not already have a state stored in ``dfhack-config/overlay.json``. +- ``viewscreens`` (default: ``{}``) + The list of viewscreens that this widget should be associated with. When + one of these viewscreens is on top of the viewscreen stack, your widget's + callback functions for update, input, and render will be interposed into the + viewscreen's call path. The name of the viewscreen is the name of the DFHack + class that represents the viewscreen, minus the ``viewscreen_`` prefix and + ``st`` suffix. For example, the fort mode main map viewscreen would be + ``dwarfmode`` and the adventure mode map viewscreen would be + ``dungeonmode``. If there is only one viewscreen that this widget is + associated with, it can be specified as a string instead of a list of + strings with a single element. If you only want your widget to appear in + certain contexts, you can specify a focus path, in the same syntax as the + `keybinding` command. For example, ``dwarfmode/Info/CREATURES/CITIZEN`` will + ensure the overlay widget is only displayed when the "Citizens" subtab under + the "Units" panel is active. +- ``hotspot`` (default: ``false``) + If set to ``true``, your widget's ``overlay_onupdate`` function will be + called whenever the `overlay` plugin's ``plugin_onupdate()`` function is + called (which corresponds to one call per call to the current top + viewscreen's ``logic()`` function). This call to ``overlay_onupdate`` is in + addition to any calls initiated from associated interposed viewscreens and + will come after calls from associated viewscreens. +- ``fullscreen`` (default: ``false``) + If set to ``true``, no widget frame will be drawn in `gui/overlay` for drag + and drop repositioning. Overlay widgets that need their frame positioned + relative to the screen and not just the scaled interface area should set + this to ``true``. +- ``full_interface`` (default: ``false``) + If set to ``true``, no widget frame will be drawn in `gui/overlay` for drag + and drop repositioning. Overlay widgets that need access to the whole + scaled interface area should set this to ``true``. +- ``overlay_onupdate_max_freq_seconds`` (default: ``5``) + This throttles how often a widget's ``overlay_onupdate`` function can be + called (from any source). Set this to the largest amount of time (in + seconds) that your widget can take to react to changes in information and + not annoy the player. Set to 0 to be called at the maximum rate. Be aware + that running more often than you really need to will impact game FPS, + especially if your widget can run while the game is unpaused. If you change + the value of this attribute dynamically, it may not be noticed until the + previous timeout expires. However, if you need a burst of high-frequency + updates, set it to ``0`` and it will be noticed immediately. + +Common widget attributes such as ``active`` and ``visible`` are also respected. +Note that those properties are checked *after* matching ``viewscreens`` focus +string(s), so you can assume they are evaluated in an consistent context. For +example, if your widget has ``viewscreens='dwarfmode/Trade/Default'``, then you +can assume your ``visible=function() ... end`` function will be executing while +the trade screen is active. + +Registering a widget with the overlay framework +*********************************************** + +Anywhere in your code after the widget classes are declared, define a table +named ``OVERLAY_WIDGETS``. The keys are the display names for your widgets and +the values are the widget classes. For example, the `dwarfmonitor` widgets are +declared like this:: + + OVERLAY_WIDGETS = { + cursor=CursorWidget, + date=DateWidget, + misery=MiseryWidget, + weather=WeatherWidget, + } + +When the `overlay` plugin is enabled, it scans all plugins and scripts for +this table and registers the widgets on your behalf. Plugin lua code is loaded +with ``require()`` and script lua code is loaded with ``reqscript()``. +If your widget is in a script, ensure your script can be +`loaded as a module `, or else the widget will not be discoverable. +Whether the widget is enabled and the widget's position is restored according +to the state saved in the :file:`dfhack-config/overlay.json` file. + +The overlay framework will instantiate widgets from the named classes and own +the resulting objects. The instantiated widgets must not be added as subviews to +any other View, including the Screen views that can be returned from the +``overlay_trigger()`` function. + +Performance considerations +************************** + +Overlays that do any processing or rendering during unpaused gameplay (that is, +nearly all of them) must be developed with performance in mind. DFHack has an +overall service level objective of no more than 10% performance impact during +unpaused gameplay with all overlays and background tools enabled. A single +overlay should seek to take up no more than a fraction of 1% of elapsed +gameplay time. + +Please see the Core `performance-monitoring` section for details on how to get +a perf report while testing your overlay. The metric that you will be +interested in is the percentage of elapsed time that your overlay accounts for. + +If you need to improve performance, here are some potential options: + +1. Shard scanning over multiple passes. For example, instead of checking every + item on the map in every update in your overlay, only check every Nth item + and change the start offset every time you scan. + +2. Reduce the frequency of state updates by moving calcuations to + ``overlay_onupdate`` and setting the value of the + ``overlay_onupdate_max_freq_seconds`` attribute appropriately + +3. Move hotspots into C++ code, either in a new core library function or in a + dedicated plugin + +Overlay framework API +--------------------- + +The overlay plugin Lua interface provides a few functions for interacting with +the framework. You can get a reference to the API via:: + + local overlay = require('plugins.overlay') + +* ``overlay.rescan()`` + + Rescans all module-loadable Lua scripts for registered overlays and loads + updated widget definitions. + +* ``overlay.isOverlayEnabled(name)`` + + Returns whether the overlay with the given name is enabled. + +Development workflows +--------------------- + +When you are developing an overlay widget, you will likely need to reload your +widget many times as you make changes. The process for this differs slightly +depending on whether your widget is attached to a plugin or is implemented in a +script. + +Note that reloading a script does not clear its global environment. This is fine +if you are changing existing functions or adding new ones. If you remove a +global function or other variable from the source, though, it will stick around +in your script's global environment until you restart DF or run +`devel/clear-script-env`. + +Scripts +******* + +#. Edit the widget source +#. If the script is not in your `script-paths`, install your script (see the + `modding-guide` for help setting up a dev environment so that you don't need + to reinstall your scripts after every edit). +#. Call ``:lua require('plugins.overlay').rescan()`` to reload your overlay + widget + +Plugins +******* + +#. Edit the widget source +#. Install the plugin so that the updated code is available in + :file:`hack/lua/plugins/` +#. If you have changed the compiled plugin, `reload` it +#. If you have changed the lua code, run ``:lua reload('plugins.mypluginname')`` +#. Call ``:lua require('plugins.overlay').rescan()`` to reload your overlay + widget + +Troubleshooting +--------------- + +You can check that your widget is getting discovered by the overlay framework +by running ``overlay list`` or by launching `gui/control-panel` and checking +the ``Overlays`` tab. + +**If your widget is not listed, double check that:** + +#. ``OVERLAY_WIDGETS`` is declared, is global (not ``local``), and references + your widget class +#. (if a script) your script is `declared as a module ` + (``--@ module = true``) and it does not have side effects when loaded as a + module (i.e. you check ``dfhack_flags.module`` and return before executing + any statements if the value is ``true``) +#. your code does not have syntax errors -- run + ``:lua ~reqscript('myscriptname')`` (if a script) or + ``:lua ~require('plugins.mypluginname')`` (if a plugin) and make sure there + are no errors and the global environment contains what you expect. + +**If your widget is not running when you expect it to be running,** run +`gui/overlay` when on the target screen and check to see if your widget is +listed when showing overlays for the current screen. If it's not there, verify +that this screen is included in the ``viewscreens`` list in the widget class +attributes. Also, load `gui/control-panel` and make sure your widget is enabled. + +Widget example 1: adding text to a DF screen +-------------------------------------------- + +This is a simple widget that displays a message at its position. The message +text is retrieved from the host script or plugin every ~20 seconds or when +the :kbd:`Alt`:kbd:`Z` hotkey is hit:: + + local overlay = require('plugins.overlay') + local widgets = require('gui.widgets') + + MessageWidget = defclass(MessageWidget, overlay.OverlayWidget) + MessageWidget.ATTRS{ + desc='Sample widget that displays a message on the screen.', + default_pos={x=5,y=-2}, + default_enabled=true, + viewscreens={'dwarfmode', 'dungeonmode'}, + overlay_onupdate_max_freq_seconds=20, + } + + function MessageWidget:init() + self:addviews{ + widgets.Label{ + view_id='label', + text='', + }, + } + end + + function MessageWidget:overlay_onupdate() + local text = getImportantMessage() -- defined in the host script/plugin + self.subviews.label:setText(text) + self.frame.w = #text + end + + function MessageWidget:onInput(keys) + if keys.CUSTOM_ALT_Z then + self:overlay_onupdate() + return true + end + return MessageWidget.super.onInput(self, keys) + end + + OVERLAY_WIDGETS = {message=MessageWidget} + +Widget example 2: highlighting artifacts on the live game map +------------------------------------------------------------- + +This widget is not rendered at its "position" at all, but instead monitors the +map and overlays information about where artifacts are located. Scanning for +which artifacts are visible on the map can slow, so that is only done every 10 +seconds to avoid slowing down the entire game on every frame. + +:: + + local overlay = require('plugins.overlay') + local widgets = require('gui.widgets') + + ArtifactRadarWidget = defclass(ArtifactRadarWidget, overlay.OverlayWidget) + ArtifactRadarWidget.ATTRS{ + desc='Sample widget that highlights artifacts on the game map.', + default_enabled=true, + viewscreens={'dwarfmode', 'dungeonmode'}, + frame={w=0, h=0}, + overlay_onupdate_max_freq_seconds=10, + } + + function ArtifactRadarWidget:overlay_onupdate() + self.visible_artifacts_coords = getVisibleArtifactCoords() + end + + function ArtifactRadarWidget:onRenderFrame() + for _,pos in ipairs(self.visible_artifacts_coords) do + -- highlight tile at given coordinates + end + end + + OVERLAY_WIDGETS = {radar=ArtifactRadarWidget} + +Widget example 3: corner hotspot +-------------------------------- + +This hotspot reacts to mouseover events and launches a screen that can react to +input events. The hotspot area is a 2x2 block near the lower right corner of the +screen (by default, but the player can move it wherever). + +:: + + local overlay = require('plugins.overlay') + local widgets = require('gui.widgets') + + HotspotMenuWidget = defclass(HotspotMenuWidget, overlay.OverlayWidget) + HotspotMenuWidget.ATTRS{ + desc='Sample widget that reacts to mouse hover.', + default_pos={x=-3,y=-3}, + default_enabled=true, + frame={w=2, h=2}, + hotspot=true, + viewscreens='dwarfmode', + overlay_onupdate_max_freq_seconds=0, -- check for mouseover every tick + } + + function HotspotMenuWidget:init() + -- note this label only gets rendered on the associated viewscreen + -- (dwarfmode), but the hotspot is active on all screens + self:addviews{widgets.Label{text={'!!', NEWLINE, '!!'}}} + self.mouseover = false + end + + function HotspotMenuWidget:overlay_onupdate() + local hasMouse = self:getMousePos() + if hasMouse and not self.mouseover then -- only trigger on mouse entry + self.mouseover = true + return true + end + self.mouseover = hasMouse + end + + function HotspotMenuWidget:overlay_trigger() + return MenuScreen{hotspot_frame=self.frame}:show() + end + + OVERLAY_WIDGETS = {menu=HotspotMenuWidget} + + MenuScreen = defclass(MenuScreen, gui.ZScreen) + MenuScreen.ATTRS{ + focus_path='hotspot/menu', + hotspot_frame=DEFAULT_NIL, + } + + function MenuScreen:init() + self.mouseover = false + + -- derive the menu frame from the hotspot frame so it + -- can appear in a nearby location + local frame = copyall(self.hotspot_frame) + -- ... + + self:addviews{ + widgets.Window{ + frame=frame, + autoarrange_subviews=true, + subviews={ + -- ... + }, + }, + }, + } + end diff --git a/docs/dev/release-process.rst b/docs/dev/release-process.rst new file mode 100644 index 0000000000..bef09be412 --- /dev/null +++ b/docs/dev/release-process.rst @@ -0,0 +1,209 @@ +Release process +=============== + +This page details the process we follow for beta and stable releases. + +For documentation on the related GitHub workflows, see +`workflows-release-automation`. + +Beta release +------------ + +This process pushes a pre-release build to GitHub and Steam. It is intended to +be lower-toil than the stable release process and allows us to facilitate +frequent public testing and feedback without compromising the stability of our +"stable" releases. + +1. Run the `Update submodules `_ GitHub action on the ``develop`` branch to ensure that all submodules are up to date. + +2. Update version strings in :source:`CMakeLists.txt` as appropriate. Set ``DFHACK_RELEASE`` to the *next* stable release version with an "rc#" suffix. For example, if the last stable release was "r1" then set the string to "r2rc1". If we do a second beta release before the final stable "r2" then the string would be "r2rc2". + + - Ensure the ``DFHACK_PRERELEASE`` flag is set to ``TRUE``. + - Commit and push to ``develop`` + - Set ``RELEASE`` in your environment for the commands below (e.g. ``RELEASE=51.07-r2rc1`` for bash) + +3. Tag ``develop`` (no need to tag the submodules) and push: ``git tag -a $RELEASE -m "Bump to $RELEASE"; git push --tags origin`` + + - This will automatically trigger `Deploy to Steam `_ and `Deploy to GitHub `_ build workflows. + +4. Write release notes highlights and any requests for feedback in the `draft GitHub release `_ and publish the draft. + +5. Associate release notes with the build on Steam + + - Go to the `announcement creation page `_ + - Select "A game update" + - Select "Small update / Patch notes" + - Set the "Event title" to the release version (e.g. "DFHack 51.07-r2rc1") + - Set the "Subtitle" to "DFHack pre-release (beta channel)" + - Mention release highlights in the "Summary" field + - Transcode release notes from the GitHub release into the "Event description" field + - patch notes must be in BBcode; see `converting-markdown-to-bbcode` below for how to convert our release notes to BBcode + - Click "Link to build" and select the staging branch (be sure the build has been deployed to the branch first. By the time you're done with the patch notes the build will likely be ready for you) + - Go to the Artwork tab, select "Previously uploaded images", and search for and double-click on dfhack_logo.png. Click "Upload" (even though it has already been uploaded). + - Switch to the "Publish" tab and publish! + - `Promote `_ the build to the "beta" branch (and the "testing" branch if it's newer than what is on the "testing" branch) + +6. Monitor for beta channel subscriber feedback on the Steam `community page `_ + +7. *Maybe* also post to Reddit and other announcement channels if we feel like we need to recruit more beta testers into the pool, but we should avoid posting so often that it is annoying for those who don't use Steam or just want announcements for stable releases. + +Stable release +-------------- + +This process creates a stable DFHack release meant for widespread distribution. +Stable releases come in two forms: straight from ``develop`` or from a point +release branch. + +During "normal" times, we will test out new features in beta releases until we +reach a point of stability. Then, after the ``develop`` branch is feature frozen +while we polish and fix bugs, we tag a release directly from ``develop`` +``HEAD``. + +However, if we have already started committing beta features to ``develop`` and +it becomes necessary to put out a bugfix release for a problem in an +already-released stable release, then we will create a new branch from the +stable tag, cherry-pick fixes from ``develop`` onto that branch, and spin a +release from there. After the point release is published, we'll merge the +branch back into ``develop`` and remove the release branch to clean up. + +1. Triage remaining issues/PRs in the `release project `_ + + - Don't feel pressure to merge anything risky just before a stable release. That's what beta releases are for. + +2. In your local clone of the ``DFHack/develop`` branch, make sure your checkout and all submodules (listed in :source:`.gitmodules`) are up to date with their latest public commits and have no uncommitted/unpushed local changes. + +3. Ensure that CI has not failed unexpectedly on the latest online changes: + + - https://github.com/DFHack/dfhack/commits/develop + - https://github.com/DFHack/scripts/commits/master + - https://github.com/DFHack/df-structures/commits/master + +4. Update version strings in :source:`CMakeLists.txt` as appropriate + + - Ensure the ``DFHACK_PRERELEASE`` flag is set to ``FALSE``. + - Set ``RELEASE`` in your environment for the commands below (e.g. ``RELEASE=51.07-r1``) + +5. Replace "Future" with the version number and clean up changelog entries; add new "Future" section (with headers pre-populated from the template at the top of the file): + + - ``docs/changelog.txt`` + - ``scripts/changelog.txt`` + - ``library/xml/changelog.txt`` + - ``plugins/stonesense/docs/changelog.txt`` + +6. Do a top-level build to ensure the docs build cleanly + +7. Commit/push changes to submodules and tag (``git tag -a $RELEASE -m "Bump to $RELEASE"; git push --tags origin master``) + + - ``scripts`` + - ``library/xml`` + - ``plugins/stonesense`` + +8. Commit and push changes to ``develop`` + + - Ensure that any updates you pushed to submodules are tracked in the commit to ``DFHack/develop`` + +9. Tag ``dfhack``: ``git tag -a $RELEASE -m "Bump to $RELEASE"; git push --tags origin develop`` + + - This will automatically trigger a `Deploy to Steam `_ GitHub action to the "staging" Steam branch and a `Deploy to GitHub `_ GitHub action to create a draft `release `_ from a template and attach the built artifacts. + +10. Switch to the Steam ``staging`` release channel in the Steam client (password: ``stagingstagingstaging``) and download/test the update. + + - Ensure DFHack starts DF when run from the Steam client + - Ensure the DFHack version string is accurate on the title page (should just be the release number, e.g. ``DFHack 51.07-r1``, with no git hash or warnings) + - Run `devel/check-release` + - If something goes wrong with this step, fix it, delete the tag (both from `GitHub `_ and locally (``git tag -d $RELEASE``)), re-tag, re-push, and re-test. Note that you do *not* need to remove the GitHub draft release -- the existing one will just get updated with the new tag and binaries. You *can* remove the draft release, though, if you want the release notes to get regenerated. + +11. Prep release on GitHub + + - Go to the draft `release `_ on GitHub + - Add announcements, highlights (with demo videos), etc. to the description + +12. Push develop to master (``git push origin develop:master``) + + - This will start the documentation build process and update the published "stable" docs + - Note that if this is a -r1 release, you won't be able to complete this step until a classic build is available on the Bay 12 website so the DFHack Test workflow can pass, which is a prerequisite for being able to push to ``master``. + +13. Post release notes on Steam + + - Go to the `announcement creation page `_ + - Select "A game update" + - Select "Regular update" + - Set the "Event title" to the release version (e.g. "DFHack 51.07-r1") + - Set the "Subtitle" to "DFHack stable release" + - Add list of highlights (and maybe announcements, if significant) to the "Summary" field + - Upload screenshots and demo videos via the button at the bottom of the "Previously uploaded videos" area + - Add release notes to the "Event description" field (must be in BBcode; see `converting-markdown-to-bbcode` below for how to convert our release notes to BBcode) + - Drag uploaded images/videos into their appropriate places in the announcement text (replace the GitHub URL tags, which won't work from Steam) + - If the generated release notes exceed the announcement length limits, add a link to the GitHub release page at the bottom of the announcement instead + - Click "Link to build" and select the staging branch (be sure the build has been deployed to the branch first. by the time you're done with the patch notes the build will likely be ready for you) + - the release notes will travel with the build when we promote it to other branches + - Go to the Artwork tab, select "Previously uploaded images", and search for and double-click on STABLEannouncement6.png. Click "Upload" (even though it has already been uploaded). + - Switch to the "Publish" tab and publish! + +14. Go to the `Steam builds page `_ and promote the build to the "default" branch + + - For the build that you just pushed to "staging", click the "-- Select an app branch --" drop-down and select "default" + - Click on "Preview Change" + - Commit the change (you may need to verify with 2FA) + - If the release is newer than what's on the ``beta`` and/or ``testing`` branches, set it live on those branches as well + +15. Publish the prepped GitHub release + +16. Send out release announcements + + - Announce new version in r/dwarffortress. Example: https://www.reddit.com/r/dwarffortress/comments/1i3l5xl/dfhack_5015r2_released_highlights_stonesense/ + - Create the post in the Reddit web interface; the mobile app is extremely painful to use for posting + - Do an "Images & Video" post, sample title: "DFHack 51.07-r1 released! Hilights: Open legends mode directly from an active fort, Dig through warm or damp tiles without interruption, Unlink buildings from levers" + - Add the animated gifs to the post (with appropriate captions naming the relevant tool and what is being demonstrated) + - Add the "DFHack Official" flair to the post. If you're not a r/dwarffortress mod, ask Myk to do this after posting. + - After posting, add each section of the release notes as its own comment, splitting out individual announcements and highlights. This gives people the opportunity to respond directly to the portion of the release notes that interests them; it also helps us avoid size limits for comments. You can include a single still shot (.png file) per comment, but you have to switch to "Fancy Pants Editor" to do it. You can only switch editors once, or the image will get messed up (that is, the image will turn into a hyperlink to an image). Suggested procedure is to prepare the comment in markdown, switch to Fancy Pants Editor, and add images just before submitting the comment. + - Announce new version in forum thread. Example: http://www.bay12forums.com/smf/index.php?topic=164123.msg8567134#msg8567134 + - Update latest version text and link in `first post `_ (if you are not Lethosor, ping Lethosor for this) + - Announce in `#announcements `_ on DFHack Discord + - Announce in `#mod-releases `_ on Kitfox Discord + - Change the name of the release thread on Kitfox Discord to match the release version (if you are not Myk, ping Myk for this) + +17. Monitor all announcement channels for feedback and respond to questions/complaints + +18. Create a `project `_ on GitHub in the DFHack org for the next release + + - Open the `project template `_ + - Click "Use this template" + - Name the project according to the version, e.g. "51.07-r2" and click "Use template" + - In the new project, select settings and set the visibility to Public + - Move any remaining To Do or In Progress items from last release project to next release project + - Close project for last release + +19. If this is a -r2 release or later, go to https://readthedocs.org/projects/dfhack/versions/ and "Edit" previous DFHack releases for the same DF version and mark them "Hidden" (keep the "Active" flag set) so they no longer appear on the docs version selector. + +.. _converting-markdown-to-bbcode: + +Converting Markdown to BBcode +----------------------------- + +Hopefully we can `automate `_ this in the future, but for now, here is the procedure: + +1. Get the markdown that you want to convert into some field on GitHub (can be a temporary text field that you then preview without saving) + +2. View the rendered release notes in your browser (these instructions are for Chrome, but other browsers probably have similar capabilities) + +3. Right click on the rendered text and inspect the DOM + +4. Copy the HTML element that contains the release notes + +5. Click on the "Import HTML" button on the Steam announcement form; paste in the HTML and click "Overwrite" + +6. Copy the generated BBCode out from the description field and into a text editor + +7. Fix it up: + + - Remove the "How do I download DFHack?" section -- people on Steam don't need it + - Some ``

`` elements aren't converted properly and need to be rewritten with square brackets + - Any monospaced text gets HTML tags instead of BBCode ``[code]`` tags, but you can't use them either since they force newlines. ``[tt]`` isn't supported. Any ```` tags just need to be removed entirely. + - Any ``
`` and ```` tags need to be removed + +8. Copy it all back into the description field for the announcement + +9. Click on "Preview event" to double check that it renders sanely + +10. You're done. diff --git a/docs/gen_changelog.py b/docs/gen_changelog.py new file mode 100644 index 0000000000..3b4452f625 --- /dev/null +++ b/docs/gen_changelog.py @@ -0,0 +1,5 @@ +import os, sys +sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'sphinx_extensions')) + +from dfhack.changelog import cli_entrypoint +cli_entrypoint() diff --git a/docs/guides/index.rst b/docs/guides/index.rst new file mode 100644 index 0000000000..f47f9565ce --- /dev/null +++ b/docs/guides/index.rst @@ -0,0 +1,13 @@ +=========== +User guides +=========== + +These pages are detailed guides covering DFHack tools. + +.. toctree:: + :maxdepth: 1 + + /docs/guides/modding-guide + /docs/guides/quickfort-library-guide + /docs/guides/quickfort-user-guide + /docs/guides/stonesense-art-guide diff --git a/docs/guides/modding-guide.rst b/docs/guides/modding-guide.rst new file mode 100644 index 0000000000..e93051d41a --- /dev/null +++ b/docs/guides/modding-guide.rst @@ -0,0 +1,743 @@ +.. _modding-guide: + +DFHack modding guide +==================== + +.. highlight:: lua + +What is the difference between a script and a mod? +-------------------------------------------------- + +Well, sometimes there is no difference. A mod is anything you add to the game, +which can be graphics overrides, content in the raws, DFHack scripts, or all of +the above. There are already resources out there for +`raws modding `__, so this +guide will focus more on scripts, both standalone and as an extension to +raws-based mods. + +A DFHack script is a Lua file that can be run as a command in +DFHack. Scripts can do pretty much anything, from displaying information to +enforcing new game mechanics. If you don't already know Lua, there's a great +primer at `lua.org `__. + +Why not just mod the raws? +-------------------------- + +It depends on what you want to do. Some mods *are* better to do in just the +raws. You don't need DFHack to add a new race or modify attributes. However, +DFHack scripts can do many things that you just can't do in the raws, like make +a creature that trails smoke or launch a unit into the air when they are hit +with a certain type of projectile. Some things *could* be done in the raws, but +a script is better (e.g. easier to maintain, easier to extend, and/or not prone +to side-effects). A great example is adding a syndrome when a reaction +is performed. If done in the raws, you have to create an exploding boulder as +an intermediary to apply the syndrome. DFHack scripts can add the syndrome +directly and with much more flexibility. In the end, complex mods will likely +require a mix of raw modding and DFHack scripting. + +The structure of a mod +---------------------- + +In the example below, we'll use a mod name of ``example-mod``. I'm sure your +mods will have more creative names! Mods have a basic structure that looks like +this:: + + info.txt + graphics/... + objects/... + blueprints/... + scripts_modactive/example-mod.lua + scripts_modactive/internal/example-mod/... + scripts_modinstalled/... + README.md (optional) + +Let's go through that line by line. + +- The :file:`info.txt` file contains metadata about your mod that DF will + display in-game. You can read more about this file in the + `Official DF Modding Guide `__. + It would be a good idea to give your mod a ``dfhack`` tag so players can + indentify it as requiring DFHack when they subscribe to it on the DF Steam + workshop. +- Modifications to the game raws (potentially with + `custom raw tokens `) go in the :file:`graphics/` and + :file:`objects/` folders. You can read more about the files that go in + these directories on the :wiki:`Modding` wiki page. +- Any `quickfort` blueprints included with your mod go in the + :file:`blueprints` folder. Note that your mod can *just* be blueprints and + the :file:`info.txt` file if you like. See the next section for an example. +- A control script in :file:`scripts_modactive/` directory that handles + system-level event hooks (e.g. reloading state when a world is loaded), + registering `overlays `, and + `enabling/disabling ` your mod. You can put other + scripts in this directory as well if you want them to appear as runnable + DFHack commands when your mod is active for the current world. Lua modules + that your main scripts use, but which don't need to be directly runnable by + the player, should go in a subdirectory under + :file:`scripts_modactive/internal/` so they don't show up in the DFHack + `launcher ` command autocomplete lists. +- Scripts that you want to be available before a world is loaded (i.e. on the + DF title screen) or that you want to be runnable in any world, regardless + of whether your mod is active, should go in the + :file:`scripts_modinstalled/` folder. You can also have an :file:`internal/` + subfolder in here for private modules if you like. +- Finally, a :file:`README.md` file that has more information about your mod. + If you develop your mod using version control (recommended!), that + :file:`README.md` file can also serve as your git repository documentation. + +These files end up in a subdirectory under :file:`mods/` when players copy them +in or install them from the +`Steam Workshop `__, and in +:file:`data/installed_mods/` when the mod is selected as "active" for the first +time. + +DFHack will discover scripts in your mod's ``scripts_modinstalled/`` directory +and other DFHack-relevant data files (like blueprints) regardless of whether +the mod has been marked "active" for any player world. + +What if I just want to distribute quickfort blueprints? +------------------------------------------------------- + +For this, all you need is :file:`info.txt` and your blueprints. + +.. highlight:: none + +Your :file:`info.txt` could look something like this:: + + [ID:drooble_blueprints] + [NUMERIC_VERSION:1] + [DISPLAYED_VERSION:1.0.0] + [EARLIEST_COMPATIBLE_NUMERIC_VERSION:1] + [EARLIEST_COMPATIBLE_DISPLAYED_VERSION:1.0.0] + [AUTHOR:Drooble] + [NAME:Drooble's blueprints] + [DESCRIPTION:Useful quickfort blueprints for any occasion.] + [STEAM_TITLE:Drooble's blueprints] + [STEAM_DESCRIPTION:Useful quickfort blueprints for any occasion.] + [STEAM_TAG:dfhack] + [STEAM_TAG:quickfort] + [STEAM_TAG:blueprints] + +and your blueprints, which could be .csv or .xlsx files, would go in the +``blueprints/`` subdirectory. If you add blueprint file named +``blueprints/bedrooms.csv``, then it will be shown to players as +``drooble_blueprints/bedrooms.csv`` in `quickfort` and `gui/quickfort`. The +"drooble_blueprints" prefix comes from the mod ID specified in ``info.txt``. + +What if I just want to distribute a simple standalone script? +------------------------------------------------------------- + +If your mod is just a script with no raws modifications, all you need is:: + + info.txt + scripts_modinstalled/yourscript.lua + README.md (optional) + +Adding your script to the :file:`scripts_modinstalled/` folder will allow +DFHack to find it and add your mod to the `script-paths`. Your script will be +runnable from the title screen and in any loaded world, regardless of whether +your mod is explicitly "active". + +A mod-maker's development environment +------------------------------------- + +Create a folder for development somewhere outside your Dwarf Fortress +installation directory (e.g. ``/path/to/mymods/``). If you work on multiple +mods, you might want to make a subdirectory for each mod. + +If you have changes to the raws, you'll still have to copy them into DF's +``data/installed_mods/`` folder to have them take effect, but you can set +things up so that scripts are run directly from your dev directory. You can +edit your scripts in your dev directory and have the changes available in the +game immediately: no copying, no restarting. + +How does this magic work? Just add a line like this to your +``dfhack-config/script-paths.txt`` file:: + + +/path/to/mymods/example-mod/scripts_modinstalled + +Then that directory will be searched when you run DFHack commands from inside +the game. The ``+`` at the front of the path means to search that directory +first, before any other script directory (like :file:`hack/scripts` or other +versions of your mod in the DF mod folders). + +The structure of the game +------------------------- + +"The game", that is, all the Dwarf Fortress state, is in the global variable +`df `. Most of the information relevant to a script is found in +``df.global.world``, which contains data like the lists of active items and +units, whether to reindex pathfinding, et cetera. Also relevant to us are the +various data types found in the game, e.g. ``df.pronoun_type`` which we will be +using in this guide. We'll explore more of the game structures below. + +Your first script +----------------- + +So! It's time to write your first script. This section will walk you through how +to make a script that will get the pronoun type of the currently selected unit. +If you're not familiar with Lua script syntax, maybe skim through some topics +in the `manual `__ first. + +.. highlight:: lua + +First line, we get a reference to an in-game unit:: + + local unit = dfhack.gui.getSelectedUnit() + +If no unit is selected by the player in the DF UI, ``unit`` will be ``nil`` and +an error message will be printed. + +If ``unit`` is ``nil``, we don't want the script to run anymore:: + + if not unit then + return + end + +Now, the field ``unit.sex`` is an integer, but each integer corresponds to a +string value ("it", "she", or "he"). We get this value by indexing the +bidirectional map ``df.pronoun_type``. Indexing the other way, with one of the +strings, will yield its corresponding number. So:: + + local pronounTypeString = df.pronoun_type[unit.sex] + print(pronounTypeString) + +Simple. The entire script altogether looks like this:: + + local unit = dfhack.gui.getSelectedUnit() + if not unit then + return + end + local pronounTypeString = df.pronoun_type[unit.sex] + print(pronounTypeString) + +Save the text as a ``.lua`` file in your own scripts directory and run it from +`gui/launcher` when a unit is selected in the Dwarf Fortress UI. + +DFHack provides a vast library of functionality that make it easier to interact +with the game state. When you start asking yourself "How do I get/do X", search +through the `lua-api` for relevant functions and look through existing scripts +for examples. + +Exploring DF state +------------------ + +So how could you have known about the field and type we just used? Well, there +are two main tools for discovering the various fields in the game's data +structures. The first is the ``df-structures`` +`repository `__ that contains XML files +describing the layouts of the game's structures. These are complete, but +difficult to read (for a human). The second option is the `gui/gm-editor` +interface, an interactive data explorer. You can run the script while objects +like units are selected to view the data within them. Press :kbd:`?` while the +script is active to view help. + +Familiarising yourself with the many structs of the game will help with ideas +immensely, and you can always ask for help in the `right places `. + +Reading and writing files and other persistent state +---------------------------------------------------- + +There are several locations and APIs that a mod might need to read or store +data: + +Global state that is not world-specific should be stored in the directory +returned by the ``scriptmanager.getModStatePath()`` function. JSON is a +convenient format for this kind of stored state, and DFHack provides facilities +for reading and writing JSON data. For example:: + + local json = require('json') + local scriptmanager = require('script-manager') + local path = scriptmanager.getModStatePath('mymodname') + config = config or json.open(path .. 'settings.json') + + -- modify state in the config.data table and persist it when it changes with + -- config:write() + +State that should be saved with a world or a specific fort within that world +should use `persistent-api` API. You can attach a state change hook for new +world loaded where you can load the state, which often includes whether the mod +itself is enabled (if the mod can be dynamically enabled/disabled -- see the +`script-enable-api` for more details). For example:: + + --@ enable=true + --@ module=true + + local utils = require('utils') + + local GLOBAL_KEY = 'mymodname' + + local function get_default_state() + return { + enabled=false, + somevar=0, + somesubtable={ + someothervar=0, + }, + } + end + state = state or get_default_state() + + -- implement the enabled API so DFHack can read this script's status + function isEnabled() + return state.enabled + end + + local function persist_state() + dfhack.persistent.saveSiteData(GLOBAL_KEY, state) + end + + local function do_enable() + -- initialization tasks, such as hooking events + end + + local function do_disable() + -- cleanup tasks, such as removing event hooks + end + + dfhack.onStateChange[GLOBAL_KEY] = function(sc) + if sc == SC_MAP_UNLOADED then + do_disable() + + -- ensure our mod doesn't run when a different + -- world is loaded where we are *not* active + dfhack.onStateChange[GLOBAL_KEY] = nil + + return + end + + if sc ~= SC_MAP_LOADED or not dfhack.world.isFortressMode() then + return + end + + -- retrieve state saved in game. merge with default state so config + -- saved from previous versions can pick up newer defaults. + state = get_default_state() + utils.assign(state, dfhack.persistent.getSiteData(GLOBAL_KEY, state)) + if state.enabled then + do_enable() + end + end + +Finally, you may have distributed data files with your mod that you need to +read at runtime. Your mod directory should be treated as read-only since data +there is not backed up. Use the `script-manager` API to get the path to your +mod data and the ``json`` (or any other file I/O) API as needed. For example:: + + local scriptmanager = require('script-manager') + + local GLOBAL_KEY = 'mymodname' + + local function read_bulk_data_db() + local mod_source_path = scriptmanager.getModSourcePath(GLOBAL_KEY) + -- read data from files in the mod directory + return ... + end + + bulk_data_db = bulk_data_db or read_bulk_data_db() + +If you want to store state in the savegame so that it is associated with the +current world/fort/adventure, use the `persistent-api` API. or in the fuller example later in this +guide. + +Reacting to events +------------------ + +The common method for injecting new behaviour into the game is to define a +callback function and get it called when something interesting happens. DFHack +provides two libraries for this, ``repeat-util`` and `eventful `. +``repeat-util`` is used to run a function once per a configurable number of +frames (paused or unpaused), ticks (unpaused), in-game days, months, or years. +If you need to be aware the instant something happens, you'll need to run a +check once a tick. Be careful not to do this gratuitously, though, since +running callbacks too often can significantly slow down the game! + +``eventful``, on the other hand, is much more performance-friendly since it will +only call your callback when a relevant event happens, like a reaction +occuring, a job being completed, or a projectile moving to a new tile. + +To get something to run once every 1000 ticks, we can call +``repeat-util.scheduleEvery()``. First, we load the module:: + + local repeatUtil = require('repeat-util') + +Both ``repeat-util`` and ``eventful`` require keys for registered callbacks. You +should use something unique, like your mod id:: + + local GLOBAL_KEY = 'mymodname' + +Then, we pass the key, amount of time units between function calls, what the +time units are, and finally the callback function itself:: + + repeatUtil.scheduleEvery(GLOBAL_KEY, 1000, 'ticks', function() + -- Do something like iterating over all active units and + -- check for something interesting + for _, unit in ipairs(df.global.world.units.active) do + ... + end + end) + +``eventful`` is slightly more involved. First get the module:: + + local eventful = require('plugins.eventful') + +``eventful`` contains a table for each event which you populate with functions. +Each function in the table is then called with the appropriate arguments when +the event occurs. So, for example, to print the position of a moving (item) +projectile:: + + eventful.onProjItemCheckMovement[GLOBAL_KEY] = function(projectile) + print(projectile.cur_pos.x, projectile.cur_pos.y, + projectile.cur_pos.z) + end + +Check out the `full list of supported events ` to see what else +you can react to with ``eventful``. + +Now, you may have noticed that you won't be able to register multiple callbacks +with a single key named after your mod. You can, of course, call all the +functions you want from a single registered callback. Alternately, you can +create multiple callbacks using different keys, using your mod ID as a key name +prefix. If you do register multiple callbacks, though, there are no guarantees +about the call order. + +Custom raw tokens +----------------- + +.. highlight:: none + +In this section, we are going to use `custom raw tokens ` +applied to a reaction to transfer the material of a reagent to a product as a +handle improvement (like on artifact buckets). As a second example, we are +going to make boots that make units go faster when worn. + +First, let's define raws for a custom crossbow with its own custom reaction. The +crossbow:: + + [ITEM_WEAPON:ITEM_WEAPON_CROSSBOW_SIEGE] + [NAME:crossbow:crossbows] + [SIZE:600] + [SKILL:HAMMER] + [RANGED:CROSSBOW:BOLT] + [SHOOT_FORCE:4000] + [SHOOT_MAXVEL:800] + [TWO_HANDED:0] + [MINIMUM_SIZE:17500] + [MATERIAL_SIZE:4] + [ATTACK:BLUNT:10000:4000:bash:bashes:NO_SUB:1250] + [ATTACK_PREPARE_AND_RECOVER:3:3] + [SIEGE_CROSSBOW_MOD_FIRE_RATE_MULTIPLIER:2] custom token (you'll see) + +The reaction to make it (you would add the reaction and not the weapon to an +entity raw):: + + [REACTION:MAKE_SIEGE_CROSSBOW] + [NAME:make siege crossbow] + [BUILDING:BOWYER:NONE] + [SKILL:BOWYER] + [REAGENT:mechanism 1:2:TRAPPARTS:NONE:NONE:NONE] + [REAGENT:bar:150:BAR:NONE:NONE:NONE] + [METAL_ITEM_MATERIAL] + [REAGENT:handle 1:1:BLOCKS:NONE:NONE:NONE] wooden handles + [ANY_PLANT_MATERIAL] + [REAGENT:handle 2:1:BLOCKS:NONE:NONE:NONE] + [ANY_PLANT_MATERIAL] + [SIEGE_CROSSBOW_MOD_TRANSFER_HANDLE_MATERIAL_TO_PRODUCT_IMPROVEMENT:1] + another custom token + [PRODUCT:100:1:WEAPON:ITEM_WEAPON_CROSSBOW_SIEGE:GET_MATERIAL_FROM_REAGENT:bar:NONE] + +So, we are going to use the ``eventful`` module to react when this crossbow is +crafted, allowing us to inject the logic that will add the handle improvement. + +.. highlight:: lua + +First, require the modules we are going to use:: + + local eventful = require('plugins.eventful') + local customRawTokens = require('custom-raw-tokens') + +and attach a callback to the event:: + + local GLOBAL_KEY = 'mymodname' + + local function reaction_handler(reaction, reactionProduct, unit, + inputItems, inputReagents, outputItems) + -- we'll be defining the body of this function below + end + + eventful.onReactionComplete[GLOBAL_KEY] = reaction_handler + +Now let's look at the ``reaction_handler`` function and give it some logic. +First, we check to see if it the reaction that just happened is relevant to this +callback:: + + if not customRawTokens.getToken(reaction, + 'SIEGE_CROSSBOW_MOD_TRANSFER_HANDLE_MATERIAL_TO_PRODUCT_IMPROVEMENT') + then + return + end + +Then, we check the reagents for names that start with "handle". For those +reagents, we get the corresponding item and add a handle improvement:: + + for i, reagent in ipairs(inputReagents) do + if reagent.code:startswith('handle') then + -- Found handle reagent + local item = inputItems[i] + local improv = df.itemimprovement_itemspecificst:new() + improv.mat_type, improv.mat_index = item.mat_type, item.mat_index + improv.type = df.itemimprovement_specific_type.HANDLE + outputItems[1].improvements:insert('#', improv) + end + end + +Let's also modify the fire rate of our siege crossbow according to the custom +token we added to the item definition in the raws:: + + eventful.onProjItemCheckMovement[GLOBAL_KEY] = function(projectile) + if projectile.distance_flown > 0 then + -- don't make this adjustment more than once + return + end + + local firer = projectile.firer + if not firer then + return + end + + local weapon = df.item.find(projectile.bow_id) + if not weapon then + return + end + + local multiplier = tonumber(customRawTokens.getToken( + weapon.subtype, + 'SIEGE_CROSSBOW_MOD_FIRE_RATE_MULTIPLIER')) or 1 + firer.counters.think_counter = math.floor( + firer.counters.think_counter * multiplier) + end + +.. highlight:: none + +Now, let's see how we could make some "pegasus boots". First, let's define the +item in the raws:: + + [ITEM_SHOES:ITEM_SHOES_BOOTS_PEGASUS] + [NAME:pegasus boot:pegasus boots] + [ARMORLEVEL:1] + [UPSTEP:1] + [METAL_ARMOR_LEVELS] + [LAYER:OVER] + [COVERAGE:100] + [LAYER_SIZE:25] + [LAYER_PERMIT:15] + [MATERIAL_SIZE:2] + [METAL] + [LEATHER] + [HARD] + [PEGASUS_BOOTS_MOD_FOOT_MOVEMENT_TIMER_REDUCTION_PER_TICK:2] custom raw token + (you don't have to comment the custom token every time, + but it does clarify what it is) + +.. highlight:: lua + +Then, let's define a function that will implement the logic associated with the +boots:: + + local function do_pegasus() + for _,unit in ipairs(df.global.world.units.active) do + local amount = 0 + for _,inv_entry in ipairs(unit.inventory) do + if inv_entry.mode == df.unit_inventory_item.T_mode.Worn then + local reduction = customRawTokens.getToken( + inv_entry.item, + 'PEGASUS_BOOTS_MOD_FOOT_MOVEMENT_TIMER_REDUCTION_PER_TICK') + amount = amount + (tonumber(reduction) or 0) + end + end + -- Subtract amount from on-foot movement timers if not on ground + if not unit.flags1.on_ground then + dfhack.units.subtractActionTimers(unit, amount, + df.unit_action_type_group.MovementFeet) + end + end + end + +Finally, we can schedule the callback to be run once a tick using the +``repeat-util`` module:: + + repeatUtil.scheduleEvery(GLOBAL_KEY, 1, 'ticks', do_pegasus) + +Note that the ``do_pegasus`` function as written here is **extremely +inefficient**. In a real mod, you would likely want to cache which units are +equipping pegasus boots so you don't have to scan every inventory item of every +active unit on every tick. + +Putting it all together +----------------------- + +Ok, you're all set up! Now, let's take a look at an example +``scripts_modinstalled/example-mod.lua`` file:: + + -- main file for the example-mod mod + + -- these lines indicate that the script supports the "enable" + -- API so you can start it by running "enable example-mod" and + -- stop it by running "disable example-mod" + --@ module=true + --@ enable=true + + -- this is the help text that will appear in `help` and + -- `gui/launcher`. see possible tags here: + -- https://docs.dfhack.org/en/stable/docs/Tags.html + --[====[ + example-mod + =========== + + Tags: fort | gameplay + + Short one-sentence description. + + Longer description ... + + Usage + ----- + + enable example-mod + disable example-mod + ]====] + + local eventful = require('plugins.eventful') + local repeatUtil = require('repeat-util') + local utils = require('utils') + + -- you can reference global values or functions declared in any of + -- your internal modules + local moduleA = reqscript('internal/example-mod/module-a') + local moduleB = reqscript('internal/example-mod/module-b') + + local GLOBAL_KEY = 'example-mod' + + local function get_default_state() + return { + enabled=false, + somevar=0, + somesubtable={ + someothervar=0, + }, + } + end + state = state or get_default_state() + + -- implement the enabled API so DFHack can read this script's status + function isEnabled() + return state.enabled + end + + -- call this whenever the contents of the state table changes + local function persist_state() + dfhack.persistent.saveSiteData(GLOBAL_KEY, state) + end + + local function do_enable() + -- do any initialization your internal scripts might require + moduleA.onEnable() + moduleB.onEnable() + + repeatUtil.scheduleEvery(GLOBAL_KEY, 1000, 'ticks', function() + moduleA.cycle() + moduleB.cycle() + end) + + eventful.onProjItemCheckMovement[GLOBAL_KEY] = + moduleB.onProjItemCheckMovement + eventful.onProjUnitCheckImpact[GLOBAL_KEY] = + moduleB.onProjUnitCheckImpact + end + + local function do_disable() + -- call any shutdown functions your internal scripts might require + moduleA.onDisable() + moduleB.onDisable() + + repeatUtil.cancel(GLOBAL_KEY) + + eventful.onProjItemCheckMovement[GLOBAL_KEY] = nil + eventful.onProjUnitCheckImpact[GLOBAL_KEY] = nil + end + + dfhack.onStateChange[GLOBAL_KEY] = function(sc) + if sc == SC_MAP_UNLOADED then + do_disable() + + -- ensure our mod doesn't run when a different + -- world is loaded where we are *not* active + dfhack.onStateChange[GLOBAL_KEY] = nil + + return + end + + if sc ~= SC_MAP_LOADED or not dfhack.world.isFortressMode() then + return + end + + -- retrieve state saved in game. merge with default state so config + -- saved from previous versions can pick up newer defaults. + state = get_default_state() + utils.assign(state, dfhack.persistent.getSiteData(GLOBAL_KEY, state)) + if state.enabled then + do_enable() + end + end + + if dfhack_flags.module then + return + end + + if not dfhack_flags.enable then + print(dfhack.script_help()) + print() + print(('Example mod is currently '):format( + enabled and 'enabled' or 'disabled')) + return + end + + if dfhack_flags.enable_state then + state.enabled = true + do_enable() + else + state.enabled = false + do_disable() + end + + persist_state() + +The ``scripts_modinstalled/internal/example-mod/module-a.lua`` file could look +something like this:: + + --@ module=true + + -- global (non-local) variables and functions are exported + function onEnable() + -- ... + end + + function onDisable() + -- ... + end + + -- this is a local function: local functions/variables + -- are not accessible to other scripts. + local function usedByCycle(unit) + -- ... + end + + function cycle() -- exported + for _,unit in ipairs(df.global.world.units.active) do + usedByCycle(unit) + end + end + +The `reqscript ` function reloads scripts that have changed, so you +can modify your scripts while DF is running and just disable/enable your mod to +load the changes into your running game! diff --git a/docs/guides/quickfort-library-guide.rst b/docs/guides/quickfort-library-guide.rst new file mode 100644 index 0000000000..e363fe0987 --- /dev/null +++ b/docs/guides/quickfort-library-guide.rst @@ -0,0 +1,232 @@ +.. _blueprint-library-guide: +.. _quickfort-library-guide: + +Quickfort blueprint library +=========================== + +This guide contains a high-level overview of the blueprints available in the +:source:`quickfort blueprint library `. + +Each file is hyperlinked to its online version so you can see exactly what the +blueprints do before you run them. Also, if you use `gui/quickfort`, you will +get a live preview of which tiles will be modified by the blueprint before you +apply it to your map. + +Whole fort blueprint sets +------------------------- + +These files contain the plans for entire fortresses. Each file has one or more +help sections that walk you through how to build the fort, step by step. + +- :source:`library/dreamfort.csv ` + +.. _dreamfort: + +Dreamfort +~~~~~~~~~ + +Dreamfort is a fully functional, self-sustaining fortress with defenses, +farming, a complete set of workshops, self-managing quantum stockpiles, a grand +dining hall, hospital (werecreature-ready), library, temple, jail, fresh water +well system, guildhalls, noble suites, and bedrooms for hundreds of dwarves. It +also comes with manager work orders to automate basic fort needs, such as food, +booze, and item production. It can function by itself or as the core of a +larger, more ambitious fortress. Read the walkthrough by running +`gui/quickfort`, searching for ``dreamfort help``, and selecting the blueprints. + +Dreamfort blueprints are available for easy viewing and copying `online +`__. + +The online spreadsheets also include `embark profile suggestions +`__, +a complete `example embark profile +`__, +and a convenient `checklist +`__ +that you can use to track your progress. + +If you'd like a visual demonstration, there is a `series of videos on YouTube `__ +that walk you through the entire process of building a Dreamfort-based +fortress. You can also download a fully built Dreamfort-based fort from +:dffd:`dffd <15434>`, load it, and explore it interactively. + +Here are annotated screenshots of the major Dreamfort levels (or click `here +`__ +for a slideshow). + +Surface level +````````````` + +.. image:: https://lh3.googleusercontent.com/d/1dlu3nmwQszav-ZaTx-ac28wrcaYBQc_t + :alt: Annotated screenshot of the dreamfort surface level + :target: https://drive.google.com/file/d/1dlu3nmwQszav-ZaTx-ac28wrcaYBQc_t + :align: center + +Farming level +````````````` + +.. image:: https://lh3.googleusercontent.com/d/1vDaedLcgoexUdKREUz75ZXQi0ZSdwWwj + :alt: Annotated screenshot of the dreamfort farming level + :target: https://drive.google.com/file/d/1vDaedLcgoexUdKREUz75ZXQi0ZSdwWwj + :align: center + +Industry level +`````````````` + +.. image:: https://lh3.googleusercontent.com/d/1c8YTHxTgJY5tUII-BOWdLhmDFAHwIOEs + :alt: Annotated screenshot of the dreamfort industry level + :target: https://drive.google.com/file/d/1c8YTHxTgJY5tUII-BOWdLhmDFAHwIOEs + :align: center + +Services levels (4 deep) +```````````````````````` + +.. image:: https://lh3.googleusercontent.com/d/1RQMy_zYQWM5GN7-zjn6LoLWmnrJjkxPM + :alt: Annotated screenshot of the dreamfort services level + :target: https://drive.google.com/file/d/1RQMy_zYQWM5GN7-zjn6LoLWmnrJjkxPM + :align: center + +**Example plumbing to fill cisterns** + +If you are routing water to fill the cisterns, you can do it like this: + +.. image:: https://lh3.googleusercontent.com/d/1paXqPJ-7h9_jG_eNXU1z5GGvR0J8C0uJ + :alt: Annotated screenshot of an example plumbing for the dreamfort cisterns + :target: https://drive.google.com/file/d/1paXqPJ-7h9_jG_eNXU1z5GGvR0J8C0uJ + :align: center + +Cistern drain (keep open while you're digging out the aquifer tap): + +.. image:: https://lh3.googleusercontent.com/d/1SwSluJcN_kOrCYPdcFOfJ13wEDvZGcJe + :alt: Annotated screenshot of an example drainage for the dreamfort cisterns + :target: https://drive.google.com/file/d/1SwSluJcN_kOrCYPdcFOfJ13wEDvZGcJe + :align: center + +Guildhall level +``````````````` + +.. image:: https://lh3.googleusercontent.com/d/1mt66QOkfBqFLtw6AJKU6GNYmhB72XSJG + :alt: Annotated screenshot of the dreamfort guildhall level + :target: https://drive.google.com/file/d/1mt66QOkfBqFLtw6AJKU6GNYmhB72XSJG + :align: center + +Noble suites +```````````` + +.. image:: https://lh3.googleusercontent.com/d/16XRb1w5zFoyVq2LBMx_aCwOyjFq7GULc + :alt: Annotated screenshot of the dreamfort noble suites + :target: https://drive.google.com/file/d/16XRb1w5zFoyVq2LBMx_aCwOyjFq7GULc + :align: center + +Apartments +`````````` + +.. image:: https://lh3.googleusercontent.com/d/16-NXlodLIQjeZUMSmsWRafeytwU2dXQo + :alt: Annotated screenshot of the dreamfort apartments + :target: https://drive.google.com/file/d/16-NXlodLIQjeZUMSmsWRafeytwU2dXQo + :align: center + +Crypt +````` + +.. image:: https://lh3.googleusercontent.com/d/16iT_ho7BIRPD_eofuxdlVQ4FunR1Li23 + :alt: Annotated screenshot of the dreamfort crypt + :target: https://drive.google.com/file/d/16iT_ho7BIRPD_eofuxdlVQ4FunR1Li23 + :align: center + +Layout helpers +-------------- + +These files simply draw diagonal marker-mode lines starting from the cursor. +They are especially useful for finding the center of the map when you are +planning your fortress. Once you are done using them for alignment, use +``quickfort undo`` at the same cursor position to make them disappear. Since +these ``#dig`` blueprints can only mark undug wall tiles for mining, they are +best used underground. They won't do much on the surface, where there aren't +many walls. + +- :source:`library/layout-helpers/mark_up_left.csv ` +- :source:`library/layout-helpers/mark_up_right.csv ` +- :source:`library/layout-helpers/mark_down_right.csv ` +- :source:`library/layout-helpers/mark_down_left.csv ` + +Bedrooms +-------- + +These are popular bedroom layouts from the :wiki:`Bedroom design` page on the +wiki. Each file has blueprints to dig the rooms, zone them as bedrooms, and +build the furniture. + +- :source:`library/bedrooms/48-4-Raynard_Whirlpool_Housing.csv ` +- :source:`library/bedrooms/95-9-Hactar1_3_Branch_Tree.csv ` +- :source:`library/bedrooms/28-3-Modified_Windmill_Villas.csv ` + +Tombs +----- + +These blueprints have burial plot layouts for fortress that expect a lot of +casualties. + +- :source:`library/tombs/Mini_Saracen.csv ` +- :source:`library/tombs/The_Saracen_Crypts.csv ` + +Exploratory mining +------------------ + +Several mining patterns to choose from when searching for gems or ores. The +patterns can be repeated up or down z-levels (via `gui/quickfort`\'s +:kbd:`r`\epeat functionality) for exploring through the depths. + +- :source:`library/exploratory-mining/tunnels.csv ` +- :source:`library/exploratory-mining/vertical-mineshafts.csv ` +- :source:`library/exploratory-mining/connected-mineshafts.csv ` + +Miscellaneous +------------- + +Extra blueprints that are useful in specific situations. + +- :source:`library/aquifer_tap.csv ` +- :source:`library/embark.csv ` +- :source:`library/pump_stack.csv ` + +Light aquifer tap +~~~~~~~~~~~~~~~~~ + +The aquifer tap helps you create a safe, everlasting source of fresh water from +a light aquifer. See the step-by-step guide, including information on how to +create a drainage system so your dwarves don't drown when digging the tap, by +running the ``library/aquifer_tap.csv`` ``/help`` blueprint. Alternately, view +the demo video below. + +You can see how to nullify the water pressure (so you don't flood your fort) in +the Dreamfort cistern screenshot above: `Services levels (4 deep)`_. + +.. raw:: html + + + +The blueprint spreadsheet is also available +`online `__. + +Post-embark +~~~~~~~~~~~ + +The embark blueprints are useful directly after embark. It contains a ``#build`` +blueprint that builds important starting workshops (mason, carpenter, mechanic, +and craftsdwarf) and a ``#place`` blueprint that lays down a pattern of useful +starting stockpiles. + +Pump stack +~~~~~~~~~~ + +The pump stack blueprints help you move water and magma up to more convenient +locations in your fort. See the step-by-step guide for using it by running the +``library/pump_stack.csv`` ``/help`` blueprint or by viewing the demo video: + +.. raw:: html + + + +The blueprint spreadsheet is also available +`online `__. diff --git a/docs/guides/quickfort-user-guide.rst b/docs/guides/quickfort-user-guide.rst new file mode 100644 index 0000000000..dae03c3aba --- /dev/null +++ b/docs/guides/quickfort-user-guide.rst @@ -0,0 +1,2391 @@ +.. _quickfort-blueprint-guide: +.. _quickfort-user-guide: +.. _quickfort-alias-guide: + +Quickfort blueprint creation guide +================================== + +`Quickfort ` is a DFHack tool that helps you build fortresses from +"blueprint" .csv and .xlsx files. Many applications exist to edit these files, +such as MS Excel and `Google Sheets `__. Most layout and +building-oriented DF actions are supported through the use of multiple files or +spreadsheets, each describing a different phase of DF construction: designating +digging, defining zones, placing stockpiles, and building. + +The original idea came from :wiki:`Valdemar's ` auto-designation +macro. Joel Thornton reimplemented the core logic in Python and extended its +functionality with `Quickfort 2.0 `__. This +DFHack-native implementation, called "DFHack Quickfort" or just "quickfort", +builds upon Quickfort 2.0's formats and features, preserving compatibility with +existing blueprints (where possible -- DF itself has changed since then). In +contrast with the earlier quickfort implementations, which interacted with DF +by simulating keyboard input, DFHack Quickfort calls lower-level API functions +to designate tiles and configure buildings. This allows for nearly +instantaneous blueprint application, error checking and recovery, and many other +advanced features. + +This guide focuses on DFHack Quickfort's capabilities and blueprint syntax, and +teaches players how to understand and create blueprint files. Some of the text +was originally written by Joel Thornton, reused here with his permission. + +If you are just looking to apply existing blueprints to your fort, check out +`gui/quickfort` (or `quickfort` for the commandline version). There are many +ready-to-use blueprints available in the `quickfort-library-guide` distributed +with DFHack. + +Before you become an expert at writing blueprints, though, you should know that +the easiest way to make a quickfort blueprint is to build your plan "for real" +in Dwarf Fortress and then export that section of your map using +`gui/blueprint`. You can apply those blueprints as-is in your next fort, or you +can fine-tune them with additional features from this guide. + +See the `Links`_ section for more information and online resources. + +.. contents:: Table of Contents + :local: + :depth: 2 + +Feature summary +--------------- + +- General + + - Blueprint modes for all phases of fort design + - Read blueprints from .csv or multi-worksheet .xlsx files + - Near-instant application, even for very large and complex blueprints + - Blueprints can span multiple z-levels + - Easy sharing of blueprints with multi-blueprint files + - Scripted application of sequences of blueprints + - Undo applied blueprints + - Rotate blueprints or flip them around + - Automatic cropping of blueprints that extend off the map + - Generate manager orders for items required by a blueprint + - Includes a library of ready-to-use blueprints + - Blueprint debugging + +- Dig mode + + - Supports all types of designations, including dumping/forbidding items and + setting traffic settings + - Supports setting dig priorities + - Supports applying dig blueprints in marker mode + - Handles carving arbitrarily complex minecart tracks, including tracks that + cross other tracks + +- Zone and place modes + + - Define zones and stockpiles of any shape, not just rectangles + - Configurable numbers of bins, barrels and wheelbarrows assigned to created + stockpiles + - Automatic splitting of stockpiles that exceed maximum dimension limits + - Create and attach locations to zones + - Full control over stockpile configuration based on the `stockpiles` + settings library + - Configurable zone/location settings, such as the pit/pond toggle or + hospital supply quantities + +- Build mode + + - Integrated with DFHack `buildingplan`: you can place buildings before + manufacturing building materials and you can use the `buildingplan` UI + for setting materials and quality preferences + - Designate entire constructions in mid-air without having to wait for each + tile to become supported + - Automatic expansion of building footprints to their minimum dimensions, so + only the center tile of a multi-tile building needs to be recorded in the + blueprint + - Tile occupancy and validity checking so, for example, buildings that + cannot be placed on a target tile will be skipped instead of causing + errors and interrupting the blueprint. Blueprints that are only partially + applied for any reason (e.g. you need to dig out some more tiles) can be + safely reapplied to build the remaining buildings. + - Relaxed rules for farm plot and road placement: you can still place the + building even if an invalid tile (e.g. stone tiles for farm plots) splits + the designated area into two disconnected parts + - Intelligent boundary detection for adjacent buildings of the same type + (e.g. a 6x6 block of ``wj`` cells will be correctly split into 4 jeweler's + workshops) + - Set building properties (such as a name) + - Can attach and configure track stops as part of hauling routes + +- Burrow mode + + - Supports creating, adding to, and subtracting from burrows. + +Introduction to blueprints +-------------------------- + +We recommend using a spreadsheet editor such as Excel, `Google +Sheets `__, or `LibreOffice `__ +to edit blueprint files, but any text editor will do. + +The format of Quickfort-compatible blueprint files is straightforward. The first +line (or upper-left cell) of the spreadsheet should look like this:: + + #dig + +The keyword ``dig`` tells Quickfort we are going to be specifying designations. +The following "mode" keywords are understood: + +============== =========== +Blueprint mode Description +============== =========== +dig Designations (digging, traffic, dumping, etc.) +build Constructions, buildings, and furniture +place Stockpiles +zone Activity zones +============== =========== + +If no modeline appears in the first cell, Quickfort assumes that it's looking at +a ``#dig`` blueprint. + +There are also other modes that don't directly correspond to Dwarf Fortress +design operations, but we'll talk about those `later `. + +If you like, you may enter a comment after the mode keyword. This comment will +appear in the output of ``quickfort list`` or in the dialog window when running +`gui/quickfort`. You can use this space for explanations, attribution, etc.:: + + #dig grand dining room + +Below this line, begin entering keys in each spreadsheet cell that represent +what you want designated in the corresponding game map tile. For example, we +could dig out a 4x4 room like so (spaces are used as column separators here for +readability, but a real .csv file would have commas):: + + #dig + d d d d # + d d d d # + d d d d # + d d d d # + # # # # # + +The letter ``d`` here stands for "dig". The character sequences in these +blueprints are based on the old (pre-v50) keyboard shortcuts for the various DF +menus. Please see the `quickfort_guide_appendix` below for a full reference. + +Note the :kbd:`#` symbols at the right end of each row and below the last row. +These are completely optional, but can be helpful to make the row and column +positions clear. + +In general, any cell that contains text that starts with a :kbd:`#` is +interpreted as a comment and is ignored by `quickfort`. You can use this to +leave notes for yourself inside of a blueprint. Take care to start your comment +with a space after the ``#`` to avoid accidentally starting a modeline if your +comment happens to be in the first column and happens to start with a modeline +keyword. For example, ``#dig this area out`` is an accidental modeline that +will cause problems. However, ``# dig this area out`` is a safe comment. + +Once the dwarves have that dug out, let's zone it as a bedroom:: + + #zone + b b b b # + b b b b # + b b b b # + b b b b # + # # # # # + +This looks very similar to the ``#dig`` blueprint above, but with ``b``\s +instead of ``d``\s. The ``b``\s mark the area for a ``b``\edroom zone just like +the ``#dig`` blueprint marked the area for digging. It's important to wait +until after the area is completely dug out before applying further blueprints +since zones can't be applied to hidden tiles and furniture can't be built in +undug walls. + +Now, let's add some walls and furniture:: + + #build + Cw Cw Cw Cw # + Cw b h Cw # + Cw Cw # + Cw Cw Cw # + # # # # # + +The :kbd:`C`:kbd:`w` cells represent the constructed walls, leaving space for a +door that we might want to add later. Quickfort uses `buildingplan` for +managing buildings, so the walls will be built out of whatever matches the +current buildingplan filter set for walls. Also note my generosity -- in +addition to the bed (:kbd:`b`) I've built a container (:kbd:`h`) for this lucky +dwarf. + +Finally, let's place a booze stockpile in the 2 unoccupied tiles in the room:: + + #place personal booze stockpile + ` ` ` ` # + ` ~ ~ ` # + ` f f{name="bedroom booze"}:=booze + ` ` ` # + # # # # # + +This illustration may be a little hard to understand. The two :kbd:`f` +characters are in row 3, columns 2 and 3. All the other cells are empty. QF +considers both :kbd:`\`` (backtick -- the character under the tilde) and +:kbd:`~` (tilde) characters within cells to be empty cells; this can help with +multilayer or fortress-wide blueprint layouts as "chalk lines". + +QF is smart enough to recognize this as a 2x1 food stockpile, and creates it as +such rather than as two 1x1 food stockpiles. Quickfort treats any connected +region of identical designations as a single entity. The tiles can be connected +orthogonally or diagonally, just as long as they are touching. You can also +treat disconnected segments as belonging to the same stockpile, but we'll get +into `Label syntax`_ later. + +Now what's all that business attached to the second ``f``? The part between the +curly brackets specifies properties, in this case the name that we want to give +the stockpile. The remaining part, from the colon (``:``) onward, applies the +``booze`` preset from the `stockpiles` library. That will configure the +stockpile to accept only booze. You can use presets (along with other options +that we'll go over later) to configure stockpiles however you want, directly +from the ``#place`` blueprint. + +And that's it! You now have a series of blueprints that you can "stamp" across +your fort to quickly build new bedrooms. + +Area expansion syntax +~~~~~~~~~~~~~~~~~~~~~ + +In Quickfort, the following blueprints are equivalent:: + + #dig a 3x3 area + d d d # + d d d # + d d d # + # # # # + + #dig the same area with d(3x3) specified in row 1, col 1 + d(3x3)# + ` ` ` # + ` ` ` # + # # # # + +The second example uses Quickfort's "area expansion syntax", which takes the +form:: + + text(WxH) + +Note that area expansion syntax can only specify rectangular areas. If you want +to create extent-based structures (e.g. farm plots or stockpiles) in different +shapes, use the first format above. For example:: + + #place A single L shaped food stockpile + f f ` ` # + f f ` ` # + f f f f # + f f f f # + # # # # # + +Area expansion syntax also sets boundaries, which can be useful if you want +adjacent, but separate, stockpiles of the same type:: + + #place Two touching but separate food stockpiles + f(2x2) # + ~ ~ ` ` # + f(4x2) # + ~ ~ ~ ~ # + # # # # # + +As mentioned previously, :kbd:`~` characters are ignored as comment characters +and can be used for visualizing the blueprint layout. This blueprint can be +equivalently written as:: + + #place Two touching but separate food stockpiles + f(2x2) # + ~ ~ ` ` # + f f f f # + f f f f # + # # # # # + +since the area expansion syntax of the upper stockpile prevents it from +combining with the lower, freeform syntax stockpile. + +Area expansion syntax can also be used for buildings which have an adjustable +size, like bridges. The following blueprints are equivalent:: + + #build a 4x2 bridge from row 1, col 1 + ga(4x2) ` # + ` ` ` ` # + # # # # # + + #build a 4x2 bridge from row 1, col 1 + ga ga ga ga # + ga ga ga ga # + # # # # # + +If it is convenient to do so, you can place the cell with the expansion syntax +in any corner of the resulting rectangle. Just use negative numbers to indicate +which direction the designation should expand in. For example, the previous +blueprint could also be written as:: + + #build a 4x2 bridge from row 2, col 4 + ` ` ` ` # + ga(4x-2) ` # + # # # # # + +Property syntax +~~~~~~~~~~~~~~~ + +Many things you can designate with `quickfort` are configurable. All buildings, +stockpiles, and zones, for example, can be named. These configuration elements +are expressed as properties. + +Properties are written between curly brackets (``{}``). There can be multiple +properties defined between those brackets, separated by spaces. Each property +has a name and a value, with an equal sign to connect them. If a property value +has a space within it, it should be surrounded by double quotes (``"``). + +If you have defined the area of something over multiple spreadsheet cells, you +can specify properties in just one of those cells and they will apply to the +whole object. You can even split properties up among multiple cells if that is +more convenient. If you are using expansion syntax, the expansion part always +goes last. + +Here's an example of a seed stockpile that is configured to take from a seed +feeder stockpile:: + + #place + f{name=Seeds links_only=true}:=seeds(3x2) + + f + f{name="Seeds feeder" give_to=Seeds}:=seeds + f{containers=0} + +Different modes and different types may have different properties that you can +configure. See the `quickfort_guide_appendix` for a full list. + +Label syntax +~~~~~~~~~~~~ + +Labels are different from the ``name`` property. They are only used internally +by Quickfort to associate tiles with a particular zones or stockpiles. This is +useful for when you want to define two touching zones or stockpiles of the same +type(s), but you can't use expansion syntax because they are non-rectangular. +It is also useful for marking two *disconnected* regions as belonging to the +same zone or stockpile. Note that every tile in the zone or stockpile must be +marked with the same label:: + + #place two touching stockpiles of the same type + f/feed f/feed f/feed{name="Seeds feeder" containers=0}:=seeds + f/feed f f/feed + f f f{name=Seeds links_only=true take_from="Seeds feeder"}:=seeds + + #zone one pasture in two disconnected regions + n/slots n/slots n/slots + + n/slots{name="Pasture slots"}(3x1) + +Automatic area expansion +~~~~~~~~~~~~~~~~~~~~~~~~ + +Buildings larger than 1x1, like workshops, can be represented in any of three +ways. You can designate just their center tile with empty cells around it to +leave room for the footprint, like this:: + + #build a stonecutter workshop in row 2, col 2 that will occupy the 3x3 area + ` ` ` # + ` wm ` # + ` ` ` # + # # # # + +Or you can fill out the entire footprint like this:: + + #build a stonecutter workshop + wm wm wm # + wm wm wm # + wm wm wm # + # # # # + +This format may be verbose for regular workshops, but it can be very helpful for +laying out structures like screw pump towers and waterwheels, whose "center +point" can be non-obvious. + +Or you can use area expansion syntax:: + + #build a stonecutter workshop + wm(3x3) # + ` ` ` # + ` ` ` # + # # # # + +This style can be convenient for laying out multiple buildings of the same type. +If you are building a large-scale block factory, for example, this will create +20 stonecutter workshops all in a row:: + + #build line of 20 stonecutter workshops + wm(60x3) + +Quickfort will intelligently break large areas of the same designation into +appropriately-sized chunks. + +Multilevel blueprints +~~~~~~~~~~~~~~~~~~~~~ + +Multilevel blueprints are accommodated by separating Z-levels of the blueprint +with ``#>`` (go down one z-level) or ``#<`` (go up one z-level) at the end of +each floor. + +:: + + #dig Stairs leading down to a small room below + j ` ` # + ` ` ` # + ` ` ` # + #> # # # + u d d # + d d d # + d d d # + # # # # + +The marker must appear in the first column of the row to be recognized, just +like a modeline. + +You can go up or down multiple levels by adding a number after the ``<`` or +``>``. For example:: + + #dig Two double-level quarries + r(10x10) + #>2 + r(10x10) + +#dig mode +--------- + +``#dig`` blueprints are normally the first step in any design. They define the +boundaries and layouts for the blueprints for later stages of construction. +Despite their name, ``#dig`` blueprints are for more than just digging. They +also handle smoothing, carving, traffic designations, and marking items on the +ground for dumping, forbidding, or other similar tags. See the full list of +supported designations in the `#dig mode reference`_. + +.. _quickfort-dig-priorities: + +Dig priorities +~~~~~~~~~~~~~~ + +DF designation priorities are supported in ``#dig`` blueprints. The full syntax +is ``[markers][symbol][number][expansion]``, where if the ``symbol`` is not +specified, ``d`` is assumed, and if ``number`` is not specified, ``4`` is +assumed (the default priority). So all of these blueprints are equivalent:: + + #dig dig the interior of the room at high priority + d d d d d # + d d1 d1 d1 d # + d d1 d1 d1 d # + d d1 d1 d1 d # + d d d d d # + # # # # # # + + #dig dig the interior of the room at high priority + d d d d d # + d d1(3x3) d # + d ` ` ` d # + d ` ` ` d # + d d d d d # + # # # # # # + + #dig dig the interior of the room at high priority + 4 4 4 4 4 # + 4 1 1 1 4 # + 4 1 1 1 4 # + 4 1 1 1 4 # + 4 4 4 4 4 # + # # # # # # + +At least one of the symbol and the priority number must be specified. + +Dig markers +~~~~~~~~~~~ + +There are three types of markers you can apply to dig designated tiles. You can +apply multiple markers to the same tile by including multiple marker prefixes. +For example, a tile that is in blueprint mode and that is also marked for warm +and damp dig would be written as:: + + #dig + mbmwmdd + +Blueprint marker +```````````````` + +"Blueprint" markers are useful for when you want to plan out your digging, but +you don't want to dig everything just yet. Here, "blueprint" refers to the +vanilla UI "blueprint mode" vs. "standard mode" buttons. You can use DF's +"Change blueprints to standard selections" button to convert the "blueprint" +marked tiles to regular designations. + +For example, to dig out the perimeter of a room, but leave the center of the +room marked for digging later:: + + #dig + d d d d d # + d mbd mbd mbd d # + d mbd mbd mbd d # + d mbd mbd mbd d # + d d d d d # + # # # # # # + +To apply an entire dig blueprint in blueprint marker mode, regardless of what +the blueprint itself says, you can set the global quickfort setting +``force_marker_mode`` to ``true`` before you apply the blueprint by running +``quickfort set force_marker_mode true``. + +Note that the state of the in-game vanilla button that you use to draw +designations in either Standard or "Blueprint" mode does not have any effect on +`quickfort`. + +Warm and damp dig markers +````````````````````````` + +Warm and damp dig markers allow digging to continue uninterrupted through warm +or damp tiles. These markers are useful to include in blueprints that are +expected to be applied near magma or in damp/aquifer layers. See the `dig` tool +for more info on warm and damp dig. + +The prefix for warm dig is ``mw`` and the prefix for damp dig is ``md``. + +Carved minecart tracks +~~~~~~~~~~~~~~~~~~~~~~ + +In the game, you carve a minecart track by specifying a beginning and ending +tile, and the game "adds" the designation to the tiles in between. You cannot +designate single tiles because DF needs a multi-tile track to figure out which +direction the track should go on each tile. For example to carve two track +segments that cross each other, you might use the cursor to designate a line of +three vertical tiles like this:: + + ` start here ` # + ` ` ` # + ` end here ` # + # # # # + +Then to carve the cross, you'd do a horizontal segment:: + + ` ` ` # + start here ` end here # + ` ` ` # + # # # # + +This will result in a carved track that would be equivalent to a constructed +track of the form:: + + #build + ` trackS ` # + trackE trackNSEW trackW # + ` trackN ` # + # # # # + +Quickfort supports both styles of specification for carving tracks with ``#dig`` +blueprints. You can use the "additive" style to carve tracks in segments or you +can use the ``track`` aliases to specify the track tile by tile. To designate +track segments, use area expansion syntax with a height or width of 1:: + + #dig + ` T(1x3) ` # + T(3x1) ` ` # + ` ` ` # + # # # # + +"But wait!", I can hear you say, "How do you designate a track corner that opens +to the South and East? You can't put both T(1xH) and T(Wx1) in the same cell!" +This is true, but you can specify both width and height greater than 1, and for +tracks, QF interprets it as an upper-left corner extending to the right W tiles +and down H tiles. For example, to carve a track in a closed ring, you'd write:: + + #dig + T(3x3) ` T(1x3) # + ` ` ` # + T(3x1) ` ` # + # # # # + +You can also use negative numbers in the expansion syntax to indicate corners +that are not upper-left corners. This blueprint will also carve a closed ring:: + + #dig + T(3x3) ` ` # + ` ` ` # + ` ` T(-3x-3) # + # # # # + +Or you could use the aliases to specify tile by tile:: + + #dig + trackSE trackEW trackSW # + trackNS ` trackNS # + trackNE trackEW trackNW # + # # # # + +The aliases can also be used to designate a solid block of track. This is +especially useful for obliterating low-quality engravings so you can re-smooth +and re-engrave with higher quality. For example, you could use the following +sequence of blueprints to ensure a 10x10 floor area contains only masterwork +engravings:: + + #dig smooth floor + s(10x10) + #dig engrave floor + e(10x10) + #dig erase low-quality engravings + trackNSEW(10x10) + +The tracks only remove low-quality engravings since quickfort won't designate +masterwork engravings for destruction (unless forced to by a commandline +parameter). You would run (and let your dwarves complete the jobs for) the +sequence of blueprints until no tiles are designated by the "erase" blueprint. + +#zone mode +---------- + +Zones define how regions of your fort should be treated. They are also the +anchor point for "locations" like taverns and hospitals. Unlike stockpiles or +buildings, zones can overlap, which can lead to some interesting layouts. See +the full list of zone symbols in the `#zone mode reference`_. + +Zone designation syntax +~~~~~~~~~~~~~~~~~~~~~~~ + +A zone is declared with a symbol followed by optional properties:: + + #zone a single tile garbage dump zone + d + + #zone a single tile garbage dump zone named "The Dump" + d{name="The Dump"} + + #zone interrogation room + o{name=Interrogation assigned_unit=sheriff} + + #zone a small inactive pond zone + p{name="Fill me" pond=true active=false}(3x3) + +If you want multiple zones that have the same footprint, they can be declared +from the same cell:: + + #zone pasture and training area + n{name="Main pasture"}t{name="Pet training area"}(14x10) + +or from different corners of the same rectangle:: + + #zone pasture and training area + n{name="Main pasture"}(10x2) + t{name="Pet training area"}(10x-2) + +and you can use this technique to achieve partial overlap, of course. The only +configuration that can't be specified in a single blueprint is multiple +non-rectangular zones that are partially overlapping. You will have to use +multiple ``#zone`` blueprints to achieve that. + +You can also use labels (see `Label syntax`_ above) to separate adjacent +non-rectangular zones that happen to be of the same type or to combine +disconnected regions into a single zone. + +Locations, locations, locations +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Hospitals, guildhalls, taverns, libraries, and temples are locations. You can +declare a location in the properties for a zone:: + + #zone metalcrafter hall + m{location=guildhall profession=metalcrafter}(7x7) + +You can attach multiple zones to a single location by giving the location a +label (not a name -- you can name zones, but you can't directly name locations) +and then using that label for each of the zones you want to attach:: + + #zone tavern and rented room + b{location=tavern/bigpub name="Rent me"}(3x1) + h{location=tavern/bigpub name="Central pub" allow=residents}(25x40) + +Note that the label ("bigpub" in this case) will never appear in-game. It is +only used in the context of the blueprint to identify a common location. + +#place mode +----------- + +``#place`` mode is dedicated to stockpiles, which are a major design element in +any fortress. + +Stockpile designation syntax +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Just like zones, stockpiles can have properties like names or lists of other +stockpiles to take from. Unlike zones, stockpiles can have configuration +specifiers for exactly what types of items to accept. The full syntax looks +like this:: + + types/label{properties}:configuration(expansion) + +with every component other than the type being optional. You're already +familiar with `Property syntax`_, `Label syntax`_, and +`Area expansion syntax`_, so let's focus in on the remaining elements. + +Stockpile types +~~~~~~~~~~~~~~~ + +The type of stockpile corresponds to the category of items it accepts. Some +types will cause the stockpile to accept bins or barrels. See the full list in +the `#place mode reference`_. + +It is very common to have stockpiles that accept multiple categories of items. +Although it is perfectly valid to declare a single-purpose stockpile, +`quickfort` also supports directly declaring all the categories at once. For +example, to declare a 20x10 stockpile that accepts both corpses and refuse, you +could write:: + + #place refuse heap + yr(20x10) + +The order of the individual letters doesn't matter. If you want to configure the +stockpile from scratch, you can place unconfigured "custom" stockpiles with +(:kbd:`c`). + +.. _quickfort-place-containers: + +Bins, barrels, and wheelbarrows +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Quickfort has global settings for default values for the number of bins, +barrels, and wheelbarrows assigned to stockpiles, but these numbers can be set +for individual stockpiles as well in the properties. + +Individual properties for ``bins``, ``barrels``, and ``wheelbarrows`` are +supported. You can also set them all at once with the ``containers`` alias (it +usually just makes sense to set this to 0 when you don't want any containers of +any type). For example:: + + #place a stone stockpile with five wheelbarrows + s{wheelbarrows=5}(3x3) + + #place a bar, ammo, weapon, and armor stockpile with 20 bins + bzpd{bins=20}(5x5) + + #place a weapon stockpile with no bins + p{containers=0}(9x2) + +That last one could have equivalently used ``bins=0``, but sometimes you just +don't want to have to think about which stockpile types take which type of +container. + +The container settings also have a shorthand form. If you add a number after a +type symbol, you can set the relevant container count. The first example above +could equivalently be written as:: + + #place a stone stockpile with five wheelbarrows + s5(3x3) + +It sets the count for wheelbarrows specifically because the container +associated with stone stockpiles is wheelbarrows. + +If a stockpile has multiple types, it is the just the previous type symbol that +matters. ``s5e`` (stone and gems) would still set wheelbarrows only since the +``5`` comes directly after the ``s``. ``se5`` would set bins and not +wheelbarrows since the ``5`` would affect the container type associated with +gem stockpiles: bins. + +If the number follows a type symbol that does not have a specific container +type associated with it, then the container type defaults to wheelbarrows. This +allows you to easily add wheelbarrows to furniture and corpse stockpiles, where +having wheelbarrows is useful, but not added by default by the game. + +If the specified number exceeds the number of available stockpile tiles, the +number of available tiles is used. For wheelbarrows, that limit is reduced by 1 +to ensure there is at least one non-wheelbarrow tile available in the stockpile. +Otherwise no stone would ever be brought to the stockpile since all tiles would +be occupied by wheelbarrows! + +Generating manager orders for a ``#place`` blueprint with explicitly set +container/wheelbarrow counts will enqueue manager orders for the specified +number of containers or wheelbarrows, even if that number exceeds the in-game +size of the stockpile. For example, the following blueprint will enqueue orders +for 10 rock pots, even though the stockpile only has 9 tiles:: + + #place + f{barrels=10}(3x3) + +Stockpile configuration +~~~~~~~~~~~~~~~~~~~~~~~ + +Quickfort uses the `stockpiles` plugin and `stockpiles-library` to configure +stockpile settings, and provides a syntax that is easy to write in a blueprint +yet still allows you to access the full power of the `stockpiles` command. + +The syntax is:: + + : [/] [ [/]...] + +```` is one of ``=``, ``-``, or ``+``, representing the three `stockpiles` +import modes: ``set``, ``disable``, or ``enable``, respectively. Note that if +you are using an ``=`` op, then it should go first in the list. Any ``=`` +configuration segment will override anything that comes before it. + +For example, a blueprint like:: + + #place + f:=booze(5x4) + +would be equivalent to creating a 5x4 food stockpile in the UI, then selecting +it and running this command:: + + stockpiles import --mode=set booze + +you can also add a slash (``/``) and a comma-separated list of filter strings +to customize the settings further:: + + #place + p{name="Metal weapons"}:-cat_weapons/other/(7x3) + +Note that the "op" in this case lets us disable the matched preset, which in +this case is the "Other materials" types in the Weapons category. This +configuration is equivalent to the `stockpiles` command:: + + stockpiles import --mode=disable cat_weapons --filter=other/ + +And we can chain multiple `stockpiles` commands together by adding another "op" +character and another preset:: + + #place + p{name="Steel weapons"}:-cat_weapons/mats/,other/+steelweapons(7x3) + +which corresponds to running these two commands:: + + stockpiles import --mode=disable cat_weapons --filter=mats/,other/ + stockpiles import --mode=enable steelweapons + +With the combination of the library presets and custom filter strings, you can +configure any stockpile any way you like! + +#build mode +----------- + +``#build`` mode handles buildings, furniture (which are also "buildings" +according to DF), constructions (including constructed tracks), and hauling +routes. + +Building designation syntax +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The syntax is very similar to the syntax for stockpiles, except that it only +makes sense to have a single symbol to indicate what to build on that tile:: + + symbol{properties}:configuration(expansion) + +See the `#build mode reference`_ for properties that you can specify for each +building type. + +Here's an example of a simple 5x5 square of flooring:: + + #build + Cf(5x5) + +or a named Jeweler's workshop that takes from specific stockpiles:: + + #build + wj{name="Encrusting center" take_from="Furniture,Gem storage"} + +or a forge that specializes in high-quality armor:: + + #build + wf{name=Armorer labors=Armoring min_skill=Master} + +The ``:configuration`` part is only relevant for hauling routes, which we'll go +over in the next section. + +Hauling route definitions +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Hauling routes are defined by properties and configuration attached to track +stops. You can define a single-stop hauling route for a quantum stockpile as +easily as a multi-stop stone quarry transportation line. The stockpile-like +``:configuration`` part of the syntax controls which item types are considered +"desired" for the hauling route stop. If it's not specified, then all item +types are accepted. This is the most common case since most hauling route +contents are filtered by the stockpiles that the stops take from, but the +flexibility is there for when multiple stops take different items from the same +stockpile, or when a stop only wants a subset of items from a stockpile. + +Here is a common setup for a quantum stone stockpile:: + + #place + s{name="Stone quantum" quantum=true} ~ s5{name="Stone feeder"}(3x3) + #build + ~ trackstopW{take_from="Stone feeder" route="Stone dumper"} + +This sets up the quantum stockpile and the feeder stockpile in the ``#place`` +blueprint, followed by the trackstop and the hauling route configuration in the +``#build`` blueprint. The ``route`` property is the name of the hauling route +to create (or attach to if it already exists). If you are applying a quantum +stockpile blueprint more than once in a fort, be sure to *avoid* defining the +``route`` property so that each application of the blueprint creates a unique +hauling route. Two quantum stockpiles on the same route will not function +properly (since one of the stops will be missing a minecart). + +Let's look at a slightly more complicated setup where we sort the stone into +different output quantum stockpiles:: + + #place + s{name="Other stone quantum" quantum=true} ~ s5e{name="Rock feeder"}(3x3) + s{name="Ore/clay stone quantum" quantum=true} ~ + s{name="Gem quantum" quantum=true} ~ + #build + ~ trackstopW{take_from="Rock feeder" route="Other stone"}:=otherstone + ~ trackstopW{take_from="Rock feeder" route="Ore/clay"}:=cat_stone-otherstone + ~ trackstopW{take_from="Rock feeder" route="Gems"}:=cat_gems + +You can see how we make use of the stockpile-style configuration syntax to +fine-tune the items desired by the hauling route stop. + +Finally, let's make a series of stops on a common hauling route. There is +nothing particularly special about this example. If the ``route`` property +names an existing route, the stop will be added to that route:: + + #dig + trackE trackEW trackEW trackW + #build + trackstop{route="Tick tock"} ~ ~ trackstop{route="Tick tock"} + +These two track stops (which do not dump their contents) simply exist on a +common route at the ends of a connected carved track. + +#burrow mode +------------ + +``#burrow`` mode can create, extend, and remove tiles from burrows. + +Burrow designation syntax +~~~~~~~~~~~~~~~~~~~~~~~~~ + +The syntax should look familiar by now:: + + symbol{properties}(expansion) + +See the `#burrow mode reference`_ for symbol and property definitions. + +Here's how to create (or add to, if a burrow by that name already exists) a +5x5 burrow named ``Inside+``. It will also register this burrow with +`gui/civ-alert` if no burrow has yet been registered:: + + #burrow + a{create=true name=Inside+ civalert=true}(5x5) + +Why the trailing ``+``? That's to indicate to the `burrow` plugin that the +burrow should grow as adjacent tiles are dug out. + +Similarly, here is how to erase a tile from all burrows that currently include +it:: + + #burrow + e + +.. _quickfort-modeline: + +Modeline markers +---------------- + +The modeline has some additional optional components that we haven't talked +about yet. You can: + +- give a blueprint a label by adding a ``label()`` marker +- set a cursor offset and/or cursor placement hint by adding a ``start()`` + marker +- hide a blueprint from being listed with a ``hidden()`` marker +- register a message to be displayed after the blueprint is successfully + applied with a ``message()`` marker + +The full modeline syntax, when all optional elements are specified, is:: + + #mode label(mylabel) start(X;Y;startcomment) hidden() message(mymessage) comment + +Note that all elements are optional except for the initial ``#mode`` (though, as +mentioned in the first section, if a modeline doesn't appear at all in the first +cell of a spreadsheet, the blueprint is interpreted as a ``#dig`` blueprint with +no optional markers). Here are a few examples of modelines with optional +elements before we discuss them in more detail:: + + #dig start(3; 3; Center tile of a 5-tile square) Regular blueprint comment + #build label(noblebedroom) No explicit 'start()' so cursor is in upper left + #meta label(digwholefort) start(center of stairs on surface) + #dig label(dig_dining) hidden() called by the digwholefort meta blueprint + #zone label(pastures) message(remember to assign animals to the pastures) + +.. _quickfort-label: + +Blueprint labels +~~~~~~~~~~~~~~~~ + +Labels are displayed in the blueprint selection dialog and the output of +``quickfort list`` and are used for addressing specific blueprints when there +are multiple blueprints in a single file or spreadsheet sheet (see +`Packaging a set of blueprints`_ below). If a blueprint has no label, the label +becomes the ordinal of the blueprint's position in the file or sheet. For +example, the label of the first blueprint will be "1" if it is not otherwise +set, the label of the second blueprint will be "2" if it is not otherwise set, +etc. Labels that are explicitly defined must start with a letter to ensure the +auto-generated labels don't conflict with user-defined labels. + +.. _quickfort-start: + +Start positions +~~~~~~~~~~~~~~~ + +Start positions specify a cursor offset for a particular blueprint, simplifying +the task of blueprint alignment. This is very helpful for blueprints that are +based on a central staircase, but it comes in handy whenever a blueprint has an +obvious "center". For example:: + + #build start(2;2;center of workshop) label(stonew) a stonecutter workshop + wm wm wm # + wm wm wm # + wm wm wm # + # # # # + +will build the workshop *centered* on the cursor, not down and to the right of +the cursor. + +The two numbers specify the column and row (or 1-based X and Y offset) where the +cursor is expected to be when you apply the blueprint. Position ``1;1`` is the +top left cell. The optional comment will show up in the blueprint listings and +should contain information about where to position the cursor. If the start +position is ``1;1``, you can omit the numbers and just add a comment describing +where to put the cursor. This is also useful for meta blueprints that don't +actually care where the cursor is, but that refer to other blueprints that have +fully-specified ``start()`` markers. For example, a meta blueprint that refers +to the ``stonew`` blueprint above could look like this:: + + #meta start(center of workshop) a stonecutter workshop + /stonew + +You can use semicolons, commas, or spaces to separate the elements of the +``start()`` marker, whichever you prefer. + +.. _quickfort-hidden: + +Hiding blueprints +~~~~~~~~~~~~~~~~~ + +A blueprint with a ``hidden()`` marker won't appear in the blueprint listings +unless hidden blueprints are specifically requested. The primary reason for +hiding a blueprint (rather than, say, deleting it or moving it out of the +``blueprints/`` folder) is if a blueprint is intended to be run as part of a +larger sequence managed by a `meta blueprint `. + +.. _quickfort-message: + +Messages +~~~~~~~~ + +A blueprint with a ``message()`` marker will display a message after the +blueprint is applied. This is useful for reminding players to take manual steps +that cannot be automated, like assigning minecarts to a route, or listing the +next step in a series of blueprints. For long or multi-part messages, you can +embed newlines:: + + "#meta label(surface1) message(This would be a good time to start digging the industry level. + Once the area is clear, continue with /surface2.) clear the embark site and set up pastures" + +The quotes surrounding the cell text are only necessary if you are writing a +.csv file by hand. Spreadsheet applications will surround multi-line text with +quotes automatically when they save/export the file. + +.. _quickfort-other-modes: + +Other blueprint modes +--------------------- + +There are a few additional blueprint modes that become useful when you are +sharing your blueprints with others or managing complex blueprint sets. Instead +of mapping tile positions to map modifications like the basic modes do, these +"blueprints" have specialized, higher-level uses: + +============== =========== +Blueprint mode Description +============== =========== +notes Display long messages, such as help text or blueprint + walkthroughs +ignore Hide a section of your spreadsheet from quickfort, useful for + scratch space or personal notes +meta Script sequences of blueprints together, transform them, and/or + repeat them across multiple z-levels +============== =========== + +.. _quickfort-notes: + +#notes mode +~~~~~~~~~~~ + +Sometimes you just want to record some information about your blueprints, such +as when to apply them, what preparations you need to make, or what the +blueprints contain. The `message() ` modeline marker is +useful for small, single-line messages, but a ``#notes`` blueprint is more +convenient for long messages or messages that span many lines. The lines in a +``#notes`` blueprint are output as if they were contained within one large +multi-line ``message()`` marker. For example, the following (empty) ``#meta`` +blueprint:: + + "#meta label(help) message(This is the help text for the blueprint set + contained in this file. + + First, make sure that you embark in...) blueprint set walkthrough" + +could more naturally be written as a ``#notes`` blueprint:: + + #notes label(help) blueprint set walkthrough + This is the help text for the blueprint set + contained in this file + + First, make sure that you embark in... + +The ``#meta`` blueprint is all squashed into a single spreadsheet cell, using +embedded newlines. Each line of the ``#notes`` "blueprint", however, is in a +separate cell, allowing for much easier viewing and editing. + +#ignore mode +~~~~~~~~~~~~ + +If you don't want some data to be visible to quickfort at all, use an +``#ignore`` blueprint. All lines until the next modeline in the file or sheet +will be completely ignored. This can be useful for personal notes, scratch +space, or temporarily "commented out" blueprints. + +.. _quickfort-meta: + +#meta mode +~~~~~~~~~~ + +``#meta`` blueprints are blueprints that control how other blueprints are +applied. For example, meta blueprints can bundle a group of other blueprints so +that they can be run with a single command. They can also encode logic, like +rotating the blueprint or duplicating it across a specified number of z-levels. + +Scripting blueprints together +````````````````````````````` + +A common scenario where meta blueprints are useful is when you have several +phases to link together. For example you might: + +1. Apply a dig blueprint to designate dig areas +#. Wait for miners to dig +#. **Apply another dig blueprint** to designate traffic costs +#. **Apply a zone blueprint** to designate zones +#. **Apply a place buildprint** to designate and configure stockpiles +#. **Apply a build buildprint** to designate buildings + +Those last four "apply"s might as well get done in one command instead of four. +A ``#meta`` blueprint can help with that. A meta blueprint refers to +other blueprints in the same file by their label (see the `Modeline markers`_ +section) in the same format used by the `quickfort` command: +``/