├── .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 |

4 |
5 | [](https://github.com/ietf-tools/svgcheck/releases)
6 | [](https://github.com/ietf-tools/svgcheck/blob/main/LICENSE)
7 | [](https://pypi.org/project/svgcheck/)
8 | [](https://pypi.org/project/svgcheck/)
9 | [](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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
5 |
--------------------------------------------------------------------------------
/svgcheck/Tests/DrawBerry-sample-2.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
29 |
--------------------------------------------------------------------------------
/svgcheck/Tests/IETF-test.svg:
--------------------------------------------------------------------------------
1 |
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 |
4 |
--------------------------------------------------------------------------------
/svgcheck/Tests/colors.svg:
--------------------------------------------------------------------------------
1 |
19 |
--------------------------------------------------------------------------------
/svgcheck/Tests/dia-sample-svg.svg:
--------------------------------------------------------------------------------
1 |
2 |
48 |
--------------------------------------------------------------------------------
/svgcheck/Tests/example-dot.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
76 |
--------------------------------------------------------------------------------
/svgcheck/Tests/good.svg:
--------------------------------------------------------------------------------
1 |
2 |
20 |
--------------------------------------------------------------------------------
/svgcheck/Tests/httpbis-proxy20-fig6.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/svgcheck/Tests/malformed.svg:
--------------------------------------------------------------------------------
1 |
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 |
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 |
10 |
--------------------------------------------------------------------------------
/svgcheck/Tests/threshold.svg:
--------------------------------------------------------------------------------
1 |
27 |
--------------------------------------------------------------------------------
/svgcheck/Tests/viewBox-both.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/svgcheck/Tests/viewBox-height.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/svgcheck/Tests/viewBox-none.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/svgcheck/Tests/viewBox-width.svg:
--------------------------------------------------------------------------------
1 |
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 |
--------------------------------------------------------------------------------