bitstruct-8.9.0/0000775000175000017500000000000013611423315013462 5ustar erikerik00000000000000bitstruct-8.9.0/PKG-INFO0000664000175000017500000002261713611423315014567 0ustar erikerik00000000000000Metadata-Version: 1.1 Name: bitstruct Version: 8.9.0 Summary: This module performs conversions between Python values and C bit field structs represented as Python byte strings. Home-page: https://github.com/eerimoq/bitstruct Author: Erik Moqvist, Ilya Petukhov Author-email: erik.moqvist@gmail.com License: MIT Description: |buildstatus|_ |appveyor|_ |coverage|_ |codecov|_ About ===== This module is intended to have a similar interface as the python struct module, but working on bits instead of primitive data types (char, int, ...). Project homepage: https://github.com/eerimoq/bitstruct Documentation: https://bitstruct.readthedocs.io Installation ============ .. code-block:: python pip install bitstruct Performance =========== Parts of this package has been re-implemented in C for faster pack and unpack operations. There are two independent C implementations; `bitstruct.c`, which is part of this package, and the standalone package `cbitstruct`_. These implementations are only available in Python 3, and must be explicitly imported. By default the pure Python implementation is used. To use `bitstruct.c`, do ``import bitstruct.c as bitstruct``. To use `cbitstruct`_, do ``import cbitstruct as bitstruct``. `bitstruct.c` has a few limitations compared to the pure Python implementation: - Integers and booleans must be 64 bits or less. - Text and raw must be a multiple of 8 bits. - Bit endianness and byte order are not yet supported. - ``byteswap()`` can only swap 1, 2, 4 and 8 bytes. See `cbitstruct`_ for its limitations. MicroPython =========== The C implementation has been ported to `MicroPython`_. See `bitstruct-micropython`_ for more details. Example usage ============= A basic example of `packing`_ and `unpacking`_ four integers using the format string ``'u1u3u4s16'``: .. code-block:: python >>> from bitstruct import * >>> pack('u1u3u4s16', 1, 2, 3, -4) b'\xa3\xff\xfc' >>> unpack('u1u3u4s16', b'\xa3\xff\xfc') (1, 2, 3, -4) >>> calcsize('u1u3u4s16') 24 An example `compiling`_ the format string once, and use it to `pack`_ and `unpack`_ data: .. code-block:: python >>> import bitstruct >>> cf = bitstruct.compile('u1u3u4s16') >>> cf.pack(1, 2, 3, -4) b'\xa3\xff\xfc' >>> cf.unpack(b'\xa3\xff\xfc') (1, 2, 3, -4) Use the `pack into`_ and `unpack from`_ functions to pack/unpack values at a bit offset into the data, in this example the bit offset is 5: .. code-block:: python >>> from bitstruct import * >>> data = bytearray(b'\x00\x00\x00\x00') >>> pack_into('u1u3u4s16', data, 5, 1, 2, 3, -4) >>> data bytearray(b'\x05\x1f\xff\xe0') >>> unpack_from('u1u3u4s16', data, 5) (1, 2, 3, -4) The unpacked values can be named by assigning them to variables or by wrapping the result in a named tuple: .. code-block:: python >>> from bitstruct import * >>> from collections import namedtuple >>> MyName = namedtuple('myname', ['a', 'b', 'c', 'd']) >>> unpacked = unpack('u1u3u4s16', b'\xa3\xff\xfc') >>> myname = MyName(*unpacked) >>> myname myname(a=1, b=2, c=3, d=-4) >>> myname.c 3 Use the `pack_dict`_ and `unpack_dict`_ functions to pack/unpack values in dictionaries: .. code-block:: python >>> from bitstruct import * >>> names = ['a', 'b', 'c', 'd'] >>> pack_dict('u1u3u4s16', names, {'a': 1, 'b': 2, 'c': 3, 'd': -4}) b'\xa3\xff\xfc' >>> unpack_dict('u1u3u4s16', names, b'\xa3\xff\xfc') {'a': 1, 'b': 2, 'c': 3, 'd': -4} An example of `packing`_ and `unpacking`_ an unsigned integer, a signed integer, a float, a boolean, a byte string and a string: .. code-block:: python >>> from bitstruct import * >>> pack('u5s5f32b1r13t40', 1, -1, 3.75, True, b'\xff\xff', 'hello') b'\x0f\xd0\x1c\x00\x00?\xffhello' >>> unpack('u5s5f32b1r13t40', b'\x0f\xd0\x1c\x00\x00?\xffhello') (1, -1, 3.75, True, b'\xff\xf8', 'hello') >>> calcsize('u5s5f32b1r13t40') 96 The same format string and values as in the previous example, but using LSB (Least Significant Bit) first instead of the default MSB (Most Significant Bit) first: .. code-block:: python >>> from bitstruct import * >>> pack('>> unpack('>> calcsize('>> from bitstruct import * >>> from binascii import unhexlify >>> unpack('s17s13r24', unhexlify('0123456789abcdef')) (582, -3751, b'\xe2j\xf3') >>> with open("test.bin", "rb") as fin: ... unpack('s17s13r24', fin.read(8)) ... ... (582, -3751, b'\xe2j\xf3') Change endianness of the data with `byteswap`_, and then unpack the values: .. code-block:: python >>> from bitstruct import * >>> packed = pack('u1u3u4s16', 1, 2, 3, 1) >>> unpack('u1u3u4s16', byteswap('12', packed)) (1, 2, 3, 256) A basic example of `packing`_ and `unpacking`_ four integers using the format string ``'u1u3u4s16'`` using the C implementation: .. code-block:: python >>> from bitstruct.c import * >>> pack('u1u3u4s16', 1, 2, 3, -4) b'\xa3\xff\xfc' >>> unpack('u1u3u4s16', b'\xa3\xff\xfc') (1, 2, 3, -4) Contributing ============ #. Fork the repository. #. Install prerequisites. .. code-block:: text pip install -r requirements.txt #. Implement the new feature or bug fix. #. Implement test case(s) to ensure that future changes do not break legacy. #. Run the tests. .. code-block:: text make test #. Create a pull request. .. |buildstatus| image:: https://travis-ci.org/eerimoq/bitstruct.svg .. _buildstatus: https://travis-ci.org/eerimoq/bitstruct .. |appveyor| image:: https://img.shields.io/appveyor/ci/eerimoq/bitstruct/master.svg?label=AppVeyor .. _appveyor: https://ci.appveyor.com/project/eerimoq/bitstruct/history .. |coverage| image:: https://coveralls.io/repos/github/eerimoq/bitstruct/badge.svg?branch=master .. _coverage: https://coveralls.io/github/eerimoq/bitstruct .. |codecov| image:: https://codecov.io/gh/eerimoq/bitstruct/branch/master/graph/badge.svg .. _codecov: https://codecov.io/gh/eerimoq/bitstruct .. _packing: http://bitstruct.readthedocs.io/en/latest/#bitstruct.pack .. _unpacking: http://bitstruct.readthedocs.io/en/latest/#bitstruct.unpack .. _pack: http://bitstruct.readthedocs.io/en/latest/#bitstruct.CompiledFormat.pack .. _unpack: http://bitstruct.readthedocs.io/en/latest/#bitstruct.CompiledFormat.unpack .. _pack into: http://bitstruct.readthedocs.io/en/latest/#bitstruct.pack_into .. _unpack from: http://bitstruct.readthedocs.io/en/latest/#bitstruct.unpack_from .. _pack_dict: http://bitstruct.readthedocs.io/en/latest/#bitstruct.pack_dict .. _unpack_dict: http://bitstruct.readthedocs.io/en/latest/#bitstruct.unpack_dict .. _byteswap: http://bitstruct.readthedocs.io/en/latest/#bitstruct.byteswap .. _compiling: http://bitstruct.readthedocs.io/en/latest/#bitstruct.compile .. _cbitstruct: https://github.com/qchateau/cbitstruct .. _MicroPython: https://github.com/micropython/micropython .. _bitstruct-micropython: https://github.com/peterzuger/bitstruct-micropython Keywords: bit field,bit parsing,bit unpack,bit pack Platform: UNKNOWN Classifier: License :: OSI Approved :: MIT License Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 3 bitstruct-8.9.0/bitstruct.egg-info/0000775000175000017500000000000013611423315017177 5ustar erikerik00000000000000bitstruct-8.9.0/bitstruct.egg-info/PKG-INFO0000664000175000017500000002261713611423315020304 0ustar erikerik00000000000000Metadata-Version: 1.1 Name: bitstruct Version: 8.9.0 Summary: This module performs conversions between Python values and C bit field structs represented as Python byte strings. Home-page: https://github.com/eerimoq/bitstruct Author: Erik Moqvist, Ilya Petukhov Author-email: erik.moqvist@gmail.com License: MIT Description: |buildstatus|_ |appveyor|_ |coverage|_ |codecov|_ About ===== This module is intended to have a similar interface as the python struct module, but working on bits instead of primitive data types (char, int, ...). Project homepage: https://github.com/eerimoq/bitstruct Documentation: https://bitstruct.readthedocs.io Installation ============ .. code-block:: python pip install bitstruct Performance =========== Parts of this package has been re-implemented in C for faster pack and unpack operations. There are two independent C implementations; `bitstruct.c`, which is part of this package, and the standalone package `cbitstruct`_. These implementations are only available in Python 3, and must be explicitly imported. By default the pure Python implementation is used. To use `bitstruct.c`, do ``import bitstruct.c as bitstruct``. To use `cbitstruct`_, do ``import cbitstruct as bitstruct``. `bitstruct.c` has a few limitations compared to the pure Python implementation: - Integers and booleans must be 64 bits or less. - Text and raw must be a multiple of 8 bits. - Bit endianness and byte order are not yet supported. - ``byteswap()`` can only swap 1, 2, 4 and 8 bytes. See `cbitstruct`_ for its limitations. MicroPython =========== The C implementation has been ported to `MicroPython`_. See `bitstruct-micropython`_ for more details. Example usage ============= A basic example of `packing`_ and `unpacking`_ four integers using the format string ``'u1u3u4s16'``: .. code-block:: python >>> from bitstruct import * >>> pack('u1u3u4s16', 1, 2, 3, -4) b'\xa3\xff\xfc' >>> unpack('u1u3u4s16', b'\xa3\xff\xfc') (1, 2, 3, -4) >>> calcsize('u1u3u4s16') 24 An example `compiling`_ the format string once, and use it to `pack`_ and `unpack`_ data: .. code-block:: python >>> import bitstruct >>> cf = bitstruct.compile('u1u3u4s16') >>> cf.pack(1, 2, 3, -4) b'\xa3\xff\xfc' >>> cf.unpack(b'\xa3\xff\xfc') (1, 2, 3, -4) Use the `pack into`_ and `unpack from`_ functions to pack/unpack values at a bit offset into the data, in this example the bit offset is 5: .. code-block:: python >>> from bitstruct import * >>> data = bytearray(b'\x00\x00\x00\x00') >>> pack_into('u1u3u4s16', data, 5, 1, 2, 3, -4) >>> data bytearray(b'\x05\x1f\xff\xe0') >>> unpack_from('u1u3u4s16', data, 5) (1, 2, 3, -4) The unpacked values can be named by assigning them to variables or by wrapping the result in a named tuple: .. code-block:: python >>> from bitstruct import * >>> from collections import namedtuple >>> MyName = namedtuple('myname', ['a', 'b', 'c', 'd']) >>> unpacked = unpack('u1u3u4s16', b'\xa3\xff\xfc') >>> myname = MyName(*unpacked) >>> myname myname(a=1, b=2, c=3, d=-4) >>> myname.c 3 Use the `pack_dict`_ and `unpack_dict`_ functions to pack/unpack values in dictionaries: .. code-block:: python >>> from bitstruct import * >>> names = ['a', 'b', 'c', 'd'] >>> pack_dict('u1u3u4s16', names, {'a': 1, 'b': 2, 'c': 3, 'd': -4}) b'\xa3\xff\xfc' >>> unpack_dict('u1u3u4s16', names, b'\xa3\xff\xfc') {'a': 1, 'b': 2, 'c': 3, 'd': -4} An example of `packing`_ and `unpacking`_ an unsigned integer, a signed integer, a float, a boolean, a byte string and a string: .. code-block:: python >>> from bitstruct import * >>> pack('u5s5f32b1r13t40', 1, -1, 3.75, True, b'\xff\xff', 'hello') b'\x0f\xd0\x1c\x00\x00?\xffhello' >>> unpack('u5s5f32b1r13t40', b'\x0f\xd0\x1c\x00\x00?\xffhello') (1, -1, 3.75, True, b'\xff\xf8', 'hello') >>> calcsize('u5s5f32b1r13t40') 96 The same format string and values as in the previous example, but using LSB (Least Significant Bit) first instead of the default MSB (Most Significant Bit) first: .. code-block:: python >>> from bitstruct import * >>> pack('>> unpack('>> calcsize('>> from bitstruct import * >>> from binascii import unhexlify >>> unpack('s17s13r24', unhexlify('0123456789abcdef')) (582, -3751, b'\xe2j\xf3') >>> with open("test.bin", "rb") as fin: ... unpack('s17s13r24', fin.read(8)) ... ... (582, -3751, b'\xe2j\xf3') Change endianness of the data with `byteswap`_, and then unpack the values: .. code-block:: python >>> from bitstruct import * >>> packed = pack('u1u3u4s16', 1, 2, 3, 1) >>> unpack('u1u3u4s16', byteswap('12', packed)) (1, 2, 3, 256) A basic example of `packing`_ and `unpacking`_ four integers using the format string ``'u1u3u4s16'`` using the C implementation: .. code-block:: python >>> from bitstruct.c import * >>> pack('u1u3u4s16', 1, 2, 3, -4) b'\xa3\xff\xfc' >>> unpack('u1u3u4s16', b'\xa3\xff\xfc') (1, 2, 3, -4) Contributing ============ #. Fork the repository. #. Install prerequisites. .. code-block:: text pip install -r requirements.txt #. Implement the new feature or bug fix. #. Implement test case(s) to ensure that future changes do not break legacy. #. Run the tests. .. code-block:: text make test #. Create a pull request. .. |buildstatus| image:: https://travis-ci.org/eerimoq/bitstruct.svg .. _buildstatus: https://travis-ci.org/eerimoq/bitstruct .. |appveyor| image:: https://img.shields.io/appveyor/ci/eerimoq/bitstruct/master.svg?label=AppVeyor .. _appveyor: https://ci.appveyor.com/project/eerimoq/bitstruct/history .. |coverage| image:: https://coveralls.io/repos/github/eerimoq/bitstruct/badge.svg?branch=master .. _coverage: https://coveralls.io/github/eerimoq/bitstruct .. |codecov| image:: https://codecov.io/gh/eerimoq/bitstruct/branch/master/graph/badge.svg .. _codecov: https://codecov.io/gh/eerimoq/bitstruct .. _packing: http://bitstruct.readthedocs.io/en/latest/#bitstruct.pack .. _unpacking: http://bitstruct.readthedocs.io/en/latest/#bitstruct.unpack .. _pack: http://bitstruct.readthedocs.io/en/latest/#bitstruct.CompiledFormat.pack .. _unpack: http://bitstruct.readthedocs.io/en/latest/#bitstruct.CompiledFormat.unpack .. _pack into: http://bitstruct.readthedocs.io/en/latest/#bitstruct.pack_into .. _unpack from: http://bitstruct.readthedocs.io/en/latest/#bitstruct.unpack_from .. _pack_dict: http://bitstruct.readthedocs.io/en/latest/#bitstruct.pack_dict .. _unpack_dict: http://bitstruct.readthedocs.io/en/latest/#bitstruct.unpack_dict .. _byteswap: http://bitstruct.readthedocs.io/en/latest/#bitstruct.byteswap .. _compiling: http://bitstruct.readthedocs.io/en/latest/#bitstruct.compile .. _cbitstruct: https://github.com/qchateau/cbitstruct .. _MicroPython: https://github.com/micropython/micropython .. _bitstruct-micropython: https://github.com/peterzuger/bitstruct-micropython Keywords: bit field,bit parsing,bit unpack,bit pack Platform: UNKNOWN Classifier: License :: OSI Approved :: MIT License Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 3 bitstruct-8.9.0/bitstruct.egg-info/dependency_links.txt0000664000175000017500000000000113611423315023245 0ustar erikerik00000000000000 bitstruct-8.9.0/bitstruct.egg-info/SOURCES.txt0000664000175000017500000000061313611423315021063 0ustar erikerik00000000000000LICENSE MANIFEST.in Makefile README.rst setup.py bitstruct/__init__.py bitstruct/bitstream.c bitstruct/bitstream.h bitstruct/c.c bitstruct/version.py bitstruct.egg-info/PKG-INFO bitstruct.egg-info/SOURCES.txt bitstruct.egg-info/dependency_links.txt bitstruct.egg-info/top_level.txt docs/Makefile docs/conf.py docs/index.rst docs/make.bat tests/__init__.py tests/test_bitstruct.py tests/test_c.pybitstruct-8.9.0/bitstruct.egg-info/top_level.txt0000664000175000017500000000001213611423315021722 0ustar erikerik00000000000000bitstruct bitstruct-8.9.0/docs/0000775000175000017500000000000013611423315014412 5ustar erikerik00000000000000bitstruct-8.9.0/docs/index.rst0000664000175000017500000000252713514016570016264 0ustar erikerik00000000000000.. bitstruct documentation master file, created by sphinx-quickstart on Sat Apr 25 11:54:09 2015. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. .. toctree:: :maxdepth: 2 bitstruct - Interpret strings as packed binary data =================================================== .. include:: ../README.rst Functions ========= .. autofunction:: bitstruct.pack .. autofunction:: bitstruct.unpack .. autofunction:: bitstruct.pack_into .. autofunction:: bitstruct.unpack_from .. autofunction:: bitstruct.pack_dict .. autofunction:: bitstruct.unpack_dict .. autofunction:: bitstruct.pack_into_dict .. autofunction:: bitstruct.unpack_from_dict .. autofunction:: bitstruct.calcsize .. autofunction:: bitstruct.byteswap .. autofunction:: bitstruct.compile Classes ======= .. autoclass:: bitstruct.CompiledFormat .. automethod:: bitstruct.CompiledFormat.pack .. automethod:: bitstruct.CompiledFormat.unpack .. automethod:: bitstruct.CompiledFormat.pack_into .. automethod:: bitstruct.CompiledFormat.unpack_from .. autoclass:: bitstruct.CompiledFormatDict .. automethod:: bitstruct.CompiledFormatDict.pack .. automethod:: bitstruct.CompiledFormatDict.unpack .. automethod:: bitstruct.CompiledFormatDict.pack_into .. automethod:: bitstruct.CompiledFormatDict.unpack_from bitstruct-8.9.0/docs/make.bat0000664000175000017500000001612212760401517016025 0ustar erikerik00000000000000@ECHO OFF REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set BUILDDIR=_build set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . set I18NSPHINXOPTS=%SPHINXOPTS% . if NOT "%PAPER%" == "" ( set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% ) if "%1" == "" goto help if "%1" == "help" ( :help echo.Please use `make ^` where ^ is one of echo. html to make standalone HTML files echo. dirhtml to make HTML files named index.html in directories echo. singlehtml to make a single large HTML file echo. pickle to make pickle files echo. json to make JSON files echo. htmlhelp to make HTML files and a HTML help project echo. qthelp to make HTML files and a qthelp project echo. devhelp to make HTML files and a Devhelp project echo. epub to make an epub echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter echo. text to make text files echo. man to make manual pages echo. texinfo to make Texinfo files echo. gettext to make PO message catalogs echo. changes to make an overview over all changed/added/deprecated items echo. xml to make Docutils-native XML files echo. pseudoxml to make pseudoxml-XML files for display purposes echo. linkcheck to check all external links for integrity echo. doctest to run all doctests embedded in the documentation if enabled echo. coverage to run coverage check of the documentation if enabled goto end ) if "%1" == "clean" ( for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i del /q /s %BUILDDIR%\* goto end ) REM Check if sphinx-build is available and fallback to Python version if any %SPHINXBUILD% 2> nul if errorlevel 9009 goto sphinx_python goto sphinx_ok :sphinx_python set SPHINXBUILD=python -m sphinx.__init__ %SPHINXBUILD% 2> nul if errorlevel 9009 ( echo. echo.The 'sphinx-build' command was not found. Make sure you have Sphinx echo.installed, then set the SPHINXBUILD environment variable to point echo.to the full path of the 'sphinx-build' executable. Alternatively you echo.may add the Sphinx directory to PATH. echo. echo.If you don't have Sphinx installed, grab it from echo.http://sphinx-doc.org/ exit /b 1 ) :sphinx_ok if "%1" == "html" ( %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/html. goto end ) if "%1" == "dirhtml" ( %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. goto end ) if "%1" == "singlehtml" ( %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. goto end ) if "%1" == "pickle" ( %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the pickle files. goto end ) if "%1" == "json" ( %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the JSON files. goto end ) if "%1" == "htmlhelp" ( %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run HTML Help Workshop with the ^ .hhp project file in %BUILDDIR%/htmlhelp. goto end ) if "%1" == "qthelp" ( %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run "qcollectiongenerator" with the ^ .qhcp project file in %BUILDDIR%/qthelp, like this: echo.^> qcollectiongenerator %BUILDDIR%\qthelp\bitstruct.qhcp echo.To view the help file: echo.^> assistant -collectionFile %BUILDDIR%\qthelp\bitstruct.ghc goto end ) if "%1" == "devhelp" ( %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp if errorlevel 1 exit /b 1 echo. echo.Build finished. goto end ) if "%1" == "epub" ( %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub if errorlevel 1 exit /b 1 echo. echo.Build finished. The epub file is in %BUILDDIR%/epub. goto end ) if "%1" == "latex" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex if errorlevel 1 exit /b 1 echo. echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. goto end ) if "%1" == "latexpdf" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex make all-pdf cd %~dp0 echo. echo.Build finished; the PDF files are in %BUILDDIR%/latex. goto end ) if "%1" == "latexpdfja" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex make all-pdf-ja cd %~dp0 echo. echo.Build finished; the PDF files are in %BUILDDIR%/latex. goto end ) if "%1" == "text" ( %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text if errorlevel 1 exit /b 1 echo. echo.Build finished. The text files are in %BUILDDIR%/text. goto end ) if "%1" == "man" ( %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man if errorlevel 1 exit /b 1 echo. echo.Build finished. The manual pages are in %BUILDDIR%/man. goto end ) if "%1" == "texinfo" ( %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo if errorlevel 1 exit /b 1 echo. echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. goto end ) if "%1" == "gettext" ( %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale if errorlevel 1 exit /b 1 echo. echo.Build finished. The message catalogs are in %BUILDDIR%/locale. goto end ) if "%1" == "changes" ( %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes if errorlevel 1 exit /b 1 echo. echo.The overview file is in %BUILDDIR%/changes. goto end ) if "%1" == "linkcheck" ( %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck if errorlevel 1 exit /b 1 echo. echo.Link check complete; look for any errors in the above output ^ or in %BUILDDIR%/linkcheck/output.txt. goto end ) if "%1" == "doctest" ( %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest if errorlevel 1 exit /b 1 echo. echo.Testing of doctests in the sources finished, look at the ^ results in %BUILDDIR%/doctest/output.txt. goto end ) if "%1" == "coverage" ( %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage if errorlevel 1 exit /b 1 echo. echo.Testing of coverage in the sources finished, look at the ^ results in %BUILDDIR%/coverage/python.txt. goto end ) if "%1" == "xml" ( %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml if errorlevel 1 exit /b 1 echo. echo.Build finished. The XML files are in %BUILDDIR%/xml. goto end ) if "%1" == "pseudoxml" ( %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml if errorlevel 1 exit /b 1 echo. echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. goto end ) :end bitstruct-8.9.0/docs/Makefile0000664000175000017500000001637512760401517016072 0ustar erikerik00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # User-friendly check for sphinx-build ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) endif # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " applehelp to make an Apple Help Book" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of all changed/added/deprecated items" @echo " xml to make Docutils-native XML files" @echo " pseudoxml to make pseudoxml-XML files for display purposes" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" @echo " coverage to run coverage check of the documentation (if enabled)" clean: rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/bitstruct.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/bitstruct.qhc" applehelp: $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp @echo @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." @echo "N.B. You won't be able to view it unless you put it in" \ "~/Library/Documentation/Help or install it in your application" \ "bundle." devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/bitstruct" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/bitstruct" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." latexpdfja: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through platex and dvipdfmx..." $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." texinfo: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." info: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." gettext: $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." coverage: $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage @echo "Testing of coverage in the sources finished, look at the " \ "results in $(BUILDDIR)/coverage/python.txt." xml: $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml @echo @echo "Build finished. The XML files are in $(BUILDDIR)/xml." pseudoxml: $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml @echo @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." bitstruct-8.9.0/docs/conf.py0000664000175000017500000002212113432214052015704 0ustar erikerik00000000000000# -*- coding: utf-8 -*- # # bitstruct documentation build configuration file, created by # sphinx-quickstart on Sat Apr 25 11:54:09 2015. # # This file is execfile()d with the current directory set to its # containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys import os import shlex # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. sys.path.insert(0, os.path.abspath('..')) import bitstruct # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ 'sphinx.ext.autodoc', 'sphinx.ext.viewcode', ] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # source_suffix = ['.rst', '.md'] source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = u'bitstruct' copyright = u'2015-2019, Erik Moqvist' author = u'Erik Moqvist' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = bitstruct.__version__ # The full version, including alpha/beta/rc tags. release = bitstruct.__version__ # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = ['_build'] # The reST default role (used for this markup: `text`) to use for all # documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # If true, keep warnings as "system message" paragraphs in the built documents. #keep_warnings = False # If true, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = False # -- Options for HTML output ---------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'sphinx_rtd_theme' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied # directly to the root of the documentation. #html_extra_path = [] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_domain_indices = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. #html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Language to be used for generating the HTML full-text search index. # Sphinx supports the following languages: # 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' # 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr' #html_search_language = 'en' # A dictionary with options for the search language support, empty by default. # Now only 'ja' uses this config value #html_search_options = {'type': 'default'} # The name of a javascript file (relative to the configuration directory) that # implements a search results scorer. If empty, the default will be used. #html_search_scorer = 'scorer.js' # Output file base name for HTML help builder. htmlhelp_basename = 'bitstructdoc' # -- Options for LaTeX output --------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). #'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). #'pointsize': '10pt', # Additional stuff for the LaTeX preamble. #'preamble': '', # Latex figure (float) alignment #'figure_align': 'htbp', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ (master_doc, 'bitstruct.tex', u'bitstruct Documentation', u'Erik Moqvist', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output --------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ (master_doc, 'bitstruct', u'bitstruct Documentation', [author], 1) ] # If true, show URL addresses after external links. #man_show_urls = False # -- Options for Texinfo output ------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ (master_doc, 'bitstruct', u'bitstruct Documentation', author, 'bitstruct', 'One line description of project.', 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. #texinfo_appendices = [] # If false, no module index is generated. #texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. #texinfo_show_urls = 'footnote' # If true, do not generate a @detailmenu in the "Top" node's menu. #texinfo_no_detailmenu = False bitstruct-8.9.0/README.rst0000664000175000017500000001566113611423043015160 0ustar erikerik00000000000000|buildstatus|_ |appveyor|_ |coverage|_ |codecov|_ About ===== This module is intended to have a similar interface as the python struct module, but working on bits instead of primitive data types (char, int, ...). Project homepage: https://github.com/eerimoq/bitstruct Documentation: https://bitstruct.readthedocs.io Installation ============ .. code-block:: python pip install bitstruct Performance =========== Parts of this package has been re-implemented in C for faster pack and unpack operations. There are two independent C implementations; `bitstruct.c`, which is part of this package, and the standalone package `cbitstruct`_. These implementations are only available in Python 3, and must be explicitly imported. By default the pure Python implementation is used. To use `bitstruct.c`, do ``import bitstruct.c as bitstruct``. To use `cbitstruct`_, do ``import cbitstruct as bitstruct``. `bitstruct.c` has a few limitations compared to the pure Python implementation: - Integers and booleans must be 64 bits or less. - Text and raw must be a multiple of 8 bits. - Bit endianness and byte order are not yet supported. - ``byteswap()`` can only swap 1, 2, 4 and 8 bytes. See `cbitstruct`_ for its limitations. MicroPython =========== The C implementation has been ported to `MicroPython`_. See `bitstruct-micropython`_ for more details. Example usage ============= A basic example of `packing`_ and `unpacking`_ four integers using the format string ``'u1u3u4s16'``: .. code-block:: python >>> from bitstruct import * >>> pack('u1u3u4s16', 1, 2, 3, -4) b'\xa3\xff\xfc' >>> unpack('u1u3u4s16', b'\xa3\xff\xfc') (1, 2, 3, -4) >>> calcsize('u1u3u4s16') 24 An example `compiling`_ the format string once, and use it to `pack`_ and `unpack`_ data: .. code-block:: python >>> import bitstruct >>> cf = bitstruct.compile('u1u3u4s16') >>> cf.pack(1, 2, 3, -4) b'\xa3\xff\xfc' >>> cf.unpack(b'\xa3\xff\xfc') (1, 2, 3, -4) Use the `pack into`_ and `unpack from`_ functions to pack/unpack values at a bit offset into the data, in this example the bit offset is 5: .. code-block:: python >>> from bitstruct import * >>> data = bytearray(b'\x00\x00\x00\x00') >>> pack_into('u1u3u4s16', data, 5, 1, 2, 3, -4) >>> data bytearray(b'\x05\x1f\xff\xe0') >>> unpack_from('u1u3u4s16', data, 5) (1, 2, 3, -4) The unpacked values can be named by assigning them to variables or by wrapping the result in a named tuple: .. code-block:: python >>> from bitstruct import * >>> from collections import namedtuple >>> MyName = namedtuple('myname', ['a', 'b', 'c', 'd']) >>> unpacked = unpack('u1u3u4s16', b'\xa3\xff\xfc') >>> myname = MyName(*unpacked) >>> myname myname(a=1, b=2, c=3, d=-4) >>> myname.c 3 Use the `pack_dict`_ and `unpack_dict`_ functions to pack/unpack values in dictionaries: .. code-block:: python >>> from bitstruct import * >>> names = ['a', 'b', 'c', 'd'] >>> pack_dict('u1u3u4s16', names, {'a': 1, 'b': 2, 'c': 3, 'd': -4}) b'\xa3\xff\xfc' >>> unpack_dict('u1u3u4s16', names, b'\xa3\xff\xfc') {'a': 1, 'b': 2, 'c': 3, 'd': -4} An example of `packing`_ and `unpacking`_ an unsigned integer, a signed integer, a float, a boolean, a byte string and a string: .. code-block:: python >>> from bitstruct import * >>> pack('u5s5f32b1r13t40', 1, -1, 3.75, True, b'\xff\xff', 'hello') b'\x0f\xd0\x1c\x00\x00?\xffhello' >>> unpack('u5s5f32b1r13t40', b'\x0f\xd0\x1c\x00\x00?\xffhello') (1, -1, 3.75, True, b'\xff\xf8', 'hello') >>> calcsize('u5s5f32b1r13t40') 96 The same format string and values as in the previous example, but using LSB (Least Significant Bit) first instead of the default MSB (Most Significant Bit) first: .. code-block:: python >>> from bitstruct import * >>> pack('>> unpack('>> calcsize('>> from bitstruct import * >>> from binascii import unhexlify >>> unpack('s17s13r24', unhexlify('0123456789abcdef')) (582, -3751, b'\xe2j\xf3') >>> with open("test.bin", "rb") as fin: ... unpack('s17s13r24', fin.read(8)) ... ... (582, -3751, b'\xe2j\xf3') Change endianness of the data with `byteswap`_, and then unpack the values: .. code-block:: python >>> from bitstruct import * >>> packed = pack('u1u3u4s16', 1, 2, 3, 1) >>> unpack('u1u3u4s16', byteswap('12', packed)) (1, 2, 3, 256) A basic example of `packing`_ and `unpacking`_ four integers using the format string ``'u1u3u4s16'`` using the C implementation: .. code-block:: python >>> from bitstruct.c import * >>> pack('u1u3u4s16', 1, 2, 3, -4) b'\xa3\xff\xfc' >>> unpack('u1u3u4s16', b'\xa3\xff\xfc') (1, 2, 3, -4) Contributing ============ #. Fork the repository. #. Install prerequisites. .. code-block:: text pip install -r requirements.txt #. Implement the new feature or bug fix. #. Implement test case(s) to ensure that future changes do not break legacy. #. Run the tests. .. code-block:: text make test #. Create a pull request. .. |buildstatus| image:: https://travis-ci.org/eerimoq/bitstruct.svg .. _buildstatus: https://travis-ci.org/eerimoq/bitstruct .. |appveyor| image:: https://img.shields.io/appveyor/ci/eerimoq/bitstruct/master.svg?label=AppVeyor .. _appveyor: https://ci.appveyor.com/project/eerimoq/bitstruct/history .. |coverage| image:: https://coveralls.io/repos/github/eerimoq/bitstruct/badge.svg?branch=master .. _coverage: https://coveralls.io/github/eerimoq/bitstruct .. |codecov| image:: https://codecov.io/gh/eerimoq/bitstruct/branch/master/graph/badge.svg .. _codecov: https://codecov.io/gh/eerimoq/bitstruct .. _packing: http://bitstruct.readthedocs.io/en/latest/#bitstruct.pack .. _unpacking: http://bitstruct.readthedocs.io/en/latest/#bitstruct.unpack .. _pack: http://bitstruct.readthedocs.io/en/latest/#bitstruct.CompiledFormat.pack .. _unpack: http://bitstruct.readthedocs.io/en/latest/#bitstruct.CompiledFormat.unpack .. _pack into: http://bitstruct.readthedocs.io/en/latest/#bitstruct.pack_into .. _unpack from: http://bitstruct.readthedocs.io/en/latest/#bitstruct.unpack_from .. _pack_dict: http://bitstruct.readthedocs.io/en/latest/#bitstruct.pack_dict .. _unpack_dict: http://bitstruct.readthedocs.io/en/latest/#bitstruct.unpack_dict .. _byteswap: http://bitstruct.readthedocs.io/en/latest/#bitstruct.byteswap .. _compiling: http://bitstruct.readthedocs.io/en/latest/#bitstruct.compile .. _cbitstruct: https://github.com/qchateau/cbitstruct .. _MicroPython: https://github.com/micropython/micropython .. _bitstruct-micropython: https://github.com/peterzuger/bitstruct-micropython bitstruct-8.9.0/tests/0000775000175000017500000000000013611423315014624 5ustar erikerik00000000000000bitstruct-8.9.0/tests/test_c.py0000664000175000017500000005420013547357566016506 0ustar erikerik00000000000000from __future__ import print_function import sys import timeit import unittest if sys.version_info[0] < 3: print('Skipping C extension tests in Python 2.') else: import bitstruct.c from bitstruct.c import * class CTest(unittest.TestCase): def test_pack(self): """Pack values. """ if sys.version_info[0] < 3: return packed = pack('u1u1s6u7u9', 0, 0, -2, 65, 22) self.assertEqual(packed, b'\x3e\x82\x16') packed = pack('u1', 1) self.assertEqual(packed, b'\x80') with self.assertRaises(NotImplementedError): packed = pack('u77', 0x100000000001000000) ref = b'\x00\x80\x00\x00\x00\x00\x08\x00\x00\x00' self.assertEqual(packed, ref) with self.assertRaises(NotImplementedError): packed = pack('u8000', int(8000 * '1', 2)) ref = 1000 * b'\xff' self.assertEqual(packed, ref) with self.assertRaises(NotImplementedError): packed = pack('s4000', int(8000 * '0', 2)) ref = 500 * b'\x00' self.assertEqual(packed, ref) packed = pack('p1u1s6u7u9', 0, -2, 65, 22) self.assertEqual(packed, b'\x3e\x82\x16') packed = pack('P1u1s6u7u9', 0, -2, 65, 22) self.assertEqual(packed, b'\xbe\x82\x16') packed = pack('p1u1s6p7u9', 0, -2, 22) self.assertEqual(packed, b'\x3e\x00\x16') packed = pack('P1u1s6p7u9', 0, -2, 22) self.assertEqual(packed, b'\xbe\x00\x16') with self.assertRaises(NotImplementedError): packed = pack('u1s6f32r43', 0, -2, 3.75, b'\x00\xff\x00\xff\x00\xff') self.assertEqual(packed, b'\x7c\x80\xe0\x00\x00\x01\xfe\x01\xfe\x01\xc0') packed = pack('b1', True) self.assertEqual(packed, b'\x80') packed = pack('b1p6b1', True, True) self.assertEqual(packed, b'\x81') packed = pack('b1P6b1', True, True) self.assertEqual(packed, b'\xff') packed = pack('u5b2u1', 31, False, 1) self.assertEqual(packed, b'\xf9') packed = pack('b1t24', False, u'Hi!') self.assertEqual(packed, b'$4\x90\x80') packed = pack('b1t24', False, 'Hi!') self.assertEqual(packed, b'$4\x90\x80') packed = pack('t8000', 1000 * '7') self.assertEqual(packed, 1000 * b'\x37') if sys.version_info >= (3, 6): packed = pack('f16', 1.0) self.assertEqual(packed, b'\x3c\x00') packed = pack('f32', 1.0) self.assertEqual(packed, b'\x3f\x80\x00\x00') packed = pack('f64', 1.0) self.assertEqual(packed, b'\x3f\xf0\x00\x00\x00\x00\x00\x00') def test_unpack(self): """Unpack values. """ if sys.version_info[0] < 3: return unpacked = unpack('u1u1s6u7u9', b'\x3e\x82\x16') self.assertEqual(unpacked, (0, 0, -2, 65, 22)) # unpacked = unpack('u1', bytearray(b'\x80')) unpacked = unpack('u1', b'\x80') self.assertEqual(unpacked, (1, )) with self.assertRaises(NotImplementedError): packed = b'\x00\x80\x00\x00\x00\x00\x08\x00\x00\x00' unpacked = unpack('u77', packed) self.assertEqual(unpacked, (0x100000000001000000,)) with self.assertRaises(NotImplementedError): packed = 1000 * b'\xff' unpacked = unpack('u8000', packed) self.assertEqual(unpacked, (int(8000 * '1', 2), )) with self.assertRaises(NotImplementedError): packed = 500 * b'\x00' unpacked = unpack('s4000', packed) self.assertEqual(unpacked, (0, )) packed = b'\xbe\x82\x16' unpacked = unpack('P1u1s6u7u9', packed) self.assertEqual(unpacked, (0, -2, 65, 22)) packed = b'\x3e\x82\x16' unpacked = unpack('P1u1s6u7u9', packed) self.assertEqual(unpacked, (0, -2, 65, 22)) packed = b'\xbe\x82\x16' unpacked = unpack('p1u1s6u7u9', packed) self.assertEqual(unpacked, (0, -2, 65, 22)) packed = b'\x3e\x82\x16' unpacked = unpack('p1u1s6u7u9', packed) self.assertEqual(unpacked, (0, -2, 65, 22)) packed = b'\x3e\x82\x16' unpacked = unpack('p1u1s6p7u9', packed) self.assertEqual(unpacked, (0, -2, 22)) with self.assertRaises(NotImplementedError): packed = b'\x7c\x80\xe0\x00\x00\x01\xfe\x01\xfe\x01\xc0' unpacked = unpack('u1s6f32r43', packed) self.assertEqual(unpacked, (0, -2, 3.75, b'\x00\xff\x00\xff\x00\xe0')) # packed = bytearray(b'\x80') packed = b'\x80' unpacked = unpack('b1', packed) self.assertEqual(unpacked, (True, )) packed = b'\x80' unpacked = unpack('b1p6b1', packed) self.assertEqual(unpacked, (True, False)) packed = b'\x06' unpacked = unpack('u5b2u1', packed) self.assertEqual(unpacked, (0, True, 0)) packed = b'\x04' unpacked = unpack('u5b2u1', packed) self.assertEqual(unpacked, (0, True, 0)) packed = b'$4\x90\x80' unpacked = unpack('b1t24', packed) self.assertEqual(unpacked, (False, u'Hi!')) packed = 1000 * b'7' unpacked = unpack('t8000', packed) self.assertEqual(packed, 1000 * b'\x37') if sys.version_info >= (3, 6): unpacked = unpack('f16', b'\x3c\x00') self.assertEqual(unpacked, (1.0, )) unpacked = unpack('f32', b'\x3f\x80\x00\x00') self.assertEqual(unpacked, (1.0, )) unpacked = unpack('f64', b'\x3f\xf0\x00\x00\x00\x00\x00\x00') self.assertEqual(unpacked, (1.0, )) def test_pack_unpack(self): """Pack and unpack values. """ if sys.version_info[0] < 3: return packed = pack('u1u1s6u7u9', 0, 0, -2, 65, 22) unpacked = unpack('u1u1s6u7u9', packed) self.assertEqual(unpacked, (0, 0, -2, 65, 22)) packed = pack('f64', 1.0) unpacked = unpack('f64', packed) self.assertEqual(unpacked, (1.0, )) if sys.version_info >= (3, 6): packed = pack('f16', 1.0) unpacked = unpack('f16', packed) self.assertEqual(unpacked, (1.0, )) def test_calcsize(self): """Calculate size. """ if sys.version_info[0] < 3: return size = calcsize('u1u1s6u7u9') self.assertEqual(size, 24) size = calcsize('u1') self.assertEqual(size, 1) size = calcsize('u1s6u7u9') self.assertEqual(size, 23) size = calcsize('b1s6u7u9p1t8') self.assertEqual(size, 32) size = calcsize('b1s6u7u9P1t8') self.assertEqual(size, 32) def test_compiled_calcsize(self): """Calculate size. """ if sys.version_info[0] < 3: return cf = bitstruct.c.compile('u1u1s6u7u9') self.assertEqual(cf.calcsize(), 24) cf = bitstruct.c.compile('u1u1s6u7u9', ['a', 'b', 'c', 'd', 'e']) self.assertEqual(cf.calcsize(), 24) def test_byteswap(self): """Byte swap. """ if sys.version_info[0] < 3: return res = b'\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a' ref = b'\x01\x03\x02\x04\x08\x07\x06\x05\x0a\x09' self.assertEqual(byteswap('12142', ref), res) packed = pack('u1u5u2u16', 1, 2, 3, 4) unpacked = unpack('u1u5u2u16', byteswap('12', packed)) self.assertEqual(unpacked, (1, 2, 3, 1024)) res = b'\x01\x02\x03\x04\x05\x06\x07\x08' ref = b'\x08\x07\x06\x05\x04\x03\x02\x01' self.assertEqual(byteswap('8', ref), res) def test_pack_into(self): """Pack values into a buffer. """ if sys.version_info[0] < 3: return packed = bytearray(3) pack_into('u1u1s6u7u9', packed, 0, 0, 0, -2, 65, 22) self.assertEqual(packed, b'\x3e\x82\x16') datas = [ (0, b'\x80\x00'), (1, b'\x40\x00'), (7, b'\x01\x00'), (15, b'\x00\x01') ] for offset, expected in datas: packed = bytearray(2) pack_into('u1', packed, offset, 1) self.assertEqual(packed, expected) with self.assertRaises(AssertionError): packed = bytearray(b'\xff\xff\xff') pack_into('p4u4p4u4p4u4', packed, 0, 1, 2, 3, fill_padding=False) self.assertEqual(packed, b'\xf1\xf2\xf3') packed = bytearray(b'\xff\xff\xff') pack_into('p4u4p4u4p4u4', packed, 0, 1, 2, 3, fill_padding=True) self.assertEqual(packed, b'\x01\x02\x03') packed = bytearray(2) with self.assertRaises(ValueError) as cm: pack_into('u17', packed, 0, 1) self.assertEqual(str(cm.exception), 'pack_into requires a buffer of at least 17 bits') packed = bytearray(b'\x00') pack_into('P4u4', packed, 0, 1) self.assertEqual(packed, b'\xf1') datas = [ (0, b'\x7f\xff\xff\xff'), (1, b'\xbf\xff\xff\xff'), (7, b'\xfe\xff\xff\xff'), (8, b'\xff\x7f\xff\xff'), (15, b'\xff\xfe\xff\xff'), (16, b'\xff\xff\x7f\xff'), (31, b'\xff\xff\xff\xfe') ] for offset, expected in datas: packed = bytearray(b'\xff\xff\xff\xff') pack_into('u1', packed, offset, 0) self.assertEqual(packed, expected) # Check for non-writable buffer. with self.assertRaises(TypeError): pack_into('u1', b'\x00', 0, 0) def test_unpack_from(self): """Unpack values at given bit offset. """ if sys.version_info[0] < 3: return unpacked = unpack_from('u1u1s6u7u9', b'\x1f\x41\x0b\x00', 1) self.assertEqual(unpacked, (0, 0, -2, 65, 22)) unpacked = unpack_from('u1', b'\x80') self.assertEqual(unpacked, (1, )) unpacked = unpack_from('u1', b'\x08', 4) self.assertEqual(unpacked, (1, )) with self.assertRaises(ValueError): unpack_from('u1', b'\xff', 8) with self.assertRaises(TypeError): unpack_from('u1', b'\xff', None) def test_compiled_pack_into(self): """Pack values at given bit offset. """ if sys.version_info[0] < 3: return cf = bitstruct.c.compile('u2') packed = bytearray(2) cf.pack_into(packed, 7, 3) self.assertEqual(packed, b'\x01\x80') def test_compiled_unpack_from(self): """Unpack values at given bit offset. """ if sys.version_info[0] < 3: return cf = bitstruct.c.compile('u1') unpacked = cf.unpack_from(b'\x40', 1) self.assertEqual(unpacked, (1, )) unpacked = cf.unpack_from(b'\x80') self.assertEqual(unpacked, (1, )) def test_pack_unpack_raw(self): """Pack and unpack raw values. """ if sys.version_info[0] < 3: return with self.assertRaises(NotImplementedError): packed = pack('r24', b'') self.assertEqual(packed, b'\x00\x00\x00') with self.assertRaises(NotImplementedError): packed = pack('r24', b'12') self.assertEqual(packed, b'12\x00') packed = pack('r24', b'123') self.assertEqual(packed, b'123') packed = pack('r24', b'1234') self.assertEqual(packed, b'123') unpacked = unpack('r24', b'\x00\x00\x00')[0] self.assertEqual(unpacked, b'\x00\x00\x00') unpacked = unpack('r24', b'12\x00')[0] self.assertEqual(unpacked, b'12\x00') unpacked = unpack('r24', b'123')[0] self.assertEqual(unpacked, b'123') unpacked = unpack('r24', b'1234')[0] self.assertEqual(unpacked, b'123') def test_pack_unpack_dict(self): if sys.version_info[0] < 3: return unpacked = { 'foo': 0, 'bar': 0, 'fie': -2, 'fum': 65, 'fam': 22 } packed = b'\x3e\x82\x16' fmt = 'u1u1s6u7u9' names = ['foo', 'bar', 'fie', 'fum', 'fam'] self.assertEqual(pack_dict(fmt, names, unpacked), packed) self.assertEqual(unpack_dict(fmt, names, packed), unpacked) def test_pack_into_unpack_from_dict(self): if sys.version_info[0] < 3: return unpacked = { 'foo': 0, 'bar': 0, 'fie': -2, 'fum': 65, 'fam': 22 } packed = b'\x3e\x82\x16' fmt = 'u1u1s6u7u9' names = ['foo', 'bar', 'fie', 'fum', 'fam'] actual = bytearray(3) pack_into_dict(fmt, names, actual, 0, unpacked) self.assertEqual(actual, packed) self.assertEqual(unpack_from_dict(fmt, names, packed), unpacked) def test_compiled_pack_into_unpack_from_dict(self): if sys.version_info[0] < 3: return unpacked = { 'foo': 0, 'bar': 0, 'fie': -2, 'fum': 65, 'fam': 22 } packed = b'\x3e\x82\x16' fmt = 'u1u1s6u7u9' names = ['foo', 'bar', 'fie', 'fum', 'fam'] cf = bitstruct.c.compile(fmt, names) actual = bytearray(3) cf.pack_into(actual, 0, unpacked) self.assertEqual(actual, packed) self.assertEqual(cf.unpack_from(packed), unpacked) def test_compile(self): if sys.version_info[0] < 3: return cf = bitstruct.c.compile('u1u1s6u7u9') packed = cf.pack(0, 0, -2, 65, 22) self.assertEqual(packed, b'\x3e\x82\x16') unpacked = cf.unpack(b'\x3e\x82\x16') self.assertEqual(unpacked, (0, 0, -2, 65, 22)) def test_compile_pack_unpack_formats(self): if sys.version_info[0] < 3: return fmts = [ ('u1s2p3', None, (1, -1)), ('u1 s2 p3', None, (1, -1)), ('u1s2p3', ['a', 'b'], {'a': 1, 'b': -1}) ] for fmt, names, decoded in fmts: if names is None: cf = bitstruct.c.compile(fmt) packed_1 = cf.pack(*decoded) packed_2 = pack(fmt, *decoded) else: cf = bitstruct.c.compile(fmt, names) packed_1 = cf.pack(decoded) packed_2 = pack_dict(fmt, names, decoded) self.assertEqual(packed_1, b'\xe0') self.assertEqual(packed_2, b'\xe0') if names is None: unpacked_1 = cf.unpack(packed_1) unpacked_2 = unpack(fmt, packed_2) else: unpacked_1 = cf.unpack(packed_1) unpacked_2 = unpack_dict(fmt, names, packed_2) self.assertEqual(unpacked_1, decoded) self.assertEqual(unpacked_2, decoded) def test_compile_formats(self): if sys.version_info[0] < 3: return bitstruct.c.compile('p1u1') bitstruct.c.compile('p1u1', ['a']) with self.assertRaises(TypeError): bitstruct.c.compile() def test_pack_unpack_signed(self): if sys.version_info[0] < 3: return datas = [ ('s1', 0, b'\x00'), ('s1', -1, b'\x80'), ('s63', -1, b'\xff\xff\xff\xff\xff\xff\xff\xfe'), ('s64', -1, b'\xff\xff\xff\xff\xff\xff\xff\xff') ] for fmt, value, packed in datas: self.assertEqual(pack(fmt, value), packed) self.assertEqual(unpack(fmt, packed), (value, )) def test_pack_unpack_unsigned(self): if sys.version_info[0] < 3: return datas = [ ('u1', 0, b'\x00'), ('u1', 1, b'\x80'), ('u63', 0x1234567890abcdef, b'$h\xac\xf1!W\x9b\xde'), ('u64', 0x1234567890abcdef, b'\x124Vx\x90\xab\xcd\xef') ] for fmt, value, packed in datas: self.assertEqual(pack(fmt, value), packed) self.assertEqual(unpack(fmt, packed), (value, )) def test_various(self): if sys.version_info[0] < 3: return with self.assertRaises(ValueError): pack('u89999888888888888888899', 1) # Fewer names than fields in the format. with self.assertRaises(ValueError): pack_dict('u1u1', ['foo'], {'foo': 1}) # Missing value for name. with self.assertRaises(KeyError): pack_dict('u1', ['foo'], {}) # Fewer names than fields in the format. with self.assertRaises(ValueError): unpack_dict('u1u1', ['foo'], b'\xff') # Short data. with self.assertRaises(ValueError): unpack_dict('u1', ['foo'], b'') # Padding last. self.assertEqual(pack('u1p1', 1), b'\x80') self.assertEqual(pack_dict('u1p1', ['foo'], {'foo': 1}), b'\x80') # Short text. with self.assertRaises(NotImplementedError) as cm: pack('t16', '1') self.assertEqual(str(cm.exception), 'Short text.') # Bad float length. with self.assertRaises(NotImplementedError) as cm: pack('f1', 1.0) if sys.version_info >= (3, 6): self.assertEqual(str(cm.exception), 'Float not 16, 32 or 64 bits.') else: self.assertEqual(str(cm.exception), 'Float not 32 or 64 bits.') # Long bool. with self.assertRaises(NotImplementedError) as cm: pack('b65', True) self.assertEqual(str(cm.exception), 'Bool over 64 bits.') # Text not multiple of 8 bits. with self.assertRaises(NotImplementedError) as cm: pack('t1', '') self.assertEqual(str(cm.exception), 'Text not multiple of 8 bits.') # Bad format kind. with self.assertRaises(ValueError) as cm: pack('x1', '') self.assertEqual(str(cm.exception), "Bad format field type 'x'.") # Too few arguments. with self.assertRaises(ValueError) as cm: pack('u1u1', 1) self.assertEqual(str(cm.exception), 'Too few arguments.') # No format string. with self.assertRaises(ValueError) as cm: pack() self.assertEqual(str(cm.exception), 'No format string.') # No format string. with self.assertRaises(ValueError) as cm: unpack('u1', b'') self.assertEqual(str(cm.exception), 'Short data.') # Bad format in compile. with self.assertRaises(ValueError) as cm: bitstruct.c.compile('x1') self.assertEqual(str(cm.exception), "Bad format field type 'x'.") # Bad format in compile dict. with self.assertRaises(ValueError) as cm: bitstruct.c.compile('x1', ['foo']) self.assertEqual(str(cm.exception), "Bad format field type 'x'.") # Offset too big. with self.assertRaises(ValueError) as cm: packed = bytearray(1) pack_into('u1', packed, 0x80000000, 1) self.assertIn("Offset must be less or equal to ", str(cm.exception)) # Offset too big. with self.assertRaises(ValueError) as cm: packed = bytearray(1) pack_into_dict('u1', ['a'], packed, 0x80000000, {'a': 1}) self.assertIn("Offset must be less or equal to ", str(cm.exception)) # Offset too big. with self.assertRaises(ValueError) as cm: unpack_from('u1', b'\x00', 0x80000000) self.assertIn("Offset must be less or equal to ", str(cm.exception)) # Offset too big. with self.assertRaises(ValueError) as cm: packed = bytearray(1) unpack_from_dict('u1', ['a'], b'\x00', 0x80000000) self.assertIn("Offset must be less or equal to ", str(cm.exception)) # Out of data to swap. datas = ['11', '2', '4', '8'] for fmt in datas: with self.assertRaises(ValueError) as cm: byteswap(fmt, b'\x00') self.assertEqual(str(cm.exception), 'Out of data to swap.') # Bad swap format. with self.assertRaises(ValueError) as cm: byteswap('3', b'\x00') # Bad swap format type. with self.assertRaises(TypeError): byteswap(None, b'\x00') self.assertEqual(str(cm.exception), 'Expected 1, 2, 4 or 8, but got 3.') # Bad format type. with self.assertRaises(TypeError): pack(None, 1) # Out of range checks. datas = [ ('s64', (1 << 63)), ('s64', -(1 << 63) - 1), ('u64', 1 << 64), ('u64', -1), ('u1', 2), ('s1', 1), ('s1', -2), ('s2', 2) ] for fmt, value in datas: with self.assertRaises(OverflowError) as cm: pack(fmt, value) # Bad value types. with self.assertRaises(TypeError) as cm: pack('s1', None) with self.assertRaises(TypeError) as cm: pack('u1', None) with self.assertRaises(TypeError) as cm: pack('f32', None) with self.assertRaises(TypeError) as cm: pack('r8', None) with self.assertRaises(TypeError) as cm: pack('t8', None) # Everything can be bool. self.assertEqual(pack('b8', None), b'\x00') # Zero bits bool. with self.assertRaises(ValueError) as cm: pack('b0', None) self.assertEqual(str(cm.exception), 'Field of size 0.') # pack/unpack dict with names as a non-list. Caused an segfault. with self.assertRaises(TypeError) as cm: pack_into_dict('u1', None, bytearray(b'\x00'), 0, {'a': 1}) self.assertEqual(str(cm.exception), 'Names is not a list.') with self.assertRaises(TypeError) as cm: pack_dict('u1', None, {'a': 1}) self.assertEqual(str(cm.exception), 'Names is not a list.') with self.assertRaises(TypeError) as cm: bitstruct.c.compile('u1', 1) self.assertEqual(str(cm.exception), 'Names is not a list.') def test_whitespaces(self): if sys.version_info[0] < 3: return fmts = [ ' ', ' u1 s2 p3 ' ] for fmt in fmts: bitstruct.c.compile(fmt) if __name__ == '__main__': unittest.main() bitstruct-8.9.0/tests/__init__.py0000664000175000017500000000000012760401517016727 0ustar erikerik00000000000000bitstruct-8.9.0/tests/test_bitstruct.py0000664000175000017500000005545613545135661020311 0ustar erikerik00000000000000from __future__ import print_function import sys import timeit import unittest from bitstruct import * import bitstruct class BitStructTest(unittest.TestCase): def test_pack(self): """Pack values. """ packed = pack('u1u1s6u7u9', 0, 0, -2, 65, 22) self.assertEqual(packed, b'\x3e\x82\x16') packed = pack('u1', 1) self.assertEqual(packed, b'\x80') packed = pack('u77', 0x100000000001000000) ref = b'\x00\x80\x00\x00\x00\x00\x08\x00\x00\x00' self.assertEqual(packed, ref) packed = pack('u8000', int(8000 * '1', 2)) ref = 1000 * b'\xff' self.assertEqual(packed, ref) packed = pack('s4000', int(8000 * '0', 2)) ref = 500 * b'\x00' self.assertEqual(packed, ref) packed = pack('p1u1s6u7u9', 0, -2, 65, 22) self.assertEqual(packed, b'\x3e\x82\x16') packed = pack('P1u1s6u7u9', 0, -2, 65, 22) self.assertEqual(packed, b'\xbe\x82\x16') packed = pack('p1u1s6p7u9', 0, -2, 22) self.assertEqual(packed, b'\x3e\x00\x16') packed = pack('P1u1s6p7u9', 0, -2, 22) self.assertEqual(packed, b'\xbe\x00\x16') packed = pack('u1s6f32r43', 0, -2, 3.75, b'\x00\xff\x00\xff\x00\xff') self.assertEqual(packed, b'\x7c\x80\xe0\x00\x00\x01\xfe\x01\xfe\x01\xc0') packed = pack('b1', True) self.assertEqual(packed, b'\x80') packed = pack('b1p6b1', True, True) self.assertEqual(packed, b'\x81') packed = pack('b1P6b1', True, True) self.assertEqual(packed, b'\xff') packed = pack('u5b2u1', 31, False, 1) self.assertEqual(packed, b'\xf9') packed = pack('b1t24', False, u'Hi!') self.assertEqual(packed, b'$4\x90\x80') packed = pack('b1t24', False, 'Hi!') self.assertEqual(packed, b'$4\x90\x80') packed = pack('t8000', 1000 * '7') self.assertEqual(packed, 1000 * b'\x37') if sys.version_info >= (3, 6): packed = pack('f16', 1.0) self.assertEqual(packed, b'\x3c\x00') packed = pack('f32', 1.0) self.assertEqual(packed, b'\x3f\x80\x00\x00') packed = pack('f64', 1.0) self.assertEqual(packed, b'\x3f\xf0\x00\x00\x00\x00\x00\x00') # Too many values to pack. with self.assertRaises(Error) as cm: pack('b1t24', False) self.assertEqual(str(cm.exception), 'pack expected 2 item(s) for packing (got 1)') # Cannot convert argument to integer. with self.assertRaises(ValueError) as cm: pack('u1', 'foo') self.assertEqual(str(cm.exception), "invalid literal for int() with base 10: 'foo'") # Cannot convert argument to float. with self.assertRaises(ValueError) as cm: pack('f32', 'foo') if sys.version_info[0] < 3: self.assertEqual(str(cm.exception), 'could not convert string to float: foo') else: self.assertEqual(str(cm.exception), "could not convert string to float: 'foo'") # Cannot convert argument to bytearray. with self.assertRaises(TypeError) as cm: pack('r5', 1.0) self.assertEqual(str(cm.exception), "object of type 'float' has no len()") # Cannot encode argument as utf-8. with self.assertRaises(AttributeError) as cm: pack('t8', 1.0) self.assertEqual(str(cm.exception), "'float' object has no attribute 'encode'") def test_unpack(self): """Unpack values. """ unpacked = unpack('u1u1s6u7u9', b'\x3e\x82\x16') self.assertEqual(unpacked, (0, 0, -2, 65, 22)) unpacked = unpack('u1', bytearray(b'\x80')) self.assertEqual(unpacked, (1, )) packed = b'\x00\x80\x00\x00\x00\x00\x08\x00\x00\x00' unpacked = unpack('u77', packed) self.assertEqual(unpacked, (0x100000000001000000,)) packed = 1000 * b'\xff' unpacked = unpack('u8000', packed) self.assertEqual(unpacked, (int(8000 * '1', 2), )) packed = 500 * b'\x00' unpacked = unpack('s4000', packed) self.assertEqual(unpacked, (0, )) packed = b'\xbe\x82\x16' unpacked = unpack('P1u1s6u7u9', packed) self.assertEqual(unpacked, (0, -2, 65, 22)) packed = b'\x3e\x82\x16' unpacked = unpack('P1u1s6u7u9', packed) self.assertEqual(unpacked, (0, -2, 65, 22)) packed = b'\xbe\x82\x16' unpacked = unpack('p1u1s6u7u9', packed) self.assertEqual(unpacked, (0, -2, 65, 22)) packed = b'\x3e\x82\x16' unpacked = unpack('p1u1s6u7u9', packed) self.assertEqual(unpacked, (0, -2, 65, 22)) packed = b'\x3e\x82\x16' unpacked = unpack('p1u1s6p7u9', packed) self.assertEqual(unpacked, (0, -2, 22)) packed = b'\x7c\x80\xe0\x00\x00\x01\xfe\x01\xfe\x01\xc0' unpacked = unpack('u1s6f32r43', packed) self.assertEqual(unpacked, (0, -2, 3.75, b'\x00\xff\x00\xff\x00\xe0')) packed = bytearray(b'\x80') unpacked = unpack('b1', packed) self.assertEqual(unpacked, (True, )) packed = b'\x80' unpacked = unpack('b1p6b1', packed) self.assertEqual(unpacked, (True, False)) packed = b'\x06' unpacked = unpack('u5b2u1', packed) self.assertEqual(unpacked, (0, True, 0)) packed = b'\x04' unpacked = unpack('u5b2u1', packed) self.assertEqual(unpacked, (0, True, 0)) packed = b'$4\x90\x80' unpacked = unpack('b1t24', packed) self.assertEqual(unpacked, (False, u'Hi!')) packed = 1000 * b'7' unpacked = unpack('t8000', packed) self.assertEqual(packed, 1000 * b'\x37') # Bad float size. with self.assertRaises(Error) as cm: unpack('f33', b'\x00\x00\x00\x00\x00') self.assertEqual(str(cm.exception), 'expected float size of 16, 32, or 64 bits (got 33)') # Too many bits to unpack. with self.assertRaises(Error) as cm: unpack('u9', b'\x00') self.assertEqual(str(cm.exception), 'unpack requires at least 9 bits to unpack (got 8)') # gcc packed struct with bitfields # # struct foo_t { # int a; # char b; # uint32_t c : 7; # uint32_t d : 25; # } foo; # # foo.a = 1; # foo.b = 1; # foo.c = 0x67; # foo.d = 0x12345; unpacked = unpack('s32s8u25u7', byteswap('414', b'\x01\x00\x00\x00\x01\xe7\xa2\x91\x00')) self.assertEqual(unpacked, (1, 1, 0x12345, 0x67)) def test_pack_unpack(self): """Pack and unpack values. """ packed = pack('u1u1s6u7u9', 0, 0, -2, 65, 22) unpacked = unpack('u1u1s6u7u9', packed) self.assertEqual(unpacked, (0, 0, -2, 65, 22)) packed = pack('f64', 1.0) unpacked = unpack('f64', packed) self.assertEqual(unpacked, (1.0, )) if sys.version_info >= (3, 6): packed = pack('f16', 1.0) unpacked = unpack('f16', packed) self.assertEqual(unpacked, (1.0, )) def test_calcsize(self): """Calculate size. """ size = calcsize('u1u1s6u7u9') self.assertEqual(size, 24) size = calcsize('u1') self.assertEqual(size, 1) size = calcsize('u77') self.assertEqual(size, 77) size = calcsize('u1s6u7u9') self.assertEqual(size, 23) size = calcsize('b1s6u7u9p1t8') self.assertEqual(size, 32) size = calcsize('b1s6u7u9P1t8') self.assertEqual(size, 32) def test_byteswap(self): """Byte swap. """ res = b'\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a' ref = b'\x01\x03\x02\x04\x08\x07\x06\x05\x0a\x09' self.assertEqual(byteswap('12142', ref), res) packed = pack('u1u5u2u16', 1, 2, 3, 4) unpacked = unpack('u1u5u2u16', byteswap('12', packed)) self.assertEqual(unpacked, (1, 2, 3, 1024)) def test_endianness(self): """Test pack/unpack with endianness information in the format string. """ # Big endian. ref = b'\x02\x46\x9a\xfe\x00\x00\x00' packed = pack('>u19s3f32', 0x1234, -2, -1.0) self.assertEqual(packed, ref) unpacked = unpack('>u19s3f32', packed) self.assertEqual(unpacked, (0x1234, -2, -1.0)) # Little endian. ref = b'\x2c\x48\x0c\x00\x00\x07\xf4' packed = pack('u19f64r3p4', 1, -2, 1.0, b'\x80') self.assertEqual(packed, ref) unpacked = unpack('>u19f64r3p4', packed) self.assertEqual(unpacked, (1, -2, 1.0, b'\x80')) # Opposite endianness of the 'mixed endianness' test. ref = b'\x80\x00\x1e\x00\x00\x00\x00\x00\x00\x0f\xfc\x20' packed = pack('s5s5', 0x1234, -2, -1.0) self.assertEqual(packed, ref) unpacked = unpack('u19s3f32>', packed) self.assertEqual(unpacked, (0x1234, -2, -1.0)) # Least significant byte first. ref = b'\x34\x12\x18\x00\x00\xe0\xbc' packed = pack('u19s3f32<', 0x1234, -2, -1.0) self.assertEqual(packed, ref) unpacked = unpack('u19s3f32<', packed) self.assertEqual(unpacked, (0x1234, -2, -1.0)) # Least significant byte first. ref = b'\x34\x12' packed = pack('u8s8<', 0x34, 0x12) self.assertEqual(packed, ref) unpacked = unpack('u8s8<', packed) self.assertEqual(unpacked, (0x34, 0x12)) # Least significant byte first. ref = b'\x34\x22' packed = pack('u3u12<', 1, 0x234) self.assertEqual(packed, ref) unpacked = unpack('u3s12<', packed) self.assertEqual(unpacked, (1, 0x234)) # Least significant byte first. ref = b'\x34\x11\x00' packed = pack('u3u17<', 1, 0x234) self.assertEqual(packed, ref) unpacked = unpack('u3s17<', packed) self.assertEqual(unpacked, (1, 0x234)) # Least significant byte first. ref = b'\x80' packed = pack('u1<', 1) self.assertEqual(packed, ref) unpacked = unpack('u1<', packed) self.assertEqual(unpacked, (1, )) # Least significant byte first. ref = b'\x45\x23\x25\x82' packed = pack('u19u5u1u7<', 0x12345, 5, 1, 2) self.assertEqual(packed, ref) unpacked = unpack('u19u5u1u7<', packed) self.assertEqual(unpacked, (0x12345, 5, 1, 2)) # Least significant byte first does not affect raw and text. ref = b'123abc' packed = pack('r24t24<', b'123', 'abc') self.assertEqual(packed, ref) unpacked = unpack('r24t24<', packed) self.assertEqual(unpacked, (b'123', 'abc')) def test_compile(self): cf = bitstruct.compile('u1u1s6u7u9') packed = cf.pack(0, 0, -2, 65, 22) self.assertEqual(packed, b'\x3e\x82\x16') unpacked = cf.unpack(b'\x3e\x82\x16') self.assertEqual(unpacked, (0, 0, -2, 65, 22)) def test_signed_integer(self): """Pack and unpack signed integer values. """ datas = [ ('s2', 0x01, b'\x40'), ('s3', 0x03, b'\x60'), ('s4', 0x07, b'\x70'), ('s5', 0x0f, b'\x78'), ('s6', 0x1f, b'\x7c'), ('s7', 0x3f, b'\x7e'), ('s8', 0x7f, b'\x7f'), ('s9', 0xff, b'\x7f\x80'), ('s1', -1, b'\x80'), ('s2', -1, b'\xc0') ] for fmt, value, packed in datas: self.assertEqual(pack(fmt, value), packed) self.assertEqual(unpack(fmt, packed), (value, )) def test_unsigned_integer(self): """Pack and unpack unsigned integer values. """ datas = [ ('u1', 0x001, b'\x80'), ('u2', 0x003, b'\xc0'), ('u3', 0x007, b'\xe0'), ('u4', 0x00f, b'\xf0'), ('u5', 0x01f, b'\xf8'), ('u6', 0x03f, b'\xfc'), ('u7', 0x07f, b'\xfe'), ('u8', 0x0ff, b'\xff'), ('u9', 0x1ff, b'\xff\x80') ] for fmt, value, packed in datas: self.assertEqual(pack(fmt, value), packed) self.assertEqual(unpack(fmt, packed), (value, )) def test_bad_float_size(self): """Test of bad float size. """ with self.assertRaises(Error) as cm: pack('f31', 1.0) self.assertEqual(str(cm.exception), 'expected float size of 16, 32, or 64 bits (got 31)') with self.assertRaises(Error) as cm: unpack('f33', 8 * b'\x00') self.assertEqual(str(cm.exception), 'expected float size of 16, 32, or 64 bits (got 33)') def test_bad_format(self): """Test of bad format. """ formats = [ ('g1', "bad char 'g' in format"), ('s1u1f32b1t8r8G13', "bad char 'G' in format"), ('s1u1f32b1t8r8G13S3', "bad char 'G' in format"), ('s', "bad format 's'"), ('1', "bad format '1'"), ('ss1', "bad format 'ss1'"), ('1s', "bad format '1s'"), ('foo', "bad format 'foo'"), ('s>1>', "bad format 's>1>'"), ('s0', "bad format 's0'") ] for fmt, expected_error in formats: with self.assertRaises(Error) as cm: bitstruct.compile(fmt) self.assertEqual(str(cm.exception), expected_error) def test_empty_format(self): """Test of empty format type. """ cf = bitstruct.compile('') self.assertEqual(cf.pack(), b'') self.assertEqual(cf.pack(1), b'') self.assertEqual(cf.unpack(b''), ()) self.assertEqual(cf.unpack(b'\x00'), ()) def test_byte_order_format(self): """Test of a format with only byte order information. """ cf = bitstruct.compile('>') self.assertEqual(cf.pack(), b'') self.assertEqual(cf.pack(1), b'') self.assertEqual(cf.unpack(b''), ()) self.assertEqual(cf.unpack(b'\x00'), ()) def test_pack_into(self): """Pack values into a buffer. """ packed = bytearray(3) pack_into('u1u1s6u7u9', packed, 0, 0, 0, -2, 65, 22) self.assertEqual(packed, b'\x3e\x82\x16') datas = [ (0, b'\x80\x00'), (1, b'\x40\x00'), (7, b'\x01\x00'), (15, b'\x00\x01') ] for offset, expected in datas: packed = bytearray(2) pack_into('u1', packed, offset, 1) self.assertEqual(packed, expected) packed = bytearray(b'\xff\xff\xff') pack_into('p4u4p4u4p4u4', packed, 0, 1, 2, 3, fill_padding=False) self.assertEqual(packed, b'\xf1\xf2\xf3') packed = bytearray(b'\xff\xff\xff') pack_into('p4u4p4u4p4u4', packed, 0, 1, 2, 3, fill_padding=True) self.assertEqual(packed, b'\x01\x02\x03') packed = bytearray(2) with self.assertRaises(Error) as cm: pack_into('u17', packed, 0, 1) self.assertEqual(str(cm.exception), 'pack_into requires a buffer of at least 17 bits') packed = bytearray(b'\x00') pack_into('P4u4', packed, 0, 1) self.assertEqual(packed, b'\xf1') # Too many values to pack. with self.assertRaises(Error) as cm: packed = bytearray(b'\x00') pack_into('b1t24', packed, 0, False) self.assertEqual(str(cm.exception), 'pack expected 2 item(s) for packing (got 1)') def test_unpack_from(self): """Unpack values at given bit offset. """ unpacked = unpack_from('u1u1s6u7u9', b'\x1f\x41\x0b\x00', 1) self.assertEqual(unpacked, (0, 0, -2, 65, 22)) with self.assertRaises(Error) as cm: unpack_from('u1u1s6u7u9', b'\x1f\x41\x0b', 1) self.assertEqual(str(cm.exception), 'unpack requires at least 24 bits to unpack ' '(got 23)') def test_pack_integers_value_checks(self): """Pack integer values range checks. """ # Formats with minimum and maximum allowed values. datas = [ ('s1', -1, 0), ('s2', -2, 1), ('s3', -4, 3), ('u1', 0, 1), ('u2', 0, 3), ('u3', 0, 7) ] for fmt, minimum, maximum in datas: # No exception should be raised for numbers in range. pack(fmt, minimum) pack(fmt, maximum) # Numbers out of range. for number in [minimum - 1, maximum + 1]: with self.assertRaises(Error) as cm: pack(fmt, number) self.assertEqual( str(cm.exception), '"{}" requires {} <= integer <= {} (got {})'.format( fmt, minimum, maximum, number)) def test_pack_unpack_raw(self): """Pack and unpack raw values. """ packed = pack('r24', b'') self.assertEqual(packed, b'\x00\x00\x00') packed = pack('r24', b'12') self.assertEqual(packed, b'12\x00') packed = pack('r24', b'123') self.assertEqual(packed, b'123') packed = pack('r24', b'1234') self.assertEqual(packed, b'123') unpacked = unpack('r24', b'\x00\x00\x00')[0] self.assertEqual(unpacked, b'\x00\x00\x00') unpacked = unpack('r24', b'12\x00')[0] self.assertEqual(unpacked, b'12\x00') unpacked = unpack('r24', b'123')[0] self.assertEqual(unpacked, b'123') unpacked = unpack('r24', b'1234')[0] self.assertEqual(unpacked, b'123') def test_pack_unpack_text(self): """Pack and unpack text values. """ packed = pack('t24', '') self.assertEqual(packed, b'\x00\x00\x00') packed = pack('t24', '12') self.assertEqual(packed, b'12\x00') packed = pack('t24', '123') self.assertEqual(packed, b'123') packed = pack('t24', '1234') self.assertEqual(packed, b'123') unpacked = unpack('t24', b'\x00\x00\x00')[0] self.assertEqual(unpacked, '\x00\x00\x00') unpacked = unpack('t24', b'12\x00')[0] self.assertEqual(unpacked, '12\x00') unpacked = unpack('t24', b'123')[0] self.assertEqual(unpacked, '123') unpacked = unpack('t24', b'1234')[0] self.assertEqual(unpacked, '123') def test_pack_unpack_dict(self): unpacked = { 'foo': 0, 'bar': 0, 'fie': -2, 'fum': 65, 'fam': 22 } packed = b'\x3e\x82\x16' fmt = 'u1u1s6u7u9' names = ['foo', 'bar', 'fie', 'fum', 'fam'] self.assertEqual(pack_dict(fmt, names, unpacked), packed) self.assertEqual(unpack_dict(fmt, names, packed), unpacked) def test_pack_into_unpack_from_dict(self): unpacked = { 'foo': 0, 'bar': 0, 'fie': -2, 'fum': 65, 'fam': 22 } packed = b'\x3e\x82\x16' fmt = 'u1u1s6u7u9' names = ['foo', 'bar', 'fie', 'fum', 'fam'] actual = bytearray(3) pack_into_dict(fmt, names, actual, 0, unpacked) self.assertEqual(actual, packed) self.assertEqual(unpack_from_dict(fmt, names, packed), unpacked) def test_pack_dict_missing_key(self): unpacked = { 'foo': 0, 'bar': 0, 'fie': -2, 'fum': 65 } fmt = 'u1u1s6u7u9' names = ['foo', 'bar', 'fie', 'fum', 'fam'] with self.assertRaises(Error) as cm: pack_dict(fmt, names, unpacked) self.assertEqual(str(cm.exception), "'fam' not found in data dictionary") with self.assertRaises(Error) as cm: data = bytearray(3) pack_into_dict(fmt, names, data, 0, unpacked) self.assertEqual(str(cm.exception), "'fam' not found in data dictionary") def test_compile_pack_unpack_formats(self): fmts = [ ('u1s2p3', None, (1, -1)), ('u1 s2 p3', None, (1, -1)), ('u1s2p3', ['a', 'b'], {'a': 1, 'b': -1}) ] for fmt, names, decoded in fmts: if names is None: cf = bitstruct.compile(fmt) packed_1 = cf.pack(*decoded) packed_2 = pack(fmt, *decoded) else: cf = bitstruct.compile(fmt, names) packed_1 = cf.pack(decoded) packed_2 = pack_dict(fmt, names, decoded) self.assertEqual(packed_1, b'\xe0') self.assertEqual(packed_2, b'\xe0') def test_compile_formats(self): bitstruct.compile('p1u1') bitstruct.compile('p1u1', ['a']) def test_pack_unpack_signed(self): datas = [ ('s1', 0, b'\x00'), ('s1', -1, b'\x80'), ('s63', -1, b'\xff\xff\xff\xff\xff\xff\xff\xfe'), ('s64', -1, b'\xff\xff\xff\xff\xff\xff\xff\xff') ] for fmt, value, packed in datas: self.assertEqual(pack(fmt, value), packed) self.assertEqual(unpack(fmt, packed), (value, )) def test_pack_unpack_unsigned(self): datas = [ ('u1', 0, b'\x00'), ('u1', 1, b'\x80'), ('u63', 0x1234567890abcdef, b'$h\xac\xf1!W\x9b\xde'), ('u64', 0x1234567890abcdef, b'\x124Vx\x90\xab\xcd\xef') ] for fmt, value, packed in datas: self.assertEqual(pack(fmt, value), packed) self.assertEqual(unpack(fmt, packed), (value, )) if __name__ == '__main__': unittest.main() bitstruct-8.9.0/Makefile0000664000175000017500000000050713544063630015131 0ustar erikerik00000000000000test: python2 setup.py test python3 setup.py test $(MAKE) test-sdist codespell -d $$(git ls-files) test-sdist: rm -rf dist python setup.py sdist cd dist && \ mkdir test && \ cd test && \ tar xf ../*.tar.gz && \ cd bitstruct-* && \ python setup.py test release-to-pypi: python setup.py sdist twine upload dist/* bitstruct-8.9.0/LICENSE0000664000175000017500000000207513432214052014470 0ustar erikerik00000000000000The MIT License (MIT) Copyright (c) 2015-2019 Erik Moqvist 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. bitstruct-8.9.0/MANIFEST.in0000664000175000017500000000035313544063630015226 0ustar erikerik00000000000000include LICENSE include Makefile include bitstruct/c.c include bitstruct/bitstream.[hc] recursive-include docs *.bat recursive-include docs *.py recursive-include docs *.rst recursive-include docs Makefile recursive-include tests *.py bitstruct-8.9.0/bitstruct/0000775000175000017500000000000013611423315015505 5ustar erikerik00000000000000bitstruct-8.9.0/bitstruct/bitstream.h0000664000175000017500000001350713547167065017675 0ustar erikerik00000000000000/** * The MIT License (MIT) * * Copyright (c) 2019 Erik Moqvist * * 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. */ #ifndef BITSTREAM_H #define BITSTREAM_H #include #define BITSTREAM_VERSION "0.5.1" struct bitstream_writer_t { uint8_t *buf_p; int byte_offset; int bit_offset; }; struct bitstream_writer_bounds_t { struct bitstream_writer_t *writer_p; int first_byte_offset; uint8_t first_byte; int last_byte_offset; uint8_t last_byte; }; struct bitstream_reader_t { const uint8_t *buf_p; int byte_offset; int bit_offset; }; /* * The writer. */ void bitstream_writer_init(struct bitstream_writer_t *self_p, uint8_t *buf_p); int bitstream_writer_size_in_bits(struct bitstream_writer_t *self_p); int bitstream_writer_size_in_bytes(struct bitstream_writer_t *self_p); /* Write bits to the stream. Clears each byte before bits are written. */ void bitstream_writer_write_bit(struct bitstream_writer_t *self_p, int value); void bitstream_writer_write_bytes(struct bitstream_writer_t *self_p, const uint8_t *buf_p, int length); void bitstream_writer_write_u8(struct bitstream_writer_t *self_p, uint8_t value); void bitstream_writer_write_u16(struct bitstream_writer_t *self_p, uint16_t value); void bitstream_writer_write_u32(struct bitstream_writer_t *self_p, uint32_t value); void bitstream_writer_write_u64(struct bitstream_writer_t *self_p, uint64_t value); /* Upper unused bits must be zero. */ void bitstream_writer_write_u64_bits(struct bitstream_writer_t *self_p, uint64_t value, int number_of_bits); void bitstream_writer_write_repeated_bit(struct bitstream_writer_t *self_p, int value, int length); void bitstream_writer_write_repeated_u8(struct bitstream_writer_t *self_p, uint8_t value, int length); /* Insert bits into the stream. Leaves all other bits unmodified. */ void bitstream_writer_insert_bit(struct bitstream_writer_t *self_p, int value); void bitstream_writer_insert_bytes(struct bitstream_writer_t *self_p, const uint8_t *buf_p, int length); void bitstream_writer_insert_u8(struct bitstream_writer_t *self_p, uint8_t value); void bitstream_writer_insert_u16(struct bitstream_writer_t *self_p, uint16_t value); void bitstream_writer_insert_u32(struct bitstream_writer_t *self_p, uint32_t value); void bitstream_writer_insert_u64(struct bitstream_writer_t *self_p, uint64_t value); void bitstream_writer_insert_u64_bits(struct bitstream_writer_t *self_p, uint64_t value, int number_of_bits); /* Move write position. Seeking backwards makes the written size smaller. Use write with care after seek, as seek does not clear bytes. */ void bitstream_writer_seek(struct bitstream_writer_t *self_p, int offset); /* Save-restore first and last bytes in given range, so write can be used in given range. */ void bitstream_writer_bounds_save(struct bitstream_writer_bounds_t *self_p, struct bitstream_writer_t *writer_p, int bit_offset, int length); void bitstream_writer_bounds_restore(struct bitstream_writer_bounds_t *self_p); /* * The reader. */ void bitstream_reader_init(struct bitstream_reader_t *self_p, const uint8_t *buf_p); /* Read bits from the stream. */ int bitstream_reader_read_bit(struct bitstream_reader_t *self_p); void bitstream_reader_read_bytes(struct bitstream_reader_t *self_p, uint8_t *buf_p, int length); uint8_t bitstream_reader_read_u8(struct bitstream_reader_t *self_p); uint16_t bitstream_reader_read_u16(struct bitstream_reader_t *self_p); uint32_t bitstream_reader_read_u32(struct bitstream_reader_t *self_p); uint64_t bitstream_reader_read_u64(struct bitstream_reader_t *self_p); uint64_t bitstream_reader_read_u64_bits(struct bitstream_reader_t *self_p, int number_of_bits); /* Move read position. */ void bitstream_reader_seek(struct bitstream_reader_t *self_p, int offset); #endif bitstruct-8.9.0/bitstruct/__init__.py0000664000175000017500000004270413545271720017634 0ustar erikerik00000000000000from __future__ import print_function import re import struct from io import BytesIO import binascii from .version import __version__ class Error(Exception): pass class _Info(object): def __init__(self, size, name=None): self.size = size self.name = name self.endianness = None class _SignedInteger(_Info): def __init__(self, size, name): super(_SignedInteger, self).__init__(size, name) self.minimum = -2 ** (size - 1) self.maximum = -self.minimum - 1 def pack(self, arg): value = int(arg) if value < self.minimum or value > self.maximum: raise Error( '"s{}" requires {} <= integer <= {} (got {})'.format( self.size, self.minimum, self.maximum, arg)) if value < 0: value += (1 << self.size) value += (1 << self.size) return bin(value)[3:] def unpack(self, bits): value = int(bits, 2) if bits[0] == '1': value -= (1 << len(bits)) return value class _UnsignedInteger(_Info): def __init__(self, size, name): super(_UnsignedInteger, self).__init__(size, name) self.maximum = 2 ** size - 1 def pack(self, arg): value = int(arg) if value < 0 or value > self.maximum: raise Error( '"u{}" requires 0 <= integer <= {} (got {})'.format( self.size, self.maximum, arg)) return bin(value + (1 << self.size))[3:] def unpack(self, bits): return int(bits, 2) class _Boolean(_UnsignedInteger): def pack(self, arg): return super(_Boolean, self).pack(int(bool(arg))) def unpack(self, bits): return bool(super(_Boolean, self).unpack(bits)) class _Float(_Info): def pack(self, arg): value = float(arg) if self.size == 16: value = struct.pack('>e', value) elif self.size == 32: value = struct.pack('>f', value) elif self.size == 64: value = struct.pack('>d', value) else: raise Error('expected float size of 16, 32, or 64 bits (got {})'.format( self.size)) return bin(int(b'01' + binascii.hexlify(value), 16))[3:] def unpack(self, bits): packed = _unpack_bytearray(self.size, bits) if self.size == 16: value = struct.unpack('>e', packed)[0] elif self.size == 32: value = struct.unpack('>f', packed)[0] elif self.size == 64: value = struct.unpack('>d', packed)[0] else: raise Error('expected float size of 16, 32, or 64 bits (got {})'.format( self.size)) return value class _Raw(_Info): def pack(self, arg): number_of_padding_bytes = ((self.size - 8 * len(arg)) // 8) arg += (number_of_padding_bytes * b'\x00') return bin(int(b'01' + binascii.hexlify(arg), 16))[3:self.size + 3] def unpack(self, bits): rest = self.size % 8 if rest > 0: bits += (8 - rest) * '0' return binascii.unhexlify(hex(int('10000000' + bits, 2))[4:].rstrip('L')) class _Padding(_Info): pass class _ZeroPadding(_Padding): def pack(self): return self.size * '0' class _OnePadding(_Padding): def pack(self): return self.size * '1' class _Text(_Info): def pack(self, arg): encoded = arg.encode('utf-8') number_of_padding_bytes = ((self.size - 8 * len(encoded)) // 8) encoded += (number_of_padding_bytes * b'\x00') return _pack_bytearray(self.size, encoded) def unpack(self, bits): return _unpack_bytearray(self.size, bits).decode('utf-8') def _parse_format(fmt, names): if fmt and fmt[-1] in '><': byte_order = fmt[-1] fmt = fmt[:-1] else: byte_order = '' parsed_infos = re.findall(r'([<>]?)([a-zA-Z])(\d+)(\s*)', fmt) if ''.join([''.join(info) for info in parsed_infos]) != fmt: raise Error("bad format '{}'".format(fmt + byte_order)) # Use big endian as default and use the endianness of the previous # value if none is given for the current value. infos = [] endianness = ">" i = 0 for parsed_info in parsed_infos: if parsed_info[0] != "": endianness = parsed_info[0] type_ = parsed_info[1] size = int(parsed_info[2]) if size == 0: raise Error("bad format '{}'".format(fmt + byte_order)) if names is None: name = i elif type_ not in 'pP': name = names[i] if type_ == 's': info = _SignedInteger(size, name) i += 1 elif type_ == 'u': info = _UnsignedInteger(size, name) i += 1 elif type_ == 'f': info = _Float(size, name) i += 1 elif type_ == 'b': info = _Boolean(size, name) i += 1 elif type_ == 't': info = _Text(size, name) i += 1 elif type_ == 'r': info = _Raw(size, name) i += 1 elif type_ == 'p': info = _ZeroPadding(size) elif type_ == 'P': info = _OnePadding(size) else: raise Error("bad char '{}' in format".format(type_)) info.endianness = endianness infos.append(info) return infos, byte_order or '>' def _pack_bytearray(size, arg): return bin(int(b'01' + binascii.hexlify(arg), 16))[3:size + 3] def _unpack_bytearray(size, bits): rest = size % 8 if rest > 0: bits += (8 - rest) * '0' return binascii.unhexlify(hex(int('10000000' + bits, 2))[4:].rstrip('L')) class _CompiledFormat(object): def __init__(self, fmt, names=None): infos, byte_order = _parse_format(fmt, names) self._infos = infos self._byte_order = byte_order self._number_of_bits_to_unpack = sum([info.size for info in infos]) def pack_value(self, info, value, bits): value_bits = info.pack(value) # Reverse the bit order in little endian values. if info.endianness == "<": value_bits = value_bits[::-1] # Reverse bytes order for least significant byte first. if self._byte_order == ">" or isinstance(info, (_Raw, _Text)): bits += value_bits else: aligned_offset = len(value_bits) - (8 - (len(bits) % 8)) while aligned_offset > 0: bits += value_bits[aligned_offset:] value_bits = value_bits[:aligned_offset] aligned_offset -= 8 bits += value_bits return bits def pack_any(self, values): bits = '' for info in self._infos: if isinstance(info, _Padding): bits += info.pack() else: bits = self.pack_value(info, values[info.name], bits) # Padding of last byte. tail = len(bits) % 8 if tail != 0: bits += (8 - tail) * '0' return bytes(_unpack_bytearray(len(bits), bits)) def unpack_from_any(self, data, offset): bits = bin(int(b'01' + binascii.hexlify(data), 16))[3 + offset:] # Sanity check. if self._number_of_bits_to_unpack > len(bits): raise Error( "unpack requires at least {} bits to unpack (got {})".format( self._number_of_bits_to_unpack, len(bits))) offset = 0 for info in self._infos: if isinstance(info, _Padding): pass else: # Reverse bytes order for least significant byte # first. if self._byte_order == ">" or isinstance(info, (_Raw, _Text)): value_bits = bits[offset:offset + info.size] else: value_bits_tmp = bits[offset:offset + info.size] aligned_offset = (info.size - ((offset + info.size) % 8)) value_bits = '' while aligned_offset > 0: value_bits += value_bits_tmp[aligned_offset:aligned_offset + 8] value_bits_tmp = value_bits_tmp[:aligned_offset] aligned_offset -= 8 value_bits += value_bits_tmp # Reverse the bit order in little endian values. if info.endianness == "<": value_bits = value_bits[::-1] yield info, info.unpack(value_bits) offset += info.size def pack_into_any(self, buf, offset, data, **kwargs): fill_padding = kwargs.get('fill_padding', True) buf_bits = _pack_bytearray(8 * len(buf), buf) bits = buf_bits[0:offset] for info in self._infos: if isinstance(info, _Padding): if fill_padding: bits += info.pack() else: bits += buf_bits[len(bits):len(bits) + info.size] else: bits = self.pack_value(info, data[info.name], bits) bits += buf_bits[len(bits):] if len(bits) > len(buf_bits): raise Error( 'pack_into requires a buffer of at least {} bits'.format( len(bits))) buf[:] = _unpack_bytearray(len(bits), bits) def calcsize(self): """Return the number of bits in the compiled format string. """ return self._number_of_bits_to_unpack class CompiledFormat(_CompiledFormat): """A compiled format string that can be used to pack and/or unpack data multiple times. Instances of this class are created by the factory function :func:`~bitstruct.compile()`. """ def __init__(self, fmt): super(CompiledFormat, self).__init__(fmt, None) self._number_of_arguments = 0 for info in self._infos: if not isinstance(info, _Padding): self._number_of_arguments += 1 def pack(self, *args): """See :func:`~bitstruct.pack()`. """ # Sanity check of the number of arguments. if len(args) < self._number_of_arguments: raise Error( "pack expected {} item(s) for packing (got {})".format( self._number_of_arguments, len(args))) return self.pack_any(args) def unpack(self, data): """See :func:`~bitstruct.unpack()`. """ return self.unpack_from(data) def pack_into(self, buf, offset, *args, **kwargs): """See :func:`~bitstruct.pack_into()`. """ # Sanity check of the number of arguments. if len(args) < self._number_of_arguments: raise Error( "pack expected {} item(s) for packing (got {})".format( self._number_of_arguments, len(args))) self.pack_into_any(buf, offset, args, **kwargs) def unpack_from(self, data, offset=0): """See :func:`~bitstruct.unpack_from()`. """ return tuple([v[1] for v in self.unpack_from_any(data, offset)]) class CompiledFormatDict(_CompiledFormat): """See :class:`~bitstruct.CompiledFormat`. """ def pack(self, data): """See :func:`~bitstruct.pack_dict()`. """ try: return self.pack_any(data) except KeyError as e: raise Error('{} not found in data dictionary'.format(str(e))) def unpack(self, data): """See :func:`~bitstruct.unpack_dict()`. """ return self.unpack_from(data) def pack_into(self, buf, offset, data, **kwargs): """See :func:`~bitstruct.pack_into_dict()`. """ try: self.pack_into_any(buf, offset, data, **kwargs) except KeyError as e: raise Error('{} not found in data dictionary'.format(str(e))) def unpack_from(self, data, offset=0): """See :func:`~bitstruct.unpack_from_dict()`. """ return {info.name: v for info, v in self.unpack_from_any(data, offset)} def pack(fmt, *args): """Return a bytes object containing the values v1, v2, ... packed according to given format string `fmt`. If the total number of bits are not a multiple of 8, padding will be added at the end of the last byte. `fmt` is a string of bit order-type-length groups, and optionally a byte order identifier after the groups. Bit Order and byte order may be omitted. Bit Order is either ``>`` or ``<``, where ``>`` means MSB first and ``<`` means LSB first. If bit order is omitted, the previous values' bit order is used for the current value. For example, in the format string ``'u1`` or ``<``, where ``>`` means most significant byte first and ``<`` means least significant byte first. If byte order is omitted, most significant byte first is used. There are eight types; ``u``, ``s``, ``f``, ``b``, ``t``, ``r``, ``p`` and ``P``. - ``u`` -- unsigned integer - ``s`` -- signed integer - ``f`` -- floating point number of 16, 32, or 64 bits - ``b`` -- boolean - ``t`` -- text (ascii or utf-8) - ``r`` -- raw, bytes - ``p`` -- padding with zeros, ignore - ``P`` -- padding with ones, ignore Length is the number of bits to pack the value into. Example format string with default bit and byte ordering: ``'u1u3p7s16'`` Same format string, but with least significant byte first: ``'u1u3p7s16<'`` Same format string, but with LSB first (``<`` prefix) and least significant byte first (``<`` suffix): ``'>> pack_dict('u4u4', ['foo', 'bar'], {'foo': 1, 'bar': 2}) b'\\x12' """ return CompiledFormatDict(fmt, names).pack(data) def unpack_dict(fmt, names, data): """Same as :func:`~bitstruct.unpack()`, but returns a dictionary. See :func:`~bitstruct.pack_dict()` for details on `names`. >>> unpack_dict('u4u4', ['foo', 'bar'], b'\\x12') {'foo': 1, 'bar': 2} """ return CompiledFormatDict(fmt, names).unpack(data) def pack_into_dict(fmt, names, buf, offset, data, **kwargs): """Same as :func:`~bitstruct.pack_into()`, but data is read from a dictionary. See :func:`~bitstruct.pack_dict()` for details on `names`. """ return CompiledFormatDict(fmt, names).pack_into(buf, offset, data, **kwargs) def unpack_from_dict(fmt, names, data, offset=0): """Same as :func:`~bitstruct.unpack_from_dict()`, but returns a dictionary. See :func:`~bitstruct.pack_dict()` for details on `names`. """ return CompiledFormatDict(fmt, names).unpack_from(data, offset) def calcsize(fmt): """Return the number of bits in given format string `fmt`. >>> calcsize('u1s3p4') 8 """ return CompiledFormat(fmt).calcsize() def byteswap(fmt, data, offset=0): """Swap bytes in `data` according to `fmt`, starting at byte `offset` and return the result. `fmt` must be an iterable, iterating over number of bytes to swap. For example, the format string ``'24'`` applied to the bytes ``b'\\x00\\x11\\x22\\x33\\x44\\x55'`` will produce the result ``b'\\x11\\x00\\x55\\x44\\x33\\x22'``. """ data = BytesIO(data) data.seek(offset) data_swapped = BytesIO() for f in fmt: swapped = data.read(int(f))[::-1] data_swapped.write(swapped) return data_swapped.getvalue() def compile(fmt, names=None): """Compile given format string `fmt` and return a compiled format object that can be used to pack and/or unpack data multiple times. Returns a :class:`~bitstruct.CompiledFormat` object if `names` is ``None``, and otherwise a :class:`~bitstruct.CompiledFormatDict` object. See :func:`~bitstruct.pack_dict()` for details on `names`. """ if names is None: return CompiledFormat(fmt) else: return CompiledFormatDict(fmt, names) bitstruct-8.9.0/bitstruct/bitstream.c0000664000175000017500000004171713547167065017674 0ustar erikerik00000000000000/** * The MIT License (MIT) * * Copyright (c) 2019 Erik Moqvist * * 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 #include "bitstream.h" void bitstream_writer_init(struct bitstream_writer_t *self_p, uint8_t *buf_p) { self_p->buf_p = buf_p; self_p->byte_offset = 0; self_p->bit_offset = 0; } int bitstream_writer_size_in_bits(struct bitstream_writer_t *self_p) { return (8 * self_p->byte_offset + self_p->bit_offset); } int bitstream_writer_size_in_bytes(struct bitstream_writer_t *self_p) { return (self_p->byte_offset + (self_p->bit_offset + 7) / 8); } void bitstream_writer_write_bit(struct bitstream_writer_t *self_p, int value) { if (self_p->bit_offset == 0) { self_p->buf_p[self_p->byte_offset] = (value << 7); self_p->bit_offset = 1; } else { self_p->buf_p[self_p->byte_offset] |= (value << (8 - self_p->bit_offset - 1)); if (self_p->bit_offset == 7) { self_p->bit_offset = 0; self_p->byte_offset++; } else { self_p->bit_offset++; } } } void bitstream_writer_write_bytes(struct bitstream_writer_t *self_p, const uint8_t *buf_p, int length) { int i; uint8_t *dst_p; dst_p = &self_p->buf_p[self_p->byte_offset]; if (self_p->bit_offset == 0) { memcpy(dst_p, buf_p, sizeof(uint8_t) * length); } else { for (i = 0; i < length; i++) { dst_p[i] |= (buf_p[i] >> self_p->bit_offset); dst_p[i + 1] = (uint8_t)(buf_p[i] << (8 - self_p->bit_offset)); } } self_p->byte_offset += length; } void bitstream_writer_write_u8(struct bitstream_writer_t *self_p, uint8_t value) { if (self_p->bit_offset == 0) { self_p->buf_p[self_p->byte_offset] = value; } else { self_p->buf_p[self_p->byte_offset] |= (value >> self_p->bit_offset); self_p->buf_p[self_p->byte_offset + 1] = (uint8_t)(value << (8 - self_p->bit_offset)); } self_p->byte_offset++; } void bitstream_writer_write_u16(struct bitstream_writer_t *self_p, uint16_t value) { if (self_p->bit_offset == 0) { self_p->buf_p[self_p->byte_offset] = (value >> 8); } else { self_p->buf_p[self_p->byte_offset] |= (value >> (8 + self_p->bit_offset)); self_p->buf_p[self_p->byte_offset + 2] = (uint8_t)(value << (8 - self_p->bit_offset)); value >>= self_p->bit_offset; } self_p->buf_p[self_p->byte_offset + 1] = (uint8_t)value; self_p->byte_offset += 2; } void bitstream_writer_write_u32(struct bitstream_writer_t *self_p, uint32_t value) { int i; if (self_p->bit_offset == 0) { self_p->buf_p[self_p->byte_offset] = (value >> 24); } else { self_p->buf_p[self_p->byte_offset] |= (value >> (24 + self_p->bit_offset)); self_p->buf_p[self_p->byte_offset + 4] = (uint8_t)(value << (8 - self_p->bit_offset)); value >>= self_p->bit_offset; } for (i = 3; i > 0; i--) { self_p->buf_p[self_p->byte_offset + i] = value; value >>= 8; } self_p->byte_offset += 4; } void bitstream_writer_write_u64(struct bitstream_writer_t *self_p, uint64_t value) { int i; if (self_p->bit_offset == 0) { self_p->buf_p[self_p->byte_offset] = (value >> 56); } else { self_p->buf_p[self_p->byte_offset] |= (value >> (56 + self_p->bit_offset)); self_p->buf_p[self_p->byte_offset + 8] = (uint8_t)(value << (8 - self_p->bit_offset)); value >>= self_p->bit_offset; } for (i = 7; i > 0; i--) { self_p->buf_p[self_p->byte_offset + i] = (uint8_t)value; value >>= 8; } self_p->byte_offset += 8; } void bitstream_writer_write_u64_bits(struct bitstream_writer_t *self_p, uint64_t value, int number_of_bits) { int i; int first_byte_bits; int last_byte_bits; int full_bytes; if (number_of_bits == 0) { return; } /* Align beginning. */ first_byte_bits = (8 - self_p->bit_offset); if (first_byte_bits != 8) { if (number_of_bits < first_byte_bits) { self_p->buf_p[self_p->byte_offset] |= (uint8_t)(value << (first_byte_bits - number_of_bits)); self_p->bit_offset += number_of_bits; } else { self_p->buf_p[self_p->byte_offset] |= (value >> (number_of_bits - first_byte_bits)); self_p->byte_offset++; self_p->bit_offset = 0; } number_of_bits -= first_byte_bits; if (number_of_bits <= 0) { return; } } /* Align end. */ last_byte_bits = (number_of_bits % 8); full_bytes = (number_of_bits / 8); if (last_byte_bits != 0) { self_p->buf_p[self_p->byte_offset + full_bytes] = (uint8_t)(value << (8 - last_byte_bits)); value >>= last_byte_bits; self_p->bit_offset = last_byte_bits; } /* Copy middle bytes. */ for (i = full_bytes; i > 0; i--) { self_p->buf_p[self_p->byte_offset + i - 1] = (uint8_t)value; value >>= 8; } self_p->byte_offset += full_bytes; } void bitstream_writer_write_repeated_bit(struct bitstream_writer_t *self_p, int value, int length) { int rest; if (value != 0) { value = 0xff; } rest = (length % 8); bitstream_writer_write_u64_bits(self_p, value & ((1 << rest) - 1), rest); bitstream_writer_write_repeated_u8(self_p, value, length / 8); } void bitstream_writer_write_repeated_u8(struct bitstream_writer_t *self_p, uint8_t value, int length) { int i; for (i = 0; i < length; i++) { bitstream_writer_write_u8(self_p, value); } } void bitstream_writer_insert_bit(struct bitstream_writer_t *self_p, int value) { struct bitstream_writer_bounds_t bounds; bitstream_writer_bounds_save(&bounds, self_p, (8 * self_p->byte_offset) + self_p->bit_offset, 1); bitstream_writer_write_bit(self_p, value); bitstream_writer_bounds_restore(&bounds); } void bitstream_writer_insert_bytes(struct bitstream_writer_t *self_p, const uint8_t *buf_p, int length) { struct bitstream_writer_bounds_t bounds; bitstream_writer_bounds_save(&bounds, self_p, (8 * self_p->byte_offset) + self_p->bit_offset, 8 * length); bitstream_writer_write_bytes(self_p, buf_p, length); bitstream_writer_bounds_restore(&bounds); } void bitstream_writer_insert_u8(struct bitstream_writer_t *self_p, uint8_t value) { struct bitstream_writer_bounds_t bounds; bitstream_writer_bounds_save(&bounds, self_p, (8 * self_p->byte_offset) + self_p->bit_offset, 8); bitstream_writer_write_u8(self_p, value); bitstream_writer_bounds_restore(&bounds); } void bitstream_writer_insert_u16(struct bitstream_writer_t *self_p, uint16_t value) { struct bitstream_writer_bounds_t bounds; bitstream_writer_bounds_save(&bounds, self_p, (8 * self_p->byte_offset) + self_p->bit_offset, 16); bitstream_writer_write_u16(self_p, value); bitstream_writer_bounds_restore(&bounds); } void bitstream_writer_insert_u32(struct bitstream_writer_t *self_p, uint32_t value) { struct bitstream_writer_bounds_t bounds; bitstream_writer_bounds_save(&bounds, self_p, (8 * self_p->byte_offset) + self_p->bit_offset, 32); bitstream_writer_write_u32(self_p, value); bitstream_writer_bounds_restore(&bounds); } void bitstream_writer_insert_u64(struct bitstream_writer_t *self_p, uint64_t value) { struct bitstream_writer_bounds_t bounds; bitstream_writer_bounds_save(&bounds, self_p, (8 * self_p->byte_offset) + self_p->bit_offset, 64); bitstream_writer_write_u64(self_p, value); bitstream_writer_bounds_restore(&bounds); } void bitstream_writer_insert_u64_bits(struct bitstream_writer_t *self_p, uint64_t value, int number_of_bits) { struct bitstream_writer_bounds_t bounds; bitstream_writer_bounds_save(&bounds, self_p, (8 * self_p->byte_offset) + self_p->bit_offset, number_of_bits); bitstream_writer_write_u64_bits(self_p, value, number_of_bits); bitstream_writer_bounds_restore(&bounds); } void bitstream_writer_seek(struct bitstream_writer_t *self_p, int offset) { offset += ((8 * self_p->byte_offset) + self_p->bit_offset); self_p->byte_offset = (offset / 8); self_p->bit_offset = (offset % 8); } void bitstream_writer_bounds_save(struct bitstream_writer_bounds_t *self_p, struct bitstream_writer_t *writer_p, int bit_offset, int length) { int number_of_bits; self_p->writer_p = writer_p; number_of_bits = (bit_offset % 8); if (number_of_bits == 0) { self_p->first_byte_offset = -1; } else { self_p->first_byte_offset = (bit_offset / 8); self_p->first_byte = writer_p->buf_p[self_p->first_byte_offset]; self_p->first_byte &= (0xff00 >> number_of_bits); } number_of_bits = ((bit_offset + length) % 8); if (number_of_bits == 0) { self_p->last_byte_offset = -1; } else { self_p->last_byte_offset = ((bit_offset + length) / 8); self_p->last_byte = writer_p->buf_p[self_p->last_byte_offset]; self_p->last_byte &= ~(0xff00 >> number_of_bits); writer_p->buf_p[self_p->last_byte_offset] = 0; } if (self_p->first_byte_offset != -1) { writer_p->buf_p[self_p->first_byte_offset] = 0; } } void bitstream_writer_bounds_restore(struct bitstream_writer_bounds_t *self_p) { if (self_p->first_byte_offset != -1) { self_p->writer_p->buf_p[self_p->first_byte_offset] |= self_p->first_byte; } if (self_p->last_byte_offset != -1) { self_p->writer_p->buf_p[self_p->last_byte_offset] |= self_p->last_byte; } } void bitstream_reader_init(struct bitstream_reader_t *self_p, const uint8_t *buf_p) { self_p->buf_p = buf_p; self_p->byte_offset = 0; self_p->bit_offset = 0; } int bitstream_reader_read_bit(struct bitstream_reader_t *self_p) { int value; if (self_p->bit_offset == 0) { value = (self_p->buf_p[self_p->byte_offset] >> 7); self_p->bit_offset = 1; } else { value = ((self_p->buf_p[self_p->byte_offset] >> (7 - self_p->bit_offset)) & 0x1); if (self_p->bit_offset == 7) { self_p->bit_offset = 0; self_p->byte_offset++; } else { self_p->bit_offset++; } } return (value); } void bitstream_reader_read_bytes(struct bitstream_reader_t *self_p, uint8_t *buf_p, int length) { int i; const uint8_t *src_p; src_p = &self_p->buf_p[self_p->byte_offset]; if (self_p->bit_offset == 0) { memcpy(buf_p, src_p, sizeof(uint8_t) * length); } else { for (i = 0; i < length; i++) { buf_p[i] = (src_p[i] << self_p->bit_offset); buf_p[i] |= (src_p[i + 1] >> (8 - self_p->bit_offset)); } } self_p->byte_offset += length; } uint8_t bitstream_reader_read_u8(struct bitstream_reader_t *self_p) { uint8_t value; value = (self_p->buf_p[self_p->byte_offset] << self_p->bit_offset); self_p->byte_offset++; if (self_p->bit_offset != 0) { value |= (self_p->buf_p[self_p->byte_offset] >> (8 - self_p->bit_offset)); } return (value); } uint16_t bitstream_reader_read_u16(struct bitstream_reader_t *self_p) { uint16_t value; int i; int offset; const uint8_t *src_p; src_p = &self_p->buf_p[self_p->byte_offset]; offset = (16 + self_p->bit_offset); value = 0; for (i = 0; i < 2; i++) { offset -= 8; value |= ((uint16_t)src_p[i] << offset); } if (offset != 0) { value |= (src_p[2] >> (8 - offset)); } self_p->byte_offset += 2; return (value); } uint32_t bitstream_reader_read_u32(struct bitstream_reader_t *self_p) { uint32_t value; int i; int offset; const uint8_t *src_p; src_p = &self_p->buf_p[self_p->byte_offset]; offset = (32 + self_p->bit_offset); value = 0; for (i = 0; i < 4; i++) { offset -= 8; value |= ((uint32_t)src_p[i] << offset); } if (offset != 0) { value |= (src_p[4] >> (8 - offset)); } self_p->byte_offset += 4; return (value); } uint64_t bitstream_reader_read_u64(struct bitstream_reader_t *self_p) { uint64_t value; int i; int offset; const uint8_t *src_p; src_p = &self_p->buf_p[self_p->byte_offset]; offset = (64 + self_p->bit_offset); value = 0; for (i = 0; i < 8; i++) { offset -= 8; value |= ((uint64_t)src_p[i] << offset); } if (offset != 0) { value |= ((uint64_t)src_p[8] >> (8 - offset)); } self_p->byte_offset += 8; return (value); } uint64_t bitstream_reader_read_u64_bits(struct bitstream_reader_t *self_p, int number_of_bits) { uint64_t value; int i; int first_byte_bits; int last_byte_bits; int full_bytes; if (number_of_bits == 0) { return (0); } /* Align beginning. */ first_byte_bits = (8 - self_p->bit_offset); if (first_byte_bits != 8) { if (number_of_bits < first_byte_bits) { value = (self_p->buf_p[self_p->byte_offset] >> (first_byte_bits - number_of_bits)); value &= ((1 << number_of_bits) - 1); self_p->bit_offset += number_of_bits; } else { value = self_p->buf_p[self_p->byte_offset]; value &= ((1 << first_byte_bits) - 1); self_p->byte_offset++; self_p->bit_offset = 0; } number_of_bits -= first_byte_bits; if (number_of_bits <= 0) { return (value); } } else { value = 0; } /* Copy middle bytes. */ full_bytes = (number_of_bits / 8); for (i = 0; i < full_bytes; i++) { value <<= 8; value |= self_p->buf_p[self_p->byte_offset + i]; } /* Last byte. */ last_byte_bits = (number_of_bits % 8); if (last_byte_bits != 0) { value <<= last_byte_bits; value |= (self_p->buf_p[self_p->byte_offset + full_bytes] >> (8 - last_byte_bits)); self_p->bit_offset = last_byte_bits; } self_p->byte_offset += full_bytes; return (value); } void bitstream_reader_seek(struct bitstream_reader_t *self_p, int offset) { offset += ((8 * self_p->byte_offset) + self_p->bit_offset); self_p->byte_offset = (offset / 8); self_p->bit_offset = (offset % 8); } bitstruct-8.9.0/bitstruct/version.py0000664000175000017500000000002613611423057017545 0ustar erikerik00000000000000__version__ = '8.9.0' bitstruct-8.9.0/bitstruct/c.c0000664000175000017500000013665213547443125016121 0ustar erikerik00000000000000/** * CPython 3 C extension. */ #include #include #include "bitstream.h" struct field_info_t; typedef void (*pack_field_t)(struct bitstream_writer_t *self_p, PyObject *value_p, struct field_info_t *field_info_p); typedef PyObject *(*unpack_field_t)(struct bitstream_reader_t *self_p, struct field_info_t *field_info_p); struct field_info_t { pack_field_t pack; unpack_field_t unpack; int number_of_bits; bool is_padding; union { struct { int64_t lower; int64_t upper; } s; struct { uint64_t upper; } u; } limits; }; struct info_t { int number_of_bits; int number_of_fields; int number_of_non_padding_fields; struct field_info_t fields[1]; }; struct compiled_format_t { PyObject_HEAD struct info_t *info_p; }; struct compiled_format_dict_t { PyObject_HEAD struct info_t *info_p; PyObject *names_p; }; static PyObject *py_zero_p = NULL; static bool is_names_list(PyObject *names_p) { if (!PyList_Check(names_p)) { PyErr_SetString(PyExc_TypeError, "Names is not a list."); return (false); } return (true); } static void pack_signed_integer(struct bitstream_writer_t *self_p, PyObject *value_p, struct field_info_t *field_info_p) { int64_t value; int64_t lower; int64_t upper; value = PyLong_AsLongLong(value_p); if ((value == -1) && PyErr_Occurred()) { return; } if (field_info_p->number_of_bits < 64) { lower = field_info_p->limits.s.lower; upper = field_info_p->limits.s.upper; if ((value < lower) || (value > upper)) { PyErr_Format(PyExc_OverflowError, "Signed integer value %lld out of range.", (long long)value); } value &= ((1ull << field_info_p->number_of_bits) - 1); } bitstream_writer_write_u64_bits(self_p, (uint64_t)value, field_info_p->number_of_bits); } static PyObject *unpack_signed_integer(struct bitstream_reader_t *self_p, struct field_info_t *field_info_p) { uint64_t value; uint64_t sign_bit; value = bitstream_reader_read_u64_bits(self_p, field_info_p->number_of_bits); sign_bit = (1ull << (field_info_p->number_of_bits - 1)); if (value & sign_bit) { value |= ~(((sign_bit) << 1) - 1); } return (PyLong_FromLongLong((long long)value)); } static void pack_unsigned_integer(struct bitstream_writer_t *self_p, PyObject *value_p, struct field_info_t *field_info_p) { uint64_t value; value = PyLong_AsUnsignedLongLong(value_p); if ((value == (uint64_t)-1) && PyErr_Occurred()) { return; } if (value > field_info_p->limits.u.upper) { PyErr_Format(PyExc_OverflowError, "Unsigned integer value %llu out of range.", (unsigned long long)value); } bitstream_writer_write_u64_bits(self_p, value, field_info_p->number_of_bits); } static PyObject *unpack_unsigned_integer(struct bitstream_reader_t *self_p, struct field_info_t *field_info_p) { uint64_t value; value = bitstream_reader_read_u64_bits(self_p, field_info_p->number_of_bits); return (PyLong_FromUnsignedLongLong(value)); } #if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 6 static void pack_float_16(struct bitstream_writer_t *self_p, PyObject *value_p, struct field_info_t *field_info_p) { uint8_t buf[2]; _PyFloat_Pack2(PyFloat_AsDouble(value_p), &buf[0], PY_BIG_ENDIAN); bitstream_writer_write_bytes(self_p, &buf[0], sizeof(buf)); } static PyObject *unpack_float_16(struct bitstream_reader_t *self_p, struct field_info_t *field_info_p) { uint8_t buf[2]; double value; bitstream_reader_read_bytes(self_p, &buf[0], sizeof(buf)); value = _PyFloat_Unpack2(&buf[0], PY_BIG_ENDIAN); return (PyFloat_FromDouble(value)); } #endif static void pack_float_32(struct bitstream_writer_t *self_p, PyObject *value_p, struct field_info_t *field_info_p) { float value; uint32_t data; value = (float)PyFloat_AsDouble(value_p); memcpy(&data, &value, sizeof(data)); bitstream_writer_write_u32(self_p, data); } static PyObject *unpack_float_32(struct bitstream_reader_t *self_p, struct field_info_t *field_info_p) { float value; uint32_t data; data = bitstream_reader_read_u32(self_p); memcpy(&value, &data, sizeof(value)); return (PyFloat_FromDouble(value)); } static void pack_float_64(struct bitstream_writer_t *self_p, PyObject *value_p, struct field_info_t *field_info_p) { double value; uint64_t data; value = PyFloat_AsDouble(value_p); memcpy(&data, &value, sizeof(data)); bitstream_writer_write_u64_bits(self_p, data, field_info_p->number_of_bits); } static PyObject *unpack_float_64(struct bitstream_reader_t *self_p, struct field_info_t *field_info_p) { double value; uint64_t data; data = bitstream_reader_read_u64(self_p); memcpy(&value, &data, sizeof(value)); return (PyFloat_FromDouble(value)); } static void pack_bool(struct bitstream_writer_t *self_p, PyObject *value_p, struct field_info_t *field_info_p) { bitstream_writer_write_u64_bits(self_p, PyObject_IsTrue(value_p), field_info_p->number_of_bits); } static PyObject *unpack_bool(struct bitstream_reader_t *self_p, struct field_info_t *field_info_p) { return (PyBool_FromLong((long)bitstream_reader_read_u64_bits( self_p, field_info_p->number_of_bits))); } static void pack_text(struct bitstream_writer_t *self_p, PyObject *value_p, struct field_info_t *field_info_p) { Py_ssize_t size; const char* buf_p; buf_p = PyUnicode_AsUTF8AndSize(value_p, &size); if (buf_p != NULL) { if (size < (field_info_p->number_of_bits / 8)) { PyErr_SetString(PyExc_NotImplementedError, "Short text."); } else { bitstream_writer_write_bytes(self_p, (uint8_t *)buf_p, field_info_p->number_of_bits / 8); } } } static PyObject *unpack_text(struct bitstream_reader_t *self_p, struct field_info_t *field_info_p) { uint8_t *buf_p; PyObject *value_p; int number_of_bytes; number_of_bytes = (field_info_p->number_of_bits / 8); buf_p = PyMem_RawMalloc(number_of_bytes); if (buf_p == NULL) { return (NULL); } bitstream_reader_read_bytes(self_p, buf_p, number_of_bytes); value_p = PyUnicode_FromStringAndSize((const char *)buf_p, number_of_bytes); PyMem_RawFree(buf_p); return (value_p); } static void pack_raw(struct bitstream_writer_t *self_p, PyObject *value_p, struct field_info_t *field_info_p) { Py_ssize_t size; char* buf_p; int res; res = PyBytes_AsStringAndSize(value_p, &buf_p, &size); if (res != -1) { if (size < (field_info_p->number_of_bits / 8)) { PyErr_SetString(PyExc_NotImplementedError, "Short raw data."); } else { bitstream_writer_write_bytes(self_p, (uint8_t *)buf_p, field_info_p->number_of_bits / 8); } } } static PyObject *unpack_raw(struct bitstream_reader_t *self_p, struct field_info_t *field_info_p) { uint8_t *buf_p; PyObject *value_p; int number_of_bytes; number_of_bytes = (field_info_p->number_of_bits / 8); value_p = PyBytes_FromStringAndSize(NULL, number_of_bytes); buf_p = (uint8_t *)PyBytes_AS_STRING(value_p); bitstream_reader_read_bytes(self_p, buf_p, number_of_bytes); return (value_p); } static void pack_zero_padding(struct bitstream_writer_t *self_p, PyObject *value_p, struct field_info_t *field_info_p) { bitstream_writer_write_repeated_bit(self_p, 0, field_info_p->number_of_bits); } static void pack_one_padding(struct bitstream_writer_t *self_p, PyObject *value_p, struct field_info_t *field_info_p) { bitstream_writer_write_repeated_bit(self_p, 1, field_info_p->number_of_bits); } static PyObject *unpack_padding(struct bitstream_reader_t *self_p, struct field_info_t *field_info_p) { bitstream_reader_seek(self_p, field_info_p->number_of_bits); return (NULL); } static int field_info_init_signed(struct field_info_t *self_p, int number_of_bits) { uint64_t limit; self_p->pack = pack_signed_integer; self_p->unpack = unpack_signed_integer; if (number_of_bits > 64) { PyErr_SetString(PyExc_NotImplementedError, "Signed integer over 64 bits."); return (-1); } limit = (1ull << (number_of_bits - 1)); self_p->limits.s.lower = -limit; self_p->limits.s.upper = (limit - 1); return (0); } static int field_info_init_unsigned(struct field_info_t *self_p, int number_of_bits) { self_p->pack = pack_unsigned_integer; self_p->unpack = unpack_unsigned_integer; if (number_of_bits > 64) { PyErr_SetString(PyExc_NotImplementedError, "Unsigned integer over 64 bits."); return (-1); } if (number_of_bits < 64) { self_p->limits.u.upper = ((1ull << number_of_bits) - 1); } else { self_p->limits.u.upper = (uint64_t)-1; } return (0); } static int field_info_init_float(struct field_info_t *self_p, int number_of_bits) { switch (number_of_bits) { #if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 6 case 16: self_p->pack = pack_float_16; self_p->unpack = unpack_float_16; break; #endif case 32: self_p->pack = pack_float_32; self_p->unpack = unpack_float_32; break; case 64: self_p->pack = pack_float_64; self_p->unpack = unpack_float_64; break; default: #if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 6 PyErr_SetString(PyExc_NotImplementedError, "Float not 16, 32 or 64 bits."); #else PyErr_SetString(PyExc_NotImplementedError, "Float not 32 or 64 bits."); #endif return (-1); } return (0); } static int field_info_init_bool(struct field_info_t *self_p, int number_of_bits) { self_p->pack = pack_bool; self_p->unpack = unpack_bool; if (number_of_bits > 64) { PyErr_SetString(PyExc_NotImplementedError, "Bool over 64 bits."); return (-1); } return (0); } static int field_info_init_text(struct field_info_t *self_p, int number_of_bits) { self_p->pack = pack_text; self_p->unpack = unpack_text; if ((number_of_bits % 8) != 0) { PyErr_SetString(PyExc_NotImplementedError, "Text not multiple of 8 bits."); return (-1); } return (0); } static int field_info_init_raw(struct field_info_t *self_p, int number_of_bits) { self_p->pack = pack_raw; self_p->unpack = unpack_raw; if ((number_of_bits % 8) != 0) { PyErr_SetString(PyExc_NotImplementedError, "Raw not multiple of 8 bits."); return (-1); } return (0); } static int field_info_init_zero_padding(struct field_info_t *self_p) { self_p->pack = pack_zero_padding; self_p->unpack = unpack_padding; return (0); } static int field_info_init_one_padding(struct field_info_t *self_p) { self_p->pack = pack_one_padding; self_p->unpack = unpack_padding; return (0); } static int field_info_init(struct field_info_t *self_p, int kind, int number_of_bits) { int res; bool is_padding; is_padding = false; switch (kind) { case 's': res = field_info_init_signed(self_p, number_of_bits); break; case 'u': res = field_info_init_unsigned(self_p, number_of_bits); break; case 'f': res = field_info_init_float(self_p, number_of_bits); break; case 'b': res = field_info_init_bool(self_p, number_of_bits); break; case 't': res = field_info_init_text(self_p, number_of_bits); break; case 'r': res = field_info_init_raw(self_p, number_of_bits); break; case 'p': is_padding = true; res = field_info_init_zero_padding(self_p); break; case 'P': is_padding = true; res = field_info_init_one_padding(self_p); break; default: PyErr_Format(PyExc_ValueError, "Bad format field type '%c'.", kind); res = -1; break; } self_p->number_of_bits = number_of_bits; self_p->is_padding = is_padding; return (res); } static int count_number_of_fields(const char *format_p, int *number_of_padding_fields_p) { int count; count = 0; *number_of_padding_fields_p = 0; while (*format_p != '\0') { if ((*format_p >= 'A') && (*format_p <= 'z')) { count++; if ((*format_p == 'p') || (*format_p == 'P')) { (*number_of_padding_fields_p)++; } } format_p++; } return (count); } const char *parse_field(const char *format_p, int *kind_p, int *number_of_bits_p) { while (isspace(*format_p)) { format_p++; } *kind_p = *format_p; *number_of_bits_p = 0; format_p++; while (isdigit(*format_p)) { if (*number_of_bits_p > (INT_MAX / 100)) { PyErr_SetString(PyExc_ValueError, "Field too long."); return (NULL); } *number_of_bits_p *= 10; *number_of_bits_p += (*format_p - '0'); format_p++; } if (*number_of_bits_p == 0) { PyErr_SetString(PyExc_ValueError, "Field of size 0."); format_p = NULL; } return (format_p); } static struct info_t *parse_format(PyObject *format_obj_p) { int number_of_fields; struct info_t *info_p; const char *format_p; int i; int kind; int number_of_bits; int number_of_padding_fields; int res; format_p = PyUnicode_AsUTF8(format_obj_p); if (format_p == NULL) { return (NULL); } number_of_fields = count_number_of_fields(format_p, &number_of_padding_fields); info_p = PyMem_RawMalloc( sizeof(*info_p) + number_of_fields * sizeof(info_p->fields[0])); if (info_p == NULL) { return (NULL); } info_p->number_of_bits = 0; info_p->number_of_fields = number_of_fields; info_p->number_of_non_padding_fields = ( number_of_fields - number_of_padding_fields); for (i = 0; i < info_p->number_of_fields; i++) { format_p = parse_field(format_p, &kind, &number_of_bits); if (format_p == NULL) { PyMem_RawFree(info_p); return (NULL); } res = field_info_init(&info_p->fields[i], kind, number_of_bits); if (res != 0) { PyMem_RawFree(info_p); return (NULL); } info_p->number_of_bits += number_of_bits; } return (info_p); } static void pack_pack(struct info_t *info_p, PyObject *args_p, int consumed_args, struct bitstream_writer_t *writer_p) { PyObject *value_p; int i; struct field_info_t *field_p; for (i = 0; i < info_p->number_of_fields; i++) { field_p = &info_p->fields[i]; if (field_p->is_padding) { value_p = NULL; } else { value_p = PyTuple_GET_ITEM(args_p, consumed_args); consumed_args++; } info_p->fields[i].pack(writer_p, value_p, field_p); } } static PyObject *pack_prepare(struct info_t *info_p, struct bitstream_writer_t *writer_p) { PyObject *packed_p; packed_p = PyBytes_FromStringAndSize(NULL, (info_p->number_of_bits + 7) / 8); if (packed_p == NULL) { return (NULL); } bitstream_writer_init(writer_p, (uint8_t *)PyBytes_AS_STRING(packed_p)); return (packed_p); } static PyObject *pack_finalize(PyObject *packed_p) { if (PyErr_Occurred() != NULL) { Py_DECREF(packed_p); packed_p = NULL; } return (packed_p); } static PyObject *pack(struct info_t *info_p, PyObject *args_p, int consumed_args, Py_ssize_t number_of_args) { struct bitstream_writer_t writer; PyObject *packed_p; if (number_of_args < info_p->number_of_non_padding_fields) { PyErr_SetString(PyExc_ValueError, "Too few arguments."); return (NULL); } packed_p = pack_prepare(info_p, &writer); if (packed_p == NULL) { return (NULL); } pack_pack(info_p, args_p, consumed_args, &writer); return (pack_finalize(packed_p)); } PyDoc_STRVAR(pack___doc__, "pack(fmt, *args)\n" "--\n" "\n"); static PyObject *m_pack(PyObject *module_p, PyObject *args_p) { Py_ssize_t number_of_args; PyObject *packed_p; struct info_t *info_p; number_of_args = PyTuple_GET_SIZE(args_p); if (number_of_args < 1) { PyErr_SetString(PyExc_ValueError, "No format string."); return (NULL); } info_p = parse_format(PyTuple_GET_ITEM(args_p, 0)); if (info_p == NULL) { return (NULL); } packed_p = pack(info_p, args_p, 1, number_of_args - 1); PyMem_RawFree(info_p); return (packed_p); } static PyObject *unpack(struct info_t *info_p, PyObject *data_p, long offset) { struct bitstream_reader_t reader; PyObject *unpacked_p; PyObject *value_p; char *packed_p; int i; int produced_args; Py_ssize_t size; int res; unpacked_p = PyTuple_New(info_p->number_of_non_padding_fields); if (unpacked_p == NULL) { return (NULL); } res = PyBytes_AsStringAndSize(data_p, &packed_p, &size); if (res == -1) { goto out1; } if (size < ((info_p->number_of_bits + offset + 7) / 8)) { PyErr_SetString(PyExc_ValueError, "Short data."); goto out1; } bitstream_reader_init(&reader, (uint8_t *)packed_p); bitstream_reader_seek(&reader, offset); produced_args = 0; for (i = 0; i < info_p->number_of_fields; i++) { value_p = info_p->fields[i].unpack(&reader, &info_p->fields[i]); if (value_p != NULL) { PyTuple_SET_ITEM(unpacked_p, produced_args, value_p); produced_args++; } } out1: if (PyErr_Occurred() != NULL) { Py_DECREF(unpacked_p); unpacked_p = NULL; } return (unpacked_p); } PyDoc_STRVAR(unpack___doc__, "unpack(fmt, data)\n" "--\n" "\n"); static PyObject *m_unpack(PyObject *module_p, PyObject *args_p) { PyObject *format_p; PyObject *data_p; PyObject *unpacked_p; struct info_t *info_p; int res; res = PyArg_ParseTuple(args_p, "OO", &format_p, &data_p); if (res == 0) { return (NULL); } info_p = parse_format(format_p); if (info_p == NULL) { return (NULL); } unpacked_p = unpack(info_p, data_p, 0); PyMem_RawFree(info_p); return (unpacked_p); } static long parse_offset(PyObject *offset_p) { unsigned long offset; offset = PyLong_AsUnsignedLong(offset_p); if (offset == (unsigned long)-1) { return (-1); } if (offset > 0x7fffffff) { PyErr_Format(PyExc_ValueError, "Offset must be less or equal to %d bits.", 0x7fffffff); return (-1); } return (offset); } static int pack_into_prepare(struct info_t *info_p, PyObject *buf_p, PyObject *offset_p, struct bitstream_writer_t *writer_p, struct bitstream_writer_bounds_t *bounds_p) { uint8_t *packed_p; Py_ssize_t size; long offset; offset = parse_offset(offset_p); if (offset == -1) { return (-1); } if (!PyByteArray_Check(buf_p)) { PyErr_SetString(PyExc_TypeError, "Bytearray needed."); return (-1); } packed_p = (uint8_t *)PyByteArray_AsString(buf_p); if (packed_p == NULL) { return (-1); } size = PyByteArray_GET_SIZE(buf_p); if (size < ((info_p->number_of_bits + offset + 7) / 8)) { PyErr_Format(PyExc_ValueError, "pack_into requires a buffer of at least %ld bits", info_p->number_of_bits + offset); return (-1); } bitstream_writer_init(writer_p, packed_p); bitstream_writer_bounds_save(bounds_p, writer_p, offset, info_p->number_of_bits); bitstream_writer_seek(writer_p, offset); return (0); } static PyObject *pack_into_finalize(struct bitstream_writer_bounds_t *bounds_p) { bitstream_writer_bounds_restore(bounds_p); if (PyErr_Occurred() != NULL) { return (NULL); } Py_INCREF(Py_None); return (Py_None); } static PyObject *pack_into(struct info_t *info_p, PyObject *buf_p, PyObject *offset_p, PyObject *args_p, Py_ssize_t consumed_args, Py_ssize_t number_of_args) { struct bitstream_writer_t writer; struct bitstream_writer_bounds_t bounds; int res; if ((number_of_args - consumed_args) < info_p->number_of_non_padding_fields) { PyErr_SetString(PyExc_ValueError, "Too few arguments."); return (NULL); } res = pack_into_prepare(info_p, buf_p, offset_p, &writer, &bounds); if (res != 0) { return (NULL); } pack_pack(info_p, args_p, consumed_args, &writer); return (pack_into_finalize(&bounds)); } PyDoc_STRVAR(pack_into___doc__, "pack_into(fmt, buf, offset, *args, **kwargs)\n" "--\n" "\n"); static PyObject *m_pack_into(PyObject *module_p, PyObject *args_p, PyObject *kwargs_p) { PyObject *format_p; PyObject *buf_p; PyObject *offset_p; PyObject *res_p; Py_ssize_t number_of_args; struct info_t *info_p; number_of_args = PyTuple_GET_SIZE(args_p); if (number_of_args < 3) { PyErr_SetString(PyExc_ValueError, "Too few arguments."); return (NULL); } format_p = PyTuple_GET_ITEM(args_p, 0); buf_p = PyTuple_GET_ITEM(args_p, 1); offset_p = PyTuple_GET_ITEM(args_p, 2); info_p = parse_format(format_p); if (info_p == NULL) { return (NULL); } res_p = pack_into(info_p, buf_p, offset_p, args_p, 3, number_of_args); PyMem_RawFree(info_p); return (res_p); } static PyObject *unpack_from(struct info_t *info_p, PyObject *data_p, PyObject *offset_p) { long offset; offset = parse_offset(offset_p); if (offset == -1) { return (NULL); } return (unpack(info_p, data_p, offset)); } PyDoc_STRVAR(unpack_from___doc__, "unpack_from(fmt, data, offset=0)\n" "--\n" "\n"); static PyObject *m_unpack_from(PyObject *module_p, PyObject *args_p, PyObject *kwargs_p) { PyObject *format_p; PyObject *data_p; PyObject *offset_p; PyObject *unpacked_p; struct info_t *info_p; int res; static char *keywords[] = { "fmt", "data", "offset", NULL }; offset_p = py_zero_p; res = PyArg_ParseTupleAndKeywords(args_p, kwargs_p, "OO|O", &keywords[0], &format_p, &data_p, &offset_p); if (res == 0) { return (NULL); } info_p = parse_format(format_p); if (info_p == NULL) { return (NULL); } unpacked_p = unpack_from(info_p, data_p, offset_p); PyMem_RawFree(info_p); return (unpacked_p); } static void pack_dict_pack(struct info_t *info_p, PyObject *names_p, PyObject *data_p, struct bitstream_writer_t *writer_p) { PyObject *value_p; int i; int consumed_args; struct field_info_t *field_p; consumed_args = 0; for (i = 0; i < info_p->number_of_fields; i++) { field_p = &info_p->fields[i]; if (field_p->is_padding) { value_p = NULL; } else { value_p = PyDict_GetItem(data_p, PyList_GET_ITEM(names_p, consumed_args)); consumed_args++; if (value_p == NULL) { PyErr_SetString(PyExc_KeyError, "Missing value."); break; } } info_p->fields[i].pack(writer_p, value_p, field_p); } } static PyObject *pack_dict(struct info_t *info_p, PyObject *names_p, PyObject *data_p) { struct bitstream_writer_t writer; PyObject *packed_p; if (PyList_GET_SIZE(names_p) < info_p->number_of_non_padding_fields) { PyErr_SetString(PyExc_ValueError, "Too few names."); return (NULL); } packed_p = pack_prepare(info_p, &writer); if (packed_p == NULL) { return (NULL); } pack_dict_pack(info_p, names_p, data_p, &writer); return (pack_finalize(packed_p)); } PyDoc_STRVAR(pack_dict___doc__, "pack_dict(fmt, names, data)\n" "--\n" "\n"); static PyObject *m_pack_dict(PyObject *module_p, PyObject *args_p) { PyObject *format_p; PyObject *names_p; PyObject *data_p; PyObject *packed_p; struct info_t *info_p; int res; res = PyArg_ParseTuple(args_p, "OOO", &format_p, &names_p, &data_p); if (res == 0) { return (NULL); } info_p = parse_format(format_p); if (info_p == NULL) { return (NULL); } if (!is_names_list(names_p)) { return (NULL); } packed_p = pack_dict(info_p, names_p, data_p); PyMem_RawFree(info_p); return (packed_p); } static PyObject *unpack_dict(struct info_t *info_p, PyObject *names_p, PyObject *data_p, long offset) { struct bitstream_reader_t reader; PyObject *unpacked_p; PyObject *value_p; char *packed_p; int i; Py_ssize_t size; int res; int produced_args; if (PyList_GET_SIZE(names_p) < info_p->number_of_non_padding_fields) { PyErr_SetString(PyExc_ValueError, "Too few names."); return (NULL); } unpacked_p = PyDict_New(); if (unpacked_p == NULL) { return (NULL); } res = PyBytes_AsStringAndSize(data_p, &packed_p, &size); if (res == -1) { goto out1; } if (size < ((info_p->number_of_bits + offset + 7) / 8)) { PyErr_SetString(PyExc_ValueError, "Short data."); goto out1; } bitstream_reader_init(&reader, (uint8_t *)packed_p); bitstream_reader_seek(&reader, offset); produced_args = 0; for (i = 0; i < info_p->number_of_fields; i++) { value_p = info_p->fields[i].unpack(&reader, &info_p->fields[i]); if (value_p != NULL) { PyDict_SetItem(unpacked_p, PyList_GET_ITEM(names_p, produced_args), value_p); produced_args++; } } out1: if (PyErr_Occurred() != NULL) { Py_DECREF(unpacked_p); unpacked_p = NULL; } return (unpacked_p); } PyDoc_STRVAR(unpack_dict___doc__, "unpack_dict(fmt, names, data)\n" "--\n" "\n"); static PyObject *m_unpack_dict(PyObject *module_p, PyObject *args_p) { PyObject *format_p; PyObject *names_p; PyObject *data_p; PyObject *unpacked_p; struct info_t *info_p; int res; res = PyArg_ParseTuple(args_p, "OOO", &format_p, &names_p, &data_p); if (res == 0) { return (NULL); } info_p = parse_format(format_p); if (info_p == NULL) { return (NULL); } if (!is_names_list(names_p)) { return (NULL); } unpacked_p = unpack_dict(info_p, names_p, data_p, 0); PyMem_RawFree(info_p); return (unpacked_p); } static PyObject *unpack_from_dict(struct info_t *info_p, PyObject *names_p, PyObject *data_p, PyObject *offset_p) { long offset; offset = parse_offset(offset_p); if (offset == -1) { return (NULL); } return (unpack_dict(info_p, names_p, data_p, offset)); } static PyObject *pack_into_dict(struct info_t *info_p, PyObject *names_p, PyObject *buf_p, PyObject *offset_p, PyObject *data_p) { struct bitstream_writer_t writer; struct bitstream_writer_bounds_t bounds; int res; res = pack_into_prepare(info_p, buf_p, offset_p, &writer, &bounds); if (res != 0) { return (NULL); } pack_dict_pack(info_p, names_p, data_p, &writer); return (pack_into_finalize(&bounds)); } PyDoc_STRVAR(pack_into_dict___doc__, "pack_into_dict(fmt, names, buf, offset, data, **kwargs)\n" "--\n" "\n"); static PyObject *m_pack_into_dict(PyObject *module_p, PyObject *args_p, PyObject *kwargs_p) { PyObject *format_p; PyObject *names_p; PyObject *buf_p; PyObject *offset_p; PyObject *data_p; PyObject *res_p; struct info_t *info_p; int res; static char *keywords[] = { "fmt", "names", "buf", "offset", "data", NULL }; offset_p = py_zero_p; res = PyArg_ParseTupleAndKeywords(args_p, kwargs_p, "OOOOO", &keywords[0], &format_p, &names_p, &buf_p, &offset_p, &data_p); if (res == 0) { return (NULL); } info_p = parse_format(format_p); if (info_p == NULL) { return (NULL); } if (!is_names_list(names_p)) { return (NULL); } res_p = pack_into_dict(info_p, names_p, buf_p, offset_p, data_p); PyMem_RawFree(info_p); return (res_p); } PyDoc_STRVAR(unpack_from_dict___doc__, "unpack_from_dict(fmt, names, data, offset=0)\n" "--\n" "\n"); static PyObject *m_unpack_from_dict(PyObject *module_p, PyObject *args_p, PyObject *kwargs_p) { PyObject *format_p; PyObject *names_p; PyObject *data_p; PyObject *offset_p; PyObject *unpacked_p; struct info_t *info_p; int res; static char *keywords[] = { "fmt", "names", "data", "offset", NULL }; offset_p = py_zero_p; res = PyArg_ParseTupleAndKeywords(args_p, kwargs_p, "OOO|O", &keywords[0], &format_p, &names_p, &data_p, &offset_p); if (res == 0) { return (NULL); } info_p = parse_format(format_p); if (info_p == NULL) { return (NULL); } if (!is_names_list(names_p)) { return (NULL); } unpacked_p = unpack_from_dict(info_p, names_p, data_p, offset_p); PyMem_RawFree(info_p); return (unpacked_p); } static PyObject *calcsize(struct info_t *info_p) { return (PyLong_FromLong(info_p->number_of_bits)); } PyDoc_STRVAR(calcsize___doc__, "calcsize(fmt)\n" "--\n" "\n"); static PyObject *m_calcsize(PyObject *module_p, PyObject *format_p) { PyObject *size_p; struct info_t *info_p; info_p = parse_format(format_p); if (info_p == NULL) { return (NULL); } size_p = calcsize(info_p); PyMem_RawFree(info_p); return (size_p); } PyDoc_STRVAR(byteswap___doc__, "byteswap(fmt, data, offset=0)\n" "--\n" "\n"); static PyObject *m_byteswap(PyObject *module_p, PyObject *args_p) { PyObject *format_p; PyObject *data_p; PyObject *swapped_p; const char *c_format_p; uint8_t *src_p; uint8_t *dst_p; Py_ssize_t size; int res; int offset; res = PyArg_ParseTuple(args_p, "OO", &format_p, &data_p); if (res == 0) { return (NULL); } c_format_p = PyUnicode_AsUTF8(format_p); if (c_format_p == NULL) { return (NULL); } res = PyBytes_AsStringAndSize(data_p, (char **)&src_p, &size); if (res == -1) { return (NULL); } swapped_p = PyBytes_FromStringAndSize(NULL, size); if (swapped_p == NULL) { return (NULL); } dst_p = (uint8_t *)PyBytes_AS_STRING(swapped_p); offset = 0; while (*c_format_p != '\0') { switch (*c_format_p) { case '1': if ((size - offset) < 1) { goto out1; } dst_p[offset] = src_p[offset]; offset += 1; break; case '2': if ((size - offset) < 2) { goto out1; } dst_p[offset + 0] = src_p[offset + 1]; dst_p[offset + 1] = src_p[offset + 0]; offset += 2; break; case '4': if ((size - offset) < 4) { goto out1; } dst_p[offset + 0] = src_p[offset + 3]; dst_p[offset + 1] = src_p[offset + 2]; dst_p[offset + 2] = src_p[offset + 1]; dst_p[offset + 3] = src_p[offset + 0]; offset += 4; break; case '8': if ((size - offset) < 8) { goto out1; } dst_p[offset + 0] = src_p[offset + 7]; dst_p[offset + 1] = src_p[offset + 6]; dst_p[offset + 2] = src_p[offset + 5]; dst_p[offset + 3] = src_p[offset + 4]; dst_p[offset + 4] = src_p[offset + 3]; dst_p[offset + 5] = src_p[offset + 2]; dst_p[offset + 6] = src_p[offset + 1]; dst_p[offset + 7] = src_p[offset + 0]; offset += 8; break; default: PyErr_Format(PyExc_ValueError, "Expected 1, 2, 4 or 8, but got %c.", (char)*c_format_p); goto out2; } c_format_p++; } return (swapped_p); out1: PyErr_SetString(PyExc_ValueError, "Out of data to swap."); out2: return (NULL); } static PyObject *compiled_format_new(PyTypeObject *subtype_p, PyObject *format_p) { struct compiled_format_t *self_p; self_p = (struct compiled_format_t *)subtype_p->tp_alloc(subtype_p, 0); if (self_p != NULL) { self_p->info_p = parse_format(format_p); if (self_p->info_p == NULL) { PyObject_Free(self_p); self_p = NULL; } } return ((PyObject *)self_p); } static void compiled_format_dealloc(struct compiled_format_t *self_p) { PyMem_RawFree(self_p->info_p); } static PyObject *m_compiled_format_pack(struct compiled_format_t *self_p, PyObject *args_p) { return (pack(self_p->info_p, args_p, 0, PyTuple_GET_SIZE(args_p))); } static PyObject *m_compiled_format_unpack(struct compiled_format_t *self_p, PyObject *args_p) { PyObject *data_p; int res; res = PyArg_ParseTuple(args_p, "O", &data_p); if (res == 0) { return (NULL); } return (unpack(self_p->info_p, data_p, 0)); } static PyObject *m_compiled_format_pack_into(struct compiled_format_t *self_p, PyObject *args_p, PyObject *kwargs_p) { PyObject *buf_p; PyObject *offset_p; Py_ssize_t number_of_args; number_of_args = PyTuple_GET_SIZE(args_p); if (number_of_args < 2) { PyErr_SetString(PyExc_ValueError, "Too few arguments."); return (NULL); } buf_p = PyTuple_GET_ITEM(args_p, 0); offset_p = PyTuple_GET_ITEM(args_p, 1); return (pack_into(self_p->info_p, buf_p, offset_p, args_p, 2, number_of_args)); } static PyObject *m_compiled_format_unpack_from(struct compiled_format_t *self_p, PyObject *args_p, PyObject *kwargs_p) { PyObject *data_p; PyObject *offset_p; int res; static char *keywords[] = { "data", "offset", NULL }; offset_p = py_zero_p; res = PyArg_ParseTupleAndKeywords(args_p, kwargs_p, "O|O", &keywords[0], &data_p, &offset_p); if (res == 0) { return (NULL); } return (unpack_from(self_p->info_p, data_p, offset_p)); } static PyObject *m_compiled_format_calcsize(struct compiled_format_t *self_p) { return (calcsize(self_p->info_p)); } static struct PyMethodDef compiled_format_methods[] = { { "pack", (PyCFunction)m_compiled_format_pack, METH_VARARGS, pack___doc__ }, { "unpack", (PyCFunction)m_compiled_format_unpack, METH_VARARGS, unpack___doc__ }, { "pack_into", (PyCFunction)m_compiled_format_pack_into, METH_VARARGS | METH_KEYWORDS, pack_into___doc__ }, { "unpack_from", (PyCFunction)m_compiled_format_unpack_from, METH_VARARGS | METH_KEYWORDS, unpack_from___doc__ }, { "calcsize", (PyCFunction)m_compiled_format_calcsize, METH_NOARGS, calcsize___doc__ }, { NULL } }; static PyTypeObject compiled_format_type = { PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "bitstruct.c.CompiledFormat", .tp_doc = NULL, .tp_basicsize = sizeof(struct compiled_format_t), .tp_itemsize = 0, .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, .tp_dealloc = (destructor)compiled_format_dealloc, .tp_methods = compiled_format_methods, }; static PyObject *compiled_format_dict_new(PyTypeObject *subtype_p, PyObject *format_p, PyObject *names_p) { struct compiled_format_dict_t *self_p; if (!is_names_list(names_p)) { return (NULL); } self_p = (struct compiled_format_dict_t *)subtype_p->tp_alloc(subtype_p, 0); if (self_p != NULL) { self_p->info_p = parse_format(format_p); if (self_p->info_p == NULL) { PyObject_Free(self_p); self_p = NULL; } else { Py_INCREF(names_p); self_p->names_p = names_p; } } return ((PyObject *)self_p); } static void compiled_format_dict_dealloc(struct compiled_format_dict_t *self_p) { PyMem_RawFree(self_p->info_p); Py_DECREF(self_p->names_p); } static PyObject *m_compiled_format_dict_pack(struct compiled_format_dict_t *self_p, PyObject *data_p) { return (pack_dict(self_p->info_p, self_p->names_p, data_p)); } static PyObject *m_compiled_format_dict_unpack( struct compiled_format_dict_t *self_p, PyObject *data_p) { return (unpack_dict(self_p->info_p, self_p->names_p, data_p, 0)); } static PyObject *m_compiled_format_dict_pack_into( struct compiled_format_dict_t *self_p, PyObject *args_p, PyObject *kwargs_p) { PyObject *buf_p; PyObject *data_p; PyObject *offset_p; int res; static char *keywords[] = { "buf", "data", "offset", NULL }; res = PyArg_ParseTupleAndKeywords(args_p, kwargs_p, "OOO", &keywords[0], &buf_p, &data_p, &offset_p); if (res == 0) { return (NULL); } return (pack_into_dict(self_p->info_p, self_p->names_p, buf_p, data_p, offset_p)); } static PyObject *m_compiled_format_dict_unpack_from( struct compiled_format_dict_t *self_p, PyObject *args_p, PyObject *kwargs_p) { PyObject *data_p; PyObject *offset_p; int res; static char *keywords[] = { "data", "offset", NULL }; offset_p = py_zero_p; res = PyArg_ParseTupleAndKeywords(args_p, kwargs_p, "O|O", &keywords[0], &data_p, &offset_p); if (res == 0) { return (NULL); } return (unpack_from_dict(self_p->info_p, self_p->names_p, data_p, offset_p)); } static PyObject *m_compiled_format_dict_calcsize( struct compiled_format_dict_t *self_p) { return (calcsize(self_p->info_p)); } static struct PyMethodDef compiled_format_dict_methods[] = { { "pack", (PyCFunction)m_compiled_format_dict_pack, METH_O, pack___doc__ }, { "unpack", (PyCFunction)m_compiled_format_dict_unpack, METH_O, unpack___doc__ }, { "pack_into", (PyCFunction)m_compiled_format_dict_pack_into, METH_VARARGS | METH_KEYWORDS, pack_into___doc__ }, { "unpack_from", (PyCFunction)m_compiled_format_dict_unpack_from, METH_VARARGS | METH_KEYWORDS, unpack_from___doc__ }, { "calcsize", (PyCFunction)m_compiled_format_dict_calcsize, METH_NOARGS, calcsize___doc__ }, { NULL } }; static PyTypeObject compiled_format_dict_type = { PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "bitstruct.c.CompiledFormatDict", .tp_doc = NULL, .tp_basicsize = sizeof(struct compiled_format_dict_t), .tp_itemsize = 0, .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, .tp_dealloc = (destructor)compiled_format_dict_dealloc, .tp_methods = compiled_format_dict_methods, }; PyDoc_STRVAR(compile___doc__, "compile(fmt, names=None)\n" "--\n" "\n"); static PyObject *m_compile(PyObject *module_p, PyObject *args_p, PyObject *kwargs_p) { PyObject *format_p; PyObject *names_p; int res; static char *keywords[] = { "fmt", "names", NULL }; names_p = Py_None; res = PyArg_ParseTupleAndKeywords(args_p, kwargs_p, "O|O", &keywords[0], &format_p, &names_p); if (res == 0) { return (NULL); } if (names_p == Py_None) { return (compiled_format_new(&compiled_format_type, format_p)); } else { return (compiled_format_dict_new(&compiled_format_dict_type, format_p, names_p)); } } static struct PyMethodDef methods[] = { { "pack", m_pack, METH_VARARGS, pack___doc__ }, { "unpack", m_unpack, METH_VARARGS, unpack___doc__ }, { "pack_into", (PyCFunction)m_pack_into, METH_VARARGS | METH_KEYWORDS, pack_into___doc__ }, { "unpack_from", (PyCFunction)m_unpack_from, METH_VARARGS | METH_KEYWORDS, unpack_from___doc__ }, { "pack_dict", m_pack_dict, METH_VARARGS, pack_dict___doc__ }, { "unpack_dict", m_unpack_dict, METH_VARARGS, unpack_dict___doc__ }, { "pack_into_dict", (PyCFunction)m_pack_into_dict, METH_VARARGS | METH_KEYWORDS, pack_into_dict___doc__ }, { "unpack_from_dict", (PyCFunction)m_unpack_from_dict, METH_VARARGS | METH_KEYWORDS, unpack_from_dict___doc__ }, { "calcsize", m_calcsize, METH_O, calcsize___doc__ }, { "byteswap", m_byteswap, METH_VARARGS, byteswap___doc__ }, { "compile", (PyCFunction)m_compile, METH_VARARGS | METH_KEYWORDS, compile___doc__ }, { NULL } }; static PyModuleDef module = { PyModuleDef_HEAD_INIT, .m_name = "bitstruct.c", .m_doc = "bitstruct C extension", .m_size = -1, .m_methods = methods }; PyMODINIT_FUNC PyInit_c(void) { PyObject *module_p; py_zero_p = PyLong_FromLong(0); module_p = PyModule_Create(&module); if (module_p == NULL) { return (NULL); } if (PyType_Ready(&compiled_format_type) < 0) { return (NULL); } if (PyType_Ready(&compiled_format_dict_type) < 0) { return (NULL); } return (module_p); } bitstruct-8.9.0/setup.cfg0000664000175000017500000000004613611423315015303 0ustar erikerik00000000000000[egg_info] tag_build = tag_date = 0 bitstruct-8.9.0/setup.py0000775000175000017500000000314413544063630015206 0ustar erikerik00000000000000#!/usr/bin/env python import sys import re import setuptools from setuptools import find_packages def find_version(): return re.search(r"^__version__ = '(.*)'$", open('bitstruct/version.py', 'r').read(), re.MULTILINE).group(1) def setup(ext_modules): setuptools.setup( name='bitstruct', version=find_version(), description=('This module performs conversions between Python values ' 'and C bit field structs represented as Python ' 'byte strings.'), long_description=open('README.rst', 'r').read(), author='Erik Moqvist, Ilya Petukhov', author_email='erik.moqvist@gmail.com', license='MIT', classifiers=[ 'License :: OSI Approved :: MIT License', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 3', ], keywords=['bit field', 'bit parsing', 'bit unpack', 'bit pack'], url='https://github.com/eerimoq/bitstruct', packages=find_packages(exclude=['tests']), ext_modules=ext_modules, test_suite="tests") if sys.version_info[0] > 2: try: setup([setuptools.Extension('bitstruct.c', sources=[ 'bitstruct/c.c', 'bitstruct/bitstream.c' ])]) except: print('WARNING: Failed to build the C extension.') setup([]) else: print('INFO: C extension not implemented in Python 2.') setup([])