├── .github └── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── concrete_bug.md │ ├── documentation.md │ └── feature_request.md ├── .gitignore ├── AUTHORS ├── COPYING ├── ChangeLog ├── INSTALL ├── LICENSE ├── LICENSE-pfp ├── Makefile.am ├── Makefile.in ├── NEWS ├── README ├── README-pfp.md ├── README.md ├── aclocal.m4 ├── bin ├── build_docs └── run_tests ├── bt.h ├── build.sh ├── checkers ├── avi.sh ├── bmp.sh ├── gif.sh ├── jpg.sh ├── midi.sh ├── mp3.sh ├── mp4.sh ├── pcap.sh ├── png.sh ├── wav.sh ├── zip.sh └── zipadv.sh ├── config.h.in ├── configure ├── configure.ac ├── depcomp ├── docs ├── .bundle │ └── config ├── .gitignore ├── .sass-cache │ └── d1bb5f1978af923d84e65a2ac37e32e066e7ca58 │ │ ├── fonts.scssc │ │ ├── jekyll-theme-minimal.scssc │ │ └── rouge-github.scssc ├── Gemfile ├── Makefile ├── README.md ├── README.txt ├── _config.yml ├── _posts │ └── 2021-11-09-How-to-make-GIFs.md ├── assets │ ├── GIF_Chrome.png │ ├── GIF_Firefox.png │ ├── GIF_Safari.png │ ├── Icon.key │ ├── Newtons_cradle_animation_book_2.gif │ ├── Splash.key │ ├── css │ │ ├── font-awesome.css │ │ ├── font-awesome.min.css │ │ └── style.scss │ ├── gif-fuzzer.gif │ ├── six-rectangles.gif │ └── three-rectangles.gif └── index.md ├── examples └── demo.png ├── ffcompile ├── file_accessor.h ├── formatfuzzer.h ├── fuzzer.cpp ├── gif.cpp ├── install-sh ├── m4 ├── m4_ax_cxx_compile_stdcxx.m4 └── m4_ax_cxx_compile_stdcxx_11.m4 ├── missing ├── pfp ├── __init__.py ├── __main__.py ├── bitwrap.py ├── dbg.py ├── errors.py ├── fields.py ├── functions.py ├── fuzz │ ├── __init__.py │ ├── basic.py │ ├── rand.py │ └── strats.py ├── interp.py ├── native │ ├── __init__.py │ ├── compat_consts.py │ ├── compat_interface.py │ ├── compat_io.py │ ├── compat_math.py │ ├── compat_string.py │ ├── compat_tools.py │ ├── dbg.py │ ├── packers.py │ └── watchers.py └── utils.py ├── png.cpp ├── requirements.txt ├── setup.cfg ├── setup.py ├── specification ├── ISO_IEC_14496-12_2005-04-01.pdf └── ISO_IEC_14496-14_2003-11-15.pdf ├── templates ├── avi-orig.bt ├── avi.bt ├── bmp-orig.bt ├── bmp.bt ├── dex-orig.bt ├── doc-orig.bt ├── elf-orig.bt ├── gif-orig.bt ├── gif.bt ├── jpg-orig.bt ├── jpg.bt ├── midi-orig.bt ├── midi.bt ├── mp3-orig.bt ├── mp3.bt ├── mp4-orig.bt ├── mp4.bt ├── ogg-orig.bt ├── pcap-orig.bt ├── pcap.bt ├── pdf-orig.bt ├── png-orig.bt ├── png.bt ├── wav-orig.bt ├── wav.bt ├── zip-orig.bt └── zip.bt ├── testcases ├── avi │ ├── Dev_Source_ESB_Base_ThirdParty_ASP.NET_Databinding_DataBinding_docs_bmp_search.avi │ ├── TargetVideo_target_video7.avi │ ├── XPSP1_NT_printscan_ui_shellext_src_cam.avi │ ├── dll_win32_shell32_res_avis_152.avi │ ├── private_shell_shdocvw_iforms.avi │ ├── small_movie.avi │ ├── source_Client_res_Upload.avi │ ├── video_Registration.avi │ ├── video_test_bwrgb.avi │ ├── webclient_node_modules_@videojs_vhs-utils_test_fixtures_formats_avi_av01.avi │ └── webclient_node_modules_@videojs_vhs-utils_test_fixtures_formats_avi_avc1.640028.avi ├── bmp │ ├── input.bmp │ ├── not_kitty.bmp │ ├── plus.bmp │ ├── tclmagick-small-diff.bmp │ ├── testimg.bmp │ ├── toolbar.bmp │ ├── valid.1.bmp │ ├── w32g_sleep.bmp │ ├── w32g_subbtn.bmp │ └── w32g_tracer.bmp ├── empty │ └── empty ├── gif │ ├── czoch.gif │ ├── lineup_16.gif │ ├── mri.gif │ ├── not_kitty.gif │ ├── polyfish_lines.gif │ └── prototein.gif ├── jpg │ ├── not_kitty.jpg │ ├── testimgint.jpg │ ├── testorig.jpg │ ├── testorig12.jpg │ ├── w3c_home.jpg │ ├── w3c_home_256.jpg │ └── w3c_home_gray.jpg ├── midi │ ├── 180 BPM - Ghostly Night - Fills.mid │ ├── Nashville - 130BPM Downtown - Verse 01.mid │ ├── Ran-D - Living For The Moment 2.mid │ ├── beatbox.mid │ ├── chpn-p7_format0.mid │ └── sound.mid ├── mp4 │ ├── blank.mp4 │ ├── giphy (10).mp4 │ ├── openaigym.video.0.21111.video000113.mp4 │ ├── openaigym.video.108.53448.video000000.mp4 │ ├── qr.mp4 │ ├── quick-ui-003.mp4 │ ├── random_animation.mp4 │ ├── small_movie.mp4 │ ├── videotest.mp4 │ └── vk-flash-format-only.mp4 ├── pcap │ ├── NTLM-wenchao.pcap │ ├── bfd-raw-auth-md5.pcap │ ├── bfd-raw-auth-simple.pcap │ ├── ipv4frags.pcap │ └── small_capture.pcap ├── png │ ├── basn0g16.png │ ├── basn3p01.png │ ├── basn3p02.png │ ├── basn3p04.png │ ├── basn4a16.png │ ├── basn6a08.png │ ├── basn6a16.png │ ├── ftbbn0g02.png │ ├── ftbgn2c16.png │ ├── ftbrn2c08.png │ ├── ftbwn0g16.png │ ├── ftbwn3p08.png │ ├── ftbyn3p08.png │ ├── ftp1n3p08.png │ ├── ibasn0g08.png │ ├── ibasn0g16.png │ ├── ibasn2c08.png │ ├── ibasn3p08.png │ ├── ibasn4a08.png │ ├── ibasn4a16.png │ ├── ibasn6a08.png │ ├── ibasn6a16.png │ ├── iftbgn2c16.png │ ├── iftbwn0g16.png │ ├── iftp0n0g08.png │ ├── iftp0n2c08.png │ ├── iftp0n3p08.png │ ├── iftp1n3p08.png │ ├── not_kitty.png │ ├── not_kitty_alpha.png │ └── not_kitty_icc.png ├── wav │ ├── CreateWithCode_Prototype │ ├── HarvestCapitalism_Assets_Sounds_ButtonSoundCut.wav │ ├── audio_land_1.wav │ ├── sounds_disconnect.wav │ ├── test-44100Hz-2ch-32bit-float-le.wav │ ├── test-44100Hz-le-1ch-4bytes.wav │ ├── test-8000Hz-le-1ch-10S-20bit-extra.wav │ ├── test-8000Hz-le-1ch-1byte-ulaw.wav │ ├── test-8000Hz-le-2ch-1byteu.wav │ ├── test-8000Hz-le-3ch-5S-24bit.wav │ ├── test-8000Hz-le-3ch-5S-64bit.wav │ ├── test-8000Hz-le-4ch-9S-12bit.wav │ └── test-8000Hz-le-5ch-9S-5bit.wav └── zip │ ├── 666.zip │ ├── CS2102_HW_1.zip │ ├── L3_01_My-first-CSS-Document.zip │ ├── Machine 6.zip │ ├── Project Settings.zip │ ├── VCS_DRS_ZDT_AST.DRS.zip │ ├── project.zip │ ├── pse03-w0020.txt.zip │ ├── small_archive.zip │ ├── snake.zip │ ├── test25.zip │ ├── type-search-index.zip │ └── update_test_new_module.zip ├── tests ├── templates │ └── JPGTemplate.bt ├── test_arrays.py ├── test_basic.py ├── test_bitfields.py ├── test_bitwrap.py ├── test_cast.py ├── test_changeset.py ├── test_compat.py ├── test_compat_checksums.py ├── test_compat_strings.py ├── test_control_flow.py ├── test_dbg.py ├── test_enums.py ├── test_fields.py ├── test_functions.py ├── test_fuzz.py ├── test_integer_promotion.py ├── test_metadata.py ├── test_strings.py ├── test_struct_union.py ├── test_type_creation.py └── utils.py └── tox.ini /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: 'Error' 5 | labels: 'bug, needs-triage' 6 | assignees: 'd0c-s4vage' 7 | --- 8 | 9 | After creating the issue, checkboxes will appear where `[] label` exist in the 10 | markdown. You can check/uncheck them to fill out the environment section. 11 | 12 | ## Checklist 13 | 14 | - [ ] I have included the [relevant portions of the] 010 template used that caused the bug 15 | - [ ] I have filled out the environment section 16 | 17 | ## Environment 18 | 19 | **Platform** 20 | 21 | - [ ] Windows 22 | - [ ] Mac 23 | - [ ] Linux 24 | - [ ] Other (please specify) 25 | 26 | **Python Version** 27 | 28 | - [ ] Python 2.7 29 | - [ ] Python 3.4 30 | - [ ] Python 3.5 31 | - [ ] Python 3.6 32 | - [ ] Python 3.7 33 | - [ ] Python 3.8 34 | - [ ] Other (please specify) 35 | 36 | ## Describe the bug 37 | 38 | A clear and concise description of what the bug is. 39 | 40 | ## To Reproduce 41 | 42 | Steps to reproduce 43 | 44 | ## Expected Behavior 45 | 46 | A clear and concise description of what you expected to happen. 47 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/concrete_bug.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Concrete Bug 3 | about: A post-triage, concrete bug with full technical, actionable details 4 | title: '' 5 | labels: 'bug, concrete-issue' 6 | assignees: 'd0c-s4vage' 7 | --- 8 | 9 | After creating the issue, checkboxes will appear where `[] label` exist in the 10 | markdown. You can check/uncheck them to fill out the environment section. 11 | 12 | ## Checklist 13 | 14 | - [ ] I have included the [relevant portions of the] 010 template used that caused the bug 15 | - [ ] I have filled out the environment section 16 | 17 | ## Environment 18 | 19 | **Platform** 20 | 21 | - [ ] Windows 22 | - [ ] Mac 23 | - [ ] Linux 24 | - [ ] Other (please specify) 25 | 26 | **Python Version** 27 | 28 | - [ ] Python 2.7 29 | - [ ] Python 3.4 30 | - [ ] Python 3.5 31 | - [ ] Python 3.6 32 | - [ ] Python 3.7 33 | - [ ] Python 3.8 34 | - [ ] Other (please specify) 35 | 36 | ## Describe the bug 37 | 38 | A clear and concise description of what the bug is. 39 | 40 | ## Stack Trace 41 | 42 | Stack traces are required 43 | 44 | ``` 45 | stack trace here 46 | ``` 47 | 48 | ## To Reproduce 49 | 50 | Steps to reproduce 51 | 52 | ## Expected Behavior 53 | 54 | A clear and concise description of what you expected to happen. 55 | 56 | ## Implementation/Fix Notes/Thoughts 57 | 58 | Thoughts on what needs to change in the code to fix the bug. 59 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/documentation.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Documentation Improvement 3 | about: Suggest changes to documentation 4 | title: 'Documentation Improvement' 5 | labels: 'documentation' 6 | assignees: 'd0c-s4vage' 7 | --- 8 | 9 | ## Describe what you would like to see changed in the documentation 10 | 11 | Section X in the documentation is unclear 12 | 13 | or 14 | 15 | A new section "X" in the documentation would be very helpful 16 | 17 | or 18 | 19 | other 20 | 21 | ## Additional context 22 | 23 | Add any other context or screenshots about the feature request here. 24 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: 'Feature Request' 5 | labels: 'enhancement' 6 | assignees: 'd0c-s4vage' 7 | --- 8 | 9 | ## Is your feature request related to a problem? Please describe 10 | 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | ## Describe the solution you'd like 14 | 15 | A clear and concise description of what you want to happen. 16 | 17 | ## Describe alternatives you've considered 18 | 19 | A clear and concise description of any alternative solutions or features you've considered. 20 | 21 | ## Additional context 22 | 23 | Add any other context or screenshots about the feature request here. 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # generation 2 | out.* 3 | output.* 4 | 5 | # editors 6 | .idea 7 | .vscode 8 | .*.sw[mnop] 9 | tags 10 | 11 | # python 12 | *.pyc 13 | .tox 14 | pfp.egg-info 15 | venv* 16 | __pycache__ 17 | .pycache 18 | .cache 19 | .coverage 20 | 21 | # compilation 22 | *.o 23 | *.so 24 | *.dSYM 25 | midi*.cpp 26 | pcap*.cpp 27 | zip*.cpp 28 | avi*.cpp 29 | *-generator 30 | *-parser 31 | *-fuzzer 32 | lextab.py 33 | yacctab.py 34 | 35 | # Automake etc. 36 | # Note: While "*.in" files ARE derived, 37 | # we want to include them in the git repo to make cloning easier 38 | Makefile 39 | autom4te.cache 40 | config.log 41 | config.status 42 | config.h 43 | stamp-* 44 | .deps 45 | 46 | # Github pages 47 | .jekyll-cache/ 48 | _site/ 49 | 50 | # Garbage 51 | .DS_Store 52 | r0 53 | r1 54 | f0 55 | f1 56 | 57 | # Own files 58 | *.code-workspace 59 | 60 | # Random outputs 61 | random.* 62 | 63 | # project related 64 | docs/build 65 | docs/source/generated 66 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | ## Authors 2 | 3 | FormatFuzzer was designed and written by Rafael Dutra <rafael.dutra@cispa.de>. 4 | 5 | The concept of a fuzzer compiler was introduced by Rahul Gopinath <rahul.gopinath@cispa.de> and Andreas Zeller <zeller@cispa.de>. 6 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/ChangeLog -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | FormatFuzzer is copyright (c) 2020 by CISPA Helmholtz Center for Information Security. The following licenses apply: 2 | 3 | * _The FormatFuzzer code_ (notably, all C++ code and code related to its generation) is subject to the GNU GENERAL PUBLIC LICENSE, as found in [COPYING](COPYING). 4 | 5 | * As an exception to the above, _C++ code generated by FormatFuzzer_ (i.e., fuzzers and parsers for specific formats) is in the public domain. 6 | 7 | * _The original pfp code_, which FormatFuzzer is based upon, is subject to a MIT license, as found in [LICENSE-pfp](LICENSE-pfp). 8 | -------------------------------------------------------------------------------- /LICENSE-pfp: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 James Johnson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | # FormatFuzzer Makefile. Edit these rules in `Makefile.am' only. 2 | 3 | # By default, we build a `gif' fuzzer 4 | bin_PROGRAMS = gif-fuzzer 5 | gif_fuzzer_SOURCES = gif.cpp fuzzer.cpp 6 | 7 | # Libraries to use (png needs -lz) 8 | LIBS = -lz 9 | 10 | # Where the .bt templates are 11 | TEMPLATES = templates/ 12 | 13 | # The create script 14 | FFCOMPILE = ./ffcompile 15 | 16 | # Create a C++ file from template (say, 'gif.cpp' from template 'gif.bt') 17 | %.cpp: $(TEMPLATES)%.bt 18 | $(FFCOMPILE) $< $@ 19 | 20 | # Keep generated .cpp files 21 | .PRECIOUS: %.cpp 22 | 23 | # How to create the fuzzer (say, 'gif-fuzzer') 24 | %-fuzzer$(EXEEXT): %.o fuzzer.o 25 | @rm -f $@ 26 | $(AM_V_CXXLD)$(CXXLINK) $+ $(LIBS) 27 | 28 | # How to create the fuzzer as a shared library (say, 'gif.so') 29 | %.so: %.cpp fuzzer.cpp 30 | @rm -f $@ 31 | $(AM_V_CXXLD)$(CXXLINK) -shared -fPIC $+ $(LIBS) 32 | 33 | # Create a random file (say, 'make random.gif') 34 | random.%: %-fuzzer$(EXEEXT) 35 | ./$< fuzz $@ 36 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/NEWS -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | README.md -------------------------------------------------------------------------------- /README-pfp.md: -------------------------------------------------------------------------------- 1 | [![Master Build Status](https://travis-ci.org/d0c-s4vage/pfp.svg?branch=master)](https://travis-ci.org/d0c-s4vage/pfp) 2 | [![PyPI Statistics](https://img.shields.io/pypi/dm/pfp)](https://pypistats.org/packages/pfp) 3 | [![Latest Release](https://img.shields.io/pypi/v/pfp)](https://pypi.python.org/pypi/pfp/) 4 | [![Documentation Status](https://readthedocs.org/projects/pfp/badge/?version=latest)](https://pfp.readthedocs.io/en/latest/) 5 | [![Coverage Status](https://coveralls.io/repos/github/d0c-s4vage/pfp/badge.svg?branch=master)](https://coveralls.io/github/d0c-s4vage/pfp?branch=master) 6 | 7 | [![Twitter Follow](https://img.shields.io/twitter/follow/d0c_s4vage?style=plastic)](https://twitter.com/d0c_s4vage) 8 | 9 | # pfp 10 | 11 | `pfp` is a python-based interpreter for 010 template scripts. 12 | 13 | See the main documentation on [Read the Docs](http://pfp.readthedocs.org/en/latest/) 14 | 15 | ## Contributing 16 | 17 | See [CONTRIBUTING.md](CONTRIBUTING.md) 18 | 19 | ## Installation 20 | 21 | Install pfp with 22 | 23 | pip install --upgrade pfp 24 | 25 | ## Tl;DR 26 | 27 | ### CLI 28 | 29 | ```bash 30 | pfp -t path/to/template input_file 31 | ``` 32 | 33 | All available options for the pfp CLI: 34 | 35 | ``` 36 | usage: pfp [-h] -t TEMPLATE [--show-offsets] [-k] input 37 | 38 | Run pfp on input data using a specified 010 Editor template for parsing 39 | 40 | positional arguments: 41 | input The input data stream or file to parse. Use '-' for 42 | piped data 43 | 44 | optional arguments: 45 | -h, --help show this help message and exit 46 | -t TEMPLATE, --template TEMPLATE 47 | The template to parse with 48 | --show-offsets Show offsets in the parsed data of parsed fields 49 | -k, --keep Keep successfully parsed data on error 50 | ``` 51 | 52 | ### Python Library 53 | 54 | This should get you started parsing something using 010 templates: 55 | 56 | ```python 57 | import pfp 58 | 59 | dom = pfp.parse( 60 | data_file="~/Desktop/image.png", 61 | template_file="~/Desktop/PNGTemplate.bt" 62 | ) 63 | ``` 64 | -------------------------------------------------------------------------------- /bin/build_docs: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) 4 | 5 | cd $DIR/../docs 6 | 7 | rm -rf source/generated 8 | sphinx-apidoc -o source/generated ../pfp/ 9 | 10 | make html 11 | -------------------------------------------------------------------------------- /bin/run_tests: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) 4 | 5 | cd $DIR/../tests 6 | 7 | pytest -n 5 --cov-report term --cov pfp "$@" 8 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Produce format-specific C++ code 4 | ./ffcompile templates/$1.bt $1.cpp 5 | git checkout -- png.cpp 6 | 7 | # Build format-specific executable 8 | g++ -c -I . -std=c++17 -g -O3 -Wall fuzzer.cpp 9 | g++ -c -I . -std=c++17 -g -O3 -Wall $1.cpp 10 | g++ -O3 $1.o fuzzer.o -o $1-fuzzer -lz 11 | 12 | # Build format-specific shared library 13 | g++ -I . -std=c++17 -g -O3 -Wall -shared -fPIC $1.cpp fuzzer.cpp -o $1.so -lz 14 | -------------------------------------------------------------------------------- /checkers/avi.sh: -------------------------------------------------------------------------------- 1 | ffmpeg -y -f avi -i - output.avi /dev/null 2 | -------------------------------------------------------------------------------- /checkers/bmp.sh: -------------------------------------------------------------------------------- 1 | identify -verbose - /dev/null | grep -q Elapsed 2 | -------------------------------------------------------------------------------- /checkers/gif.sh: -------------------------------------------------------------------------------- 1 | identify -verbose - /dev/null | grep -q Elapsed 2 | #identify -verbose - /dev/null 2>/dev/null 3 | #gif2png out.gif >/dev/null 2>/dev/null 4 | -------------------------------------------------------------------------------- /checkers/jpg.sh: -------------------------------------------------------------------------------- 1 | identify -verbose - /dev/null | grep -q Elapsed 2 | #identify -verbose - /dev/null 2>/dev/null 3 | #djpeg out.jpg >/dev/null 2>/dev/null 4 | -------------------------------------------------------------------------------- /checkers/midi.sh: -------------------------------------------------------------------------------- 1 | ! timidity - -Ol -o /dev/null /dev/null | grep -q ^-: 2 | -------------------------------------------------------------------------------- /checkers/mp3.sh: -------------------------------------------------------------------------------- 1 | mpg321 --stdout - /dev/null 2>/dev/null 2 | #ffmpeg -y -i - output.mp3 /dev/null 3 | #ffmpeg -y -i - -c:a copy output.mp3 /dev/null 4 | -------------------------------------------------------------------------------- /checkers/mp4.sh: -------------------------------------------------------------------------------- 1 | ffmpeg -y -i - -c:v mpeg4 -c:a copy output.mp4 /dev/null 2 | -------------------------------------------------------------------------------- /checkers/pcap.sh: -------------------------------------------------------------------------------- 1 | tcpdump -nr - /dev/null 2>/dev/null 2 | -------------------------------------------------------------------------------- /checkers/png.sh: -------------------------------------------------------------------------------- 1 | identify -verbose - /dev/null | grep -q Elapsed 2 | #identify -verbose - /dev/null 2>/dev/null 3 | #readpng /dev/null 4 | #pngimage out.png >/dev/null 2>/dev/null 5 | -------------------------------------------------------------------------------- /checkers/wav.sh: -------------------------------------------------------------------------------- 1 | wavpack -y - -o output.wav /dev/null 2 | #ffmpeg -y -i - output.wav /dev/null 3 | -------------------------------------------------------------------------------- /checkers/zip.sh: -------------------------------------------------------------------------------- 1 | yes | unzip -P '' -t out.zip >/dev/null 2>/dev/null 2 | RETVAL=$? 3 | [ $RETVAL = 0 -o $RETVAL = 1 ] 4 | -------------------------------------------------------------------------------- /checkers/zipadv.sh: -------------------------------------------------------------------------------- 1 | yes | unzip -P '' -t out.zipadv >/dev/null 2>/dev/null -------------------------------------------------------------------------------- /config.h.in: -------------------------------------------------------------------------------- 1 | /* config.h.in. Generated from configure.ac by autoheader. */ 2 | 3 | /* define if the compiler supports basic C++17 syntax */ 4 | #undef HAVE_CXX17 5 | 6 | /* Name of package */ 7 | #undef PACKAGE 8 | 9 | /* Define to the address where bug reports for this package should be sent. */ 10 | #undef PACKAGE_BUGREPORT 11 | 12 | /* Define to the full name of this package. */ 13 | #undef PACKAGE_NAME 14 | 15 | /* Define to the full name and version of this package. */ 16 | #undef PACKAGE_STRING 17 | 18 | /* Define to the one symbol short name of this package. */ 19 | #undef PACKAGE_TARNAME 20 | 21 | /* Define to the home page for this package. */ 22 | #undef PACKAGE_URL 23 | 24 | /* Define to the version of this package. */ 25 | #undef PACKAGE_VERSION 26 | 27 | /* Version number of package */ 28 | #undef VERSION 29 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT([FormatFuzzer], 1.0) 2 | AC_CONFIG_MACRO_DIRS([m4]) 3 | AC_CONFIG_HEADERS(config.h) 4 | AM_INIT_AUTOMAKE 5 | AM_PATH_PYTHON([3.0],, [:]) 6 | : ${CXXFLAGS="-g -O3 -Wall"} 7 | AC_PROG_CXX 8 | AX_CXX_COMPILE_STDCXX(17,noext) 9 | AC_CONFIG_FILES(Makefile) 10 | AC_OUTPUT 11 | -------------------------------------------------------------------------------- /docs/.bundle/config: -------------------------------------------------------------------------------- 1 | --- 2 | BUNDLE_WITHOUT: "development:test" 3 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | !Makefile -------------------------------------------------------------------------------- /docs/.sass-cache/d1bb5f1978af923d84e65a2ac37e32e066e7ca58/fonts.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/docs/.sass-cache/d1bb5f1978af923d84e65a2ac37e32e066e7ca58/fonts.scssc -------------------------------------------------------------------------------- /docs/.sass-cache/d1bb5f1978af923d84e65a2ac37e32e066e7ca58/jekyll-theme-minimal.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/docs/.sass-cache/d1bb5f1978af923d84e65a2ac37e32e066e7ca58/jekyll-theme-minimal.scssc -------------------------------------------------------------------------------- /docs/.sass-cache/d1bb5f1978af923d84e65a2ac37e32e066e7ca58/rouge-github.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/docs/.sass-cache/d1bb5f1978af923d84e65a2ac37e32e066e7ca58/rouge-github.scssc -------------------------------------------------------------------------------- /docs/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | gem "jekyll-theme-minimal" 3 | gem "jekyll-optional-front-matter" 4 | gem "jekyll-redirect-from" 5 | gem "kramdown-parser-gfm" 6 | gem "jekyll-feed" 7 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | preview: 2 | (sleep 3; open http://localhost:4000/FormatFuzzer/) & 3 | bundle exec jekyll serve --watch --trace 4 | 5 | install: 6 | bundle install -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # FormatFuzzer 2 | 3 | `FormatFuzzer` is a framework for *high-efficiency, high-quality generation and parsing of binary inputs.* 4 | It takes a *binary template* that describes the format of a binary input and generates an *executable* that produces and parses the given binary format. 5 | From a binary template for GIF, for instance, `FormatFuzzer` produces a GIF generator - also known as *GIF fuzzer*. 6 | 7 | Generators produced by `FormatFuzzer` are highly efficient, producing thousands of valid test inputs per second - in sharp contrast to mutation-based fuzzers, where the large majority of inputs is invalid. By default, `FormatFuzzer` operates in black-box settings, but can also integrate with AFL++ to produce valid inputs that also aim for maximum coverage. 8 | 9 | FormatFuzzer is open source, available from the [FormatFuzzer project page](https://github.com/uds-se/FormatFuzzer). Contributors are welcome! 10 | For details on how `FormatFuzzer` works and how it compares, read [our paper](https://arxiv.org/abs/2109.11277) for more info. 11 | 12 | 13 | 14 | ## Latest News from [@FormatFuzzer](https://twitter.com/FormatFuzzer) 15 | 16 | 18 | 19 | 20 | ## FormatFuzzer Blog 21 | 22 | In the FormatFuzzer blog, we discuss how to address specific problems with FormatFuzzer. 23 | 24 |
    25 | {% for post in site.posts %} 26 |
  • 27 | {{ post.title }} 28 | ({{ post.date | date: "%Y-%m-%d" }}) 29 |
  • 30 | {% endfor %} 31 |
