├── .gitattributes ├── .github └── workflows │ ├── checks.yml │ └── pypi-publish.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── MANIFEST.in ├── README.md ├── pyproject.toml ├── svgcheck ├── .coveragerc ├── Results │ ├── DrawBerry-sample-2.out │ ├── DrawBerry-sample-2.svg │ ├── IETF-test.out │ ├── IETF-test.svg │ ├── circle.out │ ├── circle.svg │ ├── clear-cache.err │ ├── clear-cache.out │ ├── colors.err │ ├── colors.out │ ├── dia-sample-svg.out │ ├── dia-sample-svg.svg │ ├── empty │ ├── example-dot.out │ ├── example-dot.svg │ ├── full-tiny-02.err │ ├── full-tiny-02.out │ ├── full-tiny.err │ ├── full-tiny.out │ ├── full-tiny.xml │ ├── good.err │ ├── httpbis-proxy20-fig6.out │ ├── httpbis-proxy20-fig6.svg │ ├── malformed.out │ ├── malformed.svg │ ├── rfc-01.err │ ├── rfc-01.out │ ├── rfc-01.xml │ ├── rfc-02.err │ ├── rfc-02.out │ ├── rfc-03.err │ ├── rfc-03.out │ ├── rfc-svg.err │ ├── rfc-svg.out │ ├── rgb.out │ ├── rgb.svg │ ├── svg-wordle.out │ ├── svg-wordle.svg │ ├── utf8-2.err │ ├── utf8-2.out │ ├── utf8-2.svg │ ├── utf8.err │ ├── utf8.out │ ├── viewBox-both.out │ ├── viewBox-both.svg │ ├── viewBox-height.out │ ├── viewBox-height.svg │ ├── viewBox-none.out │ ├── viewBox-none.svg │ ├── viewBox-width.out │ └── viewBox-width.svg ├── Tests │ ├── DrawBerry-sample-2.svg │ ├── IETF-test.svg │ ├── cache_saved │ │ └── reference.RFC.1847.xml │ ├── circle.svg │ ├── colors.svg │ ├── dia-sample-svg.svg │ ├── example-dot.svg │ ├── full-tiny.xml │ ├── good.svg │ ├── httpbis-proxy20-fig6.svg │ ├── malformed.svg │ ├── rfc-svg.xml │ ├── rfc.xml │ ├── rgb.svg │ ├── svg-wordle.svg │ ├── threshold.svg │ ├── utf8.svg │ ├── viewBox-both.svg │ ├── viewBox-height.svg │ ├── viewBox-none.svg │ └── viewBox-width.svg ├── __init__.py ├── checksvg.py ├── log.py ├── pycode.cfg ├── rewrite.x ├── run.py ├── test.py └── word_properties.py └── tox.ini /.gitattributes: -------------------------------------------------------------------------------- 1 | # Make all of the test files be normalized line endings 2 | *.xml text 3 | *.out text 4 | *.svg text 5 | -------------------------------------------------------------------------------- /.github/workflows/checks.yml: -------------------------------------------------------------------------------- 1 | name: Tests + Code Analysis 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | workflow_dispatch: 9 | 10 | jobs: 11 | analyze: 12 | name: Analyze Code 13 | runs-on: ubuntu-latest 14 | permissions: 15 | actions: read 16 | contents: read 17 | security-events: write 18 | 19 | strategy: 20 | fail-fast: false 21 | 22 | steps: 23 | - name: Checkout repository 24 | uses: actions/checkout@v4 25 | 26 | - name: Initialize CodeQL 27 | uses: github/codeql-action/init@v3 28 | with: 29 | languages: python 30 | 31 | - name: Perform CodeQL Analysis 32 | uses: github/codeql-action/analyze@v3 33 | 34 | tests: 35 | name: Unit Tests 36 | runs-on: ${{ matrix.platform }} 37 | 38 | strategy: 39 | matrix: 40 | platform: [ubuntu-latest, macos-latest, windows-latest] 41 | python-version: ['3.9', '3.10', '3.11', '3.12', '3.13'] 42 | 43 | steps: 44 | - name: Checkout repository 45 | uses: actions/checkout@v4 46 | 47 | - name: Setup Python ${{ matrix.python-version }} 48 | uses: actions/setup-python@v5 49 | with: 50 | python-version: ${{ matrix.python-version }} 51 | 52 | - name: Install dependencies 53 | run: | 54 | python -m pip install --upgrade pip 55 | python -m pip install tox tox-gh-actions 56 | 57 | - name: Test with tox 58 | env: 59 | PLATFORM: ${{ matrix.platform }} 60 | run: tox 61 | -------------------------------------------------------------------------------- /.github/workflows/pypi-publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish Python Package 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | publish_release: 7 | description: 'Create Production Release' 8 | required: true 9 | type: boolean 10 | 11 | jobs: 12 | build: 13 | name: Build distribution 📦 14 | runs-on: ubuntu-latest 15 | outputs: 16 | pkg_version: ${{ steps.semver.outputs.next }} 17 | 18 | steps: 19 | - uses: actions/checkout@v4 20 | with: 21 | persist-credentials: false 22 | fetch-depth: 0 23 | 24 | - name: Set up Python 25 | uses: actions/setup-python@v5 26 | with: 27 | python-version: "3.x" 28 | 29 | - name: Get Next Version 30 | if: ${{ inputs.publish_release }} 31 | id: semver 32 | uses: ietf-tools/semver-action@v1 33 | with: 34 | patchList: fix, bugfix, perf, refactor, test, tests, chore, revert 35 | token: ${{ github.token }} 36 | branch: main 37 | 38 | - name: Set Next Version Env Var 39 | if: ${{ inputs.publish_release }} 40 | env: 41 | NEXT_VERSION: ${{ steps.semver.outputs.next }} 42 | run: | 43 | echo "NEXT_VERSION=$next" >> $GITHUB_ENV 44 | 45 | - name: Create Draft Release 46 | uses: ncipollo/release-action@v1 47 | if: ${{ inputs.publish_release }} 48 | with: 49 | prerelease: true 50 | draft: false 51 | commit: ${{ github.sha }} 52 | tag: ${{ env.NEXT_VERSION }} 53 | name: ${{ env.NEXT_VERSION }} 54 | body: '*pending*' 55 | token: ${{ secrets.GITHUB_TOKEN }} 56 | 57 | - name: Set Build Variables 58 | run: | 59 | if [[ $NEXT_VERSION ]]; then 60 | echo "Using AUTO SEMVER mode: $NEXT_VERSION" 61 | echo "PKG_VERSION=$NEXT_VERSION" >> $GITHUB_ENV 62 | echo "PKG_VERSION_STRICT=${NEXT_VERSION#?}" >> $GITHUB_ENV 63 | elif [[ "$GITHUB_REF" =~ ^refs/tags/v* ]]; then 64 | echo "Using TAG mode: $GITHUB_REF_NAME" 65 | echo "PKG_VERSION=$GITHUB_REF_NAME" >> $GITHUB_ENV 66 | echo "PKG_VERSION_STRICT=${GITHUB_REF_NAME#?}" >> $GITHUB_ENV 67 | else 68 | echo "Using TEST mode: v3.0.0-dev.$GITHUB_RUN_NUMBER" 69 | echo "PKG_VERSION=v3.0.0-dev.$GITHUB_RUN_NUMBER" >> $GITHUB_ENV 70 | echo "PKG_VERSION_STRICT=3.0.0-dev.$GITHUB_RUN_NUMBER" >> $GITHUB_ENV 71 | fi 72 | 73 | - name: Install pypa/build 74 | run: >- 75 | python3 -m 76 | pip install 77 | build 78 | setuptools 79 | --user 80 | 81 | - name: Build a binary wheel and a source tarball 82 | run: | 83 | echo "Using version $PKG_VERSION_STRICT" 84 | sed -i -r -e "s/^__version__ += '.*'$/__version__ = '$PKG_VERSION_STRICT'/" svgcheck/__init__.py 85 | python3 -m build 86 | 87 | - name: Store the distribution packages 88 | uses: actions/upload-artifact@v4 89 | with: 90 | name: python-package-distributions 91 | path: dist/ 92 | 93 | - name: Store updated __init__.py 94 | uses: actions/upload-artifact@v4 95 | with: 96 | name: svgcheck-init 97 | path: svgcheck/__init__.py 98 | 99 | publish-to-pypi: 100 | name: >- 101 | Publish Python 🐍 distribution 📦 to PyPI 102 | needs: 103 | - build 104 | runs-on: ubuntu-latest 105 | environment: 106 | name: release 107 | url: https://pypi.org/p/svgcheck 108 | permissions: 109 | id-token: write 110 | if: ${{ inputs.publish_release }} 111 | 112 | steps: 113 | - name: Download all the dists 114 | uses: actions/download-artifact@v4 115 | with: 116 | name: python-package-distributions 117 | path: dist/ 118 | 119 | - name: Publish distribution 📦 to PyPI 120 | uses: pypa/gh-action-pypi-publish@release/v1 121 | 122 | github-release: 123 | name: >- 124 | Sign the Python 🐍 distribution 📦 with Sigstore 125 | and upload them to GitHub Release 126 | needs: 127 | - build 128 | - publish-to-pypi 129 | runs-on: ubuntu-latest 130 | 131 | permissions: 132 | contents: write 133 | id-token: write 134 | packages: write 135 | pull-requests: write 136 | 137 | steps: 138 | - uses: actions/checkout@v4 139 | with: 140 | fetch-depth: 0 141 | 142 | - name: Download all the dists 143 | uses: actions/download-artifact@v4 144 | with: 145 | name: python-package-distributions 146 | path: dist/ 147 | 148 | - name: Download updated init file 149 | uses: actions/download-artifact@v4 150 | with: 151 | name: svgcheck-init 152 | path: svgcheck/ 153 | merge-multiple: true 154 | 155 | - name: Set Variables 156 | run: echo "PKG_VERSION=${{needs.build.outputs.pkg_version}}" >> $GITHUB_ENV 157 | 158 | - name: Update CHANGELOG 159 | id: changelog 160 | uses: Requarks/changelog-action@v1 161 | with: 162 | token: ${{ github.token }} 163 | tag: ${{ env.PKG_VERSION }} 164 | excludeTypes: '' 165 | 166 | - name: Sign the dists with Sigstore 167 | uses: sigstore/gh-action-sigstore-python@v3.0.0 168 | with: 169 | inputs: >- 170 | ./dist/*.tar.gz 171 | ./dist/*.whl 172 | 173 | - name: Create Release 174 | uses: ncipollo/release-action@v1 175 | with: 176 | allowUpdates: true 177 | draft: false 178 | tag: ${{ env.PKG_VERSION }} 179 | name: ${{ env.PKG_VERSION }} 180 | body: ${{ steps.changelog.outputs.changes }} 181 | artifacts: "dist/**" 182 | token: ${{ secrets.GITHUB_TOKEN }} 183 | makeLatest: true 184 | 185 | - name: Create Pull Request 186 | uses: peter-evans/create-pull-request@v7 187 | with: 188 | commit_message: 'docs: update CHANGELOG.md + py file versions for ${{ env.PKG_VERSION }} [skip ci]' 189 | 190 | publish-to-testpypi: 191 | name: Publish Python 🐍 distribution 📦 to TestPyPI 192 | needs: 193 | - build 194 | runs-on: ubuntu-latest 195 | environment: 196 | name: release 197 | url: https://test.pypi.org/p/svgcheck 198 | permissions: 199 | id-token: write 200 | 201 | steps: 202 | - name: Download all the dists 203 | uses: actions/download-artifact@v4 204 | with: 205 | name: python-package-distributions 206 | path: dist/ 207 | 208 | - name: Publish distribution 📦 to TestPyPI 209 | uses: pypa/gh-action-pypi-publish@release/v1 210 | with: 211 | repository-url: https://test.pypi.org/legacy/ 212 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #in progress 2 | Samples 3 | cache 4 | bin 5 | Temp 6 | Release 7 | Debug 8 | _zzs.c 9 | Torture 10 | Alice 11 | 12 | # Byte-compiled / optimized / DLL files 13 | __pycache__/ 14 | *.py[cod] 15 | *$py.class 16 | 17 | # C extensions 18 | *.so 19 | 20 | # Distribution / packaging 21 | .Python 22 | env/ 23 | build/ 24 | develop-eggs/ 25 | dist/ 26 | downloads/ 27 | eggs/ 28 | .eggs/ 29 | lib/ 30 | lib64/ 31 | parts/ 32 | sdist/ 33 | var/ 34 | wheels/ 35 | *.egg-info/ 36 | .installed.cfg 37 | *.egg 38 | 39 | # PyInstaller 40 | # Usually these files are written by a python script from a template 41 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 42 | *.manifest 43 | *.spec 44 | 45 | # Installer logs 46 | pip-log.txt 47 | pip-delete-this-directory.txt 48 | 49 | # Unit test / coverage reports 50 | htmlcov/ 51 | .tox/ 52 | .coverage 53 | .coverage.* 54 | .cache 55 | nosetests.xml 56 | coverage.xml 57 | *.cover 58 | .hypothesis/ 59 | 60 | # Translations 61 | *.mo 62 | *.pot 63 | 64 | # Django stuff: 65 | *.log 66 | local_settings.py 67 | 68 | # Flask stuff: 69 | instance/ 70 | .webassets-cache 71 | 72 | # Scrapy stuff: 73 | .scrapy 74 | 75 | # Sphinx documentation 76 | docs/_build/ 77 | 78 | # PyBuilder 79 | target/ 80 | 81 | # Jupyter Notebook 82 | .ipynb_checkpoints 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # celery beat schedule file 88 | celerybeat-schedule 89 | 90 | # SageMath parsed files 91 | *.sage.py 92 | 93 | # dotenv 94 | .env 95 | 96 | # virtualenv 97 | .venv 98 | venv/ 99 | ENV/ 100 | 101 | # Spyder project settings 102 | .spyderproject 103 | .spyproject 104 | 105 | # Rope project settings 106 | .ropeproject 107 | 108 | # mkdocs documentation 109 | /site 110 | 111 | # mypy 112 | .mypy_cache/ 113 | 114 | 115 | # cleanup of emacs files 116 | *~ 117 | #* 118 | *# 119 | .#* 120 | 121 | # exclude Visual Studio files 122 | *.suo 123 | *.pyproj 124 | *.sln 125 | 126 | # other windows files 127 | *.bat 128 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [v0.11.0] - 2025-09-12 9 | ### :sparkles: New Features 10 | - [`e8471cd`](https://github.com/ietf-tools/svgcheck/commit/e8471cda1bc80206b234993fcbec244badf8c812) - Migrate to pyproject.toml *(PR [#75](https://github.com/ietf-tools/svgcheck/pull/75) by [@kesara](https://github.com/kesara))* 11 | - :arrow_lower_right: *addresses issue [#74](https://github.com/ietf-tools/svgcheck/issues/74) opened by [@kesara](https://github.com/kesara)* 12 | 13 | ### :bug: Bug Fixes 14 | - [`668682b`](https://github.com/ietf-tools/svgcheck/commit/668682bfc1faf44a63d00246f041d80b7f1ce582) - Return false on svgcheck errors *(PR [#72](https://github.com/ietf-tools/svgcheck/pull/72) by [@kesara](https://github.com/kesara))* 15 | - :arrow_lower_right: *fixes issue [#70](https://github.com/ietf-tools/svgcheck/issues/70) opened by [@szabgab](https://github.com/szabgab)* 16 | 17 | ### :construction_worker: Build System 18 | - [`ab3747f`](https://github.com/ietf-tools/svgcheck/commit/ab3747fdda28901e505b114562682f6e882b8c39) - Improve PyPI publishing workflow *(PR [#71](https://github.com/ietf-tools/svgcheck/pull/71) by [@kesara](https://github.com/kesara))* 19 | - :arrow_lower_right: *addresses issue [#69](https://github.com/ietf-tools/svgcheck/issues/69) opened by [@kesara](https://github.com/kesara)* 20 | - [`6131a2e`](https://github.com/ietf-tools/svgcheck/commit/6131a2e33c07d0b4d6c254e8b449a131e93ab8e7) - Fix pypi-publish GHA issues *(PR [#73](https://github.com/ietf-tools/svgcheck/pull/73) by [@kesara](https://github.com/kesara))* 21 | 22 | 23 | ## [v0.10.0] - 2024-12-03 24 | ### :sparkles: New Features 25 | - [`bb883fc`](https://github.com/ietf-tools/svgcheck/commit/bb883fc551c4070f13da4bffa973855a347964ae) - Drop support for Python 3.8 *(PR [#67](https://github.com/ietf-tools/svgcheck/pull/67) by [@kesara](https://github.com/kesara))* 26 | - :arrow_lower_right: *addresses issue [#59](https://github.com/ietf-tools/svgcheck/issues/59) opened by [@kesara](https://github.com/kesara)* 27 | 28 | 29 | ## [v0.9.0] - 2024-10-31 30 | ### :sparkles: New Features 31 | - [`1af4336`](https://github.com/ietf-tools/svgcheck/commit/1af43361b5cb26e2047cb3c7c575ee619f0fb12b) - Add support for Python 3.13 *(PR [#62](https://github.com/ietf-tools/svgcheck/pull/62) by [@kesara](https://github.com/kesara))* 32 | - :arrow_lower_right: *addresses issue [#58](https://github.com/ietf-tools/svgcheck/issues/58) opened by [@kesara](https://github.com/kesara)* 33 | 34 | 35 | ## [v0.8.1] - 2024-10-14 36 | ### :bug: Bug Fixes 37 | - [`40c2914`](https://github.com/ietf-tools/svgcheck/commit/40c2914c688de757b9e72560920dfd890ff0f8f9) - typo heuristic *(PR [#53](https://github.com/ietf-tools/svgcheck/pull/53) by [@Rotzbua](https://github.com/Rotzbua))* 38 | - :arrow_lower_right: *fixes issue [#40](https://github.com/ietf-tools/svgcheck/issues/40) opened by [@gregbo](https://github.com/gregbo)* 39 | - [`b330dfd`](https://github.com/ietf-tools/svgcheck/commit/b330dfdee391be0d757dcc7f426054fe875002b9) - Use correct log info method *(PR [#57](https://github.com/ietf-tools/svgcheck/pull/57) by [@kesara](https://github.com/kesara))* 40 | - [`87031fd`](https://github.com/ietf-tools/svgcheck/commit/87031fdd73ec64a3b94e3a8a9e0bb928cc6a68ad) - Read from STDIN *(PR [#56](https://github.com/ietf-tools/svgcheck/pull/56) by [@kesara](https://github.com/kesara))* 41 | - :arrow_lower_right: *fixes issue [#36](https://github.com/ietf-tools/svgcheck/issues/36) opened by [@kesara](https://github.com/kesara)* 42 | 43 | ### :wrench: Chores 44 | - [`21d3c29`](https://github.com/ietf-tools/svgcheck/commit/21d3c29bb9ed0d288c1f4957c5104560b18f7e00) - Remove Python 2.7 check *(PR [#60](https://github.com/ietf-tools/svgcheck/pull/60) by [@kesara](https://github.com/kesara))* 45 | 46 | 47 | ## [v0.8.0] - 2024-04-04 48 | ### :sparkles: New Features 49 | - [`6a6de81`](https://github.com/ietf-tools/svgcheck/commit/6a6de81112b2a2cf2056046d0283b9ee5ba4ed75) - Add support for Python 3.12 *(PR [#43](https://github.com/ietf-tools/svgcheck/pull/43) by [@Rotzbua](https://github.com/Rotzbua))* 50 | - [`e5d1820`](https://github.com/ietf-tools/svgcheck/commit/e5d1820cf7428d0744b201cda8a2a1ef52a03676) - Remove support for Python 3.7 *(PR [#49](https://github.com/ietf-tools/svgcheck/pull/49) by [@kesara](https://github.com/kesara))* 51 | - :arrow_lower_right: *addresses issue [#44](https://github.com/ietf-tools/svgcheck/issues/44) opened by [@kesara](https://github.com/kesara)* 52 | - :arrow_lower_right: *addresses issue [#47](https://github.com/ietf-tools/svgcheck/issues/47) opened by [@dwaite](https://github.com/dwaite)* 53 | 54 | ### :bug: Bug Fixes 55 | - [`db9471f`](https://github.com/ietf-tools/svgcheck/commit/db9471feedbe4484a900bba1a5d160c8346b5be5) - Remove duplicate key *(PR [#45](https://github.com/ietf-tools/svgcheck/pull/45) by [@Rotzbua](https://github.com/Rotzbua))* 56 | 57 | ### :recycle: Refactors 58 | - [`28240de`](https://github.com/ietf-tools/svgcheck/commit/28240deb91fec21739392e892dde240eabda59f5) - Remove Python 2 specific code *(PR [#46](https://github.com/ietf-tools/svgcheck/pull/46) by [@Rotzbua](https://github.com/Rotzbua))* 59 | 60 | 61 | ## [v0.7.1] - 2023-02-01 62 | ### :bug: Bug Fixes 63 | - [`182b486`](https://github.com/ietf-tools/svgcheck/commit/182b486d86cb98561d34bda2050e53a5dba34400) - No op --no-xinclude option *(PR [#35](https://github.com/ietf-tools/svgcheck/pull/35) by [@kesara](https://github.com/kesara))* 64 | 65 | 66 | ## [v0.7.0] - 2023-01-31 67 | ### :sparkles: New Features 68 | - [`ac1cc51`](https://github.com/ietf-tools/svgcheck/commit/ac1cc516f29da1495dfa10e4cfed0b7f720363be) - Use xml2rfc *(PR [#28](https://github.com/ietf-tools/svgcheck/pull/28) by [@kesara](https://github.com/kesara))* 69 | - [`8935e20`](https://github.com/ietf-tools/svgcheck/commit/8935e206769cfe158247c935120271190c27d17a) - Add support for Python 3.11 *(PR [#30](https://github.com/ietf-tools/svgcheck/pull/30) by [@kesara](https://github.com/kesara))* 70 | - [`d1076d2`](https://github.com/ietf-tools/svgcheck/commit/d1076d2ec1a4f73e9992f23d942b38730c7f56a2) - Remove command line option --no-xinclude *(PR [#32](https://github.com/ietf-tools/svgcheck/pull/32) by [@kesara](https://github.com/kesara))* 71 | 72 | ### :recycle: Refactors 73 | - [`57299b5`](https://github.com/ietf-tools/svgcheck/commit/57299b5873f1a61b3288987ab673611d6f7e562c) - Drop dependency on six in log module *(PR [#29](https://github.com/ietf-tools/svgcheck/pull/29) by [@kesara](https://github.com/kesara))* 74 | 75 | ### :wrench: Chores 76 | - [`5cafacd`](https://github.com/ietf-tools/svgcheck/commit/5cafacdc47df0128199938aee848c941162b9b13) - Move to setup.cfg *(PR [#24](https://github.com/ietf-tools/svgcheck/pull/24) by [@kesara](https://github.com/kesara))* 77 | - :arrow_lower_right: *addresses issue [#1](undefined) opened by [@dkg](https://github.com/dkg)* 78 | - :arrow_lower_right: *addresses issue [#6](undefined) opened by [@rjsparks](https://github.com/rjsparks)* 79 | 80 | 81 | ## [v0.6.2] - 2023-01-19 82 | ### :bug: Bug Fixes 83 | - [`f07f3ac`](https://github.com/ietf-tools/svgcheck/commit/f07f3aca8f051641f5e50c79a2f9c21a84f4b35b) - remove obsolete text. Fixes [#19](https://github.com/ietf-tools/svgcheck/pull/19). *(commit by [@rjsparks](https://github.com/rjsparks))* 84 | 85 | 86 | ## [v0.6.1] - 2022-04-05 87 | ### :white_check_mark: Tests 88 | - [`265b214`](https://github.com/ietf-tools/svgcheck/commit/265b2147961b1adafaded13be8f154bd2354357a) - add tox.ini *(commit by [@NGPixel](https://github.com/NGPixel))* 89 | - [`5e75de3`](https://github.com/ietf-tools/svgcheck/commit/5e75de35d4122a450884dd1f97212bd22f56febb) - fix test entry path *(commit by [@NGPixel](https://github.com/NGPixel))* 90 | - [`689ebe0`](https://github.com/ietf-tools/svgcheck/commit/689ebe07be31edfa5dd4cb164e86cf0526713f81) - add missing pycodestyle *(commit by [@NGPixel](https://github.com/NGPixel))* 91 | - [`91febab`](https://github.com/ietf-tools/svgcheck/commit/91febab5098d70da944233f62590338131ed75f7) - missing pyflakes *(commit by [@NGPixel](https://github.com/NGPixel))* 92 | - [`217f4a7`](https://github.com/ietf-tools/svgcheck/commit/217f4a7e29a8d1df6c735ba78a2d87be3b8c2874) - update Results. address pep8 complaint. *(PR [#3](https://github.com/ietf-tools/svgcheck/pull/3) by [@rjsparks](https://github.com/rjsparks))* 93 | 94 | ### :wrench: Chores 95 | - [`5da8749`](https://github.com/ietf-tools/svgcheck/commit/5da8749f0505065634d1d1ada9921e86bda6464f) - exclude non-svgcheck files *(commit by [@NGPixel](https://github.com/NGPixel))* 96 | 97 | 98 | ## [0.5.19] - 2019-08-29 99 | 100 | ### Changed 101 | - Move sources to an appropirate github location 102 | - Always emit a file when repair is chosen 103 | 104 | ## [0.5.17] - 2019-08-16 105 | 106 | ### Removed 107 | - Remove Python 3.4 from the supported list 108 | 109 | ## [0.5.16] - 2019-07-01 110 | 111 | ### Changed 112 | 113 | - Require new version of rfctools for new RNG file 114 | 115 | ## [0.5.15] - 2019-05-27 116 | 117 | ### Added 118 | 119 | - Add test case for UTF-8 120 | - Add test case for two pass 121 | 122 | ### Changed 123 | 124 | - Fix errors where we need to emit UTF-8 characters in either text or attributes 125 | - Force DOCTYPE not to be emitted when we have fixed a file so that we don't pick up default attributes 126 | 127 | ## [0.5.14] - 2019-04-21 128 | 129 | ### Changed 130 | 131 | - Force a viewBox to be part of the output 132 | 133 | ## [0.5.13] - 2019-04-06 134 | 135 | ### Changed 136 | 137 | - Setup so that it can take input from stdin 138 | - Clean up so that pyflakes passes 139 | 140 | ## [0.5.12] - 2019-02-22 141 | 142 | ### Added 143 | 144 | - Add exit comment on success/Failure 145 | 146 | ### Changed 147 | 148 | - Copy the preserve whitespace parameter from rfclint. This preserves formatting. 149 | - Preserve comments when doing a repair 150 | - Change the test scripts to use the same parsing options 151 | 152 | ## [0.5.4] - 2018-05-09 153 | 154 | ### Added 155 | 156 | - Add the numeric values for font-weight 157 | 158 | ### Changed 159 | 160 | - Allow for #fff to be tagged as white. Original discussions thought this was not going to be used. 161 | 162 | ## [0.5.1] - 2018-03-04 163 | 164 | ### Added 165 | 166 | - Setup things so it publishes to PyPI 167 | 168 | ## [0.5.0] - 2018-02-25 169 | 170 | - No changes 171 | 172 | ## [0.0.3] - 2018-02-11 173 | 174 | ### Changed 175 | 176 | - Correct black/white substitutions on RGB colors 177 | 178 | ## [0.0.2] - 2018-01-25 179 | 180 | ### Added 181 | 182 | - Add more test cases to get coverage number above 85% 183 | 184 | ### Changed 185 | 186 | - Rewrite style proprety handling to promote items rather than validate in place 187 | 188 | ## [0.0.1] - 2018-01-05 189 | 190 | ### Added 191 | 192 | - Create the initial simple version 193 | - Create python setup program 194 | 195 | [0.5.19]: https://github.com/ietf-tools/rfc2html/compare/0.5.17...0.5.19 196 | [0.5.17]: https://github.com/ietf-tools/rfc2html/compare/0.5.16...0.5.17 197 | [0.5.16]: https://github.com/ietf-tools/rfc2html/compare/0.5.15...0.5.16 198 | [0.5.15]: https://github.com/ietf-tools/rfc2html/compare/0.5.14...0.5.15 199 | [0.5.14]: https://github.com/ietf-tools/rfc2html/compare/0.5.13...0.5.14 200 | [0.5.13]: https://github.com/ietf-tools/rfc2html/compare/0.5.12...0.5.13 201 | [0.5.12]: https://github.com/ietf-tools/rfc2html/compare/0.5.4...0.5.12 202 | [0.5.4]: https://github.com/ietf-tools/rfc2html/compare/0.5.1...0.5.4 203 | [0.5.1]: https://github.com/ietf-tools/rfc2html/compare/0.5.0...0.5.1 204 | [0.5.0]: https://github.com/ietf-tools/rfc2html/compare/0.0.3...0.5.0 205 | [0.0.3]: https://github.com/ietf-tools/rfc2html/compare/0.0.2...0.0.3 206 | [0.0.2]: https://github.com/ietf-tools/rfc2html/compare/0.0.1...0.0.2 207 | [0.0.1]: https://github.com/ietf-tools/rfc2html/releases/tag/0.0.1 208 | 209 | [v0.6.1]: https://github.com/ietf-tools/svgcheck/compare/0.6.0...v0.6.1 210 | [v0.6.2]: https://github.com/ietf-tools/svgcheck/compare/v0.6.1...v0.6.2 211 | [v0.7.0]: https://github.com/ietf-tools/svgcheck/compare/v0.6.2...v0.7.0 212 | [v0.7.1]: https://github.com/ietf-tools/svgcheck/compare/v0.7.0...v0.7.1 213 | [v0.8.0]: https://github.com/ietf-tools/svgcheck/compare/v0.7.1...v0.8.0 214 | [v0.8.1]: https://github.com/ietf-tools/svgcheck/compare/v0.8.0...v0.8.1 215 | [v0.9.0]: https://github.com/ietf-tools/svgcheck/compare/v0.8.1...v0.9.0 216 | [v0.10.0]: https://github.com/ietf-tools/svgcheck/compare/v0.9.0...v0.10.0 217 | [v0.11.0]: https://github.com/ietf-tools/svgcheck/compare/v0.10.0...v0.11.0 218 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2017, 2022 IETF Trust 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 14 | 3. Neither the name of the copyright holder nor the names of its contributors 15 | may be used to endorse or promote products derived from this software 16 | without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include CHANGELOG.md 2 | include LICENSE 3 | include README.md 4 | include requirements.txt 5 | include svgcheck/run.py 6 | include svgcheck/checksvg.py 7 | include svgcheck/word_properties.py 8 | include svgcheck/run.py 9 | include svgcheck/__init__.py 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | SVGCHECK 4 | 5 | [![Release](https://img.shields.io/github/release/ietf-tools/svgcheck.svg?style=flat&maxAge=360)](https://github.com/ietf-tools/svgcheck/releases) 6 | [![License](https://img.shields.io/github/license/ietf-tools/svgcheck)](https://github.com/ietf-tools/svgcheck/blob/main/LICENSE) 7 | [![PyPI - Version](https://img.shields.io/pypi/v/svgcheck)](https://pypi.org/project/svgcheck/) 8 | [![PyPI - Status](https://img.shields.io/pypi/status/svgcheck)](https://pypi.org/project/svgcheck/) 9 | [![PyPI - Format](https://img.shields.io/pypi/format/svgcheck)](https://pypi.org/project/svgcheck/) 10 | 11 | ##### Check SVG against RFC schema 12 | 13 |
14 | 15 | - [Changelog](https://github.com/ietf-tools/svgcheck/blob/main/CHANGELOG.md) 16 | - [Contributing](https://github.com/ietf-tools/.github/blob/main/CONTRIBUTING.md) 17 | 18 | --- 19 | 20 | This program takes an XML file containing an SVG or an RFC document. It then compares all of the SVG elements with the schema defined in the document with [RFC 7996 bis](https://datatracker.ietf.org/doc/draft-7996-bis). The program has the option of modifying and writing out a version of the input that passes the defined schema. 21 | 22 | 23 | ## Usage 24 | 25 | `svgcheck` accepts a single XML document as input and optionally outputs a modified version of the document. 26 | 27 | ### Basic Usage 28 | 29 | ```sh 30 | svgcheck [options] SOURCE 31 | ``` 32 | 33 | ### Options 34 | 35 | | Short | Long | Description | 36 | |---------------|------------------|-----------------------------------------------------------------------------------| 37 | | `-C` | `--clear-cache` | purge the cache and exit | 38 | | `-h` | `--help` | show the help message and exit | 39 | | `-N` | `--no-network` | don't use the network to resolve references | 40 | | `-q` | `--quiet` | dont print anything | 41 | | `-r` | `--repair` | repair the SVG so it meets RFC 7966, only emit the new file if repairs are needed | 42 | | `-a` | `--always-emit` | repair the SVG file if needed, emit the file even if no repairs are needed | 43 | | `-v` | `--verbose` | print extra information | 44 | | `-V` | `--version` | display the version number and exit | 45 | | `-d RNG` | `--rng=RNG` | specify an alternate RNG file | 46 | | `-o FILENAME` | `--out=FILENAME` | specify an output filename, default to stdout | 47 | | `-g` | `--grey-scale` | use a grey scale heuristic to determine what is white | 48 | | | `--grey-level` | cut off level between black and white | 49 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools>=61.0", "wheel"] 3 | build-backend = "setuptools.build_meta" 4 | 5 | [project] 6 | name = "svgcheck" 7 | dynamic = ["version"] 8 | authors = [ 9 | {name = "IETF Tools", email = "tools-help@ietf.org"}, 10 | ] 11 | description = "Verify that an svg file is compliant with the RFC standards." 12 | keywords = ["svg", "validation", "rfc", "internet-draft", "xml", "xml2rfc"] 13 | readme = "README.md" 14 | license = "BSD-3-Clause" 15 | license-files = ["LICENSE"] 16 | requires-python = ">=3.9" 17 | classifiers = [ 18 | "Development Status :: 5 - Production/Stable", 19 | "Programming Language :: Python :: 3.9", 20 | "Programming Language :: Python :: 3.10", 21 | "Programming Language :: Python :: 3.11", 22 | "Programming Language :: Python :: 3.12", 23 | "Programming Language :: Python :: 3.13", 24 | ] 25 | dependencies = [ 26 | "lxml>=5.3.0", 27 | "xml2rfc>=3.24.0", 28 | ] 29 | 30 | [project.urls] 31 | homepage = "https://github.com/ietf-tools/svgcheck" 32 | source = "https://github.com/ietf-tools/svgcheck" 33 | issues = "https://github.com/ietf-tools/svgcheck/issues" 34 | changelog = "https://github.com/ietf-tools/svgcheck/blob/main/CHANGELOG.md" 35 | releasenotes = "https://github.com/ietf-tools/svgcheck/releases" 36 | 37 | [project.optional-dependencies] 38 | tests = [ 39 | "coverage", 40 | "pycodestyle", 41 | "pyflakes>=0.8.1", 42 | "tox", 43 | ] 44 | 45 | [project.scripts] 46 | svgcheck = "svgcheck.run:main" 47 | 48 | [tool.setuptools] 49 | include-package-data = true 50 | 51 | [tool.setuptools.dynamic] 52 | version = {attr = "svgcheck.__version__"} 53 | 54 | [tool.setuptools.packages.find] 55 | include = ["svgcheck"] 56 | -------------------------------------------------------------------------------- /svgcheck/.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | branch=True 3 | omit = 4 | */rfctools_common/* 5 | parallel=True 6 | -------------------------------------------------------------------------------- /svgcheck/Results/DrawBerry-sample-2.out: -------------------------------------------------------------------------------- 1 | Tests/DrawBerry-sample-2.svg:14: Element 'g' does not allow attributes with namespace 'http://www.inkscape.org/namespaces/inkscape' 2 | Tests/DrawBerry-sample-2.svg:14: Element 'g' does not allow attributes with namespace 'http://www.inkscape.org/namespaces/inkscape' 3 | Tests/DrawBerry-sample-2.svg:16: Style property 'fill' promoted to attribute 4 | Tests/DrawBerry-sample-2.svg:16: Style property 'stroke' promoted to attribute 5 | Tests/DrawBerry-sample-2.svg:16: Style property 'stroke-width' promoted to attribute 6 | Tests/DrawBerry-sample-2.svg:16: Style property 'stroke-opacity' promoted to attribute 7 | Tests/DrawBerry-sample-2.svg:16: Style property 'stroke-linecap' promoted to attribute 8 | Tests/DrawBerry-sample-2.svg:16: Style property 'stroke-linejoin' promoted to attribute 9 | Tests/DrawBerry-sample-2.svg:18: Style property 'fill' promoted to attribute 10 | Tests/DrawBerry-sample-2.svg:18: Style property 'stroke' promoted to attribute 11 | Tests/DrawBerry-sample-2.svg:18: Style property 'stroke-width' promoted to attribute 12 | Tests/DrawBerry-sample-2.svg:18: Style property 'stroke-opacity' promoted to attribute 13 | Tests/DrawBerry-sample-2.svg:18: Style property 'stroke-linecap' promoted to attribute 14 | Tests/DrawBerry-sample-2.svg:18: Style property 'stroke-linejoin' promoted to attribute 15 | Tests/DrawBerry-sample-2.svg:20: Style property 'fill' promoted to attribute 16 | Tests/DrawBerry-sample-2.svg:20: Style property 'stroke' promoted to attribute 17 | Tests/DrawBerry-sample-2.svg:22: Style property 'fill' promoted to attribute 18 | Tests/DrawBerry-sample-2.svg:22: Style property 'stroke' promoted to attribute 19 | Tests/DrawBerry-sample-2.svg:24: Style property 'fill' promoted to attribute 20 | Tests/DrawBerry-sample-2.svg:24: Style property 'stroke' promoted to attribute 21 | Tests/DrawBerry-sample-2.svg:26: Style property 'fill' promoted to attribute 22 | Tests/DrawBerry-sample-2.svg:26: Style property 'stroke' promoted to attribute 23 | -------------------------------------------------------------------------------- /svgcheck/Results/DrawBerry-sample-2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /svgcheck/Results/IETF-test.out: -------------------------------------------------------------------------------- 1 | Tests/IETF-test.svg:4: Style property 'stroke' promoted to attribute 2 | Tests/IETF-test.svg:4: Style property 'stroke-width' promoted to attribute 3 | Tests/IETF-test.svg:4: Style property 'fill' promoted to attribute 4 | Tests/IETF-test.svg:4: The attribute 'stroke' does not allow the value 'rgb(0,0,0)', replaced with 'black' 5 | Tests/IETF-test.svg:5: Style property 'fill' promoted to attribute 6 | Tests/IETF-test.svg:9: Style property 'stroke' promoted to attribute 7 | Tests/IETF-test.svg:9: Style property 'stroke-width' promoted to attribute 8 | Tests/IETF-test.svg:9: Style property 'fill' promoted to attribute 9 | Tests/IETF-test.svg:9: The attribute 'stroke' does not allow the value 'rgb(0,0,0)', replaced with 'black' 10 | Tests/IETF-test.svg:10: Style property 'fill' promoted to attribute 11 | Tests/IETF-test.svg:14: Style property 'stroke' promoted to attribute 12 | Tests/IETF-test.svg:14: Style property 'fill' promoted to attribute 13 | Tests/IETF-test.svg:17: Style property 'font-family' promoted to attribute 14 | Tests/IETF-test.svg:17: Style property 'font-size' promoted to attribute 15 | Tests/IETF-test.svg:17: Style property 'font-weight' promoted to attribute 16 | Tests/IETF-test.svg:17: The attribute 'font-family' does not allow the value 'Arial embedded', replaced with 'sans-serif' 17 | Tests/IETF-test.svg:18: Style property 'stroke' promoted to attribute 18 | Tests/IETF-test.svg:18: Style property 'fill' promoted to attribute 19 | Tests/IETF-test.svg:18: The attribute 'fill' does not allow the value 'rgb(0,0,0)', replaced with 'black' 20 | -------------------------------------------------------------------------------- /svgcheck/Results/IETF-test.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | Updated Scenario Diagram 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /svgcheck/Results/circle.out: -------------------------------------------------------------------------------- 1 | Tests/circle.svg:2: The attribute 'fill' does not allow the value 'red', replaced with 'black' 2 | -------------------------------------------------------------------------------- /svgcheck/Results/circle.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /svgcheck/Results/clear-cache.err: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ietf-tools/svgcheck/d96180b95c9ef561899fbf96a8830572873e1594/svgcheck/Results/clear-cache.err -------------------------------------------------------------------------------- /svgcheck/Results/clear-cache.out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ietf-tools/svgcheck/d96180b95c9ef561899fbf96a8830572873e1594/svgcheck/Results/clear-cache.out -------------------------------------------------------------------------------- /svgcheck/Results/colors.err: -------------------------------------------------------------------------------- 1 | Tests/colors.svg:2: The attribute 'fill' does not allow the value 'red', replaced with 'black' 2 | Tests/colors.svg:3: The attribute 'fill' does not allow the value 'rgb(0,0,0)', replaced with 'black' 3 | Tests/colors.svg:4: The attribute 'fill' does not allow the value 'rgb(255,255,255)', replaced with 'white' 4 | Tests/colors.svg:5: The attribute 'fill' does not allow the value 'rgb(128,128,182)', replaced with 'black' 5 | Tests/colors.svg:6: The attribute 'fill' does not allow the value '#fff', replaced with 'white' 6 | Tests/colors.svg:7: The attribute 'fill' does not allow the value '#aaa', replaced with 'black' 7 | Tests/colors.svg:8: The attribute 'fill' does not allow the value '#000', replaced with 'black' 8 | Tests/colors.svg:11: The attribute 'fill' does not allow the value '#0a0a0a', replaced with 'black' 9 | Tests/colors.svg:12: The attribute 'fill' does not allow the value 'grey', replaced with 'black' 10 | Tests/colors.svg:13: The attribute 'fill' does not allow the value 'gray', replaced with 'black' 11 | Tests/colors.svg:16: The attribute 'fill' does not allow the value 'unknown', replaced with 'black' 12 | Tests/colors.svg:17: The attribute 'fill' does not allow the value 'rgb(100%,100%,100%)', replaced with 'white' 13 | ERROR: File does not conform to SVG requirements 14 | -------------------------------------------------------------------------------- /svgcheck/Results/colors.out: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /svgcheck/Results/dia-sample-svg.out: -------------------------------------------------------------------------------- 1 | Tests/dia-sample-svg.svg:3: Style property 'fill' promoted to attribute 2 | Tests/dia-sample-svg.svg:3: Style property 'text-anchor' promoted to attribute 3 | Tests/dia-sample-svg.svg:3: Style property 'font-family' promoted to attribute 4 | Tests/dia-sample-svg.svg:3: Style property 'font-style' promoted to attribute 5 | Tests/dia-sample-svg.svg:3: Style property 'font-weight' promoted to attribute 6 | Tests/dia-sample-svg.svg:3: The attribute 'fill' does not allow the value '#00FF00', replaced with 'black' 7 | Tests/dia-sample-svg.svg:7: Style property 'fill' promoted to attribute 8 | Tests/dia-sample-svg.svg:8: Style property 'fill' promoted to attribute 9 | Tests/dia-sample-svg.svg:8: Style property 'fill-opacity' promoted to attribute 10 | Tests/dia-sample-svg.svg:8: Style property 'stroke-width' promoted to attribute 11 | Tests/dia-sample-svg.svg:8: Style property 'stroke' promoted to attribute 12 | Tests/dia-sample-svg.svg:11: Style property 'fill' promoted to attribute 13 | Tests/dia-sample-svg.svg:11: The attribute 'fill' does not allow the value '#ff00ff', replaced with 'black' 14 | Tests/dia-sample-svg.svg:12: Style property 'fill' promoted to attribute 15 | Tests/dia-sample-svg.svg:12: Style property 'fill-opacity' promoted to attribute 16 | Tests/dia-sample-svg.svg:12: Style property 'stroke-width' promoted to attribute 17 | Tests/dia-sample-svg.svg:12: Style property 'stroke' promoted to attribute 18 | Tests/dia-sample-svg.svg:15: Style property 'fill' promoted to attribute 19 | Tests/dia-sample-svg.svg:15: Style property 'fill-opacity' promoted to attribute 20 | Tests/dia-sample-svg.svg:15: Style property 'stroke-width' promoted to attribute 21 | Tests/dia-sample-svg.svg:15: Style property 'stroke' promoted to attribute 22 | Tests/dia-sample-svg.svg:16: Style property 'fill' promoted to attribute 23 | Tests/dia-sample-svg.svg:16: The attribute 'fill' does not allow the value '#FF0000', replaced with 'black' 24 | Tests/dia-sample-svg.svg:17: Style property 'fill' promoted to attribute 25 | Tests/dia-sample-svg.svg:17: Style property 'fill-opacity' promoted to attribute 26 | Tests/dia-sample-svg.svg:17: Style property 'stroke-width' promoted to attribute 27 | Tests/dia-sample-svg.svg:17: Style property 'stroke' promoted to attribute 28 | Tests/dia-sample-svg.svg:20: Style property 'fill' promoted to attribute 29 | Tests/dia-sample-svg.svg:20: Style property 'fill-opacity' promoted to attribute 30 | Tests/dia-sample-svg.svg:20: Style property 'stroke-width' promoted to attribute 31 | Tests/dia-sample-svg.svg:20: Style property 'stroke' promoted to attribute 32 | Tests/dia-sample-svg.svg:21: Style property 'fill' promoted to attribute 33 | Tests/dia-sample-svg.svg:22: Style property 'fill' promoted to attribute 34 | Tests/dia-sample-svg.svg:22: Style property 'fill-opacity' promoted to attribute 35 | Tests/dia-sample-svg.svg:22: Style property 'stroke-width' promoted to attribute 36 | Tests/dia-sample-svg.svg:22: Style property 'stroke' promoted to attribute 37 | Tests/dia-sample-svg.svg:24: Style property 'fill' promoted to attribute 38 | Tests/dia-sample-svg.svg:24: Style property 'text-anchor' promoted to attribute 39 | Tests/dia-sample-svg.svg:24: Style property 'font-family' promoted to attribute 40 | Tests/dia-sample-svg.svg:24: Style property 'font-style' promoted to attribute 41 | Tests/dia-sample-svg.svg:24: Style property 'font-weight' promoted to attribute 42 | Tests/dia-sample-svg.svg:27: Style property 'fill' promoted to attribute 43 | Tests/dia-sample-svg.svg:27: Style property 'text-anchor' promoted to attribute 44 | Tests/dia-sample-svg.svg:27: Style property 'font-family' promoted to attribute 45 | Tests/dia-sample-svg.svg:27: Style property 'font-style' promoted to attribute 46 | Tests/dia-sample-svg.svg:27: Style property 'font-weight' promoted to attribute 47 | Tests/dia-sample-svg.svg:30: Style property 'fill' promoted to attribute 48 | Tests/dia-sample-svg.svg:30: Style property 'text-anchor' promoted to attribute 49 | Tests/dia-sample-svg.svg:30: Style property 'font-family' promoted to attribute 50 | Tests/dia-sample-svg.svg:30: Style property 'font-style' promoted to attribute 51 | Tests/dia-sample-svg.svg:30: Style property 'font-weight' promoted to attribute 52 | Tests/dia-sample-svg.svg:34: Style property 'fill' promoted to attribute 53 | Tests/dia-sample-svg.svg:34: Style property 'fill-opacity' promoted to attribute 54 | Tests/dia-sample-svg.svg:34: Style property 'stroke-width' promoted to attribute 55 | Tests/dia-sample-svg.svg:34: Style property 'stroke' promoted to attribute 56 | Tests/dia-sample-svg.svg:35: Style property 'fill' promoted to attribute 57 | Tests/dia-sample-svg.svg:36: Style property 'fill' promoted to attribute 58 | Tests/dia-sample-svg.svg:36: Style property 'fill-opacity' promoted to attribute 59 | Tests/dia-sample-svg.svg:36: Style property 'stroke-width' promoted to attribute 60 | Tests/dia-sample-svg.svg:36: Style property 'stroke' promoted to attribute 61 | Tests/dia-sample-svg.svg:38: Style property 'fill' promoted to attribute 62 | Tests/dia-sample-svg.svg:38: Style property 'text-anchor' promoted to attribute 63 | Tests/dia-sample-svg.svg:38: Style property 'font-family' promoted to attribute 64 | Tests/dia-sample-svg.svg:38: Style property 'font-style' promoted to attribute 65 | Tests/dia-sample-svg.svg:38: Style property 'font-weight' promoted to attribute 66 | Tests/dia-sample-svg.svg:41: Style property 'fill' promoted to attribute 67 | Tests/dia-sample-svg.svg:41: Style property 'text-anchor' promoted to attribute 68 | Tests/dia-sample-svg.svg:41: Style property 'font-family' promoted to attribute 69 | Tests/dia-sample-svg.svg:41: Style property 'font-style' promoted to attribute 70 | Tests/dia-sample-svg.svg:41: Style property 'font-weight' promoted to attribute 71 | Tests/dia-sample-svg.svg:44: Style property 'fill' promoted to attribute 72 | Tests/dia-sample-svg.svg:44: Style property 'text-anchor' promoted to attribute 73 | Tests/dia-sample-svg.svg:44: Style property 'font-family' promoted to attribute 74 | Tests/dia-sample-svg.svg:44: Style property 'font-style' promoted to attribute 75 | Tests/dia-sample-svg.svg:44: Style property 'font-weight' promoted to attribute 76 | -------------------------------------------------------------------------------- /svgcheck/Results/dia-sample-svg.svg: -------------------------------------------------------------------------------- 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 | original 29 | 30 | 31 | canonical 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | nit 40 | 41 | 42 | edit 43 | 44 | 45 | nit (no-op) 46 | 47 | 48 | -------------------------------------------------------------------------------- /svgcheck/Results/empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ietf-tools/svgcheck/d96180b95c9ef561899fbf96a8830572873e1594/svgcheck/Results/empty -------------------------------------------------------------------------------- /svgcheck/Results/example-dot.out: -------------------------------------------------------------------------------- 1 | Tests/example-dot.svg:15: The attribute 'font-family' does not allow the value 'Times,serif', replaced with 'serif' 2 | Tests/example-dot.svg:20: The attribute 'font-family' does not allow the value 'Times,serif', replaced with 'serif' 3 | Tests/example-dot.svg:24: The attribute 'stroke' does not allow the value 'red', replaced with 'black' 4 | Tests/example-dot.svg:29: The attribute 'font-family' does not allow the value 'Times,serif', replaced with 'serif' 5 | Tests/example-dot.svg:37: The attribute 'stroke' does not allow the value 'red', replaced with 'black' 6 | Tests/example-dot.svg:42: The attribute 'font-family' does not allow the value 'Times,serif', replaced with 'serif' 7 | Tests/example-dot.svg:50: The attribute 'stroke' does not allow the value 'red', replaced with 'black' 8 | Tests/example-dot.svg:55: The attribute 'font-family' does not allow the value 'Times,serif', replaced with 'serif' 9 | Tests/example-dot.svg:64: The attribute 'font-family' does not allow the value 'Times,serif', replaced with 'serif' 10 | Tests/example-dot.svg:68: The attribute 'stroke' does not allow the value 'red', replaced with 'black' 11 | -------------------------------------------------------------------------------- /svgcheck/Results/example-dot.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | 9 | %3 10 | 11 | 12 | a 13 | 14 | a 15 | 16 | 17 | b 18 | 19 | b 20 | 21 | 22 | a--b 23 | 24 | 25 | 26 | d 27 | 28 | d 29 | 30 | 31 | a--d 32 | 33 | 34 | 35 | b--d 36 | 37 | 38 | 39 | c 40 | 41 | c 42 | 43 | 44 | b--c 45 | 46 | 47 | 48 | d--c 49 | 50 | 51 | 52 | e 53 | 54 | e 55 | 56 | 57 | d--e 58 | 59 | 60 | 61 | f 62 | 63 | f 64 | 65 | 66 | c--f 67 | 68 | 69 | 70 | e--f 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /svgcheck/Results/full-tiny-02.err: -------------------------------------------------------------------------------- 1 | INFO: File conforms to SVG requirements. 2 | -------------------------------------------------------------------------------- /svgcheck/Results/full-tiny-02.out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ietf-tools/svgcheck/d96180b95c9ef561899fbf96a8830572873e1594/svgcheck/Results/full-tiny-02.out -------------------------------------------------------------------------------- /svgcheck/Results/full-tiny.out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ietf-tools/svgcheck/d96180b95c9ef561899fbf96a8830572873e1594/svgcheck/Results/full-tiny.out -------------------------------------------------------------------------------- /svgcheck/Results/full-tiny.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Dummy Text goes here 4 | Dummy Text goes here 5 | 6 | -------------------------------------------------------------------------------- /svgcheck/Results/good.err: -------------------------------------------------------------------------------- 1 | INFO: File conforms to SVG requirements. 2 | -------------------------------------------------------------------------------- /svgcheck/Results/httpbis-proxy20-fig6.out: -------------------------------------------------------------------------------- 1 | Tests/httpbis-proxy20-fig6.svg:2: The attribute 'fill' does not allow the value 'grey', replaced with 'black' 2 | Tests/httpbis-proxy20-fig6.svg:2: The attribute 'stroke' does not allow the value 'grey', replaced with 'black' 3 | Tests/httpbis-proxy20-fig6.svg:2: The attribute 'fill' does not allow the value 'grey', replaced with 'black' 4 | Tests/httpbis-proxy20-fig6.svg:2: The attribute 'stroke' does not allow the value 'grey', replaced with 'black' 5 | -------------------------------------------------------------------------------- /svgcheck/Results/httpbis-proxy20-fig6.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | user-agent 9 | 10 | Proxy 11 | 12 | Server 13 | 14 | 15 | 16 | 17 | (1) TLS ClientHello 18 | 19 | (ALPN ProtocolName: http) 20 | 21 | 22 | 23 | (2) TLS Error 24 | 25 | (Proxy Cert) 26 | 27 | 28 | 29 | 30 | (inform user of the SecureProxy) 31 | 32 | 33 | 34 | 35 | (3) TLS ClientHello 36 | 37 | 38 | 39 | (4) ServerHello 40 | 41 | HTTP2.0 42 | 43 | 44 | 45 | 46 | (5) stream(X) GET 47 | 48 | 49 | 50 | (6) TLS ClientHello 51 | 52 | 53 | 54 | TLS ServerHello 55 | 56 | HTTP2.0 57 | 58 | 59 | 60 | 61 | (7) stream(Z) GET 62 | 63 | 64 | 65 | (8) stream(Z) 200 OK 66 | 67 | 68 | 69 | (9) stream(X) 200 OK 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /svgcheck/Results/malformed.out: -------------------------------------------------------------------------------- 1 | Tests/malformed.svg:2: The attribute 'fill' does not allow the value 'red', replaced with 'black' 2 | Tests/malformed.svg:3: Malformed field '['malformed']' in style attribute found. Field removed. 3 | Tests/malformed.svg:4: Style property 'foobar' removed 4 | Tests/malformed.svg:5: Style property 'foobar' removed 5 | Tests/malformed.svg:7: The element 'circle' is not allowed as a child of 'desc' 6 | Tests/malformed.svg:9: The namespace http://ietf.org/namespaces/foobar is not permitted for svg elements. 7 | Tests/malformed.svg:10: The element 'notreal' is not allowed as a child of 'svg' 8 | -------------------------------------------------------------------------------- /svgcheck/Results/malformed.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | This tries to cover all of the edge cases 5 | This tries to cover all of the edge cases 6 | 7 | -------------------------------------------------------------------------------- /svgcheck/Results/rfc-01.err: -------------------------------------------------------------------------------- 1 | Tests/rfc.xml:24: The attribute 'fill' does not allow the value 'red', replaced with 'black' 2 | ERROR: File does not conform to SVG requirements 3 | -------------------------------------------------------------------------------- /svgcheck/Results/rfc-01.out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ietf-tools/svgcheck/d96180b95c9ef561899fbf96a8830572873e1594/svgcheck/Results/rfc-01.out -------------------------------------------------------------------------------- /svgcheck/Results/rfc-01.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Example w/ SVG files 5 | 6 |
7 | ietf@augustcellars.com 8 |
9 |
10 | 11 | 12 | 13 | abstract 14 | 15 | 16 |
17 | 18 |
19 | Introduction 20 | 21 | Put in some text followed by a picture. 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | And pull in the same picture in a different way. 30 | 31 | 32 | 33 | 34 |
35 |
36 | 37 |
38 | -------------------------------------------------------------------------------- /svgcheck/Results/rfc-02.err: -------------------------------------------------------------------------------- 1 | Tests/rfc.xml:24: The attribute 'fill' does not allow the value 'red', replaced with 'black' 2 | ERROR: File does not conform to SVG requirements 3 | -------------------------------------------------------------------------------- /svgcheck/Results/rfc-02.out: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Example w/ SVG files 5 | 6 |
7 | ietf@augustcellars.com 8 |
9 |
10 | 11 | 12 | 13 | abstract 14 | 15 | 16 |
17 | 18 |
19 | Introduction 20 | 21 | Put in some text followed by a picture. 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | And pull in the same picture in a different way. 30 | 31 | 32 | 33 | 34 |
35 |
36 | 37 |
38 | -------------------------------------------------------------------------------- /svgcheck/Results/rfc-03.err: -------------------------------------------------------------------------------- 1 | ERROR: File does not conform to SVG requirements 2 | -------------------------------------------------------------------------------- /svgcheck/Results/rfc-03.out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ietf-tools/svgcheck/d96180b95c9ef561899fbf96a8830572873e1594/svgcheck/Results/rfc-03.out -------------------------------------------------------------------------------- /svgcheck/Results/rfc-svg.err: -------------------------------------------------------------------------------- 1 | INFO: File conforms to SVG requirements. 2 | -------------------------------------------------------------------------------- /svgcheck/Results/rfc-svg.out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ietf-tools/svgcheck/d96180b95c9ef561899fbf96a8830572873e1594/svgcheck/Results/rfc-svg.out -------------------------------------------------------------------------------- /svgcheck/Results/rgb.out: -------------------------------------------------------------------------------- 1 | Tests/rgb.svg:5: The attribute 'stroke' does not allow the value 'BLACK', replaced with 'black' 2 | Tests/rgb.svg:5: The attribute 'fill' does not allow the value 'WHITE', replaced with 'black' 3 | Tests/rgb.svg:6: The attribute 'stroke' does not allow the value '#000', replaced with 'black' 4 | Tests/rgb.svg:6: The attribute 'fill' does not allow the value '#fff', replaced with 'white' 5 | Tests/rgb.svg:7: The attribute 'stroke' does not allow the value '#000', replaced with 'black' 6 | Tests/rgb.svg:7: The attribute 'fill' does not allow the value '#fff', replaced with 'white' 7 | Tests/rgb.svg:8: The attribute 'stroke' does not allow the value 'rgb(0, 0, 0)', replaced with 'black' 8 | Tests/rgb.svg:8: The attribute 'fill' does not allow the value 'rgb(20%, 20%, 20%)', replaced with 'black' 9 | -------------------------------------------------------------------------------- /svgcheck/Results/rgb.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /svgcheck/Results/utf8-2.err: -------------------------------------------------------------------------------- 1 | INFO: File conforms to SVG requirements. 2 | -------------------------------------------------------------------------------- /svgcheck/Results/utf8-2.out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ietf-tools/svgcheck/d96180b95c9ef561899fbf96a8830572873e1594/svgcheck/Results/utf8-2.out -------------------------------------------------------------------------------- /svgcheck/Results/utf8-2.svg: -------------------------------------------------------------------------------- 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 | <number> 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 | Updated Scenario Diagram 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 | IPv6 Clients in the Internet 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | HTTPserver 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | L3/L4 balancer 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | HTTP proxy 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | Ingress router 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | TLS proxy 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | HTTP proxy 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | TLS proxy 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | L3/L4 balancer 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | HTTPserver 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | HTTPserver 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | HTTPserver 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | HTTPserver 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | DNS-based ←load splitting→ 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | Ingress router 352 | 353 | 354 | 355 | 356 | 357 | 358 | Possible flow label use 359 | 360 | 361 | 362 | 363 | 364 | 365 | Possible flow label use 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | -------------------------------------------------------------------------------- /svgcheck/Results/utf8.err: -------------------------------------------------------------------------------- 1 | Tests/utf8.svg:5: The element 'clipPath' is not allowed as a child of 'defs' 2 | Tests/utf8.svg:8: The element 'clipPath' is not allowed as a child of 'defs' 3 | Tests/utf8.svg:13: Element 'g' does not allow attributes with namespace 'http://xml.openoffice.org/svg/export' 4 | Tests/utf8.svg:13: Element 'g' does not allow attributes with namespace 'http://xml.openoffice.org/svg/export' 5 | Tests/utf8.svg:14: Element 'g' does not allow attributes with namespace 'http://xml.openoffice.org/svg/export' 6 | Tests/utf8.svg:14: Element 'g' does not allow attributes with namespace 'http://xml.openoffice.org/svg/export' 7 | Tests/utf8.svg:14: Element 'g' does not allow attributes with namespace 'http://xml.openoffice.org/svg/export' 8 | Tests/utf8.svg:14: Element 'g' does not allow attributes with namespace 'http://xml.openoffice.org/svg/export' 9 | Tests/utf8.svg:14: Element 'g' does not allow attributes with namespace 'http://xml.openoffice.org/svg/export' 10 | Tests/utf8.svg:15: Element 'g' does not allow attributes with namespace 'http://xml.openoffice.org/svg/export' 11 | Tests/utf8.svg:15: Element 'g' does not allow attributes with namespace 'http://xml.openoffice.org/svg/export' 12 | Tests/utf8.svg:15: Element 'g' does not allow attributes with namespace 'http://xml.openoffice.org/svg/export' 13 | Tests/utf8.svg:15: Element 'g' does not allow attributes with namespace 'http://xml.openoffice.org/svg/export' 14 | Tests/utf8.svg:15: Element 'g' does not allow attributes with namespace 'http://xml.openoffice.org/svg/export' 15 | Tests/utf8.svg:20: The element 'font' is not allowed as a child of 'defs' 16 | Tests/utf8.svg:72: The element 'font' is not allowed as a child of 'defs' 17 | Tests/utf8.svg:79: The element 'font' is not allowed as a child of 'defs' 18 | Tests/utf8.svg:86: Element 'g' does not allow attributes with namespace 'http://xml.openoffice.org/svg/export' 19 | Tests/utf8.svg:86: Element 'g' does not allow attributes with namespace 'http://xml.openoffice.org/svg/export' 20 | Tests/utf8.svg:122: Element 'g' does not allow attributes with namespace 'http://xml.openoffice.org/svg/export' 21 | Tests/utf8.svg:126: Element 'g' does not allow attributes with namespace 'http://xml.openoffice.org/svg/export' 22 | Tests/utf8.svg:128: The attribute 'fill' does not allow the value 'rgb(255,255,255)', replaced with 'white' 23 | Tests/utf8.svg:131: Element 'g' does not allow attributes with namespace 'http://xml.openoffice.org/svg/export' 24 | Tests/utf8.svg:134: The attribute 'font-family' does not allow the value 'Arial, sans-serif', replaced with 'sans-serif' 25 | Tests/utf8.svg:134: The attribute 'fill' does not allow the value 'rgb(255,255,255)', replaced with 'white' 26 | Tests/utf8.svg:142: The element 'g' does not allow the attribute 'clip-path', attribute to be removed. 27 | Tests/utf8.svg:143: Element 'g' does not allow attributes with namespace 'http://xml.openoffice.org/svg/export' 28 | Tests/utf8.svg:150: The element 'g' does not allow the attribute 'clip-path', attribute to be removed. 29 | Tests/utf8.svg:151: Element 'g' does not allow attributes with namespace 'http://xml.openoffice.org/svg/export' 30 | Tests/utf8.svg:155: The attribute 'stroke' does not allow the value 'rgb(0,0,0)', replaced with 'black' 31 | Tests/utf8.svg:161: The attribute 'stroke' does not allow the value 'rgb(0,0,0)', replaced with 'black' 32 | Tests/utf8.svg:167: The attribute 'stroke' does not allow the value 'rgb(0,0,0)', replaced with 'black' 33 | Tests/utf8.svg:173: The attribute 'stroke' does not allow the value 'rgb(0,0,0)', replaced with 'black' 34 | Tests/utf8.svg:179: The attribute 'stroke' does not allow the value 'rgb(0,0,0)', replaced with 'black' 35 | Tests/utf8.svg:185: The attribute 'stroke' does not allow the value 'rgb(0,0,0)', replaced with 'black' 36 | Tests/utf8.svg:191: The attribute 'stroke' does not allow the value 'rgb(0,0,0)', replaced with 'black' 37 | Tests/utf8.svg:197: The attribute 'stroke' does not allow the value 'rgb(0,0,0)', replaced with 'black' 38 | Tests/utf8.svg:203: The attribute 'stroke' does not allow the value 'rgb(0,0,0)', replaced with 'black' 39 | Tests/utf8.svg:209: The attribute 'stroke' does not allow the value 'rgb(0,0,0)', replaced with 'black' 40 | Tests/utf8.svg:215: The attribute 'stroke' does not allow the value 'rgb(0,0,0)', replaced with 'black' 41 | Tests/utf8.svg:221: The attribute 'stroke' does not allow the value 'rgb(0,0,0)', replaced with 'black' 42 | Tests/utf8.svg:227: The attribute 'stroke' does not allow the value 'rgb(0,0,0)', replaced with 'black' 43 | Tests/utf8.svg:233: The attribute 'font-family' does not allow the value 'Arial, sans-serif', replaced with 'sans-serif' 44 | Tests/utf8.svg:233: The attribute 'fill' does not allow the value 'rgb(0,0,0)', replaced with 'black' 45 | Tests/utf8.svg:239: The attribute 'stroke' does not allow the value 'rgb(128,128,128)', replaced with 'black' 46 | Tests/utf8.svg:240: The attribute 'stroke' does not allow the value 'rgb(128,128,128)', replaced with 'black' 47 | Tests/utf8.svg:241: The attribute 'stroke' does not allow the value 'rgb(128,128,128)', replaced with 'black' 48 | Tests/utf8.svg:242: The attribute 'stroke' does not allow the value 'rgb(128,128,128)', replaced with 'black' 49 | Tests/utf8.svg:243: The attribute 'stroke' does not allow the value 'rgb(128,128,128)', replaced with 'black' 50 | Tests/utf8.svg:244: The attribute 'stroke' does not allow the value 'rgb(128,128,128)', replaced with 'black' 51 | Tests/utf8.svg:245: The attribute 'stroke' does not allow the value 'rgb(128,128,128)', replaced with 'black' 52 | Tests/utf8.svg:246: The attribute 'stroke' does not allow the value 'rgb(128,128,128)', replaced with 'black' 53 | Tests/utf8.svg:247: The attribute 'stroke' does not allow the value 'rgb(128,128,128)', replaced with 'black' 54 | Tests/utf8.svg:248: The attribute 'stroke' does not allow the value 'rgb(128,128,128)', replaced with 'black' 55 | Tests/utf8.svg:249: The attribute 'stroke' does not allow the value 'rgb(128,128,128)', replaced with 'black' 56 | Tests/utf8.svg:250: The attribute 'stroke' does not allow the value 'rgb(128,128,128)', replaced with 'black' 57 | Tests/utf8.svg:251: The attribute 'stroke' does not allow the value 'rgb(0,0,0)', replaced with 'black' 58 | Tests/utf8.svg:252: The attribute 'stroke' does not allow the value 'rgb(0,0,0)', replaced with 'black' 59 | Tests/utf8.svg:253: The attribute 'stroke' does not allow the value 'rgb(0,0,0)', replaced with 'black' 60 | Tests/utf8.svg:254: The attribute 'stroke' does not allow the value 'rgb(0,0,0)', replaced with 'black' 61 | Tests/utf8.svg:255: The attribute 'stroke' does not allow the value 'rgb(0,0,0)', replaced with 'black' 62 | Tests/utf8.svg:256: The attribute 'stroke' does not allow the value 'rgb(0,0,0)', replaced with 'black' 63 | Tests/utf8.svg:257: The attribute 'stroke' does not allow the value 'rgb(0,0,0)', replaced with 'black' 64 | Tests/utf8.svg:258: The attribute 'stroke' does not allow the value 'rgb(0,0,0)', replaced with 'black' 65 | Tests/utf8.svg:259: The attribute 'stroke' does not allow the value 'rgb(0,0,0)', replaced with 'black' 66 | Tests/utf8.svg:260: The attribute 'stroke' does not allow the value 'rgb(0,0,0)', replaced with 'black' 67 | Tests/utf8.svg:261: The attribute 'stroke' does not allow the value 'rgb(0,0,0)', replaced with 'black' 68 | Tests/utf8.svg:262: The attribute 'stroke' does not allow the value 'rgb(0,0,0)', replaced with 'black' 69 | Tests/utf8.svg:268: The attribute 'font-family' does not allow the value 'Arial, sans-serif', replaced with 'sans-serif' 70 | Tests/utf8.svg:268: The attribute 'fill' does not allow the value 'rgb(0,0,0)', replaced with 'black' 71 | Tests/utf8.svg:274: The attribute 'fill' does not allow the value 'rgb(255,255,255)', replaced with 'white' 72 | Tests/utf8.svg:275: The attribute 'stroke' does not allow the value 'rgb(0,0,0)', replaced with 'black' 73 | Tests/utf8.svg:276: The attribute 'font-family' does not allow the value 'Arial, sans-serif', replaced with 'sans-serif' 74 | Tests/utf8.svg:276: The attribute 'fill' does not allow the value 'rgb(0,0,0)', replaced with 'black' 75 | Tests/utf8.svg:276: The attribute 'fill' does not allow the value 'rgb(0,0,0)', replaced with 'black' 76 | Tests/utf8.svg:282: The attribute 'fill' does not allow the value 'rgb(255,255,255)', replaced with 'white' 77 | Tests/utf8.svg:283: The attribute 'stroke' does not allow the value 'rgb(0,0,0)', replaced with 'black' 78 | Tests/utf8.svg:284: The attribute 'font-family' does not allow the value 'Arial, sans-serif', replaced with 'sans-serif' 79 | Tests/utf8.svg:284: The attribute 'fill' does not allow the value 'rgb(0,0,0)', replaced with 'black' 80 | Tests/utf8.svg:290: The attribute 'fill' does not allow the value 'rgb(255,255,255)', replaced with 'white' 81 | Tests/utf8.svg:291: The attribute 'stroke' does not allow the value 'rgb(0,0,0)', replaced with 'black' 82 | Tests/utf8.svg:292: The attribute 'font-family' does not allow the value 'Arial, sans-serif', replaced with 'sans-serif' 83 | Tests/utf8.svg:292: The attribute 'fill' does not allow the value 'rgb(0,0,0)', replaced with 'black' 84 | Tests/utf8.svg:298: The attribute 'fill' does not allow the value 'rgb(255,255,255)', replaced with 'white' 85 | Tests/utf8.svg:299: The attribute 'stroke' does not allow the value 'rgb(0,0,0)', replaced with 'black' 86 | Tests/utf8.svg:300: The attribute 'font-family' does not allow the value 'Arial, sans-serif', replaced with 'sans-serif' 87 | Tests/utf8.svg:300: The attribute 'fill' does not allow the value 'rgb(0,0,0)', replaced with 'black' 88 | Tests/utf8.svg:306: The attribute 'fill' does not allow the value 'rgb(255,255,255)', replaced with 'white' 89 | Tests/utf8.svg:307: The attribute 'stroke' does not allow the value 'rgb(0,0,0)', replaced with 'black' 90 | Tests/utf8.svg:308: The attribute 'font-family' does not allow the value 'Arial, sans-serif', replaced with 'sans-serif' 91 | Tests/utf8.svg:308: The attribute 'fill' does not allow the value 'rgb(0,0,0)', replaced with 'black' 92 | Tests/utf8.svg:314: The attribute 'fill' does not allow the value 'rgb(255,255,255)', replaced with 'white' 93 | Tests/utf8.svg:315: The attribute 'stroke' does not allow the value 'rgb(0,0,0)', replaced with 'black' 94 | Tests/utf8.svg:316: The attribute 'font-family' does not allow the value 'Arial, sans-serif', replaced with 'sans-serif' 95 | Tests/utf8.svg:316: The attribute 'fill' does not allow the value 'rgb(0,0,0)', replaced with 'black' 96 | Tests/utf8.svg:322: The attribute 'fill' does not allow the value 'rgb(255,255,255)', replaced with 'white' 97 | Tests/utf8.svg:323: The attribute 'stroke' does not allow the value 'rgb(0,0,0)', replaced with 'black' 98 | Tests/utf8.svg:324: The attribute 'font-family' does not allow the value 'Arial, sans-serif', replaced with 'sans-serif' 99 | Tests/utf8.svg:324: The attribute 'fill' does not allow the value 'rgb(0,0,0)', replaced with 'black' 100 | Tests/utf8.svg:330: The attribute 'fill' does not allow the value 'rgb(255,255,255)', replaced with 'white' 101 | Tests/utf8.svg:331: The attribute 'stroke' does not allow the value 'rgb(0,0,0)', replaced with 'black' 102 | Tests/utf8.svg:332: The attribute 'font-family' does not allow the value 'Arial, sans-serif', replaced with 'sans-serif' 103 | Tests/utf8.svg:332: The attribute 'fill' does not allow the value 'rgb(0,0,0)', replaced with 'black' 104 | Tests/utf8.svg:338: The attribute 'fill' does not allow the value 'rgb(255,255,255)', replaced with 'white' 105 | Tests/utf8.svg:339: The attribute 'stroke' does not allow the value 'rgb(0,0,0)', replaced with 'black' 106 | Tests/utf8.svg:340: The attribute 'font-family' does not allow the value 'Arial, sans-serif', replaced with 'sans-serif' 107 | Tests/utf8.svg:340: The attribute 'fill' does not allow the value 'rgb(0,0,0)', replaced with 'black' 108 | Tests/utf8.svg:340: The attribute 'fill' does not allow the value 'rgb(0,0,0)', replaced with 'black' 109 | Tests/utf8.svg:346: The attribute 'fill' does not allow the value 'rgb(255,255,255)', replaced with 'white' 110 | Tests/utf8.svg:347: The attribute 'stroke' does not allow the value 'rgb(0,0,0)', replaced with 'black' 111 | Tests/utf8.svg:348: The attribute 'font-family' does not allow the value 'Arial, sans-serif', replaced with 'sans-serif' 112 | Tests/utf8.svg:348: The attribute 'fill' does not allow the value 'rgb(0,0,0)', replaced with 'black' 113 | Tests/utf8.svg:348: The attribute 'fill' does not allow the value 'rgb(0,0,0)', replaced with 'black' 114 | Tests/utf8.svg:354: The attribute 'fill' does not allow the value 'rgb(255,255,255)', replaced with 'white' 115 | Tests/utf8.svg:355: The attribute 'stroke' does not allow the value 'rgb(0,0,0)', replaced with 'black' 116 | Tests/utf8.svg:356: The attribute 'font-family' does not allow the value 'Arial, sans-serif', replaced with 'sans-serif' 117 | Tests/utf8.svg:356: The attribute 'fill' does not allow the value 'rgb(0,0,0)', replaced with 'black' 118 | Tests/utf8.svg:356: The attribute 'fill' does not allow the value 'rgb(0,0,0)', replaced with 'black' 119 | Tests/utf8.svg:362: The attribute 'fill' does not allow the value 'rgb(255,255,255)', replaced with 'white' 120 | Tests/utf8.svg:363: The attribute 'stroke' does not allow the value 'rgb(0,0,0)', replaced with 'black' 121 | Tests/utf8.svg:364: The attribute 'font-family' does not allow the value 'Arial, sans-serif', replaced with 'sans-serif' 122 | Tests/utf8.svg:364: The attribute 'fill' does not allow the value 'rgb(0,0,0)', replaced with 'black' 123 | Tests/utf8.svg:364: The attribute 'fill' does not allow the value 'rgb(0,0,0)', replaced with 'black' 124 | Tests/utf8.svg:370: The attribute 'stroke' does not allow the value 'rgb(0,0,0)', replaced with 'black' 125 | Tests/utf8.svg:376: The attribute 'stroke' does not allow the value 'rgb(0,0,0)', replaced with 'black' 126 | Tests/utf8.svg:382: The attribute 'stroke' does not allow the value 'rgb(0,0,0)', replaced with 'black' 127 | Tests/utf8.svg:388: The attribute 'stroke' does not allow the value 'rgb(0,0,0)', replaced with 'black' 128 | Tests/utf8.svg:394: The attribute 'font-family' does not allow the value 'Arial, sans-serif', replaced with 'sans-serif' 129 | Tests/utf8.svg:394: The attribute 'fill' does not allow the value 'rgb(0,0,0)', replaced with 'black' 130 | Tests/utf8.svg:394: The attribute 'fill' does not allow the value 'rgb(0,0,0)', replaced with 'black' 131 | Tests/utf8.svg:400: The attribute 'font-family' does not allow the value 'Arial, sans-serif', replaced with 'sans-serif' 132 | Tests/utf8.svg:400: The attribute 'fill' does not allow the value 'rgb(0,0,0)', replaced with 'black' 133 | Tests/utf8.svg:400: The attribute 'fill' does not allow the value 'rgb(0,0,0)', replaced with 'black' 134 | Tests/utf8.svg:400: The attribute 'fill' does not allow the value 'rgb(0,0,0)', replaced with 'black' 135 | Tests/utf8.svg:406: The attribute 'font-family' does not allow the value 'Arial, sans-serif', replaced with 'sans-serif' 136 | Tests/utf8.svg:406: The attribute 'fill' does not allow the value 'rgb(0,0,0)', replaced with 'black' 137 | Tests/utf8.svg:406: The attribute 'fill' does not allow the value 'rgb(0,0,0)', replaced with 'black' 138 | Tests/utf8.svg:406: The attribute 'fill' does not allow the value 'rgb(0,0,0)', replaced with 'black' 139 | Tests/utf8.svg:412: The attribute 'font-family' does not allow the value 'Arial, sans-serif', replaced with 'sans-serif' 140 | Tests/utf8.svg:412: The attribute 'fill' does not allow the value 'rgb(0,0,0)', replaced with 'black' 141 | Tests/utf8.svg:412: The attribute 'fill' does not allow the value 'rgb(0,0,0)', replaced with 'black' 142 | Tests/utf8.svg:412: The attribute 'fill' does not allow the value 'rgb(0,0,0)', replaced with 'black' 143 | Tests/utf8.svg:418: The attribute 'font-family' does not allow the value 'Arial, sans-serif', replaced with 'sans-serif' 144 | Tests/utf8.svg:418: The attribute 'fill' does not allow the value 'rgb(0,0,0)', replaced with 'black' 145 | Tests/utf8.svg:418: The attribute 'fill' does not allow the value 'rgb(0,0,0)', replaced with 'black' 146 | Tests/utf8.svg:418: The attribute 'fill' does not allow the value 'rgb(0,0,0)', replaced with 'black' 147 | Tests/utf8.svg:424: The attribute 'fill' does not allow the value 'rgb(255,255,255)', replaced with 'white' 148 | Tests/utf8.svg:425: The attribute 'stroke' does not allow the value 'rgb(0,0,0)', replaced with 'black' 149 | Tests/utf8.svg:426: The attribute 'font-family' does not allow the value 'Arial, sans-serif', replaced with 'sans-serif' 150 | Tests/utf8.svg:426: The attribute 'fill' does not allow the value 'rgb(0,0,0)', replaced with 'black' 151 | Tests/utf8.svg:432: The attribute 'stroke' does not allow the value 'rgb(0,0,0)', replaced with 'black' 152 | Tests/utf8.svg:433: The attribute 'font-family' does not allow the value 'Arial, sans-serif', replaced with 'sans-serif' 153 | Tests/utf8.svg:433: The attribute 'fill' does not allow the value 'rgb(255,255,255)', replaced with 'white' 154 | Tests/utf8.svg:433: The attribute 'fill' does not allow the value 'rgb(255,255,255)', replaced with 'white' 155 | Tests/utf8.svg:433: The attribute 'fill' does not allow the value 'rgb(255,255,255)', replaced with 'white' 156 | Tests/utf8.svg:438: The attribute 'stroke' does not allow the value 'no—ne', replaced with 'black' 157 | Tests/utf8.svg:439: The attribute 'stroke' does not allow the value 'rgb(0,0,0)', replaced with 'black' 158 | Tests/utf8.svg:440: The attribute 'font-family' does not allow the value 'Arial, sans-serif', replaced with 'sans-serif' 159 | Tests/utf8.svg:440: The attribute 'fill' does not allow the value 'rgb(0,0,0)', replaced with 'black' 160 | Tests/utf8.svg:440: The attribute 'fill' does not allow the value 'rgb(0,0,0)', replaced with 'black' 161 | Tests/utf8.svg:440: The attribute 'fill' does not allow the value 'rgb(0,0,0)', replaced with 'black' 162 | ERROR: File does not conform to SVG requirements 163 | -------------------------------------------------------------------------------- /svgcheck/Results/viewBox-both.out: -------------------------------------------------------------------------------- 1 | Tests/viewBox-both.svg:1: The attribute viewBox is required on the root svg element 2 | Tests/viewBox-both.svg:1: Trying to put in the attribute with value '0 0 100.0 100.0' 3 | Tests/viewBox-both.svg:2: The attribute 'fill' does not allow the value 'red', replaced with 'black' 4 | -------------------------------------------------------------------------------- /svgcheck/Results/viewBox-both.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /svgcheck/Results/viewBox-height.out: -------------------------------------------------------------------------------- 1 | Tests/viewBox-height.svg:1: The attribute viewBox is required on the root svg element 2 | Tests/viewBox-height.svg:2: The attribute 'fill' does not allow the value 'red', replaced with 'black' 3 | -------------------------------------------------------------------------------- /svgcheck/Results/viewBox-height.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /svgcheck/Results/viewBox-none.out: -------------------------------------------------------------------------------- 1 | Tests/viewBox-none.svg:1: The attribute viewBox is required on the root svg element 2 | Tests/viewBox-none.svg:2: The attribute 'fill' does not allow the value 'red', replaced with 'black' 3 | -------------------------------------------------------------------------------- /svgcheck/Results/viewBox-none.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /svgcheck/Results/viewBox-width.out: -------------------------------------------------------------------------------- 1 | Tests/viewBox-width.svg:1: The attribute viewBox is required on the root svg element 2 | Tests/viewBox-width.svg:2: The attribute 'fill' does not allow the value 'red', replaced with 'black' 3 | -------------------------------------------------------------------------------- /svgcheck/Results/viewBox-width.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /svgcheck/Tests/DrawBerry-sample-2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 14 | 15 | 17 | 19 | 21 | 23 | 25 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /svgcheck/Tests/IETF-test.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | Updated Scenario Diagram 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /svgcheck/Tests/cache_saved/reference.RFC.1847.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Security Multiparts for MIME: Multipart/Signed and Multipart/Encrypted 6 | 7 | 8 | 9 | 10 | 11 | This document defines a framework within which security services may be applied to MIME body parts. [STANDARDS-TRACK] This memo defines a new Simple Mail Transfer Protocol (SMTP) [1] reply code, 521, which one may use to indicate that an Internet host does not accept incoming mail. This memo defines an Experimental Protocol for the Internet community. This memo defines an extension to the SMTP service whereby an interrupted SMTP transaction can be restarted at a later time without having to repeat all of the commands and message content sent prior to the interruption. This memo defines an Experimental Protocol for the Internet community. 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /svgcheck/Tests/circle.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /svgcheck/Tests/colors.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /svgcheck/Tests/dia-sample-svg.svg: -------------------------------------------------------------------------------- 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 | original 29 | 30 | 31 | canonical 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | nit 40 | 41 | 42 | edit 43 | 44 | 45 | nit (no-op) 46 | 47 | 48 | -------------------------------------------------------------------------------- /svgcheck/Tests/example-dot.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | %3 11 | 12 | 13 | a 14 | 15 | a 16 | 17 | 18 | b 19 | 20 | b 21 | 22 | 23 | a--b 24 | 25 | 26 | 27 | d 28 | 29 | d 30 | 31 | 32 | a--d 33 | 34 | 35 | 36 | b--d 37 | 38 | 39 | 40 | c 41 | 42 | c 43 | 44 | 45 | b--c 46 | 47 | 48 | 49 | d--c 50 | 51 | 52 | 53 | e 54 | 55 | e 56 | 57 | 58 | d--e 59 | 60 | 61 | 62 | f 63 | 64 | f 65 | 66 | 67 | c--f 68 | 69 | 70 | 71 | e--f 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /svgcheck/Tests/good.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /svgcheck/Tests/httpbis-proxy20-fig6.svg: -------------------------------------------------------------------------------- 1 | 2 | user-agentProxyServer(1) TLS ClientHello(ALPN ProtocolName: http)(2) TLS Error(Proxy Cert)(inform user of the SecureProxy)(3) TLS ClientHello(4) ServerHelloHTTP2.0(5) stream(X) GET(6) TLS ClientHelloTLS ServerHelloHTTP2.0(7) stream(Z) GET(8) stream(Z) 200 OK(9) stream(X) 200 OK -------------------------------------------------------------------------------- /svgcheck/Tests/malformed.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | This tries to cover all of the edge cases 4 | This tries to cover all of the edge cases 5 | 6 | This tries to cover all of the edge cases 7 | 8 | 9 | 10 | text field 11 | 12 | -------------------------------------------------------------------------------- /svgcheck/Tests/rfc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Example w/ SVG files 4 | 5 |
6 | ietf@augustcellars.com 7 |
8 |
9 | 10 | 11 | 12 | abstract 13 | 14 | 15 |
16 | 17 |
18 | Introduction 19 | 20 | Put in some text followed by a picture. 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | And pull in the same picture in a different way. 29 | 30 | 31 | 32 | 33 |
34 |
35 | 36 |
37 | 38 | -------------------------------------------------------------------------------- /svgcheck/Tests/rgb.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /svgcheck/Tests/threshold.svg: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /svgcheck/Tests/viewBox-both.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /svgcheck/Tests/viewBox-height.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /svgcheck/Tests/viewBox-none.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /svgcheck/Tests/viewBox-width.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /svgcheck/__init__.py: -------------------------------------------------------------------------------- 1 | # ---------------------------------------------------- 2 | # Copyright The IETF Trust 2018-9, All Rights Reserved 3 | # ---------------------------------------------------- 4 | 5 | # Static values 6 | __version__ = '0.11.0' 7 | NAME = 'svgcheck' 8 | -------------------------------------------------------------------------------- /svgcheck/checksvg.py: -------------------------------------------------------------------------------- 1 | # This source file originally came from 2 | # 3 | # Nevil Brownlee, U Auckland 4 | # 5 | 6 | # From a simple original version by Joe Hildebrand 7 | 8 | from svgcheck import log 9 | 10 | import re 11 | 12 | import svgcheck.word_properties as wp 13 | 14 | indent = 4 15 | errorCount = 0 16 | 17 | trace = True 18 | 19 | bad_namespaces = [] 20 | 21 | 22 | def maybefloat(f): 23 | try: 24 | return float(f) 25 | except (ValueError, TypeError): 26 | return None 27 | 28 | 29 | def modify_style(node): 30 | """ 31 | For style properties, we want to pull it apart and then make individual attributes 32 | """ 33 | log.note("modify_style check '{0}' in '{1}'".format(node.attrib["style"], node.tag)) 34 | 35 | style_props = node.attrib["style"].rstrip(";").split(";") 36 | props_to_check = wp.style_properties 37 | 38 | for prop in style_props: 39 | # print("prop = %s" % prop) 40 | v = prop.split(":") 41 | if len(v) != 2: 42 | log.error( 43 | "Malformed field '{0}' in style attribute found. Field removed.".format( 44 | v 45 | ), 46 | where=node, 47 | ) 48 | continue 49 | p = v[0].strip() 50 | v = v[1].strip() # May have leading blank 51 | log.note(" modify_style - p={0} v={1}".format(p, v)) 52 | # we will deal with the change of values later when the attribute list is processed. 53 | if p in props_to_check: 54 | log.error( 55 | "Style property '{0}' promoted to attribute".format(p), where=node 56 | ) 57 | node.attrib[p] = v 58 | else: 59 | log.error("Style property '{0}' removed".format(p), where=node) 60 | del node.attrib["style"] 61 | 62 | 63 | def value_ok(obj, v): 64 | """ 65 | Check that the value v is a legal value for the attribute passed in 66 | The return value is going to be (Value OK?, Replacement value) 67 | v -> set of values 68 | obj -> attribute name 69 | Returns if the value is ok, and if there is a value that should be used 70 | to replace the value if it is not. 71 | """ 72 | 73 | log.note("value_ok look for %s in %s" % (v, obj)) 74 | # Look if the object is a real attribute, or we recursed w/ an 75 | # internal type name such as '' (i.e. a basic_type) 76 | if obj in wp.properties: 77 | values = wp.properties[obj] 78 | elif obj in wp.basic_types: 79 | values = wp.basic_types[obj] 80 | elif isinstance(obj, str): 81 | # values to check is a string 82 | if obj[0] == "+": 83 | n = re.match(r"\d+\.\d+%?$", v) 84 | rv = None 85 | if n: 86 | rv = n.group() 87 | return (True, rv) 88 | # if obj[0] == '[': 89 | # return check_some_props(obj, v) 90 | if v == obj: 91 | return (True, v) 92 | return (False, None) 93 | else: # Unknown attribute 94 | return (False, None) 95 | 96 | log.note(" legal value list {0}".format(values)) 97 | if len(values) == 0: 98 | # Empty tuples have nothing to check, assume it is correct 99 | return (True, None) 100 | 101 | replaceWith = None 102 | for val in values: 103 | ok_v, matched_v = value_ok(val, v) 104 | if ok_v: 105 | return (True, matched_v) 106 | if matched_v: 107 | replaceWith = matched_v 108 | 109 | log.note(" --- skip to end -- {0}".format(obj)) 110 | v = v.lower() 111 | if obj == "font-family": 112 | all = v.split(",") 113 | newFonts = [] 114 | for font in ["sans-serif", "serif", "monospace"]: 115 | if font in all: 116 | newFonts.append(font) 117 | if len(newFonts) == 0: 118 | newFonts.append("sans-serif") 119 | return (False, ",".join(newFonts)) 120 | if obj == "": 121 | if v in wp.color_map: 122 | return (False, wp.color_map[v]) 123 | 124 | # Heuristic conversion of color or grayscale 125 | # when we get here, v is a non-conforming color element 126 | if ("rgb(" not in v) and v[0] != "#": 127 | return (False, wp.color_default) 128 | if v[0] == "#" and len(v) == 7: 129 | # hexadecimal color code 130 | shade = int(v[1:3], 16) + int(v[3:5], 16) + int(v[5:7], 16) 131 | elif v[0] == "#" and len(v) == 4: 132 | shade = ( 133 | int(v[1], 16) * 16 134 | + int(v[1], 16) 135 | + int(v[2], 16) * 16 136 | + int(v[2], 16) 137 | + int(v[3], 16) * 16 138 | + int(v[3], 16) 139 | ) 140 | elif "rgb(" in v: 141 | triple = v.split("(")[1].split(")")[0].split(",") 142 | if "%" in triple[0]: 143 | shade = sum([int(t.replace("%", "")) * 255 / 100 for t in triple]) 144 | else: 145 | shade = sum([int(t) for t in triple]) 146 | else: 147 | shade = 0 148 | 149 | log.note( 150 | "Color or grayscale heuristic applied to: '{0}' yields shade: '{1}'".format( 151 | v, shade 152 | ) 153 | ) 154 | if shade > wp.color_threshold: 155 | return (False, "white") 156 | return (False, wp.color_default) 157 | 158 | return (False, replaceWith) 159 | 160 | 161 | def strip_prefix(element, el): 162 | """ 163 | Given the tag for an element, separate the namespace from the tag 164 | and return a tuple of the namespace and the local tag 165 | It will be up to the caller to determine if the namespace is acceptable 166 | """ 167 | 168 | ns = None 169 | if element[0] == "{": 170 | rbp = element.rfind("}") # Index of rightmost } 171 | if rbp >= 0: 172 | ns = element[1:rbp] 173 | element = element[rbp + 1:] 174 | else: 175 | log.warn("Malformed namespace. Should have errored during parsing") 176 | return element, ns # return tag, namespace 177 | 178 | 179 | def check(el, depth=0): 180 | """ 181 | Walk the current tree checking to see if all elements pass muster 182 | relative to RFC 7996 the RFC Tiny SVG document 183 | 184 | Return False if the element is to be removed from tree when 185 | writing it back out 186 | """ 187 | global errorCount 188 | 189 | log.note("%s tag = %s" % (" " * (depth * indent), el.tag)) 190 | 191 | # Check that the namespace is one of the pre-approved ones 192 | # ElementTree prefixes elements with default namespace in braces 193 | 194 | element, ns = strip_prefix(el.tag, el) # name of element 195 | 196 | # namespace for elements must be either empty or svg 197 | if ns is not None and ns not in wp.svg_urls: 198 | log.warn( 199 | "Element '{0}' in namespace '{1}' is not allowed".format(element, ns), 200 | where=el, 201 | ) 202 | return False # Remove this el 203 | 204 | # Is the element in the list of legal elements? 205 | log.note("%s element % s: %s" % (" " * (depth * indent), element, el.attrib)) 206 | if element not in wp.elements: 207 | errorCount += 1 208 | log.warn("Element '{0}' not allowed".format(element), where=el) 209 | return False # Remove this el 210 | 211 | elementAttributes = wp.elements[element] # Allowed attributes for element 212 | 213 | # do a re-write of style into individual elements 214 | if "style" in el.attrib: 215 | modify_style(el) 216 | 217 | attribs_to_remove = [] # Can't remove them inside the iteration! 218 | for nsAttrib, val in el.attrib.items(): 219 | # validate that the namespace of the element is known and ok 220 | attr, ns = strip_prefix(nsAttrib, el) 221 | log.note("%s attr %s = %s (ns = %s)" % (" " * (depth * indent), attr, val, ns)) 222 | if ns is not None and ns not in wp.svg_urls: 223 | if ns not in wp.xmlns_urls: 224 | log.warn( 225 | "Element '{0}' does not allow attributes with namespace '{1}'".format( 226 | element, ns 227 | ), 228 | where=el, 229 | ) 230 | attribs_to_remove.append(nsAttrib) 231 | continue 232 | 233 | # look to see if the attribute is either an attribute for a specific 234 | # element or is an attribute generically for all properties 235 | if (attr not in elementAttributes) and (attr not in wp.properties): 236 | errorCount += 1 237 | log.warn( 238 | "The element '{0}' does not allow the attribute '{1}'," 239 | " attribute to be removed.".format(element, attr), 240 | where=el, 241 | ) 242 | attribs_to_remove.append(nsAttrib) 243 | 244 | # Now check if the attribute is a generic property 245 | elif attr in wp.properties: 246 | vals = wp.properties[attr] 247 | # log.note("vals = " + vals + "<<<<<") 248 | 249 | # Do method #1 of checking if the value is legal - not currently used. 250 | if vals and vals[0] == "[" and False: 251 | # ok, new_val = check_some_props(attr, val, depth) 252 | # if not ok: 253 | # el.attrib[attr] = new_val[1:] 254 | pass 255 | else: 256 | ok, new_val = value_ok(attr, val) 257 | if vals and not ok: 258 | errorCount += 1 259 | if new_val is not None: 260 | el.attrib[attr] = new_val 261 | log.warn( 262 | "The attribute '{1}' does not allow the value '{0}'," 263 | " replaced with '{2}'".format(val, attr, new_val), 264 | where=el, 265 | ) 266 | else: 267 | attribs_to_remove.append(nsAttrib) 268 | log.warn( 269 | "The attribute '{1}' does not allow the value '{0}'," 270 | " attribute to be removed".format(val, attr), 271 | where=el, 272 | ) 273 | 274 | for attrib in attribs_to_remove: 275 | del el.attrib[attrib] 276 | 277 | # Need to have a viewBox on the root 278 | if depth == 0: 279 | if el.get("viewBox"): 280 | pass 281 | else: 282 | log.warn( 283 | "The attribute viewBox is required on the root svg element", where=el 284 | ) 285 | svgw = maybefloat(el.get("width")) 286 | svgh = maybefloat(el.get("height")) 287 | try: 288 | if svgw and svgh: 289 | newValue = "0 0 %s %s" % (svgw, svgh) 290 | log.warn( 291 | "Trying to put in the attribute with value '{0}'".format( 292 | newValue 293 | ), 294 | where=el, 295 | ) 296 | el.set("viewBox", newValue) 297 | except ValueError as e: 298 | log.error("Error when calculating SVG size: %s" % e, where=el) 299 | 300 | els_to_rm = [] # Can't remove them inside the iteration! 301 | if element in wp.element_children: 302 | allowed_children = wp.element_children[element] 303 | else: 304 | allowed_children = [] 305 | 306 | for child in el: 307 | log.note("%schild, tag = %s" % (" " * (depth * indent), child.tag)) 308 | if not isinstance(child.tag, str): 309 | continue 310 | ch_tag, ns = strip_prefix(child.tag, el) 311 | if ns not in wp.svg_urls: 312 | log.warn( 313 | "The namespace {0} is not permitted for svg elements.".format(ns), 314 | where=child, 315 | ) 316 | els_to_rm.append(child) 317 | continue 318 | 319 | if ch_tag not in allowed_children: 320 | log.warn( 321 | "The element '{0}' is not allowed as a child of '{1}'".format( 322 | ch_tag, element 323 | ), 324 | where=child, 325 | ) 326 | els_to_rm.append(child) 327 | elif not check(child, depth + 1): 328 | els_to_rm.append(child) 329 | 330 | if len(els_to_rm) != 0: 331 | for child in els_to_rm: 332 | el.remove(child) 333 | return False 334 | return True # OK 335 | 336 | 337 | def checkTree(tree): 338 | """ 339 | Process the XML tree. There are two cases to be dealt with 340 | 1. This is a simple svg at the root - can be either the real namespace or 341 | an empty namespace 342 | 2. This is an rfc tree - and we should only look for real namespaces, but 343 | there may be more than one thing to look for. 344 | """ 345 | global errorCount 346 | 347 | errorCount = 0 348 | checkOK = True 349 | element = tree.getroot().tag 350 | if element[0] == "{": 351 | element = element[element.rfind("}") + 1:] 352 | if element == "svg": 353 | checkOK = check(tree.getroot(), 0) 354 | else: 355 | # Locate all of the svg elements that we need to check 356 | 357 | svgPaths = tree.getroot().xpath( 358 | "//x:svg", namespaces={"x": "http://www.w3.org/2000/svg"} 359 | ) 360 | 361 | for path in svgPaths: 362 | if len(svgPaths) > 1: 363 | log.note( 364 | "Checking svg element at line {0} in file {1}".format(1, "file") 365 | ) 366 | checkOK = check(path, 0) 367 | 368 | return errorCount == 0 and checkOK 369 | -------------------------------------------------------------------------------- /svgcheck/log.py: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------- 2 | # Copyright The IETF Trust 2011-2019, All Rights Reserved 3 | # -------------------------------------------------- 4 | 5 | """ Module Singleton which handles output of warnings and errors to 6 | stdout/stderr, or alternatively to specified file paths. 7 | 8 | If warn_error is set, then any warnings submitted will raise a 9 | python exception. 10 | """ 11 | 12 | import sys 13 | import os 14 | import io 15 | 16 | quiet = False 17 | verbose = False 18 | debug = False 19 | 20 | write_err = sys.stderr 21 | 22 | 23 | def info(*args, **kwargs): 24 | """ Prints a warning message unless quiet """ 25 | prefix = "INFO: " 26 | if 'where' in kwargs: 27 | where = kwargs['where'] 28 | fileName = where.base 29 | if fileName.startswith("file:///"): 30 | fileName = os.path.relpath(fileName[8:]) 31 | elif fileName[0:6] == 'file:/': 32 | fileName = os.path.relpath(fileName[6:]) 33 | elif fileName[0:7] == 'http://' or fileName[0:8] == 'https://': 34 | pass 35 | else: 36 | fileName = os.path.relpath(fileName) 37 | prefix = "{0}:{1}: ".format(fileName, where.sourceline) 38 | write_err.write(prefix + ' '.join(args)) 39 | write_err.write('\n') 40 | write_err.flush() 41 | 42 | 43 | def note(*args): 44 | """ Call for being verbose only """ 45 | if verbose and not quiet: 46 | write_err.write(' '.join(args)) 47 | write_err.write('\n') 48 | 49 | 50 | def warn(*args, **kwargs): 51 | """ Prints a warning message unless quiet """ 52 | if not quiet: 53 | prefix = "WARNING: " 54 | if 'where' in kwargs: 55 | where = kwargs['where'] 56 | fileName = where.base 57 | if fileName.startswith("file:///"): 58 | fileName = os.path.relpath(fileName[8:]) 59 | elif fileName[0:6] == 'file:/': 60 | fileName = os.path.relpath(fileName[6:]) 61 | elif fileName[0:7] == 'http://' or fileName[0:8] == 'https://': 62 | pass 63 | else: 64 | fileName = os.path.relpath(fileName) 65 | prefix = "{0}:{1}: ".format(fileName, where.sourceline) 66 | write_err.write(prefix + u' '.join(args)) 67 | write_err.write('\n') 68 | write_err.flush() 69 | 70 | 71 | def error(*args, **kwargs): 72 | """ This is typically called after an exception was already raised. """ 73 | prefix = "ERROR: " 74 | if 'where' in kwargs: 75 | where = kwargs['where'] 76 | fileName = make_relative(where.base) 77 | prefix = "{0}:{1}: ".format(fileName, where.sourceline) 78 | if 'file' in kwargs: 79 | fileName = make_relative(kwargs['file']) 80 | prefix = "{0}:{1}: ".format(fileName, kwargs['line']) 81 | if 'additional' in kwargs: 82 | prefix = ' ' * kwargs['additional'] 83 | 84 | write_err.write(prefix + ' '.join(args)) 85 | write_err.write('\n') 86 | write_err.flush() 87 | 88 | 89 | def exception(message, list): 90 | error(message) 91 | if isinstance(list, Exception): 92 | list = [list] 93 | for e in list: 94 | attr = dict([(n, str(getattr(e, n)).replace("\n", " ")) for n in dir(e) 95 | if not n.startswith("_")]) 96 | if 'message' in attr: 97 | if attr["message"].endswith(", got "): 98 | attr["message"] += "nothing." 99 | else: 100 | attr['message'] = '-- none --' 101 | if 'filename' in attr: 102 | attr["filename"] = make_relative(attr["filename"]) 103 | else: 104 | attr['filename'] = 'unknown' 105 | if 'line' not in attr: 106 | attr['line'] = -1 107 | write_err.write(" %(filename)s: Line %(line)s: %(message)s\n" % attr) 108 | 109 | 110 | def exception_lines(message, list): 111 | if isinstance(list, Exception): 112 | list = [list] 113 | for e in list: 114 | attr = dict([(n, str(getattr(e, n)).replace("\n", " ")) for n in dir(e) 115 | if not n.startswith("_")]) 116 | if attr["message"].endswith(", got "): 117 | attr["message"] += "nothing." 118 | attr["filename"] = make_relative(attr["filename"]) 119 | write_err.write(" %(filename)s: Line %(line)s: %(message)s\n" % attr) 120 | 121 | 122 | def make_relative(fileName): 123 | if fileName.startswith("file:///"): 124 | fileName = os.path.relpath(fileName[8:]) 125 | elif fileName[0:6] == 'file:/': 126 | fileName = os.path.relpath(fileName[6:]) 127 | else: 128 | fileName = os.path.relpath(fileName) 129 | return fileName 130 | -------------------------------------------------------------------------------- /svgcheck/pycode.cfg: -------------------------------------------------------------------------------- 1 | [pycodestyle] 2 | max-line-length = 100 3 | -------------------------------------------------------------------------------- /svgcheck/rewrite.x: -------------------------------------------------------------------------------- 1 | 'svg': ('fill-opacity', 'stroke-opacity','fill', 'fill-rule', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-width', 'color', 'color-rendering', 'vector-effect','direction', 'unicode-bidi','solid-color', 'solid-opacity','display-align', 'line-increment','stop-color', 'stop-opacity','font-family', 'font-size', 'font-style', 'font-variant', 'font-weight', 'text-anchor', 'text-align','id', 'xml:id', 'xml:base', 'xml:lang', 'class', 'role', 'rel', 'rev', 'typeof', 'content', 'datatype', 'resource', 'about', 'property', 'xml:space', 'width', 'height', 'preserveAspectRatio', 'viewBox', 'version', 'baseProfile', 'snapshotTime', <<(desc | svgTitle | path | rect | circle | line | ellipse | polyline | polygon | solidColor | textArea | \text | g | defs | use | a)*>> } 2 | 'svgTitle': () 3 | 'desc': ('id', 'xml:id', 'xml:base', 'xml:lang', 'class', 'role', 'rel', 'rev', 'typeof', 'content', 'datatype', 'resource', 'about', 'property', 'xml:space','display', 'visibility', 'image-rendering', 'shape-rendering', 'text-rendering', 'buffered-rendering','viewport-fill', 'viewport-fill-opacity', <> } 4 | 'title': ('id', 'xml:id', 'xml:base', 'xml:lang', 'class', 'role', 'rel', 'rev', 'typeof', 'content', 'datatype', 'resource', 'about', 'property', 'xml:space','display', 'visibility', 'image-rendering', 'shape-rendering', 'text-rendering', 'buffered-rendering', 'viewport-fill', 'viewport-fill-opacity', <> } 5 | 'path': ('id', 'xml:id', 'xml:base', 'xml:lang', 'class', 'role', 'rel', 'rev', 'typeof', 'content', 'datatype', 'resource', 'about', 'property', 'xml:space', 'transform','fill-opacity', 'stroke-opacity','fill', 'fill-rule', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-width', 'color', 'color-rendering', 'vector-effect','direction', 'unicode-bidi','solid-color', 'solid-opacity', 'display-align', 'line-increment','stop-color', 'stop-opacity','font-family', 'font-size', 'font-style', 'font-variant', 'font-weight', 'text-anchor', 'text-align', 'd', 'pathLength', <<(desc | svgTitle)>>* 6 | } 7 | 'rect': ('id', 'xml:id', 'xml:base', 'xml:lang', 'class', 'role', 'rel', 'rev', 'typeof', 'content', 'datatype', 'resource', 'about', 'property', 'xml:space', 'transform','fill-opacity', 'stroke-opacity','fill', 'fill-rule', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-width', 'color', 'color-rendering', 'vector-effect','direction', 'unicode-bidi','solid-color', 'solid-opacity','display-align', 'line-increment','stop-color', 'stop-opacity','font-family', 'font-size', 'font-style', 'font-variant', 'font-weight', 'text-anchor', 'text-align', 'x', 'y', 'width', 'height', 'rx', 'ry', <<(desc | svgTitle)*>> } 8 | 'circle': ('id', 'xml:id', 'xml:base', 'xml:lang', 'class', 'role', 'rel', 'rev', 'typeof', 'content', 'datatype', 'resource', 'about', 'property', 'xml:space', 'transform','fill-opacity', 'stroke-opacity','fill', 'fill-rule', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-width', 'color', 'color-rendering', 'vector-effect','direction', 'unicode-bidi','solid-color', 'solid-opacity','display-align', 'line-increment','stop-color', 'stop-opacity','font-family', 'font-size', 'font-style', 'font-variant', 'font-weight', 'text-anchor', 'text-align', 'cx', 'cy', 'r', <<(desc | svgTitle)*>> } 9 | 'line': ('id', 'xml:id', 'xml:base', 'xml:lang', 'class', 'role', 'rel', 'rev', 'typeof', 'content', 'datatype', 'resource', 'about', 'property', 'xml:space', 'transform','fill-opacity', 'stroke-opacity','fill', 'fill-rule', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-width', 'color', 'color-rendering', 'vector-effect','direction', 'unicode-bidi','solid-color', 'solid-opacity','display-align', 'line-increment','stop-color', 'stop-opacity','font-family', 'font-size', 'font-style', 'font-variant', 'font-weight', 'text-anchor', 'text-align', 'x1', 'y1', 'x2', 'y2', <<(desc | svgTitle)*>> } 10 | 'ellipse': ('id', 'xml:id', 'xml:base', 'xml:lang', 'class', 'role', 'rel', 'rev', 'typeof', 'content', 'datatype', 'resource', 'about', 'property', 'xml:space', 'transform','fill-opacity', 'stroke-opacity','fill', 'fill-rule', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-width', 'color', 'color-rendering', 'vector-effect','direction', 'unicode-bidi','solid-color', 'solid-opacity','display-align', 'line-increment','stop-color', 'stop-opacity','font-family', 'font-size', 'font-style', 'font-variant', 'font-weight', 'text-anchor', 'text-align', 'rx', 'ry', 'cx', 'cy', <<(desc | svgTitle)*>> } 11 | 'polyline': ('id', 'xml:id', 'xml:base', 'xml:lang', 'class', 'role', 'rel', 'rev', 'typeof', 'content', 'datatype', 'resource', 'about', 'property', 'xml:space', 'transform','fill-opacity', 'stroke-opacity','fill', 'fill-rule', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-width', 'color', 'color-rendering', 'vector-effect','direction', 'unicode-bidi','solid-color', 'solid-opacity','display-align', 'line-increment','stop-color', 'stop-opacity','font-family', 'font-size', 'font-style', 'font-variant', 'font-weight', 'text-anchor', 'text-align', 'points', <<(desc | svgTitle)*>> } 12 | 'polygon': ('id', 'xml:id', 'xml:base', 'xml:lang', 'class', 'role', 'rel', 'rev', 'typeof', 'content', 'datatype', 'resource', 'about', 'property', 'xml:space', 'transform','fill-opacity', 'stroke-opacity','fill', 'fill-rule', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-width', 'color', 'color-rendering', 'vector-effect','direction', 'unicode-bidi','solid-color', 'solid-opacity','display-align', 'line-increment','stop-color', 'stop-opacity','font-family', 'font-size', 'font-style', 'font-variant', 'font-weight', 'text-anchor', 'text-align', 'points', <<(desc | svgTitle)*>> } 13 | 'solidColor': ('fill-opacity', 'stroke-opacity','fill', 'fill-rule', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-width', 'color', 'color-rendering', 'vector-effect','direction', 'unicode-bidi','solid-color', 'solid-opacity','display-align', 'line-increment','stop-color', 'stop-opacity','font-family', 'font-size', 'font-style', 'font-variant', 'font-weight', 'text-anchor', 'text-align','id', 'xml:id', 'xml:base', 'xml:lang', 'class', 'role', 'rel', 'rev', 'typeof', 'content', 'datatype', 'resource', 'about', 'property', 'xml:space', <<(desc | svgTitle)*>> } 14 | 'textArea': ('fill-opacity', 'stroke-opacity','fill', 'fill-rule', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-width', 'color', 'color-rendering', 'vector-effect','direction', 'unicode-bidi','solid-color', 'solid-opacity','display-align', 'line-increment','stop-color', 'stop-opacity','font-family', 'font-size', 'font-style', 'font-variant', 'font-weight', 'text-anchor', 'text-align','id', 'xml:id', 'xml:base', 'xml:lang', 'class', 'role', 'rel', 'rev', 'typeof', 'content', 'datatype', 'resource', 'about', 'property', 'xml:space', 'transform', 'x', 'y', 'width', 'height', <<(tspan | desc | svgTitle | tspan_2 | text | a_2)+>> } 15 | 'text': ('fill-opacity', 'stroke-opacity','fill', 'fill-rule', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-width', 'color', 'color-rendering', 'vector-effect','direction', 'unicode-bidi','solid-color', 'solid-opacity','display-align', 'line-increment','stop-color', 'stop-opacity','font-family', 'font-size', 'font-style', 'font-variant', 'font-weight', 'text-anchor', 'text-align','id', 'xml:id', 'xml:base', 'xml:lang', 'class', 'role', 'rel', 'rev', 'typeof', 'content', 'datatype', 'resource', 'about', 'property', 'xml:space', 'transform', 'x', 'y', 'rotate', <<(desc | svgTitle | tspan_2 | text | a_2)+>> } 16 | 'g': ('fill-opacity', 'stroke-opacity','fill', 'fill-rule', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-width', 'color', 'color-rendering', 'vector-effect','direction', 'unicode-bidi','solid-color', 'solid-opacity','display-align', 'line-increment','stop-color', 'stop-opacity','font-family', 'font-size', 'font-style', 'font-variant', 'font-weight', 'text-anchor', 'text-align','id', 'xml:id', 'xml:base', 'xml:lang', 'class', 'role', 'rel', 'rev', 'typeof', 'content', 'datatype', 'resource', 'about', 'property', 'xml:space', 'transform', <<(desc | svgTitle | path | rect | circle | line | ellipse | polyline | polygon | solidColor | textArea | \text | g | defs | use | a)*>> } 17 | 'defs': ('fill-opacity', 'stroke-opacity','fill', 'fill-rule', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-width', 'color', 'color-rendering', 'vector-effect','direction', 'unicode-bidi','solid-color', 'solid-opacity','display-align', 'line-increment','stop-color', 'stop-opacity','font-family', 'font-size', 'font-style', 'font-variant', 'font-weight', 'text-anchor', 'text-align','id', 'xml:id', 'xml:base', 'xml:lang', 'class', 'role', 'rel', 'rev', 'typeof', 'content', 'datatype', 'resource', 'about', 'property', 'xml:space', <<(desc | svgTitle | path | rect | circle | line | ellipse | polyline | polygon | solidColor | textArea | \text | g | defs | use | a)*>> } 18 | 'use': ('fill-opacity', 'stroke-opacity','fill', 'fill-rule', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-width', 'color', 'color-rendering', 'vector-effect','direction', 'unicode-bidi','solid-color', 'solid-opacity','display-align', 'line-increment','stop-color', 'stop-opacity','font-family', 'font-size', 'font-style', 'font-variant', 'font-weight', 'text-anchor', 'text-align','id', 'xml:id', 'xml:base', 'xml:lang', 'class', 'role', 'rel', 'rev', 'typeof', 'content', 'datatype', 'resource', 'about', 'property', 'xml:space', 'transform', 'xlink:show', 'xlink:actuate', 'xlink:type', 'xlink:role', 'xlink:arcrole', 'xlink:title', 'xlink:href', 'x', 'y', <<(desc | svgTitle)*>> } 19 | 'a': ('id', 'xml:id', 'xml:base', 'xml:lang', 'class', 'role', 'rel', 'rev', 'typeof', 'content', 'datatype', 'resource', 'about', 'property', 'xml:space','fill-opacity', 'stroke-opacity','fill', 'fill-rule', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-width', 'color', 'color-rendering', 'vector-effect','direction', 'unicode-bidi','solid-color', 'solid-opacity','display-align', 'line-increment','stop-color', 'stop-opacity','font-family', 'font-size', 'font-style', 'font-variant', 'font-weight', 'text-anchor', 'text-align', 'transform', 'xlink:show', 'xlink:actuate', 'xlink:type', 'xlink:role', 'xlink:arcrole', 'xlink:title', 'xlink:href', 'target', <<(desc | svgTitle | path | rect | circle | line | ellipse | polyline | polygon | solidColor | textArea | \text | g | defs | use)*>> } 20 | 'tspan': ('fill-opacity', 'stroke-opacity','fill', 'fill-rule', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-width', 'color', 'color-rendering', 'vector-effect','direction', 'unicode-bidi','solid-color', 'solid-opacity','display-align', 'line-increment','stop-color', 'stop-opacity','font-family', 'font-size', 'font-style', 'font-variant', 'font-weight', 'text-anchor', 'text-align','id', 'xml:id', 'xml:base', 'xml:lang', 'class', 'role', 'rel', 'rev', 'typeof', 'content', 'datatype', 'resource', 'about', 'property', 'xml:space', 'x', 'y', <<(tbreak | desc | svgTitle | tspan_2 | text | a_2)+>> } 21 | 'tspan': ('fill-opacity', 'stroke-opacity','fill', 'fill-rule', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-width', 'color', 'color-rendering', 'vector-effect','direction', 'unicode-bidi','solid-color', 'solid-opacity','display-align', 'line-increment','stop-color', 'stop-opacity','font-family', 'font-size', 'font-style', 'font-variant', 'font-weight', 'text-anchor', 'text-align','id', 'xml:id', 'xml:base', 'xml:lang', 'class', 'role', 'rel', 'rev', 'typeof', 'content', 'datatype', 'resource', 'about', 'property', 'xml:space', 'x', 'y', <<(desc | svgTitle | tspan_2 | text | a_2)+>> } 22 | 'a': 'id', 'xml:id', 'xml:base', 'xml:lang', 'class', 'role', 'rel', 'rev', 'typeof', 'content', 'datatype', 'resource', 'about', 'property', 'xml:space','fill-opacity', 'stroke-opacity','fill', 'fill-rule', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-width', 'color', 'color-rendering', 'vector-effect','direction', 'unicode-bidi','solid-color', 'solid-opacity','display-align', 'line-increment','stop-color', 'stop-opacity','font-family', 'font-size', 'font-style', 'font-variant', 'font-weight', 'text-anchor', 'text-align', 'transform', 'xlink:show', 'xlink:actuate', 'xlink:type', 'xlink:role', 'xlink:arcrole', 'xlink:title', 'xlink:href', 'target', <<(desc | svgTitle | tspan_2 | text)+>> } 23 | 'tbreak': ('id', 'xml:id', 'xml:base', 'xml:lang', 'class', 'role', 'rel', 'rev', 'typeof', 'content', 'datatype', 'resource', 'about', 'property', 'xml:space', <<>>} 24 | -------------------------------------------------------------------------------- /svgcheck/run.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import optparse 3 | import os 4 | import shutil 5 | import tempfile 6 | import lxml.etree 7 | from svgcheck.checksvg import checkTree 8 | from svgcheck.__init__ import __version__ 9 | from svgcheck import log 10 | from xml2rfc.parser import XmlRfcParser, XmlRfcError 11 | from xml2rfc import CACHES, CACHE_PREFIX 12 | import svgcheck.word_properties as wp 13 | 14 | 15 | def display_version(self, opt, value, parser): 16 | print("svgcheck = " + __version__) 17 | sys.exit() 18 | 19 | 20 | def clear_cache(cache_path): 21 | # Explicit path given? 22 | paths = [os.path.expanduser(cache_path) for cache_path in CACHES] 23 | caches = cache_path and [cache_path] or paths 24 | for dir in caches: 25 | path = os.path.join(dir, CACHE_PREFIX) 26 | if os.access(path, os.W_OK): 27 | shutil.rmtree(path) 28 | log.info('Deleted cache directory at', path) 29 | sys.exit() 30 | 31 | 32 | def main(): 33 | # Populate the options 34 | formatter = optparse.IndentedHelpFormatter(max_help_position=40) 35 | optionparser = optparse.OptionParser(usage='svgcheck SOURCE [OPTIONS] ' 36 | '...\nExample: svgcheck draft.xml', 37 | formatter=formatter) 38 | 39 | parser_options = optparse.OptionGroup(optionparser, 'Parser Options') 40 | parser_options.add_option('-N', '--no-network', action='store_true', default=False, 41 | help='don\'t use the network to resolve references') 42 | parser_options.add_option('-X', "--no-xinclude", action='store_true', default=False, 43 | help='This option is deprecated and has no effect.') 44 | 45 | parser_options.add_option('-C', '--clear-cache', action='store_true', dest='clear_cache', 46 | default=False, help='purge the cache and exit') 47 | parser_options.add_option('-c', '--cache', dest='cache', 48 | help='specify a primary cache directory to write to;' 49 | 'default: try [ %s ]' % ', '.join(CACHES)) 50 | 51 | parser_options.add_option('-d', '--rng', dest='rng', help='specify an alternate RNG file') 52 | optionparser.add_option_group(parser_options) 53 | 54 | other_options = optparse.OptionGroup(optionparser, 'Other options') 55 | other_options.add_option('-q', '--quiet', action='store_true', 56 | help='don\'t print anything') 57 | other_options.add_option('-o', '--out', dest='output_filename', metavar='FILE', 58 | help='specify an explicit output filename') 59 | other_options.add_option('-v', '--verbose', action='store_true', 60 | help='print extra information') 61 | other_options.add_option('-V', '--version', action='callback', callback=display_version, 62 | help='display the version number and exit') 63 | optionparser.add_option_group(other_options) 64 | 65 | svg_options = optparse.OptionGroup(optionparser, 'SVG options') 66 | svg_options.add_option('-r', '--repair', action='store_true', default=False, 67 | help='Repair the SVG so it meets RFC 7966') 68 | svg_options.add_option('-a', '--always-emit', action='store_true', default=False, 69 | help='Emit the SVG file even if does not need repairing. Implies -r') 70 | svg_options.add_option('-g', '--grey-scale', action='store_true', 71 | help='Use grey scaling heuristic to determine what is white') 72 | svg_options.add_option('--grey-level', default=381, 73 | help='Level to use for grey scaling, defaults to 381') 74 | optionparser.add_option_group(svg_options) 75 | 76 | # --- Parse and validate arguments -------------- 77 | 78 | (options, args) = optionparser.parse_args() 79 | 80 | # Setup warnings module 81 | # rfclint.log.warn_error = options.warn_error and True or False 82 | log.quiet = options.quiet and True or False 83 | log.verbose = options.verbose 84 | 85 | if options.no_xinclude: 86 | log.warn('--no-xinclude option is deprecated and has no effect.') 87 | 88 | if options.cache: 89 | if not os.path.exists(options.cache): 90 | try: 91 | os.makedirs(options.cache) 92 | if options.verbose: 93 | log.info('Created cache directory at', 94 | options.cache) 95 | except OSError as e: 96 | print('Unable to make cache directory: %s ' % options.cache) 97 | print(e) 98 | sys.exit(1) 99 | else: 100 | if not os.access(options.cache, os.W_OK): 101 | print('Cache directory is not writable: %s' % options.cache) 102 | sys.exit(1) 103 | 104 | if options.clear_cache: 105 | clear_cache(options.cache) 106 | 107 | if options.grey_scale: 108 | wp.color_threshold = options.grey_level 109 | 110 | if len(args) < 1: 111 | source = None 112 | try: 113 | with tempfile.NamedTemporaryFile(mode="w+b", delete=False) as tmp_file: 114 | data = sys.stdin.buffer.read() 115 | tmp_file.write(data) 116 | tmp_file.close() 117 | source = tmp_file.name 118 | process_svg(options, source) 119 | finally: 120 | if source and os.path.exists(source): 121 | os.remove(source) 122 | else: 123 | source = args[0] 124 | if not os.path.exists(source): 125 | sys.exit('No such file: ' + source) 126 | process_svg(options, source) 127 | 128 | 129 | def process_svg(options, source): 130 | # Setup warnings module 131 | # rfclint.log.warn_error = options.warn_error and True or False 132 | log.quiet = options.quiet and True or False 133 | log.verbose = options.verbose 134 | 135 | # Parse the document into an xmlrfc tree instance 136 | parser = XmlRfcParser(source, verbose=options.verbose, 137 | quiet=options.quiet, 138 | cache_path=options.cache, 139 | no_network=options.no_network) 140 | try: 141 | xmlrfc = parser.parse(remove_pis=True, remove_comments=False, 142 | strip_cdata=False) 143 | except XmlRfcError as e: 144 | log.exception('Unable to parse the XML document: ' + source, e) 145 | sys.exit(1) 146 | except lxml.etree.XMLSyntaxError as e: 147 | # Give the lxml.etree.XmlSyntaxError exception a line attribute which 148 | # matches lxml.etree._LogEntry, so we can use the same logging function 149 | log.exception('Unable to parse the XML document: ' + source, e.error_log) 150 | sys.exit(1) 151 | 152 | # Check that 153 | 154 | ok = checkTree(xmlrfc.tree) 155 | if (not ok and options.repair) or options.always_emit: 156 | encodedBytes = lxml.etree.tostring(xmlrfc.tree.getroot(), 157 | xml_declaration=True, 158 | encoding='utf-8', 159 | pretty_print=True).decode('utf-8') 160 | if options.output_filename is None: 161 | file = sys.stdout 162 | else: 163 | file = open(options.output_filename, 'w', encoding='utf-8') 164 | file.write(encodedBytes) 165 | 166 | if ok: 167 | log.info("File conforms to SVG requirements.") 168 | sys.exit(0) 169 | 170 | log.error("File does not conform to SVG requirements") 171 | sys.exit(1) 172 | 173 | 174 | if __name__ == '__main__': 175 | main() 176 | -------------------------------------------------------------------------------- /svgcheck/test.py: -------------------------------------------------------------------------------- 1 | import pycodestyle 2 | import unittest 3 | import os 4 | import shutil 5 | import lxml.etree 6 | import subprocess 7 | import sys 8 | from xml2rfc.parser import XmlRfcParser 9 | import difflib 10 | from svgcheck.checksvg import checkTree 11 | from svgcheck import log 12 | import io 13 | 14 | test_program = "svgcheck" 15 | 16 | 17 | def which(program): 18 | def is_exe(fpath): 19 | return os.path.isfile(fpath) and os.access(fpath, os.X_OK) 20 | 21 | fpath, fname = os.path.split(program) 22 | if fpath: 23 | if is_exe(program): 24 | return program 25 | else: 26 | for path in os.environ["PATH"].split(os.pathsep): 27 | exe_file = os.path.join(path, program) 28 | if is_exe(exe_file): 29 | return exe_file 30 | return None 31 | 32 | 33 | class Test_Coding(unittest.TestCase): 34 | def test_pycodestyle_conformance(self): 35 | """Test that we conform to PEP8.""" 36 | pep8style = pycodestyle.StyleGuide(quiet=False, config_file="pycode.cfg") 37 | result = pep8style.check_files(['run.py', 'checksvg.py', 'test.py', 'word_properties.py']) 38 | self.assertEqual(result.total_errors, 0, 39 | "Found code style errors (and warnings).") 40 | 41 | def test_pyflakes_confrmance(self): 42 | p = subprocess.Popen(['pyflakes', 'run.py', 'checksvg.py', 'test.py', 43 | 'word_properties.py'], 44 | stdout=subprocess.PIPE, stderr=subprocess.PIPE) 45 | (stdoutX, stderrX) = p.communicate() 46 | ret = p.wait() 47 | if ret > 0: 48 | stdoutX = stdoutX.decode('utf-8') 49 | stderrX = stderrX.decode('utf-8') 50 | print(stdoutX) 51 | print(stderrX) 52 | self.assertEqual(ret, 0) 53 | 54 | 55 | class TestCommandLineOptions(unittest.TestCase): 56 | """ Run a set of command line checks to make sure they work """ 57 | def test_clear_cache(self): 58 | if not os.path.exists('Temp'): 59 | os.mkdir('Temp') 60 | if not os.path.exists('Temp/cache'): 61 | os.mkdir('Temp/cache') 62 | shutil.copy('Tests/cache_saved/reference.RFC.1847.xml', 63 | 'Temp/cache/reference.RFC.1847.xml') 64 | check_process(self, [sys.executable, test_program, "--clear-cache", 65 | "--cache=Temp/cache"], 66 | None, None, 67 | None, None) 68 | self.assertFalse(os.path.exists('Temp/cache/reference.RFC.1847.xml')) 69 | 70 | def test_stdin(self): 71 | process = subprocess.Popen([sys.executable, test_program], 72 | stdin=subprocess.PIPE, 73 | stderr=subprocess.PIPE) 74 | _, stderr_data = process.communicate(input=b'') 75 | self.assertEqual(stderr_data.decode("utf-8").strip(), 76 | "INFO: File conforms to SVG requirements.") 77 | 78 | def test_no_such_file(self): 79 | file = "this_file_does_not_exist.svg" 80 | process = subprocess.Popen([sys.executable, test_program, file], 81 | stderr=subprocess.PIPE) 82 | _, stderr_data = process.communicate() 83 | self.assertEqual(stderr_data.decode("utf-8").strip(), 84 | f"No such file: {file}") 85 | 86 | 87 | class TestParserMethods(unittest.TestCase): 88 | 89 | def test_circle(self): 90 | """ Tests/circle.svg: Test a simple example with a small number of required edits """ 91 | test_svg_file(self, "circle.svg") 92 | 93 | def test_rbg(self): 94 | """ Tests/rgb.svg: Test a simple example with a small number of required edits """ 95 | test_svg_file(self, "rgb.svg") 96 | 97 | def test_dia_sample(self): 98 | """ Tests/dia-sample-svg.svg: Generated by some unknown program """ 99 | test_svg_file(self, "dia-sample-svg.svg") 100 | 101 | def test_drawberry_sample(self): 102 | """ Tests/drawberry-sample-2.svg: Generated by DrawBerry """ 103 | test_svg_file(self, "DrawBerry-sample-2.svg") 104 | 105 | def test_example_dot(self): 106 | """ Tests/example-dot.svg """ 107 | test_svg_file(self, "example-dot.svg") 108 | 109 | def test_httpbis_proxy(self): 110 | """ Tests/httpbis-proxy20-fig6.svg """ 111 | test_svg_file(self, "httpbis-proxy20-fig6.svg") 112 | 113 | def test_ietf_test(self): 114 | """ Tests/IETF-test.svg """ 115 | test_svg_file(self, "IETF-test.svg") 116 | 117 | def test_svg_wordle(self): 118 | """ Tests/svg-wordle.svg """ 119 | test_svg_file(self, "svg-wordle.svg") 120 | 121 | def test_svg_malformed(self): 122 | """ Tests/malformed.svg """ 123 | test_svg_file(self, "malformed.svg") 124 | 125 | def test_simple_sub(self): 126 | if not os.path.exists('Temp'): 127 | os.mkdir('Temp') 128 | check_process(self, [sys.executable, test_program, "--out=Temp/rfc.xml", 129 | "--repair", "Tests/rfc.xml"], 130 | "Results/rfc-01.out", "Results/rfc-01.err", 131 | "Results/rfc-01.xml", "Temp/rfc.xml") 132 | 133 | def test_to_stdout(self): 134 | check_process(self, [sys.executable, test_program, "--repair", 135 | "Tests/rfc.xml"], "Results/rfc-02.out", "Results/rfc-02.err", 136 | None, None) 137 | 138 | def test_always_to_stdout(self): 139 | check_process(self, [sys.executable, test_program, "--always-emit", 140 | "Tests/good.svg"], "Results/colors.out", "Results/good.err", 141 | None, None) 142 | 143 | def test_always2_to_stdout(self): 144 | check_process(self, [sys.executable, test_program, "--always-emit", 145 | "Tests/colors.svg"], "Results/colors.out", "Results/colors.err", 146 | None, None) 147 | 148 | def test_to_quiet(self): 149 | check_process(self, [sys.executable, test_program, "--quiet", 150 | "Tests/rfc.xml"], "Results/rfc-03.out", 151 | "Results/rfc-03.err", None, None) 152 | 153 | def test_rfc_complete(self): 154 | check_process(self, [sys.executable, test_program, "--repair", "Tests/rfc-svg.xml"], 155 | "Results/rfc-svg.out", "Results/rfc-svg.err", None, None) 156 | 157 | def test_colors(self): 158 | check_process(self, [sys.executable, test_program, "-r", "Tests/colors.svg"], 159 | "Results/colors.out", "Results/colors.err", None, None) 160 | 161 | def test_full_tiny(self): 162 | if not os.path.exists('Temp'): 163 | os.mkdir('Temp') 164 | check_process(self, [sys.executable, test_program, "--out=Temp/full-tiny.xml", 165 | "--repair", "Tests/full-tiny.xml"], 166 | "Results/full-tiny.out", "Results/full-tiny.err", 167 | "Results/full-tiny.xml", "Temp/full-tiny.xml") 168 | print("pass 2") 169 | check_process(self, [sys.executable, test_program, "--out=Temp/full-tiny-02.xml", 170 | "Temp/full-tiny.xml"], 171 | "Results/full-tiny-02.out", "Results/full-tiny-02.err", 172 | None, None) 173 | 174 | def test_utf8(self): 175 | check_process(self, [sys.executable, test_program, "-r", "Tests/utf8.svg"], 176 | "Results/utf8.out", "Results/utf8.err", None, None) 177 | 178 | def test_twice(self): 179 | if not os.path.exists('Temp'): 180 | os.mkdir('Temp') 181 | check_process(self, [sys.executable, test_program, "-r", "--out=Temp/utf8-1.svg", 182 | "Tests/utf8.svg"], 183 | "Results/empty", "Results/utf8.err", None, None) 184 | check_process(self, [sys.executable, test_program, "-r", "--out=Temp/utf8-2.svg", 185 | "Temp/utf8-1.svg"], 186 | "Results/empty", "Results/utf8-2.err", 187 | None, "Temp/utf8-2.svg") 188 | 189 | 190 | class TestViewBox(unittest.TestCase): 191 | def test_svg_noViewbox(self): 192 | """ Tests/viewBox-none.svg """ 193 | test_svg_file(self, "viewBox-none.svg") 194 | 195 | def test_svg_ViewboxHeight(self): 196 | """ Tests/viewBox-height.svg """ 197 | test_svg_file(self, "viewBox-height.svg") 198 | 199 | def test_svg_ViewboxWidth(self): 200 | """ Tests/viewBox-width.svg """ 201 | test_svg_file(self, "viewBox-width.svg") 202 | 203 | def test_svg_ViewboxBoth(self): 204 | """ Tests/viewBox-both.svg """ 205 | test_svg_file(self, "viewBox-both.svg") 206 | 207 | 208 | def test_svg_file(tester, fileName): 209 | """ Run the basic tests for a single input file """ 210 | 211 | basename = os.path.basename(fileName) 212 | parse = XmlRfcParser("Tests/" + fileName, quiet=True, cache_path=None, no_network=True) 213 | tree = parse.parse(remove_comments=False, remove_pis=True, strip_cdata=False) 214 | 215 | log.write_out = io.StringIO() 216 | log.write_err = log.write_out 217 | checkTree(tree.tree) 218 | 219 | (result, errors) = tree.validate() 220 | 221 | returnValue = check_results(log.write_out, "Results/" + basename.replace(".svg", ".out")) 222 | tester.assertFalse(returnValue, "Output to console is different") 223 | 224 | result = io.StringIO(lxml.etree.tostring(tree.tree, 225 | xml_declaration=True, 226 | encoding='utf-8', 227 | pretty_print=True).decode('utf-8')) 228 | returnValue = check_results(result, "Results/" + basename) 229 | tester.assertFalse(returnValue, "Result from editing the tree is different") 230 | tester.assertTrue(result, "Fails to validate againist the RNG") 231 | 232 | 233 | def check_results(file1, file2Name): 234 | """ Compare two files and say what the differences are or even if there are 235 | any differences 236 | """ 237 | 238 | with open(file2Name, encoding='utf-8') as f: 239 | lines2 = f.readlines() 240 | 241 | if os.name == 'nt' and (file2Name.endswith(".out") or file2Name.endswith(".err")): 242 | lines2 = [line.replace('Tests/', 'Tests\\').replace('Temp/', 'Temp\\') for line in lines2] 243 | 244 | if not file2Name.endswith(".out"): 245 | cwd = os.getcwd() 246 | if os.name == 'nt': 247 | cwd = cwd.replace('\\', '/') 248 | lines2 = [line.replace('$$CWD$$', cwd) for line in lines2] 249 | 250 | file1.seek(0) 251 | lines1 = file1.readlines() 252 | 253 | d = difflib.Differ() 254 | result = list(d.compare(lines1, lines2)) 255 | 256 | hasError = False 257 | for line in result: 258 | if line[0:2] == '+ ' or line[0:2] == '- ': 259 | hasError = True 260 | break 261 | 262 | if hasError: 263 | print("".join(result)) 264 | 265 | return hasError 266 | 267 | 268 | def check_process(tester, args, stdoutFile, errFile, generatedFile, compareFile): 269 | """ 270 | Execute a subprocess using args as the command line. 271 | if stdoutFile is not None, compare it to the stdout of the process 272 | if generatedFile and compareFile are not None, compare them to each other 273 | """ 274 | 275 | if args[1][-4:] == '.exe': 276 | args = args[1:] 277 | p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 278 | (stdoutX, stderr) = p.communicate() 279 | p.wait() 280 | 281 | returnValue = True 282 | if stdoutFile is not None: 283 | with open(stdoutFile, encoding='utf-8') as f: 284 | lines2 = f.readlines() 285 | 286 | lines1 = stdoutX.decode('utf-8').splitlines(True) 287 | 288 | if os.name == 'nt': 289 | lines2 = [line.replace('Tests/', 'Tests\\').replace('Temp/', 'Temp\\') 290 | for line in lines2] 291 | lines1 = [line.replace('\r', '') for line in lines1] 292 | 293 | d = difflib.Differ() 294 | result = list(d.compare(lines1, lines2)) 295 | 296 | hasError = False 297 | for line in result: 298 | if line[0:2] == '+ ' or line[0:2] == '- ': 299 | hasError = True 300 | break 301 | if hasError: 302 | print("stdout:") 303 | print("".join(result)) 304 | returnValue = False 305 | 306 | if errFile is not None: 307 | with open(errFile, encoding='utf-8') as f: 308 | lines2 = f.readlines() 309 | 310 | lines1 = stderr.decode('utf-8').splitlines(True) 311 | 312 | if os.name == 'nt': 313 | lines2 = [line.replace('Tests/', 'Tests\\').replace('Temp/', 'Temp\\') 314 | for line in lines2] 315 | lines1 = [line.replace('\r', '') for line in lines1] 316 | 317 | d = difflib.Differ() 318 | result = list(d.compare(lines1, lines2)) 319 | 320 | hasError = False 321 | for line in result: 322 | if line[0:2] == '+ ' or line[0:2] == '- ': 323 | hasError = True 324 | break 325 | if hasError: 326 | print("stderr") 327 | print("".join(result)) 328 | returnValue = False 329 | 330 | if generatedFile is not None: 331 | with open(generatedFile, encoding='utf-8') as f: 332 | lines2 = f.readlines() 333 | 334 | with open(compareFile, encoding='utf-8') as f: 335 | lines1 = f.readlines() 336 | 337 | d = difflib.Differ() 338 | result = list(d.compare(lines1, lines2)) 339 | 340 | hasError = False 341 | for line in result: 342 | if line[0:2] == '+ ' or line[0:2] == '- ': 343 | hasError = True 344 | break 345 | 346 | if hasError: 347 | print(generatedFile) 348 | print("".join(result)) 349 | returnValue = False 350 | 351 | tester.assertTrue(returnValue, "Comparisons failed") 352 | 353 | 354 | def clear_cache(parser): 355 | parser.delete_cache() 356 | 357 | 358 | if __name__ == '__main__': 359 | if os.environ.get('RFCEDITOR_TEST'): 360 | test_program = "run.py" 361 | else: 362 | if os.name == 'nt': 363 | test_program += '.exe' 364 | test_program = which(test_program) 365 | if test_program is None: 366 | print("Failed to find the svgcheck for testing") 367 | test_program = "run.py" 368 | unittest.main(buffer=True) 369 | -------------------------------------------------------------------------------- /svgcheck/word_properties.py: -------------------------------------------------------------------------------- 1 | # 2 | # The contents of this file comes mainly from code by 3 | # Nevil Brownlee, U Auckland 4 | 5 | # imported as wp 6 | 7 | ''' 8 | Elements not allowed in SVG 1.2: 9 | https://www.ruby-forum.com/topic/144684 10 | http://inkscape.13.x6.nabble.com/SVG-Tiny-td2881845.html 11 | marker 12 | clipPath 13 | 14 | style properties come from the CSS, they are allowed in Tiny 1.2 15 | 16 | DrawBerry produces attributes with inkscape:, 17 | 'http://www.w3.org/XML/1998/namespace', # wordle uses this 18 | 19 | e.g. inkscape:label and inkscape:groupmode 20 | DrawBerry and Inkscape seem to use this for layers; don't use it! 21 | 22 | XML NameSpaces. Specified by xmlns attribute, 23 | e.g. xmlns:inkscape="http://inkscape..." specifies inkscape elements 24 | such elements are prefixed by the namespace identifier, 25 | e.g. inkscape:label="Background" inkscape:groupmode="layer" 26 | 27 | Attributes in elements{} 'bottom lines' added during chek.py testing 28 | ''' 29 | 30 | elements = { 31 | 'svg': ('version', 'baseProfile', 'width', 'viewBox', 32 | 'preserveAspectRatio', 'snapshotTime', 33 | 'height', 'id', 'role', 'break', 'color-rendering', 34 | 'fill-rule', ''), 35 | 'desc': ('id', 'role', 'shape-rendering', 'text-rendering', 'buffered-rendering', 36 | 'visibility', ''), 37 | 'title': ('id', 'role', 'shape-rendering', 'text-rendering', 'buffered-rendering', 38 | 'visibility', ''), 39 | 'path': ('d', 'pathLength', 'stroke-miterlimit', 'id', 'role', 'fill', 'style', 40 | 'transform', 'font-size', 'fill-rule', ''), 41 | 'rect': ('x', 'y', 'width', 'height', 'rx', 'ry', 42 | 'stroke-miterlimit', 43 | 'id', 'role', 'fill', 'style', 'transform', 'fill-rule', ''), 44 | 'circle': ('cx', 'cy', 'r', 'id', 'role', 'fill', 'style', 'transform', 45 | 'fill-rule', ''), 46 | 'line': ('x1', 'y1', 'x2', 'y2', 'id', 'role', 'fill', 'transform', 'fill-rule', 47 | ''), 48 | 'ellipse': ('cx', 'cy', 'rx', 'ry', 49 | 'id', 'role', 'fill', 'style', 'transform', 'fill-rule', ''), 50 | 'polyline': ('points', 51 | 'id', 'role', 'fill', 'transform', 'fill-rule', ''), 52 | 'polygon': ('points', 53 | 'id', 'role', 'fill', 'style', 'transform', 'fill-rule', ''), 54 | 'solidColor': ('id', 'role', 'fill', 'fill-rule', ''), 55 | 'textArea': ('x', 'y', 'width', 'height', 'auto', 56 | 'id', 'role', 'fill', 'transform', 'fill-rule', ''), 57 | 'text': ('x', 'y', 'rotate', 'id', 'role', 'fill', 'style', 'transform', 58 | 'font-size', 'fill-rule', ''), 59 | 'g': ('label', 'class', 'id', 'role', 'fill', 'style', 'transform', 60 | 'fill-rule', 'visibility', ''), 61 | 'defs': ('id', 'role', 'fill', 'fill-rule', ''), 62 | 'use': ('x', 'y', 'href', 'id', 'role', 'fill', 'transform', 63 | 'fill-rule', ''), 64 | 'a': ('id', 'role', 'fill', 'transform', 'fill-rule', 'target', 65 | ''), # Linking 66 | 'tspan': ('x', 'y', 'id', 'role', 'fill', 'fill-rule', ''), 67 | 'tbreak': ('id', 'role', ''), 68 | 69 | 70 | # 'linearGradient': ('gradientUnits', 'x1', 'y1', 'x2', 'y2', 71 | # 'id', 'role', 'fill'), 72 | # 'radialGradient': ('gradientUnits', 'cx', 'cy', 'r', 73 | # 'id', 'role', 'fill'), 74 | # 'stop': ('id', 'role', 'fill'), # Gradients 75 | 76 | } 77 | 78 | # Elements have a list of attributes (above), 79 | # need to know what attributes each can have. 80 | 81 | # Properties capture CSS info, they have lists of allowable values. 82 | # Attributes have allowed values too; 83 | # we also need to know which elements they're allowed in. 84 | 85 | properties = { 86 | 'about': (), # Allowed values for element attributes, 87 | 'base': (), # including those listed in 88 | 'baseProfile': (), 89 | 'd': (), 90 | 'break': (), 91 | 'class': (), 92 | 'content': (), 93 | 'cx': ('',), 94 | 'cy': ('',), 95 | 'datatype': (), 96 | 'height': ('',), 97 | 'href': (), 98 | 'id': (), 99 | 'label': (), 100 | 'lang': (), 101 | 'pathLength': (), 102 | 'points': (), 103 | 'preserveAspectRatio': (), 104 | 'property': (), 105 | 'r': ('',), 106 | 'rel': (), 107 | 'resource': (), 108 | 'rev': (), 109 | 'role': (), 110 | 'rotate': (), 111 | 'rx': ('',), 112 | 'ry': ('',), 113 | 'space': (), 114 | 'snapshotTime': (), 115 | 'transform': (), 116 | 'typeof': (), 117 | 'version': (), 118 | 'width': ('',), 119 | 'viewBox': ('',), 120 | 'x': ('',), 121 | 'x1': ('',), 122 | 'x2': ('',), 123 | 'y': ('',), 124 | 'y1': ('',), 125 | 'y2': ('',), 126 | 127 | 'stroke': ('none', ''), # Change from I-D 128 | 'stroke-width': (), # 'inherit' 129 | 'stroke-linecap': ('butt', 'round', 'square', 'inherit'), 130 | 'stroke-linejoin': ('miter', 'round', 'bevel', 'inherit'), 131 | 'stroke-miterlimit': (), # 'inherit' 132 | 'stroke-dasharray': (), # 'inherit', 'none' 133 | 'stroke-dashoffset': (), # 'inherit' 134 | 'stroke-opacity': (), # 'inherit' 135 | 'vector-effect': ('non-scaling-stroke', 'none', 'inherit'), 136 | 'viewport-fill': ('none', 'currentColor', 'inherit', ''), 137 | 138 | 'display': ('inline', 'block', 'list-item', 'run-in', 'compact', 139 | 'table', 'inline-table', 'table-row-group', 140 | 'table-header-group', 'table-footer-group', 141 | 'table-row', 'table-column-group', 142 | 'table-column', 'table-cell', 'table-caption', 143 | 'none', 'inherit'), 144 | 'viewport-fill-opacity': (), # "inherit" 145 | 'visibility': ('visible', 'hidden', 'collapse', 'inherit'), 146 | 'image-rendering': ('auto', 'optimizeSpeed', 'optimizeQuality', 'inherit'), 147 | 'color-rendering': ('auto', 'optimizeSpeed', 'optimizeQuality', 'inherit'), 148 | 'shape-rendering': ('auto', 'optimizeSpeed', 'crispEdges', 149 | 'geometricPrecision', 'inherit'), 150 | 'text-rendering': ('auto', 'optimizeSpeed', 'optimizeLegibility', 151 | 'geometricPrecision', 'inherit'), 152 | 'buffered-rendering': ('auto', 'dynamic', 'static', 'inherit'), 153 | 154 | 'solid-opacity': (), # 'inherit' 155 | 'solid-color': ('currentColor', 'inherit', ''), 156 | 'color': ('currentColor', 'inherit', ''), 157 | 158 | 'stop-color': ('currentColor', 'inherit', ''), 159 | 'stop-opacity': (), # 'inherit' 160 | 161 | 'line-increment': (''), # 'auto', 'inherit' 162 | 'text-align': ('start', 'end', 'center', 'inherit'), 163 | 'display-align': ('auto', 'before', 'center', 'after', 'inherit'), 164 | 165 | 'font-size': (), # 'inherit' 166 | 'font-family': ('serif', 'sans-serif', 'monospace', 'inherit'), 167 | 'font-weight': ('normal', 'bold', 'bolder', 'lighter', 'inherit', 168 | '100', '200', '300', '400', '500', '600', '700', 169 | '800', '900'), 170 | 'font-style': ('normal', 'italic', 'oblique', 'inherit'), 171 | 'font-variant': ('normal', 'small-caps', 'inherit'), 172 | 'direction': ('ltr', 'rtl', 'inherit'), 173 | 'unicode-bidi': ('normal', 'embed', 'bidi-override', 'inherit'), 174 | 'text-anchor': ('start', 'middle', 'end', 'inherit'), 175 | 'fill': ('none', 'inherit', ''), # # = RGB val 176 | 'fill-rule': ('nonzero', 'evenodd', 'inherit'), 177 | 'fill-opacity': (), # 'inherit' 178 | 179 | 'requiredFeatures': (), 180 | 'requiredFormats': (), 181 | 'requiredExtensions': (), 182 | 'requiredFonts': (), 183 | 'systemLanguage': () 184 | } 185 | 186 | basic_types = { # Lists of allowed values 187 | '': ('black', '#ffffff', '#FFFFFF', 'white', '#000000'), 188 | '': ('none', 'currentColor', 'inherit', ''), 189 | '': ('id', 'base', 'lang', 'class', 'rel', 'rev', 'typeof', 'content', 190 | 'datatype', 'resource', 'about', 'property', 'space', 'fill-rule'), 191 | '': ('+',), 192 | '': ('+',) 193 | } 194 | 195 | color_default = 'black' 196 | 197 | style_properties = ('font-family', 'font-weight', 'font-style', 198 | 'font-variant', 'direction', 'unicode-bidi', 'text-anchor', 199 | 'fill', 'fill-rule', 'stroke', 'stroke-width', 'font-size', 200 | 'fill-opacity', 'stroke-linecap', 'stroke-opacity', 'stroke-linejoin') 201 | 202 | # Elements allowed within other elements 203 | svg_child = ('title', 'path', 'rect', 'circle', 'line', 'ellipse', 204 | 'polyline', 'polygon', 'solidColor', 'textArea', 205 | 'text', 'g', 'defs', 'use', 'a', 'tspan', 'desc') 206 | text_child = ('desc', 'title', 'tspan', 'text', 'a') 207 | 208 | element_children = { # Elements allowed within other elements 209 | 'svg': svg_child, 210 | 'desc': ('text'), 211 | 'title': ('text'), 212 | 'path': ('title', 'desc'), 213 | 'rect': ('title', 'desc'), 214 | 'circle': ('title', 'desc'), 215 | 'line': ('title', 'desc'), 216 | 'ellipse': ('title', 'desc'), 217 | 'polyline': ('title', 'desc'), 218 | 'polygon': ('title', 'desc'), 219 | 'solidColor': ('title', 'desc'), 220 | 'textArea': text_child, 221 | 'text': text_child, 222 | 'g': svg_child, 223 | 'defs': svg_child, 224 | 'use': ('title', 'desc'), 225 | 'a': svg_child, 226 | 'tspan': text_child + ('tbreak',), # should allow tbreak as a child 227 | } 228 | 229 | 230 | svg_urls = ( 231 | 'http://www.w3.org/2000/svg', # Base namespace for SVG 232 | ) 233 | 234 | xmlns_urls = ( # Whitelist of allowed URLs 235 | 'http://www.w3.org/2000/svg', # Base namespace for SVG 236 | 'http://www.w3.org/1999/xlink', # svgwrite uses this 237 | 'http://www.w3.org/XML/1998/namespace', # imagebot uses this -- This is xml: 238 | ) 239 | 240 | color_map = { 241 | 'rgb(0,0,0)': 'black', 242 | # 'rgb(255,255,255)': 'white', 243 | # '#fff': 'white' 244 | } 245 | 246 | color_threshold = 764 # 764 = 255 + 255 + 254 - BC original value is 381 247 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | # Tox (https://tox.testrun.org/) is a tool for running tests 2 | # in multiple virtualenvs. This configuration file will run the 3 | # test suite on all supported python versions. To use it, "pip install tox" 4 | # and then run "tox" from this directory. 5 | 6 | [tox] 7 | envlist = py{39,310,311,313}-{linux,macos,windows} 8 | 9 | [gh-actions] 10 | python = 11 | 3.9: py39 12 | 3.10: py310 13 | 3.11: py311 14 | 3.12: py312 15 | 3.13: py313 16 | 17 | [gh-actions:env] 18 | PLATFORM = 19 | ubuntu-latest: linux 20 | macos-latest: macos 21 | windows-latest: windows 22 | 23 | [testenv] 24 | changedir = svgcheck 25 | commands = 26 | python --version 27 | coverage run test.py 28 | deps = 29 | .[tests] 30 | allowlist_externals = 31 | coverage 32 | --------------------------------------------------------------------------------