Squashed 'third_party/pycrc/' content from commit cb91196b9
Change-Id: Iaed6f7d683e3c11395f10f0724f973363aad2cdb
git-subtree-dir: third_party/pycrc
git-subtree-split: cb91196b920d1f892c05941ed470c7a80cba7596
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..a72d066
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,10 @@
+.svn
+.*.swp
+*.pyc
+*.pyo
+__pycache__
+build
+doc/pycrc.1
+doc/pycrc.html
+doc/docbook.css
+test/pycrc_files.tar.gz
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..3c04ca9
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,15 @@
+language: python
+python:
+ - "2.6"
+ - "2.7"
+ - "3.2"
+ - "3.3"
+ - "3.4"
+ - "3.5"
+ - "3.6"
+
+install:
+ python setup.py install
+
+script:
+ python test/test.py -av
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..e81101d
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,14 @@
+Thomas Pircher: main developer.
+
+Matthias Urlichs: removed the unused 'direct' parameter and added a fix not to
+ recurse into main() when an unknown algorithm is selected.
+
+Marti Raudsepp: improved spacing for the table-driven algorithm.
+
+Stephan Brumme: his implementation of the slice-by-x algorithm was used as a
+ basis for the implementation in pycrc.
+
+Danjel McGougan: whose Universal Crc project was highly influential in the
+ implementation of widths < 8 in the table-driven algorithm.
+
+André Hartmann, ashelly and others for minor fixes.
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..a086a96
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,511 @@
+# Change Log
+All notable changes to this project will be documented in this file.
+For a detailed list of changes see the [pycrc GitHub][pycrc github] page.
+This project adheres to [Semantic Versioning](http://semver.org/).
+
+
+
+## [v0.9.1] - 2017-09-09
+
+### Added
+- Added setup.py script to install pycrc on the system, if desired.
+- Added checks about possibly unsuitable polynomials. Use the --force-poly
+ option to override the error message.
+
+### Changed
+- Completely rewritten the code generator back-end. The new back-end is more
+ flexible and allows for a better optimisation of the generated expressions.
+- Moved the python code under the `pycrc` directory and changed how the pycrc
+ sub-modules are included. Before one would write `import crc_xxx`, now one
+ would write `import pycrc.xxx`.
+- New license for the documentation:
+ [Creative Commons Attribution-Share Alike 4.0 Unported License][CC-BY-SA-4.0].
+
+### Fixed
+- Fixed binary files handling with Python 2.7.
+ Fixes #11. Thanks to James Bowman.
+- Fixed some spelling. Thanks to Frank (ftheile) and ashelly.
+- Fixed Header Guard generation. Don't use underscores to start the header
+ guard name. Thanks to Andre Hartmann.
+
+
+## [v0.9] - 2016-01-06
+
+### Added
+- Added Stephan Brumme to the `AUTHORS` file as his implementation of the
+ slice-by algorithm is the basis for pycrc's implementation.
+- Added a new option `--slice-by`. This option is still experimental and
+ limited in its use.
+
+### Changed
+- Documented the experimental `--slice-by option`.
+- Simplified the implementation where Width is less than 8 bits.
+- Run the code through `pylint`.
+- __API change__: changed the names of the member variables from `CamelCase` to the
+ format suggested in `PEP 0008` (lowercase letters and words separated by
+ underscore).
+
+### Fixed
+- Suppressed the `crc_reflect` function where not needed. Addresses part of #8.
+ Thanks to Craig McQueen.
+- Allow strings with values greater than 0x80 in `--check-hexstring`.
+- When the CRC width is less than 8 then the `bit-by-bit` algorithm needs to
+ apply the CRC mask to the final value.
+ Fixes #10. Thanks to Steve Geo.
+- Fixed the initial value of the 16-bit `CCITT` algorithm. Renamed the model
+ from `ccitt` to `crc-16-ccitt`.
+ Fixes #7. Thanks to Craig McQueen.
+
+
+## [v0.8.3] - 2015-08-31
+
+### Changed
+- pycrc has a new [homepage][pycrc home].
+- The [issue tracker on GitHub][pycrc issues]
+ is now advertised as the preferred issue tracker.
+- Applied some minor optimisations to the generated table-driven code.
+- Belatedly added an authors file. Should I have forgotten to mention someone
+ please don't hesitate to send a mail.
+- Upgraded documentation to DocBook 5.
+- Removed sourceforge mailing list from `README.md` in an effort to move pycrc
+ away from sourceforge.
+- Removed the experimental `--bitwise-expression` option to facilitate
+ restructuring of the code.
+- The preferred format for the input data for the Python API is now a byte
+ array. But if a string is supplied it is decoded as UTF-8 string.
+ Alternative formats are not supported and must be passed to the functions
+ as byte arrays.
+- Changed the signature of the `crc_update()` function: the data argument is
+ now a pointer to void to improve compatibility with C++.
+ Thanks to Kamil Szczygieł.
+ This closes GitHub issue #4.
+
+
+## [v0.8.2] - 2014-12-04
+
+### Changed
+- Smaller code cleanups.
+- Stated more clearly that the bitwise expression algorithm is experimental in
+ the documentation.
+- Fixed a typo in the documentation.
+ The description previously stated:
+ "The reflected value of 0xa3 (10100010b) is 0x45 (01000101b)"
+ but this should be:
+ "The reflected value of 0xa2 (10100010b) is 0x45 (01000101b)"
+ Thanks to Andreas Nebenfuehr for reporting the mistake.
+- Small cleanups.
+ Added a tests for special cases. For now, added `crc-5` with non-inverted
+ input. This test is currently failing.
+- Removed warning about even polynomials. As Lars Pötter rightly pointed out,
+ polynomials may be even.
+ Added a caveat emptor about even polinomials in the documentation.
+
+### Fixed
+- The table-driven code for polynomials of width < 8 using a table index
+ width < 8 was producing a wrong checksum.
+ Thanks to Radosław Gancarz.
+- Updated the generated code to cope with big Widths (>32 bits) on 32 bit
+ processors.
+ Since C89 does not give a way to specify the minimum length of a data type,
+ the test does not validate C89 code using Widths > 32.
+ For C99, the `uint_fastN_t` data types are used or long long, if the Width is
+ unknown.
+
+
+## [v0.8.1] - 2013-05-17
+
+### Changed
+- Updated [qm.py from GitHub][qm github].
+- Explicitly stated that the output of pycrc is not considered a substantial
+ part of the code of pycrc in `README.md`.
+- Re-organised the symbol table: grouped the code by functionality, not by
+ algorithm.
+- The input to the CRC routines can now be bytes or strings.
+- Minor formatting change in the manpage.
+- Better python3 compatibility.
+- Added the files generated with the `bwe` algorithm to `check_files.sh`.
+
+### Fixed
+- Fixed a bug in the handling of hexstrings in Python3.
+ Thanks to Matthias Kuehlewein.
+- Added `--check-hexstring` to the tests.
+- Remove obsolete and unused `direct` parameter.
+ Merge pull request #2 from smurfix/master.
+ Thanks to Matthias Urlichs.
+- Don't recurse into main() when an unknown algorithm is selected.
+ Merge pull request #2 from smurfix/master.
+ Thanks to Matthias Urlichs.
+
+
+## [v0.8] - 2013-01-04
+
+### Added
+- Merged (private) bitwise-expression branch to main.
+ This adds the highly experimental `bitwise-expression` (`bwe`) code generator
+ target, which might one day be almost as fast as the table-driven code but
+ much smaller.
+ At the moment the generated code is bigger and slower than any other
+ algorithm, so use at your own risk.
+
+### Changed
+- Now it is possible to specify the `--include` option multiple times.
+- Completely revisited and reworked the documentation.
+- Updated the command line help screen with more useful command descriptions.
+- Removed the `-*- coding: Latin-1 -*-` string.
+- Updated the copyright year to 2013.
+- Renamed abbreviations to `bbb`, `bbf`, `tbl`.
+- It is possible now to abbreviate the algorithms (`bbb` for `bit-by-bit`,
+ `bbf` for `bit-by-bit-fast` and `tbl` for `table-driven`).
+ Added the list of supported CRC models to the error message when an
+ unknown model parameter was supplied.
+- Documented the possibility to abbreviate the algorithms. Minor
+ improvements in the documentation.
+- Added a note to `README.md` that version 0.7.10 of pycrc is the last one
+ known to work with Python 2.4.
+- Updated a link to the list of CRC models.
+- Renamed i`README` to `README.md`.
+- Updated link to the [Catalogue of parametrised CRC algorithms][crc catalogue].
+
+
+## [v0.7.11] - 2012-10-20
+
+### Changed
+- Improved Python3 compatibility. pycrc now requires Python 2.6 or later.
+- Added a test for compiled standard models.
+
+### Fixed
+- Fixed a wrong `check` value of the `crc-64-jones` model.
+- Don't use `snprintf()` with `c89` code, changed to `sprintf()`.
+- Deleted `test.sh` shell script and replaced it with `test.py`.
+
+
+## [v0.7.10] - 2012-02-13
+
+### Added
+- Added the models `crc-12-3gpp`, `crc-16-genibus`, `crc-32-bzip2` and `crc-64-xz`.
+ Taken from [Greg Cook's Catalogue of parametrised CRC algorithms][crc catalogue].
+
+### Changed
+- Bad-looking C code generated; make sure the `bit-by-bit`(`-fast`) code does not
+ contain two instructions on one line. Thanks to "intgr" for the fix.
+- Some small code clean-up: use `set()` when appropriate.
+
+### Fixed
+- Fixed a mistake in the man page that still used the old model name
+ `crc-32mpeg` instead of `crc-32-mpeg`. Thanks to Marek Erban.
+
+
+## [v0.7.9] - 2011-12-08
+
+### Fixed
+- Fixed a bug in the generated C89 code that included `stdint.h`.
+ Thanks to Frank (ftheile).
+ Closes issue 3454356.
+- Fixed a bug in the generated C89 code when using a 64 bit CRC.
+- Using the `--verbose` option made pycrc quit without error message.
+
+
+## [v0.7.8] - 2011-07-10
+
+### Changed
+- When generating C code for the C89 or ANSI standard, don't include `stdint.h`.
+ This closes issue 3338930
+- If no output file name is given while generating a C file, then pycrc will
+ `#include` a hypothetical `pycrc.h` file instead of a `stdout.h` file.
+ Also, added a comment on that line to make debugging easier.
+ Closes issue 3325109.
+- Removed unused variable `this_option_optind` in the generated option parser.
+
+
+## [v0.7.7] - 2011-02-11
+
+### Changed
+- Updated the copyright year.
+ Fixed some coding style issues found by `pylint` and `pychecker`.
+
+### Fixed
+- Substituted the deprecated function `atoi()` with `int()`. Closes issue 3136566.
+ Thanks to Tony Smith.
+- Updated the documentation using Windows-style calls to the Python interpreter.
+
+
+## [v0.7.6] - 2010-10-21
+
+### Changed
+- Rewritten macro parser from scratch. Simplified the macro language.
+- Changed a simple division (/) to a integer division (//) for Python3
+ compatibility.
+
+### Fixed
+- Fixed a minor bug in the command line parsing of the generated main function.
+
+
+## [v0.7.5] - 2010-03-28
+
+### Added
+- Python implementation of the `table-driven` algorithm can handle widths less
+ than 8.
+- Suppressed warnings of unused cfg structure on partially defined models.
+
+### Removed
+- Removed the half-baken and confusing `--direct` option.
+
+### Changed
+- C/C++ code can now be generated for the table-driven algorithm with widths
+ that are not byte-aligned or less than 8.
+ This feature was heavily inspired by a similar feature in Danjel McGougan's
+ [Universal Crc][universal crc].
+- __API change__: introduced new variable `crc_shift`, member of the `crc_cfg_t`
+ structure, which must be initialised manually when the width was undefined
+ during C/C++ code generation.
+- Minor code cleanup.
+
+
+## [v0.7.4] - 2010-01-24
+
+### Added
+- Added `crc-16-modbus`. Closes issue 2896611.
+
+### Changed
+- Changed the `xor-in` value of the `crc-64-jones` model.
+- Set xmodem parameters equal to the `zmodem` parameters.
+- Generate more uniform error messages.
+- Added a warning for even polynomials.
+
+### Fixed
+- Fix for unused variable argv.
+ Closes issue 2893224. Thanks to Marko von Oppen.
+
+
+## [v0.7.3] - 2009-10-25
+
+### Added
+- Added `crc-64-jones` CRC model. Thanks to Waterspirit.
+
+### Changed
+- Renamed `crc-32mpeg` to `crc-32-mpeg`.
+
+
+## [v0.7.2] - 2009-09-30
+
+### Fixed
+- Fixed a bug that caused the result of the Python `table-driven` code not
+ being evaluated at all.
+ Closes issue 2870630. Thanks to Ildar Muslukhov.
+
+
+## [v0.7.1] - 2009-04-05
+
+### Added
+- Added `crc-32mpeg`. Thanks to Thomas Edwards.
+
+
+## [v0.7] - 2009-02-27
+
+### Added
+- Added the `--direct` option.
+- Added `--check-hexstring` option. Closes issue 2545183.
+ Thanks to Arnim Littek.
+- Added a check for extra arguments on the command line.
+ Closes issue 2545185. Thanks to Arnim Littek.
+
+### Changed
+- Added one more example in the documentation.
+
+
+## [v0.6.7] - 2008-12-11
+
+### Changed
+- Run Python's 2to3 script on all files.
+ Check the code on a x64 platform.
+- Fixed a bug that raised an exception when an unknown model was selected.
+
+
+## [v0.6.6] - 2008-06-05
+
+### Changed
+- New license for the documentation:
+ [Creative Commons Attribution-Share Alike 3.0 Unported License][CC-BY-SA-3.0].
+
+### Fixed
+- Fixed a bug in the `print_params()` function. Closes issue 1985197.
+ Thanks to Artur Lipowski.
+
+
+## [v0.6.5] - 2008-03-03
+
+### Added
+- Added dallas-1-wire 8 bit CRC.
+- Added `r-crc-16 model` (DECT (cordless digital standard) packets A-field
+ according to ETSI EN 300 175-3 v2.1.1).
+ Thanks to "raimondo".
+- Added `--crc-type` and `--include-file` options.
+- Added new file to handle CRC models.
+
+### Changed
+- Added extern "C" declaration to the generated C header file.
+ Thanks to Nathan Royer.
+- Changed the API to take the CRC model direct as parameter. Deleted the need
+ for an obscure `opt` object.
+
+### Fixed
+- Fixed a problem with the generated code for bit-by-bit-fast algorithms.
+ Thanks to Hans Bacher.
+
+
+## [v0.6.4] - 2007-12-05
+
+### Fixed
+- Fixed a bug in the code generator for the `table-driven`
+ algorithm. Thanks to Tom McDermott. Closes issue 1843774
+
+
+## [v0.6.3] - 2007-10-13
+
+### Added
+- Added new models: `crc-5`, `crc-15`, `crc-16-usb`, `crc-24`, `crc-64`.
+ The new models are taken from Ray Burr's CrcMoose.
+
+### Fixed
+- Fixed some portability problems in the generated code.
+ Thanks to Helmut Bauer. Closes issue 1812894.
+- The option `--check-file` works now with `--width` < 8. Closes issue 1794343.
+- Removed unnecessary restriction on the width when using the `bit-by-bit-fast`
+ algorithm. Closes issue 1794344.
+
+
+## [v0.6.2] - 2007-08-25
+
+### Changed
+- Simplified the table-driven code. Closes issue 1727128.
+- Changed the macro language syntax to a better format.
+- Renamed `crc_code_gen.py` to `crc_parser.py`.
+- Documented the usage of the `crc_*` modules.
+
+### Fixed
+- The parameter to `--check-string` was ignored. Closes issue 1781637.
+
+
+## [v0.6.1] - 2007-08-12
+
+### Added
+- Added test for C89 compilation.
+- Added a test case to loop over the input bytes one by one.
+
+### Removed
+- Deleted obsolete options.
+
+### Changed
+- Tidied up the documentation.
+ Code cleanup.
+
+### Fixed
+- Bugfix in the source code generator for C89:
+ Compilation error due to mismatch of parameters in the `crc_finalize`
+ funtion.
+- Changes related to 919107: Code generator includes `reflect()` function even
+ if not needed.
+- Fixed a typo in the C89 source code generator.
+ Thanks to Helmut Bauer.
+
+
+## [v0.6] - 2007-05-21
+
+### Added
+- Added the `--std` option to generate C89 (ANSI) compliant code.
+- Added a new check to the test script which validate all possible
+ combination of undefined parameters.
+- Made the generated main function cope with command line arguments.
+- Added the `--generate` table option.
+- Added a template engine for the code generation. Split up `pycrc.py` into
+ smaller modules.
+- Added obsolete options again tor legacy reasons.
+- Added a better handling of the `--model` parameter.
+
+### Changed
+- Reduced the size of the symbol table by re-arranging items.
+- Changed licence to the MIT licence. This makes the additional clause for
+ generated source code obsolete.
+ Changed all command line options with underscores to hyphen (e.g.
+ `table_driven` becomes `table-driven`).
+ Added the option `--generate` which obsoletes the old options `--generate_c`
+ `--generate_h` etc.
+
+
+## [v0.5] - 2007-03-25
+
+### Fixed
+- Fixed bug 1686404: unhandled exception when called with both options
+ `--table_idx_width` and `--check_file`.
+- Eliminated useless declaration of `crc_reflect`, when not used.
+- Corrected typos in the documentation.
+
+
+## [v0.4] - 2007-01-26
+
+### Added
+- Added more parameter sets (now supported: `crc-8`, `crc-16`, `citt`, `kermit`,
+ `x-25`, `xmodem`, `zmodem`, `crc-32`, `crc-32c`, `posix`, `jam`, `xfer`) from
+ [Greg Cook's Catalogue of parametrised CRC algorithms][crc catalogue].
+- Added Doxygen documentation strings to the functions.
+- Added the `--symbol_prefix` option.
+- Added the `--check_file` option.
+- Added a non-regression test on the generated C source.
+
+### Changed
+- Eliminated needless documentation of not generated functions.
+- Many corrections to the manual (thanks Francesca) Documented the new
+ parameter sets.
+- Added some new tests, disabled the random loop.
+
+### Fixed
+- Corrected many typos and bad phrasing (still a lot to do) Documented the
+ `--symbol_prefix` option.
+
+
+## [v0.3] - 2007-01-14
+
+### Added
+- First public release pycrc v0.3
+
+
+
+[Unreleased]: https://github.com/tpircher/pycrc
+[v0.9.1]: https://github.com/tpircher/pycrc/releases/tag/v0.9.1
+[v0.9]: https://github.com/tpircher/pycrc/releases/tag/v0.9
+[v0.8.3]: https://github.com/tpircher/pycrc/releases/tag/v0.8.3
+[v0.8.2]: https://github.com/tpircher/pycrc/releases/tag/v0.8.2
+[v0.8.1]: https://github.com/tpircher/pycrc/releases/tag/v0.8.1
+[v0.8]: https://github.com/tpircher/pycrc/releases/tag/v0.8
+[v0.7.11]: https://github.com/tpircher/pycrc/releases/tag/v0.7.11
+[v0.7.10]: https://github.com/tpircher/pycrc/releases/tag/v0.7.10
+[v0.7.9]: https://github.com/tpircher/pycrc/releases/tag/v0.7.9
+[v0.7.8]: https://github.com/tpircher/pycrc/releases/tag/v0.7.8
+[v0.7.7]: https://github.com/tpircher/pycrc/releases/tag/v0.7.7
+[v0.7.6]: https://github.com/tpircher/pycrc/releases/tag/v0.7.6
+[v0.7.5]: https://github.com/tpircher/pycrc/releases/tag/v0.7.5
+[v0.7.4]: https://github.com/tpircher/pycrc/releases/tag/v0.7.4
+[v0.7.3]: https://github.com/tpircher/pycrc/releases/tag/v0.7.3
+[v0.7.2]: https://github.com/tpircher/pycrc/releases/tag/v0.7.2
+[v0.7.1]: https://github.com/tpircher/pycrc/releases/tag/v0.7.1
+[v0.7]: https://github.com/tpircher/pycrc/releases/tag/v0.7
+[v0.6.7]: https://github.com/tpircher/pycrc/releases/tag/v0.6.7
+[v0.6.6]: https://github.com/tpircher/pycrc/releases/tag/v0.6.6
+[v0.6.5]: https://github.com/tpircher/pycrc/releases/tag/v0.6.5
+[v0.6.4]: https://github.com/tpircher/pycrc/releases/tag/v0.6.4
+[v0.6.3]: https://github.com/tpircher/pycrc/releases/tag/v0.6.3
+[v0.6.2]: https://github.com/tpircher/pycrc/releases/tag/v0.6.2
+[v0.6.1]: https://github.com/tpircher/pycrc/releases/tag/v0.6.1
+[v0.6]: https://github.com/tpircher/pycrc/releases/tag/v0.6
+[v0.5]: https://github.com/tpircher/pycrc/releases/tag/v0.5
+[v0.4]: https://github.com/tpircher/pycrc/releases/tag/v0.4
+[v0.3]: https://github.com/tpircher/pycrc/releases/tag/v0.3
+
+[pycrc home]: https://pycrc.org
+[pycrc github]: https://github.com/tpircher/pycrc
+[pycrc issues]: https://github.com/tpircher/pycrc/issues
+[crc catalogue]: http://regregex.bbcmicro.net/crc-catalogue.htm
+[universal crc]: http://mcgougan.se/universal_crc/
+[qm github]: https://github.com/tpircher/quine-mccluskey
+[CC-BY-SA-3.0]: https://creativecommons.org/licenses/by-sa/3.0/
+[CC-BY-SA-4.0]: https://creativecommons.org/licenses/by-sa/4.0/
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..9f90d03
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,19 @@
+Copyright (c) 2006-2015, Thomas Pircher <tehpeh-web@tty1.net>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..cab802b
--- /dev/null
+++ b/README.md
@@ -0,0 +1,80 @@
+
+
+ _ __ _ _ ___ _ __ ___
+ | '_ \| | | |/ __| '__/ __|
+ | |_) | |_| | (__| | | (__
+ | .__/ \__, |\___|_| \___|
+ |_| |___/
+
+ https://pycrc.org
+
+
+pycrc is a free, easy to use Cyclic Redundancy Check (CRC) calculator and C
+source code generator.
+
+
+
+System Requirements
+===================
+
+pycrc requires Python 2.6 or later. Python 3.x is supported.
+The last version compatible with Python 2.4 is pycrc v0.7.10.
+
+
+Running pycrc
+=============
+
+This program doesn't need to be installed to be called. The script can be
+executed from the source directory.
+Simply call the python interpreter with the script as parameter:
+
+ python pycrc.py [options]
+
+On a UNIX-like system, you can make the pycrc.py wrapper script executable and
+call it like a normal binary:
+
+ chmod +x pycrc.py
+ ./pycrc.py [options]
+
+
+Installation
+============
+
+Install pycrc (if required) using the setup.py script:
+
+ python setup.py install
+
+
+Getting help
+============
+
+If you are new to pycrc and want to generate C code, start with
+[the tutorial](https://pycrc.org/tutorial.html).
+
+The [pycrc manual page](https://pycrc.org/pycrc.html) explains the command line
+options in some detail and also gives some more examples how to use pycrc.
+
+If you have found a bug in pycrc or want to request a feature please take the
+time and submit it to the
+[issue tracker](https://github.com/tpircher/pycrc/issues).
+Thanks for your help.
+
+Also see the [frequently asked questions](https://pycrc.org/faq.html).
+
+
+Feedback
+========
+
+If you like pycrc, let me know and drop me a note. If you don't like pycrc let
+me know what you don't like and why. In both cases, I would really appreciate
+some [feed back](https://sourceforge.net/projects/pycrc/reviews/).
+If you want some idea how to say thanks for this software, please have a look
+[here](https://www.tty1.net/say-thanks_en.html).
+
+
+Copyright of the generated source code
+======================================
+
+The code generated by pycrc is not considered a substantial portion of the
+software, therefore the licence does not cover the generated code, and the
+author of pycrc will not claim any copyright on the generated code.
diff --git a/doc/Makefile b/doc/Makefile
new file mode 100644
index 0000000..a0f2581
--- /dev/null
+++ b/doc/Makefile
@@ -0,0 +1,24 @@
+HTML_PARAMS = style-html.xsl
+MAN_PARAMS = style-man.xsl
+
+source = pycrc.xml
+targets = $(source:.xml=.html) $(source:.xml=.1)
+
+all: $(targets)
+
+.PHONY: clean
+clean:
+ $(RM) $(targets)
+
+.PHONY: check
+check:
+ xmllint --valid --noout $(source)
+
+%.html: %.xml $(HTML_PARAMS)
+ saxon-xslt -o $@ $^
+
+%.1: %.xml $(MAN_PARAMS)
+ saxon-xslt -o $@ $^
+
+%.txt: %.html
+ links -dump -no-numbering -no-references $< > $@
diff --git a/doc/pycrc.xml b/doc/pycrc.xml
new file mode 100644
index 0000000..9f5a4a2
--- /dev/null
+++ b/doc/pycrc.xml
@@ -0,0 +1,681 @@
+<?xml version='1.0' encoding="utf-8"?>
+
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V5.1//EN"
+ "http://www.oasis-open.org/docbook/xml/5.0b5/dtd/docbook.dtd" [
+<!ENTITY project_version "0.9.1">
+<!ENTITY project_homepage "https://pycrc.org">
+<!ENTITY project_models "https://pycrc.org/models.html">
+<!ENTITY date "2017-08-11">
+<!ENTITY author_firstname "Thomas">
+<!ENTITY author_surname "Pircher">
+<!ENTITY author_email "tehpeh-web@tty1.net">
+<!ENTITY bit-by-bit "bit-by-bit">
+<!ENTITY bbb "bbb">
+<!ENTITY bit-by-bit-fast "bit-by-bit-fast">
+<!ENTITY bbf "bbf">
+<!ENTITY table-driven "table-driven">
+<!ENTITY tbl "tbl">
+<!ENTITY slice-by "slice-by">
+<!ENTITY width "Width">
+<!ENTITY poly "Polynomial">
+<!ENTITY reflect_in "ReflectIn">
+<!ENTITY xor_in "XorIn">
+<!ENTITY reflect_out "ReflectOut">
+<!ENTITY xor_out "XorOut">
+<!ENTITY check "Check">
+]>
+
+
+<refentry xmlns='http://docbook.org/ns/docbook' version="5.0" xml:id="pycrc">
+ <info>
+ <title>pycrc</title>
+ <productname>pycrc</productname>
+ <productnumber>&project_version;</productnumber>
+ <author>
+ <personname>
+ <firstname>&author_firstname;</firstname>
+ <surname>&author_surname;</surname>
+ </personname>
+ <contrib>Author of pycrc and this manual page.</contrib>
+ <email>&author_email;</email>
+ </author>
+ <date>&date;</date>
+ </info>
+
+ <refmeta>
+ <refentrytitle>pycrc</refentrytitle>
+ <manvolnum>1</manvolnum>
+ </refmeta>
+
+ <refnamediv>
+ <refname>pycrc</refname>
+ <refpurpose>a free, easy to use Cyclic Redundancy Check (CRC) calculator and C source code generator.</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <cmdsynopsis>
+ <command>python pycrc.py</command>
+ <arg>OPTIONS</arg>
+ </cmdsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+ <para>
+ <link xlink:href="&project_homepage;">pycrc</link>
+ is a CRC reference implementation in Python and a C source code generator for parametrised CRC models.
+ The generated C source code can be optimised for simplicity,
+ speed or small memory footprint, as required on small embedded systems.
+
+ The following operations are implemented:
+ <itemizedlist>
+ <listitem>
+ <para>calculate the checksum of a string (ASCII or hex)</para>
+ </listitem>
+ <listitem>
+ <para>calculate the checksum of a file</para>
+ </listitem>
+ <listitem>
+ <para>generate the header and source files for a C implementation.</para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ pycrc supports the following variants of the CRC algorithm:
+ <itemizedlist>
+ <listitem>
+ <para><replaceable>&bit-by-bit;</replaceable> or <replaceable>&bbb;</replaceable>:
+ the basic algorithm which operates individually on every bit of the augmented message
+ (i.e. the input data with <replaceable>&width;</replaceable> zero bits added at the end).
+ This algorithm is a straightforward implementation of the basic polynomial division and
+ is the easiest one to understand, but it is also the slowest one among all possible
+ variants.
+ </para>
+ </listitem>
+ <listitem>
+ <para><replaceable>&bit-by-bit-fast;</replaceable> or <replaceable>&bbf;</replaceable>:
+ a variation of the simple <replaceable>&bit-by-bit;</replaceable> algorithm.
+ This algorithm still iterates over every bit of the message, but does not augment
+ it (does not add <replaceable>&width;</replaceable> zero bits at the end).
+ It gives the same result as the <replaceable>&bit-by-bit;</replaceable> method by
+ carefully choosing the initial value of the algorithm.
+ This method might be a good choice for embedded platforms, where code space is more
+ important than execution speed.
+ </para>
+ </listitem>
+ <listitem>
+ <para><replaceable>&table-driven;</replaceable> or <replaceable>&tbl;</replaceable>:
+ the standard table driven algorithm.
+ This is the fastest variant because it operates on one byte at a time, as opposed to one
+ bit at the time.
+ This method uses a look-up table (usually of 256 elements), which might not be acceptable
+ for small embedded systems. The number of elements in the look-up table can be reduced
+ with the <option>--table-idx-width</option> command line switch.
+ The value of 4 bits for the table index (16 elements in the look-up table) can be a good
+ compromise between execution speed and code size.
+ </para>
+ <para>
+ The <option>--slice-by</option> option enables a variant of the <replaceable>&table-driven;</replaceable>
+ algorithm that operates on 32 bits of data or more at a time rather than 8 bits.
+ This can dramatically speed-up the calculation of the CRC, at the cost of
+ increased code and data size.
+ <emphasis>Note</emphasis>: this option is experimental and not well-tested.
+ Check your results and please raise bugs if you find problems.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Options</title>
+ <variablelist>
+ <varlistentry>
+ <term>
+ <option>--version</option>
+ </term>
+ <listitem>
+ <para>show the program version number and exit.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <option>-h</option>
+ </term>
+ <term>
+ <option>--help</option>
+ </term>
+ <listitem>
+ <para>show this help message and exit.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <option>--verbose</option>
+ </term>
+ <listitem>
+ <para>be more verbose; in particular, print the value of the parameters and the chosen model to <filename>stdout</filename>.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <option>--check-string=</option><replaceable>STRING</replaceable>
+ </term>
+ <listitem>
+ <para>calculate the checksum of a string (default: <quote><replaceable>123456789</replaceable></quote>). If the string contains non-ASCII characters then it will be UTF-8 decoded.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <option>--check-hexstring=</option><replaceable>STRING</replaceable>
+ </term>
+ <listitem>
+ <para>calculate the checksum of a hexadecimal number string.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <option>--check-file=</option><replaceable>FILE</replaceable>
+ </term>
+ <listitem>
+ <para>calculate the checksum of a file. If the file contains non-ASCII characters then it will be UTF-8 decoded.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <option>--generate=</option><replaceable>CODE</replaceable>
+ </term>
+ <listitem>
+ <para>generate C source code; choose the type from {<replaceable>h</replaceable>,
+ <replaceable>c</replaceable>, <replaceable>c-main</replaceable>, <replaceable>table</replaceable>}.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <option>--std=</option><replaceable>STD</replaceable>
+ </term>
+ <listitem>
+ <para>specify the C dialect of the generated code from {C89, ANSI, C99}.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <option>--algorithm=</option><replaceable>ALGO</replaceable>
+ </term>
+ <listitem>
+ <para>choose an algorithm from {<replaceable>bit-by-bit</replaceable>, <replaceable>bbb</replaceable>,
+ <replaceable>bit-by-bit-fast</replaceable>, <replaceable>bbf</replaceable>,
+ <replaceable>table-driven</replaceable>, <replaceable>tbl</replaceable>,
+ <replaceable>all</replaceable>}.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <option>--model=</option><replaceable>MODEL</replaceable>
+ </term>
+ <listitem>
+ <para>choose a parameter set from
+ {<replaceable>crc-5</replaceable>,
+ <replaceable>crc-8</replaceable>,
+ <replaceable>dallas-1-wire</replaceable>,
+ <replaceable>crc-12-3gpp</replaceable>,
+ <replaceable>crc-15</replaceable>,
+ <replaceable>crc-16</replaceable>,
+ <replaceable>crc-16-usb</replaceable>,
+ <replaceable>crc-16-modbus</replaceable>,
+ <replaceable>crc-16-genibus</replaceable>,
+ <replaceable>crc-16-ccitt</replaceable>,
+ <replaceable>r-crc-16</replaceable>,
+ <replaceable>kermit</replaceable>,
+ <replaceable>x-25</replaceable>,
+ <replaceable>xmodem</replaceable>,
+ <replaceable>zmodem</replaceable>,
+ <replaceable>crc-24</replaceable>,
+ <replaceable>crc-32</replaceable>,
+ <replaceable>crc-32c</replaceable>,
+ <replaceable>crc-32-mpeg</replaceable>,
+ <replaceable>crc-32-bzip2</replaceable>,
+ <replaceable>posix</replaceable>,
+ <replaceable>jam</replaceable>,
+ <replaceable>xfer</replaceable>,
+ <replaceable>crc-64</replaceable>,
+ <replaceable>crc-64-jones</replaceable>,
+ <replaceable>crc-64-xz</replaceable>}.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <option>--width=</option><replaceable>NUM</replaceable>
+ </term>
+ <listitem>
+ <para>use <replaceable>NUM</replaceable> bits in the <replaceable>&poly;</replaceable>.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <option>--poly=</option><replaceable>HEX</replaceable>
+ </term>
+ <listitem>
+ <para>use <replaceable>HEX</replaceable> as <replaceable>&poly;</replaceable>.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <option>--reflect-in=</option><replaceable>BOOL</replaceable>
+ </term>
+ <listitem>
+ <para>reflect the octets in the input message.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <option>--xor-in=</option><replaceable>HEX</replaceable>
+ </term>
+ <listitem>
+ <para>use <replaceable>HEX</replaceable> as initial value.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <option>--reflect-out=</option><replaceable>BOOL</replaceable>
+ </term>
+ <listitem>
+ <para>reflect the resulting checksum before applying the &xor_out; value.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <option>--xor-out=</option><replaceable>HEX</replaceable>
+ </term>
+ <listitem>
+ <para>xor the final CRC value with <replaceable>HEX</replaceable>.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <option>--slice-by=</option><replaceable>NUM</replaceable>
+ </term>
+ <listitem>
+ <para>speed-up the &table-driven; calculation by operating on
+ <replaceable>NUM</replaceable> octets of data rather than a
+ single octet at a time.
+ <replaceable>NUM</replaceable> must be one of the values
+ {<replaceable>4</replaceable>, <replaceable>8</replaceable>,
+ <replaceable>16</replaceable>}.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <option>--table-idx-width=</option><replaceable>NUM</replaceable>
+ </term>
+ <listitem>
+ <para>use <replaceable>NUM</replaceable> bits to index the CRC table;
+ <replaceable>NUM</replaceable> must be one of the values
+ {<replaceable>1</replaceable>, <replaceable>2</replaceable>,
+ <replaceable>4</replaceable>, <replaceable>8</replaceable>}.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <option>--force-poly</option>
+ </term>
+ <listitem>
+ <para>override any errors about possibly unsuitable
+ polynoms. pycrc does not allow even polynoms or
+ polynoms that are wider than &width;. Use this option
+ to override the error, if you know what you are
+ doing.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <option>--symbol-prefix=</option><replaceable>STRING</replaceable>
+ </term>
+ <listitem>
+ <para>when generating source code, use <replaceable>STRING</replaceable>
+ as prefix to the exported C symbols.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <option>--crc-type=</option><replaceable>STRING</replaceable>
+ </term>
+ <listitem>
+ <para>when generating source code, use <replaceable>STRING</replaceable> as crc_t type.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <option>--include-file=</option><replaceable>FILE</replaceable>
+ </term>
+ <listitem>
+ <para>when generating source code, include also <replaceable>FILE</replaceable> as header file.
+ This option can be specified multiple times.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <option>-o</option><replaceable>FILE</replaceable>
+ </term>
+ <term>
+ <option>--output=</option><replaceable>FILE</replaceable>
+ </term>
+ <listitem>
+ <para>write the generated code to <replaceable>FILE</replaceable> instead of <filename>stdout</filename>.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>The CRC Parametric Model</title>
+ <para>
+ The parametric model follows Ross N. Williams' convention described in
+ <link xlink:href="http://www.ross.net/crc/crcpaper.html">A Painless Guide to CRC Error Detection Algorithms</link>,
+ often called the Rocksoft Model.
+ Since most people are familiar with this kind of parameters, pycrc follows this convention, described as follows:
+ <glosslist>
+ <glossentry>
+ <glossterm><replaceable>&width;</replaceable></glossterm>
+ <glossdef>
+ <para>
+ The number of significant bits in the CRC <replaceable>&poly;</replaceable>,
+ excluding the most significant 1.
+ This will also be the number of bits in the final CRC result.
+ In previous versions of pycrc only multiples of 8 could be used as
+ <replaceable>&width;</replaceable> for the <replaceable>&table-driven;</replaceable> algorithm.
+ As of version 0.7.5 any value is accepted for <replaceable>&width;</replaceable> for all algorithms.
+ </para>
+ </glossdef>
+ </glossentry>
+ <glossentry>
+ <glossterm><replaceable>&poly;</replaceable></glossterm>
+ <glossdef>
+ <para>
+ The unreflected polynomial of the CRC algorithm.
+ </para>
+ <para>
+ The <replaceable>&poly;</replaceable> may be specified in its standard form,
+ i.e. with bit <replaceable>&width;</replaceable>+1 set to 1, but the most significant
+ bit may also be omitted.
+ For example, both numbers 0x18005 and 0x8005 are accepted for a 16-bit
+ <replaceable>&poly;</replaceable>.
+ </para>
+ <para>
+ Most polynomials used in real world applications are odd (the least significant
+ bit is 1), but there are some good even ones.
+ pycrc allows the use of even polynomials with the <option>--force-poly</option>
+ option.
+ Some even polynomials may yield incorrect checksums depending on the used algorithm.
+ Use at your own risk and if at all possible use a well-known <replaceable>MODEL</replaceable> above.
+ </para>
+ </glossdef>
+ </glossentry>
+ <glossentry>
+ <glossterm><replaceable>&reflect_in;</replaceable></glossterm>
+ <glossdef>
+ <para>
+ Reflect the octets of the message before processing them.
+ </para>
+ <para>
+ A word is reflected or reversed by <quote>flipping</quote> its bits around the
+ mid-point of the word.
+ The most significant bit of the word is moved to the least significant position,
+ the second-most significant bit is moved to the second-least significant position
+ and so on.
+ The reflected value of 0xa2 (10100010b) is 0x45 (01000101b), for example.
+ </para>
+ <para>
+ Some CRC algorithms can be implemented more efficiently in a bit reversed version,
+ that's why many of the standard CRC models use reflected input octets.
+ </para>
+ </glossdef>
+ </glossentry>
+ <glossentry>
+ <glossterm><replaceable>&xor_in;</replaceable></glossterm>
+ <glossdef>
+ <para>
+ The initial value (usually all 0 or all 1) for algorithms which operate on the
+ non-augmented message, that is, any algorithm other than the
+ <replaceable>&bit-by-bit;</replaceable> one.
+ This value can be interpreted as a value which will be XOR-ed into the CRC register
+ after <replaceable>&width;</replaceable> iterations of the
+ <replaceable>&bit-by-bit;</replaceable> algorithm.
+ This implies that the simple <replaceable>&bit-by-bit;</replaceable> algorithm must
+ calculate the initial value using some sort of reverse CRC algorithm on the
+ <replaceable>&xor_in;</replaceable> value.
+ </para>
+ </glossdef>
+ </glossentry>
+ <glossentry>
+ <glossterm><replaceable>&reflect_out;</replaceable></glossterm>
+ <glossdef>
+ <para>
+ Reflect the final CRC result. This operation takes place before XOR-ing the final CRC
+ value with the <replaceable>&xor_out;</replaceable> parameter.
+ </para>
+ </glossdef>
+ </glossentry>
+ <glossentry>
+ <glossterm><replaceable>&xor_out;</replaceable></glossterm>
+ <glossdef>
+ <para>
+ A value (usually all bits 0 or all 1) which will be XOR-ed to the final CRC value.
+ </para>
+ </glossdef>
+ </glossentry>
+ <glossentry>
+ <glossterm><replaceable>✓</replaceable></glossterm>
+ <glossdef>
+ <para>
+ This value is not exactly a parameter of a model but it is sometimes given together
+ with the Rocksoft Model parameters.
+ It is the CRC value of the parametrised model over the string
+ <quote><replaceable>123456789</replaceable></quote> and
+ can be used as a sanity check for a particular CRC implementation.
+ </para>
+ </glossdef>
+ </glossentry>
+ </glosslist>
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Code generation</title>
+ <para>
+ In the default configuration, the generated code is strict ISO C99.
+ A minimal set of three functions are defined for each algorithm:
+ <function>crc_init()</function>, <function>crc_update()</function> and <function>crc_finalize()</function>.
+ Depending on the number of parameters given to pycrc, a different interface will be defined.
+ A fully parametrised model has a simpler API, while the generated code for a runtime-specified
+ implementation requires a pointer to a configuration structure as first parameter to all functions.
+ </para>
+ <para>
+ The generated source code uses the type <type>crc_t</type>, which is used throughout the code
+ to hold intermediate results and also the final CRC value.
+ It is defined in the generated header file and its type may be overridden with the
+ <option>--crc-type</option> option.
+ </para>
+
+ <refsect2><title>Fully parametrised models</title>
+ <para>
+ The prototypes of the CRC functions are normally generated by pycrc using the
+ <replaceable>--generate h</replaceable> option.
+ The CRC functions for a fully parametrised model will look like:
+ </para>
+ <funcsynopsis>
+ <funcsynopsisinfo>
+#include <stdlib.h>
+typedef uint16_t crc_t; /* pycrc will use an appropriate size here */
+ </funcsynopsisinfo>
+ <funcprototype>
+ <?dbhtml funcsynopsis-style='ansi'?>
+ <funcdef>crc_t <function>crc_init</function></funcdef>
+ <void/>
+ </funcprototype>
+
+ <funcprototype>
+ <?dbhtml funcsynopsis-style='ansi'?>
+ <funcdef>crc_t <function>crc_update</function></funcdef>
+ <paramdef>crc_t <parameter>crc</parameter></paramdef>
+ <paramdef>const unsigned char *<parameter>data</parameter></paramdef>
+ <paramdef>size_t <parameter>data_len</parameter></paramdef>
+ </funcprototype>
+
+ <funcprototype>
+ <?dbhtml funcsynopsis-style='ansi'?>
+ <funcdef>crc_t <function>crc_finalize</function></funcdef>
+ <paramdef>crc_t <parameter>crc</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+
+ <para>
+ The code snippet below shows how to use the generated functions.
+ <programlisting>
+#include "pycrc_generated_crc.h"
+#include <stdio.h>
+
+int main(void)
+{
+ static const unsigned char str1[] = "1234";
+ static const unsigned char str2[] = "56789";
+ crc_t crc;
+
+ crc = crc_init();
+ crc = crc_update(crc, str1, sizeof(str1) - 1);
+ crc = crc_update(crc, str2, sizeof(str2) - 1);
+ /* more calls to crc_update... */
+ crc = crc_finalize(crc);
+
+ printf("0x%lx\n", (long)crc);
+ return 0;
+}
+ </programlisting>
+ </para>
+ </refsect2>
+
+ <refsect2>
+ <title>Models with runtime-configurable parameters</title>
+ <para>
+ When the model is not fully defined then the missing parameters are stored in a structure of
+ type <type>crc_cfg_t</type>.
+ If a CRC function requires a value from the <type>crc_cfg_t</type> structure, then the first
+ function argument is always a pointer to that structure.
+ All fields of the configuration structure must be properly initialised before the first call
+ to any CRC function.
+ </para>
+ <para>
+ If the <replaceable>&width;</replaceable> was not specified when the code was generated, then
+ the <type>crc_cfg_t</type> structure will contain three more fields:
+ <parameter>msb_mask</parameter>, <parameter>crc_mask</parameter> and <parameter>crc_shift</parameter>.
+ They are defined for performance reasons and must be initialised to the value given next to the
+ field definition.
+ </para>
+ <para>
+ For example, a completely undefined CRC implementation will generate a <type>crc_cfg_t</type>
+ structure as below:
+ <programlisting>
+typedef struct {
+ unsigned int width;
+ crc_t poly;
+ bool reflect_in;
+ crc_t xor_in;
+ bool reflect_out;
+ crc_t xor_out;
+
+ // internal parameters
+ crc_t msb_mask; // initialise as (crc_t)1u << (cfg->width - 1)
+ crc_t crc_mask; // initialise as (cfg->msb_mask - 1) | cfg->msb_mask
+ unsigned int crc_shift; // initialise as cfg->width < 8 ? 8 - cfg->width : 0
+} crc_cfg_t;
+ </programlisting>
+ </para>
+ <para>
+ <parameter>msb_mask</parameter> is a bitmask with the most significant bit of a
+ <replaceable>&width;</replaceable> bits wide data type set to 1.
+
+ <parameter>crc_mask</parameter> is a bitmask with all bits of a
+ <replaceable>&width;</replaceable> bits wide data type set to 1.
+
+ <parameter>crc_shift</parameter> is a shift counter that is used when
+ <replaceable>&width;</replaceable> is less than 8.
+ It is the number of bits to shift the CRC register to align its top bit to a byte boundary.
+ </para>
+
+ <para>
+ The file <filename>test/main.c</filename> in the source package of pycrc
+ contains a fully featured example of how to use the generated source code.
+ A shorter, more compact <code>main()</code> function can be generated with the
+ <replaceable>--generate c-main</replaceable> option.
+ This second variant is the better option as it will always output valid code when
+ some of the CRC parameters are known and some are unknown during code generation.
+ </para>
+ </refsect2>
+ </refsect1>
+
+ <refsect1><title>Examples</title>
+ <para>
+ <glosslist>
+ <glossentry>
+ <glossterm>Calculate the CRC-32 checksum of the string <quote>123456789</quote>:</glossterm>
+ <glossdef>
+ <para>
+ <userinput>python pycrc.py --model crc-32 --check-string 123456789</userinput>
+ </para>
+ </glossdef>
+ </glossentry>
+ <glossentry>
+ <glossterm>Generate the source code of the table-driven algorithm for an embedded application.</glossterm>
+ <glossdef>
+ <para>
+ The table index width of 4 bits ensures a moderate memory usage.
+ To be precise, the size of the resulting table will be <code>16 * sizeof(crc_t)</code>.
+ </para>
+ <para>
+ <userinput>python pycrc.py --model crc-16 --algorithm table-driven --table-idx-width 4 --generate h -o crc.h</userinput>
+ </para>
+ <para>
+ <userinput>python pycrc.py --model crc-16 --algorithm table-driven --table-idx-width 4 --generate c -o crc.c</userinput>
+ </para>
+ <para>
+ A variant of the <replaceable>c</replaceable> target is <replaceable>c-main</replaceable>:
+ this target will generate a simple <replaceable>main()</replaceable> function in addition to
+ the CRC functions:
+ </para>
+ <para>
+ <userinput>python pycrc.py --model crc-16 --algorithm table-driven --table-idx-width 4 --generate c-main -o crc.c</userinput>
+ </para>
+ </glossdef>
+ </glossentry>
+ <glossentry>
+ <glossterm>Generate the CRC table only:</glossterm>
+ <glossdef>
+ <para>
+ <userinput>python pycrc.py --model kermit --generate table -o crc-table.txt</userinput>
+ </para>
+ </glossdef>
+ </glossentry>
+ </glosslist>
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+ <para>
+ The homepage of pycrc is <link xlink:href="&project_homepage;">&project_homepage;</link>.
+ </para>
+ <para>
+ A list of common CRC models is at <link xlink:href="&project_models;">&project_models;</link>.
+ For a long list of known CRC models, see Greg Cook's
+ <link xlink:href="http://reveng.sourceforge.net/crc-catalogue/">Catalogue of Parameterised CRC Algorithms</link>.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Copyright</title>
+ <para>
+ This work is licensed under a
+ <link xlink:href="https://creativecommons.org/licenses/by-sa/4.0/">Creative Commons Attribution-ShareAlike 4.0 International</link>.
+ </para>
+ </refsect1>
+</refentry>
diff --git a/doc/style-html.xsl b/doc/style-html.xsl
new file mode 100644
index 0000000..3f9cb89
--- /dev/null
+++ b/doc/style-html.xsl
@@ -0,0 +1,14 @@
+<?xml version='1.0'?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+<xsl:import href="file:///usr/share/xml/docbook/stylesheet/docbook-xsl-ns/xhtml5/docbook.xsl"/>
+
+<xsl:output encoding="UTF-8" indent="no" method="html"/>
+<xsl:param name="default.table.frame" select="none"/>
+<xsl:param name="html.cleanup" select="1"/>
+<xsl:param name="make.valid.html" select="1"/>
+
+<xsl:template name="user.head.content">
+ <meta name="viewport" content="width=device-width, initial-scale=1"/>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/doc/style-man.xsl b/doc/style-man.xsl
new file mode 100644
index 0000000..639b454
--- /dev/null
+++ b/doc/style-man.xsl
@@ -0,0 +1,6 @@
+<?xml version='1.0'?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+<xsl:import href="file:///usr/share/xml/docbook/stylesheet/docbook-xsl-ns/manpages/docbook.xsl"/>
+
+
+</xsl:stylesheet>
diff --git a/pycrc.py b/pycrc.py
new file mode 100755
index 0000000..2dd1612
--- /dev/null
+++ b/pycrc.py
@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+
+# pycrc -- parameterisable CRC calculation utility and C source code generator
+#
+# Copyright (c) 2006-2017 Thomas Pircher <tehpeh-web@tty1.net>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+
+from pycrc.main import main
+import sys
+
+
+if __name__ == "__main__":
+ sys.exit(main())
diff --git a/pycrc/__init__.py b/pycrc/__init__.py
new file mode 100644
index 0000000..e0749e4
--- /dev/null
+++ b/pycrc/__init__.py
@@ -0,0 +1,3 @@
+progname = "pycrc"
+version = "0.9.1"
+url = 'https://pycrc.org'
diff --git a/pycrc/__main__.py b/pycrc/__main__.py
new file mode 100644
index 0000000..cefc3bb
--- /dev/null
+++ b/pycrc/__main__.py
@@ -0,0 +1,30 @@
+#!/usr/bin/env python
+
+# pycrc -- parameterisable CRC calculation utility and C source code generator
+#
+# Copyright (c) 2006-2017 Thomas Pircher <tehpeh-web@tty1.net>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+from pycrc.main import main
+import sys
+
+
+if __name__ == "__main__":
+ sys.exit(main())
diff --git a/pycrc/algorithms.py b/pycrc/algorithms.py
new file mode 100644
index 0000000..3ebcebd
--- /dev/null
+++ b/pycrc/algorithms.py
@@ -0,0 +1,235 @@
+# pycrc -- parameterisable CRC calculation utility and C source code generator
+#
+# Copyright (c) 2006-2017 Thomas Pircher <tehpeh-web@tty1.net>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+
+"""
+CRC algorithms implemented in Python.
+If you want to study the Python implementation of the CRC routines, then this
+is a good place to start from.
+
+The algorithms Bit by Bit, Bit by Bit Fast and Table-Driven are implemented.
+
+This module can also be used as a library from within Python.
+
+Examples
+========
+
+This is an example use of the different algorithms:
+
+ from pycrc.algorithms import Crc
+
+ crc = Crc(width = 16, poly = 0x8005,
+ reflect_in = True, xor_in = 0x0000,
+ reflect_out = True, xor_out = 0x0000)
+ print("{0:#x}".format(crc.bit_by_bit("123456789")))
+ print("{0:#x}".format(crc.bit_by_bit_fast("123456789")))
+ print("{0:#x}".format(crc.table_driven("123456789")))
+"""
+
+class Crc(object):
+ """
+ A base class for CRC routines.
+ """
+ # pylint: disable=too-many-instance-attributes
+
+ def __init__(self, width, poly, reflect_in, xor_in, reflect_out, xor_out, table_idx_width=None, slice_by=1):
+ """The Crc constructor.
+
+ The parameters are as follows:
+ width
+ poly
+ reflect_in
+ xor_in
+ reflect_out
+ xor_out
+ """
+ # pylint: disable=too-many-arguments
+
+ self.width = width
+ self.poly = poly
+ self.reflect_in = reflect_in
+ self.xor_in = xor_in
+ self.reflect_out = reflect_out
+ self.xor_out = xor_out
+ self.tbl_idx_width = table_idx_width
+ self.slice_by = slice_by
+
+ self.msb_mask = 0x1 << (self.width - 1)
+ self.mask = ((self.msb_mask - 1) << 1) | 1
+ if self.tbl_idx_width != None:
+ self.tbl_width = 1 << self.tbl_idx_width
+ else:
+ self.tbl_idx_width = 8
+ self.tbl_width = 1 << self.tbl_idx_width
+
+ self.direct_init = self.xor_in
+ self.nondirect_init = self.__get_nondirect_init(self.xor_in)
+ if self.width < 8:
+ self.crc_shift = 8 - self.width
+ else:
+ self.crc_shift = 0
+
+
+ def __get_nondirect_init(self, init):
+ """
+ return the non-direct init if the direct algorithm has been selected.
+ """
+ crc = init
+ for dummy_i in range(self.width):
+ bit = crc & 0x01
+ if bit:
+ crc ^= self.poly
+ crc >>= 1
+ if bit:
+ crc |= self.msb_mask
+ return crc & self.mask
+
+
+ def reflect(self, data, width):
+ """
+ reflect a data word, i.e. reverts the bit order.
+ """
+ # pylint: disable=no-self-use
+
+ res = data & 0x01
+ for dummy_i in range(width - 1):
+ data >>= 1
+ res = (res << 1) | (data & 0x01)
+ return res
+
+
+ def bit_by_bit(self, in_data):
+ """
+ Classic simple and slow CRC implementation. This function iterates bit
+ by bit over the augmented input message and returns the calculated CRC
+ value at the end.
+ """
+ # If the input data is a string, convert to bytes.
+ if isinstance(in_data, str):
+ in_data = bytearray(in_data, 'utf-8')
+
+ reg = self.nondirect_init
+ for octet in in_data:
+ if self.reflect_in:
+ octet = self.reflect(octet, 8)
+ for i in range(8):
+ topbit = reg & self.msb_mask
+ reg = ((reg << 1) & self.mask) | ((octet >> (7 - i)) & 0x01)
+ if topbit:
+ reg ^= self.poly
+
+ for i in range(self.width):
+ topbit = reg & self.msb_mask
+ reg = ((reg << 1) & self.mask)
+ if topbit:
+ reg ^= self.poly
+
+ if self.reflect_out:
+ reg = self.reflect(reg, self.width)
+ return (reg ^ self.xor_out) & self.mask
+
+
+ def bit_by_bit_fast(self, in_data):
+ """
+ This is a slightly modified version of the bit-by-bit algorithm: it
+ does not need to loop over the augmented bits, i.e. the Width 0-bits
+ wich are appended to the input message in the bit-by-bit algorithm.
+ """
+ # If the input data is a string, convert to bytes.
+ if isinstance(in_data, str):
+ in_data = bytearray(in_data, 'utf-8')
+
+ reg = self.direct_init
+ for octet in in_data:
+ if self.reflect_in:
+ octet = self.reflect(octet, 8)
+ for i in range(8):
+ topbit = reg & self.msb_mask
+ if octet & (0x80 >> i):
+ topbit ^= self.msb_mask
+ reg <<= 1
+ if topbit:
+ reg ^= self.poly
+ reg &= self.mask
+ if self.reflect_out:
+ reg = self.reflect(reg, self.width)
+ return reg ^ self.xor_out
+
+
+ def gen_table(self):
+ """
+ This function generates the CRC table used for the table_driven CRC
+ algorithm. The Python version cannot handle tables of an index width
+ other than 8. See the generated C code for tables with different sizes
+ instead.
+ """
+ table_length = 1 << self.tbl_idx_width
+ tbl = [[0 for i in range(table_length)] for j in range(self.slice_by)]
+ for i in range(table_length):
+ reg = i
+ if self.reflect_in:
+ reg = self.reflect(reg, self.tbl_idx_width)
+ reg = reg << (self.width - self.tbl_idx_width + self.crc_shift)
+ for dummy_j in range(self.tbl_idx_width):
+ if reg & (self.msb_mask << self.crc_shift) != 0:
+ reg = (reg << 1) ^ (self.poly << self.crc_shift)
+ else:
+ reg = (reg << 1)
+ if self.reflect_in:
+ reg = self.reflect(reg >> self.crc_shift, self.width) << self.crc_shift
+ tbl[0][i] = (reg >> self.crc_shift) & self.mask
+
+ for j in range(1, self.slice_by):
+ for i in range(table_length):
+ tbl[j][i] = (tbl[j - 1][i] >> 8) ^ tbl[0][tbl[j - 1][i] & 0xff]
+ return tbl
+
+
+ def table_driven(self, in_data):
+ """
+ The Standard table_driven CRC algorithm.
+ """
+ # pylint: disable = line-too-long
+
+ # If the input data is a string, convert to bytes.
+ if isinstance(in_data, str):
+ in_data = bytearray(in_data, 'utf-8')
+
+ tbl = self.gen_table()
+
+ if not self.reflect_in:
+ reg = self.direct_init << self.crc_shift
+ for octet in in_data:
+ tblidx = ((reg >> (self.width - self.tbl_idx_width + self.crc_shift)) ^ octet) & 0xff
+ reg = ((reg << (self.tbl_idx_width - self.crc_shift)) ^ (tbl[0][tblidx] << self.crc_shift)) & (self.mask << self.crc_shift)
+ reg = reg >> self.crc_shift
+ else:
+ reg = self.reflect(self.direct_init, self.width)
+ for octet in in_data:
+ tblidx = (reg ^ octet) & 0xff
+ reg = ((reg >> self.tbl_idx_width) ^ tbl[0][tblidx]) & self.mask
+ reg = self.reflect(reg, self.width) & self.mask
+
+ if self.reflect_out:
+ reg = self.reflect(reg, self.width)
+ return reg ^ self.xor_out
+
diff --git a/pycrc/codegen.py b/pycrc/codegen.py
new file mode 100644
index 0000000..4079cc0
--- /dev/null
+++ b/pycrc/codegen.py
@@ -0,0 +1,1559 @@
+# pycrc -- parameterisable CRC calculation utility and C source code generator
+#
+# Copyright (c) 2017 Thomas Pircher <tehpeh-web@tty1.net>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+
+"""
+use as follows:
+
+ import pycrc.codegen as cg
+ import pycrc.opt as opt
+ opt = opt.Options()
+ print(cg.CodeGen(opt, '', [
+ 'if (a == b) {',
+ cg.CodeGen(opt, 4*' ', ['print("a equals b\\n");']),
+ '}',
+ ]))
+"""
+
+import pycrc.symtable
+import pycrc.expr as expr
+
+
+class CodeGen(object):
+ """
+ The symbol table class.
+ """
+ def __init__(self, opt, indent, content = []):
+ """
+ The class constructor.
+ """
+ self.opt = opt
+ self.sym = pycrc.symtable.SymbolTable(opt)
+ self.indent = indent
+ self.content = content
+
+ def gen(self, indent = ''):
+ """
+ Return an array of strings.
+ """
+ out = []
+ if self.indent is None:
+ indent = ''
+ else:
+ indent += self.indent
+ for item in self.content:
+ if isinstance(item, str):
+ out.append(indent + item)
+ else:
+ out += item.gen(indent)
+ return out
+
+ def __str__(self):
+ """
+ Stringify the object.
+ """
+ return '\n'.join([l.rstrip() for l in self.gen()])
+
+
+class Conditional(CodeGen):
+ """
+ A conditional block of code.
+ """
+ def __init__(self, opt, indent, condition, content):
+ """
+ The class constructor.
+ """
+ super(Conditional, self).__init__(opt, indent)
+ if condition:
+ self.content = content
+
+
+class Conditional2(CodeGen):
+ """
+ A conditional block of code with an else block.
+ """
+ def __init__(self, opt, indent, condition, content_true, content_false):
+ """
+ The class constructor.
+ """
+ super(Conditional2, self).__init__(opt, indent)
+ if condition:
+ self.content = content_true
+ else:
+ self.content = content_false
+
+
+class Comment(CodeGen):
+ """
+ A comment wrapper.
+ """
+ def __init__(self, opt, indent, content):
+ """
+ The class constructor.
+ """
+ super(Comment, self).__init__(opt, indent)
+ self.content = [
+ '/**',
+ CodeGen(opt, indent + ' * ', content),
+ ' */'
+ ]
+
+
+class ParamBlock(CodeGen):
+ """
+ Print the parameters of the model.
+ """
+ def __init__(self, opt, indent, algorithm = False):
+ """
+ The class constructor.
+ """
+ super(ParamBlock, self).__init__(opt, indent)
+ self.content = [
+ '- {0:13s} = {1}'.format('Width', self.sym['crc_width']),
+ '- {0:13s} = {1}'.format('Poly', self.sym['crc_poly']),
+ '- {0:13s} = {1}'.format('XorIn', self.sym['crc_xor_in']),
+ '- {0:13s} = {1}'.format('ReflectIn', self.sym['crc_reflect_in']),
+ '- {0:13s} = {1}'.format('XorOut', self.sym['crc_xor_out']),
+ '- {0:13s} = {1}'.format('ReflectOut', self.sym['crc_reflect_out']),
+ Conditional(opt, '', algorithm,
+ ['- {0:13s} = {1}'.format('Algorithm', self.sym['crc_algorithm'])]),
+ Conditional(opt, '', opt.slice_by > 1,
+ ['- {0:13s} = {1}'.format('SliceBy', opt.slice_by)]),
+ ]
+
+
+
+class File(CodeGen):
+ """
+ Generate the file output.
+ """
+ def __init__(self, opt, indent):
+ """
+ The class constructor.
+ """
+ super(File, self).__init__(opt, indent)
+ self.content = [
+ Comment(opt, '', [
+ '\\file',
+ 'Functions and types for CRC checks.',
+ '',
+ 'Generated on {datetime}'.format(**self.sym),
+ 'by {program_version}, {program_url}'.format(**self.sym),
+ 'using the configuration:',
+ ParamBlock(opt, ' ', algorithm = True),
+ Conditional(opt, '', opt.action == opt.action_generate_h, [
+ '',
+ 'This file defines the functions {crc_init_function}(), ' \
+ '{crc_update_function}() and {crc_finalize_function}().'.format(**self.sym),
+ '',
+ 'The {crc_init_function}() function returns the inital \c crc value and must be called'.format(**self.sym),
+ 'before the first call to {crc_update_function}().'.format(**self.sym),
+ 'Similarly, the {crc_finalize_function}() function must be called after the last call'.format(**self.sym),
+ 'to {crc_update_function}(), before the \c crc is being used.'.format(**self.sym),
+ 'is being used.',
+ '',
+ 'The {crc_update_function}() function can be called any number of times (including zero'.format(**self.sym),
+ 'times) in between the {crc_init_function}() and {crc_finalize_function}() calls.'.format(**self.sym),
+ '',
+ 'This pseudo-code shows an example usage of the API:',
+ '\code{.c}',
+ Conditional(self.opt, '', self.opt.undefined_crc_parameters, [
+ '{cfg_t} cfg = '.format(**self.sym) + '{',
+ Conditional(self.opt, 4*' ', self.opt.width is None, [
+ '0, // width',
+ ]),
+ Conditional(self.opt, 4*' ', self.opt.poly is None, [
+ '0, // poly',
+ ]),
+ Conditional(self.opt, 4*' ', self.opt.reflect_in is None, [
+ '0, // reflect_in',
+ ]),
+ Conditional(self.opt, 4*' ', self.opt.xor_in is None, [
+ '0, // xor_in',
+ ]),
+ Conditional(self.opt, 4*' ', self.opt.reflect_out is None, [
+ '0, // reflect_out',
+ ]),
+ Conditional(self.opt, 4*' ', self.opt.xor_out is None, [
+ '0, // xor_out',
+ ]),
+ Conditional(self.opt, 4*' ', self.opt.width is None, [
+ '',
+ '0, // crc_mask',
+ '0, // msb_mask',
+ '0, // crc_shift',
+ ]),
+ '};',
+ ]),
+ '{crc_t} crc;'.format(**self.sym),
+ 'unsigned char data[MAX_DATA_LEN];',
+ 'size_t data_len;',
+ '',
+ Conditional(self.opt, '', _use_crc_table_gen(self.opt), [
+ '{crc_table_gen_function}(&cfg);'.format(**self.sym),
+ ]),
+ 'crc = {0}({1});'.format(self.sym['crc_init_function'], '' if _use_constant_crc_init(self.sym) else '&cfg'),
+ 'while ((data_len = read_data(data, MAX_DATA_LEN)) > 0) {',
+ CodeGen(self.opt, 4*' ', [
+ 'crc = {0}({1}crc, data, data_len);'.format(self.sym['crc_update_function'], '' if _use_cfg_in_crc_update(self.opt) else '&cfg, '),
+ ]),
+ '}',
+ 'crc = {0}({1}crc);'.format(self.sym['crc_finalize_function'], '' if _use_cfg_in_finalize(self.opt) else '&cfg, '),
+ '\endcode',
+ ]),
+ ]),
+ ]
+ if opt.action == opt.action_generate_h:
+ self.content += self._header_file()
+ elif opt.action == opt.action_generate_c:
+ self.content += self._c_file()
+ elif opt.action == opt.action_generate_c_main:
+ self.content += self._c_file() + self._main_file()
+
+ def _header_file(self):
+ """
+ Add header content.
+ """
+ out = [
+ '#ifndef {header_protection}'.format(**self.sym),
+ '#define {header_protection}'.format(**self.sym),
+ '',
+ CodeGen(self.opt, '', _includes(self.opt)),
+ '#include <stdlib.h>',
+ Conditional(self.opt, '', self.opt.c_std != 'C89',
+ ['#include <stdint.h>']),
+ Conditional(self.opt, '', _use_cfg(self.opt) and self.opt.c_std != 'C89',
+ ['#include <stdbool.h>']),
+ '',
+ '#ifdef __cplusplus',
+ 'extern "C" {',
+ '#endif',
+ '', '',
+ Comment(self.opt, '', [
+ 'The definition of the used algorithm.',
+ '',
+ 'This is not used anywhere in the generated code, but it may be used by the',
+ 'application code to call algorithm-specific code, if desired.',
+ ]),
+ '#define {0} 1'.format(_crc_algo_define(self.opt, self.sym)),
+ '', '',
+ Comment(self.opt, self.indent, [
+ 'The type of the CRC values.',
+ '',
+ 'This type must be big enough to contain at least {cfg_width} bits.'.format(**self.sym),
+ ]),
+ 'typedef {underlying_crc_t} {crc_t};'.format(**self.sym),
+ Conditional(self.opt, '', _use_cfg(self.opt), [
+ '', '',
+ Comment(self.opt, self.indent, ['The configuration type of the CRC algorithm.']),
+ 'typedef struct {',
+ Conditional(self.opt, 4*' ', self.opt.width is None,
+ ['{0:24s} {1}'.format('unsigned int width;',
+ '/*!< The width of the polynomial */')]),
+ Conditional(self.opt, 4*' ', self.opt.poly is None,
+ ['{0:24s} {1}'.format(self.sym['crc_t'] + ' poly;',
+ '/*!< The CRC polynomial */')]),
+ Conditional(self.opt, 4*' ', self.opt.reflect_in is None,
+ ['{0:24s} {1}'.format(self.sym['c_bool'] + ' reflect_in;',
+ '/*!< Whether the input shall be reflected or not */')]),
+ Conditional(self.opt, 4*' ', self.opt.xor_in is None,
+ ['{0:24s} {1}'.format(self.sym['crc_t'] + ' xor_in;',
+ '/*!< The initial value of the register */')]),
+ Conditional(self.opt, 4*' ', self.opt.reflect_out is None,
+ ['{0:24s} {1}'.format(self.sym['c_bool'] + ' reflect_out;',
+ '/*!< Whether the output shall be reflected or not */')]),
+ Conditional(self.opt, 4*' ', self.opt.xor_out is None,
+ ['{0:24s} {1}'.format(self.sym['crc_t'] + ' xor_out;',
+ '/*!< The value which shall be XOR-ed to the final CRC value */')]),
+ Conditional(self.opt, 4*' ', self.opt.width is None, [
+ '',
+ '/* internal parameters */',
+ '{0:24s} {1}'.format(self.sym['crc_t'] + ' msb_mask;', '/*!< a bitmask with the Most Significant Bit set to 1'),
+ 33*' ' + 'initialise as (crc_t)1u << (width - 1) */',
+ '{0:24s} {1}'.format(self.sym['crc_t'] + ' crc_mask;', '/*!< a bitmask with all width bits set to 1'),
+ 33*' ' + 'initialise as (cfg->msb_mask - 1) | cfg->msb_mask */',
+ '{0:24s} {1}'.format('unsigned int crc_shift;', '/*!< a shift count that is used when width < 8'),
+ 33*' ' + 'initialise as cfg->width < 8 ? 8 - cfg->width : 0 */',
+ ]),
+ '}} {cfg_t};'.format(**self.sym),
+ ]),
+ Conditional(self.opt, '', _use_reflect_func(self.opt) and not _use_static_reflect_func(self.opt), [
+ '', '',
+ Comment(self.opt, '', [
+ 'Reflect all bits of a \\a data word of \\a data_len bytes.',
+ '',
+ '\\param[in] data The data word to be reflected.',
+ '\\param[in] data_len The width of \\a data expressed in number of bits.',
+ '\\return The reflected data.'
+ ]),
+ '{crc_t} {crc_reflect_function}({crc_t} data, size_t data_len);'.format(**self.sym),
+ ]),
+ Conditional(self.opt, '', _use_crc_table_gen(self.opt), [
+ '', '',
+ Comment(self.opt, '', [
+ 'Populate the private static crc table.',
+ '',
+ '\\param[in] cfg A pointer to an initialised {cfg_t} structure.'.format(**self.sym),
+ ]),
+ 'void {crc_table_gen_function}(const {cfg_t} *cfg);'.format(**self.sym),
+ ]),
+ '', '',
+ Comment(self.opt, '', [
+ 'Calculate the initial crc value.',
+ '',
+ Conditional(self.opt, '', _use_cfg(self.opt), [
+ '\\param[in] cfg A pointer to an initialised {cfg_t} structure.'.format(**self.sym),
+ ]),
+ '\\return The initial crc value.',
+ ]),
+ Conditional2(self.opt, '', _use_constant_crc_init(self.sym), [
+ Conditional2(self.opt, '', self.opt.c_std == 'C89', [
+ '#define {crc_init_function}() ({crc_init_value})'.format(**self.sym),
+ ], [
+ 'static inline {0}'.format(_crc_init_function_def(self.opt, self.sym)),
+ '{',
+ ' return {crc_init_value};'.format(**self.sym),
+ '}',
+ ]),
+ ], [
+ '{0};'.format(_crc_init_function_def(self.opt, self.sym)),
+ ]),
+ '', '',
+ Comment(self.opt, '', [
+ 'Update the crc value with new data.',
+ '',
+ '\\param[in] crc The current crc value.',
+ Conditional(self.opt, '', not _use_cfg_in_crc_update(self.opt), [
+ '\\param[in] cfg A pointer to an initialised {cfg_t} structure.'.format(**self.sym),
+ ]),
+ '\\param[in] data Pointer to a buffer of \\a data_len bytes.',
+ '\\param[in] data_len Number of bytes in the \\a data buffer.',
+ '\\return The updated crc value.',
+ ]),
+ '{0};'.format(_crc_update_function_def(self.opt, self.sym)),
+ '', '',
+ Comment(self.opt, '', [
+ 'Calculate the final crc value.',
+ '',
+ Conditional(self.opt, '', not _use_cfg_in_finalize(self.opt), [
+ '\\param[in] cfg A pointer to an initialised {cfg_t} structure.'.format(**self.sym),
+ ]),
+ '\\param[in] crc The current crc value.',
+ '\\return The final crc value.',
+ ]),
+ Conditional2(self.opt, '', _use_inline_crc_finalize(self.opt), [
+ Conditional2(self.opt, '', self.opt.c_std == 'C89', [
+ '#define {0}(crc) ({1})'.format(self.sym['crc_finalize_function'], _crc_final_value(self.opt, self.sym)),
+ ], [
+ 'static inline {0}'.format(_crc_finalize_function_def(self.opt, self.sym)),
+ '{',
+ ' return {0};'.format(_crc_final_value(self.opt, self.sym)),
+ '}',
+ ]),
+ ], [
+ '{0};'.format(_crc_finalize_function_def(self.opt, self.sym)),
+ ]),
+ '', '',
+ '#ifdef __cplusplus',
+ '} /* closing brace for extern "C" */',
+ '#endif',
+ '',
+ '#endif /* {header_protection} */'.format(**self.sym),
+ '',
+ ]
+ return out
+
+ def _c_file(self):
+ """
+ Add C file content.
+ """
+ out = [
+ CodeGen(self.opt, '', _includes(self.opt)),
+ '#include "{header_filename}" /* include the header file generated with pycrc */'.format(**self.sym),
+ '#include <stdlib.h>',
+ Conditional(self.opt, '', self.opt.c_std != 'C89', [
+ '#include <stdint.h>',
+ Conditional(self.opt, '', self.opt.undefined_crc_parameters or \
+ self.opt.algorithm == self.opt.algo_bit_by_bit or \
+ self.opt.algorithm == self.opt.algo_bit_by_bit_fast, [
+ '#include <stdbool.h>',
+ ]),
+ ]),
+ Conditional(self.opt, '', self.opt.slice_by > 1, [
+ '#include <endian.h>',
+ ]),
+ Conditional(self.opt, '', _use_reflect_func(self.opt) and _use_static_reflect_func(self.opt), [
+ '',
+ 'static {crc_t} {crc_reflect_function}({crc_t} data, size_t data_len);'.format(**self.sym),
+ ]),
+ '',
+ CodeGen(self.opt, '', _crc_table(self.opt, self.sym)),
+ CodeGen(self.opt, '', _crc_reflect_function_gen(self.opt, self.sym)),
+ CodeGen(self.opt, '', _crc_init_function_gen(self.opt, self.sym)),
+ CodeGen(self.opt, '', _crc_table_gen(self.opt, self.sym)),
+ CodeGen(self.opt, '', _crc_update_function_gen(self.opt, self.sym)),
+ CodeGen(self.opt, '', _crc_finalize_function_gen(self.opt, self.sym)),
+ '',
+ ]
+ return out
+
+ def _main_file(self):
+ """
+ Add main file content.
+ """
+ out = [
+ '',
+ '',
+ CodeGen(self.opt, '', _includes(self.opt)),
+ '#include <stdio.h>',
+ '#include <getopt.h>',
+ Conditional(self.opt, '', self.opt.undefined_crc_parameters, [
+ '#include <stdlib.h>',
+ '#include <stdio.h>',
+ '#include <ctype.h>',
+ ]),
+ Conditional(self.opt, '', self.opt.c_std != 'C89', [
+ '#include <stdbool.h>',
+ ]),
+ '#include <string.h>',
+ '',
+ 'static char str[256] = "123456789";',
+ 'static {c_bool} verbose = {c_false};'.format(**self.sym),
+ self._getopt_template(),
+ '',
+ '',
+ Conditional2(self.opt, '', self.opt.undefined_crc_parameters, [
+ 'static void print_params(const {cfg_t} *cfg)'.format(**self.sym),
+ ], [
+ 'static void print_params(void)',
+ ]),
+ '{',
+ CodeGen(self.opt, 4*' ', [
+ 'char format[20];',
+ '',
+ Conditional2(self.opt, '', self.opt.c_std == 'C89', [
+ 'sprintf(format, "%%-16s = 0x%%0%dlx\\n", (unsigned int)({cfg_width} + 3) / 4);'.format(**self.sym),
+ 'printf("%-16s = %d\\n", "width", (unsigned int){cfg_width});'.format(**self.sym),
+ 'printf(format, "poly", (unsigned long int){cfg_poly});'.format(**self.sym),
+ 'printf("%-16s = %s\\n", "reflect_in", {0});'.format(self.sym['cfg_reflect_in'] + ' ? "true": "false"' if self.opt.reflect_in is None else ('"true"' if self.opt.reflect_in else '"false"')),
+ 'printf(format, "xor_in", (unsigned long int){cfg_xor_in});'.format(**self.sym),
+ 'printf("%-16s = %s\\n", "reflect_out", {0});'.format(self.sym['cfg_reflect_out'] + ' ? "true": "false"' if self.opt.reflect_out is None else ('"true"' if self.opt.reflect_out else '"false"')),
+ 'printf(format, "xor_out", (unsigned long int){cfg_xor_out});'.format(**self.sym),
+ 'printf(format, "crc_mask", (unsigned long int){cfg_mask});'.format(**self.sym),
+ 'printf(format, "msb_mask", (unsigned long int){cfg_msb_mask});'.format(**self.sym),
+ ], [
+ 'snprintf(format, sizeof(format), "%%-16s = 0x%%0%dllx\\n", (unsigned int)({cfg_width} + 3) / 4);'.format(**self.sym),
+ 'printf("%-16s = %d\\n", "width", (unsigned int){cfg_width});'.format(**self.sym),
+ 'printf(format, "poly", (unsigned long long int){cfg_poly});'.format(**self.sym),
+ 'printf("%-16s = %s\\n", "reflect_in", {0});'.format(self.sym['cfg_reflect_in'] + ' ? "true": "false"' if self.opt.reflect_in is None else ('"true"' if self.opt.reflect_in else '"false"')),
+ 'printf(format, "xor_in", (unsigned long long int){cfg_xor_in});'.format(**self.sym),
+ 'printf("%-16s = %s\\n", "reflect_out", {0});'.format(self.sym['cfg_reflect_out'] + ' ? "true": "false"' if self.opt.reflect_out is None else ('"true"' if self.opt.reflect_out else '"false"')),
+ 'printf(format, "xor_out", (unsigned long long int){cfg_xor_out});'.format(**self.sym),
+ 'printf(format, "crc_mask", (unsigned long long int){cfg_mask});'.format(**self.sym),
+ 'printf(format, "msb_mask", (unsigned long long int){cfg_msb_mask});'.format(**self.sym),
+ ]),
+ ]),
+ '}',
+ '',
+ '',
+ Comment(self.opt, '', [
+ 'C main function.',
+ '\\param[in] argc the number of arguments in \\a argv.',
+ '\\param[in] argv a NULL-terminated array of pointers to the argument strings.',
+ '\\retval 0 on success.',
+ '\\retval >0 on error.',
+ ]),
+ 'int main(int argc, char *argv[])',
+ '{',
+ CodeGen(self.opt, 4*' ', [
+ Conditional(self.opt, '', self.opt.undefined_crc_parameters, [
+ '{cfg_t} cfg = '.format(**self.sym) + '{',
+ Conditional(self.opt, 4*' ', self.opt.width is None, [
+ '0, /* width */',
+ ]),
+ Conditional(self.opt, 4*' ', self.opt.poly is None, [
+ '0, /* poly */',
+ ]),
+ Conditional(self.opt, 4*' ', self.opt.reflect_in is None, [
+ '0, /* reflect_in */',
+ ]),
+ Conditional(self.opt, 4*' ', self.opt.xor_in is None, [
+ '0, /* xor_in */',
+ ]),
+ Conditional(self.opt, 4*' ', self.opt.reflect_out is None, [
+ '0, /* reflect_out */',
+ ]),
+ Conditional(self.opt, 4*' ', self.opt.xor_out is None, [
+ '0, /* xor_out */',
+ ]),
+ Conditional(self.opt, 4*' ', self.opt.width is None, [
+ '',
+ '0, /* crc_mask */',
+ '0, /* msb_mask */',
+ '0, /* crc_shift */',
+ ]),
+ '};',
+ ]),
+ '{crc_t} crc;'.format(**self.sym),
+ '',
+ Conditional2(self.opt, '', self.opt.undefined_crc_parameters, [
+ 'get_config(argc, argv, &cfg);',
+ ], [
+ 'get_config(argc, argv);',
+ ]),
+ Conditional(self.opt, '', _use_crc_table_gen(self.opt), [
+ '{crc_table_gen_function}(&cfg);'.format(**self.sym),
+ ]),
+ 'crc = {0}({1});'.format(self.sym['crc_init_function'], '' if _use_constant_crc_init(self.sym) else '&cfg'),
+ 'crc = {0}({1}crc, (void *)str, strlen(str));'.format(self.sym['crc_update_function'], '' if _use_cfg_in_crc_update(self.opt) else '&cfg, '),
+ 'crc = {0}({1}crc);'.format(self.sym['crc_finalize_function'], '' if _use_cfg_in_finalize(self.opt) else '&cfg, '),
+ '',
+ 'if (verbose) {',
+ CodeGen(self.opt, 4*' ', [
+ 'print_params({0});'.format('&cfg' if self.opt.undefined_crc_parameters else ''),
+ ]),
+ '}',
+ Conditional2(self.opt, '', self.opt.c_std == 'C89', [
+ 'printf("0x%lx\\n", (unsigned long int)crc);',
+ ], [
+ 'printf("0x%llx\\n", (unsigned long long int)crc);',
+ ]),
+ 'return 0;',
+ ]),
+ '}',
+ ]
+ return out
+
+ def _getopt_template(self):
+ """
+ Add getopt functions.
+ """
+ out = [
+ Conditional(self.opt, '', self.opt.reflect_in is None or self.opt.reflect_out is None, [
+ '',
+ '',
+ 'static {c_bool} atob(const char *str)'.format(**self.sym),
+ '{',
+ CodeGen(self.opt, 4*' ', [
+ 'if (!str) {',
+ CodeGen(self.opt, 4*' ', [
+ 'return 0;',
+ ]),
+ '}',
+ 'if (isdigit(str[0])) {',
+ CodeGen(self.opt, 4*' ', [
+ 'return ({c_bool})atoi(str);'.format(**self.sym),
+ ]),
+ '}',
+ 'if (tolower(str[0]) == \'t\') {',
+ CodeGen(self.opt, 4*' ', [
+ 'return {c_true};'.format(**self.sym),
+ ]),
+ '}',
+ 'return {c_false};'.format(**self.sym),
+ ]),
+ '}',
+ ]),
+ Conditional(self.opt, '', self.opt.poly is None or self.opt.xor_in is None or self.opt.xor_out is None, [
+ '',
+ '',
+ 'static crc_t xtoi(const char *str)',
+ '{',
+ CodeGen(self.opt, 4*' ', [
+ 'crc_t ret = 0;',
+ '',
+ 'if (!str) {',
+ CodeGen(self.opt, 4*' ', [
+ 'return 0;',
+ ]),
+ '}',
+ 'if (str[0] == \'0\' && tolower(str[1]) == \'x\') {',
+ CodeGen(self.opt, 4*' ', [
+ 'str += 2;',
+ 'while (*str) {',
+ CodeGen(self.opt, 4*' ', [
+ 'if (isdigit(*str))',
+ CodeGen(self.opt, 4*' ', [
+ 'ret = 16 * ret + *str - \'0\';',
+ ]),
+ 'else if (isxdigit(*str))',
+ CodeGen(self.opt, 4*' ', [
+ 'ret = 16 * ret + tolower(*str) - \'a\' + 10;',
+ ]),
+ 'else',
+ CodeGen(self.opt, 4*' ', [
+ 'return ret;',
+ ]),
+ 'str++;',
+ ]),
+ '}',
+ ]),
+ '} else if (isdigit(*str)) {',
+ CodeGen(self.opt, 4*' ', [
+ 'while (*str) {',
+ CodeGen(self.opt, 4*' ', [
+ 'if (isdigit(*str))',
+ CodeGen(self.opt, 4*' ', [
+ 'ret = 10 * ret + *str - \'0\';',
+ ]),
+ 'else',
+ CodeGen(self.opt, 4*' ', [
+ 'return ret;',
+ ]),
+ 'str++;',
+ ]),
+ '}',
+ ]),
+ '}',
+ 'return ret;',
+ ]),
+ '}',
+ ]),
+ '',
+ '',
+ Conditional2(self.opt, '', self.opt.undefined_crc_parameters, [
+ 'static int get_config(int argc, char *argv[], {cfg_t} *cfg)'.format(**self.sym),
+ ], [
+ 'static int get_config(int argc, char *argv[])',
+ ]),
+ '{',
+ CodeGen(self.opt, 4*' ', [
+ 'int c;',
+ 'int option_index;',
+ 'static struct option long_options[] = {',
+ CodeGen(self.opt, 4*' ', [
+ Conditional(self.opt, '', self.opt.width is None, [
+ '{"width", 1, 0, \'w\'},',
+ ]),
+ Conditional(self.opt, '', self.opt.poly is None, [
+ '{"poly", 1, 0, \'p\'},',
+ ]),
+ Conditional(self.opt, '', self.opt.reflect_in is None, [
+ '{"reflect-in", 1, 0, \'n\'},',
+ ]),
+ Conditional(self.opt, '', self.opt.xor_in is None, [
+ '{"xor-in", 1, 0, \'i\'},',
+ ]),
+ Conditional(self.opt, '', self.opt.reflect_out is None, [
+ '{"reflect-out", 1, 0, \'u\'},',
+ ]),
+ Conditional(self.opt, '', self.opt.xor_out is None, [
+ '{"xor-out", 1, 0, \'o\'},',
+ ]),
+ '{"verbose", 0, 0, \'v\'},',
+ '{"check-string", 1, 0, \'s\'},',
+ Conditional(self.opt, '', self.opt.width is None, [
+ '{"table-idx-with", 1, 0, \'t\'},',
+ ]),
+ '{0, 0, 0, 0}',
+ ]),
+ '};',
+ '',
+ 'while (1) {',
+ CodeGen(self.opt, 4*' ', [
+ 'option_index = 0;',
+ '',
+ 'c = getopt_long(argc, argv, "w:p:n:i:u:o:s:vt", long_options, &option_index);',
+ 'if (c == -1)',
+ CodeGen(self.opt, 4*' ', [
+ 'break;',
+ ]),
+ '',
+ 'switch (c) {',
+ CodeGen(self.opt, 4*' ', [
+ 'case 0:',
+ CodeGen(self.opt, 4*' ', [
+ 'printf("option %s", long_options[option_index].name);',
+ 'if (optarg)',
+ CodeGen(self.opt, 4*' ', [
+ 'printf(" with arg %s", optarg);',
+ ]),
+ 'printf("\\n");',
+ 'break;',
+ ]),
+ Conditional(self.opt, '', self.opt.width is None, [
+ 'case \'w\':',
+ CodeGen(self.opt, 4*' ', [
+ 'cfg->width = atoi(optarg);',
+ 'break;',
+ ]),
+ ]),
+ Conditional(self.opt, '', self.opt.poly is None, [
+ 'case \'p\':',
+ CodeGen(self.opt, 4*' ', [
+ 'cfg->poly = xtoi(optarg);',
+ 'break;',
+ ]),
+ ]),
+ Conditional(self.opt, '', self.opt.reflect_in is None, [
+ 'case \'n\':',
+ CodeGen(self.opt, 4*' ', [
+ 'cfg->reflect_in = atob(optarg);',
+ 'break;',
+ ]),
+ ]),
+ Conditional(self.opt, '', self.opt.xor_in is None, [
+ 'case \'i\':',
+ CodeGen(self.opt, 4*' ', [
+ 'cfg->xor_in = xtoi(optarg);',
+ 'break;',
+ ]),
+ ]),
+ Conditional(self.opt, '', self.opt.reflect_out is None, [
+ 'case \'u\':',
+ CodeGen(self.opt, 4*' ', [
+ 'cfg->reflect_out = atob(optarg);',
+ 'break;',
+ ]),
+ ]),
+ Conditional(self.opt, '', self.opt.xor_out is None, [
+ 'case \'o\':',
+ CodeGen(self.opt, 4*' ', [
+ 'cfg->xor_out = xtoi(optarg);',
+ 'break;',
+ ]),
+ ]),
+ 'case \'s\':',
+ CodeGen(self.opt, 4*' ', [
+ 'memcpy(str, optarg, strlen(optarg) < sizeof(str) ? strlen(optarg) + 1 : sizeof(str));',
+ 'str[sizeof(str) - 1] = \'\\0\';',
+ 'break;',
+ ]),
+ 'case \'v\':',
+ CodeGen(self.opt, 4*' ', [
+ 'verbose = {c_true};'.format(**self.sym),
+ 'break;',
+ ]),
+ Conditional(self.opt, '', self.opt.width is None, [
+ 'case \'t\':',
+ CodeGen(self.opt, 4*' ', [
+ '/* ignore --table_idx_width option */',
+ 'break;',
+ ]),
+ ]),
+ 'case \'?\':',
+ CodeGen(self.opt, 4*' ', [
+ 'return -1;',
+ ]),
+ 'case \':\':',
+ CodeGen(self.opt, 4*' ', [
+ 'fprintf(stderr, "missing argument to option %c\\n", c);',
+ 'return -1;',
+ ]),
+ 'default:',
+ CodeGen(self.opt, 4*' ', [
+ 'fprintf(stderr, "unhandled option %c\\n", c);',
+ 'return -1;',
+ ]),
+ ]),
+ '}',
+ ]),
+ '}',
+ Conditional(self.opt, '', self.opt.width is None, [
+ 'cfg->msb_mask = (crc_t)1u << (cfg->width - 1);',
+ 'cfg->crc_mask = (cfg->msb_mask - 1) | cfg->msb_mask;',
+ 'cfg->crc_shift = cfg->width < 8 ? 8 - cfg->width : 0;',
+ ]),
+ '',
+ Conditional(self.opt, '', self.opt.poly is None, [
+ 'cfg->poly &= {cfg_mask};'.format(**self.sym),
+ ]),
+ Conditional(self.opt, '', self.opt.xor_in is None, [
+ 'cfg->xor_in &= {cfg_mask};'.format(**self.sym),
+ ]),
+ Conditional(self.opt, '', self.opt.xor_out is None, [
+ 'cfg->xor_out &= {cfg_mask};'.format(**self.sym),
+ ]),
+ 'return 0;',
+ ]),
+ '}',
+ ]
+ return CodeGen(self.opt, '', out)
+
+
+def _includes(opt):
+ """
+ Return the #include directives for the user-defined list of include files.
+ """
+ includes = []
+ if opt.include_files is not None and len(opt.include_files) > 0:
+ for include_file in opt.include_files:
+ if include_file[0] == '"' or include_file[0] == '<':
+ includes.append('#include {0}'.format(include_file))
+ else:
+ includes.append('#include "{0}"'.format(include_file))
+ return includes
+
+
+def _crc_algo_define(opt, sym):
+ """
+ Get the the identifier for header files.
+ """
+ name = sym['crc_algorithm'].upper().replace('-', '_')
+ return 'CRC_ALGO_' + name
+
+
+def _use_cfg(opt):
+ """
+ Return True if a cfg_t structure is to be used.
+ """
+ return opt.undefined_crc_parameters
+
+
+def _use_constant_crc_init(sym):
+ """
+ Return True if the inintial value is constant.
+ """
+ return sym['crc_init_value'] is not None
+
+
+def _use_reflect_func(opt):
+ """
+ Return True if the reflect function is to be used.
+ """
+ if opt.reflect_out == None or opt.reflect_in == None:
+ return True
+ elif opt.algorithm == opt.algo_table_driven:
+ if opt.reflect_in != opt.reflect_out:
+ return True
+ elif opt.algorithm == opt.algo_bit_by_bit:
+ if opt.reflect_in:
+ return True
+ if opt.reflect_out:
+ return True
+ elif opt.algorithm == opt.algo_bit_by_bit_fast:
+ if opt.reflect_in:
+ return True
+ if opt.reflect_out:
+ return True
+ return False
+
+
+def _use_static_reflect_func(opt):
+ """
+ Whether a static reflect function is to be used.
+ """
+ if opt.algorithm == opt.algo_table_driven:
+ return False
+ elif opt.reflect_out is not None and opt.algorithm == opt.algo_bit_by_bit_fast:
+ return False
+ else:
+ return True
+
+
+def _use_crc_table_gen(opt):
+ """
+ Return True if the table generator function is to be generated.
+ """
+ if opt.algorithm == opt.algo_table_driven:
+ return opt.width is None or opt.poly is None or opt.reflect_in is None
+ else:
+ return False
+
+
+def _crc_init_function_def(opt, sym):
+ """
+ The definition for the init function.
+ """
+ if _use_constant_crc_init(sym):
+ return '{crc_t} {crc_init_function}(void)'.format(**sym)
+ else:
+ return '{crc_t} {crc_init_function}(const {cfg_t} *cfg)'.format(**sym)
+
+
+def _use_cfg_in_crc_update(opt):
+ """
+ Return True if the update function uses the cfg_t parameter.
+ """
+ if opt.algorithm in set([opt.algo_bit_by_bit, opt.algo_bit_by_bit_fast]):
+ if opt.width is not None and opt.poly is not None and opt.reflect_in is not None:
+ return True
+ elif opt.algorithm == opt.algo_table_driven:
+ if opt.width is not None and opt.reflect_in is not None:
+ return True
+ return False
+
+
+def _crc_update_function_def(opt, sym):
+ """
+ The definition of the update function.
+ """
+ if _use_cfg_in_crc_update(opt):
+ return '{crc_t} {crc_update_function}({crc_t} crc, const void *data, size_t data_len)'.format(**sym)
+ else:
+ return '{crc_t} {crc_update_function}(const {cfg_t} *cfg, {crc_t} crc, const void *data, size_t data_len)'.format(**sym)
+
+
+def _use_cfg_in_finalize(opt):
+ """
+ Return True if the cfg_t parameter is used in the finalize function.
+ """
+ if opt.algorithm == opt.algo_bit_by_bit:
+ if opt.width is not None and opt.poly is not None and opt.reflect_out is not None and opt.xor_out is not None:
+ return True
+ elif opt.algorithm == opt.algo_bit_by_bit_fast:
+ if opt.width is not None and opt.reflect_out is not None and opt.xor_out is not None:
+ return True
+ elif opt.algorithm == opt.algo_table_driven:
+ if opt.width is not None and opt.reflect_in is not None and opt.reflect_out is not None and opt.xor_out is not None:
+ return True
+ return False
+
+
+def _use_inline_crc_finalize(opt):
+ """
+ Return True if the init function can be inlined.
+ """
+ if opt.algorithm in set([opt.algo_bit_by_bit_fast, opt.algo_table_driven]) and \
+ (opt.width is not None and opt.reflect_in is not None and opt.reflect_out is not None and opt.xor_out is not None):
+ return True
+ else:
+ return False
+
+
+def _use_constant_crc_table(opt):
+ """
+ Return True is the CRC table is constant.
+ """
+ if opt.width is not None and opt.poly is not None and opt.reflect_in is not None:
+ return True
+ else:
+ return False
+
+
+def _crc_finalize_function_def(opt, sym):
+ """
+ The definition of the finalize function.
+ """
+ if _use_cfg_in_finalize(opt):
+ return '{crc_t} {crc_finalize_function}({crc_t} crc)'.format(**sym)
+ else:
+ return '{crc_t} {crc_finalize_function}(const {cfg_t} *cfg, {crc_t} crc)'.format(**sym)
+
+
+def _crc_final_value(opt, sym):
+ """
+ The return value for the finalize function.
+ """
+ if opt.algorithm == opt.algo_table_driven:
+ if opt.reflect_in == opt.reflect_out:
+ return expr.Xor('crc', sym['crc_xor_out']).simplify()
+ else:
+ reflect_fun = expr.FunctionCall(sym['crc_reflect_function'], ['crc', sym['crc_width']])
+ return expr.Xor(reflect_fun, sym['crc_xor_out']).simplify()
+ elif opt.reflect_out:
+ reflect_fun = expr.FunctionCall(sym['crc_reflect_function'], ['crc', sym['crc_width']])
+ return expr.Xor(reflect_fun, sym['crc_xor_out']).simplify()
+ else:
+ return expr.Xor('crc', sym['crc_xor_out']).simplify()
+
+
+def _crc_table(opt, sym):
+ """
+ Return the code for the CRC table or the generator function.
+ """
+ if opt.algorithm != opt.algo_table_driven:
+ return []
+ return [
+ '', '',
+ Comment(opt, '', [
+ 'Static table used for the table_driven implementation.',
+ Conditional(opt, '', opt.undefined_crc_parameters, [
+ 'Must be initialised with the {crc_table_gen_function} function.'.format(**sym),
+ ]),
+ ]),
+ Conditional2(opt, '', _use_constant_crc_table(opt), [
+ Conditional2(opt, '', opt.slice_by > 1, [
+ 'static const {crc_t} crc_table[{crc_slice_by}][{crc_table_width}] = {crc_table_init};'.format(**sym),
+ ], [
+ 'static const {crc_t} crc_table[{crc_table_width}] = {crc_table_init};'.format(**sym),
+ ]),
+ ], [
+ 'static {crc_t} crc_table[{crc_table_width}];'.format(**sym),
+ ]),
+ ]
+
+
+def _crc_table_gen(opt, sym):
+ """
+ Return the code for the CRC table or the generator function.
+ """
+ if opt.algorithm != opt.algo_table_driven or _use_constant_crc_table(opt):
+ return []
+ return [
+ '', '',
+ 'void {crc_table_gen_function}(const {cfg_t} *cfg)'.format(**sym),
+ '{',
+ CodeGen(opt, 4*' ', [
+ '{crc_t} crc;'.format(**sym),
+ 'unsigned int i, j;',
+ '',
+ 'for (i = 0; i < {cfg_table_width}; i++) '.format(**sym) + '{',
+ CodeGen(opt, 4*' ', [
+ Conditional2(opt, '', opt.reflect_in is None, [
+ 'if (cfg->reflect_in) {',
+ CodeGen(opt, 4*' ', [
+ 'crc = {crc_reflect_function}(i, {cfg_table_idx_width});'.format(**sym),
+ ]),
+ '} else {',
+ CodeGen(opt, 4*' ', [
+ 'crc = i;',
+ ]),
+ '}',
+ ], [
+ Conditional2(opt, '', opt.reflect_in, [
+ 'crc = {crc_reflect_function}(i, {cfg_table_idx_width});'.format(**sym),
+ ], [
+ 'crc = i;',
+ ]),
+ ]),
+ 'crc <<= {0};'.format(expr.Parenthesis(expr.Add(expr.Sub(sym['cfg_width'], sym['cfg_table_idx_width']), sym['cfg_shift'])).simplify()),
+ 'for (j = 0; j < {cfg_table_idx_width}; j++) '.format(**sym) + '{',
+ CodeGen(opt, 4*' ', [
+ 'if (crc & {cfg_msb_mask_shifted}) '.format(**sym) + '{',
+ CodeGen(opt, 4*' ', [
+ 'crc = {0};'.format(expr.Xor(expr.Parenthesis(expr.Shl('crc', 1)), sym['cfg_poly_shifted']).simplify()),
+ ]),
+ '} else {',
+ CodeGen(opt, 4*' ', [
+ 'crc = crc << 1;',
+ ]),
+ '}',
+ ]),
+ '}',
+ Conditional(opt, '', opt.reflect_in is None, [
+ 'if (cfg->reflect_in) {',
+ Conditional2(opt, 4*' ', sym.tbl_shift is None or sym.tbl_shift > 0, [
+ 'crc = {0};'.format(expr.Shl(expr.FunctionCall(sym['crc_reflect_function'], [expr.Shr('crc', sym['cfg_shift']), sym['cfg_width']]), sym['cfg_shift']).simplify()),
+ ], [
+ 'crc = {crc_reflect_function}(crc, {cfg_width});'.format(**sym),
+ ]),
+ '}',
+ ]),
+ Conditional(opt, '', opt.reflect_in, [
+ Conditional2(opt, 4*' ', sym.tbl_shift is None or sym.tbl_shift > 0, [
+ 'crc = {0};'.format(expr.Shl(expr.FunctionCall(sym['crc_reflect_function'], [expr.Shr('crc', sym['cfg_shift']), sym['cfg_width']]), sym['cfg_shift']).simplify()),
+ ], [
+ 'crc = {crc_reflect_function}(crc, {cfg_width});'.format(**sym),
+ ]),
+ ]),
+ 'crc_table[i] = {0};'.format(expr.Shr(expr.Parenthesis(expr.And('crc', sym['cfg_mask_shifted'])), sym['cfg_shift'])),
+ ]),
+ '}',
+ ]),
+ '}',
+ ]
+
+
+def _crc_reflect_function_gen(opt, sym):
+ """
+ Return the code for the reflect functon.
+ """
+ if not _use_reflect_func(opt):
+ return []
+ if not (opt.reflect_in is None or opt.reflect_in or \
+ opt.reflect_out is None or opt.reflect_out):
+ return []
+ return [
+ '', '',
+ '{crc_t} {crc_reflect_function}({crc_t} data, size_t data_len)'.format(**sym),
+ '{',
+ CodeGen(opt, 4*' ', [
+ 'unsigned int i;',
+ '{crc_t} ret;'.format(**sym),
+ '',
+ 'ret = data & 0x01;',
+ 'for (i = 1; i < data_len; i++) {',
+ CodeGen(opt, 4*' ', [
+ 'data >>= 1;',
+ 'ret = (ret << 1) | (data & 0x01);',
+ ]),
+ '}',
+ 'return ret;',
+ ]),
+ '}',
+ ]
+
+
+def _crc_init_function_gen(opt, sym):
+ """
+ Return the code for the init function.
+ """
+ if _use_constant_crc_init(sym):
+ return []
+ out = [
+ '', '',
+ _crc_init_function_def(opt, sym),
+ '{',
+ CodeGen(opt, 4*' ', [
+ Conditional(opt, '', opt.algorithm == opt.algo_bit_by_bit, [
+ 'unsigned int i;',
+ '{c_bool} bit;'.format(**sym),
+ '{crc_t} crc = {cfg_xor_in};'.format(**sym),
+ 'for (i = 0; i < {cfg_width}; i++) '.format(**sym) + '{',
+ CodeGen(opt, 4*' ', [
+ 'bit = crc & 0x01;',
+ 'if (bit) {',
+ CodeGen(opt, 4*' ', [
+ 'crc = ((crc ^ {cfg_poly}) >> 1) | {cfg_msb_mask};'.format(**sym),
+ ]),
+ '} else {',
+ CodeGen(opt, 4*' ', [
+ 'crc >>= 1;',
+ ]),
+ '}',
+ ]),
+ '}',
+ 'return crc & {cfg_mask};'.format(**sym),
+ ]),
+ Conditional(opt, '', opt.algorithm == opt.algo_bit_by_bit_fast, [
+ 'return {cfg_xor_in} & {cfg_mask};'.format(**sym),
+ ]),
+ Conditional(opt, '', opt.algorithm == opt.algo_table_driven, [
+ Conditional2(opt, '', opt.reflect_in is None, [
+ 'if ({cfg_reflect_in}) '.format(**sym) + '{',
+ CodeGen(opt, 4*' ', [
+ 'return {crc_reflect_function}({cfg_xor_in} & {cfg_mask}, {cfg_width});'.format(**sym),
+ ]),
+ '} else {',
+ CodeGen(opt, 4*' ', [
+ 'return {cfg_xor_in} & {cfg_mask};'.format(**sym),
+ ]),
+ '}',
+ ], [
+ Conditional2(opt, '', opt.algorithm == opt.reflect_in, [
+ 'return {crc_reflect_function}({cfg_xor_in} & {cfg_mask}, {cfg_width});'.format(**sym),
+ ], [
+ 'return {cfg_xor_in} & {cfg_mask};'.format(**sym),
+ ]),
+ ]),
+ ]),
+ ]),
+ '}',
+ ]
+ return out
+
+
+def _crc_update_function_gen(opt, sym):
+ """
+ Return the code for the update function.
+ """
+ out = [
+ '', '',
+ _crc_update_function_def(opt, sym),
+ '{',
+ CodeGen(opt, 4*' ', [ 'const unsigned char *d = (const unsigned char *)data;' ]),
+ ]
+ if opt.algorithm == opt.algo_bit_by_bit:
+ out += [
+ CodeGen(opt, 4*' ', [
+ 'unsigned int i;',
+ '{c_bool} bit;'.format(**sym),
+ 'unsigned char c;',
+ '',
+ 'while (data_len--) {',
+ Conditional2(opt, 4*' ', opt.reflect_in is None, [
+ 'if (' + sym['cfg_reflect_in'] + ') {',
+ CodeGen(opt, 4*' ', [
+ 'c = {crc_reflect_function}(*d++, 8);'.format(**sym),
+ ]),
+ '} else {',
+ CodeGen(opt, 4*' ', [
+ 'c = *d++;',
+ ]),
+ '}',
+ ], [
+ Conditional2(opt, '', opt.reflect_in, [
+ 'c = {crc_reflect_function}(*d++, 8);'.format(**sym),
+ ], [
+ 'c = *d++;',
+ ]),
+ ]),
+
+ CodeGen(opt, 4*' ', [
+ 'for (i = 0; i < 8; i++) {',
+ CodeGen(opt, 4*' ', [
+ Conditional2(opt, '', opt.c_std == 'C89', [
+ 'bit = !!(crc & {cfg_msb_mask});'.format(**sym),
+ ], [
+ 'bit = crc & {cfg_msb_mask};'.format(**sym),
+ ]),
+ 'crc = (crc << 1) | ((c >> (7 - i)) & 0x01);',
+ 'if (bit) {',
+ CodeGen(opt, 4*' ', [
+ 'crc ^= {cfg_poly};'.format(**sym),
+ ]),
+ '}',
+ ]),
+ '}',
+ 'crc &= {cfg_mask};'.format(**sym),
+ ]),
+ '}',
+ 'return crc & {cfg_mask};'.format(**sym),
+ ]),
+ ]
+
+ if opt.algorithm == opt.algo_bit_by_bit_fast:
+ out += [
+ CodeGen(opt, 4*' ', [
+ 'unsigned int i;',
+ '{c_bool} bit;'.format(**sym),
+ 'unsigned char c;',
+ '',
+ 'while (data_len--) {',
+ CodeGen(opt, 4*' ', [
+ Conditional2(opt, '', opt.reflect_in == None, [
+ 'if (' + sym['cfg_reflect_in'] + ') {',
+ CodeGen(opt, 4*' ', [
+ 'c = {crc_reflect_function}(*d++, 8);'.format(**sym),
+ ]),
+ '} else {',
+ CodeGen(opt, 4*' ', [
+ 'c = *d++;',
+ ]),
+ '}',
+ ], [
+ 'c = *d++;',
+ ]),
+ Conditional2(opt, '', opt.reflect_in, [
+ 'for (i = 0x01; i & 0xff; i <<= 1) {',
+ ], [
+ 'for (i = 0x80; i > 0; i >>= 1) {',
+ ]),
+ CodeGen(opt, 4*' ', [
+ Conditional2(opt, '', opt.c_std == 'C89', [
+ 'bit = !!({0});'.format(expr.And('crc', sym['cfg_msb_mask']).simplify()),
+ ], [
+ 'bit = {0};'.format(expr.And('crc', sym['cfg_msb_mask']).simplify()),
+ ]),
+ 'if (c & i) {',
+ CodeGen(opt, 4*' ', [
+ 'bit = !bit;',
+ ]),
+ '}',
+ 'crc <<= 1;',
+ 'if (bit) {',
+ CodeGen(opt, 4*' ', [
+ 'crc ^= {cfg_poly};'.format(**sym),
+ ]),
+ '}',
+ ]),
+ '}',
+ 'crc &= {cfg_mask};'.format(**sym)
+ ]),
+ '}',
+ 'return {0};'.format(expr.And('crc', sym['cfg_mask']).simplify()),
+ ]),
+ ]
+
+ if opt.algorithm == opt.algo_table_driven:
+ out += [
+ CodeGen(opt, 4*' ', [
+ 'unsigned int tbl_idx;',
+ '',
+ Conditional2(opt, '', opt.reflect_in == None, [
+ 'if (cfg->reflect_in) {',
+ CodeGen(opt, 4*' ', [
+ 'while (data_len--) {',
+ CodeGen(opt, 4*' ', [
+ _crc_table_core_algorithm_reflected(opt, sym),
+ 'd++;',
+ ]),
+ '}',
+ ]),
+ '} else {',
+ CodeGen(opt, 4*' ', [
+ 'while (data_len--) {',
+ CodeGen(opt, 4*' ', [
+ _crc_table_core_algorithm_nonreflected(opt, sym),
+ 'd++;',
+ ]),
+ '}',
+ ]),
+ '}',
+ ], [
+ Conditional(opt, '', opt.slice_by > 1, [
+ '/* Align to a multiple of {crc_slice_by} bytes */'.format(**sym),
+ 'while (data_len && (((uintptr_t)(const void *)d) % {crc_slice_by} != 0))'.format(**sym) + ' {',
+ CodeGen(opt, 4*' ', [
+ _crc_table_core_algorithm(opt, sym),
+ 'data_len--;',
+ ]),
+ '}',
+ '',
+ _crc_table_slice_by_algorithm(opt, sym),
+ '/* Remaining bytes with the standard algorithm */',
+ 'd = (const unsigned char *)d32;',
+ ]),
+ 'while (data_len--) {',
+ CodeGen(opt, 4*' ', [
+ _crc_table_core_algorithm(opt, sym),
+ ]),
+ '}',
+ ]),
+ 'return {0};'.format(expr.And('crc', sym['cfg_mask']).simplify()),
+ ]),
+ ]
+ out += [
+ '}',
+ ]
+ return out
+
+
+
+def _crc_finalize_function_gen(opt, sym):
+ """
+ Return the code for the finalize function.
+ """
+ if _use_inline_crc_finalize(opt):
+ return []
+ out = [
+ '', '',
+ _crc_finalize_function_def(opt, sym),
+ '{',
+ ]
+ if opt.algorithm in set([opt.algo_bit_by_bit, opt.algo_bit_by_bit_fast]):
+ out += [
+ Conditional(opt, 4*' ', opt.algorithm == opt.algo_bit_by_bit, [
+ 'unsigned int i;',
+ '{c_bool} bit;'.format(**sym),
+ '',
+ 'for (i = 0; i < ' + sym['cfg_width'] + '; i++) {',
+ CodeGen(opt, 4*' ', [
+ Conditional2(opt, '', opt.c_std == 'C89', [
+ 'bit = !!(crc & {cfg_msb_mask});'.format(**sym)
+ ], [
+ 'bit = crc & {cfg_msb_mask};'.format(**sym),
+ ]),
+ 'crc <<= 1;',
+ 'if (bit) {',
+ CodeGen(opt, 4*' ', [
+ 'crc ^= {cfg_poly};'.format(**sym),
+ ]),
+ '}',
+ ]),
+ '}',
+ Conditional(opt, '', opt.reflect_out is None, [
+ 'if (' + sym['cfg_reflect_out'] + ') {',
+ CodeGen(opt, 4*' ', [
+ 'crc = {crc_reflect_function}(crc, {cfg_width});'.format(**sym),
+ ]),
+ '}',
+ ]),
+ Conditional(opt, '', opt.reflect_out, [
+ 'crc = {crc_reflect_function}(crc, {cfg_width});'.format(**sym),
+ ]),
+ ]),
+
+ Conditional(opt, 4*' ', opt.algorithm == opt.algo_bit_by_bit_fast, [
+ Conditional(opt, '', opt.reflect_out is None, [
+ 'if (' + sym['cfg_reflect_out'] + ') {',
+ CodeGen(opt, 4*' ', [
+ 'crc = {crc_reflect_function}(crc, {cfg_width});'.format(**sym),
+ ]),
+ '}',
+ ]),
+ Conditional(opt, '', opt.reflect_out, [
+ 'crc = {crc_reflect_function}(crc, {cfg_width});'.format(**sym),
+ ]),
+ ]),
+ ]
+
+ if opt.algorithm == opt.algo_table_driven:
+ if opt.reflect_in is None or opt.reflect_out is None:
+ if opt.reflect_in is None and opt.reflect_out is None:
+ cond = 'cfg->reflect_in != cfg->reflect_out'
+ elif opt.reflect_out is None:
+ cond = '!' if opt.reflect_in else '' + 'cfg->reflect_out'
+ else:
+ cond = '!' if opt.reflect_out else '' + 'cfg->reflect_in'
+ out += [
+ CodeGen(opt, 4*' ', [
+ 'if (' + cond + ') {',
+ CodeGen(opt, 4*' ', [
+ 'crc = {crc_reflect_function}(crc, {cfg_width});'.format(**sym),
+ ]),
+ '}',
+ ]),
+ ]
+ elif opt.reflect_in != opt.reflect_out:
+ out += [
+ 'crc = {crc_reflect_function}(crc, {cfg_width});'.format(**sym),
+ ]
+ out += [
+ CodeGen(opt, 4*' ', [
+ 'return {0};'.format(expr.And(expr.Parenthesis(expr.Xor('crc', sym['cfg_xor_out'])), sym['cfg_mask']).simplify()),
+ ]),
+ '}',
+ ]
+ return out
+
+def _crc_table_core_algorithm(opt, sym):
+ """
+ Return the core of the table-driven algorithm.
+ """
+ out = []
+ out += [
+ Conditional2(opt, '', opt.reflect_in, [
+ _crc_table_core_algorithm_reflected(opt, sym),
+ ], [
+ _crc_table_core_algorithm_nonreflected(opt, sym),
+ ]),
+ 'd++;',
+ ]
+ return CodeGen(opt, '', out)
+
+def _crc_table_core_algorithm_reflected(opt, sym):
+ """
+ Return the core loop of the table-driven algorithm, reflected variant.
+ """
+ out = []
+ if opt.width is not None and opt.tbl_idx_width is not None and opt.width <= opt.tbl_idx_width:
+ crc_xor_expr = '0'
+ else:
+ crc_xor_expr = '(crc >> {cfg_table_idx_width})'.format(**sym)
+
+ if opt.tbl_idx_width == 8:
+ if opt.slice_by > 1:
+ crc_lookup = 'crc_table[0][tbl_idx]'
+ else:
+ crc_lookup = 'crc_table[tbl_idx]'
+ out += [
+ Conditional2(opt, '', opt.width is None or opt.width > 8, [
+ 'tbl_idx = (crc ^ *d) & {crc_table_mask};'.format(**sym),
+ ], [
+ 'tbl_idx = crc ^ *d;',
+ ]),
+ 'crc = {0};'.format(expr.And(expr.Parenthesis(expr.Xor(crc_lookup, expr.Parenthesis(expr.Shr('crc', sym['cfg_table_idx_width'])))), sym['cfg_mask']).simplify()),
+ ]
+ else:
+ crc_lookup = 'crc_table[tbl_idx & {crc_table_mask}]'.format(**sym)
+ for i in range(8 // opt.tbl_idx_width):
+ out += [
+ 'tbl_idx = {0};'.format(expr.Xor('crc', expr.Parenthesis(expr.Shr('*d', expr.Parenthesis(expr.Mul(i, sym['cfg_table_idx_width']))))).simplify()),
+ 'crc = {0};'.format(expr.Xor(crc_lookup, crc_xor_expr).simplify())
+ ]
+ return CodeGen(opt, '', out)
+
+def _crc_table_core_algorithm_nonreflected(opt, sym):
+ """
+ Return the core loop of the table-driven algorithm, non-reflected variant.
+ """
+ out = []
+ if opt.width == None:
+ crc_shifted_right = expr.Parenthesis(expr.Shr('crc', expr.Parenthesis(expr.Sub(sym['cfg_width'], sym['cfg_table_idx_width'])))).simplify()
+ elif opt.width < 8:
+ shift_val = opt.width - opt.tbl_idx_width
+ if shift_val < 0:
+ crc_shifted_right = expr.Parenthesis(expr.Shl('crc', -shift_val)).simplify()
+ else:
+ crc_shifted_right = expr.Parenthesis(expr.Shr('crc', shift_val)).simplify()
+ else:
+ shift_val = opt.width - opt.tbl_idx_width
+ crc_shifted_right = expr.Parenthesis(expr.Shr('crc', shift_val)).simplify()
+
+ if opt.width is not None and opt.tbl_idx_width is not None and opt.width <= opt.tbl_idx_width:
+ crc_xor_expr = '0'
+ else:
+ crc_xor_expr = '(crc << {cfg_table_idx_width})'.format(**sym)
+
+ if opt.tbl_idx_width == 8:
+ if opt.slice_by > 1:
+ crc_lookup = 'crc_table[0][tbl_idx]'
+ else:
+ crc_lookup = 'crc_table[tbl_idx]'
+ out += [
+ Conditional2(opt, '', opt.width is None or opt.width > 8, [
+ 'tbl_idx = {0};'.format(expr.And(expr.Parenthesis(expr.Xor(crc_shifted_right, '*d')), sym['crc_table_mask']).simplify())
+ ], [
+ 'tbl_idx = {0};'.format(expr.Xor(crc_shifted_right, '*d').simplify())
+ ]),
+ 'crc = {0};'.format(expr.And(expr.Parenthesis(expr.Xor(crc_lookup, crc_xor_expr)), sym['cfg_mask']).simplify())
+ ]
+ else:
+ crc_lookup = 'crc_table[tbl_idx & {crc_table_mask}]'.format(**sym)
+ for i in range(8 // opt.tbl_idx_width):
+ str_idx = '{0:d}'.format(8 - (i + 1) * opt.tbl_idx_width)
+ out += [
+ 'tbl_idx = {0};'.format(expr.Xor(crc_shifted_right, expr.Parenthesis(expr.Shr('*d', str_idx)))),
+ 'crc = {0};'.format(expr.Xor(crc_lookup, crc_xor_expr).simplify()),
+ ]
+ return CodeGen(opt, '', out)
+
+def _crc_table_slice_by_algorithm(opt, sym):
+ update_be = []
+ for i in range(opt.slice_by // 4):
+ vard = 'd{0}'.format(opt.slice_by // 4 - i)
+ for j in range(4):
+ idx1 = i * 4 + j
+ idx2 = expr.And(expr.Parenthesis(expr.Shr(vard, j*8)), expr.Terminal(255, '0xffu')).simplify()
+ update_be.append('crc_table[{0}][{1}]{2}'.format(idx1, idx2, ' ^' if idx1 < opt.slice_by - 1 else ';'))
+
+ update_le = []
+ for i in range(opt.slice_by // 4):
+ vard = 'd{0}'.format(opt.slice_by // 4 - i)
+ for j in range(4):
+ idx1 = i * 4 + j
+ idx2 = expr.And(expr.Parenthesis(expr.Shr(vard, 24 - j*8)), expr.Terminal(255, '0xffu')).simplify()
+ update_le.append('crc_table[{0}][{1}]{2}'.format(idx1, idx2, ' ^' if idx1 < opt.slice_by - 1 else ';'))
+
+ out = [
+ 'const uint32_t *d32 = (const uint32_t *)d;',
+ 'while (data_len >= {crc_slice_by})'.format(**sym),
+ '{',
+ CodeGen(opt, 4*' ', [
+ CodeGen(opt, None, [
+ '#if __BYTE_ORDER == __BIG_ENDIAN',
+ ]),
+ '{crc_t} d1 = *d32++ ^ le16toh(crc);'.format(**sym),
+ Conditional(opt, '', opt.slice_by >= 8, [
+ '{crc_t} d2 = *d32++;'.format(**sym),
+ ]),
+ Conditional(opt, '', opt.slice_by >= 16, [
+ '{crc_t} d3 = *d32++;'.format(**sym),
+ '{crc_t} d4 = *d32++;'.format(**sym),
+ ]),
+ 'crc =',
+ CodeGen(opt, 4*' ', update_be),
+ CodeGen(opt, None, [
+ '#else',
+ ]),
+ '{crc_t} d1 = *d32++ ^ crc;'.format(**sym),
+ Conditional(opt, '', opt.slice_by >= 8, [
+ '{crc_t} d2 = *d32++;'.format(**sym),
+ ]),
+ Conditional(opt, '', opt.slice_by >= 16, [
+ '{crc_t} d3 = *d32++;'.format(**sym),
+ '{crc_t} d4 = *d32++;'.format(**sym),
+ ]),
+ 'crc =',
+ CodeGen(opt, 4*' ', update_le),
+ CodeGen(opt, None, [
+ '#endif',
+ ]),
+ '',
+ 'data_len -= {crc_slice_by};'.format(**sym),
+ ]),
+ '}',
+ '',
+ ]
+ return CodeGen(opt, '', out)
diff --git a/pycrc/expr.py b/pycrc/expr.py
new file mode 100644
index 0000000..a15742c
--- /dev/null
+++ b/pycrc/expr.py
@@ -0,0 +1,398 @@
+# pycrc -- parameterisable CRC calculation utility and C source code generator
+#
+# Copyright (c) 2017 Thomas Pircher <tehpeh-web@tty1.net>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+
+"""
+This modules simplifies an expression.
+
+ import pycrc.expr as exp
+
+ my_expr = exp.Xor('var', exp.Parenthesis(exp.And('0x700', 4)))
+ print('"{}" -> "{}"'.format(my_expr, my_expr.simplify()))
+"""
+
+
+def _classify(val):
+ """
+ Creates a Terminal object if the parameter is a string or an integer.
+ """
+ if type(val) is int:
+ return Terminal(val)
+ if type(val) is str:
+ if val.isdigit():
+ return Terminal(int(val), val)
+ if val[:2].lower() == '0x':
+ return Terminal(int(val, 16), val)
+ return Terminal(val)
+ return val
+
+
+class Expression(object):
+ """
+ Base class for all expressions.
+ """
+ def is_int(self, val = None):
+ return False
+
+
+class Terminal(Expression):
+ """
+ A terminal object.
+ """
+ def __init__(self, val, pretty = None):
+ """
+ Construct a Terminal.
+ The val variable is usually a string or an integer. Integers may also
+ be passed as strings. The pretty-printer will use the string when
+ formatting the expression.
+ """
+ self.val = val
+ self.pretty = pretty
+
+ def __str__(self):
+ """
+ Return the string expression of this object.
+ """
+ if self.pretty is None:
+ return str(self.val)
+ return self.pretty
+
+ def simplify(self):
+ """
+ Return a simplified version of this sub-expression.
+ """
+ return self
+
+ def is_int(self, val = None):
+ """
+ Return True if the value of this Terminal is an integer.
+ """
+ if type(self.val) is int:
+ return val is None or self.val == val
+ return False
+
+
+class FunctionCall(Expression):
+ """
+ Represent a function call
+ """
+ def __init__(self, name, args):
+ """
+ Construct a function call object.
+ """
+ self.name = _classify(name)
+ self.args = [_classify(arg) for arg in args]
+
+ def __str__(self):
+ """
+ Return the string expression of this object.
+ """
+ return str(self.name) + '(' + ', '.join([str(arg) for arg in self.args]) + ')'
+
+ def simplify(self):
+ """
+ Return a simplified version of this sub-expression.
+ """
+ args = [arg.simplify() for arg in self.args]
+ return FunctionCall(self.name, args)
+
+
+class Parenthesis(Expression):
+ """
+ Represent a pair of round brackets.
+ """
+ def __init__(self, val):
+ """
+ Construct a parenthesis object.
+ """
+ self.val = _classify(val)
+
+ def simplify(self):
+ """
+ Return a simplified version of this sub-expression.
+ """
+ val = self.val.simplify()
+ if type(val) is Terminal:
+ return val
+ return Parenthesis(val)
+
+ def __str__(self):
+ """
+ Return the string expression of this object.
+ """
+ return '(' + str(self.val) + ')'
+
+
+class Add(Expression):
+ """
+ Represent an addition of operands.
+ """
+ def __init__(self, lhs, rhs):
+ """
+ Construct an addition object.
+ """
+ self.lhs = _classify(lhs)
+ self.rhs = _classify(rhs)
+
+ def simplify(self):
+ """
+ Return a simplified version of this sub-expression.
+ """
+ lhs = self.lhs.simplify()
+ rhs = self.rhs.simplify()
+ if lhs.is_int() and rhs.is_int():
+ return Terminal(lhs.val + rhs.val)
+ if lhs.is_int(0):
+ return rhs
+ if rhs.is_int(0):
+ return lhs
+ return Add(lhs, rhs)
+
+ def __str__(self):
+ """
+ Return the string expression of this object.
+ """
+ return str(self.lhs) + ' + ' + str(self.rhs)
+
+
+class Sub(Expression):
+ """
+ Represent a subtraction of operands.
+ """
+ def __init__(self, lhs, rhs):
+ """
+ Construct subtraction object.
+ """
+ self.lhs = _classify(lhs)
+ self.rhs = _classify(rhs)
+
+ def simplify(self):
+ """
+ Return a simplified version of this sub-expression.
+ """
+ lhs = self.lhs.simplify()
+ rhs = self.rhs.simplify()
+ if lhs.is_int() and rhs.is_int():
+ return Terminal(lhs.val - rhs.val)
+ if lhs.is_int(0):
+ return rhs
+ if rhs.is_int(0):
+ return lhs
+ return Sub(lhs, rhs)
+
+ def __str__(self):
+ """
+ Return the string expression of this object.
+ """
+ return str(self.lhs) + ' - ' + str(self.rhs)
+
+
+class Mul(Expression):
+ """
+ Represent the multiplication of operands.
+ """
+ def __init__(self, lhs, rhs):
+ """
+ Construct a multiplication object.
+ """
+ self.lhs = _classify(lhs)
+ self.rhs = _classify(rhs)
+
+ def simplify(self):
+ """
+ Return a simplified version of this sub-expression.
+ """
+ lhs = self.lhs.simplify()
+ rhs = self.rhs.simplify()
+ if lhs.is_int() and rhs.is_int():
+ return Terminal(lhs.val * rhs.val)
+ if lhs.is_int(0) or rhs.is_int(0):
+ return Terminal(0)
+ if lhs.is_int(1):
+ return rhs
+ if rhs.is_int(1):
+ return lhs
+ return Mul(lhs, rhs)
+
+ def __str__(self):
+ """
+ Return the string expression of this object.
+ """
+ return str(self.lhs) + ' * ' + str(self.rhs)
+
+
+class Shl(Expression):
+ """
+ Shift left operation.
+ """
+ def __init__(self, lhs, rhs):
+ """
+ Construct a shift left object.
+ """
+ self.lhs = _classify(lhs)
+ self.rhs = _classify(rhs)
+
+ def simplify(self):
+ """
+ Return a simplified version of this sub-expression.
+ """
+ lhs = self.lhs.simplify()
+ rhs = self.rhs.simplify()
+ if lhs.is_int() and rhs.is_int():
+ return Terminal(lhs.val << rhs.val)
+ if lhs.is_int(0):
+ return Terminal(0)
+ if rhs.is_int(0):
+ return lhs
+ return Shl(lhs, rhs)
+
+ def __str__(self):
+ """
+ Return the string expression of this object.
+ """
+ return str(self.lhs) + ' << ' + str(self.rhs)
+
+
+class Shr(Expression):
+ """
+ Shift right operation.
+ """
+ def __init__(self, lhs, rhs):
+ """
+ Construct a shift right object.
+ """
+ self.lhs = _classify(lhs)
+ self.rhs = _classify(rhs)
+
+ def simplify(self):
+ """
+ Return a simplified version of this sub-expression.
+ """
+ lhs = self.lhs.simplify()
+ rhs = self.rhs.simplify()
+ if lhs.is_int() and rhs.is_int():
+ return Terminal(lhs.val >> rhs.val)
+ if lhs.is_int(0):
+ return Terminal(0)
+ if rhs.is_int(0):
+ return lhs
+ return Shr(lhs, rhs)
+
+ def __str__(self):
+ """
+ Return the string expression of this object.
+ """
+ return str(self.lhs) + ' >> ' + str(self.rhs)
+
+
+class Or(Expression):
+ """
+ Logical or operation.
+ """
+ def __init__(self, lhs, rhs):
+ """
+ Construct a logical and object.
+ """
+ self.lhs = _classify(lhs)
+ self.rhs = _classify(rhs)
+
+ def simplify(self):
+ """
+ Return a simplified version of this sub-expression.
+ """
+ lhs = self.lhs.simplify()
+ rhs = self.rhs.simplify()
+ if lhs.is_int() and rhs.is_int():
+ return Terminal(lhs.val | rhs.val)
+ if lhs.is_int(0):
+ return rhs
+ if rhs.is_int(0):
+ return lhs
+ return Or(lhs, rhs)
+
+ def __str__(self):
+ """
+ Return the string expression of this object.
+ """
+ return str(self.lhs) + ' | ' + str(self.rhs)
+
+
+class And(Expression):
+ """
+ Logical and operation.
+ """
+ def __init__(self, lhs, rhs):
+ """
+ Construct a logical and object.
+ """
+ self.lhs = _classify(lhs)
+ self.rhs = _classify(rhs)
+
+ def simplify(self):
+ """
+ Return a simplified version of this sub-expression.
+ """
+ lhs = self.lhs.simplify()
+ rhs = self.rhs.simplify()
+ if lhs.is_int() and rhs.is_int():
+ return Terminal(lhs.val & rhs.val)
+ if lhs.is_int(0) or rhs.is_int(0):
+ return Terminal(0)
+ return And(lhs, rhs)
+
+ def __str__(self):
+ """
+ Return the string expression of this object.
+ """
+ return str(self.lhs) + ' & ' + str(self.rhs)
+
+
+class Xor(Expression):
+ """
+ Logical xor operation.
+ """
+ def __init__(self, lhs, rhs):
+ """
+ Construct a logical xor object.
+ """
+ self.lhs = _classify(lhs)
+ self.rhs = _classify(rhs)
+
+ def simplify(self):
+ """
+ Return a simplified version of this sub-expression.
+ """
+ lhs = self.lhs.simplify()
+ rhs = self.rhs.simplify()
+ if lhs.is_int() and rhs.is_int():
+ return Terminal(lhs.val ^ rhs.val)
+ if lhs.is_int(0):
+ return rhs
+ if rhs.is_int(0):
+ return lhs
+ return Xor(lhs, rhs)
+
+ def __str__(self):
+ """
+ Return the string expression of this object.
+ """
+ return str(self.lhs) + ' ^ ' + str(self.rhs)
diff --git a/pycrc/main.py b/pycrc/main.py
new file mode 100644
index 0000000..d446362
--- /dev/null
+++ b/pycrc/main.py
@@ -0,0 +1,241 @@
+#!/usr/bin/env python
+
+# pycrc -- parameterisable CRC calculation utility and C source code generator
+#
+# Copyright (c) 2006-2017 Thomas Pircher <tehpeh-web@tty1.net>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+
+"""
+pycrc is a fully parameterisable Cyclic Redundancy Check (CRC) calculation
+utility and C source code generator written in Python.
+
+It can:
+ - generate the checksum of a string
+ - generate the checksum of a file
+ - generate the C header file and source of any of the algorithms below
+
+It supports the following CRC algorithms:
+ - bit-by-bit the basic algorithm which operates bit by bit on the
+ augmented message
+ - bit-by-bit-fast a variation of the simple bit-by-bit algorithm
+ - table-driven the standard table driven algorithm
+"""
+
+from __future__ import print_function
+from pycrc import progname, version, url
+from pycrc.opt import Options
+from pycrc.algorithms import Crc
+import pycrc.codegen as cg
+import binascii
+import sys
+
+
+
+def print_parameters(opt):
+ """
+ Generate a string with the options pretty-printed (used in the --verbose mode).
+ """
+ return str(cg.ParamBlock(opt, ''))
+
+
+def check_string(opt):
+ """
+ Return the calculated CRC sum of a string.
+ """
+ error = False
+ if opt.undefined_crc_parameters:
+ sys.stderr.write("{0:s}: error: undefined parameters\n".format(progname))
+ sys.exit(1)
+ if opt.algorithm == 0:
+ opt.algorithm = opt.algo_bit_by_bit | opt.algo_bit_by_bit_fast | opt.algo_table_driven
+
+ alg = Crc(
+ width=opt.width, poly=opt.poly,
+ reflect_in=opt.reflect_in, xor_in=opt.xor_in,
+ reflect_out=opt.reflect_out, xor_out=opt.xor_out,
+ table_idx_width=opt.tbl_idx_width)
+
+ crc = None
+ if opt.algorithm & opt.algo_bit_by_bit:
+ bbb_crc = alg.bit_by_bit(opt.check_string)
+ if crc != None and bbb_crc != crc:
+ error = True
+ crc = bbb_crc
+ if opt.algorithm & opt.algo_bit_by_bit_fast:
+ bbf_crc = alg.bit_by_bit_fast(opt.check_string)
+ if crc != None and bbf_crc != crc:
+ error = True
+ crc = bbf_crc
+ if opt.algorithm & opt.algo_table_driven:
+ # no point making the python implementation slower by using less than 8 bits as index.
+ opt.tbl_idx_width = 8
+ tbl_crc = alg.table_driven(opt.check_string)
+ if crc != None and tbl_crc != crc:
+ error = True
+ crc = tbl_crc
+
+ if error:
+ sys.stderr.write("{0:s}: error: different checksums!\n".format(progname))
+ if opt.algorithm & opt.algo_bit_by_bit:
+ sys.stderr.write(" bit-by-bit: {0:#x}\n".format(bbb_crc))
+ if opt.algorithm & opt.algo_bit_by_bit_fast:
+ sys.stderr.write(" bit-by-bit-fast: {0:#x}\n".format(bbf_crc))
+ if opt.algorithm & opt.algo_table_driven:
+ sys.stderr.write(" table_driven: {0:#x}\n".format(tbl_crc))
+ sys.exit(1)
+ return crc
+
+
+def check_hexstring(opt):
+ """
+ Return the calculated CRC sum of a hex string.
+ """
+ if opt.undefined_crc_parameters:
+ sys.stderr.write("{0:s}: error: undefined parameters\n".format(progname))
+ sys.exit(1)
+ if len(opt.check_string) % 2 != 0:
+ opt.check_string = "0" + opt.check_string
+ if sys.version_info >= (3, 0):
+ opt.check_string = bytes(opt.check_string, 'utf_8')
+ try:
+ check_str = bytearray(binascii.unhexlify(opt.check_string))
+ except TypeError:
+ sys.stderr.write(
+ "{0:s}: error: invalid hex string {1:s}\n".format(progname, opt.check_string))
+ sys.exit(1)
+
+ opt.check_string = check_str
+ return check_string(opt)
+
+
+def crc_file_update(alg, register, check_bytes):
+ """
+ Update the CRC using the bit-by-bit-fast CRC algorithm.
+ """
+ # If the input data is a string, convert to bytes.
+ if isinstance(check_bytes, str):
+ check_bytes = bytearray(check_bytes, 'utf_8')
+
+ for octet in check_bytes:
+ if alg.reflect_in:
+ octet = alg.reflect(octet, 8)
+ for j in range(8):
+ bit = register & alg.msb_mask
+ register <<= 1
+ if octet & (0x80 >> j):
+ bit ^= alg.msb_mask
+ if bit:
+ register ^= alg.poly
+ register &= alg.mask
+ return register
+
+
+def check_file(opt):
+ """
+ Calculate the CRC of a file.
+ This algorithm uses the table_driven CRC algorithm.
+ """
+ if opt.undefined_crc_parameters:
+ sys.stderr.write("{0:s}: error: undefined parameters\n".format(progname))
+ sys.exit(1)
+ alg = Crc(
+ width=opt.width, poly=opt.poly,
+ reflect_in=opt.reflect_in, xor_in=opt.xor_in,
+ reflect_out=opt.reflect_out, xor_out=opt.xor_out,
+ table_idx_width=opt.tbl_idx_width)
+
+ if not opt.reflect_in:
+ register = opt.xor_in
+ else:
+ register = alg.reflect(opt.xor_in, opt.width)
+
+ try:
+ with open(opt.check_file, 'rb') as f:
+ check_bytes = bytearray(f.read(1024))
+ while check_bytes != b"":
+ register = crc_file_update(alg, register, check_bytes)
+ check_bytes = bytearray(f.read(1024))
+ except IOError:
+ sys.stderr.write(
+ "{0:s}: error: can't open file {1:s}\n".format(progname, opt.check_file))
+ sys.exit(1)
+
+ if opt.reflect_out:
+ register = alg.reflect(register, opt.width)
+ register = register ^ opt.xor_out
+ return register
+
+
+def write_file(filename, out_str):
+ """
+ Write the content of out_str to filename.
+ """
+ try:
+ out_file = open(filename, "w")
+ out_file.write(out_str)
+ out_file.close()
+ except IOError:
+ sys.stderr.write("{0:s}: error: cannot write to file {1:s}\n".format(progname, filename))
+ sys.exit(1)
+
+
+def main():
+ """
+ Main function.
+ """
+ opt = Options(progname, version, url)
+ opt.parse(sys.argv[1:])
+ if opt.verbose:
+ print(print_parameters(opt))
+ if opt.action == opt.action_check_str:
+ crc = check_string(opt)
+ print("{0:#x}".format(crc))
+ if opt.action == opt.action_check_hex_str:
+ crc = check_hexstring(opt)
+ print("{0:#x}".format(crc))
+ if opt.action == opt.action_check_file:
+ crc = check_file(opt)
+ print("{0:#x}".format(crc))
+ if opt.action in set([
+ opt.action_generate_h, opt.action_generate_c, opt.action_generate_c_main,
+ opt.action_generate_table]):
+ if opt.action == opt.action_generate_h:
+ in_str = "$h_template"
+ elif opt.action == opt.action_generate_c:
+ in_str = "$c_template"
+ elif opt.action == opt.action_generate_c_main:
+ in_str = "$c_template\n\n$main_template"
+ elif opt.action == opt.action_generate_table:
+ in_str = "$crc_table_init"
+ else:
+ sys.stderr.write(
+ "{0:s}: error: unknown action. Please file a bug report!\n".format(progname))
+ sys.exit(1)
+ out = str(cg.File(opt, ''))
+ if opt.output_file == None:
+ print(out)
+ else:
+ write_file(opt.output_file, out)
+ return 0
+
+
+if __name__ == "__main__":
+ sys.exit(main())
diff --git a/pycrc/models.py b/pycrc/models.py
new file mode 100644
index 0000000..d12c91c
--- /dev/null
+++ b/pycrc/models.py
@@ -0,0 +1,334 @@
+# pycrc -- parameterisable CRC calculation utility and C source code generator
+#
+# Copyright (c) 2006-2017 Thomas Pircher <tehpeh-web@tty1.net>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+
+"""
+Collection of CRC models. This module contains the CRC models known to pycrc.
+
+To print the parameters of a particular model:
+
+ from pycrc.models import CrcModels
+
+ models = CrcModels()
+ print(", ".join(models.names()))
+ m = models.get_params("crc-32")
+ if m != None:
+ print("Width: {width:d}".format(**m))
+ print("Poly: {poly:#x}".format(**m))
+ print("ReflectIn: {reflect_in}".format(**m))
+ print("XorIn: {xor_in:#x}".format(**m))
+ print("ReflectOut: {reflect_out}".format(**m))
+ print("XorOut: {xor_out:#x}".format(**m))
+ print("Check: {check:#x}".format(**m))
+ else:
+ print("model not found.")
+"""
+
+
+
+class CrcModels(object):
+ """
+ CRC Models.
+
+ All models are defined as constant class variables.
+ """
+
+ models = []
+
+ models.append({
+ 'name': 'crc-5',
+ 'width': 5,
+ 'poly': 0x05,
+ 'reflect_in': True,
+ 'xor_in': 0x1f,
+ 'reflect_out': True,
+ 'xor_out': 0x1f,
+ 'check': 0x19,
+ })
+ models.append({
+ 'name': 'crc-8',
+ 'width': 8,
+ 'poly': 0x07,
+ 'reflect_in': False,
+ 'xor_in': 0x0,
+ 'reflect_out': False,
+ 'xor_out': 0x0,
+ 'check': 0xf4,
+ })
+ models.append({
+ 'name': 'dallas-1-wire',
+ 'width': 8,
+ 'poly': 0x31,
+ 'reflect_in': True,
+ 'xor_in': 0x0,
+ 'reflect_out': True,
+ 'xor_out': 0x0,
+ 'check': 0xa1,
+ })
+ models.append({
+ 'name': 'crc-12-3gpp',
+ 'width': 12,
+ 'poly': 0x80f,
+ 'reflect_in': False,
+ 'xor_in': 0x0,
+ 'reflect_out': True,
+ 'xor_out': 0x0,
+ 'check': 0xdaf,
+ })
+ models.append({
+ 'name': 'crc-15',
+ 'width': 15,
+ 'poly': 0x4599,
+ 'reflect_in': False,
+ 'xor_in': 0x0,
+ 'reflect_out': False,
+ 'xor_out': 0x0,
+ 'check': 0x59e,
+ })
+ models.append({
+ 'name': 'crc-16',
+ 'width': 16,
+ 'poly': 0x8005,
+ 'reflect_in': True,
+ 'xor_in': 0x0,
+ 'reflect_out': True,
+ 'xor_out': 0x0,
+ 'check': 0xbb3d,
+ })
+ models.append({
+ 'name': 'crc-16-usb',
+ 'width': 16,
+ 'poly': 0x8005,
+ 'reflect_in': True,
+ 'xor_in': 0xffff,
+ 'reflect_out': True,
+ 'xor_out': 0xffff,
+ 'check': 0xb4c8,
+ })
+ models.append({
+ 'name': 'crc-16-modbus',
+ 'width': 16,
+ 'poly': 0x8005,
+ 'reflect_in': True,
+ 'xor_in': 0xffff,
+ 'reflect_out': True,
+ 'xor_out': 0x0,
+ 'check': 0x4b37,
+ })
+ models.append({
+ 'name': 'crc-16-genibus',
+ 'width': 16,
+ 'poly': 0x1021,
+ 'reflect_in': False,
+ 'xor_in': 0xffff,
+ 'reflect_out': False,
+ 'xor_out': 0xffff,
+ 'check': 0xd64e,
+ })
+ models.append({
+ 'name': 'crc-16-ccitt',
+ 'width': 16,
+ 'poly': 0x1021,
+ 'reflect_in': False,
+ 'xor_in': 0x1d0f,
+ 'reflect_out': False,
+ 'xor_out': 0x0,
+ 'check': 0xe5cc,
+ })
+ models.append({
+ 'name': 'r-crc-16',
+ 'width': 16,
+ 'poly': 0x0589,
+ 'reflect_in': False,
+ 'xor_in': 0x0,
+ 'reflect_out': False,
+ 'xor_out': 0x0001,
+ 'check': 0x007e,
+ })
+ models.append({
+ 'name': 'kermit',
+ 'width': 16,
+ 'poly': 0x1021,
+ 'reflect_in': True,
+ 'xor_in': 0x0,
+ 'reflect_out': True,
+ 'xor_out': 0x0,
+ 'check': 0x2189,
+ })
+ models.append({
+ 'name': 'x-25',
+ 'width': 16,
+ 'poly': 0x1021,
+ 'reflect_in': True,
+ 'xor_in': 0xffff,
+ 'reflect_out': True,
+ 'xor_out': 0xffff,
+ 'check': 0x906e,
+ })
+ models.append({
+ 'name': 'xmodem',
+ 'width': 16,
+ 'poly': 0x1021,
+ 'reflect_in': False,
+ 'xor_in': 0x0,
+ 'reflect_out': False,
+ 'xor_out': 0x0,
+ 'check': 0x31c3,
+ })
+ models.append({
+ 'name': 'zmodem',
+ 'width': 16,
+ 'poly': 0x1021,
+ 'reflect_in': False,
+ 'xor_in': 0x0,
+ 'reflect_out': False,
+ 'xor_out': 0x0,
+ 'check': 0x31c3,
+ })
+ models.append({
+ 'name': 'crc-24',
+ 'width': 24,
+ 'poly': 0x864cfb,
+ 'reflect_in': False,
+ 'xor_in': 0xb704ce,
+ 'reflect_out': False,
+ 'xor_out': 0x0,
+ 'check': 0x21cf02,
+ })
+ models.append({
+ 'name': 'crc-32',
+ 'width': 32,
+ 'poly': 0x4c11db7,
+ 'reflect_in': True,
+ 'xor_in': 0xffffffff,
+ 'reflect_out': True,
+ 'xor_out': 0xffffffff,
+ 'check': 0xcbf43926,
+ })
+ models.append({
+ 'name': 'crc-32c',
+ 'width': 32,
+ 'poly': 0x1edc6f41,
+ 'reflect_in': True,
+ 'xor_in': 0xffffffff,
+ 'reflect_out': True,
+ 'xor_out': 0xffffffff,
+ 'check': 0xe3069283,
+ })
+ models.append({
+ 'name': 'crc-32-mpeg',
+ 'width': 32,
+ 'poly': 0x4c11db7,
+ 'reflect_in': False,
+ 'xor_in': 0xffffffff,
+ 'reflect_out': False,
+ 'xor_out': 0x0,
+ 'check': 0x0376e6e7,
+ })
+ models.append({
+ 'name': 'crc-32-bzip2',
+ 'width': 32,
+ 'poly': 0x04c11db7,
+ 'reflect_in': False,
+ 'xor_in': 0xffffffff,
+ 'reflect_out': False,
+ 'xor_out': 0xffffffff,
+ 'check': 0xfc891918,
+ })
+ models.append({
+ 'name': 'posix',
+ 'width': 32,
+ 'poly': 0x4c11db7,
+ 'reflect_in': False,
+ 'xor_in': 0x0,
+ 'reflect_out': False,
+ 'xor_out': 0xffffffff,
+ 'check': 0x765e7680,
+ })
+ models.append({
+ 'name': 'jam',
+ 'width': 32,
+ 'poly': 0x4c11db7,
+ 'reflect_in': True,
+ 'xor_in': 0xffffffff,
+ 'reflect_out': True,
+ 'xor_out': 0x0,
+ 'check': 0x340bc6d9,
+ })
+ models.append({
+ 'name': 'xfer',
+ 'width': 32,
+ 'poly': 0x000000af,
+ 'reflect_in': False,
+ 'xor_in': 0x0,
+ 'reflect_out': False,
+ 'xor_out': 0x0,
+ 'check': 0xbd0be338,
+ })
+ models.append({
+ 'name': 'crc-64',
+ 'width': 64,
+ 'poly': 0x000000000000001b,
+ 'reflect_in': True,
+ 'xor_in': 0x0,
+ 'reflect_out': True,
+ 'xor_out': 0x0,
+ 'check': 0x46a5a9388a5beffe,
+ })
+ models.append({
+ 'name': 'crc-64-jones',
+ 'width': 64,
+ 'poly': 0xad93d23594c935a9,
+ 'reflect_in': True,
+ 'xor_in': 0xffffffffffffffff,
+ 'reflect_out': True,
+ 'xor_out': 0x0,
+ 'check': 0xcaa717168609f281,
+ })
+ models.append({
+ 'name': 'crc-64-xz',
+ 'width': 64,
+ 'poly': 0x42f0e1eba9ea3693,
+ 'reflect_in': True,
+ 'xor_in': 0xffffffffffffffff,
+ 'reflect_out': True,
+ 'xor_out': 0xffffffffffffffff,
+ 'check': 0x995dc9bbdf1939fa,
+ })
+
+
+ def names(self):
+ """
+ This function returns the list of supported CRC models.
+ """
+ return [model['name'] for model in self.models]
+
+
+ def get_params(self, model):
+ """
+ This function returns the parameters of a given model.
+ """
+ model = model.lower()
+ for i in self.models:
+ if i['name'] == model:
+ return i
+ return None
diff --git a/pycrc/opt.py b/pycrc/opt.py
new file mode 100644
index 0000000..7868b2e
--- /dev/null
+++ b/pycrc/opt.py
@@ -0,0 +1,484 @@
+# pycrc -- parameterisable CRC calculation utility and C source code generator
+#
+# Copyright (c) 2006-2017 Thomas Pircher <tehpeh-web@tty1.net>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+
+"""
+Option parsing library for pycrc.
+use as follows:
+
+ from pycrc.opt import Options
+
+ opt = Options()
+ opt.parse(sys.argv[1:])
+"""
+
+from optparse import OptionParser, Option, OptionValueError
+from copy import copy
+import sys
+from pycrc.models import CrcModels
+
+
+class Options(object):
+ """
+ The options parsing and validating class.
+ """
+ # pylint: disable=too-many-instance-attributes, too-few-public-methods
+
+ # Bitmap of the algorithms
+ algo_none = 0x00
+ algo_bit_by_bit = 0x01
+ algo_bit_by_bit_fast = 0x02
+ algo_table_driven = 0x08
+
+ action_check_str = 0x01
+ action_check_hex_str = 0x02
+ action_check_file = 0x03
+ action_generate_h = 0x04
+ action_generate_c = 0x05
+ action_generate_c_main = 0x06
+ action_generate_table = 0x07
+
+
+ def __init__(self, progname='pycrc', version=None, url=None):
+ self.program_name = progname
+ self.version = version
+ self.version_str = "{0:s} v{1:s}".format(progname, version)
+ self.web_address = url
+
+ self.width = None
+ self.poly = None
+ self.reflect_in = None
+ self.xor_in = None
+ self.reflect_out = None
+ self.xor_out = None
+ self.tbl_idx_width = 8
+ self.tbl_width = 1 << self.tbl_idx_width
+ self.slice_by = 1
+ self.verbose = False
+ self.check_string = "123456789"
+ self.msb_mask = None
+ self.mask = None
+
+ self.algorithm = self.algo_none
+ self.symbol_prefix = "crc_"
+ self.crc_type = None
+ self.include_files = []
+ self.output_file = None
+ self.action = self.action_check_str
+ self.check_file = None
+ self.c_std = None
+ self.undefined_crc_parameters = False
+
+
+ def parse(self, argv=None):
+ """
+ Parses and validates the options given as arguments
+ """
+ # pylint: disable=too-many-branches, too-many-statements
+
+ usage = """python %prog [OPTIONS]
+
+To calculate the checksum of a string or hexadecimal data:
+ python %prog [model] --check-string "123456789"
+ python %prog [model] --check-hexstring "313233343536373839"
+
+To calculate the checksum of a file:
+ python %prog [model] --check-file filename
+
+To generate the C source code and write it to filename:
+ python %prog [model] --generate c -o filename
+
+The model can be defined either with the --model switch or by specifying each
+of the following parameters:
+ --width --poly --reflect-in --xor-in --reflect-out --xor-out"""
+
+ models = CrcModels()
+ model_list = ", ".join(models.names())
+ parser = OptionParser(option_class=MyOption, usage=usage, version=self.version_str)
+ parser.add_option(
+ "-v", "--verbose",
+ action="store_true", dest="verbose", default=False,
+ help="be more verbose; print the value of the parameters "
+ "and the chosen model to stdout")
+ parser.add_option(
+ "--check-string",
+ action="store", type="string", dest="check_string",
+ help="calculate the checksum of a string (default: '123456789')",
+ metavar="STRING")
+ parser.add_option(
+ "--check-hexstring",
+ action="store", type="string", dest="check_hexstring",
+ help="calculate the checksum of a hexadecimal number string",
+ metavar="STRING")
+ parser.add_option(
+ "--check-file",
+ action="store", type="string", dest="check_file",
+ help="calculate the checksum of a file",
+ metavar="FILE")
+ parser.add_option(
+ "--generate",
+ action="store", type="string", dest="generate", default=None,
+ help="generate C source code; choose the type from {h, c, c-main, table}",
+ metavar="CODE")
+ parser.add_option(
+ "--std",
+ action="store", type="string", dest="c_std", default="C99",
+ help="choose the C dialect of the generated code from {C89, ANSI, C99}",
+ metavar="STD")
+ parser.add_option(
+ "--algorithm",
+ action="store", type="string", dest="algorithm", default="all",
+ help="choose an algorithm from "
+ "{bit-by-bit, bbb, bit-by-bit-fast, bbf, table-driven, tbl, all}",
+ metavar="ALGO")
+ parser.add_option(
+ "--model",
+ action="callback", callback=_model_cb, type="string", dest="model", default=None,
+ help="choose a parameter set from {{{0:s}}}".format(model_list),
+ metavar="MODEL")
+ parser.add_option(
+ "--width",
+ action="store", type="hex", dest="width",
+ help="use NUM bits in the polynomial",
+ metavar="NUM")
+ parser.add_option(
+ "--poly",
+ action="store", type="hex", dest="poly",
+ help="use HEX as polynomial",
+ metavar="HEX")
+ parser.add_option(
+ "--reflect-in",
+ action="store", type="bool", dest="reflect_in",
+ help="reflect the octets in the input message",
+ metavar="BOOL")
+ parser.add_option(
+ "--xor-in",
+ action="store", type="hex", dest="xor_in",
+ help="use HEX as initial value",
+ metavar="HEX")
+ parser.add_option(
+ "--reflect-out",
+ action="store", type="bool", dest="reflect_out",
+ help="reflect the resulting checksum before applying the --xor-out value",
+ metavar="BOOL")
+ parser.add_option(
+ "--xor-out",
+ action="store", type="hex", dest="xor_out",
+ help="xor the final CRC value with HEX",
+ metavar="HEX")
+ parser.add_option(
+ "--slice-by",
+ action="store", type="int", dest="slice_by",
+ help="read NUM bytes at a time from the input. NUM must be one of the values {4, 8, 16}",
+ metavar="NUM")
+ parser.add_option(
+ "--table-idx-width",
+ action="store", type="int", dest="table_idx_width",
+ help="use NUM bits to index the CRC table; NUM must be one of the values {1, 2, 4, 8}",
+ metavar="NUM")
+ parser.add_option(
+ "--force-poly",
+ action="store_true", dest="force_poly", default=False,
+ help="override any errors about possibly unsuitable polynoms")
+ parser.add_option(
+ "--symbol-prefix",
+ action="store", type="string", dest="symbol_prefix",
+ help="when generating source code, use STRING as prefix to the exported C symbols",
+ metavar="STRING")
+ parser.add_option(
+ "--crc-type",
+ action="store", type="string", dest="crc_type",
+ help="when generating source code, use STRING as crc_t type",
+ metavar="STRING")
+ parser.add_option(
+ "--include-file",
+ action="append", type="string", dest="include_files",
+ help="when generating source code, include also FILE as header file; "
+ "can be specified multiple times",
+ metavar="FILE")
+ parser.add_option(
+ "-o", "--output",
+ action="store", type="string", dest="output_file",
+ help="write the generated code to file instead to stdout",
+ metavar="FILE")
+
+ (options, args) = parser.parse_args(argv)
+
+ if options.c_std != None:
+ std = options.c_std.upper()
+ if std == "ANSI" or std == "C89":
+ self.c_std = "C89"
+ elif std == "C99":
+ self.c_std = std
+ else:
+ self.__error("unknown C standard {0:s}".format(options.c_std))
+
+ undefined_params = []
+ if options.width != None:
+ self.width = options.width
+ else:
+ undefined_params.append("--width")
+ if options.poly != None:
+ self.poly = options.poly
+ else:
+ undefined_params.append("--poly")
+ if options.reflect_in != None:
+ self.reflect_in = options.reflect_in
+ else:
+ undefined_params.append("--reflect-in")
+ if options.xor_in != None:
+ self.xor_in = options.xor_in
+ else:
+ undefined_params.append("--xor-in")
+ if options.reflect_out != None:
+ self.reflect_out = options.reflect_out
+ else:
+ undefined_params.append("--reflect-out")
+ if options.xor_out != None:
+ self.xor_out = options.xor_out
+ else:
+ undefined_params.append("--xor-out")
+
+ if options.table_idx_width != None:
+ if options.table_idx_width in set((1, 2, 4, 8)):
+ self.tbl_idx_width = options.table_idx_width
+ self.tbl_width = 1 << options.table_idx_width
+ else:
+ self.__error("unsupported table-idx-width {0:d}".format(options.table_idx_width))
+
+ if self.poly != None and self.poly % 2 == 0 and not options.force_poly:
+ self.__error("even polinomials are not allowed by default. Use --force-poly to override this.")
+
+ if self.width != None:
+ if self.width <= 0:
+ self.__error("Width must be strictly positive")
+ self.msb_mask = 0x1 << (self.width - 1)
+ self.mask = ((self.msb_mask - 1) << 1) | 1
+ if self.poly != None and self.poly >> (self.width + 1) != 0 and not options.force_poly:
+ self.__error("the polynomial is wider than the supplied Width. Use --force-poly to override this.")
+ if self.poly != None:
+ self.poly = self.poly & self.mask
+ if self.xor_in != None:
+ self.xor_in = self.xor_in & self.mask
+ if self.xor_out != None:
+ self.xor_out = self.xor_out & self.mask
+ else:
+ self.msb_mask = None
+ self.mask = None
+
+ if self.width == None or \
+ self.poly == None or \
+ self.reflect_in == None or \
+ self.xor_in == None or \
+ self.reflect_out == None or \
+ self.xor_out == None:
+ self.undefined_crc_parameters = True
+ else:
+ self.undefined_crc_parameters = False
+
+ if options.slice_by != None:
+ if options.slice_by in set((4, 8, 16)):
+ self.slice_by = options.slice_by
+ else:
+ self.__error("unsupported slice-by {0:d}".format(options.slice_by))
+ if self.undefined_crc_parameters:
+ self.__error("slice-by is only implemented for fully defined models")
+ if self.tbl_idx_width != 8:
+ self.__error("slice-by is only implemented for table-idx-width=8")
+ # FIXME tp: Fix corner cases and disable the following tests
+ if self.width < 8:
+ self.__warning("disabling slice-by for width {0}".format(self.width))
+ self.slice_by = 1
+ if self.width < 16:
+ self.__warning("disabling slice-by for width {0}".format(self.width))
+ self.slice_by = 1
+ if self.width > 32:
+ self.__warning("disabling slice-by for width {0}".format(self.width))
+ self.slice_by = 1
+ if not self.reflect_in:
+ self.__warning("disabling slice-by for non-reflected algorithm")
+ self.slice_by = 1
+# FIXME tp: reintroduce this?
+# if self.width % 8 != 0:
+# self.__error("slice-by is only implemented for width multiples of 8")
+# if options.slice_by < self.width / 8:
+# self.__error("slice-by must be greater or equal width / 8")
+ if self.c_std == "C89":
+ self.__error("--slice-by not supported for C89")
+
+ if options.algorithm != None:
+ alg = options.algorithm.lower()
+ if alg in set(["bit-by-bit", "bbb", "all"]):
+ self.algorithm |= self.algo_bit_by_bit
+ if alg in set(["bit-by-bit-fast", "bbf", "all"]):
+ self.algorithm |= self.algo_bit_by_bit_fast
+ if alg in set(["table-driven", "tbl", "all"]):
+ self.algorithm |= self.algo_table_driven
+ if self.algorithm == 0:
+ self.__error("unknown algorithm {0:s}".format(options.algorithm))
+
+ if options.symbol_prefix != None:
+ self.symbol_prefix = options.symbol_prefix
+ if options.include_files != None:
+ self.include_files = options.include_files
+ if options.crc_type != None:
+ self.crc_type = options.crc_type
+ if options.output_file != None:
+ self.output_file = options.output_file
+ op_count = 0
+ if options.check_string != None:
+ self.action = self.action_check_str
+ self.check_string = options.check_string
+ op_count += 1
+ if options.check_hexstring != None:
+ self.action = self.action_check_hex_str
+ self.check_string = options.check_hexstring
+ op_count += 1
+ if options.check_file != None:
+ self.action = self.action_check_file
+ self.check_file = options.check_file
+ op_count += 1
+ if options.generate != None:
+ arg = options.generate.lower()
+ if arg == 'h':
+ self.action = self.action_generate_h
+ elif arg == 'c':
+ self.action = self.action_generate_c
+ elif arg == 'c-main':
+ self.action = self.action_generate_c_main
+ elif arg == 'table':
+ self.action = self.action_generate_table
+ else:
+ self.__error("don't know how to generate {0:s}".format(options.generate))
+ op_count += 1
+
+ if self.action == self.action_generate_table:
+ if self.algorithm & self.algo_table_driven == 0:
+ self.__error("the --generate table option is incompatible "
+ "with the --algorithm option")
+ self.algorithm = self.algo_table_driven
+ elif self.algorithm not in set(
+ [self.algo_bit_by_bit, self.algo_bit_by_bit_fast, self.algo_table_driven]):
+ self.__error("select an algorithm to be used in the generated file")
+ else:
+ if self.tbl_idx_width != 8:
+ self.__warning("reverting to Table Index Width = 8 "
+ "for internal CRC calculation")
+ self.tbl_idx_width = 8
+ self.tbl_width = 1 << options.table_idx_width
+ if op_count == 0:
+ self.action = self.action_check_str
+ if op_count > 1:
+ self.__error("too many actions specified")
+
+ if len(args) != 0:
+ self.__error("unrecognized argument(s): {0:s}".format(" ".join(args)))
+
+ def_params_acts = (self.action_check_str, self.action_check_hex_str,
+ self.action_check_file, self.action_generate_table)
+ if self.undefined_crc_parameters and self.action in set(def_params_acts):
+ self.__error("undefined parameters: Add {0:s} or use --model"
+ .format(", ".join(undefined_params)))
+ self.verbose = options.verbose
+
+
+
+ def __warning(self, message):
+ """
+ Print a warning message to stderr.
+ """
+ sys.stderr.write(
+ "{0:s}: warning: {1:s}\n".format(self.program_name, message))
+
+
+
+ def __error(self, message):
+ """
+ Print a error message to stderr and terminate the program.
+ """
+ sys.stderr.write(
+ "{0:s}: error: {1:s}\n".format(self.program_name, message))
+ sys.exit(1)
+
+
+def _model_cb(option, opt_str, value, parser):
+ """
+ This function sets up the single parameters if the 'model' option has been selected
+ by the user.
+ """
+ model_name = value.lower()
+ models = CrcModels()
+ model = models.get_params(model_name)
+ if model != None:
+ setattr(parser.values, 'width', model['width'])
+ setattr(parser.values, 'poly', model['poly'])
+ setattr(parser.values, 'reflect_in', model['reflect_in'])
+ setattr(parser.values, 'xor_in', model['xor_in'])
+ setattr(parser.values, 'reflect_out', model['reflect_out'])
+ setattr(parser.values, 'xor_out', model['xor_out'])
+ else:
+ models = CrcModels()
+ model_list = ", ".join(models.names())
+ raise OptionValueError(
+ "unsupported model {0:s}. Supported models are: {1:s}."
+ .format(value, model_list))
+
+
+def _check_hex(dummy_option, opt, value):
+ """
+ Checks if a value is given in a decimal integer of hexadecimal reppresentation.
+ Returns the converted value or rises an exception on error.
+ """
+ try:
+ if value.lower().startswith("0x"):
+ return int(value, 16)
+ else:
+ return int(value)
+ except ValueError:
+ raise OptionValueError(
+ "option {0:s}: invalid integer or hexadecimal value: {1:s}.".format(opt, value))
+
+
+def _check_bool(dummy_option, opt, value):
+ """
+ Checks if a value is given as a boolean value (either 0 or 1 or "true" or "false")
+ Returns the converted value or rises an exception on error.
+ """
+ if value.isdigit():
+ return int(value, 10) != 0
+ elif value.lower() == "false":
+ return False
+ elif value.lower() == "true":
+ return True
+ else:
+ raise OptionValueError("option {0:s}: invalid boolean value: {1:s}.".format(opt, value))
+
+
+class MyOption(Option):
+ """
+ New option parsing class extends the Option class
+ """
+ TYPES = Option.TYPES + ("hex", "bool")
+ TYPE_CHECKER = copy(Option.TYPE_CHECKER)
+ TYPE_CHECKER["hex"] = _check_hex
+ TYPE_CHECKER["bool"] = _check_bool
+
diff --git a/pycrc/symtable.py b/pycrc/symtable.py
new file mode 100644
index 0000000..e46ab9c
--- /dev/null
+++ b/pycrc/symtable.py
@@ -0,0 +1,352 @@
+# pycrc -- parameterisable CRC calculation utility and C source code generator
+#
+# Copyright (c) 2006-2017 Thomas Pircher <tehpeh-web@tty1.net>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+
+"""
+Symbol table for the macro processor used by pycrc.
+use as follows:
+
+ import pycrc.opt as opt
+ import pycrc.symtable as sym
+
+ opt = opt.Options()
+ sym = sym.SymbolTable(opt)
+
+ print(sym['crc_width'])
+ print('width: {crc_width}, poly: {crc_poly}'.format(**sym))
+"""
+
+from pycrc.algorithms import Crc
+import collections
+import time
+import os
+
+
+class SymbolTable(object):
+ def __init__(self, opt):
+ self.opt = opt
+
+
+class SymbolTable(collections.MutableMapping):
+ """A dictionary that applies an arbitrary key-altering
+ function before accessing the keys"""
+
+ def __init__(self, opt):
+ self.opt = opt
+ self.tbl_shift = _tbl_shift(opt)
+ self.cache = dict()
+ self.generator = dict({
+ 'datetime': lambda: time.asctime(),
+ 'program_version': lambda: self.opt.version_str,
+ 'program_url': lambda: self.opt.web_address,
+ 'filename': lambda: 'pycrc_stdout' if self.opt.output_file is None else os.path.basename(self.opt.output_file),
+ 'header_filename': lambda: _pretty_header_filename(self.opt.output_file),
+ 'header_protection': lambda: _pretty_hdrprotection(self.opt),
+
+ 'crc_algorithm': lambda: _pretty_algorithm(self.opt),
+ 'crc_width': lambda: _pretty_str(self.opt.width),
+ 'crc_poly': lambda: _pretty_hex(self.opt.poly, self.opt.width),
+ 'crc_reflect_in': lambda: _pretty_bool(self.opt.reflect_in),
+ 'crc_xor_in': lambda: _pretty_hex(self.opt.xor_in, self.opt.width),
+ 'crc_reflect_out': lambda: _pretty_bool(self.opt.reflect_out),
+ 'crc_xor_out': lambda: _pretty_hex(self.opt.xor_out, self.opt.width),
+ 'crc_slice_by': lambda: _pretty_str(self.opt.slice_by),
+ 'crc_table_idx_width': lambda: str(self.opt.tbl_idx_width),
+ 'crc_table_width': lambda: _pretty_str(1 << self.opt.tbl_idx_width),
+ 'crc_table_mask': lambda: _pretty_hex(self.opt.tbl_width - 1, 8),
+ 'crc_mask': lambda: _pretty_hex(self.opt.mask, self.opt.width),
+ 'crc_msb_mask': lambda: _pretty_hex(self.opt.msb_mask, self.opt.width),
+ 'crc_shift': lambda: _pretty_str(self.tbl_shift),
+
+ 'cfg_width': lambda: self.__getitem__('crc_width') if self.opt.width is not None else 'cfg->width',
+ 'cfg_poly': lambda: self.__getitem__('crc_poly') if self.opt.poly is not None else 'cfg->poly',
+ 'cfg_reflect_in': lambda: self.__getitem__('crc_reflect_in') if self.opt.reflect_in is not None else 'cfg->reflect_in',
+ 'cfg_xor_in': lambda: self.__getitem__('crc_xor_in') if self.opt.xor_in is not None else 'cfg->xor_in',
+ 'cfg_reflect_out': lambda: self.__getitem__('crc_reflect_out') if self.opt.reflect_out is not None else 'cfg->reflect_out',
+ 'cfg_xor_out': lambda: self.__getitem__('crc_xor_out') if self.opt.xor_out is not None else 'cfg->xor_out',
+ 'cfg_table_idx_width': lambda: self.__getitem__('crc_table_idx_width') if self.opt.tbl_idx_width is not None else 'cfg->table_idx_width',
+ 'cfg_table_width': lambda: self.__getitem__('crc_table_width') if self.opt.tbl_width is not None else 'cfg->table_width',
+ 'cfg_mask': lambda: self.__getitem__('crc_mask') if self.opt.mask is not None else 'cfg->crc_mask',
+ 'cfg_msb_mask': lambda: self.__getitem__('crc_msb_mask') if self.opt.msb_mask is not None else 'cfg->msb_mask',
+ 'cfg_shift': lambda: self.__getitem__('crc_shift') if self.tbl_shift is not None else 'cfg->crc_shift',
+ 'cfg_poly_shifted': lambda: '('+self.__getitem__('cfg_poly')+' << '+self.__getitem__('cfg_shift')+')' if self.tbl_shift is None or self.tbl_shift > 0 else self.__getitem__('cfg_poly'),
+ 'cfg_mask_shifted': lambda: '('+self.__getitem__('cfg_mask')+' << '+self.__getitem__('cfg_shift')+')' if self.tbl_shift is None or self.tbl_shift > 0 else self.__getitem__('cfg_mask'),
+ 'cfg_msb_mask_shifted': lambda: '('+self.__getitem__('cfg_msb_mask')+' << '+self.__getitem__('cfg_shift')+')' if self.tbl_shift is None or self.tbl_shift > 0 else self.__getitem__('cfg_msb_mask'),
+
+ 'c_bool': lambda: 'int' if self.opt.c_std == 'C89' else 'bool',
+ 'c_true': lambda: '1' if self.opt.c_std == 'C89' else 'true',
+ 'c_false': lambda: '0' if self.opt.c_std == 'C89' else 'false',
+
+ 'underlying_crc_t': lambda: _get_underlying_crc_t(self.opt),
+ 'crc_t': lambda: self.opt.symbol_prefix + 't',
+ 'cfg_t': lambda: self.opt.symbol_prefix + 'cfg_t',
+ 'crc_reflect_function': lambda: self.opt.symbol_prefix + 'reflect',
+ 'crc_table_gen_function': lambda: self.opt.symbol_prefix + 'table_gen',
+ 'crc_init_function': lambda: self.opt.symbol_prefix + 'init',
+ 'crc_update_function': lambda: self.opt.symbol_prefix + 'update',
+ 'crc_finalize_function': lambda: self.opt.symbol_prefix + 'finalize',
+
+ 'crc_init_value': lambda: _get_init_value(self.opt),
+ 'crc_table_init': lambda: _get_table_init(self.opt),
+ })
+
+ def __getitem__(self, key):
+ """
+ Return the value for the requested key
+ """
+ if key in self.cache:
+ return self.cache[key]
+ if key not in self.generator:
+ raise KeyError(key)
+ generator = self.generator[key]
+ val = self.generator[key]()
+ self.cache[key] = val
+ return val
+
+ def __setitem__(self, key, value):
+ self.generator[key] = value
+
+ def __delitem__(self, key):
+ del self.generator[key]
+
+ def __iter__(self):
+ return iter(self.generator)
+
+ def __len__(self):
+ return len(self.generator)
+
+
+
+def _pretty_str(value):
+ """
+ Return a value of width bits as a pretty string.
+ """
+ if value is None:
+ return 'Undefined'
+ return str(value)
+
+
+def _pretty_hex(value, width=None):
+ """
+ Return a value of width bits as a pretty hexadecimal formatted string.
+ """
+ if value is None:
+ return 'Undefined'
+ if width is None:
+ return '{0:#x}'.format(value)
+ width = (width + 3) // 4
+ hex_str = "{{0:#0{0:d}x}}".format(width + 2)
+ return hex_str.format(value)
+
+
+def _pretty_bool(value):
+ """
+ Return a boolen value of width bits as a pretty formatted string.
+ """
+ if value is None:
+ return 'Undefined'
+ return 'True' if value else 'False'
+
+
+def _pretty_algorithm(opt):
+ """
+ Return the algorithm name.
+ """
+ if opt.algorithm == opt.algo_bit_by_bit:
+ return 'bit-by-bit'
+ elif opt.algorithm == opt.algo_bit_by_bit_fast:
+ return 'bit-by-bit-fast'
+ elif opt.algorithm == opt.algo_table_driven:
+ return 'table-driven'
+ else:
+ return 'UNDEFINED'
+
+def _pretty_header_filename(filename):
+ """
+ Return the sanitized filename of a header file.
+ """
+ if filename is None:
+ return 'pycrc_stdout.h'
+ filename = os.path.basename(filename)
+ if filename[-2:] == '.c':
+ return filename[0:-1] + 'h'
+ else:
+ return filename + '.h'
+
+
+def _pretty_hdrprotection(opt):
+ """
+ Return the name of a C header protection (e.g. CRC_IMPLEMENTATION_H).
+ """
+ if opt.output_file is None:
+ filename = 'pycrc_stdout'
+ else:
+ filename = os.path.basename(opt.output_file)
+ out_str = ''.join([s.upper() if s.isalnum() else '_' for s in filename])
+ return out_str
+
+
+def _get_underlying_crc_t(opt):
+ """
+ Return the C type of the crc_t typedef.
+ """
+ # pylint: disable=too-many-return-statements, too-many-branches
+
+ if opt.crc_type is not None:
+ return opt.crc_type
+ if opt.c_std == 'C89':
+ if opt.width is None:
+ return 'unsigned long int'
+ if opt.width <= 8:
+ return 'unsigned char'
+ elif opt.width <= 16:
+ return 'unsigned int'
+ else:
+ return 'unsigned long int'
+ else: # C99
+ if opt.width is None:
+ return 'unsigned long long int'
+ if opt.width <= 8:
+ return 'uint_fast8_t'
+ elif opt.width <= 16:
+ return 'uint_fast16_t'
+ elif opt.width <= 32:
+ return 'uint_fast32_t'
+ elif opt.width <= 64:
+ return 'uint_fast64_t'
+ elif opt.width <= 128:
+ return 'uint_fast128_t'
+ else:
+ return 'uintmax_t'
+
+
+def _get_init_value(opt):
+ """
+ Return the init value of a C implementation, according to the selected
+ algorithm and to the given options.
+ If no default option is given for a given parameter, value in the cfg_t
+ structure must be used.
+ """
+ if opt.algorithm == opt.algo_bit_by_bit:
+ if opt.xor_in is None or opt.width is None or opt.poly is None:
+ return None
+ crc = Crc(
+ width=opt.width, poly=opt.poly,
+ reflect_in=opt.reflect_in, xor_in=opt.xor_in,
+ reflect_out=opt.reflect_out, xor_out=opt.xor_out,
+ table_idx_width=opt.tbl_idx_width)
+ init = crc.nondirect_init
+ elif opt.algorithm == opt.algo_bit_by_bit_fast:
+ if opt.xor_in is None:
+ return None
+ init = opt.xor_in
+ elif opt.algorithm == opt.algo_table_driven:
+ if opt.reflect_in is None or opt.xor_in is None or opt.width is None:
+ return None
+ if opt.poly is None:
+ poly = 0
+ else:
+ poly = opt.poly
+ crc = Crc(
+ width=opt.width, poly=poly,
+ reflect_in=opt.reflect_in, xor_in=opt.xor_in,
+ reflect_out=opt.reflect_out, xor_out=opt.xor_out,
+ table_idx_width=opt.tbl_idx_width)
+ if opt.reflect_in:
+ init = crc.reflect(crc.direct_init, opt.width)
+ else:
+ init = crc.direct_init
+ else:
+ init = 0
+ return _pretty_hex(init, opt.width)
+
+
+def _get_simple_table(opt, crc_tbl, values_per_line, format_width, indent):
+ """
+ Get one CRC table, formatted as string with appropriate indenting and
+ line breaks.
+ """
+ out = ""
+ for i in range(opt.tbl_width):
+ if i % values_per_line == 0:
+ out += " " * indent
+ tbl_val = _pretty_hex(crc_tbl[i], format_width)
+ if i == (opt.tbl_width - 1):
+ out += "{0:s}".format(tbl_val)
+ elif i % values_per_line == (values_per_line - 1):
+ out += "{0:s},\n".format(tbl_val)
+ else:
+ out += "{0:s}, ".format(tbl_val)
+ return out
+
+
+def _get_table_init(opt): # TODO: change to return a list
+ """
+ Return the precalculated CRC table for the table_driven implementation.
+ """
+ if opt.algorithm != opt.algo_table_driven:
+ return "0"
+ if opt.width is None or opt.poly is None or opt.reflect_in is None:
+ return "0"
+ crc = Crc(
+ width=opt.width, poly=opt.poly,
+ reflect_in=opt.reflect_in,
+ xor_in=0, reflect_out=False, xor_out=0, # set unimportant variables to known values
+ table_idx_width=opt.tbl_idx_width,
+ slice_by=opt.slice_by)
+ crc_tbl = crc.gen_table()
+ if opt.width > 32:
+ values_per_line = 4
+ elif opt.width >= 16:
+ values_per_line = 8
+ else:
+ values_per_line = 16
+ format_width = max(opt.width, 8)
+ if opt.slice_by == 1:
+ indent = 4
+ else:
+ indent = 8
+
+ out = [''] * opt.slice_by
+ for i in range(opt.slice_by):
+ out[i] = _get_simple_table(opt, crc_tbl[i], values_per_line, format_width, indent)
+ fixed_indent = ' ' * (indent - 4)
+ out = '{0:s}{{\n'.format(fixed_indent) + \
+ '\n{0:s}}},\n{0:s}{{\n'.format(fixed_indent).join(out) + \
+ '\n{0:s}}}'.format(fixed_indent)
+ if opt.slice_by == 1:
+ return out
+ return '{\n' + out + '\n}'
+
+
+def _tbl_shift(opt):
+ """
+ Return the table shift value
+ """
+ if opt.algorithm == opt.algo_table_driven and (opt.width is None or opt.width < 8):
+ if opt.width is None:
+ return None
+ else:
+ return 8 - opt.width
+ else:
+ return 0
+
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000..7d270ae
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,12 @@
+from distutils.core import setup
+
+from pycrc import progname, version, url
+
+setup(name = 'pycrc',
+ version = version,
+ description = 'Free, easy to use Cyclic Redundancy Check source code generator for C/C++',
+ author = 'Thomas Pircher',
+ author_email = 'tehpeh-web@tty1.net',
+ url = url,
+ packages = ['pycrc'],
+ )
diff --git a/test/check_files.sh b/test/check_files.sh
new file mode 100755
index 0000000..4cc874f
--- /dev/null
+++ b/test/check_files.sh
@@ -0,0 +1,116 @@
+#!/bin/sh
+set -e
+
+PYCRC=`dirname $0`/../pycrc.py
+outdir_old="/tmp/pycrc_out"
+outdir_new="/tmp/pycrc_new"
+tarfile="pycrc_files.tar.gz"
+
+usage() {
+ echo >&2 "usage: $0 [OPTIONS]"
+ echo >&2 ""
+ echo >&2 "with OPTIONS in"
+ echo >&2 " -c check the generated output"
+ echo >&2 " -g generate the database"
+ echo >&2 " -n no cleanup: don't delete the directories with the generated code"
+ echo >&2 " -h this help message"
+}
+
+
+opt_check=off
+opt_no_cleanup=off
+opt_generate=off
+
+while getopts cgnh opt; do
+ case "$opt" in
+ c) opt_check=on;;
+ g) opt_generate=on;;
+ n) opt_no_cleanup=on;;
+ h) usage
+ exit 0
+ ;;
+ \?) usage # unknown flag
+ exit 1
+ ;;
+ esac
+done
+shift `expr $OPTIND - 1`
+
+if [ -e "$outdir_old" ]; then
+ echo >&2 "Output directory $outdir_old exists!"
+ exit 1
+fi
+if [ -e "$outdir_new" ]; then
+ echo >&2 "Output directory $outdir_new exists!"
+ exit 1
+fi
+
+
+cleanup() {
+ if [ "$opt_no_cleanup" = "on" ]; then
+ echo "No cleanup. Please delete $outdir_old and $outdir_new when you're done"
+ else
+ rm -rf "$outdir_old" "$outdir_new"
+ fi
+}
+
+trap cleanup 0 1 2 3 15
+
+
+generate() {
+ outfile="$1"
+ shift
+ $PYCRC "$@" -o "${outfile}"
+ sed -i -e 's/Generated on ... ... .. ..:..:.. ..../Generated on XXX XXX XX XX:XX:XX XXXX/; s/by pycrc v[0-9.]*/by pycrc vXXX/;' "${outfile}"
+}
+
+populate() {
+ outdir=$1
+ mkdir -p "$outdir"
+ models=`PYTHONPATH=.. python -c 'import pycrc.models as m; print(" ".join(m.CrcModels().names()))'`
+ for model in "undefined" $models; do
+ for algo in "bbb" "bbf" "tbl"; do
+ for cstd in c98 c99; do
+ if [ "$model" = "undefined" ]; then
+ mod_opt=
+ else
+ mod_opt="--model=${model}"
+ fi
+ generate "${outdir}/${model}_${algo}_${cstd}.h" --generate=h --algorithm=${algo} $mod_opt
+ generate "${outdir}/${model}_${algo}_${cstd}.c" --generate=c --algorithm=${algo} $mod_opt
+ done
+ done
+ done
+
+ algo=tbl
+ for model in crc-32; do
+ for slice in 4 8 16; do
+ for cstd in c98 c99; do
+ generate "${outdir}/${model}_${algo}_sb${slice}_${cstd}.h" --generate=h --algorithm=${algo} --model=${model} --slice-by ${slice}
+ generate "${outdir}/${model}_${algo}_sb${slice}_${cstd}.c" --generate=c --algorithm=${algo} --model=${model} --slice-by ${slice}
+ done
+ done
+ done
+}
+
+do_check() {
+ tar xzf "$tarfile" -C "`dirname $outdir_new`"
+ populate "$outdir_new"
+ diff -ru "$outdir_old" "$outdir_new"
+}
+
+
+if [ "$opt_check" = "on" ]; then
+ if [ ! -f "$tarfile" ]; then
+ echo >&2 "Can't find tarfile $tarfile"
+ exit 1
+ fi
+ do_check
+fi
+
+if [ "$opt_generate" = "on" ]; then
+ populate "$outdir_old"
+ dirname="`dirname $outdir_old`"
+ basename="`basename $outdir_old`"
+ tar czf "$tarfile" -C "$dirname" "$basename"
+fi
diff --git a/test/main.c b/test/main.c
new file mode 100644
index 0000000..252d4fd
--- /dev/null
+++ b/test/main.c
@@ -0,0 +1,283 @@
+// Copyright (c) 2006-2013 Thomas Pircher <tehpeh-web@tty1.net>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "crc.h"
+#include <getopt.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <stdbool.h>
+#include <string.h>
+
+static bool atob(const char *str);
+static crc_t xtoi(const char *str);
+static int get_config(int argc, char *argv[], crc_cfg_t *cfg);
+#if CRC_ALGO_BIT_BY_BIT
+static crc_t crc_verify(const crc_cfg_t *cfg, crc_t crc_pre_final, crc_t crc);
+static crc_t crc_reflect(crc_t data, size_t data_len);
+#endif
+
+
+
+static bool verbose = false;
+static unsigned char str[256] = "123456789";
+
+bool atob(const char *str)
+{
+ if (!str) {
+ return 0;
+ }
+ if (isdigit(str[0])) {
+ return (bool)atoi(str);
+ }
+ if (tolower(str[0]) == 't') {
+ return true;
+ }
+ return false;
+}
+
+crc_t xtoi(const char *str)
+{
+ crc_t ret = 0;
+
+ if (!str) {
+ return 0;
+ }
+ if (str[0] == '0' && tolower(str[1]) == 'x') {
+ str += 2;
+ while (*str) {
+ if (isdigit(*str))
+ ret = 16 * ret + *str - '0';
+ else if (isxdigit(*str))
+ ret = 16 * ret + tolower(*str) - 'a' + 10;
+ else
+ return ret;
+ str++;
+ }
+ } else if (isdigit(*str)) {
+ while (*str) {
+ if (isdigit(*str))
+ ret = 10 * ret + *str - '0';
+ else
+ return ret;
+ str++;
+ }
+ }
+ return ret;
+}
+
+
+int get_config(int argc, char *argv[], crc_cfg_t *cfg)
+{
+ int c;
+ int option_index;
+ static struct option long_options[] = {
+ {"width", 1, 0, 'w'},
+ {"poly", 1, 0, 'p'},
+ {"reflect-in", 1, 0, 'n'},
+ {"xor-in", 1, 0, 'i'},
+ {"reflect-out", 1, 0, 'u'},
+ {"xor-out", 1, 0, 'o'},
+ {"verbose", 0, 0, 'v'},
+ {"check-string", 1, 0, 's'},
+ {"table-idx-with", 1, 0, 't'},
+ {0, 0, 0, 0}
+ };
+
+ while (1) {
+ option_index = 0;
+
+ c = getopt_long(argc, argv, "w:p:ni:uo:v", long_options, &option_index);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 0:
+ printf("option %s", long_options[option_index].name);
+ if (optarg)
+ printf(" with arg %s", optarg);
+ printf ("\n");
+ case 'w':
+ cfg->width = atoi(optarg);
+ break;
+ case 'p':
+ cfg->poly = xtoi(optarg);
+ break;
+ case 'n':
+ cfg->reflect_in = atob(optarg);
+ break;
+ case 'i':
+ cfg->xor_in = xtoi(optarg);
+ break;
+ case 'u':
+ cfg->reflect_out = atob(optarg);
+ break;
+ case 'o':
+ cfg->xor_out = xtoi(optarg);
+ break;
+ case 's':
+ memcpy(str, optarg, strlen(optarg) < sizeof(str) ? strlen(optarg) + 1 : sizeof(str));
+ str[sizeof(str) - 1] = '\0';
+ break;
+ case 'v':
+ verbose = true;
+ break;
+ case 't':
+ // ignore --table_idx_width option
+ break;
+ case '?':
+ return -1;
+ case ':':
+ fprintf(stderr, "missing argument to option %c\n", c);
+ return -1;
+ default:
+ fprintf(stderr, "unhandled option %c\n", c);
+ return -1;
+ }
+ }
+ cfg->msb_mask = (crc_t)1u << (cfg->width - 1);
+ cfg->crc_mask = (cfg->msb_mask - 1) | cfg->msb_mask;
+ cfg->crc_shift = cfg->width < 8 ? 8 - cfg->width : 0;
+
+ cfg->poly &= cfg->crc_mask;
+ cfg->xor_in &= cfg->crc_mask;
+ cfg->xor_out &= cfg->crc_mask;
+ return 0;
+}
+
+
+#if CRC_ALGO_BIT_BY_BIT
+crc_t crc_verify(const crc_cfg_t *cfg, crc_t crc_pre_final, crc_t crc)
+{
+ crc_t result;
+ unsigned char data;
+ unsigned int i;
+
+ // don't verify if the width is not a multiple of 8
+ if (cfg->width % 8) {
+ return 0;
+ }
+ if (cfg->xor_out) {
+ crc ^= cfg->xor_out;
+ }
+ if (cfg->reflect_out) {
+ crc = crc_reflect(crc, cfg->width);
+ }
+ result = crc_pre_final;
+ for (i = 0; i < cfg->width / 8; i++) {
+ data = (crc >> (cfg->width - 8 * i - 8)) & 0xff;
+ if (cfg->reflect_in) {
+ data = crc_reflect(data, 8);
+ }
+ result = crc_update(cfg, result, &data, 1);
+ }
+ // no crc_finalize, because if the CRC calculation is correct, result == 0.
+ // A crc_finalize would XOR-in again some ones into the solution.
+ // In theory the finalize function of the bit-by-bit algorithm
+ // would also loop over cfg->width zero bits, but since
+ // a) result == 0, and
+ // b) input data == 0
+ // the output would always be zero
+ return result;
+}
+
+crc_t crc_reflect(crc_t data, size_t data_len)
+{
+ unsigned int i;
+ crc_t ret;
+
+ ret = 0;
+ for (i = 0; i < data_len; i++)
+ {
+ if (data & 0x01) {
+ ret = (ret << 1) | 1;
+ } else {
+ ret = ret << 1;
+ }
+ data >>= 1;
+ }
+ return ret;
+}
+#endif // CRC_ALGO_BIT_BY_BIT
+
+
+int main(int argc, char *argv[])
+{
+ crc_cfg_t cfg = {
+ 0, // width
+ 0, // poly
+ 0, // xor_in
+ 0, // reflect_in
+ 0, // xor_out
+ 0, // reflect_out
+
+ 0, // crc_mask
+ 0, // msb_mask
+ 0, // crc_shift
+ };
+ crc_t crc;
+ crc_t crc_test, crc_pre_final;
+ char format[20];
+ int ret, i;
+
+ ret = get_config(argc, argv, &cfg);
+ if (ret == 0) {
+# if CRC_ALGO_TABLE_DRIVEN
+ crc_table_gen(&cfg);
+# endif // CRC_ALGO_TABLE_DRIVEN
+ crc = crc_init(&cfg);
+ crc = crc_pre_final = crc_update(&cfg, crc, str, strlen((char *)str));
+ crc = crc_finalize(&cfg, crc);
+
+# if CRC_ALGO_BIT_BY_BIT
+ if (crc_verify(&cfg, crc_pre_final, crc) != 0) {
+ fprintf(stderr, "error: crc verification failed\n");
+ return 1;
+ }
+# endif
+
+ // calculate the checksum again, but this time loop over the input
+ // bytes one-by-one.
+ crc_test = crc_init(&cfg);
+ for (i = 0; str[i]; i++)
+ {
+ crc_test = crc_update(&cfg, crc_test, str + i, 1);
+ }
+ crc_test = crc_finalize(&cfg, crc_test);
+ if (crc_test != crc) {
+ fprintf(stderr, "error: crc loop verification failed\n");
+ return 1;
+ }
+
+ if (verbose) {
+ snprintf(format, sizeof(format), "%%-16s = 0x%%0%dx\n", (unsigned int)(cfg.width + 3) / 4);
+ printf("%-16s = %d\n", "width", (unsigned int)cfg.width);
+ printf(format, "poly", (unsigned int)cfg.poly);
+ printf("%-16s = %s\n", "reflect_in", cfg.reflect_in ? "true": "false");
+ printf(format, "xor_in", cfg.xor_in);
+ printf("%-16s = %s\n", "reflect_out", cfg.reflect_out ? "true": "false");
+ printf(format, "xor_out", (unsigned int)cfg.xor_out);
+ printf(format, "crc_mask", (unsigned int)cfg.crc_mask);
+ printf(format, "msb_mask", (unsigned int)cfg.msb_mask);
+ }
+ printf("0x%llx\n", (unsigned long long int)crc);
+ }
+ return !ret;
+}
diff --git a/test/performance.sh b/test/performance.sh
new file mode 100755
index 0000000..7b6b239
--- /dev/null
+++ b/test/performance.sh
@@ -0,0 +1,147 @@
+#!/bin/sh
+set -e
+
+PYCRC=`dirname $0`/../pycrc.py
+
+cleanup() {
+ rm -f a.out performance.c crc_bbb.[ch] crc_bbf.[ch] crc_tb[l4].[ch] crc_sb4.[ch]
+}
+
+trap cleanup 0 1 2 3 15
+
+model=crc-32
+
+prefix=bbb
+$PYCRC --model $model --symbol-prefix crc_${prefix}_ --generate c -o crc_$prefix.c --algo bit-by-bit
+$PYCRC --model $model --symbol-prefix crc_${prefix}_ --generate h -o crc_$prefix.h --algo bit-by-bit
+prefix=bbf
+$PYCRC --model $model --symbol-prefix crc_${prefix}_ --generate h -o crc_$prefix.h --algo bit-by-bit-fast
+$PYCRC --model $model --symbol-prefix crc_${prefix}_ --generate c -o crc_$prefix.c --algo bit-by-bit-fast
+prefix=tbl
+$PYCRC --model $model --symbol-prefix crc_${prefix}_ --generate h -o crc_$prefix.h --algo table-driven
+$PYCRC --model $model --symbol-prefix crc_${prefix}_ --generate c -o crc_$prefix.c --algo table-driven
+prefix=tb4
+$PYCRC --model $model --symbol-prefix crc_${prefix}_ --generate h -o crc_$prefix.h --algo table-driven --table-idx-width 4
+$PYCRC --model $model --symbol-prefix crc_${prefix}_ --generate c -o crc_$prefix.c --algo table-driven --table-idx-width 4
+prefix=sb4
+$PYCRC --model $model --symbol-prefix crc_${prefix}_ --generate h -o crc_$prefix.h --algo table-driven --slice-by 4
+$PYCRC --model $model --symbol-prefix crc_${prefix}_ --generate c -o crc_$prefix.c --algo table-driven --slice-by 4
+
+
+print_main() {
+cat <<EOF
+#include "crc_bbb.h"
+#include "crc_bbf.h"
+#include "crc_tbl.h"
+#include "crc_tb4.h"
+#include "crc_sb4.h"
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/times.h>
+#include <unistd.h>
+
+#define NUM_RUNS (128*256*256)
+
+unsigned char buf[1024];
+
+void test_bbb(unsigned char *buf, size_t buf_len, size_t num_runs, clock_t clock_per_sec);
+void test_bbf(unsigned char *buf, size_t buf_len, size_t num_runs, clock_t clock_per_sec);
+void test_tbl(unsigned char *buf, size_t buf_len, size_t num_runs, clock_t clock_per_sec);
+void test_tb4(unsigned char *buf, size_t buf_len, size_t num_runs, clock_t clock_per_sec);
+void test_sb4(unsigned char *buf, size_t buf_len, size_t num_runs, clock_t clock_per_sec);
+
+/**
+ * Print results.
+ *
+ * \param dsc Description of the test
+ * \param buflen Length of one buffer
+ * \param num_runs Number of runs over that buffer
+ * \param t_user user time
+ * \param t_sys system time
+ * \return void
+ *****************************************************************************/
+void show_times(const char *dsc, size_t buflen, size_t num_runs, double t_user)
+{
+ double mbps = (((double)buflen) * num_runs)/(1024*1024*t_user);
+ printf("%s of %ld bytes (%ld * %ld)\n", dsc, (long)buflen*num_runs, (long)buflen, (long)num_runs);
+ printf("%13s: %7.3f s %13s: %7.3f MiB/s\n", "user time", t_user, "throughput", mbps);
+ printf("\n");
+}
+
+
+/**
+ * C main function.
+ *
+ * \retval 0 on success
+ * \retval 1 on failure
+ *****************************************************************************/
+int main(void)
+{
+ unsigned int i;
+ long int clock_per_sec;
+
+ for (i = 0; i < sizeof(buf); i++) {
+ buf[i] = (unsigned char)rand();
+ }
+ clock_per_sec = sysconf(_SC_CLK_TCK);
+
+ // bit-by-bit
+ test_bbb(buf, sizeof(buf), NUM_RUNS / 8, clock_per_sec);
+
+ // bit-by-bit-fast
+ test_bbf(buf, sizeof(buf), NUM_RUNS / 8, clock_per_sec);
+
+ // table-driven
+ test_tbl(buf, sizeof(buf), NUM_RUNS, clock_per_sec);
+
+ // table-driven idx4
+ test_tb4(buf, sizeof(buf), NUM_RUNS / 2, clock_per_sec);
+
+ // table-driven slice-by 4
+ test_sb4(buf, sizeof(buf), NUM_RUNS, clock_per_sec);
+
+ return 0;
+}
+EOF
+}
+
+print_routine() {
+ algo=$1
+ prefix=$2
+ cat <<EOF
+/**
+ * Test $algo Algorithm.
+ *
+ * \return void
+ *****************************************************************************/
+void test_${prefix}(unsigned char *buf, size_t buf_len, size_t num_runs, clock_t clock_per_sec)
+{
+ crc_${prefix}_t crc;
+ unsigned int i;
+ struct tms tm1, tm2;
+
+ times(&tm1);
+ crc = crc_${prefix}_init();
+ for (i = 0; i < num_runs; i++) {
+ crc = crc_${prefix}_update(crc, buf, buf_len);
+ }
+ crc = crc_${prefix}_finalize(crc);
+ times(&tm2);
+ show_times("$model, $algo, block-wise", buf_len, num_runs,
+ ((double)(tm2.tms_utime - tm1.tms_utime) / (double)clock_per_sec));
+}
+
+EOF
+}
+
+print_main > performance.c
+print_routine "bit-by-bit" bbb >> performance.c
+print_routine "bit-by-bit-fast" bbf >> performance.c
+print_routine "table-driven" tbl >> performance.c
+print_routine "table-driven idx4" tb4 >> performance.c
+print_routine "table-driven sb4" sb4 >> performance.c
+
+gcc -W -Wall -O3 crc_bbb.c crc_bbf.c crc_tbl.c crc_tb4.c crc_sb4.c performance.c
+./a.out
diff --git a/test/test.py b/test/test.py
new file mode 100644
index 0000000..1731416
--- /dev/null
+++ b/test/test.py
@@ -0,0 +1,679 @@
+#!/usr/bin/env python
+# -*- coding: Latin-1 -*-
+
+# pycrc test application.
+
+from optparse import OptionParser, Option, OptionValueError
+from copy import copy
+import os, sys
+import tempfile
+sys.path.append('..')
+sys.path.append('.')
+from pycrc.models import CrcModels
+from pycrc.algorithms import Crc
+
+
+class Options(object):
+ """
+ The options parsing and validating class
+ """
+
+ def __init__(self):
+ self.AllAlgorithms = set(['bit-by-bit', 'bbb', 'bit-by-bit-fast', 'bbf', 'table-driven', 'tbl'])
+ self.Compile = False
+ self.RandomParameters = False
+ self.CompileMixedArgs = False
+ self.VariableWidth = False
+ self.verbose = False
+ self.algorithm = copy(self.AllAlgorithms)
+
+ def parse(self, argv = None):
+ """
+ Parses and validates the options given as arguments
+ """
+ usage = """%prog [OPTIONS]"""
+
+ algorithms = ', '.join(sorted(list(self.AllAlgorithms)) + ['all'])
+ parser = OptionParser(usage=usage)
+ parser.add_option('-v', '--verbose',
+ action='store_true', dest='verbose', default=self.verbose,
+ help='print information about the model')
+ parser.add_option('-c', '--compile',
+ action='store_true', dest='compile', default=self.Compile,
+ help='test compiled version')
+ parser.add_option('-r', '--random-parameters',
+ action='store_true', dest='random_parameters', default=self.RandomParameters,
+ help='test random parameters')
+ parser.add_option('-m', '--compile-mixed-arguments',
+ action='store_true', dest='compile_mixed_args', default=self.CompileMixedArgs,
+ help='test compiled C program with some arguments given at compile time some arguments given at runtime')
+ parser.add_option('-w', '--variable-width',
+ action='store_true', dest='variable_width', default=self.VariableWidth,
+ help='test variable width from 1 to 64')
+ parser.add_option('-a', '--all',
+ action='store_true', dest='all', default=False,
+ help='do all tests')
+ parser.add_option('--algorithm',
+ action='store', type='string', dest='algorithm', default='all',
+ help='choose an algorithm from {{{0:s}}}'.format(algorithms, metavar='ALGO'))
+
+ (options, args) = parser.parse_args(argv)
+
+ self.verbose = options.verbose
+ self.Compile = options.all or options.compile or options.random_parameters
+ self.RandomParameters = options.all or options.random_parameters
+ self.CompileMixedArgs = options.all or options.compile_mixed_args
+ self.VariableWidth = options.all or options.variable_width
+
+ if options.algorithm is not None:
+ alg = options.algorithm.lower()
+ if alg in self.AllAlgorithms:
+ self.algorithm = set([alg])
+ elif alg == 'all':
+ self.algorithm = copy(self.AllAlgorithms)
+ else:
+ sys.stderr.write('unknown algorithm: {0:s}\n'.format(alg))
+ sys.exit(1)
+
+
+class CrcTests(object):
+ """
+ The CRC test class.
+ """
+
+ def __init__(self):
+ """
+ The class constructor.
+ """
+ self.pycrc_bin = '/bin/false'
+ self.use_algo_bit_by_bit = True
+ self.use_algo_bit_by_bit_fast = True
+ self.use_algo_table_driven = True
+ self.verbose = False
+ self.python3 = sys.version_info[0] >= 3
+ self.tmpdir = tempfile.mkdtemp(prefix='pycrc.')
+ self.check_file = None
+ self.crc_bin_bbb_c89 = None
+ self.crc_bin_bbb_c99 = None
+ self.crc_bin_bbf_c89 = None
+ self.crc_bin_bbf_c99 = None
+ self.crc_bin_bwe_c89 = None
+ self.crc_bin_bwe_c99 = None
+ self.crc_bin_tbl_c89 = None
+ self.crc_bin_tbl_c99 = None
+ self.crc_bin_tbl_sb4 = None
+ self.crc_bin_tbl_sb8 = None
+ self.crc_bin_tbl_sb16 = None
+ self.crc_bin_tbl_idx2 = None
+ self.crc_bin_tbl_idx4 = None
+
+ def __del__(self):
+ """
+ The class destructor. Delete all generated files.
+ """
+ if self.check_file is not None:
+ os.remove(self.check_file)
+ if self.crc_bin_bbb_c89 is not None:
+ self.__del_files([self.crc_bin_bbb_c89, self.crc_bin_bbb_c89+'.h', self.crc_bin_bbb_c89+'.c'])
+ if self.crc_bin_bbb_c99 is not None:
+ self.__del_files([self.crc_bin_bbb_c99, self.crc_bin_bbb_c99+'.h', self.crc_bin_bbb_c99+'.c'])
+ if self.crc_bin_bbf_c89 is not None:
+ self.__del_files([self.crc_bin_bbf_c89, self.crc_bin_bbf_c89+'.h', self.crc_bin_bbf_c89+'.c'])
+ if self.crc_bin_bbf_c99 is not None:
+ self.__del_files([self.crc_bin_bbf_c99, self.crc_bin_bbf_c99+'.h', self.crc_bin_bbf_c99+'.c'])
+ if self.crc_bin_bwe_c89 is not None:
+ self.__del_files([self.crc_bin_bwe_c89, self.crc_bin_bwe_c89+'.h', self.crc_bin_bwe_c89+'.c'])
+ if self.crc_bin_bwe_c99 is not None:
+ self.__del_files([self.crc_bin_bwe_c99, self.crc_bin_bwe_c99+'.h', self.crc_bin_bwe_c99+'.c'])
+ if self.crc_bin_tbl_c89 is not None:
+ self.__del_files([self.crc_bin_tbl_c89, self.crc_bin_tbl_c89+'.h', self.crc_bin_tbl_c89+'.c'])
+ if self.crc_bin_tbl_c99 is not None:
+ self.__del_files([self.crc_bin_tbl_c99, self.crc_bin_tbl_c99+'.h', self.crc_bin_tbl_c99+'.c'])
+ if self.crc_bin_tbl_sb4 is not None:
+ self.__del_files([self.crc_bin_tbl_sb4, self.crc_bin_tbl_sb4+'.h', self.crc_bin_tbl_sb4+'.c'])
+ if self.crc_bin_tbl_sb8 is not None:
+ self.__del_files([self.crc_bin_tbl_sb8, self.crc_bin_tbl_sb8+'.h', self.crc_bin_tbl_sb8+'.c'])
+ if self.crc_bin_tbl_sb16 is not None:
+ self.__del_files([self.crc_bin_tbl_sb16, self.crc_bin_tbl_sb16+'.h', self.crc_bin_tbl_sb16+'.c'])
+ if self.crc_bin_tbl_idx2 is not None:
+ self.__del_files([self.crc_bin_tbl_idx2, self.crc_bin_tbl_idx2+'.h', self.crc_bin_tbl_idx2+'.c'])
+ if self.crc_bin_tbl_idx4 is not None:
+ self.__del_files([self.crc_bin_tbl_idx4, self.crc_bin_tbl_idx4+'.h', self.crc_bin_tbl_idx4+'.c'])
+ os.removedirs(self.tmpdir)
+
+ def __del_files(delf, files):
+ """
+ Helper function to delete files.
+ """
+ for f in files:
+ try:
+ os.remove(f)
+ except:
+ print("error: can't delete {0:s}".format(f))
+ pass
+
+ def __get_status_output(self, cmd_str):
+ if self.python3:
+ import subprocess
+ return subprocess.getstatusoutput(cmd_str)
+ else:
+ import commands
+ return commands.getstatusoutput(cmd_str)
+
+ def __make_src(self, args, basename, cstd):
+ """
+ Generate the *.h and *.c source files for a test.
+ """
+ gen_src = '{0:s}/{1:s}'.format(self.tmpdir, basename)
+ cmd_str = self.pycrc_bin + ' {0:s} --std {1:s} --generate h -o {2:s}.h'.format(args, cstd, gen_src)
+ if self.verbose:
+ print(cmd_str)
+ ret = self.__get_status_output(cmd_str)
+ if ret[0] != 0:
+ print('error: the following command returned error: {0:s}'.format(cmd_str))
+ print(ret[1])
+ print(ret[2])
+ return None
+
+ cmd_str = self.pycrc_bin + ' {0:s} --std {1:s} --generate c-main -o {2:s}.c'.format(args, cstd, gen_src)
+ if self.verbose:
+ print(cmd_str)
+ ret = self.__get_status_output(cmd_str)
+ if ret[0] != 0:
+ print('error: the following command returned error: {0:s}'.format(cmd_str))
+ print(ret[1])
+ print(ret[2])
+ return None
+ return gen_src
+
+ def __compile(self, args, binfile, cstd):
+ """
+ Compile a generated source file.
+ """
+ cmd_str = 'gcc -W -Wall -pedantic -Werror -std={0:s} -o {1:s} {2:s}.c'.format(cstd, binfile, binfile)
+ if self.verbose:
+ print(cmd_str)
+ ret = self.__get_status_output(cmd_str)
+ if len(ret) > 1 and len(ret[1]) > 0:
+ print(ret[1])
+ if ret[0] != 0:
+ print('error: {0:d} with command error: {1:s}'.format(ret[0], cmd_str))
+ return None
+ return binfile
+
+ def __make_bin(self, args, basename, cstd='c99'):
+ """
+ Generate the source and compile to a binary.
+ """
+ filename = self.__make_src(args, basename, cstd)
+ if filename is None:
+ return None
+ if not self.__compile(args, filename, cstd):
+ self.__del_files([filename, filename+'.h', filename+'.c'])
+ return None
+ return filename
+
+ def __setup_files(self, opt):
+ """
+ Set up files needed during the test.
+ """
+ if self.verbose:
+ print('Setting up files...')
+ self.check_file = '{0:s}/check.txt'.format(self.tmpdir)
+ f = open(self.check_file, 'wb')
+ if self.python3:
+ f.write(bytes('123456789', 'utf-8'))
+ else:
+ f.write('123456789')
+ f.close()
+
+ if opt.Compile:
+ if self.use_algo_bit_by_bit:
+ filename = self.__make_bin('--algorithm bit-by-bit', 'crc_bbb_c89', 'c89')
+ if filename is None:
+ return False
+ self.crc_bin_bbb_c89 = filename
+
+ filename = self.__make_bin('--algorithm bit-by-bit', 'crc_bbb_c99', 'c99')
+ if filename is None:
+ return False
+ self.crc_bin_bbb_c99 = filename
+
+ if self.use_algo_bit_by_bit_fast:
+ filename = self.__make_bin('--algorithm bit-by-bit-fast', 'crc_bbf_c89', 'c89')
+ if filename is None:
+ return False
+ self.crc_bin_bbf_c89 = filename
+
+ filename = self.__make_bin('--algorithm bit-by-bit-fast', 'crc_bbf_c99', 'c99')
+ if filename is None:
+ return False
+ self.crc_bin_bbf_c99 = filename
+
+ if self.use_algo_table_driven:
+ filename = self.__make_bin('--algorithm table-driven', 'crc_tbl_c89', 'c89')
+ if filename is None:
+ return False
+ self.crc_bin_tbl_c89 = filename
+
+ filename = self.__make_bin('--algorithm table-driven', 'crc_tbl_c99', 'c99')
+ if filename is None:
+ return False
+ self.crc_bin_tbl_c99 = filename
+
+# FIXME don't test undefined params
+# filename = self.__make_bin('--algorithm table-driven --slice-by 4', 'crc_tbl_sb4')
+# if filename is None:
+# return False
+# self.crc_bin_tbl_sb4 = filename
+#
+# filename = self.__make_bin('--algorithm table-driven --slice-by 8', 'crc_tbl_sb8')
+# if filename is None:
+# return False
+# self.crc_bin_tbl_sb8 = filename
+#
+# filename = self.__make_bin('--algorithm table-driven --slice-by 16', 'crc_tbl_sb16')
+# if filename is None:
+# return False
+# self.crc_bin_tbl_sb16 = filename
+
+ filename = self.__make_bin('--algorithm table-driven --table-idx-width 2', 'crc_tbl_idx2')
+ if filename is None:
+ return False
+ self.crc_bin_tbl_idx2 = filename
+
+ filename = self.__make_bin('--algorithm table-driven --table-idx-width 4', 'crc_tbl_idx4')
+ if filename is None:
+ return False
+ self.crc_bin_tbl_idx4 = filename
+
+ return True
+
+
+ def __run_command(self, cmd_str):
+ """
+ Run a command and return its stdout.
+ """
+ if self.verbose:
+ print(cmd_str)
+ ret = self.__get_status_output(cmd_str)
+ if ret[0] != 0:
+ print('error: the following command returned error: {0:s}'.format(cmd_str))
+ print(ret[1])
+ return None
+ return ret[1]
+
+ def __check_command(self, cmd_str, expected_result):
+ """
+ Run a command and check if the stdout matches the expected result.
+ """
+ ret = self.__run_command(cmd_str)
+ if int(ret, 16) != expected_result:
+ print('error: different checksums!')
+ print('{0:s}: expected {1:#x}, got {2:s}'.format(cmd_str, expected_result, ret))
+ return False
+ return True
+
+ def __check_bin(self, args, expected_result, long_data_type = True):
+ """
+ Check all precompiled binaries.
+ """
+ for binary in [
+ self.crc_bin_bbb_c89, self.crc_bin_bbb_c99,
+ self.crc_bin_bbf_c89, self.crc_bin_bbf_c99,
+ self.crc_bin_tbl_c89, self.crc_bin_tbl_c99,
+ self.crc_bin_tbl_sb4, self.crc_bin_tbl_sb8, self.crc_bin_tbl_sb16,
+ self.crc_bin_tbl_idx2, self.crc_bin_tbl_idx4]:
+ if binary is not None:
+ # Don't test width > 32 for C89, as I don't know how to ask for an data type > 32 bits.
+ if binary[-3:] == 'c89' and long_data_type:
+ continue
+ cmd_str = binary + ' ' + args
+ if not self.__check_command(cmd_str, expected_result):
+ return False
+ return True
+
+ def __get_crc(self, model, check_str = '123456789', expected_crc = None):
+ """
+ Get the CRC for a set of parameters from the Python reference implementation.
+ """
+ if self.verbose:
+ out_str = 'Crc(width = {width:d}, poly = {poly:#x}, reflect_in = {reflect_in}, xor_in = {xor_in:#x}, reflect_out = {reflect_out}, xor_out = {xor_out:#x})'.format(**model)
+ if expected_crc is not None:
+ out_str += ' [check = {0:#x}]'.format(expected_crc)
+ print(out_str)
+ alg = Crc(width = model['width'], poly = model['poly'],
+ reflect_in = model['reflect_in'], xor_in = model['xor_in'],
+ reflect_out = model['reflect_out'], xor_out = model['xor_out'])
+ error = False
+ crc = expected_crc
+
+ if self.use_algo_bit_by_bit:
+ bbb_crc = alg.bit_by_bit(check_str)
+ if crc is None:
+ crc = bbb_crc
+ error = error or bbb_crc != crc
+ if self.use_algo_bit_by_bit_fast:
+ bbf_crc = alg.bit_by_bit_fast(check_str)
+ if crc is None:
+ crc = bbf_crc
+ error = error or bbf_crc != crc
+ if self.use_algo_table_driven:
+ tbl_crc = alg.table_driven(check_str)
+ if crc is None:
+ crc = tbl_crc
+ error = error or tbl_crc != crc
+
+ if error:
+ print('error: different checksums!')
+ if expected_crc is not None:
+ print(' check: {0:#x}'.format(expected_crc))
+ if self.use_algo_bit_by_bit:
+ print(' bit-by-bit: {0:#x}'.format(bbb_crc))
+ if self.use_algo_bit_by_bit_fast:
+ print(' bit-by-bit-fast: {0:#x}'.format(bbf_crc))
+ if self.use_algo_table_driven:
+ print(' table_driven: {0:#x}'.format(tbl_crc))
+ return None
+ return crc
+
+ def __compile_and_check_res(self, cmp_opt, run_opt, name, expected_crc):
+ """
+ Compile a model and run it.
+ """
+ filename = self.__make_bin(cmp_opt, name)
+ if filename is None:
+ return False
+ if run_opt is None:
+ cmd = filename
+ else:
+ cmd = filename + ' ' + run_opt
+ ret = self.__check_command(cmd, expected_crc)
+ self.__del_files([filename, filename+'.h', filename+'.c'])
+ if not ret:
+ return False
+ return True
+
+
+ def __test_models(self):
+ """
+ Standard Tests.
+ Test all known models.
+ """
+ if self.verbose:
+ print('Running __test_models()...')
+ check_str = '123456789'
+ check_bytes = bytearray(check_str, 'utf-8')
+ models = CrcModels()
+ for m in models.models:
+ expected_crc = m['check']
+ if self.__get_crc(m, check_str, expected_crc) != expected_crc:
+ return False
+
+ ext_args = '--width {width:d} --poly {poly:#x} --xor-in {xor_in:#x} --reflect-in {reflect_in} --xor-out {xor_out:#x} --reflect-out {reflect_out}'.format(**m)
+
+ cmd_str = '{0:s} --model {1:s}'.format(self.pycrc_bin, m['name'])
+ if not self.__check_command(cmd_str, expected_crc):
+ return False
+
+ cmd_str = '{0:s} {1:s}'.format(self.pycrc_bin, ext_args)
+ if not self.__check_command(cmd_str, expected_crc):
+ return False
+
+ cmd_str = '{0:s} {1:s} --check-hexstring {2:s}'.format(self.pycrc_bin, ext_args, ''.join(['{0:02x}'.format(c) for c in check_bytes]))
+ if not self.__check_command(cmd_str, expected_crc):
+ return False
+
+ cmd_str = '{0:s} --model {1:s} --check-file {2:s}'.format(self.pycrc_bin, m['name'], self.check_file)
+ if not self.__check_command(cmd_str, expected_crc):
+ return False
+
+ if not self.__check_bin(ext_args, expected_crc, m['width'] > 32):
+ return False
+
+ if self.verbose:
+ print("")
+ return True
+
+
+ def __test_compiled_models(self):
+ """
+ Standard Tests.
+ Test all known models with the compiled code
+ """
+ if self.verbose:
+ print('Running __test_compiled_models()...')
+ models = CrcModels()
+ for m in models.models:
+ expected_crc = m['check']
+ cmp_opt = '--model {name}'.format(**m)
+
+ if self.use_algo_bit_by_bit:
+ if not self.__compile_and_check_res('--algorithm bit-by-bit' + ' ' + cmp_opt, None, 'crc_bbb_mod', expected_crc):
+ return False
+
+ if self.use_algo_bit_by_bit_fast:
+ if not self.__compile_and_check_res('--algorithm bit-by-bit-fast' + ' ' + cmp_opt, None, 'crc_bbf_mod', expected_crc):
+ return False
+
+ if self.use_algo_table_driven:
+ if not self.__compile_and_check_res('--algorithm table-driven' + ' ' + cmp_opt, None, 'crc_tbl_mod', expected_crc):
+ return False
+
+ if not self.__compile_and_check_res('--algorithm table-driven --slice-by=4' + ' ' + cmp_opt, None, 'crc_tsb4_mod', expected_crc):
+ return False
+
+ if not self.__compile_and_check_res('--algorithm table-driven --slice-by=8' + ' ' + cmp_opt, None, 'crc_tsb8_mod', expected_crc):
+ return False
+
+ if not self.__compile_and_check_res('--algorithm table-driven --slice-by=16' + ' ' + cmp_opt, None, 'crc_tsb16_mod', expected_crc):
+ return False
+
+ if not self.__compile_and_check_res('--algorithm table-driven --table-idx-width=2' + ' ' + cmp_opt, None, 'crc_tix2_mod', expected_crc):
+ return False
+
+ if not self.__compile_and_check_res('--algorithm table-driven --table-idx-width=4' + ' ' + cmp_opt, None, 'crc_tix4_mod', expected_crc):
+ return False
+ return True
+
+
+ def __test_compiled_special_cases(self):
+ """
+ Standard Tests.
+ Test some special cases.
+ """
+ if self.verbose:
+ print('Running __test_compiled_special_cases()...')
+ if self.use_algo_table_driven:
+ if not self.__compile_and_check_res('--model=crc-5 --reflect-in=0 --algorithm table-driven --table-idx-width=8', None, 'crc_tbl_special', 0x01):
+ return False
+ if not self.__compile_and_check_res('--model=crc-5 --reflect-in=0 --algorithm table-driven --table-idx-width=4', None, 'crc_tbl_special', 0x01):
+ return False
+ if not self.__compile_and_check_res('--model=crc-5 --reflect-in=0 --algorithm table-driven --table-idx-width=2', None, 'crc_tbl_special', 0x01):
+ return False
+ return True
+
+
+ def __test_variable_width(self):
+ """
+ Test variable width.
+ """
+ if self.verbose:
+ print('Running __test_variable_width()...')
+ models = CrcModels()
+ m = models.get_params('crc-64-jones')
+
+ for width in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 15, 16, 17, 23, 24, 25, 31, 32, 33, 63, 64]:
+ mask = (1 << width) - 1
+ mw = {
+ 'width': width,
+ 'poly': m['poly'] & mask,
+ 'reflect_in': m['reflect_in'],
+ 'xor_in': m['xor_in'] & mask,
+ 'reflect_out': m['reflect_out'],
+ 'xor_out': m['xor_out'] & mask,
+ }
+ args = '--width {width:d} --poly {poly:#x} --xor-in {xor_in:#x} --reflect-in {reflect_in} --xor-out {xor_out:#x} --reflect-out {reflect_out}'.format(**mw)
+
+ check = self.__get_crc(mw)
+ if check is None:
+ return False
+
+ if self.use_algo_bit_by_bit:
+ if self.crc_bin_bbb_c99 is not None:
+ if not self.__check_command(self.crc_bin_bbb_c99 + ' ' + args, check):
+ return False
+
+ if not self.__compile_and_check_res('--algorithm bit-by-bit' + ' ' + args, None, 'crc_bbb_arg', check):
+ return False
+
+ if self.use_algo_bit_by_bit_fast:
+ if self.crc_bin_bbf_c99 is not None:
+ if not self.__check_command(self.crc_bin_bbf_c99 + ' ' + args, check):
+ return False
+
+ if not self.__compile_and_check_res('--algorithm bit-by-bit-fast' + ' ' + args, None, 'crc_bbf_arg', check):
+ return False
+
+ if self.use_algo_table_driven:
+ if self.crc_bin_tbl_c99 is not None:
+ if not self.__check_command(self.crc_bin_tbl_c99 + ' ' + args, check):
+ return False
+
+ if not self.__compile_and_check_res('--algorithm table-driven' + ' ' + args, None, 'crc_tbl_arg', check):
+ return False
+ return True
+
+
+ def __test_compiled_mixed_args(self):
+ """
+ Test compiled arguments.
+ """
+ if self.verbose:
+ print('Running __test_compiled_mixed_args()...')
+ m = {
+ 'name': 'zmodem',
+ 'width': ['', '--width 16'],
+ 'poly': ['', '--poly 0x1021'],
+ 'reflect_in': ['', '--reflect-in False'],
+ 'xor_in': ['', '--xor-in 0x0'],
+ 'reflect_out': ['', '--reflect-out False'],
+ 'xor_out': ['', '--xor-out 0x0'],
+ 'check': 0x31c3,
+ }
+ cmp_args = {}
+ run_args = {}
+ for b_width in range(2):
+ cmp_args['width'] = m['width'][b_width]
+ run_args['width'] = m['width'][1 - b_width]
+ for b_poly in range(2):
+ cmp_args['poly'] = m['poly'][b_poly]
+ run_args['poly'] = m['poly'][1 - b_poly]
+ for b_ref_in in range(2):
+ cmp_args['reflect_in'] = m['reflect_in'][b_ref_in]
+ run_args['reflect_in'] = m['reflect_in'][1 - b_ref_in]
+ for b_xor_in in range(2):
+ cmp_args['xor_in'] = m['xor_in'][b_xor_in]
+ run_args['xor_in'] = m['xor_in'][1 - b_xor_in]
+ for b_ref_out in range(2):
+ cmp_args['reflect_out'] = m['reflect_out'][b_ref_out]
+ run_args['reflect_out'] = m['reflect_out'][1 - b_ref_out]
+ for b_xor_out in range(2):
+ cmp_args['xor_out'] = m['xor_out'][b_xor_out]
+ run_args['xor_out'] = m['xor_out'][1 - b_xor_out]
+
+ cmp_opt = '{width:s} {poly:s} {reflect_in} {xor_in:s} {reflect_out} {xor_out:s}'.format(**cmp_args)
+ run_opt = '{width:s} {poly:s} {reflect_in} {xor_in:s} {reflect_out} {xor_out:s}'.format(**run_args)
+
+ if self.use_algo_bit_by_bit:
+ if not self.__compile_and_check_res('--algorithm bit-by-bit' + ' ' + cmp_opt, run_opt, 'crc_bbb_arg', m['check']):
+ return False
+
+ if self.use_algo_bit_by_bit_fast:
+ if not self.__compile_and_check_res('--algorithm bit-by-bit-fast' + ' ' + cmp_opt, run_opt, 'crc_bbf_arg', m['check']):
+ return False
+
+ if self.use_algo_table_driven:
+ if not self.__compile_and_check_res('--algorithm table-driven' + ' ' + cmp_opt, run_opt, 'crc_tbl_arg', m['check']):
+ return False
+ return True
+
+
+ def __test_random_params(self):
+ """
+ Test random parameters.
+ """
+ if self.verbose:
+ print('Running __test_random_params()...')
+ for width in [8, 16, 32]:
+ for poly in [0x8005, 0x4c11db7, 0xa5a5a5a5]:
+ poly = poly & ((1 << width) - 1)
+ for refin in [0, 1]:
+ for refout in [0, 1]:
+ for init in [0x0, 0x1, 0x5a5a5a5a]:
+ args='--width {0:d} --poly {1:#x} --reflect-in {2} --reflect-out {3} --xor-in {4:#x} --xor-out 0x0'.format(width, poly, refin, refout, init)
+ cmd_str = self.pycrc_bin + ' ' + args
+ ret = self.__run_command(cmd_str)
+ if ret is None:
+ return False
+ ret = int(ret, 16)
+ if not self.__check_bin(args, ret, width > 32):
+ return False
+ return True
+
+
+ def run(self, opt):
+ """
+ Run all tests
+ """
+ self.use_algo_bit_by_bit = 'bit-by-bit' in opt.algorithm or 'bbb' in opt.algorithm
+ self.use_algo_bit_by_bit_fast = 'bit-by-bit-fast' in opt.algorithm or 'bbf' in opt.algorithm
+ self.use_algo_table_driven = 'table-driven' in opt.algorithm or 'tbl' in opt.algorithm
+ self.verbose = opt.verbose
+
+ if self.python3:
+ self.pycrc_bin = 'python3 pycrc.py'
+ else:
+ self.pycrc_bin = 'python pycrc.py'
+
+ if not self.__setup_files(opt):
+ return False
+
+ if not self.__test_models():
+ return False
+
+ if opt.Compile and not self.__test_compiled_models():
+ return False
+
+ if opt.Compile and not self.__test_compiled_special_cases():
+ return False
+
+ if opt.VariableWidth and not self.__test_variable_width():
+ return False
+
+ if opt.CompileMixedArgs and not self.__test_compiled_mixed_args():
+ return False
+
+ if opt.RandomParameters and not self.__test_random_params():
+ return False
+
+ return True
+
+
+def main():
+ """
+ Main function.
+ """
+ opt = Options()
+ opt.parse(sys.argv[1:])
+
+ test = CrcTests()
+ if not test.run(opt):
+ return 1
+ print('Test OK')
+ return 0
+
+
+# program entry point
+if __name__ == '__main__':
+ sys.exit(main())