32 | 33 | 34 | ## Stay Tuned 35 | 36 | All relevant events regarding current work are [posted on Twitter](https://twitter.com/FormatFuzzer). 37 | 38 | 39 | 40 | We do not collect any data from this site, but Twitter does. See the Twitter privacy policy 41 | for details. 42 | 43 | -------------------------------------------------------------------------------- /docs/README.txt: -------------------------------------------------------------------------------- 1 | To create a blog post, go to /docs/_posts in the FormatFuzzer git repo and add a new .md file (like the existing one). If you have jekyll installed, you can run 2 | 3 | $ bundle exec jekyll serve 4 | 5 | and open 6 | 7 | http://localhost:4000/FormatFuzzer/ 8 | 9 | to obtain a preview before committing/pushing. 10 | -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-minimal 2 | title: FormatFuzzer 3 | layout: default 4 | baseurl: /FormatFuzzer 5 | plugins: 6 | - jekyll-optional-front-matter 7 | - jekyll-redirect-from 8 | - jekyll-feed 9 | include: 10 | - README.md 11 | optional_front_matter: 12 | remove_originals: true 13 | defaults: 14 | - scope: 15 | path: "*.md" 16 | values: 17 | layout: default 18 | tagline: High-efficiency, high-quality fuzzing with binary inputs 19 | twitter: 20 | - username: FormatFuzzer 21 | social: 22 | links: 23 | - https://twitter.com/FormatFuzzer 24 | 25 | include: 26 | - README.md 27 | 28 | description: FormatFuzzer is a framework for high-efficiency, high-quality generation and parsing of binary inputs. 29 | bio: 30 | Twitter:  @FormatFuzzer 31 | 32 | logo: assets/gif-fuzzer.gif 33 | logo_title: FormatFuzzer in action 34 | -------------------------------------------------------------------------------- /docs/_posts/2021-11-09-How-to-make-GIFs.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: "How to make millions of GIFs with a GIF fuzzer" 4 | author: Andreas Zeller 5 | --- 6 | 7 | So you have written a program that processes GIFs. How do you test it? One common way to do so would be to collect a set of GIFs from the Internet (where there's no shortage of GIFs), and to test your program on these. Obviously, if your program fails to process one of these GIFs, you had better fix it. Here's some neat GIF from Wikipedia; you can use it to test your program. 8 | 9 | ![]({{ '/assets/Newtons_cradle_animation_book_2.gif' | relative_url }}) 10 | 11 | Unfortunately, the GIFs that are present on the Internet may not encompass the full range of features that GIFs (or your program) have to offer. As the [Wikipedia article on GIFs](https://en.wikipedia.org/wiki/GIF) will be happy to lay out, GIFs can have several obscure features such as tiles, layers, CLEAR codes, and lots of metadata. If your program is subject to third-party inputs (say, when someone uploads a GIF to your application), it had better handle all of these features – or at least not crash or hang. So, you need more GIFs. Where do you get them from? 12 | 13 | In the past years, _fuzzers_ have become one of the most important tools to generate test inputs – in particular, to find vulnerabilities and other robustness issues. Popular fuzzers such as AFL _mutate_ a set of inputs again and again, guided by achieving a maximum _coverage_ of the program under test. 14 | 15 | Could you thus use such a fuzzer to test your program? The answer is: yes and no. Since a fuzzer _mutates_ given GIF files, what it will generate first and foremost is plenty of _invalid_ GIF files. You will thus thoroughly test the _parser_ that reads in a file, as well as error handling. So, yes. However, it is unlikely that a mutation will actually create a new GIF feature, unless it is already contained in one of the given GIFs. So, no. 16 | 17 | This is where _language_-based fuzzers come in. A language-based fuzzer such as `FormatFuzzer` uses a _format description_ called [binary template](https://www.sweetscape.com/010editor/templates.html) to generate millions of inputs that adhere to this very format. Using a binary template for GIFs, for instance, `FormatFuzzer` can generate millions of GIFs, all valid, and including all features that the GIF format has to offer. A simple 18 | 19 | ```sh 20 | $ make gif-fuzzer 21 | ``` 22 | 23 | suffices, and you get a super-efficient GIF generator `gif-fuzzer`, which you can invoke as 24 | 25 | ```sh 26 | $ ./gif-fuzzer fuzz foo.gif 27 | ``` 28 | 29 | to create a GIF file `foo.gif`. 30 | 31 | Here's one of the GIFs produced by FormatFuzzer – [six-rectangles.gif]({{ '/assets/six-rectangles.gif' | relative_url }}), an animated series of six black rectangles. It may look unspectacular, but it covers plenty of GIF features, including animation. You can create a large number of these, and put your program to the test. 32 | 33 | ![]({{ '/assets/six-rectangles.gif' | relative_url }}) 34 | 35 | Interestingly, `six-rectangles.gif` renders differently in different browsers. On Safari 15.1, it renders as a big black rectangle: 36 | 37 | ![]({{ '/assets/GIF_Safari.png' | relative_url }}) 38 | 39 | On Firefox 94.0, it renders as a small black rectangle: 40 | 41 | ![]({{ '/assets/GIF_Firefox.png' | relative_url }}) 42 | 43 | And on Google Chrome 95.0, it renders as white space: 44 | 45 | ![]({{ '/assets/GIF_Chrome.png' | relative_url }}) 46 | 47 | So, with the help of `FormatFuzzer`, we already detected an inconsistency in how GIF files are processed. Which one is the correct behavior? 48 | 49 | Once set up for a particular format, tools like `FormatFuzzer` can mbe tremendously useful. However, _someone has to write these binary templates in the first place_ - which means digging through file format specifications and encoding their rules such that `FormatFuzzer` can process them. We are currently exploring ways to _convert_ more existing formats, and also to [_mine_ such formats from existing programs](https://publications.cispa.saarland/3101/). However, [many common formats already _are_ encoded as binary templates](https://www.sweetscape.com/010editor/repository/templates/) (including GIFs!) and it only takes little effort to make them suitable for high-quality production of inputs. 50 | 51 | GIF is one of the formats that is already fully supported by `FormatFuzzer`. Hence, you can happily produce as many GIFs as you like, and test your program against them. Happy fuzzing! 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /docs/assets/GIF_Chrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/docs/assets/GIF_Chrome.png -------------------------------------------------------------------------------- /docs/assets/GIF_Firefox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/docs/assets/GIF_Firefox.png -------------------------------------------------------------------------------- /docs/assets/GIF_Safari.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/docs/assets/GIF_Safari.png -------------------------------------------------------------------------------- /docs/assets/Icon.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/docs/assets/Icon.key -------------------------------------------------------------------------------- /docs/assets/Newtons_cradle_animation_book_2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/docs/assets/Newtons_cradle_animation_book_2.gif -------------------------------------------------------------------------------- /docs/assets/Splash.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/docs/assets/Splash.key -------------------------------------------------------------------------------- /docs/assets/css/style.scss: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | 4 | @import "{{ site.theme }}"; 5 | 6 | /* Don't make links bold when hovering, underline instead */ 7 | a:hover, a:focus { 8 | font-weight: unset; 9 | text-decoration: underline; 10 | } 11 | 12 | @import "font-awesome.min.css"; 13 | -------------------------------------------------------------------------------- /docs/assets/gif-fuzzer.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/docs/assets/gif-fuzzer.gif -------------------------------------------------------------------------------- /docs/assets/six-rectangles.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/docs/assets/six-rectangles.gif -------------------------------------------------------------------------------- /docs/assets/three-rectangles.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/docs/assets/three-rectangles.gif -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | README.md -------------------------------------------------------------------------------- /examples/demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/examples/demo.png -------------------------------------------------------------------------------- /ffcompile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import sys 3 | import argparse 4 | 5 | # Note: must be _local_ pfp 6 | import pfp 7 | 8 | if __name__ == "__main__": 9 | parser = argparse.ArgumentParser() 10 | parser.add_argument("template_file", help=".bt template file to be compiled") 11 | parser.add_argument("target", help=".cpp target to be produced") 12 | args = parser.parse_args() 13 | 14 | # Note: Output to sys.argv[2] is currently hardwired into pfp, 15 | # so ignore args 16 | dom = pfp.parse(data="", template_file=sys.argv[1]) 17 | -------------------------------------------------------------------------------- /formatfuzzer.h: -------------------------------------------------------------------------------- 1 | #define MAX_RAND_SIZE 131072 2 | #define MAX_FILE_SIZE 65536 3 | //#define SIMPLE_MUTATIONS 1 4 | 5 | #include 6 | 7 | 8 | struct InsertionPoint { 9 | unsigned pos; 10 | const char* type; 11 | const char* name; 12 | #ifdef SIMPLE_MUTATIONS 13 | unsigned pos_file; 14 | #endif 15 | InsertionPoint(unsigned pos, const char* type, const char* name, unsigned pos_file) : pos(pos), type(type), name(name) 16 | #ifdef SIMPLE_MUTATIONS 17 | , pos_file(pos_file) 18 | #endif 19 | {} 20 | }; 21 | 22 | struct Chunk { 23 | int file_index; 24 | unsigned start; 25 | unsigned end; 26 | const char* type; 27 | const char* name; 28 | #ifdef SIMPLE_MUTATIONS 29 | unsigned start_file; 30 | unsigned end_file; 31 | #endif 32 | Chunk(int file_index, unsigned start, unsigned end, const char* type, const char* name, unsigned start_file, unsigned end_file) : file_index(file_index), start(start), end(end), type(type), name(name) 33 | #ifdef SIMPLE_MUTATIONS 34 | , start_file(start_file), end_file(end_file) 35 | #endif 36 | {} 37 | }; 38 | 39 | struct NonOptional { 40 | const char* type; 41 | int start; 42 | int size; 43 | NonOptional(const char* type, int start, int size) : type(type), start(start), size(size) {} 44 | }; 45 | 46 | extern std::unordered_map variable_types; 47 | extern std::vector> insertion_points; 48 | extern std::vector> deletable_chunks; 49 | extern std::vector optional_chunks; 50 | extern std::vector optional_index; 51 | extern std::unordered_map> non_optional_chunks; 52 | extern std::vector> non_optional_index; 53 | extern std::vector rand_names; 54 | extern std::vector file_names; 55 | 56 | void set_parser(); 57 | 58 | void set_generator(); 59 | 60 | bool setup_input(const char* filename); 61 | 62 | void generate_file(); 63 | 64 | unsigned get_file_size(); 65 | 66 | double get_validity(); 67 | 68 | void delete_globals(); 69 | 70 | char* get_bin_name(char* arg); 71 | 72 | void save_output(const char* filename); 73 | 74 | -------------------------------------------------------------------------------- /m4/m4_ax_cxx_compile_stdcxx_11.m4: -------------------------------------------------------------------------------- 1 | # ============================================================================= 2 | # https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html 3 | # ============================================================================= 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_CXX_COMPILE_STDCXX_11([ext|noext], [mandatory|optional]) 8 | # 9 | # DESCRIPTION 10 | # 11 | # Check for baseline language coverage in the compiler for the C++11 12 | # standard; if necessary, add switches to CXX and CXXCPP to enable 13 | # support. 14 | # 15 | # This macro is a convenience alias for calling the AX_CXX_COMPILE_STDCXX 16 | # macro with the version set to C++11. The two optional arguments are 17 | # forwarded literally as the second and third argument respectively. 18 | # Please see the documentation for the AX_CXX_COMPILE_STDCXX macro for 19 | # more information. If you want to use this macro, you also need to 20 | # download the ax_cxx_compile_stdcxx.m4 file. 21 | # 22 | # LICENSE 23 | # 24 | # Copyright (c) 2008 Benjamin Kosnik 25 | # Copyright (c) 2012 Zack Weinberg 26 | # Copyright (c) 2013 Roy Stogner 27 | # Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov 28 | # Copyright (c) 2015 Paul Norman 29 | # Copyright (c) 2015 Moritz Klammler 30 | # 31 | # Copying and distribution of this file, with or without modification, are 32 | # permitted in any medium without royalty provided the copyright notice 33 | # and this notice are preserved. This file is offered as-is, without any 34 | # warranty. 35 | 36 | #serial 18 37 | 38 | AX_REQUIRE_DEFINED([AX_CXX_COMPILE_STDCXX]) 39 | AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [AX_CXX_COMPILE_STDCXX([11], [$1], [$2])]) 40 | -------------------------------------------------------------------------------- /missing: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # Common wrapper for a few potentially missing GNU programs. 3 | 4 | scriptversion=2018-03-07.03; # UTC 5 | 6 | # Copyright (C) 1996-2020 Free Software Foundation, Inc. 7 | # Originally written by Fran,cois Pinard , 1996. 8 | 9 | # This program is free software; you can redistribute it and/or modify 10 | # it under the terms of the GNU General Public License as published by 11 | # the Free Software Foundation; either version 2, or (at your option) 12 | # any later version. 13 | 14 | # This program is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU General Public License for more details. 18 | 19 | # You should have received a copy of the GNU General Public License 20 | # along with this program. If not, see . 21 | 22 | # As a special exception to the GNU General Public License, if you 23 | # distribute this file as part of a program that contains a 24 | # configuration script generated by Autoconf, you may include it under 25 | # the same distribution terms that you use for the rest of that program. 26 | 27 | if test $# -eq 0; then 28 | echo 1>&2 "Try '$0 --help' for more information" 29 | exit 1 30 | fi 31 | 32 | case $1 in 33 | 34 | --is-lightweight) 35 | # Used by our autoconf macros to check whether the available missing 36 | # script is modern enough. 37 | exit 0 38 | ;; 39 | 40 | --run) 41 | # Back-compat with the calling convention used by older automake. 42 | shift 43 | ;; 44 | 45 | -h|--h|--he|--hel|--help) 46 | echo "\ 47 | $0 [OPTION]... PROGRAM [ARGUMENT]... 48 | 49 | Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due 50 | to PROGRAM being missing or too old. 51 | 52 | Options: 53 | -h, --help display this help and exit 54 | -v, --version output version information and exit 55 | 56 | Supported PROGRAM values: 57 | aclocal autoconf autoheader autom4te automake makeinfo 58 | bison yacc flex lex help2man 59 | 60 | Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and 61 | 'g' are ignored when checking the name. 62 | 63 | Send bug reports to ." 64 | exit $? 65 | ;; 66 | 67 | -v|--v|--ve|--ver|--vers|--versi|--versio|--version) 68 | echo "missing $scriptversion (GNU Automake)" 69 | exit $? 70 | ;; 71 | 72 | -*) 73 | echo 1>&2 "$0: unknown '$1' option" 74 | echo 1>&2 "Try '$0 --help' for more information" 75 | exit 1 76 | ;; 77 | 78 | esac 79 | 80 | # Run the given program, remember its exit status. 81 | "$@"; st=$? 82 | 83 | # If it succeeded, we are done. 84 | test $st -eq 0 && exit 0 85 | 86 | # Also exit now if we it failed (or wasn't found), and '--version' was 87 | # passed; such an option is passed most likely to detect whether the 88 | # program is present and works. 89 | case $2 in --version|--help) exit $st;; esac 90 | 91 | # Exit code 63 means version mismatch. This often happens when the user 92 | # tries to use an ancient version of a tool on a file that requires a 93 | # minimum version. 94 | if test $st -eq 63; then 95 | msg="probably too old" 96 | elif test $st -eq 127; then 97 | # Program was missing. 98 | msg="missing on your system" 99 | else 100 | # Program was found and executed, but failed. Give up. 101 | exit $st 102 | fi 103 | 104 | perl_URL=https://www.perl.org/ 105 | flex_URL=https://github.com/westes/flex 106 | gnu_software_URL=https://www.gnu.org/software 107 | 108 | program_details () 109 | { 110 | case $1 in 111 | aclocal|automake) 112 | echo "The '$1' program is part of the GNU Automake package:" 113 | echo "<$gnu_software_URL/automake>" 114 | echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" 115 | echo "<$gnu_software_URL/autoconf>" 116 | echo "<$gnu_software_URL/m4/>" 117 | echo "<$perl_URL>" 118 | ;; 119 | autoconf|autom4te|autoheader) 120 | echo "The '$1' program is part of the GNU Autoconf package:" 121 | echo "<$gnu_software_URL/autoconf/>" 122 | echo "It also requires GNU m4 and Perl in order to run:" 123 | echo "<$gnu_software_URL/m4/>" 124 | echo "<$perl_URL>" 125 | ;; 126 | esac 127 | } 128 | 129 | give_advice () 130 | { 131 | # Normalize program name to check for. 132 | normalized_program=`echo "$1" | sed ' 133 | s/^gnu-//; t 134 | s/^gnu//; t 135 | s/^g//; t'` 136 | 137 | printf '%s\n' "'$1' is $msg." 138 | 139 | configure_deps="'configure.ac' or m4 files included by 'configure.ac'" 140 | case $normalized_program in 141 | autoconf*) 142 | echo "You should only need it if you modified 'configure.ac'," 143 | echo "or m4 files included by it." 144 | program_details 'autoconf' 145 | ;; 146 | autoheader*) 147 | echo "You should only need it if you modified 'acconfig.h' or" 148 | echo "$configure_deps." 149 | program_details 'autoheader' 150 | ;; 151 | automake*) 152 | echo "You should only need it if you modified 'Makefile.am' or" 153 | echo "$configure_deps." 154 | program_details 'automake' 155 | ;; 156 | aclocal*) 157 | echo "You should only need it if you modified 'acinclude.m4' or" 158 | echo "$configure_deps." 159 | program_details 'aclocal' 160 | ;; 161 | autom4te*) 162 | echo "You might have modified some maintainer files that require" 163 | echo "the 'autom4te' program to be rebuilt." 164 | program_details 'autom4te' 165 | ;; 166 | bison*|yacc*) 167 | echo "You should only need it if you modified a '.y' file." 168 | echo "You may want to install the GNU Bison package:" 169 | echo "<$gnu_software_URL/bison/>" 170 | ;; 171 | lex*|flex*) 172 | echo "You should only need it if you modified a '.l' file." 173 | echo "You may want to install the Fast Lexical Analyzer package:" 174 | echo "<$flex_URL>" 175 | ;; 176 | help2man*) 177 | echo "You should only need it if you modified a dependency" \ 178 | "of a man page." 179 | echo "You may want to install the GNU Help2man package:" 180 | echo "<$gnu_software_URL/help2man/>" 181 | ;; 182 | makeinfo*) 183 | echo "You should only need it if you modified a '.texi' file, or" 184 | echo "any other file indirectly affecting the aspect of the manual." 185 | echo "You might want to install the Texinfo package:" 186 | echo "<$gnu_software_URL/texinfo/>" 187 | echo "The spurious makeinfo call might also be the consequence of" 188 | echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" 189 | echo "want to install GNU make:" 190 | echo "<$gnu_software_URL/make/>" 191 | ;; 192 | *) 193 | echo "You might have modified some files without having the proper" 194 | echo "tools for further handling them. Check the 'README' file, it" 195 | echo "often tells you about the needed prerequisites for installing" 196 | echo "this package. You may also peek at any GNU archive site, in" 197 | echo "case some other package contains this missing '$1' program." 198 | ;; 199 | esac 200 | } 201 | 202 | give_advice "$1" | sed -e '1s/^/WARNING: /' \ 203 | -e '2,$s/^/ /' >&2 204 | 205 | # Propagate the correct exit status (expected to be 127 for a program 206 | # not found, 63 for a program that failed due to version mismatch). 207 | exit $st 208 | 209 | # Local variables: 210 | # eval: (add-hook 'before-save-hook 'time-stamp) 211 | # time-stamp-start: "scriptversion=" 212 | # time-stamp-format: "%:y-%02m-%02d.%02H" 213 | # time-stamp-time-zone: "UTC0" 214 | # time-stamp-end: "; # UTC" 215 | # End: 216 | -------------------------------------------------------------------------------- /pfp/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import os 4 | import six 5 | import sys 6 | 7 | import py010parser.c_parser 8 | 9 | import pfp.interp 10 | from pfp.bitwrap import BitwrappedStream 11 | import pfp.fuzz 12 | 13 | 14 | pfp.fuzz.init() 15 | 16 | 17 | __version__ = "{{VERSION}}" 18 | 19 | PARSER = py010parser.c_parser.CParser() 20 | 21 | 22 | def parse( 23 | data=None, 24 | template=None, 25 | data_file=None, 26 | template_file=None, 27 | interp=None, 28 | debug=False, 29 | predefines=True, 30 | int3=True, 31 | keep_successful=False, 32 | printf=True, 33 | generate=True, 34 | ): 35 | """Parse the data stream using the supplied template. The data stream 36 | WILL NOT be automatically closed. 37 | 38 | :data: Input data, can be either a string or a file-like object (StringIO, file, etc) 39 | :template: template contents (str) 40 | :data_file: PATH to the data to be used as the input stream 41 | :template_file: template file path 42 | :interp: the interpretor to be used (a default one will be created if ``None``) 43 | :debug: if debug information should be printed while interpreting the template (false) 44 | :predefines: if built-in type information should be inserted (true) 45 | :int3: if debugger breaks are allowed while interpreting the template (true) 46 | :keep_successful: return any succesfully parsed data instead of raising an error. If an error occurred and ``keep_successful`` is True, then ``_pfp__error`` will be contain the exception object 47 | :printf: if ``False``, all calls to ``Printf`` (:any:`pfp.native.compat_interface.Printf`) will be noops. (default=``True``) 48 | :returns: pfp DOM 49 | """ 50 | if data is None and data_file is None: 51 | raise Exception("No input data was specified") 52 | 53 | if data is not None and data_file is not None: 54 | raise Exception("Only one input data may be specified") 55 | 56 | if isinstance(data, six.string_types): 57 | data = six.StringIO(data) 58 | 59 | if data_file is not None: 60 | data = open(os.path.expanduser(data_file), "rb") 61 | 62 | if template is None and template_file is None: 63 | raise Exception("No template specified!") 64 | 65 | if template is not None and template_file is not None: 66 | raise Exception("Only one template may be specified!") 67 | 68 | orig_filename = "string" 69 | if template_file is not None: 70 | orig_filename = template_file 71 | try: 72 | with open(os.path.expanduser(template_file), "r") as f: 73 | template = f.read() 74 | except Exception as e: 75 | raise Exception( 76 | "Could not open template file '{}'".format(template_file) 77 | ) 78 | 79 | # the user may specify their own instance of PfpInterp to be 80 | # used 81 | if interp is None: 82 | interp = pfp.interp.PfpInterp(debug=debug, parser=PARSER, int3=int3, generate=generate) 83 | 84 | # so we can consume single bits at a time 85 | data = BitwrappedStream(data, generate=generate) 86 | 87 | dom = interp.parse( 88 | data, 89 | template, 90 | predefines=predefines, 91 | orig_filename=orig_filename, 92 | keep_successful=keep_successful, 93 | printf=printf, 94 | ) 95 | 96 | # close the data stream if a data_file was specified 97 | if data_file is not None: 98 | data.close() 99 | 100 | return dom 101 | 102 | 103 | def create_interp(template_file=None, template=None): 104 | """Create an Interp instance with the template preloaded 105 | 106 | :template: template contents (str) 107 | :template_file: template file path 108 | :returns: Interp 109 | """ 110 | if template is None and template_file is None: 111 | raise Exception("No template specified!") 112 | 113 | if template is not None and template_file is not None: 114 | raise Exception("Only one template may be specified!") 115 | 116 | orig_filename = "string" 117 | if template_file is not None: 118 | orig_filename = template_file 119 | try: 120 | with open(os.path.expanduser(template_file), "r") as f: 121 | template = f.read() 122 | except Exception as e: 123 | raise Exception( 124 | "Could not open template file '{}'".format(template_file) 125 | ) 126 | 127 | interp = pfp.interp.PfpInterp(parser=PARSER) 128 | interp.load_template(template) 129 | return interp 130 | -------------------------------------------------------------------------------- /pfp/__main__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | 5 | """ 6 | Run pfp on input data using a specified 010 Editor template for parsing 7 | """ 8 | 9 | 10 | import argparse 11 | import os 12 | import pfp 13 | import sys 14 | 15 | 16 | def parse_args(argv): 17 | parser = argparse.ArgumentParser("pfp", description=__doc__) 18 | 19 | parser.add_argument( 20 | "-t", "--template", 21 | required=True, 22 | help="The template to parse with", 23 | ) 24 | 25 | parser.add_argument( 26 | "--show-offsets", 27 | action="store_true", 28 | default=False, 29 | help="Show offsets in the parsed data of parsed fields", 30 | ) 31 | 32 | parser.add_argument( 33 | "-k", "--keep", 34 | default=False, 35 | action="store_true", 36 | help="Keep successfully parsed data on error", 37 | ) 38 | 39 | parser.add_argument( 40 | "input", 41 | type=argparse.FileType("rb"), 42 | default=sys.stdin, 43 | help="The input data stream or file to parse. Use '-' for piped data", 44 | ) 45 | 46 | return parser.parse_args(argv[1:]) 47 | 48 | 49 | def main(argv=None): 50 | """Main function for this script 51 | 52 | :argv: TODO 53 | :returns: TODO 54 | """ 55 | if argv is None: 56 | argv = sys.argv 57 | 58 | args = parse_args(argv) 59 | dom = pfp.parse( 60 | template_file=args.template, 61 | data=args.input, 62 | keep_successful=args.keep, 63 | ) 64 | print(dom._pfp__show(include_offset=args.show_offsets)) 65 | 66 | 67 | if __name__ == "__main__": 68 | main(sys.argv) 69 | -------------------------------------------------------------------------------- /pfp/dbg.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | 4 | import cmd 5 | import collections 6 | import os 7 | import sys 8 | 9 | import pfp.fields as fields 10 | import pfp.errors as errors 11 | import pfp.utils as utils 12 | 13 | 14 | class PfpDbg(cmd.Cmd, object): 15 | """The pfp debugger cmd.Cmd class""" 16 | 17 | prompt = "pfp> " 18 | 19 | def __init__(self, interp): 20 | """Create the pfp debugger 21 | 22 | :scope: The scope in which to start debugging 23 | """ 24 | super(PfpDbg, self).__init__() 25 | 26 | self._interp = interp 27 | 28 | self._do_print_from_last_cmd = False 29 | 30 | def _update_prompt(self): 31 | if fields.NumberBase.endian == fields.BIG_ENDIAN: 32 | self.prompt = "BE pfp> " 33 | else: 34 | self.prompt = "LE pfp> " 35 | 36 | def update(self, ctxt, scope): 37 | self._ctxt = ctxt 38 | self._scope = scope 39 | 40 | def preloop(self): 41 | self._update_prompt() 42 | self.print_lines() 43 | 44 | def postcmd(self, stop, line): 45 | self._update_prompt() 46 | return stop 47 | 48 | def default(self, line): 49 | cmd, arg, line = self.parseline(line) 50 | funcs = [ 51 | getattr(self, n) 52 | for n in self.get_names() 53 | if n.startswith("do_" + cmd) 54 | ] 55 | 56 | if len(funcs) > 1: 57 | for func in funcs: 58 | print(func) 59 | elif len(funcs) == 1: 60 | return funcs[0](arg) 61 | elif len(funcs) == 0: 62 | return self.do_eval(line) 63 | 64 | def do_peek(self, args): 65 | """Peek at the next 16 bytes in the stream:: 66 | 67 | Example: 68 | 69 | The peek command will display the next 16 hex bytes in the input 70 | stream:: 71 | pfp> peek 72 | 89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52 .PNG........IHDR 73 | """ 74 | s = self._interp._stream 75 | # make a copy of it 76 | pos = s.tell() 77 | saved_bits = collections.deque(s._bits) 78 | data = s.read(0x10) 79 | s.seek(pos, 0) 80 | s._bits = saved_bits 81 | 82 | parts = [ 83 | "{:02x}".format(ord(data[x : x + 1])) for x in range(len(data)) 84 | ] 85 | if len(parts) != 0x10: 86 | parts += [" "] * (0x10 - len(parts)) 87 | hex_line = " ".join(parts) 88 | 89 | res = utils.binary("") 90 | for x in range(len(data)): 91 | char = data[x : x + 1] 92 | val = ord(char) 93 | if 0x20 <= val <= 0x7E: 94 | res += char 95 | else: 96 | res += utils.binary(".") 97 | 98 | if len(res) < 0x10: 99 | res += utils.binary(" " * (0x10 - len(res))) 100 | 101 | res = "{} {}".format(hex_line, utils.string(res)) 102 | if len(saved_bits) > 0: 103 | reverse_bits = reversed(list(saved_bits)) 104 | print("bits: {}".format(" ".join(str(x) for x in reverse_bits))) 105 | print(res) 106 | 107 | def do_next(self, args): 108 | """Step over the next statement 109 | """ 110 | self._do_print_from_last_cmd = True 111 | self._interp.step_over() 112 | return True 113 | 114 | def do_step(self, args): 115 | """Step INTO the next statement 116 | """ 117 | self._do_print_from_last_cmd = True 118 | self._interp.step_into() 119 | return True 120 | 121 | def do_s(self, args): 122 | """Step into the next statement 123 | """ 124 | return self.do_step(args) 125 | 126 | def do_continue(self, args): 127 | """Continue the interpreter 128 | """ 129 | self._do_print_from_last_cmd = True 130 | self._interp.cont() 131 | return True 132 | 133 | def do_eval(self, args): 134 | """Eval the user-supplied statement. Note that you can do anything with 135 | this command that you can do in a template. 136 | 137 | The resulting value of your statement will be displayed. 138 | """ 139 | try: 140 | res = self._interp.eval(args) 141 | if res is not None: 142 | if hasattr(res, "_pfp__show"): 143 | print(res._pfp__show()) 144 | else: 145 | print(repr(res)) 146 | except errors.UnresolvedID as e: 147 | print("ERROR: " + e.message) 148 | except Exception as e: 149 | raise 150 | print("ERROR: " + e.message) 151 | 152 | return False 153 | 154 | def do_show(self, args): 155 | """Show the current structure of __root (no args), 156 | or show the result of the expression (something that can be eval'd). 157 | """ 158 | args = args.strip() 159 | 160 | to_show = self._interp._root 161 | if args != "": 162 | try: 163 | to_show = self._interp.eval(args) 164 | except Exception as e: 165 | print("ERROR: " + e.message) 166 | return False 167 | 168 | if hasattr(to_show, "_pfp__show"): 169 | print(to_show._pfp__show()) 170 | else: 171 | print(repr(to_show)) 172 | 173 | def do_x(self, args): 174 | pass 175 | 176 | do_x = do_show 177 | 178 | def do_list(self, args): 179 | """List the current location in the template 180 | """ 181 | self.print_lines() 182 | return False 183 | 184 | def do_quit(self, args): 185 | """The quit command 186 | """ 187 | self._interp.set_break(self._interp.BREAK_NONE) 188 | return True 189 | 190 | def do_EOF(self, args): 191 | """The eof command 192 | """ 193 | return True 194 | 195 | # --------------------- 196 | 197 | def print_lines(self): 198 | curr_line, lines = self._interp.get_curr_lines() 199 | 200 | for line_no, line in lines: 201 | prefix = " " 202 | line_no += 1 203 | if line_no == curr_line: 204 | prefix = "--> " 205 | print( 206 | "{}{:3d} {}".format( 207 | prefix, line_no, line.replace("\t", " ") 208 | ) 209 | ) 210 | -------------------------------------------------------------------------------- /pfp/errors.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Errors for pfp 5 | """ 6 | 7 | 8 | class PfpError(Exception): 9 | pass 10 | 11 | 12 | class PrematureEOF(PfpError): 13 | pass 14 | 15 | 16 | class InterpBreak(PfpError): 17 | pass 18 | 19 | 20 | class InterpContinue(PfpError): 21 | pass 22 | 23 | 24 | class InterpExit(PfpError): 25 | def __init__(self, error_code=0): 26 | self.error_code = error_code 27 | 28 | 29 | class UnmodifiableConst(PfpError): 30 | pass 31 | 32 | 33 | class CoordError(PfpError): 34 | """Base class for pfp exceptions""" 35 | 36 | def __init__(self, coord=None, *args): 37 | super(CoordError, self).__init__( 38 | (self.msg + " at {}").format(*(args + (coord,))) 39 | ) 40 | 41 | 42 | class InterpReturn(CoordError): 43 | def __init__(self, ret_val): 44 | self.value = ret_val 45 | 46 | 47 | class InvalidArguments(CoordError): 48 | msg = "Invalid arguments, received {!r}, expected {!r}" 49 | 50 | 51 | class InvalidState(CoordError): 52 | msg = "Pfp has reached an invalid state" 53 | 54 | 55 | class UnsupportedASTNode(CoordError): 56 | msg = "Pfp can not yet interpret {!r} nodes" 57 | 58 | 59 | class UnresolvedType(CoordError): 60 | """These exceptions will be raised when a type cannot be resolved""" 61 | 62 | msg = "The type {!r} ({!r}) could not be resolved" 63 | 64 | 65 | class UnsupportedConstantType(CoordError): 66 | """These exceptions will be raised when a constant type is encountered 67 | that can not yet be handled (or not implemented yet)""" 68 | 69 | msg = "Unsupported constant type {!r}" 70 | 71 | 72 | class UnresolvedID(CoordError): 73 | """These exceptionsn will be raised when a referenced ID cannot 74 | be resolved""" 75 | 76 | msg = "Could not resolve field {!r}" 77 | 78 | 79 | class UnsupportedUnaryOperator(CoordError): 80 | """docstring for UnsupportedUnaryOperator""" 81 | 82 | msg = "Unsupported unary operator {!r}" 83 | 84 | 85 | class UnsupportedBinaryOperator(CoordError): 86 | """docstring for UnsupportedUnaryOperator""" 87 | 88 | msg = "Unsupported binary operator {!r}" 89 | 90 | 91 | class UnsupportedAssignmentOperator(CoordError): 92 | """docstring for UnsupportedAssignmentOperator""" 93 | 94 | msg = "Unsupported assignment operator {!r}" 95 | -------------------------------------------------------------------------------- /pfp/functions.py: -------------------------------------------------------------------------------- 1 | import six 2 | 3 | import pfp.bitwrap as bitwrap 4 | import pfp.errors as errors 5 | import pfp.utils as utils 6 | import pfp.fields 7 | 8 | 9 | class BaseFunction(object): 10 | pass 11 | 12 | 13 | class Function(BaseFunction): 14 | """A class to maintain function state and arguments""" 15 | 16 | def __init__(self, return_type, params, scope): 17 | """ 18 | Initialized the function. The Function body is intended to be set 19 | after the Function object has been created. 20 | """ 21 | super(Function, self).__init__() 22 | 23 | self.name = None 24 | self.body = None 25 | 26 | # note that the _scope is determined by where the function is 27 | # declared, not where it is called from 28 | # TODO see the comment in Scope.clone for potential future work/bugs 29 | self._scope = scope.clone() 30 | self._params = params 31 | 32 | def call(self, args, ctxt, scope, stream, interp, coord, no_cast=False): 33 | # the no_cast arg does nothing for interpreted functions 34 | 35 | if self.body is None: 36 | raise errors.InvalidState(coord) 37 | 38 | # scopes will be pushed and popped by the Compound node handler! 39 | # If a return statement is interpreted in the function, 40 | # the Compound statement will pop the scope before the exception 41 | # bubbles up to here 42 | 43 | self._scope.push() 44 | 45 | params = self._params.instantiate(self._scope, args, interp) 46 | 47 | ret_val = None 48 | try: 49 | interp._handle_node(self.body, self._scope, ctxt, stream) 50 | except errors.InterpReturn as e: 51 | # TODO do some type checking on the return value?? 52 | # perhaps this should be done when initially traversing 53 | # the AST of the function... a dry run traversing it to find 54 | # return values?? 55 | ret_val = e.value 56 | finally: 57 | self._scope.pop() 58 | 59 | return ret_val 60 | 61 | 62 | class NativeFunction(BaseFunction): 63 | """A class for native functions""" 64 | 65 | def __init__(self, name, func, ret, send_interp=False): 66 | """ 67 | """ 68 | super(NativeFunction, self).__init__() 69 | self._pfp__name = name 70 | self.name = name 71 | self.func = func 72 | self.ret = ret 73 | self.send_interp = send_interp 74 | 75 | def call(self, args, ctxt, scope, stream, interp, coord, no_cast=False): 76 | if self.send_interp: 77 | res = self.func(args, ctxt, scope, stream, coord, interp) 78 | else: 79 | res = self.func(args, ctxt, scope, stream, coord) 80 | 81 | if no_cast: 82 | res_field = res 83 | elif utils.is_str(res) and self.ret == pfp.fields.Array: 84 | tmp_stream = bitwrap.BitwrappedStream(six.BytesIO(res)) 85 | res_field = pfp.fields.Array(len(res), pfp.fields.Char, tmp_stream) 86 | elif utils.is_str(self.ret) and scope.get_type(self.ret) is not None: 87 | # TODO should we do any type-checking here to make sure that the 88 | # return value matches what is declared as the return type? 89 | res_field = res 90 | else: 91 | res_field = self.ret() 92 | res_field._pfp__set_value(res) 93 | 94 | return res_field 95 | 96 | 97 | class ParamClsWrapper(object): 98 | """This is a temporary wrapper around a param class 99 | that can store temporary information, such as byref values 100 | """ 101 | 102 | def __init__(self, param_cls): 103 | self._cls = param_cls 104 | 105 | def __call__(self, *args, **kwargs): 106 | """This should be fairly transparent in use and should 107 | behave as if a new object of `self._cls` was directly 108 | instantiated 109 | """ 110 | return self._cls(*args, **kwargs) 111 | 112 | 113 | class ParamListDef(object): 114 | """docstring for ParamList""" 115 | 116 | def __init__(self, params, coords): 117 | super(ParamListDef, self).__init__() 118 | 119 | self._params = params 120 | self._coords = coords 121 | 122 | def instantiate(self, scope, args, interp): 123 | """Create a ParamList instance for actual interpretation 124 | 125 | :args: TODO 126 | :returns: A ParamList object 127 | 128 | """ 129 | param_instances = [] 130 | 131 | BYREF = "byref" 132 | 133 | # TODO are default values for function parameters allowed in 010? 134 | if len(self._params) == 1 and type(self._params[0]) is type: 135 | return ParamList([]) 136 | for param_name, param_cls in self._params: 137 | # we don't instantiate a copy of byref params 138 | if getattr(param_cls, "byref", False): 139 | param_instances.append(BYREF) 140 | else: 141 | field = param_cls() 142 | field._pfp__name = param_name 143 | param_instances.append(field) 144 | 145 | if len(args) != len(param_instances): 146 | raise errors.InvalidArguments( 147 | self._coords, 148 | [x.__class__.__name__ for x in args], 149 | [x.__class__.__name__ for x in param_instances], 150 | ) 151 | 152 | # TODO type checking on provided types 153 | 154 | for x in six.moves.range(len(args)): 155 | param = param_instances[x] 156 | 157 | # arrays are simply passed through into the function. We shouldn't 158 | # have to worry about frozenness/unfrozenness at this point 159 | if param is BYREF or isinstance(param, pfp.fields.Array): 160 | param = args[x] 161 | param_instances[x] = param 162 | scope.add_local(self._params[x][0], param) 163 | else: 164 | if args[x] is not None: 165 | param._pfp__set_value(args[x]) 166 | scope.add_local(param._pfp__name, param) 167 | param._pfp__interp = interp 168 | 169 | return ParamList(param_instances) 170 | 171 | 172 | class ParamList(object): 173 | """Used for when a function is actually called. See ParamListDef 174 | for how function definitions store function parameter definitions 175 | """ 176 | 177 | def __init__(self, params): 178 | super(ParamList, self).__init__() 179 | self.params = params 180 | 181 | # for use by __getitem__ 182 | self._params_map = {} 183 | for param in self.params: 184 | self._params_map[param._pfp__name] = param 185 | 186 | def __iter__(self): 187 | """Return an iterator that will iterate through each of the 188 | parameters in order 189 | 190 | """ 191 | for param in self.params: 192 | yield param 193 | 194 | def __getitem__(self, name): 195 | if name in self._params_map: 196 | return self._params_map[name] 197 | raise KeyError(name) 198 | 199 | # def __setitem__??? 200 | -------------------------------------------------------------------------------- /pfp/fuzz/basic.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | This module defines basic mutation strategies 6 | """ 7 | 8 | 9 | import six 10 | 11 | 12 | import pfp.fuzz as fuzz 13 | import pfp.fields as fields 14 | import pfp.utils as utils 15 | 16 | 17 | class BasicStrat(fuzz.StratGroup): 18 | """A basic strategy that has FieldStrats (field strategies) defined 19 | for every field type. Nothing fancy, just basic. 20 | """ 21 | 22 | name = "basic" 23 | 24 | class Int(fuzz.FieldStrat): 25 | klass = [fields.IntBase] 26 | 27 | def prob(self, field): 28 | # generate the probabilities table 29 | offset = 0 30 | 31 | max_val = 1 << (field.width * 8) 32 | 33 | if field.signed: 34 | min_val = int(-max_val / 2) 35 | max_val = int(max_val / 2) - 1 36 | vals = [min_val, max_val, 0] 37 | vals += [1 << (x * 8) for x in six.moves.range(field.width)] 38 | vals += [-x for x in vals] 39 | vals = sorted(set(vals)) 40 | vals = vals[:-1] 41 | 42 | else: 43 | min_val = 0 44 | max_val -= 1 45 | vals = [0] 46 | vals += [ 47 | 1 << (x * 4) for x in six.moves.range(field.width * 2) 48 | ] 49 | vals.append((1 << (field.width * 8)) - 1) 50 | 51 | # now add the +-1 values 52 | new_vals = [] 53 | for val in vals[2:-1]: 54 | new_vals.append(val - 1) 55 | new_vals.append(val + 1) 56 | vals += new_vals 57 | 58 | pv = 1.0 / 3.0 59 | res = [ 60 | (pv, vals), 61 | (pv, six.moves.xrange(0, min(max_val, 0x100))), 62 | (pv, {"min": min_val, "max": max_val}), 63 | ] 64 | 65 | return res 66 | 67 | class Float(fuzz.FieldStrat): 68 | klass = fields.Float 69 | prob = [(1.0, lambda: fuzz.rand.randfloat(-0x10000000, 0x10000000))] 70 | 71 | class Double(fuzz.FieldStrat): 72 | klass = fields.Double 73 | prob = [(1.0, lambda: fuzz.rand.randfloat(-0x10000000, 0x10000000))] 74 | 75 | class Enum(Int): 76 | klass = fields.Enum 77 | 78 | def prob(self, field): 79 | # treat it the same as ints, with the addition of the actual (valid) 80 | # enum values 81 | res = super(BasicStrat.Enum, self).prob(field) 82 | 83 | # add in the new enum values 84 | prob_percent = 1.0 / float(len(res) + 1) 85 | res = [(prob_percent, x[1]) for x in res] 86 | res.append((prob_percent, list(filter( 87 | lambda x: not isinstance(x, six.string_types), 88 | field.enum_vals.keys(), 89 | )))) 90 | 91 | return res 92 | 93 | # class Array(fuzz.FieldStrat): 94 | # klass = fields.Array 95 | # 96 | # # set the raw data to be a random string 97 | # def next_val(self, field): 98 | # rand_data_size = ( 99 | # fuzz.rand.randint(0, 0x100) * field.field_cls.width 100 | # ) 101 | # return fuzz.rand.data( 102 | # rand_data_size, [utils.binary(chr(x)) for x in six.moves.range(0x100)] 103 | # ) 104 | 105 | class String(fuzz.FieldStrat): 106 | klass = fields.String 107 | 108 | def next_val(self, field): 109 | rand_data_size = fuzz.rand.randint(0, 0x100) 110 | res = fuzz.rand.data( 111 | rand_data_size, [utils.binary(chr(x)) for x in six.moves.range(0x100)] 112 | ) 113 | 114 | if fuzz.rand.maybe(): 115 | res += utils.binary("\x00") 116 | 117 | return res 118 | -------------------------------------------------------------------------------- /pfp/fuzz/rand.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | 4 | import random as r 5 | import six 6 | 7 | RANDOM = r.Random() 8 | _randint = RANDOM.randint 9 | random = _random = RANDOM.random 10 | choice = _choice = RANDOM.choice 11 | sample = _sample = RANDOM.sample 12 | 13 | 14 | def seed(val): 15 | RANDOM.seed(val) 16 | 17 | 18 | def randint(a, b=None): 19 | if b is None: 20 | return _randint(0, a) 21 | else: 22 | return _randint(a, b) 23 | 24 | 25 | def randfloat(min_, max_): 26 | diff = max_ - min_ 27 | res = _random() 28 | res *= diff 29 | res += min_ 30 | return res 31 | 32 | 33 | def maybe(prob=0.5): 34 | return _random() < prob 35 | 36 | 37 | def data(length, charset): 38 | return b"".join(_choice(charset) for x in six.moves.range(length)) 39 | -------------------------------------------------------------------------------- /pfp/native/__init__.py: -------------------------------------------------------------------------------- 1 | import functools 2 | 3 | import pfp.interp 4 | 5 | 6 | def native(name, ret, interp=None, send_interp=False): 7 | """Used as a decorator to add the decorated function to the 8 | pfp interpreter so that it can be used from within scripts. 9 | 10 | :param str name: The name of the function as it will be exposed in template scripts. 11 | :param pfp.fields.Field ret: The return type of the function (a class) 12 | :param pfp.interp.PfpInterp interp: The specific interpreter to add the function to 13 | :param bool send_interp: If the current interpreter should be passed to the function. 14 | 15 | Examples: 16 | 17 | The example below defines a ``Sum`` function that will return the sum of 18 | all parameters passed to the function: :: 19 | 20 | from pfp.fields import PYVAL 21 | 22 | @native(name="Sum", ret=pfp.fields.Int64) 23 | def sum_numbers(params, ctxt, scope, stream, coord): 24 | res = 0 25 | for param in params: 26 | res += PYVAL(param) 27 | return res 28 | 29 | The code below is the code for the :any:`Int3 ` function. Notice that it 30 | requires that the interpreter be sent as a parameter: :: 31 | 32 | @native(name="Int3", ret=pfp.fields.Void, send_interp=True) 33 | def int3(params, ctxt, scope, stream, coord, interp): 34 | if interp._no_debug: 35 | return 36 | 37 | if interp._int3: 38 | interp.debugger = PfpDbg(interp) 39 | interp.debugger.cmdloop() 40 | """ 41 | 42 | def native_decorator(func): 43 | @functools.wraps(func) 44 | def native_wrapper(*args, **kwargs): 45 | return func(*args, **kwargs) 46 | 47 | pfp.interp.PfpInterp.add_native( 48 | name, func, ret, interp=interp, send_interp=send_interp 49 | ) 50 | return native_wrapper 51 | 52 | return native_decorator 53 | 54 | 55 | def predefine(template): 56 | pfp.interp.PfpInterp.add_predefine(template) 57 | -------------------------------------------------------------------------------- /pfp/native/compat_consts.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | 5 | """ 6 | This module defines constants that don't fit into tool or inteferface 7 | categories 8 | """ 9 | 10 | 11 | from pfp.native import predefine 12 | 13 | 14 | predefine( 15 | """ 16 | const int true = 1; 17 | const int True = 1; 18 | const int TRUE = 1; 19 | 20 | const int false = 0; 21 | const int False = 0; 22 | const int FALSE = 0; 23 | """ 24 | ) 25 | -------------------------------------------------------------------------------- /pfp/native/compat_math.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | 4 | """ 5 | This module of native functions is implemented for 6 | compatability with 010 editor functions. Some of these functions 7 | are nops, some are fully implemented. 8 | """ 9 | 10 | import sys 11 | 12 | from pfp.native import native 13 | import pfp.fields 14 | 15 | # http://www.sweetscape.com/010editor/manual/FuncMath.htm 16 | 17 | # double Abs( double x ) 18 | @native(name="Abs", ret=pfp.fields.Double) 19 | def Abs(params, ctxt, scope, stream, coord): 20 | if params[0]._pfp__interp._generate: 21 | return 0.0 22 | raise NotImplementedError() 23 | 24 | 25 | # double Ceil( double x ) 26 | @native(name="Ceil", ret=pfp.fields.Double) 27 | def Ceil(params, ctxt, scope, stream, coord): 28 | raise NotImplementedError() 29 | 30 | 31 | # double Cos( double a ) 32 | @native(name="Cos", ret=pfp.fields.Double) 33 | def Cos(params, ctxt, scope, stream, coord): 34 | raise NotImplementedError() 35 | 36 | 37 | # double Exp( double x ) 38 | @native(name="Exp", ret=pfp.fields.Double) 39 | def Exp(params, ctxt, scope, stream, coord): 40 | raise NotImplementedError() 41 | 42 | 43 | # double Floor( double x) 44 | @native(name="Floor", ret=pfp.fields.Double) 45 | def Floor(params, ctxt, scope, stream, coord): 46 | raise NotImplementedError() 47 | 48 | 49 | # double Log( double x ) 50 | @native(name="Log", ret=pfp.fields.Double) 51 | def Log(params, ctxt, scope, stream, coord): 52 | raise NotImplementedError() 53 | 54 | 55 | # double Max( double a, double b ) 56 | @native(name="Max", ret=pfp.fields.Double) 57 | def Max(params, ctxt, scope, stream, coord): 58 | raise NotImplementedError() 59 | 60 | 61 | # double Min( double a, double b) 62 | @native(name="Min", ret=pfp.fields.Double) 63 | def Min(params, ctxt, scope, stream, coord): 64 | raise NotImplementedError() 65 | 66 | 67 | # double Pow( double x, double y) 68 | @native(name="Pow", ret=pfp.fields.Double) 69 | def Pow(params, ctxt, scope, stream, coord): 70 | raise NotImplementedError() 71 | 72 | 73 | # int Random( int maximum ) 74 | @native(name="Random", ret=pfp.fields.Int) 75 | def Random(params, ctxt, scope, stream, coord): 76 | raise NotImplementedError() 77 | 78 | 79 | # double Sin( double a ) 80 | @native(name="Sin", ret=pfp.fields.Double) 81 | def Sin(params, ctxt, scope, stream, coord): 82 | raise NotImplementedError() 83 | 84 | 85 | # double Sqrt( double x ) 86 | @native(name="Sqrt", ret=pfp.fields.Double) 87 | def Sqrt(params, ctxt, scope, stream, coord): 88 | raise NotImplementedError() 89 | 90 | 91 | # data_type SwapBytes( data_type x ) 92 | @native(name="SwapBytes", ret=pfp.fields.Int) 93 | def SwapBytes(params, ctxt, scope, stream, coord): 94 | raise NotImplementedError() 95 | 96 | 97 | # double Tan( double a ) 98 | @native(name="Tan", ret=pfp.fields.Double) 99 | def Tan(params, ctxt, scope, stream, coord): 100 | raise NotImplementedError() 101 | -------------------------------------------------------------------------------- /pfp/native/dbg.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | 4 | from pfp.native import native 5 | import pfp.fields 6 | from pfp.dbg import PfpDbg 7 | 8 | 9 | @native(name="Int3", ret=pfp.fields.Void, send_interp=True) 10 | def int3(params, ctxt, scope, stream, coord, interp): 11 | """Define the ``Int3()`` function in the interpreter. Calling 12 | ``Int3()`` will drop the user into an interactive debugger. 13 | """ 14 | if interp._no_debug: 15 | return 16 | 17 | if interp._int3: 18 | interp.debugger = PfpDbg(interp) 19 | interp.debugger.cmdloop() 20 | -------------------------------------------------------------------------------- /pfp/native/packers.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | 4 | import zlib 5 | import six 6 | 7 | from pfp.native import native 8 | import pfp.fields 9 | from pfp.dbg import PfpDbg 10 | import pfp.utils as utils 11 | import pfp.errors as errors 12 | 13 | 14 | @native(name="PackerGZip", ret=pfp.fields.Array) 15 | def packer_gzip(params, ctxt, scope, stream, coord): 16 | """``PackerGZip`` - implements both unpacking and packing. Can be used 17 | as the ``packer`` for a field. When packing, concats the build output 18 | of all params and gzip-compresses the result. When unpacking, concats 19 | the build output of all params and gzip-decompresses the result. 20 | 21 | Example: 22 | 23 | The code below specifies that the ``data`` field is gzipped 24 | and that once decompressed, should be parsed with ``PACK_TYPE``. 25 | When building the ``PACK_TYPE`` structure, ``data`` will be updated 26 | with the compressed data.:: 27 | 28 | char data[0x100]; 29 | 30 | :pack: True if the data should be packed, false if it should be unpacked 31 | :data: The data to operate on 32 | :returns: An array 33 | """ 34 | if len(params) <= 1: 35 | raise errors.InvalidArguments( 36 | coord, "{} args".format(len(params)), "at least two arguments" 37 | ) 38 | 39 | # to gzip it (pack it) 40 | if params[0]: 41 | return pack_gzip(params[1:], ctxt, scope, stream, coord) 42 | else: 43 | return unpack_gzip(params[1:], ctxt, scope, stream, coord) 44 | 45 | 46 | @native(name="PackGZip", ret=pfp.fields.Array) 47 | def pack_gzip(params, ctxt, scope, stream, coord): 48 | """``PackGZip`` - Concats the build output of all params and gzips the 49 | resulting data, returning a char array. 50 | 51 | Example: :: 52 | 53 | char data[0x100]; 54 | """ 55 | if len(params) == 0: 56 | raise errors.InvalidArguments( 57 | coord, "{} args".format(len(params)), "at least one argument" 58 | ) 59 | 60 | built = utils.binary("") 61 | for param in params: 62 | if isinstance(param, pfp.fields.Field): 63 | built += param._pfp__build() 64 | else: 65 | built += param 66 | 67 | return zlib.compress(built) 68 | 69 | 70 | @native(name="UnpackGZip", ret=pfp.fields.Array) 71 | def unpack_gzip(params, ctxt, scope, stream, coord): 72 | """``UnpackGZip`` - Concats the build output of all params and gunzips the 73 | resulting data, returning a char array. 74 | 75 | Example: :: 76 | 77 | char data[0x100]; 78 | """ 79 | if len(params) == 0: 80 | raise errors.InvalidArguments( 81 | coord, "{} args".format(len(params)), "at least one argument" 82 | ) 83 | 84 | built = utils.binary("") 85 | for param in params: 86 | if isinstance(param, pfp.fields.Field): 87 | built += param._pfp__build() 88 | else: 89 | built += param 90 | 91 | return zlib.decompress(built) 92 | -------------------------------------------------------------------------------- /pfp/native/watchers.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | 4 | import binascii 5 | import zlib 6 | import six 7 | 8 | from pfp.native import native 9 | import pfp.fields 10 | from pfp.dbg import PfpDbg 11 | import pfp.utils as utils 12 | import pfp.errors as errors 13 | 14 | 15 | @native(name="WatchLength", ret=pfp.fields.Void) 16 | def watch_length(params, ctxt, scope, stream, coord): 17 | """WatchLength - Watch the total length of each of the params. 18 | 19 | Example: 20 | The code below uses the ``WatchLength`` update function to update 21 | the ``length`` field to the length of the ``data`` field :: 22 | 23 | int length; 24 | char data[length]; 25 | """ 26 | if len(params) <= 1: 27 | raise errors.InvalidArguments( 28 | coord, "{} args".format(len(params)), "at least two arguments" 29 | ) 30 | 31 | to_update = params[0] 32 | 33 | total_size = 0 34 | for param in params[1:]: 35 | total_size += param._pfp__width() 36 | 37 | to_update._pfp__set_value(total_size) 38 | 39 | 40 | @native(name="WatchCrc32", ret=pfp.fields.Void) 41 | def watch_crc(params, ctxt, scope, stream, coord): 42 | """WatchCrc32 - Watch the total crc32 of the params. 43 | 44 | Example: 45 | The code below uses the ``WatchCrc32`` update function to update 46 | the ``crc`` field to the crc of the ``length`` and ``data`` fields :: 47 | 48 | char length; 49 | char data[length]; 50 | int crc; 51 | """ 52 | if len(params) <= 1: 53 | raise errors.InvalidArguments( 54 | coord, "{} args".format(len(params)), "at least two arguments" 55 | ) 56 | 57 | to_update = params[0] 58 | 59 | total_data = utils.binary("") 60 | for param in params[1:]: 61 | total_data += param._pfp__build() 62 | 63 | to_update._pfp__set_value(binascii.crc32(total_data)) 64 | -------------------------------------------------------------------------------- /pfp/utils.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | 4 | import contextlib 5 | import six 6 | import sys 7 | import time 8 | 9 | 10 | @contextlib.contextmanager 11 | def timeit(msg, num=None): 12 | start = time.time() 13 | yield 14 | end = time.time() 15 | if num is None: 16 | print("{} took {:.04f}s".format(msg, end - start)) 17 | else: 18 | print("{} with {:.04f}/s".format(msg, (num / (end - start)))) 19 | 20 | 21 | def is_str(s): 22 | for type_ in six.string_types: 23 | if isinstance(s, type_): 24 | return True 25 | if isinstance(s, bytes): 26 | return True 27 | return False 28 | 29 | 30 | # Useful for very coarse version differentiation. 31 | PY3 = sys.version_info[0] == 3 32 | 33 | if PY3: 34 | from queue import Queue 35 | 36 | def string_escape(s): 37 | return bytes(string(s), "utf-8").decode("unicode_escape") 38 | 39 | def binary(s): 40 | if type(s) is bytes: 41 | return s 42 | return s.encode("ISO-8859-1") 43 | 44 | def string(s): 45 | if type(s) is bytes: 46 | return s.decode("ISO-8859-1") 47 | return s 48 | 49 | 50 | else: 51 | from Queue import Queue 52 | 53 | def string_escape(s): 54 | return string(s).decode("string_escape") 55 | 56 | def binary(s): 57 | return s 58 | 59 | def string(s): 60 | return s 61 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | py010parser>=0.1.17 2 | six>=1.10.0,<2.0.0 3 | intervaltree>=3.0.2,<4.0.0 4 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | description-file = README.md 3 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | 4 | import os, sys 5 | from setuptools import setup 6 | 7 | setup( 8 | # metadata 9 | name="pfp", 10 | description="An 010 template interpreter for Python", 11 | long_description=""" 12 | pfp is an 010 template interpreter for Python. It accepts an 13 | input data stream and an 010 template and returns a modifiable 14 | DOM of the parsed data. Extensions have also been added to the 15 | 010 template syntax to allow for linked fields (e.g. checksums, 16 | length calculations, etc), sub structures in compressed data, 17 | etc. 18 | """, 19 | license="MIT", 20 | version="{{VERSION}}", 21 | author="James Johnson", 22 | maintainer="James Johnson", 23 | author_email="d0c.s4vage@gmail.com", 24 | url="https://github.com/d0c-s4vage/pfp", 25 | platforms="Cross Platform", 26 | download_url="https://github.com/d0c-s4vage/pfp/tarball/v{{VERSION}}", 27 | install_requires=open( 28 | os.path.join(os.path.dirname(__file__), "requirements.txt") 29 | ) 30 | .read() 31 | .split("\n"), 32 | classifiers=[ 33 | "Programming Language :: Python :: 2", 34 | "Programming Language :: Python :: 3", 35 | ], 36 | entry_points={ 37 | "console_scripts": ["pfp = pfp.__main__:main"] 38 | }, 39 | packages=["pfp", "pfp.native", "pfp.fuzz"], 40 | ) 41 | -------------------------------------------------------------------------------- /specification/ISO_IEC_14496-12_2005-04-01.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/specification/ISO_IEC_14496-12_2005-04-01.pdf -------------------------------------------------------------------------------- /specification/ISO_IEC_14496-14_2003-11-15.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/specification/ISO_IEC_14496-14_2003-11-15.pdf -------------------------------------------------------------------------------- /templates/avi-orig.bt: -------------------------------------------------------------------------------- 1 | //------------------------------------------------ 2 | //--- 010 Editor v1.2 Binary Template 3 | // 4 | // File: AVI.bt 5 | // Authors: Blaine Lefebvre [bl], Elias Bachaalany [eb] 6 | // Version: 1.2 7 | // Purpose: Parse an AVI movie file. 8 | // Category: Video 9 | // File Mask: *.avi 10 | // ID Bytes: 52 49 46 46 [+4] 41 56 49 20 //RIFF????AVI 11 | // History: 12 | // 1.2 2016-01-27 SweetScape: Updated header for repository submission, added coloring for header. 13 | // 1.1 2006-10-02 eb: Added BITMAPINFO and WAVEFORMATEX proper strfHEADER recognition, 14 | // Fixed 'idx1' parsing. 15 | // 1.0 bl: Initial release. 16 | //------------------------------------------------ 17 | 18 | typedef struct 19 | { 20 | WORD wFormatTag; 21 | WORD nChannels; 22 | DWORD nSamplesPerSec; 23 | DWORD nAvgBytesPerSec; 24 | WORD nBlockAlign; 25 | WORD wBitsPerSample; 26 | WORD cbSize; 27 | } WAVEFORMATEX; 28 | 29 | // head structure info 30 | typedef struct 31 | { 32 | DWORD dwMicroSecPerFrame; 33 | DWORD dwMaxBytesPerSec; 34 | DWORD dwReserved1; 35 | DWORD dwFlags; 36 | DWORD dwTotalFrames; 37 | DWORD dwInitialFrames; 38 | DWORD dwStreams; 39 | DWORD dwSuggestedBufferSize; 40 | DWORD dwWidth; 41 | DWORD dwHeight; 42 | DWORD dwScale; 43 | DWORD dwRate; 44 | DWORD dwStart; 45 | DWORD dwLength; 46 | } MainAVIHeader; 47 | 48 | typedef struct 49 | { 50 | uint32 biSize; 51 | uint32 biWidth; 52 | uint32 biHeight; 53 | uint16 biPlanes; 54 | uint16 biBitCount; 55 | uint32 biCompression; 56 | uint32 biSizeImage; 57 | uint32 biXPelsPerMeter; 58 | uint32 biYPelsPerMeter; 59 | uint32 biClrUsed; 60 | uint32 biClrImportant; 61 | } BITMAPINFOHEADER; 62 | 63 | typedef struct 64 | { 65 | unsigned char rgbBlue; 66 | unsigned char rgbGreen; 67 | unsigned char rgbRed; 68 | unsigned char rgbReserved; 69 | } RGBQUAD; 70 | 71 | typedef struct 72 | { 73 | BITMAPINFOHEADER bmiHeader; 74 | RGBQUAD bmiColors; 75 | } BITMAPINFO; 76 | 77 | typedef struct 78 | { 79 | char id[4]; 80 | uint32 datalen; 81 | MainAVIHeader data; 82 | } avihHEADER; 83 | 84 | 85 | // header stream structure info 86 | typedef struct 87 | { 88 | char fccType[4]; 89 | char fccHandler[4]; 90 | DWORD dwFlags; 91 | DWORD dwReserved1; 92 | DWORD dwInitialFrames; 93 | DWORD dwScale; 94 | DWORD dwRate; 95 | DWORD dwStart; 96 | DWORD dwLength; 97 | DWORD dwSuggestedBufferSize; 98 | DWORD dwQuality; 99 | DWORD dwSampleSize; 100 | DWORD xdwQuality; 101 | DWORD xdwSampleSize; 102 | } AVIStreamHeader; 103 | 104 | typedef struct 105 | { 106 | char id[4]; 107 | uint32 datalen; 108 | AVIStreamHeader data; 109 | }strhHEADER; 110 | 111 | 112 | // Generic strfHEADER 113 | typedef struct 114 | { 115 | char id[4]; 116 | uint32 datalen; 117 | if (datalen % 2) 118 | char data[datalen+1]; 119 | else 120 | char data[datalen]; 121 | } strfHEADER; 122 | 123 | // strfHEADER with BITMAPINFOHEADER 124 | typedef struct 125 | { 126 | char id[4]; 127 | uint32 datalen; 128 | BITMAPINFOHEADER bmiHeader; 129 | local int sz = sizeof(bmiHeader); 130 | if (datalen == 44) 131 | { 132 | RGBQUAD bmiColors; 133 | sz += 4; 134 | } 135 | Printf("left: %d\n", sz); 136 | char exData[datalen - sz]; 137 | } strfHEADER_BIH; 138 | 139 | 140 | // strfHEADER with WAVEFORMAT 141 | typedef struct 142 | { 143 | char id[4]; 144 | uint32 datalen; 145 | WAVEFORMATEX wave; 146 | char exData[datalen - 18]; 147 | } strfHEADER_WAVE; 148 | 149 | // 150 | typedef struct 151 | { 152 | char id[4]; 153 | uint32 datalen; 154 | if ( datalen % 2 ) 155 | char data[datalen+1]; 156 | else 157 | char data[datalen]; 158 | } strnHEADER; 159 | 160 | // 161 | typedef struct 162 | { 163 | char id[4]; 164 | uint32 datalen; 165 | if ( datalen % 2 ) 166 | char data[datalen+1]; 167 | else 168 | char data[datalen]; 169 | } genericblock; 170 | 171 | 172 | 173 | typedef struct 174 | { 175 | char id[4]; 176 | uint32 datalen; 177 | char type[4]; 178 | 179 | if (!Memcmp(type,"hdrl",4)) 180 | { 181 | avihHEADER avhi; 182 | } 183 | else if (!Memcmp(type,"strl",4)) 184 | { 185 | strhHEADER strh; 186 | 187 | // Printf("->%c%c%c%c\n", strh.data.fccHandler[0], strh.data.fccHandler[1],strh.data.fccHandler[2],strh.data.fccHandler[3]); 188 | if (Memcmp(strh.data.fccType, "vids", 4) == 0) 189 | { 190 | strfHEADER_BIH strf; 191 | } 192 | else if (Memcmp(strh.data.fccType, "auds", 4) == 0) 193 | { 194 | strfHEADER_WAVE strf; 195 | } 196 | else 197 | { 198 | strfHEADER strf; 199 | } 200 | strnHEADER strn; 201 | } 202 | else if (Memcmp(type,"movi",4) == 0) 203 | { 204 | local int32 pointer = 0; 205 | local int32 stop = datalen - 4; 206 | 207 | //Printf("stop=%d\n", stop); 208 | 209 | do 210 | { 211 | genericblock gb; 212 | pointer += sizeof(gb); 213 | //Printf("+%x = %d\n", gb.datalen, pointer); 214 | } while (pointer != stop); 215 | } 216 | else 217 | { 218 | char data[datalen-4]; 219 | } 220 | } LISTHEADER; 221 | 222 | 223 | // junk structure info 224 | typedef struct 225 | { 226 | char id[4]; 227 | uint32 datalen; 228 | if ( datalen % 2 ) 229 | char data[datalen+1]; 230 | else 231 | char data[datalen]; 232 | } JUNKHEADER; 233 | 234 | 235 | // aviindex structure info 236 | typedef struct 237 | { 238 | DWORD ckid; 239 | DWORD dwFlags; 240 | DWORD dwChunkOffset; 241 | DWORD dwChunkLength; 242 | } AVIINDEXENTRY; 243 | 244 | const DWORD AVIINDEXENTRYLEN = 16; 245 | 246 | typedef struct 247 | { 248 | char id[4]; 249 | uint32 datalen; 250 | AVIINDEXENTRY data[datalen/AVIINDEXENTRYLEN]; 251 | } idx1HEADER; 252 | 253 | // root structure info 254 | typedef struct xroot 255 | { 256 | char id[4]; // RIFF 257 | if (root.id[3] == 'X') 258 | { 259 | Printf("Motorola format\n"); 260 | BigEndian(); 261 | } 262 | else 263 | { 264 | Printf("Intel format\n"); 265 | LittleEndian(); 266 | } 267 | 268 | uint32 datalen; 269 | char form[4]; 270 | 271 | if (Strcmp(form, "AVI ")) 272 | { 273 | Warning("Not a valid AVI file"); 274 | return -1; 275 | } 276 | } ROOT ; 277 | 278 | local char nheader[4]; 279 | 280 | ROOT root; 281 | 282 | while (!FEof()) 283 | { 284 | ReadBytes(nheader,FTell(), 4); 285 | 286 | if (Memcmp(nheader,"LIST",4) == 0) 287 | { 288 | LISTHEADER list; 289 | } 290 | else if (Memcmp(nheader, "JUNK",4) == 0) 291 | { 292 | JUNKHEADER junk; 293 | } 294 | else if (Memcmp(nheader, "idx1",4) == 0) 295 | { 296 | idx1HEADER idx1; 297 | } 298 | else 299 | { 300 | if (!FEof()) 301 | Printf("unknown chunk: %c%c%c%c", nheader[0],nheader[1],nheader[2],nheader[3]); 302 | return -1; 303 | } 304 | } 305 | -------------------------------------------------------------------------------- /templates/bmp-orig.bt: -------------------------------------------------------------------------------- 1 | //------------------------------------------------ 2 | //--- 010 Editor v2.0 Binary Template 3 | // 4 | // File: BMP.bt 5 | // Author: SweetScape Software 6 | // Version: 2.3 7 | // Purpose: Parse BMP image files. 8 | // Category: Image 9 | // File Mask: *.bmp 10 | // ID Bytes: 42 4D //BM 11 | // History: 12 | // 2.3 2016-02-26 SweetScape: Allow negative heights. 13 | // 2.2 2015-10-13 SweetScape: Updated header for repository submission. 14 | // 2.1 SweetScape: Bug fix for ReadRGBQUAD function. 15 | // 2.0 SweetScape: Added read functions. 16 | // 1.0 SweetScape: Initial release. 17 | // 18 | // More information available at 19 | // https://en.wikipedia.org/wiki/BMP_file_format 20 | //------------------------------------------------ 21 | 22 | // Define structures used in BMP files 23 | 24 | typedef struct { // bmfh 25 | CHAR bfType[2]; 26 | DWORD bfSize; 27 | WORD bfReserved1; 28 | WORD bfReserved2; 29 | DWORD bfOffBits; 30 | } BITMAPFILEHEADER; 31 | 32 | typedef struct { // bmih 33 | DWORD biSize; 34 | LONG biWidth; 35 | LONG biHeight; 36 | WORD biPlanes; 37 | WORD biBitCount; 38 | DWORD biCompression; 39 | DWORD biSizeImage; 40 | LONG biXPelsPerMeter; 41 | LONG biYPelsPerMeter; 42 | DWORD biClrUsed; 43 | DWORD biClrImportant; 44 | } BITMAPINFOHEADER; 45 | 46 | typedef struct { // rgbq 47 | UBYTE rgbBlue; 48 | UBYTE rgbGreen; 49 | UBYTE rgbRed; 50 | UBYTE rgbReserved; 51 | } RGBQUAD ; 52 | 53 | typedef struct { // rgbt 54 | UBYTE rgbBlue; 55 | UBYTE rgbGreen; 56 | UBYTE rgbRed; 57 | } RGBTRIPLE ; 58 | 59 | //--------------------------------------------- 60 | // Custom read functions for color types - this allows the 61 | // color to be displayed without having to open up the structure. 62 | 63 | string ReadRGBQUAD( RGBQUAD &a ) 64 | { 65 | string s; 66 | SPrintf( s, "#%02X%02X%02X%02X", a.rgbReserved, a.rgbRed, a.rgbGreen, a.rgbBlue ); 67 | return s; 68 | } 69 | 70 | string ReadRGBTRIPLE( RGBTRIPLE &a ) 71 | { 72 | string s; 73 | SPrintf( s, "#%02X%02X%02X", a.rgbRed, a.rgbGreen, a.rgbBlue ); 74 | return s; 75 | } 76 | 77 | //--------------------------------------------- 78 | 79 | // Define the headers 80 | LittleEndian(); 81 | SetBackColor( cLtGray ); 82 | BITMAPFILEHEADER bmfh; 83 | BITMAPINFOHEADER bmih; 84 | 85 | // Check for header 86 | if( bmfh.bfType != "BM" ) 87 | { 88 | Warning( "File is not a bitmap. Template stopped." ); 89 | return -1; 90 | } 91 | 92 | // Define the color table 93 | if( (bmih.biBitCount != 24) && (bmih.biBitCount != 32) ) 94 | { 95 | SetBackColor( cLtAqua ); 96 | if( bmih.biClrUsed > 0 ) 97 | RGBQUAD aColors[ bmih.biClrUsed ]; 98 | else 99 | RGBQUAD aColors[ 1 << bmih.biBitCount ]; 100 | } 101 | 102 | // Define the bytes of the data 103 | SetBackColor( cNone ); 104 | if( bmih.biCompression > 0 ) 105 | { 106 | // Bytes are compressed 107 | if( bmih.biSizeImage > 0 ) 108 | UBYTE rleData[ bmih.biSizeImage ]; 109 | else 110 | UBYTE rleData[ bmfh.bfSize - FTell() ]; 111 | } 112 | else 113 | { 114 | // Calculate bytes per line and padding required 115 | local int bytesPerLine = ( bmih.biWidth * bmih.biBitCount + 7 ) / 8; 116 | local int padding = 4 - (bytesPerLine % 4); 117 | if( padding == 4 ) 118 | padding = 0; 119 | 120 | // Define each line of the image 121 | struct BITMAPLINE { 122 | 123 | // Define color data 124 | if( bmih.biBitCount < 8 ) 125 | UBYTE imageData[ bytesPerLine ]; 126 | else if( bmih.biBitCount == 8 ) 127 | UBYTE colorIndex[ bmih.biWidth ]; 128 | else if( bmih.biBitCount == 24 ) 129 | RGBTRIPLE colors[ bmih.biWidth ]; 130 | else if( bmih.biBitCount == 32 ) 131 | RGBQUAD colors[ bmih.biWidth ]; 132 | 133 | // Pad if necessary 134 | if( padding != 0 ) 135 | UBYTE padBytes[ padding ]; 136 | 137 | } lines[ (bmih.biHeight < 0) ? -bmih.biHeight : bmih.biHeight] ; 138 | } 139 | -------------------------------------------------------------------------------- /templates/bmp.bt: -------------------------------------------------------------------------------- 1 | //------------------------------------------------ 2 | //--- 010 Editor v2.0 Binary Template 3 | // 4 | // File: BMP.bt 5 | // Author: SweetScape Software 6 | // Version: 2.3 7 | // Purpose: Parse BMP image files. 8 | // Category: Image 9 | // File Mask: *.bmp 10 | // ID Bytes: 42 4D //BM 11 | // History: 12 | // 2.3 2016-02-26 SweetScape: Allow negative heights. 13 | // 2.2 2015-10-13 SweetScape: Updated header for repository submission. 14 | // 2.1 SweetScape: Bug fix for ReadRGBQUAD function. 15 | // 2.0 SweetScape: Added read functions. 16 | // 1.0 SweetScape: Initial release. 17 | // 18 | // More information available at 19 | // https://en.wikipedia.org/wiki/BMP_file_format 20 | //------------------------------------------------ 21 | 22 | // Define structures used in BMP files 23 | 24 | typedef enum < DWORD > compressions1bpp { 25 | BI_RGB_1 = 0x0000, 26 | } E_COMPRESSIONS1BPP; 27 | 28 | typedef enum < DWORD > compressions2bpp { 29 | BI_RGB_2 = 0x0000, 30 | } E_COMPRESSIONS2BPP; 31 | 32 | typedef enum < DWORD > compressions4bpp { 33 | BI_RGB_4 = 0x0000, 34 | BI_RLE4_4 = 0x0002, //only 4 bit per pixel 35 | } E_COMPRESSIONS4BPP; 36 | 37 | typedef enum < DWORD > compressions8bpp { 38 | BI_RGB_8 = 0x0000, 39 | BI_RLE8_8 = 0x0001, //only 8 bit per pixel 40 | } E_COMPRESSIONS8BPP; 41 | 42 | typedef enum < DWORD > compressions16bpp {//always stored uncompressed 43 | BI_RGB_16 = 0x0000, 44 | //BI_BITFIELDS_16 = 0x0003, //only 16 and 32 bit per pixel //TODO implement bitfields 45 | } E_COMPRESSIONS16BPP; 46 | 47 | typedef enum < DWORD > compressions24bpp { 48 | BI_RGB_24 = 0x0000, 49 | } E_COMPRESSIONS24BPP; 50 | 51 | typedef enum < DWORD > compressions32bpp { //always stored uncompressed 52 | BI_RGB_32 = 0x0000, 53 | //BI_BITFIELDS_32 = 0x0003, //only 16 and 32 bit per pixel 54 | } E_COMPRESSIONS32BPP; 55 | 56 | typedef enum < WORD > bpp { 57 | One = 1, 58 | // Two = 2, 59 | Four = 4, //TODO 30% 60 | Eight = 8, //TODO 8% 61 | Sixteen = 16, 62 | Twentyfour = 24, 63 | Thirtytwo = 32, 64 | } E_BPP; 65 | 66 | typedef struct { // bmfh 67 | local int evil = SetEvilBit(false); 68 | CHAR bfType[2] = {"BM"}; 69 | SetEvilBit(evil); 70 | DWORD bfSize; //fixed at the end of binary template 71 | WORD bfReserved1 = { 0x0 }; 72 | WORD bfReserved2 = { 0x0 }; 73 | DWORD bfOffBits; //An integer (unsigned) representing the offset of actual pixel data in bytes. In nutshell:- it is the number of bytes between start of the file (0) and the first byte of the pixel data. TODO fix after creation if needed 74 | } BITMAPFILEHEADER; 75 | 76 | typedef struct { // bmih 77 | DWORD biSize = { 40 }; 78 | LONG biWidth ; 79 | LONG biHeight ; 80 | WORD biPlanes = { 1 }; 81 | E_BPP biBitCount; 82 | if(biBitCount == 1 ){ 83 | E_COMPRESSIONS1BPP biCompression; 84 | } 85 | if(biBitCount == 2 ){ 86 | E_COMPRESSIONS2BPP biCompression; 87 | } 88 | if(biBitCount == 4 ){ 89 | E_COMPRESSIONS4BPP biCompression; 90 | } 91 | if(biBitCount == 8 ){ 92 | E_COMPRESSIONS8BPP biCompression; 93 | } 94 | if(biBitCount == 16 ){ 95 | E_COMPRESSIONS16BPP biCompression; 96 | } 97 | if(biBitCount == 24 ){ 98 | E_COMPRESSIONS24BPP biCompression; 99 | } 100 | if(biBitCount == 32 ){ 101 | E_COMPRESSIONS32BPP biCompression; 102 | } 103 | if(biCompression == 0 || biCompression == 11){ //Size after compression set to 0 if no compression is used 104 | DWORD biSizeImage = { 0 }; 105 | } 106 | else{ 107 | DWORD biSizeImage; //TODO if needed calculate decompressed size 108 | } 109 | LONG biXPelsPerMeter = { 0 }; 110 | LONG biYPelsPerMeter = { 0 }; 111 | switch(biBitCount){ 112 | 113 | case 8: 114 | DWORD biClrUsed ; 115 | break; 116 | 117 | case 4: 118 | DWORD biClrUsed = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }; 119 | break; 120 | 121 | case 2: 122 | DWORD biClrUsed = { 0, 1, 2, 3, 4 }; 123 | break; 124 | 125 | case 1: 126 | DWORD biClrUsed = { 0, 1, 2 }; 127 | break; 128 | 129 | default: 130 | DWORD biClrUsed = { 0 }; 131 | } 132 | DWORD biClrImportant = { 0 }; 133 | } BITMAPINFOHEADER; 134 | 135 | typedef struct { // rgbq 136 | UBYTE rgbBlue; 137 | UBYTE rgbGreen; 138 | UBYTE rgbRed; 139 | UBYTE rgbReserved = { 0 }; 140 | } RGBQUAD ; 141 | 142 | typedef struct { // rgbt 143 | UBYTE rgbBlue; 144 | UBYTE rgbGreen; 145 | UBYTE rgbRed; 146 | } RGBTRIPLE ; 147 | 148 | typedef struct { // rgba 149 | UBYTE rgbBlue; 150 | UBYTE rgbGreen; 151 | UBYTE rgbRed; 152 | UBYTE alphamaskFlag; 153 | } RGBALPHA; 154 | 155 | //--------------------------------------------- 156 | // Custom read functions for color types - this allows the 157 | // color to be displayed without having to open up the structure. 158 | 159 | string ReadRGBQUAD( RGBQUAD &a ) 160 | { 161 | string s; 162 | SPrintf( s, "#%02X%02X%02X%02X", a.rgbReserved, a.rgbRed, a.rgbGreen, a.rgbBlue ); 163 | return s; 164 | } 165 | 166 | string ReadRGBTRIPLE( RGBTRIPLE &a ) 167 | { 168 | string s; 169 | SPrintf( s, "#%02X%02X%02X", a.rgbRed, a.rgbGreen, a.rgbBlue ); 170 | return s; 171 | } 172 | 173 | //--------------------------------------------- 174 | 175 | // Define the headers 176 | LittleEndian(); 177 | SetBackColor( cLtGray ); 178 | BITMAPFILEHEADER bmfh; 179 | BITMAPINFOHEADER bmih; 180 | 181 | // Check for header 182 | if( bmfh.bfType != "BM" ) 183 | { 184 | Warning( "File is not a bitmap. Template stopped." ); 185 | return -1; 186 | } 187 | 188 | // Define the color table only when biBitCount <= 8 TODO fix insufficient image data bug (color map size) bmp.c line 947 in ImageMagick 189 | if( (bmih.biBitCount != 16) && (bmih.biBitCount != 24) && (bmih.biBitCount != 32) ) 190 | { 191 | SetBackColor( cLtAqua ); 192 | if( bmih.biClrUsed > 0 ) 193 | RGBQUAD aColors[ bmih.biClrUsed ]; 194 | else 195 | RGBQUAD aColors[ 1 << bmih.biBitCount ]; 196 | } 197 | //Fixing offset 198 | local int evil = SetEvilBit(false); 199 | local DWORD current_pos = FTell(); 200 | FSeek(10);//fix offset to pixel data 201 | DWORD real_offset = { current_pos }; 202 | FSeek( current_pos ); 203 | SetEvilBit(evil); 204 | 205 | // Define the bytes of the data 206 | SetBackColor( cNone ); 207 | if( bmih.biCompression > 0 ) 208 | { 209 | // Bytes are compressed 210 | if( bmih.biSizeImage > 0 ) 211 | UBYTE rleData[ bmih.biSizeImage ]; 212 | else 213 | UBYTE rleData[ bmfh.bfSize - FTell() ]; 214 | } 215 | else 216 | { 217 | // Calculate bytes per line and padding required 218 | local int bytesPerLine = ( bmih.biWidth * bmih.biBitCount + 7 ) / 8; 219 | local int padding = 4 - (bytesPerLine % 4); 220 | if( padding == 4 ) 221 | padding = 0; 222 | 223 | // Define each line of the image 224 | struct BITMAPLINE { 225 | 226 | // Define color data 227 | if( bmih.biBitCount < 8 ) 228 | UBYTE imageData[ bytesPerLine ]; 229 | else if( bmih.biBitCount == 8 ) 230 | UBYTE colorIndex[ bmih.biWidth ]; 231 | else if( bmih.biBitCount == 16 ) 232 | RGBALPHA colors[ bmih.biWidth ]; 233 | else if( bmih.biBitCount == 24 ) 234 | RGBTRIPLE colors[ bmih.biWidth ]; 235 | else if( bmih.biBitCount == 32 ) 236 | RGBQUAD colors[ bmih.biWidth ]; 237 | 238 | // Pad if necessary 239 | if( padding != 0 ) 240 | UBYTE padBytes[ padding ]; 241 | 242 | } lines[ (bmih.biHeight < 0) ? -bmih.biHeight : bmih.biHeight] ; 243 | } 244 | 245 | // adding file size to header, needed to be parsed 246 | local int evil = SetEvilBit(false); 247 | local int file_size = FTell(); 248 | FSeek(2);//fix size 249 | LONG real_hsize = { file_size }; 250 | -------------------------------------------------------------------------------- /templates/gif-orig.bt: -------------------------------------------------------------------------------- 1 | //------------------------------------------------ 2 | //--- 010 Editor v2.0 Binary Template 3 | // 4 | // File: GIF.bt 5 | // Authors: Berend-Jan "SkyLined" Wever 6 | // Version: 1.3 7 | // Purpose: Defines a template for 8 | // parsing GIF image files. 9 | // Category: Image 10 | // File Mask: *.gif 11 | // ID Bytes: 47 49 46 //GIF 12 | // History: 13 | // 1.3 2016-01-28 SweetScape: Updated header for repository submission. 14 | // 1.2 2007-09-25 SweetScape: Added bug fixes for reading local color table and 15 | // changed ReadShort to ReadUShort. 16 | // 1.1 2007-05-02 SweetScape: Added bug fixes for reading global color table. 17 | // 1.0 BJ Wever: Initial release. 18 | //------------------------------------------------ 19 | 20 | // From GIF89a Specification: 21 | 22 | // ::= Header * Trailer 23 | // ::= Logical Screen Descriptor [Global Color Table] 24 | // ::= | 25 | // ::= [Graphic Control Extension] 26 | // ::= | Plain Text Extension 27 | // ::= Image Descriptor [Local Color Table] Image Data 28 | // ::= Application Extension | Comment Extension 29 | 30 | LittleEndian(); 31 | 32 | typedef struct { 33 | UBYTE R; 34 | UBYTE G; 35 | UBYTE B; 36 | } RGB ; 37 | string ReadRGB( RGB &color ) 38 | { 39 | string s; 40 | SPrintf( s, "#%02X%02X%02X", color.R, color.G, color.B ); 41 | return s; 42 | } 43 | typedef struct { 44 | local UBYTE size = ReadUByte(FTell()); 45 | while (size != 0) { 46 | struct DATASUBBLOCK { 47 | UBYTE Size; 48 | char Data[size]; 49 | } DataSubBlock; 50 | size = ReadUByte(FTell()); 51 | } 52 | UBYTE BlockTerminator; 53 | } DATASUBBLOCKS; 54 | 55 | typedef struct { 56 | char Signature[3]; 57 | char Version[3]; 58 | } GIFHEADER; 59 | 60 | typedef struct { 61 | ushort Width; 62 | ushort Height; 63 | BitfieldLeftToRight(); 64 | struct LOGICALSCREENDESCRIPTOR_PACKEDFIELDS { 65 | UBYTE GlobalColorTableFlag : 1; 66 | UBYTE ColorResolution : 3; 67 | UBYTE SortFlag : 1; 68 | UBYTE SizeOfGlobalColorTable : 3; 69 | } PackedFields; 70 | UBYTE BackgroundColorIndex; 71 | UBYTE PixelAspectRatio; 72 | } LOGICALSCREENDESCRIPTOR; 73 | 74 | // ::= Header * Trailer 75 | // Header 76 | SetBackColor( 0xFFFFFF ); 77 | GIFHEADER GifHeader; 78 | if( GifHeader.Signature != "GIF" ) 79 | { 80 | Warning( "File is not a valid GIF. Template stopped." ); 81 | return -1; 82 | } 83 | // ::= Logical Screen Descriptor [Global Color Table] 84 | // Logical Screen Descriptor 85 | SetBackColor( 0xE0E0E0 ); 86 | LOGICALSCREENDESCRIPTOR LogicalScreenDescriptor; 87 | // [Global Color Table] 88 | if (LogicalScreenDescriptor.PackedFields.GlobalColorTableFlag == 1) { 89 | SetBackColor( 0xC0C0C0 ); 90 | struct GLOBALCOLORTABLE { 91 | local int i; 92 | local int size = 1; 93 | for (i = 0; i <= LogicalScreenDescriptor.PackedFields.SizeOfGlobalColorTable; i++) { 94 | size *= 2; 95 | } 96 | RGB rgb[size]; 97 | } GlobalColorTable ;; 98 | } 99 | // ::= | 100 | SetBackColor( 0xFFFFFF ); 101 | struct DATA { 102 | while (ReadUByte(FTell()) != 0x3B) { 103 | // ::= [Graphic Control Extension] 104 | if (ReadUByte(FTell()) == 0x2C) { 105 | SetBackColor( 0xE0FFE0 ); 106 | struct IMAGEDESCRIPTOR { 107 | UBYTE ImageSeperator; 108 | ushort ImageLeftPosition; 109 | ushort ImageTopPosition; 110 | ushort ImageWidth; 111 | ushort ImageHeight; 112 | struct IMAGEDESCRIPTOR_PACKEDFIELDS { 113 | UBYTE LocalColorTableFlag : 1; 114 | UBYTE InterlaceFlag : 1; 115 | UBYTE SortFlag : 1; 116 | UBYTE Reserved : 2; 117 | UBYTE SizeOfLocalColorTable : 3; 118 | } PackedFields; 119 | } ImageDescriptor; 120 | if (ImageDescriptor.PackedFields.LocalColorTableFlag == 1) { 121 | SetBackColor( 0xC0FFC0 ); 122 | struct LOCALCOLORTABLE { 123 | local int i; 124 | local int size = 1; 125 | for (i = 0; i <= ImageDescriptor.PackedFields.SizeOfLocalColorTable; i++) { 126 | size *= 2; 127 | } 128 | RGB rgb[size]; 129 | } LocalColorTable ;; 130 | } 131 | SetBackColor( 0xA0FFA0 ); 132 | struct IMAGEDATA { 133 | UBYTE LZWMinimumCodeSize; 134 | DATASUBBLOCKS DataSubBlocks; 135 | } ImageData; 136 | } else if (ReadUShort(FTell()) == 0xF921) { 137 | SetBackColor( 0xC0FFFF ); 138 | struct GRAPHICCONTROLEXTENSION { 139 | UBYTE ExtensionIntroducer; // 0x21 140 | UBYTE GraphicControlLabel; // 0xF9 141 | struct GRAPHICCONTROLSUBBLOCK { 142 | UBYTE BlockSize; 143 | struct GRAPHICCONTROLEXTENSION_DATASUBBLOCK_PACKEDFIELDS { 144 | UBYTE Reserved : 3; 145 | UBYTE DisposalMethod : 3; 146 | UBYTE UserInputFlag : 1; 147 | UBYTE TransparentColorFlag : 1; 148 | } PackedFields; 149 | ushort DelayTime; 150 | UBYTE TransparentColorIndex; 151 | } GraphicControlSubBlock; 152 | UBYTE BlockTerminator; 153 | } GraphicControlExtension; 154 | } else if (ReadUShort(FTell()) == 0xFE21) { 155 | SetBackColor( 0xFFFFC0 ); 156 | struct COMMENTEXTENSION { 157 | UBYTE ExtensionIntroducer; // 0x21 158 | UBYTE CommentLabel; // 0xFE 159 | DATASUBBLOCKS CommentData; 160 | } CommentExtension; 161 | } else if (ReadUShort(FTell()) == 0x0121) { 162 | SetBackColor( 0xC0C0C0 ); 163 | struct PLAINTEXTEXTENTION { 164 | UBYTE ExtensionIntroducer; // 0x21 165 | UBYTE PlainTextLabel; // 0x01 166 | struct PLAINTEXTSUBBLOCK { 167 | UBYTE BlockSize; 168 | ushort TextGridLeftPosition; 169 | ushort TextGridTopPosition; 170 | ushort TextGridWidth; 171 | ushort TextGridHeight; 172 | UBYTE CharacterCellWidth; 173 | UBYTE CharacterCellHeight; 174 | UBYTE TextForegroundColorIndex; 175 | UBYTE TextBackgroundColorIndex; 176 | } PlainTextSubBlock; 177 | DATASUBBLOCKS PlainTextData; 178 | } PlainTextExtension; 179 | } else if (ReadUShort(FTell()) == 0xFF21) { 180 | SetBackColor( 0xC0C0FF ); 181 | struct APPLICATIONEXTENTION { 182 | UBYTE ExtensionIntroducer; // 0x21 183 | UBYTE ApplicationLabel; // 0xFF 184 | struct APPLICATIONSUBBLOCK { 185 | UBYTE BlockSize; 186 | char ApplicationIdentifier[8]; 187 | char ApplicationAuthenticationCode[3]; 188 | } ApplicationSubBlock; 189 | DATASUBBLOCKS ApplicationData; 190 | } ApplicationExtension; 191 | } else { 192 | SetBackColor( 0xFF8080 ); 193 | struct UNDEFINEDDATA { 194 | UBYTE ExtensionIntroducer; // 21 195 | UBYTE Label; // F9 196 | DATASUBBLOCKS DataSubBlocks; 197 | } UndefinedData; 198 | } 199 | } 200 | } Data; 201 | SetBackColor( 0xFFFFFF ); 202 | struct TRAILER { 203 | UBYTE GIFTrailer; 204 | } Trailer; 205 | -------------------------------------------------------------------------------- /templates/gif.bt: -------------------------------------------------------------------------------- 1 | //------------------------------------------------ 2 | //--- 010 Editor v2.0 Binary Template 3 | // 4 | // File: GIF.bt 5 | // Authors: Berend-Jan "SkyLined" Wever 6 | // Version: 1.3 7 | // Purpose: Defines a template for 8 | // parsing GIF image files. 9 | // Category: Image 10 | // File Mask: *.gif 11 | // ID Bytes: 47 49 46 //GIF 12 | // History: 13 | // 1.3 2016-01-28 SweetScape: Updated header for repository submission. 14 | // 1.2 2007-09-25 SweetScape: Added bug fixes for reading local color table and 15 | // changed ReadShort to ReadUShort. 16 | // 1.1 2007-05-02 SweetScape: Added bug fixes for reading global color table. 17 | // 1.0 BJ Wever: Initial release. 18 | //------------------------------------------------ 19 | 20 | // From GIF89a Specification: 21 | 22 | // ::= Header * Trailer 23 | // ::= Logical Screen Descriptor [Global Color Table] 24 | // ::= | 25 | // ::= [Graphic Control Extension] 26 | // ::= | Plain Text Extension 27 | // ::= Image Descriptor [Local Color Table] Image Data 28 | // ::= Application Extension | Comment Extension 29 | 30 | LittleEndian(); 31 | const local UBYTE ReadUByteInitValues[0]; 32 | 33 | typedef struct { 34 | UBYTE R; 35 | UBYTE G; 36 | UBYTE B; 37 | } RGB ; 38 | string ReadRGB( RGB &color ) 39 | { 40 | string s; 41 | SPrintf( s, "#%02X%02X%02X", color.R, color.G, color.B ); 42 | return s; 43 | } 44 | typedef struct { 45 | local UBYTE values[0]; 46 | local int count; 47 | for (count = 1; count < 256; ++count) 48 | values += (UBYTE)count; 49 | count = 0; 50 | local UBYTE size = ReadUByte(FTell(), values); 51 | while (size != 0) { 52 | struct DATASUBBLOCK { 53 | UBYTE Size; 54 | char Data[size]; 55 | } DataSubBlock; 56 | count += size; 57 | size = ReadUByte(FTell(), values); 58 | if (count > 1500) { 59 | local UBYTE values[] = { 0, 255 }; 60 | } 61 | } 62 | UBYTE BlockTerminator; 63 | } DATASUBBLOCKS; 64 | 65 | typedef struct { 66 | local int evil = SetEvilBit(false); 67 | char Signature[3]; 68 | SetEvilBit(evil); 69 | char Version[3] = { {"87a"}, {"89a"} }; 70 | } GIFHEADER; 71 | 72 | typedef struct { 73 | ushort Width; 74 | ushort Height; 75 | BitfieldLeftToRight(); 76 | struct LOGICALSCREENDESCRIPTOR_PACKEDFIELDS { 77 | UBYTE GlobalColorTableFlag : 1; 78 | UBYTE ColorResolution : 3; 79 | UBYTE SortFlag : 1; 80 | UBYTE SizeOfGlobalColorTable : 3; 81 | } PackedFields; 82 | UBYTE BackgroundColorIndex; 83 | if(GifHeader.Version == "89a") 84 | UBYTE PixelAspectRatio; 85 | else 86 | UBYTE PixelAspectRatio = { 0 }; 87 | } LOGICALSCREENDESCRIPTOR; 88 | 89 | // ::= Header * Trailer 90 | // Header 91 | SetBackColor( 0xFFFFFF ); 92 | GIFHEADER GifHeader; 93 | if( GifHeader.Signature != "GIF" ) 94 | { 95 | Warning( "File is not a valid GIF. Template stopped." ); 96 | return -1; 97 | } 98 | // ::= Logical Screen Descriptor [Global Color Table] 99 | // Logical Screen Descriptor 100 | SetBackColor( 0xE0E0E0 ); 101 | LOGICALSCREENDESCRIPTOR LogicalScreenDescriptor; 102 | // [Global Color Table] 103 | if (LogicalScreenDescriptor.PackedFields.GlobalColorTableFlag == 1) { 104 | SetBackColor( 0xC0C0C0 ); 105 | struct GLOBALCOLORTABLE { 106 | local int i; 107 | local int size = 1; 108 | for (i = 0; i <= LogicalScreenDescriptor.PackedFields.SizeOfGlobalColorTable; i++) { 109 | size *= 2; 110 | } 111 | RGB rgb[size]; 112 | } GlobalColorTable ;; 113 | } 114 | // ::= | 115 | SetBackColor( 0xFFFFFF ); 116 | struct DATA { 117 | if(GifHeader.Version == "89a") 118 | local UBYTE possible[] = { 0x2C, 0x21 }; 119 | else 120 | local UBYTE possible[] = { 0x2C }; 121 | 122 | local int has_data = false; 123 | while (ReadUByte(FTell(), possible) != 0x3B) { 124 | // ::= [Graphic Control Extension] 125 | if (ReadUByte(FTell()) == 0x2C) { 126 | if (!has_data) { 127 | has_data = true; 128 | possible += 0x3B; 129 | } 130 | SetBackColor( 0xE0FFE0 ); 131 | struct IMAGEDESCRIPTOR { 132 | UBYTE ImageSeperator; 133 | ushort ImageLeftPosition; 134 | ushort ImageTopPosition; 135 | ushort ImageWidth; 136 | ushort ImageHeight; 137 | struct IMAGEDESCRIPTOR_PACKEDFIELDS { 138 | if(LogicalScreenDescriptor.PackedFields.GlobalColorTableFlag == 1) 139 | local UBYTE possible_values[] = { 0, 1 }; 140 | else 141 | local UBYTE possible_values[] = { 1 }; 142 | UBYTE LocalColorTableFlag : 1 ; 143 | UBYTE InterlaceFlag : 1; 144 | UBYTE SortFlag : 1; 145 | UBYTE Reserved : 2; 146 | UBYTE SizeOfLocalColorTable : 3; 147 | } PackedFields; 148 | } ImageDescriptor; 149 | if (ImageDescriptor.PackedFields.LocalColorTableFlag == 1) { 150 | SetBackColor( 0xC0FFC0 ); 151 | struct LOCALCOLORTABLE { 152 | local int i; 153 | local int size = 1; 154 | for (i = 0; i <= ImageDescriptor.PackedFields.SizeOfLocalColorTable; i++) { 155 | size *= 2; 156 | } 157 | RGB rgb[size]; 158 | } LocalColorTable ;; 159 | } 160 | SetBackColor( 0xA0FFA0 ); 161 | struct IMAGEDATA { 162 | UBYTE LZWMinimumCodeSize = { 8 }; 163 | DATASUBBLOCKS DataSubBlocks; 164 | } ImageData; 165 | } else if (ReadUShort(FTell()) == 0xF921) { 166 | SetBackColor( 0xC0FFFF ); 167 | struct GRAPHICCONTROLEXTENSION { 168 | UBYTE ExtensionIntroducer; // 0x21 169 | UBYTE GraphicControlLabel; // 0xF9 170 | struct GRAPHICCONTROLSUBBLOCK { 171 | UBYTE BlockSize = { 4 }; 172 | struct GRAPHICCONTROLEXTENSION_DATASUBBLOCK_PACKEDFIELDS { 173 | UBYTE Reserved : 3; 174 | UBYTE DisposalMethod : 3; 175 | UBYTE UserInputFlag : 1; 176 | UBYTE TransparentColorFlag : 1; 177 | } PackedFields; 178 | ushort DelayTime; 179 | UBYTE TransparentColorIndex; 180 | } GraphicControlSubBlock; 181 | UBYTE BlockTerminator; 182 | } GraphicControlExtension; 183 | } else if (ReadUShort(FTell()) == 0xFE21) { 184 | SetBackColor( 0xFFFFC0 ); 185 | struct COMMENTEXTENSION { 186 | UBYTE ExtensionIntroducer; // 0x21 187 | UBYTE CommentLabel; // 0xFE 188 | DATASUBBLOCKS CommentData; 189 | } CommentExtension; 190 | } else if (ReadUShort(FTell()) == 0x0121) { 191 | SetBackColor( 0xC0C0C0 ); 192 | struct PLAINTEXTEXTENTION { 193 | UBYTE ExtensionIntroducer; // 0x21 194 | UBYTE PlainTextLabel; // 0x01 195 | struct PLAINTEXTSUBBLOCK { 196 | UBYTE BlockSize; 197 | ushort TextGridLeftPosition; 198 | ushort TextGridTopPosition; 199 | ushort TextGridWidth; 200 | ushort TextGridHeight; 201 | UBYTE CharacterCellWidth; 202 | UBYTE CharacterCellHeight; 203 | UBYTE TextForegroundColorIndex; 204 | UBYTE TextBackgroundColorIndex; 205 | } PlainTextSubBlock; 206 | DATASUBBLOCKS PlainTextData; 207 | } PlainTextExtension; 208 | } else if (ReadUShort(FTell()) == 0xFF21) { 209 | SetBackColor( 0xC0C0FF ); 210 | struct APPLICATIONEXTENTION { 211 | UBYTE ExtensionIntroducer; // 0x21 212 | UBYTE ApplicationLabel; // 0xFF 213 | struct APPLICATIONSUBBLOCK { 214 | UBYTE BlockSize; 215 | char ApplicationIdentifier[8]; 216 | char ApplicationAuthenticationCode[3]; 217 | } ApplicationSubBlock; 218 | DATASUBBLOCKS ApplicationData; 219 | } ApplicationExtension; 220 | } else { 221 | SetBackColor( 0xFF8080 ); 222 | struct UNDEFINEDDATA { 223 | UBYTE ExtensionIntroducer; // 21 224 | UBYTE Label; // F9 225 | DATASUBBLOCKS DataSubBlocks; 226 | } UndefinedData; 227 | } 228 | } 229 | } Data; 230 | SetBackColor( 0xFFFFFF ); 231 | SetEvilBit(false); 232 | struct TRAILER { 233 | UBYTE GIFTrailer = {0x3B}; 234 | } Trailer; 235 | -------------------------------------------------------------------------------- /templates/midi-orig.bt: -------------------------------------------------------------------------------- 1 | //------------------------------------------------ 2 | //--- 010 Editor Binary Template 3 | // 4 | // File: MIDI.bt 5 | // Authors: Jack Andersen 6 | // Version: 1.2 7 | // Purpose: General MIDI sound file template. Complete with 8 | // delta-time and BPM evaluation into local variables. 9 | // Category: Audio 10 | // File Mask: *.mid 11 | // ID Bytes: 4D 54 68 64 //MThd 12 | // History: 13 | // 1.2 2016-05-17 J Andersen: Correctly interpret unset status-bit as repeat message. 14 | // 1.1 2016-02-12 SweetScape Software: Updated header for repository submission. 15 | // 1.0 J Andersen: Initial release. 16 | //------------------------------------------------ 17 | 18 | BigEndian(); 19 | 20 | struct MidiHeader 21 | { 22 | char m_magic[4] ; 23 | uint m_seclen; 24 | enum 25 | { 26 | MIDI_SINGLE = 0, 27 | MIDI_MULTIPLE = 1, 28 | MIDI_PATTERN = 2 29 | } m_format; 30 | short m_ntracks; 31 | short m_tickdiv; 32 | }; 33 | 34 | struct DeltaTime 35 | { 36 | local uint total = 0; 37 | char t0; 38 | total += t0 & 0x7f; 39 | if (!(t0 & 0x80)) 40 | break; 41 | 42 | total <<= 7; 43 | char t1; 44 | total += t1 & 0x7f; 45 | if (!(t1 & 0x80)) 46 | break; 47 | 48 | total <<= 7; 49 | char t2; 50 | total += t2 & 0x7f; 51 | if (!(t2 & 0x80)) 52 | break; 53 | 54 | total <<= 7; 55 | char t3; 56 | total += t3 & 0x7f; 57 | if (!(t3 & 0x80)) 58 | break; 59 | }; 60 | 61 | local char lastStatus = 0; 62 | 63 | struct MidiMessage 64 | { 65 | DeltaTime m_dtime; 66 | char m_status; 67 | if (m_status & 0x80) 68 | lastStatus = m_status; 69 | else 70 | FSeek(FTell()-1); 71 | 72 | local char m_channel = lastStatus & 0xf; 73 | if ((lastStatus & 0xf0) == 0x80) 74 | { 75 | struct 76 | { 77 | char m_note; 78 | char m_velocity; 79 | } note_off_event; 80 | } 81 | else if ((lastStatus & 0xf0) == 0x90) 82 | { 83 | struct 84 | { 85 | char m_note; 86 | char m_velocity; 87 | } note_on_event; 88 | } 89 | else if ((lastStatus & 0xf0) == 0xA0) 90 | { 91 | struct 92 | { 93 | char m_note; 94 | char m_pressure; 95 | } note_pressure_event; 96 | } 97 | else if ((lastStatus & 0xf0) == 0xB0) 98 | { 99 | struct 100 | { 101 | char m_controller; 102 | char m_value; 103 | } controller_event; 104 | } 105 | else if ((lastStatus & 0xf0) == 0xC0) 106 | { 107 | struct 108 | { 109 | char m_program; 110 | } program_event; 111 | } 112 | else if ((lastStatus & 0xf0) == 0xD0) 113 | { 114 | struct 115 | { 116 | char m_pressure; 117 | } channel_pressure_event; 118 | } 119 | else if ((lastStatus & 0xf0) == 0xE0) 120 | { 121 | struct 122 | { 123 | char m_lsb; 124 | char m_msb; 125 | } pitch_bend_event; 126 | } 127 | else if (lastStatus == -1) 128 | { 129 | struct 130 | { 131 | enum 132 | { 133 | META_SEQUENCE_NUM = 0, 134 | META_TEXT = 1, 135 | META_COPYRIGHT = 2, 136 | META_SEQUENCE_NAME = 3, 137 | META_INSTRUMENT_NAME = 4, 138 | META_LYRIC = 5, 139 | META_MARKER = 6, 140 | META_CUE_POINT = 7, 141 | META_PROGRAM_NAME = 8, 142 | META_DEVICE_NAME = 9, 143 | META_MIDI_CHANNEL_PREFIX = 0x20, 144 | META_MIDI_PORT = 0x21, 145 | META_END_OF_TRACK = 0x2f, 146 | META_TEMPO = 0x51, 147 | META_SMPTE_OFFSET = 0x54, 148 | META_TIME_SIGNATURE = 0x58, 149 | META_KEY_SIGNATURE = 0x59, 150 | META_SEQUENCER_EVENT = 0x7f 151 | } m_type; 152 | DeltaTime m_length; 153 | if (m_type == META_SEQUENCE_NUM) 154 | { 155 | short m_seqNum; 156 | } 157 | else if (m_type == META_TEXT) 158 | { 159 | char m_text[m_length.total]; 160 | } 161 | else if (m_type == META_COPYRIGHT) 162 | { 163 | char m_copyright[m_length.total]; 164 | } 165 | else if (m_type == META_SEQUENCE_NAME) 166 | { 167 | char m_name[m_length.total]; 168 | } 169 | else if (m_type == META_INSTRUMENT_NAME) 170 | { 171 | char m_name[m_length.total]; 172 | } 173 | else if (m_type == META_LYRIC) 174 | { 175 | char m_lyric[m_length.total]; 176 | } 177 | else if (m_type == META_MARKER) 178 | { 179 | char m_marker[m_length.total]; 180 | } 181 | else if (m_type == META_CUE_POINT) 182 | { 183 | char m_cuePoint[m_length.total]; 184 | } 185 | else if (m_type == META_PROGRAM_NAME) 186 | { 187 | char m_programName[m_length.total]; 188 | } 189 | else if (m_type == META_DEVICE_NAME) 190 | { 191 | char m_deviceName[m_length.total]; 192 | } 193 | else if (m_type == META_MIDI_CHANNEL_PREFIX) 194 | { 195 | char m_channelPrefix; 196 | } 197 | else if (m_type == META_MIDI_PORT) 198 | { 199 | char m_port; 200 | } 201 | else if (m_type == META_END_OF_TRACK) 202 | { 203 | } 204 | else if (m_type == META_TEMPO) 205 | { 206 | uint m_usecPerQuarterNote : 24; 207 | // local uint m_bpm = 60000000 / m_usecPerQuarterNote; 208 | FSeek(FTell() - 1); 209 | } 210 | else if (m_type == META_SMPTE_OFFSET) 211 | { 212 | char m_hours; 213 | char m_mins; 214 | char m_secs; 215 | char m_fps; 216 | char m_fracFrames; 217 | } 218 | else if (m_type == META_TIME_SIGNATURE) 219 | { 220 | char m_numerator; 221 | char m_denominator; 222 | char m_clocksPerClick; 223 | char m_32ndPer4th; 224 | } 225 | else if (m_type == META_KEY_SIGNATURE) 226 | { 227 | char m_flatsSharps; 228 | char m_majorMinor; 229 | } 230 | else 231 | { 232 | char m_data[m_length.total]; 233 | } 234 | } meta_event; 235 | } 236 | else if ((lastStatus & 0xf0) == 0xF0) 237 | { 238 | struct 239 | { 240 | DeltaTime m_length; 241 | char m_message[m_length.total]; 242 | } sysex_event; 243 | } 244 | }; 245 | 246 | struct MidiTrack 247 | { 248 | char m_magic[4] ; 249 | uint m_seclen; 250 | local uint remaining = m_seclen; 251 | while (remaining) { 252 | MidiMessage message; 253 | remaining -= sizeof(message); 254 | } 255 | }; 256 | 257 | struct 258 | { 259 | MidiHeader header; 260 | MidiTrack tracks[header.m_ntracks] ; 261 | } file; 262 | -------------------------------------------------------------------------------- /templates/ogg-orig.bt: -------------------------------------------------------------------------------- 1 | //------------------------------------------------ 2 | //--- 010 Editor v4.0.4 Binary Template 3 | // 4 | // File: OGG.bt 5 | // Authors: George Woods 6 | // Version: 1.1 7 | // Purpose: Parses the ogg container format. 8 | // Category: Audio 9 | // File Mask: *.ogg,*.oga,*.ogv,*.ogx 10 | // ID Bytes: 4F 67 67 53 //OggS 11 | // History: 12 | // 1.1 2016-01-28 SweetScape: Updated header for repository submission. 13 | // 1.0 GS: Initial release. 14 | //------------------------------------------------ 15 | 16 | // ogg files can be quite large. Don't read more the 1000 pages. 17 | local uint MAXPAGES = 1000; 18 | 19 | typedef struct { // bmfh 20 | CHAR CapturePattern[4]; 21 | BYTE Version; 22 | BYTE HeaderType; 23 | QUAD GranulePosition; 24 | DWORD BitstreamSerial; 25 | DWORD PageSequenceNumber; 26 | DWORD Checksum; 27 | UBYTE PageSegments; 28 | 29 | // the lengths of the segments that follow 30 | UBYTE SegmentLen[PageSegments]; 31 | 32 | // the segments themselves 33 | local uint i; 34 | for (i = 0; i < PageSegments; i++) { 35 | struct { 36 | BYTE Data[SegmentLen[i]] ; 37 | } Segment; 38 | } 39 | } PAGE; 40 | 41 | 42 | LittleEndian(); 43 | 44 | local uint currpage = 0; 45 | while( !FEof() ) 46 | { 47 | currpage++; 48 | if (MAXPAGES < currpage) 49 | { 50 | Printf("Max Pages of %d reached!\n", MAXPAGES); 51 | return 0; 52 | } 53 | 54 | PAGE page ; 55 | 56 | // Check for valid header 57 | if( page.CapturePattern != "OggS" ) 58 | { 59 | Warning( "File is not a valid ogg file. Template stopped." ); 60 | return -1; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /templates/pcap-orig.bt: -------------------------------------------------------------------------------- 1 | //------------------------------------------------ 2 | //--- 010 Editor v3.0.3 Binary Template 3 | // 4 | // File: PCAP.bt 5 | // Authors: Didier Stevens 6 | // Website: https://DidierStevens.com 7 | // Version: 0.5 8 | // Purpose: Parse a PCAP network capture file. 9 | // Category: Network 10 | // File Mask: *.pcap 11 | // ID Bytes: D4 C3 B2 A1 12 | // History: 13 | // 0.5 2019-12-24 Tony Saigut: fix L2 padding. 14 | // 0.4 2019-05-22 S Gorbov: support for VLAN header. 15 | // 0.3 2018-03-15 Banny: support raw data pcap file. 16 | // 0.2 2016-02-12 SweetScape Software: Updated header for repository submission. 17 | // 0.1 D Stevens: Initial release. 18 | // 19 | // References: 20 | // http://wiki.wireshark.org/Development/LibpcapFileFormat 21 | //------------------------------------------------ 22 | 23 | typedef struct { 24 | uint32 magic_number ; /* magic number */ 25 | if(magic_number != 0xA1B2C3D4) { 26 | Warning("Not a valid PCAP file"); 27 | return 1; 28 | } 29 | uint16 version_major; /* major version number */ 30 | uint16 version_minor; /* minor version number */ 31 | int32 thiszone; /* GMT to local correction */ 32 | uint32 sigfigs; /* accuracy of timestamps */ 33 | uint32 snaplen; /* max length of captured packets, in octets */ 34 | uint32 network; /* data link type */ 35 | } PCAPHEADER; 36 | 37 | typedef struct 38 | { 39 | uchar Byte[6]; 40 | } MACaddr; 41 | 42 | typedef struct 43 | { 44 | MACaddr DstMac; 45 | MACaddr SrcMac; 46 | uint16 L3type; 47 | } Layer_2 ; 48 | 49 | typedef struct 50 | { 51 | uint16 priority:3; 52 | uint16 dei:1; 53 | uint16 id:12; 54 | uint16 L3type; 55 | } Dot1q ; 56 | 57 | typedef struct 58 | { 59 | uchar Byte[4]; 60 | } IPv4addr; 61 | 62 | string IPv4addrName(IPv4addr &IP) 63 | { 64 | string strReturn; 65 | SPrintf(strReturn,"%d.%d.%d.%d",IP.Byte[0],IP.Byte[1],IP.Byte[2],IP.Byte[3]); 66 | return strReturn; 67 | } 68 | typedef struct (uint16 proto_type) 69 | { 70 | uchar version:4; 71 | uchar ip_hdr_len:4; 72 | local int hdr_length = ip_hdr_len*4; 73 | BYTE DiffServField; 74 | uint16 total_length; 75 | if (proto_type == 0x0800) // IP 76 | { 77 | uint16 Identification; 78 | uint16 Flags; 79 | BYTE TTL; 80 | BYTE L4proto; 81 | uint16 HdrChecksum; 82 | IPv4addr SRC_IP; 83 | IPv4addr DST_IP; 84 | } 85 | else 86 | { 87 | BYTE Unknown[hdr_length-4]; 88 | } 89 | } Layer_3; 90 | 91 | typedef struct (ushort VER_HDR,uint16 total_length,uint L4proto) 92 | { 93 | local uint16 ip_hdr_length = VER_HDR*4; 94 | 95 | if (L4proto == 0x11) // UDP 96 | { 97 | uint16 SrcPort; 98 | uint16 DstPort; 99 | uint16 udp_hdr_len; 100 | uint16 ChkSum; 101 | } 102 | else if (L4proto == 0x6) // TCP 103 | { 104 | uint16 SrcPort; 105 | uint16 DstPort; 106 | uint32 SEQ; 107 | uint32 ACK; 108 | uchar tcp_hdr_len:4; 109 | uchar Reserved:4; 110 | BYTE Crap[tcp_hdr_len*4-13]; 111 | } 112 | else 113 | { 114 | BYTE packet[total_length-ip_hdr_length]; 115 | } 116 | 117 | } Layer_4; 118 | 119 | string L4protoName(BYTE val) 120 | { 121 | if (val == 0x06) 122 | { 123 | return "TCP"; 124 | } 125 | else if (val == 0x11) 126 | { 127 | return "UDP"; 128 | } 129 | else 130 | { 131 | return "Unknown"; 132 | } 133 | } 134 | 135 | typedef struct (uint32 network) { 136 | local uint32 len_before_l3; 137 | time_t ts_sec; /* timestamp seconds */ 138 | uint32 ts_usec; /* timestamp microseconds */ 139 | uint32 incl_len; /* number of octets of packet saved in file */ 140 | uint32 orig_len; /* actual length of packet */ 141 | BigEndian(); 142 | 143 | len_before_l3 = 0; 144 | if (network == 101) { // Raw IP; the packet begins with an IPv4 or IPv6 header 145 | Layer_3 L3(0x0800) ; 146 | } else { // other wise create L2 header 147 | Layer_2 L2 ; 148 | len_before_l3 += 14; 149 | if (L2.L3type == 0x0800) { 150 | Layer_3 L3(L2.L3type) ; 151 | } 152 | else if (L2.L3type == 0x8100) { 153 | Dot1q d1q ; 154 | len_before_l3 += 4; 155 | Layer_3 L3(d1q.L3type) ; 156 | } 157 | } 158 | Layer_4 L4(L3.ip_hdr_len,L3.total_length,L3.L4proto); 159 | 160 | if (L3.L4proto == 0x6) 161 | { 162 | local uint16 AppDataLen = L3.total_length - L3.ip_hdr_len*4 - L4.tcp_hdr_len*4; 163 | if (AppDataLen > 0) 164 | { 165 | BYTE AppData[AppDataLen]; 166 | } 167 | } 168 | else if (L3.L4proto == 0x11) 169 | { 170 | local uint AppDataLen = L4.udp_hdr_len-8; 171 | if (AppDataLen > 0) 172 | { 173 | BYTE AppData[AppDataLen]; 174 | } 175 | } 176 | if (len_before_l3 + L3.total_length < incl_len) { 177 | uchar padding[incl_len - len_before_l3 - L3.total_length]; 178 | } 179 | LittleEndian(); 180 | } PCAPRECORD ; 181 | 182 | string PCAPcomments(PCAPRECORD &P) 183 | { 184 | local uint16 L4_proto = P.L3.L4proto; 185 | string strReturn; 186 | local uint16 AppDataLen = 0; 187 | if (L4_proto == 0x6) 188 | { 189 | AppDataLen = P.L3.total_length - P.L3.ip_hdr_len*4 - P.L4.tcp_hdr_len*4; 190 | } 191 | else if (L4_proto == 0x11) 192 | { 193 | AppDataLen = P.L4.udp_hdr_len - 8; 194 | } 195 | SPrintf(strReturn,"%s:%d -> %s:%d %s %s",IPv4addrName(P.L3.SRC_IP),P.L4.SrcPort,IPv4addrName(P.L3.DST_IP),P.L4.DstPort,L4protoName(L4_proto), AppDataLen > 0 ? "***" : ""); 196 | return strReturn; 197 | } 198 | string ReadPCAPRECORD(PCAPRECORD &record) 199 | { 200 | string strReturn; 201 | 202 | SPrintf(strReturn, "%s.%06u", TimeTToString(record.ts_sec), record.ts_usec); 203 | return strReturn; 204 | } 205 | 206 | string MACname(MACaddr &addr) 207 | { 208 | string strReturn; 209 | SPrintf(strReturn,"%.02x:%.02x:%.02x:%.02x:%.02x:%.02x",addr.Byte[0],addr.Byte[1],addr.Byte[2],addr.Byte[3],addr.Byte[4],addr.Byte[5]); 210 | return strReturn; 211 | } 212 | 213 | // Define the headers 214 | LittleEndian(); 215 | PCAPHEADER header; 216 | 217 | while( !FEof() ) 218 | { 219 | PCAPRECORD record(header.network) ; 220 | } 221 | -------------------------------------------------------------------------------- /testcases/avi/Dev_Source_ESB_Base_ThirdParty_ASP.NET_Databinding_DataBinding_docs_bmp_search.avi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/avi/Dev_Source_ESB_Base_ThirdParty_ASP.NET_Databinding_DataBinding_docs_bmp_search.avi -------------------------------------------------------------------------------- /testcases/avi/TargetVideo_target_video7.avi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/avi/TargetVideo_target_video7.avi -------------------------------------------------------------------------------- /testcases/avi/XPSP1_NT_printscan_ui_shellext_src_cam.avi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/avi/XPSP1_NT_printscan_ui_shellext_src_cam.avi -------------------------------------------------------------------------------- /testcases/avi/dll_win32_shell32_res_avis_152.avi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/avi/dll_win32_shell32_res_avis_152.avi -------------------------------------------------------------------------------- /testcases/avi/private_shell_shdocvw_iforms.avi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/avi/private_shell_shdocvw_iforms.avi -------------------------------------------------------------------------------- /testcases/avi/small_movie.avi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/avi/small_movie.avi -------------------------------------------------------------------------------- /testcases/avi/source_Client_res_Upload.avi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/avi/source_Client_res_Upload.avi -------------------------------------------------------------------------------- /testcases/avi/video_Registration.avi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/avi/video_Registration.avi -------------------------------------------------------------------------------- /testcases/avi/video_test_bwrgb.avi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/avi/video_test_bwrgb.avi -------------------------------------------------------------------------------- /testcases/avi/webclient_node_modules_@videojs_vhs-utils_test_fixtures_formats_avi_av01.avi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/avi/webclient_node_modules_@videojs_vhs-utils_test_fixtures_formats_avi_av01.avi -------------------------------------------------------------------------------- /testcases/avi/webclient_node_modules_@videojs_vhs-utils_test_fixtures_formats_avi_avc1.640028.avi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/avi/webclient_node_modules_@videojs_vhs-utils_test_fixtures_formats_avi_avc1.640028.avi -------------------------------------------------------------------------------- /testcases/bmp/input.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/bmp/input.bmp -------------------------------------------------------------------------------- /testcases/bmp/not_kitty.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/bmp/not_kitty.bmp -------------------------------------------------------------------------------- /testcases/bmp/plus.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/bmp/plus.bmp -------------------------------------------------------------------------------- /testcases/bmp/tclmagick-small-diff.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/bmp/tclmagick-small-diff.bmp -------------------------------------------------------------------------------- /testcases/bmp/testimg.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/bmp/testimg.bmp -------------------------------------------------------------------------------- /testcases/bmp/toolbar.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/bmp/toolbar.bmp -------------------------------------------------------------------------------- /testcases/bmp/valid.1.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/bmp/valid.1.bmp -------------------------------------------------------------------------------- /testcases/bmp/w32g_sleep.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/bmp/w32g_sleep.bmp -------------------------------------------------------------------------------- /testcases/bmp/w32g_subbtn.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/bmp/w32g_subbtn.bmp -------------------------------------------------------------------------------- /testcases/bmp/w32g_tracer.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/bmp/w32g_tracer.bmp -------------------------------------------------------------------------------- /testcases/empty/empty: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /testcases/gif/czoch.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/gif/czoch.gif -------------------------------------------------------------------------------- /testcases/gif/lineup_16.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/gif/lineup_16.gif -------------------------------------------------------------------------------- /testcases/gif/mri.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/gif/mri.gif -------------------------------------------------------------------------------- /testcases/gif/not_kitty.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/gif/not_kitty.gif -------------------------------------------------------------------------------- /testcases/gif/polyfish_lines.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/gif/polyfish_lines.gif -------------------------------------------------------------------------------- /testcases/gif/prototein.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/gif/prototein.gif -------------------------------------------------------------------------------- /testcases/jpg/not_kitty.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/jpg/not_kitty.jpg -------------------------------------------------------------------------------- /testcases/jpg/testimgint.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/jpg/testimgint.jpg -------------------------------------------------------------------------------- /testcases/jpg/testorig.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/jpg/testorig.jpg -------------------------------------------------------------------------------- /testcases/jpg/testorig12.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/jpg/testorig12.jpg -------------------------------------------------------------------------------- /testcases/jpg/w3c_home.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/jpg/w3c_home.jpg -------------------------------------------------------------------------------- /testcases/jpg/w3c_home_256.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/jpg/w3c_home_256.jpg -------------------------------------------------------------------------------- /testcases/jpg/w3c_home_gray.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/jpg/w3c_home_gray.jpg -------------------------------------------------------------------------------- /testcases/midi/180 BPM - Ghostly Night - Fills.mid: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/midi/180 BPM - Ghostly Night - Fills.mid -------------------------------------------------------------------------------- /testcases/midi/Nashville - 130BPM Downtown - Verse 01.mid: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/midi/Nashville - 130BPM Downtown - Verse 01.mid -------------------------------------------------------------------------------- /testcases/midi/Ran-D - Living For The Moment 2.mid: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/midi/Ran-D - Living For The Moment 2.mid -------------------------------------------------------------------------------- /testcases/midi/beatbox.mid: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/midi/beatbox.mid -------------------------------------------------------------------------------- /testcases/midi/chpn-p7_format0.mid: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/midi/chpn-p7_format0.mid -------------------------------------------------------------------------------- /testcases/midi/sound.mid: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/midi/sound.mid -------------------------------------------------------------------------------- /testcases/mp4/blank.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/mp4/blank.mp4 -------------------------------------------------------------------------------- /testcases/mp4/giphy (10).mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/mp4/giphy (10).mp4 -------------------------------------------------------------------------------- /testcases/mp4/openaigym.video.0.21111.video000113.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/mp4/openaigym.video.0.21111.video000113.mp4 -------------------------------------------------------------------------------- /testcases/mp4/openaigym.video.108.53448.video000000.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/mp4/openaigym.video.108.53448.video000000.mp4 -------------------------------------------------------------------------------- /testcases/mp4/qr.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/mp4/qr.mp4 -------------------------------------------------------------------------------- /testcases/mp4/quick-ui-003.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/mp4/quick-ui-003.mp4 -------------------------------------------------------------------------------- /testcases/mp4/random_animation.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/mp4/random_animation.mp4 -------------------------------------------------------------------------------- /testcases/mp4/small_movie.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/mp4/small_movie.mp4 -------------------------------------------------------------------------------- /testcases/mp4/videotest.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/mp4/videotest.mp4 -------------------------------------------------------------------------------- /testcases/mp4/vk-flash-format-only.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/mp4/vk-flash-format-only.mp4 -------------------------------------------------------------------------------- /testcases/pcap/NTLM-wenchao.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/pcap/NTLM-wenchao.pcap -------------------------------------------------------------------------------- /testcases/pcap/bfd-raw-auth-md5.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/pcap/bfd-raw-auth-md5.pcap -------------------------------------------------------------------------------- /testcases/pcap/bfd-raw-auth-simple.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/pcap/bfd-raw-auth-simple.pcap -------------------------------------------------------------------------------- /testcases/pcap/ipv4frags.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/pcap/ipv4frags.pcap -------------------------------------------------------------------------------- /testcases/pcap/small_capture.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/pcap/small_capture.pcap -------------------------------------------------------------------------------- /testcases/png/basn0g16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/png/basn0g16.png -------------------------------------------------------------------------------- /testcases/png/basn3p01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/png/basn3p01.png -------------------------------------------------------------------------------- /testcases/png/basn3p02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/png/basn3p02.png -------------------------------------------------------------------------------- /testcases/png/basn3p04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/png/basn3p04.png -------------------------------------------------------------------------------- /testcases/png/basn4a16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/png/basn4a16.png -------------------------------------------------------------------------------- /testcases/png/basn6a08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/png/basn6a08.png -------------------------------------------------------------------------------- /testcases/png/basn6a16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/png/basn6a16.png -------------------------------------------------------------------------------- /testcases/png/ftbbn0g02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/png/ftbbn0g02.png -------------------------------------------------------------------------------- /testcases/png/ftbgn2c16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/png/ftbgn2c16.png -------------------------------------------------------------------------------- /testcases/png/ftbrn2c08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/png/ftbrn2c08.png -------------------------------------------------------------------------------- /testcases/png/ftbwn0g16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/png/ftbwn0g16.png -------------------------------------------------------------------------------- /testcases/png/ftbwn3p08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/png/ftbwn3p08.png -------------------------------------------------------------------------------- /testcases/png/ftbyn3p08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/png/ftbyn3p08.png -------------------------------------------------------------------------------- /testcases/png/ftp1n3p08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/png/ftp1n3p08.png -------------------------------------------------------------------------------- /testcases/png/ibasn0g08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/png/ibasn0g08.png -------------------------------------------------------------------------------- /testcases/png/ibasn0g16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/png/ibasn0g16.png -------------------------------------------------------------------------------- /testcases/png/ibasn2c08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/png/ibasn2c08.png -------------------------------------------------------------------------------- /testcases/png/ibasn3p08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/png/ibasn3p08.png -------------------------------------------------------------------------------- /testcases/png/ibasn4a08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/png/ibasn4a08.png -------------------------------------------------------------------------------- /testcases/png/ibasn4a16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/png/ibasn4a16.png -------------------------------------------------------------------------------- /testcases/png/ibasn6a08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/png/ibasn6a08.png -------------------------------------------------------------------------------- /testcases/png/ibasn6a16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/png/ibasn6a16.png -------------------------------------------------------------------------------- /testcases/png/iftbgn2c16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/png/iftbgn2c16.png -------------------------------------------------------------------------------- /testcases/png/iftbwn0g16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/png/iftbwn0g16.png -------------------------------------------------------------------------------- /testcases/png/iftp0n0g08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/png/iftp0n0g08.png -------------------------------------------------------------------------------- /testcases/png/iftp0n2c08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/png/iftp0n2c08.png -------------------------------------------------------------------------------- /testcases/png/iftp0n3p08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/png/iftp0n3p08.png -------------------------------------------------------------------------------- /testcases/png/iftp1n3p08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/png/iftp1n3p08.png -------------------------------------------------------------------------------- /testcases/png/not_kitty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/png/not_kitty.png -------------------------------------------------------------------------------- /testcases/png/not_kitty_alpha.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/png/not_kitty_alpha.png -------------------------------------------------------------------------------- /testcases/png/not_kitty_icc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/png/not_kitty_icc.png -------------------------------------------------------------------------------- /testcases/wav/CreateWithCode_Prototype: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/wav/CreateWithCode_Prototype -------------------------------------------------------------------------------- /testcases/wav/HarvestCapitalism_Assets_Sounds_ButtonSoundCut.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/wav/HarvestCapitalism_Assets_Sounds_ButtonSoundCut.wav -------------------------------------------------------------------------------- /testcases/wav/audio_land_1.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/wav/audio_land_1.wav -------------------------------------------------------------------------------- /testcases/wav/sounds_disconnect.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/wav/sounds_disconnect.wav -------------------------------------------------------------------------------- /testcases/wav/test-44100Hz-2ch-32bit-float-le.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/wav/test-44100Hz-2ch-32bit-float-le.wav -------------------------------------------------------------------------------- /testcases/wav/test-44100Hz-le-1ch-4bytes.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/wav/test-44100Hz-le-1ch-4bytes.wav -------------------------------------------------------------------------------- /testcases/wav/test-8000Hz-le-1ch-10S-20bit-extra.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/wav/test-8000Hz-le-1ch-10S-20bit-extra.wav -------------------------------------------------------------------------------- /testcases/wav/test-8000Hz-le-1ch-1byte-ulaw.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/wav/test-8000Hz-le-1ch-1byte-ulaw.wav -------------------------------------------------------------------------------- /testcases/wav/test-8000Hz-le-2ch-1byteu.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/wav/test-8000Hz-le-2ch-1byteu.wav -------------------------------------------------------------------------------- /testcases/wav/test-8000Hz-le-3ch-5S-24bit.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/wav/test-8000Hz-le-3ch-5S-24bit.wav -------------------------------------------------------------------------------- /testcases/wav/test-8000Hz-le-3ch-5S-64bit.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/wav/test-8000Hz-le-3ch-5S-64bit.wav -------------------------------------------------------------------------------- /testcases/wav/test-8000Hz-le-4ch-9S-12bit.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/wav/test-8000Hz-le-4ch-9S-12bit.wav -------------------------------------------------------------------------------- /testcases/wav/test-8000Hz-le-5ch-9S-5bit.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/wav/test-8000Hz-le-5ch-9S-5bit.wav -------------------------------------------------------------------------------- /testcases/zip/666.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/zip/666.zip -------------------------------------------------------------------------------- /testcases/zip/CS2102_HW_1.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/zip/CS2102_HW_1.zip -------------------------------------------------------------------------------- /testcases/zip/L3_01_My-first-CSS-Document.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/zip/L3_01_My-first-CSS-Document.zip -------------------------------------------------------------------------------- /testcases/zip/Machine 6.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/zip/Machine 6.zip -------------------------------------------------------------------------------- /testcases/zip/Project Settings.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/zip/Project Settings.zip -------------------------------------------------------------------------------- /testcases/zip/VCS_DRS_ZDT_AST.DRS.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/zip/VCS_DRS_ZDT_AST.DRS.zip -------------------------------------------------------------------------------- /testcases/zip/project.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/zip/project.zip -------------------------------------------------------------------------------- /testcases/zip/pse03-w0020.txt.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/zip/pse03-w0020.txt.zip -------------------------------------------------------------------------------- /testcases/zip/small_archive.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/zip/small_archive.zip -------------------------------------------------------------------------------- /testcases/zip/snake.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/zip/snake.zip -------------------------------------------------------------------------------- /testcases/zip/test25.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/zip/test25.zip -------------------------------------------------------------------------------- /testcases/zip/type-search-index.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/zip/type-search-index.zip -------------------------------------------------------------------------------- /testcases/zip/update_test_new_module.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uds-se/FormatFuzzer/337bbbc3b46027964a06e65c0d59e971beb66290/testcases/zip/update_test_new_module.zip -------------------------------------------------------------------------------- /tests/test_bitwrap.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | 4 | import os 5 | import six 6 | import struct 7 | import sys 8 | import unittest 9 | 10 | sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) 11 | 12 | import pfp 13 | import pfp.errors 14 | from pfp.fields import * 15 | import pfp.utils 16 | from pfp.bitwrap import BitwrappedStream 17 | 18 | import utils 19 | 20 | 21 | class TestBitwrap(unittest.TestCase): 22 | def setUp(self): 23 | pass 24 | 25 | def tearDown(self): 26 | pass 27 | 28 | def test_bytes_read(self): 29 | stream = six.BytesIO(pfp.utils.binary("abcd")) 30 | bitwrapped = BitwrappedStream(stream) 31 | res = bitwrapped.read(4) 32 | self.assertEqual(pfp.utils.binary("abcd"), res) 33 | 34 | def test_bits_read1(self): 35 | stream = six.BytesIO(pfp.utils.binary(chr(int("01010101", 2)))) 36 | bitwrapped = BitwrappedStream(stream) 37 | res = bitwrapped.read_bits(8) 38 | self.assertEqual([0, 1, 0, 1, 0, 1, 0, 1], res) 39 | 40 | def test_bits_read2_padded1(self): 41 | stream = six.BytesIO( 42 | pfp.utils.binary(chr(int("11110000", 2)) + chr(int("10101010", 2))) 43 | ) 44 | bitwrapped = BitwrappedStream(stream) 45 | bitwrapped.padded = True 46 | 47 | res = bitwrapped.read_bits(4) 48 | self.assertEqual([1, 1, 1, 1], res) 49 | 50 | res = bitwrapped.read_bits(3) 51 | self.assertEqual([0, 0, 0], res) 52 | 53 | res = bitwrapped.read_bits(4) 54 | self.assertEqual([0, 1, 0, 1], res) 55 | 56 | res = bitwrapped.read_bits(5) 57 | self.assertEqual([0, 1, 0, 1, 0], res) 58 | 59 | def test_bits_read2_padded2(self): 60 | stream = six.BytesIO( 61 | pfp.utils.binary(chr(int("11110000", 2)) + chr(int("10101010", 2))) 62 | ) 63 | bitwrapped = BitwrappedStream(stream) 64 | bitwrapped.padded = True 65 | 66 | res = bitwrapped.read_bits(4) 67 | self.assertEqual([1, 1, 1, 1], res) 68 | 69 | next_byte = bitwrapped.read(1) 70 | self.assertEqual(pfp.utils.binary(chr(int("10101010", 2))), next_byte) 71 | 72 | def test_bits_read_unpadded(self): 73 | stream = six.BytesIO( 74 | pfp.utils.binary(chr(int("11110000", 2)) + chr(int("10101010", 2))) 75 | ) 76 | bitwrapped = BitwrappedStream(stream) 77 | bitwrapped.padded = False 78 | 79 | res = bitwrapped.read_bits(4) 80 | self.assertEqual([1, 1, 1, 1], res) 81 | 82 | res = bitwrapped.read(1) 83 | self.assertEqual(pfp.utils.binary(chr(int("00001010", 2))), res) 84 | 85 | res = bitwrapped.read_bits(4) 86 | self.assertEqual([1, 0, 1, 0], res) 87 | 88 | def test_bits_read_unpadded(self): 89 | stream = six.BytesIO( 90 | pfp.utils.binary(chr(int("11110000", 2)) + chr(int("10101010", 2))) 91 | ) 92 | bitwrapped = BitwrappedStream(stream) 93 | bitwrapped.padded = False 94 | 95 | res = bitwrapped.read_bits(4) 96 | self.assertEqual([1, 1, 1, 1], res) 97 | 98 | res = bitwrapped.read(1) 99 | self.assertEqual(pfp.utils.binary(chr(int("00001010", 2))), res) 100 | 101 | res = bitwrapped.read_bits(4) 102 | self.assertEqual([1, 0, 1, 0], res) 103 | 104 | def test_bits_write_padded(self): 105 | stream = six.BytesIO() 106 | bitwrapped = BitwrappedStream(stream) 107 | bitwrapped.padded = True 108 | 109 | bitwrapped.write_bits([1, 1, 0, 1]) 110 | # should go to a new byte now, zero padded after the 111 | # 1101 bits 112 | bitwrapped.write(pfp.utils.binary("hello")) 113 | 114 | self.assertEqual( 115 | stream.getvalue(), 116 | pfp.utils.binary(chr(int("11010000", 2)) + "hello"), 117 | ) 118 | 119 | def test_unconsumed_ranges1(self): 120 | stream = six.BytesIO(pfp.utils.binary("A" * 100)) 121 | bitwrapped = BitwrappedStream(stream) 122 | 123 | bitwrapped.read(10) 124 | bitwrapped.seek(bitwrapped.tell() + 10) 125 | bitwrapped.read(10) 126 | bitwrapped.seek(bitwrapped.tell() + 10) 127 | bitwrapped.read(10) 128 | 129 | uranges = bitwrapped.unconsumed_ranges() 130 | 131 | # test (11,20] 132 | self.assertEqual(len(uranges[11]), 1) 133 | self.assertEqual(len(uranges[10]), 0) 134 | self.assertEqual(len(uranges[19]), 1) 135 | self.assertEqual(len(uranges[20]), 0) 136 | 137 | # test (31,40] 138 | self.assertEqual(len(uranges[31]), 1) 139 | self.assertEqual(len(uranges[30]), 0) 140 | self.assertEqual(len(uranges[39]), 1) 141 | self.assertEqual(len(uranges[40]), 0) 142 | 143 | def test_unconsumed_ranges2(self): 144 | stream = six.BytesIO(pfp.utils.binary("A" * 100)) 145 | bitwrapped = BitwrappedStream(stream) 146 | 147 | bitwrapped.read(10) 148 | bitwrapped.seek(bitwrapped.tell() + 10) 149 | 150 | # it should not need a second read to add the 151 | # unconsumed range 152 | uranges = bitwrapped.unconsumed_ranges() 153 | 154 | self.assertEqual(len(uranges), 1) 155 | 156 | # test (11,20] 157 | self.assertEqual(len(uranges[11]), 1) 158 | self.assertEqual(len(uranges[10]), 0) 159 | self.assertEqual(len(uranges[19]), 1) 160 | self.assertEqual(len(uranges[20]), 0) 161 | 162 | def test_unconsumed_ranges3(self): 163 | stream = six.BytesIO(pfp.utils.binary("A" * 100)) 164 | bitwrapped = BitwrappedStream(stream) 165 | 166 | bitwrapped.read(10) 167 | 168 | # it should not need a second read to add the 169 | # unconsumed range 170 | uranges = bitwrapped.unconsumed_ranges() 171 | 172 | self.assertEqual(len(uranges), 0) 173 | 174 | def test_tell_bits(self): 175 | stream = six.BytesIO(pfp.utils.binary("\x41" + chr(0b11001100))) 176 | bitwrapped = BitwrappedStream(stream) 177 | 178 | res = bitwrapped.read(1) 179 | self.assertEqual(res, b"\x41") 180 | 181 | self.assertEqual(bitwrapped.tell(), 1) 182 | self.assertEqual(bitwrapped.tell_bits(), 0) 183 | 184 | bits = bitwrapped.read_bits(1) 185 | self.assertEqual(bits, [1]) 186 | self.assertEqual(bitwrapped.tell_bits(), 1) 187 | 188 | bits = bitwrapped.read_bits(1) 189 | self.assertEqual(bits, [1]) 190 | self.assertEqual(bitwrapped.tell_bits(), 2) 191 | 192 | bits = bitwrapped.read_bits(1) 193 | self.assertEqual(bits, [0]) 194 | self.assertEqual(bitwrapped.tell_bits(), 3) 195 | 196 | 197 | if __name__ == "__main__": 198 | unittest.main() 199 | -------------------------------------------------------------------------------- /tests/test_cast.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | 4 | import os 5 | import struct 6 | import sys 7 | import unittest 8 | 9 | sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) 10 | 11 | import pfp 12 | import pfp.errors 13 | from pfp.fields import * 14 | import pfp.utils 15 | 16 | import utils 17 | 18 | 19 | class TestArrays(utils.PfpTestCase): 20 | def setUp(self): 21 | pfp.fields.NumberBase.endian = pfp.fields.BIG_ENDIAN 22 | 23 | def tearDown(self): 24 | pass 25 | 26 | def test_cast_basic(self): 27 | dom = self._test_parse_build( 28 | "", 29 | """ 30 | local int a = 0x61; 31 | local uchar b = (char)a; 32 | Printf(b); 33 | """, 34 | stdout="a", 35 | ) 36 | 37 | def test_cast_from_dex(self): 38 | dom = self._test_parse_build( 39 | "", 40 | """ 41 | local ubyte cur = 7; 42 | local uint test1 = (uint)(10); 43 | local uint test2 = (uint)((cur & 0x7f) << 7); 44 | Printf("%u,%u", test1, test2); 45 | """, 46 | stdout="10,896", 47 | ) 48 | 49 | 50 | if __name__ == "__main__": 51 | unittest.main() 52 | -------------------------------------------------------------------------------- /tests/test_changeset.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | 4 | import pfp 5 | from pfp.utils import binary 6 | from pfp.fuzz import Changer 7 | 8 | 9 | def test_changeset(): 10 | template = """ 11 | struct { 12 | ushort a; 13 | ushort b; 14 | ushort c; 15 | ushort d; 16 | uint e; 17 | } data; 18 | """ 19 | data = "aabbccddeeee" 20 | dom = pfp.parse(template=template, data=data) 21 | orig_data = dom._pfp__build() 22 | assert orig_data == binary(data) 23 | 24 | dom.data.a = 0x4141 25 | dom.data.b = 0x4242 26 | dom.data.c = 0x4343 27 | dom.data.d = 0x4444 28 | dom.data.e = 0x45454545 29 | 30 | changer = Changer(orig_data) 31 | changer.push_changes([dom.data.a]) 32 | assert changer.build() == bytearray(b"AAbbccddeeee") 33 | changer.pop_changes() 34 | assert changer.build() == bytearray(binary(data)) 35 | 36 | changer.push_changes([dom.data.a, dom.data.d]) 37 | assert changer.build() == bytearray(b"AAbbccDDeeee") 38 | changer.push_changes([dom.data.b, dom.data.c]) 39 | assert changer.build() == bytearray(b"AABBCCDDeeee") 40 | changer.push_changes([dom.data.e]) 41 | assert changer.build() == bytearray(b"AABBCCDDEEEE") 42 | 43 | changer.pop_changes() 44 | assert changer.build() == bytearray(b"AABBCCDDeeee") 45 | changer.pop_changes() 46 | assert changer.build() == bytearray(b"AAbbccDDeeee") 47 | changer.pop_changes() 48 | assert changer.build() == bytearray(binary(data)) 49 | 50 | 51 | def test_changeset_with_bitfields(): 52 | template = """ 53 | BigEndian(); 54 | struct { 55 | char a:2; // 11 56 | char b:2; // 00 57 | char c:3; // 111 58 | char d:1; // 0 59 | uint e; 60 | } data; 61 | """ 62 | # 0xc3 = 0b11001110 63 | data = "\xceeeee" 64 | dom = pfp.parse(template=template, data=data) 65 | orig_data = dom._pfp__build() 66 | assert orig_data == binary(data) 67 | 68 | dom.data.a = 0 69 | 70 | changer = Changer(orig_data) 71 | 72 | with changer.change([dom.data.a]) as changed: 73 | assert changed == binary("\x0eeeee") # 0x0e = 0b00001110 74 | assert changer.build() == binary(data) 75 | 76 | dom._pfp__snapshot() 77 | dom.data.a = 0 78 | dom.data.d = 1 79 | with changer.change([dom.data.a, dom.data.d]) as changed: 80 | assert changed == binary("\x0feeee") # 0x0f = 0b00001111 81 | 82 | dom._pfp__snapshot() 83 | dom.data.b = 3 84 | dom.data.c = 0 85 | with changer.change([dom.data.b, dom.data.c]) as changed: 86 | assert changed == binary("\x31eeee") # 0x31 = 0b00110001 87 | 88 | dom._pfp__snapshot() 89 | dom.data.e = 0x45454545 90 | with changer.change([dom.data.e]) as changed: 91 | assert changed == binary("\x31EEEE") # 0x31 = 0b00110001 92 | 93 | dom._pfp__restore_snapshot() 94 | assert changer.build() == binary("\x31eeee") # 0x31 = 0b00110001 95 | 96 | dom._pfp__restore_snapshot() 97 | assert changer.build() == binary("\x0feeee") # 0x0f = 0b00001111 98 | 99 | dom._pfp__restore_snapshot() 100 | assert changer.build() == binary(data) 101 | -------------------------------------------------------------------------------- /tests/test_compat_checksums.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | 4 | import unittest 5 | import os 6 | import sys 7 | import utils 8 | 9 | sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) 10 | 11 | 12 | class TestCompat(utils.PfpTestCase): 13 | def setUp(self): 14 | pass 15 | 16 | def tearDown(self): 17 | pass 18 | 19 | def test_adler32(self): 20 | dom = self._test_parse_build( 21 | "test\x00", 22 | """ 23 | string test; 24 | Printf("%X", Checksum(CHECKSUM_ADLER32, 0, 1, -1, -1)); 25 | """, 26 | stdout="750075", 27 | # Required for CHECKSUM_ADLER32 to be found 28 | predefines=True, 29 | ) 30 | -------------------------------------------------------------------------------- /tests/test_compat_strings.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | 4 | import os 5 | import six 6 | import sys 7 | import unittest 8 | 9 | sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) 10 | 11 | import pfp 12 | import pfp.fields 13 | import pfp.interp 14 | import pfp.utils 15 | 16 | import utils 17 | 18 | 19 | class TestCompatStrings(utils.PfpTestCase): 20 | def setUp(self): 21 | pfp.fields.NumberBase.endian = pfp.fields.BIG_ENDIAN 22 | 23 | def tearDown(self): 24 | pass 25 | 26 | def test_strlen(self): 27 | dom = self._test_parse_build( 28 | "", 29 | """ 30 | Printf("%d.%d.%d", Strlen("HELLO"), Strlen("abcd"), Strlen("abc")); 31 | """, 32 | stdout="5.4.3", 33 | ) 34 | 35 | def test_substr(self): 36 | dom = self._test_parse_build( 37 | "", 38 | """ 39 | Printf("%s\\n", SubStr("Hello there", 0, 5)); 40 | 41 | string local someString = "abcdefg"; 42 | Printf("%s", SubStr(someString, 3)); 43 | """, 44 | stdout="Hello\ndefg", 45 | ) 46 | 47 | 48 | if __name__ == "__main__": 49 | unittest.main() 50 | -------------------------------------------------------------------------------- /tests/test_dbg.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | 4 | import os 5 | import sys 6 | import unittest 7 | 8 | try: 9 | from StringIO import StringIO 10 | 11 | # StringIO does not exist in python3 12 | except ImportError as e: 13 | from io import StringIO 14 | 15 | sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) 16 | 17 | import pfp 18 | import pfp.dbg 19 | 20 | import utils 21 | 22 | 23 | class TestDebug(utils.PfpTestCase): 24 | def setUp(self): 25 | pass 26 | 27 | def tearDown(self): 28 | pass 29 | 30 | def test_debug_prompt(self): 31 | return 32 | dom = pfp.parse( 33 | StringIO("aaaabbbbcccchello there\x00\x05abcdf"), 34 | """ 35 | Int3(); 36 | int a; 37 | int b; 38 | int c; 39 | string greeting; 40 | unsigned char length; 41 | char str[length]; 42 | """, 43 | ) 44 | 45 | 46 | if __name__ == "__main__": 47 | unittest.main() 48 | -------------------------------------------------------------------------------- /tests/test_enums.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | 4 | import os 5 | import struct 6 | import sys 7 | import unittest 8 | 9 | sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) 10 | 11 | import pfp 12 | import pfp.errors 13 | from pfp.fields import * 14 | import pfp.utils 15 | 16 | import utils 17 | 18 | 19 | class TestEnums(utils.PfpTestCase): 20 | def setUp(self): 21 | pfp.fields.NumberBase.endian = pfp.fields.BIG_ENDIAN 22 | 23 | def tearDown(self): 24 | pass 25 | 26 | def test_basic_enum(self): 27 | dom = self._test_parse_build( 28 | "\x00\x00\x00\x01", 29 | """ 30 | BigEndian(); 31 | enum TEST_ENUM { 32 | BLAH1, 33 | BLAH2, 34 | BLAH3, 35 | BLAH4, 36 | BLAH5, 37 | BLAH6 38 | } var1; 39 | """, 40 | ) 41 | self.assertEqual(dom.var1.enum_cls, Int) 42 | self.assertEqual(dom.var1.enum_name, "BLAH2") 43 | 44 | def test_basic_enum2(self): 45 | dom = self._test_parse_build( 46 | "\x01", 47 | """ 48 | enum TEST_ENUM { 49 | BLAH1, 50 | BLAH2, 51 | BLAH3, 52 | BLAH4, 53 | BLAH5, 54 | BLAH6 55 | } var1; 56 | 57 | local uchar blah = BLAH4; 58 | Printf("%d", blah); 59 | """, 60 | stdout="3", 61 | ) 62 | self.assertEqual(dom.var1.enum_cls, UChar) 63 | self.assertEqual(dom.var1.enum_name, "BLAH2") 64 | 65 | def test_basic_enum_unnamed(self): 66 | dom = self._test_parse_build( 67 | "\x01", 68 | """ 69 | enum { 70 | BLAH1, 71 | BLAH2, 72 | BLAH3, 73 | BLAH4, 74 | BLAH5, 75 | BLAH6 76 | } var1; 77 | """, 78 | ) 79 | self.assertEqual(dom.var1.enum_cls, UChar) 80 | self.assertEqual(dom.var1.enum_name, "BLAH2") 81 | 82 | def test_basic_enum_typedef(self): 83 | dom = self._test_parse_build( 84 | "\x01", 85 | """ 86 | typedef enum blahs { 87 | BLAH1, 88 | BLAH2, 89 | BLAH3, 90 | BLAH4, 91 | BLAH5, 92 | BLAH6 93 | } ENUM_TYPE; 94 | 95 | ENUM_TYPE hello; 96 | """, 97 | ) 98 | self.assertEqual(dom.hello.enum_cls, UChar) 99 | self.assertEqual(dom.hello.enum_name, "BLAH2") 100 | self.assertEqual(dom.hello, 1) 101 | 102 | def test_basic_enum_types(self): 103 | dom = self._test_parse_build( 104 | "", 105 | """ 106 | enum blahs { 107 | BLAH1, 108 | BLAH2, 109 | BLAH3, 110 | BLAH4, 111 | BLAH5, 112 | BLAH6 113 | }; 114 | 115 | local uchar blah = BLAH6; 116 | Printf("%d", blah); 117 | """, 118 | stdout="5", 119 | ) 120 | 121 | def test_enum_name_as_type(self): 122 | dom = self._test_parse_build( 123 | "\x01", 124 | """ 125 | enum BLAHS { 126 | BLAH1, 127 | BLAH2, 128 | BLAH3 129 | }; 130 | BLAHS test; 131 | """, 132 | ) 133 | self.assertEqual(dom.test, 1) 134 | self.assertEqual(dom.test.enum_name, "BLAH2") 135 | 136 | def test_enum_word_type(self): 137 | dom = self._test_parse_build( 138 | "", 139 | """ 140 | enum tagID { 141 | M_TAG0, // should be 0 142 | M_TAG1 = 0xff01, 143 | M_TAG2, 144 | M_TAG3, 145 | }; 146 | """, 147 | ) 148 | self.assertEqual(dom.M_TAG0, 0) 149 | self.assertEqual(dom.M_TAG1, 0xff01) 150 | self.assertEqual(dom.M_TAG2, 0xff02) 151 | self.assertEqual(dom.M_TAG3, 0xff03) 152 | 153 | self.assertTrue(isinstance(dom.M_TAG0, UShort)) 154 | self.assertTrue(isinstance(dom.M_TAG1, UShort)) 155 | self.assertTrue(isinstance(dom.M_TAG2, UShort)) 156 | self.assertTrue(isinstance(dom.M_TAG3, UShort)) 157 | 158 | def test_enum_with_bitfield(self): 159 | dom = self._test_parse_build( 160 | "\x31", 161 | """ 162 | BigEndian(); 163 | enum BLAHS { 164 | BLAH1, 165 | BLAH2, 166 | BLAH3, 167 | BLAH4 168 | }; 169 | 170 | BLAHS test1: 4; 171 | BLAHS test2: 4; 172 | """, 173 | ) 174 | self.assertEqual(dom.test1, 3) 175 | self.assertEqual(dom.test1.enum_name, "BLAH4") 176 | self.assertEqual(dom.test2, 1) 177 | self.assertEqual(dom.test2.enum_name, "BLAH2") 178 | 179 | def test_enum_with_bitfield_typedef(self): 180 | dom = self._test_parse_build( 181 | "\x31", 182 | """ 183 | typedef enum blahs { 184 | BLAH1, 185 | BLAH2, 186 | BLAH3, 187 | BLAH4 188 | } BLAHS; 189 | 190 | BLAHS test1: 4; 191 | BLAHS test2: 4; 192 | """, 193 | ) 194 | self.assertEqual(dom.test1, 3) 195 | self.assertEqual(dom.test1.enum_name, "BLAH4") 196 | self.assertEqual(dom.test2, 1) 197 | self.assertEqual(dom.test2.enum_name, "BLAH2") 198 | 199 | def test_enum_with_bitfield_inline(self): 200 | dom = self._test_parse_build( 201 | "\x31", 202 | """ 203 | BigEndian(); 204 | enum { 205 | BLAH1, 206 | BLAH2, 207 | BLAH3, 208 | BLAH4 209 | } test1: 4; 210 | 211 | enum { 212 | BLAH1, 213 | BLAH2, 214 | BLAH3, 215 | BLAH4 216 | } test2: 4; 217 | """, 218 | ) 219 | self.assertEqual(dom.test1, 3) 220 | self.assertEqual(dom.test1.enum_name, "BLAH4") 221 | self.assertEqual(dom.test2, 1) 222 | self.assertEqual(dom.test2.enum_name, "BLAH2") 223 | 224 | def test_enum_compared_to_enum(self): 225 | dom = self._test_parse_build( 226 | "\x00\x00\x00\x01", 227 | """ 228 | BigEndian(); 229 | enum TEST_ENUM { 230 | BLAH1, 231 | }; 232 | 233 | do { 234 | TEST_ENUM test = BLAH1; 235 | } while (test == BLAH1); 236 | """, 237 | ) 238 | self.assertEqual(len(dom.test), 4) 239 | 240 | 241 | if __name__ == "__main__": 242 | unittest.main() 243 | -------------------------------------------------------------------------------- /tests/test_fields.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | 4 | import os 5 | 6 | try: 7 | from StringIO import StringIO 8 | # StringIO does not exist in python3 9 | except ImportError as e: 10 | from io import StringIO 11 | import struct 12 | import sys 13 | import unittest 14 | 15 | sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) 16 | 17 | import pfp 18 | import pfp.errors 19 | from pfp.fields import * 20 | import pfp.utils 21 | 22 | import utils 23 | 24 | 25 | class TestNumericFields(utils.PfpTestCase): 26 | def setUp(self): 27 | pass 28 | 29 | def tearDown(self): 30 | pass 31 | 32 | def _do_parse(self, field, data): 33 | field._pfp__parse(StringIO(data.decode("ISO-8859-1"))) 34 | 35 | def _do_endian_tests(self, field, format): 36 | field.endian = pfp.fields.BIG_ENDIAN 37 | self._do_parse(field, struct.pack(">" + format, 1)) 38 | self.assertEqual(field, 1) 39 | 40 | field.endian = pfp.fields.LITTLE_ENDIAN 41 | self._do_parse(field, struct.pack("<" + format, 1)) 42 | self.assertEqual(field, 1) 43 | 44 | def test_char(self): 45 | field = Char() 46 | self._do_endian_tests(field, "b") 47 | 48 | def test_uchar(self): 49 | field = UChar() 50 | self._do_endian_tests(field, "b") 51 | 52 | def test_short(self): 53 | field = Short() 54 | self._do_endian_tests(field, "h") 55 | 56 | def test_ushort(self): 57 | field = UShort() 58 | self._do_endian_tests(field, "H") 59 | 60 | def test_int(self): 61 | field = Int() 62 | self._do_endian_tests(field, "i") 63 | 64 | def test_uint(self): 65 | field = UInt() 66 | self._do_endian_tests(field, "I") 67 | 68 | def test_int64(self): 69 | field = Int64() 70 | self._do_endian_tests(field, "q") 71 | 72 | def test_int64(self): 73 | field = UInt64() 74 | self._do_endian_tests(field, "Q") 75 | 76 | def test_const_int64(self): 77 | dom = self._test_parse_build( 78 | "", 79 | """ 80 | const uint64 PNGMAGIC = 0x89504E470D0A1A0AL; 81 | Printf("%d", PNGMAGIC); 82 | """, 83 | stdout="9894494448401390090", 84 | ) 85 | 86 | 87 | if __name__ == "__main__": 88 | unittest.main() 89 | -------------------------------------------------------------------------------- /tests/test_functions.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | 4 | import os 5 | 6 | try: 7 | from StringIO import StringIO 8 | 9 | # StringIO does not exist in python3 10 | except ImportError as e: 11 | from io import StringIO 12 | import sys 13 | import unittest 14 | 15 | sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) 16 | 17 | import pfp 18 | import pfp.fields 19 | import pfp.interp 20 | import pfp.utils 21 | 22 | import utils 23 | 24 | 25 | class TestFunctions(utils.PfpTestCase): 26 | def setUp(self): 27 | pfp.fields.NumberBase.endian = pfp.fields.LITTLE_ENDIAN 28 | 29 | def tearDown(self): 30 | pass 31 | 32 | def test_function(self): 33 | dom = self._test_parse_build( 34 | "", 35 | """ 36 | void func(int a, int b) { 37 | local int c = a + b; 38 | } 39 | 40 | func(10, 20); 41 | """, 42 | ) 43 | 44 | def test_declaration_order(self): 45 | dom = self._test_parse_build( 46 | "", 47 | # this has been tested in 010 to work 48 | """ 49 | hello(); 50 | void hello() { 51 | Printf("Hello World"); 52 | } 53 | """, 54 | stdout="Hello World", 55 | ) 56 | 57 | def test_declaration_order2(self): 58 | dom = self._test_parse_build( 59 | "", 60 | # this has been tested in 010 to work 61 | r""" 62 | hello(10); 63 | typedef unsigned short custom_ushort; 64 | void hello(custom_ushort test) { 65 | Printf("Hello World %d", test); 66 | } 67 | """, 68 | stdout="Hello World 10", 69 | ) 70 | 71 | def test_builtin(self): 72 | dom = self._test_parse_build( 73 | "", 74 | """ 75 | Printf("hello there"); 76 | Printf("%d", 10); 77 | """, 78 | stdout="hello there10", 79 | ) 80 | 81 | def test_custom_func(self): 82 | dom = self._test_parse_build( 83 | "", 84 | """ 85 | int add(int n1, int n2) { 86 | return n1 + n2; 87 | } 88 | 89 | Printf("%d", add(5, 8)); 90 | """, 91 | stdout="13", 92 | ) 93 | 94 | def test_custom_func2(self): 95 | dom = self._test_parse_build( 96 | "", 97 | """ 98 | string prepend(string orig) { 99 | return "blah: " + orig; 100 | } 101 | 102 | Printf(prepend("hello")); 103 | """, 104 | stdout="blah: hello", 105 | ) 106 | 107 | def test_native_func(self): 108 | func_called = False 109 | 110 | def func(params, ctxt, scope, stream, coord): 111 | func_called = True 112 | return 555 113 | 114 | interp = pfp.interp.PfpInterp() 115 | interp.add_native(name="func", func=func, ret=pfp.fields.Int) 116 | 117 | dom = self._test_parse_build( 118 | "", 119 | """ 120 | Printf("%d", func()); 121 | """, 122 | stdout="555", 123 | ) 124 | 125 | def test_lazy_type_checking(self): 126 | dom = self._test_parse_build( 127 | "\x0a", 128 | """ 129 | void lazy_type_checking_function(LazyType &blah) { 130 | Printf("blah.var1 = %d", blah.var1); 131 | } 132 | 133 | typedef struct LazyType { 134 | uchar var1; 135 | } LAZY_TYPE_TYPE; 136 | 137 | LAZY_TYPE_TYPE a; 138 | lazy_type_checking_function(a); 139 | """, 140 | stdout="blah.var1 = 10", 141 | ) 142 | 143 | def test_function_string_return(self): 144 | dom = self._test_parse_build( 145 | "abcd\x00", 146 | """ 147 | string ReadStringN(int64 pos, int n) { 148 | local uchar s[n]; 149 | ReadBytes(s, pos, n); 150 | return s; 151 | } 152 | if(ReadStringN(FTell(), 5) == "abcd") { 153 | Printf("true"); 154 | } else { 155 | Printf("false"); 156 | } 157 | """, 158 | stdout="true", 159 | ) 160 | 161 | # see https://github.com/d0c-s4vage/pfp/issues/27 - thanks @vit9696! 162 | def test_void_return(self): 163 | dom = self._test_parse_build( 164 | "", 165 | r""" 166 | void func() { 167 | #ifndef DEBUG 168 | return; 169 | #endif 170 | Printf("Hello\n"); 171 | } 172 | func(); 173 | """, 174 | ) 175 | 176 | def test_array_as_param(self): 177 | dom = self._test_parse_build( 178 | "".join( 179 | [ 180 | "\x00\x00\x00\x01", 181 | "\x00\x00\x00\x02", 182 | "\x00\x00\x00\x03", 183 | "\x00\x00\x00\x04", 184 | "\x00\x00\x00\x05", 185 | ] 186 | ), 187 | r""" 188 | LittleEndian(); 189 | int me[5]; 190 | void passMe(int value[]) { 191 | Printf("%08x", value[0]); 192 | } 193 | passMe(me); 194 | """, 195 | stdout="01000000", 196 | ) 197 | 198 | 199 | if __name__ == "__main__": 200 | unittest.main() 201 | -------------------------------------------------------------------------------- /tests/test_fuzz.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | 4 | 5 | """ 6 | This module tests pfp.fuzz functionality 7 | """ 8 | 9 | 10 | import os 11 | import six 12 | import sys 13 | import unittest 14 | 15 | 16 | sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) 17 | 18 | 19 | import pfp 20 | import pfp.fields 21 | import pfp.fuzz 22 | import pfp.interp 23 | import pfp.utils 24 | 25 | import utils 26 | 27 | 28 | class TestPfpFuzz(unittest.TestCase): 29 | """Test PfpFuzz functionality 30 | """ 31 | 32 | def setUp(self): 33 | super(TestPfpFuzz, self).setUp() 34 | 35 | def tearDown(self): 36 | super(TestPfpFuzz, self).tearDown() 37 | 38 | # see #49 - make mutate return the changed fields 39 | def test_fuzz_yield_fields(self): 40 | template = """ 41 | struct { 42 | struct { 43 | char a; 44 | char b; 45 | } nested; 46 | char c; 47 | } root; 48 | """ 49 | data = "abc" 50 | dom = pfp.parse(template=template, data=data) 51 | pfp.fuzz.rand.seed(1) 52 | 53 | #for at_once in [1, 2, 3]: 54 | for at_once in [2]: 55 | for mutated, changed_fields in pfp.fuzz.mutate( 56 | dom, "basic", num=100, at_once=at_once, yield_changed=True 57 | ): 58 | self.assertEqual(len(changed_fields), at_once) 59 | 60 | # see #49 - make mutate return the changed fields 61 | def test_fuzz_yield_fields_no_yield(self): 62 | template = """ 63 | struct { 64 | struct { 65 | char a; 66 | char b; 67 | } nested; 68 | char c; 69 | } root; 70 | """ 71 | data = "abc" 72 | dom = pfp.parse(template=template, data=data) 73 | 74 | for at_once in [0, 1, 2]: 75 | for mutated in pfp.fuzz.mutate( 76 | dom, "basic", num=100, at_once=at_once, yield_changed=False 77 | ): 78 | # make sure it does not return a tuple, as would be the case with 79 | # yield_changed = True 80 | self.assertFalse(isinstance(mutated, tuple)) 81 | 82 | 83 | if __name__ == "__main__": 84 | unittest.main() 85 | -------------------------------------------------------------------------------- /tests/test_metadata.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | 4 | import binascii 5 | import os 6 | import struct 7 | import sys 8 | import unittest 9 | 10 | sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) 11 | 12 | import pfp 13 | import pfp.errors 14 | from pfp.fields import * 15 | import pfp.utils 16 | 17 | import utils 18 | 19 | 20 | class TestMetadata(utils.PfpTestCase): 21 | def setUp(self): 22 | pfp.fields.NumberBase.endian = pfp.fields.BIG_ENDIAN 23 | 24 | def tearDown(self): 25 | pass 26 | 27 | # < format=hex|decimal|octal|binary, 28 | # fgcolor=, 29 | # bgcolor=, 30 | # comment=""|, 31 | # name=""|, 32 | # open=true|false|suppress, 33 | # hidden=true|false, 34 | # read=, 35 | # write= 36 | # size=| > 37 | def test_metadata_watch_interpd(self): 38 | dom = self._test_parse_build( 39 | "\x05\x07", 40 | """ 41 | void PlusTwo(int &to_update, int watched) { 42 | to_update = watched + 2; 43 | } 44 | 45 | uchar hello; 46 | uchar blah; 47 | """, 48 | ) 49 | self.assertEqual(dom.hello, 5) 50 | self.assertEqual(dom.blah, 7) 51 | 52 | dom.hello = 20 53 | 54 | self.assertEqual(dom.hello, 20) 55 | self.assertEqual(dom.blah, 22) 56 | 57 | def test_metadata_watch_native(self): 58 | def plus_two(params, ctxt, scope, stream, coord): 59 | params[0]._pfp__set_value(params[1] + 2) 60 | 61 | interp = pfp.interp.PfpInterp() 62 | interp.add_native(name="PlusTwo", func=plus_two, ret=pfp.fields.Void) 63 | 64 | dom = self._test_parse_build( 65 | "\x05\x07", 66 | """ 67 | uchar hello; 68 | uchar blah; 69 | """, 70 | ) 71 | self.assertEqual(dom.hello, 5) 72 | self.assertEqual(dom.blah, 7) 73 | 74 | dom.hello = 20 75 | 76 | self.assertEqual(dom.hello, 20) 77 | self.assertEqual(dom.blah, 22) 78 | 79 | def test_metadata_watch_struct(self): 80 | dom = self._test_parse_build( 81 | "\x02\x03\xff\x05", 82 | """ 83 | void TwoFieldsPlusTwo(char &to_update, some_type &watched) { 84 | to_update = watched.a + watched.b; 85 | } 86 | 87 | typedef struct { 88 | uchar a; 89 | uchar b; 90 | uchar c; 91 | } some_type; 92 | some_type a_struct; 93 | 94 | char sum_a_b; 95 | """, 96 | ) 97 | self.assertEqual(dom.a_struct.a, 2) 98 | self.assertEqual(dom.a_struct.b, 3) 99 | self.assertEqual(dom.a_struct.c, 0xFF) 100 | self.assertEqual(dom.sum_a_b, 5) 101 | 102 | dom.a_struct.a = 10 103 | 104 | self.assertEqual(dom.a_struct.a, 10) 105 | self.assertEqual(dom.a_struct.b, 3) 106 | self.assertEqual(dom.a_struct.c, 0xFF) 107 | self.assertEqual(dom.sum_a_b, 13) 108 | 109 | def test_metadata_watch_this(self): 110 | dom = self._test_parse_build( 111 | "\x05\x06\x0b", 112 | """ 113 | void PlusTwo(char &to_update, void &watched) { 114 | to_update = watched.a + watched.b; 115 | } 116 | 117 | struct { 118 | char a; 119 | char b; 120 | char c; 121 | } main_struct; 122 | """, 123 | ) 124 | self.assertEqual(dom.main_struct.a, 5) 125 | self.assertEqual(dom.main_struct.b, 6) 126 | self.assertEqual(dom.main_struct.c, 11) 127 | 128 | dom.main_struct.b = 50 129 | 130 | self.assertEqual(dom.main_struct.a, 5) 131 | self.assertEqual(dom.main_struct.b, 50) 132 | self.assertEqual(dom.main_struct.c, 55) 133 | 134 | def test_metadata_complex(self): 135 | def crc32(params, ctxt, scope, stream, coord): 136 | data = pfp.utils.binary("").join( 137 | [x._pfp__build() for x in params[1:]] 138 | ) 139 | val = binascii.crc32(data) 140 | params[0]._pfp__set_value(val) 141 | 142 | interp = pfp.interp.PfpInterp() 143 | interp.add_native(name="Crc32", func=crc32, ret=pfp.fields.Void) 144 | 145 | dom = self._test_parse_build( 146 | "TYPA\x41\x410000TYPB\x42\x420000", 147 | """ 148 | BigEndian(); 149 | typedef struct { 150 | uchar a; 151 | uchar b; 152 | } TYPE_A; 153 | 154 | typedef struct { 155 | ushort hello; 156 | } TYPE_B; 157 | 158 | while(!FEof()) { 159 | struct { 160 | uchar cname[4]; 161 | 162 | union { 163 | if(cname == "TYPA") { 164 | TYPE_A type_a; 165 | uchar raw[sizeof(type_a)]; 166 | } else if(cname == "TYPB") { 167 | TYPE_B type_b; 168 | uchar raw[sizeof(type_b)]; 169 | } 170 | } data; 171 | uint crc; 172 | } chunks; 173 | } 174 | """, 175 | ) 176 | self.assertEqual(len(dom.chunks), 2) 177 | self.assertEqual(dom.chunks[0].data.raw, "AA") 178 | self.assertEqual(dom.chunks[0].data.type_a.a, ord("A")) 179 | self.assertEqual(dom.chunks[0].data.type_a.b, ord("A")) 180 | self.assertEqual(dom.chunks[1].data.raw, "BB") 181 | self.assertEqual(dom.chunks[1].data.type_b.hello, 0x4242) 182 | 183 | dom.chunks[1].data.type_b.hello = 0xFF01 184 | 185 | self.assertEqual(dom.chunks[1].crc, 0xA5FADF1B) 186 | 187 | def test_metadata_packer(self): 188 | dom = self._test_parse_build( 189 | "yoyoyo\x00\x10x\x9cc```d```\x02\x00\x00\x0f\x00\x04", 190 | """ 191 | BigEndian(); 192 | typedef struct { 193 | int a; 194 | int b; 195 | } PACKED_DATA; 196 | 197 | struct { 198 | string type; 199 | uchar length; 200 | char data[length] ; 201 | } main_struct; 202 | """, 203 | ) 204 | 205 | self.assertEqual(dom.main_struct.data._.a, 1) 206 | self.assertEqual(dom.main_struct.data._.b, 2) 207 | 208 | dom.main_struct.data._.a = 5 209 | 210 | self.assertEqual( 211 | dom.main_struct.data._pfp__build(), 212 | b"x\x9cc```e```\x02\x00\x00#\x00\x08", 213 | ) 214 | 215 | # def test_metadata_packer_interpd(self): 216 | # dom = self._test_parse_build( 217 | # "\x08AaAbAcAd", 218 | # r""" 219 | # string CustomPacker(int pack, string data) { 220 | # Int3(); 221 | # local string res = ""; 222 | # local int size = sizeof(data); 223 | 224 | 225 | # 226 | # if(pack) { 227 | # for(local int i = 0; i < size; i++) { 228 | # res += "A" + data[i]; 229 | # } 230 | # } else { 231 | # for(local int i = 0; i < size; i += 2) { 232 | # res += data[i]; 233 | # } 234 | # } 235 | # 236 | # return res; 237 | # } 238 | # 239 | # typedef struct { 240 | # char a; 241 | # char b; 242 | # char c; 243 | # char d; 244 | # } PACKED_DATA; 245 | # 246 | # struct { 247 | # uchar length; 248 | # char data[length] ; 249 | # } main_struct; 250 | # """, 251 | # ) 252 | 253 | if __name__ == "__main__": 254 | unittest.main() 255 | -------------------------------------------------------------------------------- /tests/test_strings.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | 4 | import binascii 5 | import os 6 | import struct 7 | import sys 8 | import unittest 9 | 10 | sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) 11 | 12 | import pfp 13 | import pfp.errors 14 | from pfp.fields import * 15 | import pfp.utils 16 | 17 | import utils 18 | 19 | 20 | class TestStrings(utils.PfpTestCase): 21 | def setUp(self): 22 | pfp.fields.NumberBase.endian = pfp.fields.BIG_ENDIAN 23 | 24 | def tearDown(self): 25 | pass 26 | 27 | def test_unicode_const(self): 28 | dom = self._test_parse_build( 29 | "\n", 30 | """ 31 | char newline; 32 | if(newline == \'\\n\') { 33 | Warning("Found newline!"); 34 | } 35 | """, 36 | ) 37 | self.assertEqual(dom.newline, ord("\n")) 38 | 39 | def test_basic_string(self): 40 | dom = self._test_parse_build( 41 | "hello there\x00good byte\x00", 42 | """ 43 | struct { 44 | string hello; 45 | string goodbye; 46 | } greetings; 47 | """, 48 | ) 49 | self.assertEqual(dom.greetings.hello, pfp.utils.binary("hello there")) 50 | self.assertEqual(dom.greetings.goodbye, pfp.utils.binary("good byte")) 51 | 52 | def test_basic_wstring(self): 53 | dom = self._test_parse_build( 54 | "h\x00e\x00l\x00l\x00o\x00 \x00t\x00h\x00e\x00r\x00e\x00\x00\x00g\x00o\x00o\x00d\x00 \x00b\x00y\x00t\x00e\x00\x00\x00", 55 | """ 56 | struct { 57 | wstring hello; 58 | wstring goodbye; 59 | } greetings; 60 | """, 61 | ) 62 | self.assertEqual(dom.greetings.hello, pfp.utils.binary("hello there")) 63 | self.assertEqual(dom.greetings.goodbye, pfp.utils.binary("good byte")) 64 | 65 | def test_unterminated_string(self): 66 | with self.assertRaises(pfp.errors.PfpError): 67 | dom = self._test_parse_build( 68 | "unterminated string", 69 | """ 70 | struct { 71 | string something; 72 | } data; 73 | """, 74 | ) 75 | 76 | def test_string_indexing(self): 77 | dom = self._test_parse_build( 78 | "abcd\x00", 79 | """ 80 | string alpha; 81 | local char a = alpha[0]; 82 | Printf(a); 83 | """, 84 | stdout="a", 85 | ) 86 | 87 | self.assertEqual(dom.alpha[0], ord("a")) 88 | self.assertEqual(dom.alpha[1], ord("b")) 89 | self.assertEqual(dom.alpha[2], ord("c")) 90 | self.assertEqual(dom.alpha[3], ord("d")) 91 | 92 | dom.alpha[2] = ord("C") 93 | 94 | self.assertEqual(dom.alpha[0], ord("a")) 95 | self.assertEqual(dom.alpha[1], ord("b")) 96 | self.assertEqual(dom.alpha[2], ord("C")) 97 | self.assertEqual(dom.alpha[3], ord("d")) 98 | 99 | def test_string_declaration_with_chars(self): 100 | dom = self._test_parse_build( 101 | "", 102 | r""" 103 | local string RarSignature = "Rar!" + '\x1A' + '\x07'; 104 | Printf("%s", RarSignature); 105 | """, 106 | stdout="Rar!\x1a\x07", 107 | ) 108 | 109 | # temp_char ends up being of class Bytes in python 3 - but not on python 2 110 | # This test ensures we can handle adding both a String and byte together 111 | def test_add_strings(self): 112 | dom = self._test_parse_build( 113 | "\x01\x02\x03\x04\x05", 114 | """ 115 | local string temp_expected, temp_char; 116 | local int i; 117 | for(i = 0; i < 5; i++) { 118 | SPrintf(temp_char, "%.2X", ReadUByte(FTell()+i)); 119 | temp_expected += temp_char; 120 | } 121 | Printf("%s", temp_expected); 122 | """, 123 | stdout="0102030405", 124 | ) 125 | 126 | def test_add_strings_simple(self): 127 | dom = self._test_parse_build( 128 | "\x01", 129 | """ 130 | local string test; 131 | local int i; 132 | for(i = 0; i < 5; i++) { 133 | test += "test"; 134 | } 135 | Printf("%s", test); 136 | """, 137 | stdout="testtesttesttesttest", 138 | ) 139 | 140 | 141 | if __name__ == "__main__": 142 | unittest.main() 143 | -------------------------------------------------------------------------------- /tests/test_type_creation.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | 4 | import os 5 | import sys 6 | import unittest 7 | 8 | sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) 9 | 10 | import pfp 11 | import pfp.fields 12 | from pfp.fields import PYVAL, PYSTR 13 | import pfp.interp 14 | import pfp.utils 15 | 16 | import utils 17 | 18 | 19 | class TestTypeCreation(utils.PfpTestCase): 20 | def setUp(self): 21 | pfp.fields.NumberBase.endian = pfp.fields.LITTLE_ENDIAN 22 | 23 | def tearDown(self): 24 | pass 25 | 26 | def test_atomic(self): 27 | dom = self._test_parse_build( 28 | "", 29 | """ 30 | typedef unsigned int BLAH; 31 | """, 32 | ) 33 | res = dom.BLAH() 34 | self.assertTrue(isinstance(res, pfp.fields.UInt)) 35 | self.assertEqual(res, 0) 36 | 37 | def test_struct(self): 38 | dom = self._test_parse_build( 39 | "", 40 | """ 41 | LittleEndian(); 42 | typedef struct { 43 | char a; 44 | char b; 45 | uint c; 46 | } TEST_STRUCT; 47 | """, 48 | ) 49 | res = dom.TEST_STRUCT() 50 | 51 | self.assertTrue(isinstance(res, pfp.fields.Struct)) 52 | self.assertEqual(res.a, 0) 53 | self.assertEqual(res.b, 0) 54 | self.assertEqual(res.c, 0) 55 | 56 | res.a = 0x30 57 | res.b = 0x40 58 | res.c = 0x1000 59 | self.assertEqual(res.a, 0x30) 60 | self.assertEqual(res.b, 0x40) 61 | self.assertEqual(res.c, 0x1000) 62 | 63 | output = res._pfp__build() 64 | self.assertEqual(output, pfp.utils.binary("\x30\x40\x00\x10\x00\x00")) 65 | 66 | 67 | if __name__ == "__main__": 68 | unittest.main() 69 | -------------------------------------------------------------------------------- /tests/utils.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | 4 | import six 5 | import sys 6 | import pfp 7 | import pfp.utils 8 | import unittest 9 | import contextlib 10 | 11 | 12 | class PfpTestMeta(type): 13 | def __init__(cls, name, bases, dict_): 14 | for attr_name, attr_val in six.iteritems(dict_): 15 | if not attr_name.startswith("test_"): 16 | continue 17 | 18 | if not hasattr(attr_val, "__call__"): 19 | continue 20 | 21 | new_func_name = attr_name + "_with_string_data" 22 | new_func = cls._create_string_data_test(attr_val) 23 | setattr(cls, new_func_name, new_func) 24 | 25 | return super(PfpTestMeta, cls).__init__(name, bases, dict_) 26 | 27 | def _create_string_data_test(cls, method): 28 | """Wrap the test method in a new function that causes _test_parse_build 29 | to use _stream=False as the default in order to test string data 30 | as input to pfp.parse 31 | """ 32 | 33 | @contextlib.wraps(method) 34 | def new_method(self, *args, **kwargs): 35 | self._test_parse_build = self._test_parse_build_with_string 36 | try: 37 | res = method(self, *args, **kwargs) 38 | finally: 39 | self._test_parse_build = cls._test_parse_build_orig 40 | 41 | return new_method 42 | 43 | 44 | @six.add_metaclass(PfpTestMeta) 45 | class PfpTestCase(unittest.TestCase): 46 | def __init__(self, *args, **kwargs): 47 | # create two versions of each test 48 | 49 | unittest.TestCase.__init__(self, *args, **kwargs) 50 | 51 | def _test_parse_build_with_string(self, *args, **kwargs): 52 | kwargs["_stream"] = False 53 | return self._test_parse_build_orig(*args, **kwargs) 54 | 55 | def _test_parse_build( 56 | self, 57 | data, 58 | template, 59 | stdout=None, 60 | debug=False, 61 | predefines=False, 62 | _stream=True, 63 | printf=True, 64 | ): 65 | if stdout is not None: 66 | fake_stdout = sys.stdout = six.StringIO() 67 | 68 | if _stream: 69 | data = six.StringIO(data) 70 | 71 | # defaults to LittleEndian 72 | template = "LittleEndian();" + template 73 | 74 | dom = pfp.parse( 75 | data, template, debug=debug, predefines=predefines, printf=printf 76 | ) 77 | 78 | if stdout is not None: 79 | sys.stdout = sys.__stdout__ 80 | output = fake_stdout.getvalue() 81 | self.assertEqual(output, stdout) 82 | 83 | return dom 84 | 85 | _test_parse_build_orig = _test_parse_build 86 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = py27,py37 3 | 4 | [testenv] 5 | # install pytest in the virtualenv where commands will be executed 6 | deps = -r requirements.txt 7 | pytest 8 | pytest-xdist 9 | pytest-cov 10 | commands = 11 | pytest -n 4 --tb native {posargs} 12 | --------------------------------------------------------------------------------