├── .gitignore ├── .hgignore ├── .travis.yml ├── Cargo.toml ├── LICENSE ├── README.md ├── benches └── lib.rs ├── data ├── .gitattributes ├── 10x10y ├── 10x10y.compressed ├── 64x ├── 64x.compressed ├── alice29.txt ├── alice29.txt.compressed ├── asyoulik.txt ├── asyoulik.txt.compressed ├── backward65536 ├── backward65536.compressed ├── compressed_file ├── compressed_file.compressed ├── compressed_repeated ├── compressed_repeated.compressed ├── empty ├── empty.compressed ├── empty.compressed.00 ├── empty.compressed.01 ├── empty.compressed.02 ├── empty.compressed.03 ├── empty.compressed.04 ├── empty.compressed.05 ├── empty.compressed.06 ├── empty.compressed.07 ├── empty.compressed.08 ├── empty.compressed.09 ├── empty.compressed.10 ├── empty.compressed.11 ├── empty.compressed.12 ├── empty.compressed.13 ├── empty.compressed.14 ├── empty.compressed.15 ├── empty.compressed.16 ├── empty.compressed.17 ├── empty.compressed.18 ├── frewsxcv_01.compressed ├── frewsxcv_02.compressed ├── frewsxcv_03.compressed ├── frewsxcv_04.compressed ├── frewsxcv_05.compressed ├── frewsxcv_06.compressed ├── frewsxcv_07.compressed ├── frewsxcv_08.compressed ├── frewsxcv_09.compressed ├── lcet10.txt ├── lcet10.txt.compressed ├── mapsdatazrh ├── mapsdatazrh.compressed ├── metablock_reset ├── metablock_reset.compressed ├── monkey ├── monkey.compressed ├── plrabn12.txt ├── plrabn12.txt.compressed ├── quickfox ├── quickfox.compressed ├── quickfox_repeated ├── quickfox_repeated.compressed ├── random_chunks ├── random_org_10k.bin ├── random_org_10k.bin.compressed ├── ukkonooa ├── ukkonooa.compressed ├── x ├── x.compressed ├── x.compressed.00 ├── x.compressed.01 ├── x.compressed.02 ├── x.compressed.03 ├── xxxxxyyyyy.txt ├── xyzzy ├── xyzzy.compressed ├── zeros └── zeros.compressed ├── docs ├── analysis.afl-00.compressed.txt ├── analysis.afl-01.compressed.txt ├── analysis.afl-02.compressed.txt ├── analysis.afl-03.compressed.txt ├── analysis.afl-04.compressed.txt ├── analysis.frewsxcv.compressed.txt ├── analysis_alice29.txt.compressed.txt ├── analysis_asyoulik.txt.compressed.txt ├── analysis_empty.compressed.01.txt ├── analysis_empty.compressed.02.txt ├── analysis_empty.compressed.15.txt ├── analysis_empty.compressed.16.txt ├── analysis_empty.compressed.17.txt ├── analysis_empty.compressed.txt ├── analysis_quickfox_repeated.txt ├── analysis_x.compressed.00.txt ├── analysis_x.compressed.03.txt ├── analysis_x.compressed.txt ├── bench_notes.txt ├── draft-alakuijala-brotli-07.txt └── notes_afl.txt ├── src ├── bitreader │ └── mod.rs ├── dictionary │ └── mod.rs ├── huffman │ ├── mod.rs │ └── tree │ │ └── mod.rs ├── lib.rs ├── lookuptable │ └── mod.rs ├── main.rs ├── ringbuffer │ └── mod.rs └── transformation │ └── mod.rs └── tests └── lib.rs /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | afl-findings -------------------------------------------------------------------------------- /.hgignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | afl-findings -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: rust 3 | addons: 4 | apt: 5 | packages: 6 | - libcurl4-openssl-dev 7 | - libelf-dev 8 | - libdw-dev 9 | rust: 10 | - beta 11 | - stable 12 | - nightly 13 | before_script: 14 | - | 15 | pip install 'travis-cargo<0.2' --user && 16 | export PATH=$HOME/.local/bin:$PATH 17 | script: 18 | - | 19 | travis-cargo build && 20 | travis-cargo test && 21 | travis-cargo bench && 22 | travis-cargo --only stable doc 23 | after_success: 24 | - travis-cargo --only stable doc-upload 25 | - travis-cargo coveralls --no-sudo 26 | env: 27 | global: 28 | - TRAVIS_CARGO_NIGHTLY_FEATURE="" 29 | - secure: Q5R4XLxPf27ng4nLY/4lbwg7/zDG0F4PrzZEXvq7WMdAMDQLtzUhBq1M40ahNG7nxL0RqVFJhwcoOm16wwqldsx/C/sFMFPNowijAxcUo/DhlIzjqbzLGFaoLphYdfAJRPayZXWhD9wSgLMUBEq0eLKyG/kmV+4UhG3WyamGnTvzPPKMd17pU1pXsG8nycEomflYWNR4WSTrmHZCOjWSn6mROuolFNogwLAgw5HgTHfKxuGVDI6gEfsNk0A5wLI2OxianKzLHHWrxpDIi93Sq97JfnERVB9xK7OfwJaE63KTvkGdex2U44SB6mxiF/TfKLbVJ2e99oHHCbr5S10KILUwElAtyW57TloDTnwNGoBaYLLzWxJ+KFrWprdH9um0K3ea0ig8z2l1UEO4vVizWZcVdkDyrNrrS56TdPPsNjzgyYxLiyQWQIvAB7HkxGk/Z4N9dnxiRTuG8dTwtXfxpX60AloaVhSSpfvBXHK74ZIMcUkl4P+zeCdDyb81uwHWSOe9VE5VqNx+jlTpsDiBOerhvSPBlads2kWbizAZfCmqnAI1ix5nikkMqQfQ7CqQf/yyl3pe31ZSPer5ibAk5YFgNhUa7MmJubz3mb7E3ZC+u1/GB9eQktXyiZcLgBvOqUKwZJxw4ZyEz4UEv3UFreKCb2e5fVkM/hFbFu1f94k= 30 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "brotli" 3 | version = "0.3.23" 4 | authors = ["Thomas Pickert "] 5 | license = "Apache-2.0" 6 | repository = "https://github.com/ende76/brotli-rs" 7 | documentation = "http://ende76.github.io/brotli-rs/brotli/" 8 | 9 | [[bin]] 10 | doc = false 11 | name = "main" 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Brotli-rs - Brotli decompression in pure, safe Rust 2 | 3 | [![Build Status](https://api.travis-ci.org/ende76/brotli-rs.png?branch=master)](https://travis-ci.org/ende76/brotli-rs) ![Works on stable](https://img.shields.io/badge/works%20on-stable-green.svg) ![Works on beta](https://img.shields.io/badge/works%20on-beta-yellow.svg) ![Works on nightly](https://img.shields.io/badge/works%20on-nightly-lightgrey.svg) 4 | 5 | [Documentation](http://ende76.github.io/brotli-rs/brotli/) 6 | 7 | Compression provides a \-struct to wrap a Brotli-compressed stream. A consumer is thus able to read a compressed stream with usual convenience. 8 | 9 | ## Changelog 10 | 11 | ### v0.3.22 -> v0.3.23 12 | ---------------- 13 | 14 | Bug with literal buffer not being populated when processing uncompressed metablock, bug where a valid stream could be rejected too early as oversized, if the last bytes happened to be shortened by an OMIT-type transformation after the early check, reported and fixed by [Daniel](https://github.com/danielrh). 15 | 16 | 17 | ### v0.3.21 -> v0.3.22 18 | ---------------- 19 | 20 | Bug with metablock structure not getting fully reset when encountering a new metablock in the brotli stream, reported and fixed by [Daniel](https://github.com/danielrh). 21 | 22 | ### v0.3.20 -> v0.3.21 23 | ---------------- 24 | 25 | Bug with multiple metablocks, reported and fixed by [Daniel](https://github.com/danielrh). 26 | 27 | ###v0.3.19 -> v0.3.20 28 | ---------------- 29 | 30 | Worked around feature gate issue in nightly. (Thanks, [Corey](https://github.com/frewsxcv)!) 31 | 32 | ### v0.3.18 -> v0.3.19 33 | ---------------- 34 | 35 | Removed 64k big Pseudo-Code lookup table, because creating this trivial table probably took more time than making the calculcation on the fly. (Bench tests seem to suggest a 1% time savings without the lookup table) 36 | 37 | ### v0.3.17 -> v0.3.18 38 | ---------------- 39 | 40 | Fixed case where a simple prefix code could have duplicate symbols. 41 | 42 | ### v0.3.16 -> v0.3.17 43 | ---------------- 44 | 45 | Fixed case where a complex prefix code could have an incorrect checksum on its runlength code. 46 | 47 | ### v0.3.15 -> v0.3.16 48 | ---------------- 49 | 50 | - Fixed incorrect calculation of alphabet size for distance code. 51 | - Fixed evaluation where streams with excessive insert/copy lengths could be rejected early. 52 | 53 | ### v0.3.14 -> v0.3.15 54 | ---------------- 55 | 56 | Fixed injection of invalid symbols in simple prefix code. 57 | 58 | ### v0.3.13 -> v0.3.14 59 | ---------------- 60 | 61 | Fixed invalid block-type in switch command. (Thanks, [Corey](https://github.com/frewsxcv)!). 62 | 63 | ### v0.3.12 -> v0.3.13 64 | ---------------- 65 | 66 | Fixed uncaught non-positive distances. (Thanks, [Corey](https://github.com/frewsxcv)!). 67 | 68 | ### v0.3.11 -> v0.3.12 69 | ---------------- 70 | 71 | Fixed uncaught zero-byte in word transformation. (Thanks, [Corey](https://github.com/frewsxcv)!). 72 | 73 | ### v0.3.10 -> v0.3.11 74 | ---------------- 75 | 76 | Fixed possible arithmetic overflow in word transformation. (Thanks, [Corey](https://github.com/frewsxcv)!). 77 | 78 | ### v0.3.9 -> v0.3.10 79 | ---------------- 80 | 81 | Fixed incorrect type for runlength code. (Thanks, [Corey](https://github.com/frewsxcv)!). 82 | 83 | ### v0.3.8 -> v0.3.9 84 | ---------------- 85 | 86 | Fixed incorrect array index bound check in tree lookup. (Thanks, [Corey](https://github.com/frewsxcv)!). 87 | 88 | ### v0.3.7 -> v0.3.8 89 | ---------------- 90 | 91 | Fixed some value range checks on block types and ntree*. (Thanks, [Corey](https://github.com/frewsxcv)!). 92 | 93 | ### v0.3.6 -> v0.3.7 94 | ---------------- 95 | 96 | Went over "unreachable!()" statements, analyzed, and handled error condition properly, if they were reachable through invalid data. 97 | 98 | ### v0.3.5 -> v0.3.6 99 | ---------------- 100 | 101 | Fixed a case where an invalid prefix code with all-zero codelengths could create an index-out-of-bounds panic. (Thanks, [Corey](https://github.com/frewsxcv)!). 102 | 103 | ### v0.3.4 -> v0.3.5 104 | ---------------- 105 | 106 | Fixed a case where an invalid insert-and-copy-length-code would produce a panic. (Thanks, [Corey](https://github.com/frewsxcv)!). 107 | 108 | ### v0.3.1 -> v0.3.4 109 | ---------------- 110 | 111 | Fair amount of internal small improvements, improving code quality. Fixed a couple of cases where invalid streams would lead to panics and/or infinite loops (Thanks, [Corey](https://github.com/frewsxcv)!). 112 | 113 | 114 | ### v0.3.0 -> v0.3.1 115 | ---------------- 116 | 117 | This is only a minor version bump, with no breakage in usage, but it's exciting nonetheless! 118 | 119 | In Brotli, a lot of work is done with and by prefix codes. Through a change in the internal representation of prefix codes, it was possible to speed the reference benchmark time by a factor of ~7. The benchmark decompresses the contents of the file data/monkey.compressed. 120 | 121 | - With linked-list-based, recursive tree implementation: 122 | test bench_monkey ... bench: __866,888 ns__/iter (+/- 58,119) 123 | 124 | - With array-based, iterative tree implementation, before max-depth constraint: 125 | test bench_monkey ... bench: __704,282 ns__/iter (+/- 220,068) 126 | 127 | - With array-based, iterative tree implementation, with max-depth constraint: 128 | test bench_monkey ... bench: __120,745 ns__/iter (+/- 16,627) 129 | 130 | 131 | ### v0.2.0 -> v0.3.0 132 | ---------------- 133 | 134 | - renamed crate compression -> brotli 135 | - restructured modules to avoid redundant paths like brotli::brotli::Decompressor (now it's just brotli::Decompressor) 136 | 137 | 138 | ### v0.1.0 -> v0.2.0 139 | ---------------- 140 | 141 | - Decompressor::new() now accepts a Read, as opposed to a BitReader. 142 | -------------------------------------------------------------------------------- /benches/lib.rs: -------------------------------------------------------------------------------- 1 | #![feature(test)] 2 | 3 | extern crate test; 4 | extern crate brotli; 5 | 6 | use test::Bencher; 7 | 8 | 9 | #[bench] 10 | fn bench_monkey(b: &mut Bencher) { 11 | use std::io::{ Cursor, Read }; 12 | use brotli::Decompressor; 13 | 14 | b.iter(|| { 15 | let brotli_stream = Cursor::new(vec![ 16 | 0x1b, 0x4a, 0x03, 0x00, 0x8c, 0x94, 0x6e, 0xde, 0xb4, 0xd7, 0x96, 0xb1, 0x78, 0x86, 0xf2, 0x2d, 17 | 0xe1, 0x1a, 0xbc, 0x0b, 0x1c, 0xba, 0xa9, 0xc7, 0xf7, 0xcc, 0x6e, 0xb2, 0x42, 0x34, 0x51, 0x44, 18 | 0x8b, 0x4e, 0x13, 0x08, 0xa0, 0xcd, 0x6e, 0xe8, 0x2c, 0xa5, 0x53, 0xa1, 0x9c, 0x5d, 0x2c, 0x1d, 19 | 0x23, 0x1a, 0xd2, 0x56, 0xbe, 0xdb, 0xeb, 0x26, 0xba, 0x03, 0x65, 0x7c, 0x96, 0x6a, 0xa2, 0x76, 20 | 0xec, 0xef, 0x87, 0x47, 0x33, 0xd6, 0x27, 0x0e, 0x63, 0x95, 0xe2, 0x1d, 0x8d, 0x2c, 0xc5, 0xd1, 21 | 0x28, 0x9f, 0x60, 0x94, 0x6f, 0x02, 0x8b, 0xdd, 0xaa, 0x64, 0x94, 0x2c, 0x1e, 0x3b, 0x65, 0x7c, 22 | 0x07, 0x45, 0x5a, 0xb2, 0xe2, 0xfc, 0x49, 0x81, 0x2c, 0x9f, 0x40, 0xae, 0xef, 0x68, 0x81, 0xac, 23 | 0x16, 0x7a, 0x0f, 0xf5, 0x3b, 0x6d, 0x1c, 0xb9, 0x1e, 0x2d, 0x5f, 0xd5, 0xc8, 0xaf, 0x5e, 0x85, 24 | 0xaa, 0x05, 0xbe, 0x53, 0x75, 0xc2, 0xb0, 0x22, 0x8a, 0x15, 0xc6, 0xa3, 0xb1, 0xe6, 0x42, 0x14, 25 | 0xf4, 0x84, 0x54, 0x53, 0x19, 0x5f, 0xbe, 0xc3, 0xf2, 0x1d, 0xd1, 0xb7, 0xe5, 0xdd, 0xb6, 0xd9, 26 | 0x23, 0xc6, 0xf6, 0x9f, 0x9e, 0xf6, 0x4d, 0x65, 0x30, 0xfb, 0xc0, 0x71, 0x45, 0x04, 0xad, 0x03, 27 | 0xb5, 0xbe, 0xc9, 0xcb, 0xfd, 0xe2, 0x50, 0x5a, 0x46, 0x74, 0x04, 0x0d, 0xff, 0x20, 0x04, 0x77, 28 | 0xb2, 0x6d, 0x27, 0xbf, 0x47, 0xa9, 0x9d, 0x1b, 0x96, 0x2c, 0x62, 0x90, 0x23, 0x8b, 0xe0, 0xf8, 29 | 0x1d, 0xcf, 0xaf, 0x1d, 0x3d, 0xee, 0x8a, 0xc8, 0x75, 0x23, 0x66, 0xdd, 0xde, 0xd6, 0x6d, 0xe3, 30 | 0x2a, 0x82, 0x8a, 0x78, 0x8a, 0xdb, 0xe6, 0x20, 0x4c, 0xb7, 0x5c, 0x63, 0xba, 0x30, 0xe3, 0x3f, 31 | 0xb6, 0xee, 0x8c, 0x22, 0xa2, 0x2a, 0xb0, 0x22, 0x0a, 0x99, 0xff, 0x3d, 0x62, 0x51, 0xee, 0x08, 32 | 0xf6, 0x3d, 0x4a, 0xe4, 0xcc, 0xef, 0x22, 0x87, 0x11, 0xe2, 0x83, 0x28, 0xe4, 0xf5, 0x8f, 0x35, 33 | 0x19, 0x63, 0x5b, 0xe1, 0x5a, 0x92, 0x73, 0xdd, 0xa1, 0x50, 0x9d, 0x38, 0x5c, 0xeb, 0xb5, 0x03, 34 | 0x6a, 0x64, 0x90, 0x94, 0xc8, 0x8d, 0xfb, 0x2f, 0x8a, 0x86, 0x22, 0xcc, 0x1d, 0x87, 0xe0, 0x48, 35 | 0x0a, 0x96, 0x77, 0x90, 0x39, 0xc6, 0x23, 0x23, 0x48, 0xfb, 0x11, 0x47, 0x56, 0xca, 0x20, 0xe3, 36 | 0x42, 0x81, 0xf7, 0x77, 0x32, 0xc1, 0xa5, 0x5c, 0x40, 0x21, 0x65, 0x17, 0x40, 0x29, 0x17, 0x17, 37 | 0x6c, 0x56, 0x32, 0x98, 0x38, 0x06, 0xdc, 0x99, 0x4d, 0x33, 0x29, 0xbb, 0x02, 0xdf, 0x4c, 0x26, 38 | 0x93, 0x6c, 0x17, 0x82, 0x86, 0x20, 0xd7, 0x03, 0x79, 0x7d, 0x9a, 0x00, 0xd7, 0x87, 0x00, 0xe7, 39 | 0x0b, 0x66, 0xe3, 0x4c, 0x66, 0x71, 0x67, 0x08, 0x32, 0xf9, 0x08, 0x3e, 0x81, 0x33, 0xcd, 0x17, 40 | 0x72, 0x31, 0xf0, 0xb8, 0x94, 0x52, 0x4b, 0x90, 0x31, 0x8e, 0x68, 0xc1, 0xef, 0x90, 0xc9, 0xe5, 41 | 0xf2, 0x61, 0x09, 0x72, 0x25, 0xad, 0xec, 0xc5, 0x62, 0xc0, 0x0b, 0x12, 0x05, 0xf7, 0x91, 0x75, 42 | 0x0d, 0xee, 0x61, 0x2e, 0x2e, 0x19, 0x09, 0xc2, 0x03, 43 | ]); 44 | 45 | let mut decompressed = &mut String::new(); 46 | Decompressor::new(brotli_stream).read_to_string(&mut decompressed) 47 | }); 48 | } 49 | 50 | #[bench] 51 | fn bench_alice(b: &mut Bencher) { 52 | use std::io::Read; 53 | use brotli::Decompressor; 54 | 55 | b.iter(|| { 56 | let mut input = Vec::new(); 57 | let _ = Decompressor::new(std::fs::File::open("data/alice29.txt.compressed").unwrap()).read_to_end(&mut input); 58 | }); 59 | } 60 | 61 | 62 | #[bench] 63 | fn bench_bitstring_version_0(b: &mut Bencher) { 64 | fn bit_string_from_code_and_length(code: usize, len: usize) -> Vec { 65 | let mut bits = vec![false; len]; 66 | 67 | for i in 0..len { 68 | bits[len - i - 1] = (code >> i) & 1 == 1; 69 | } 70 | 71 | bits 72 | } 73 | 74 | b.iter(|| { 75 | assert_eq!(vec![false, false], bit_string_from_code_and_length(0b00, 2)); 76 | assert_eq!(vec![false, true, true], bit_string_from_code_and_length(0b011, 3)); 77 | assert_eq!(vec![true, false, false, true, true], bit_string_from_code_and_length(0b10011, 5)); 78 | }); 79 | } 80 | 81 | #[bench] 82 | fn bench_bitstring_version_1(b: &mut Bencher) { 83 | fn bit_string_from_code_and_length(code: usize, len: usize) -> Vec { 84 | let mut bits = Vec::with_capacity(len); 85 | 86 | for i in 0..len { 87 | bits.push(code >> (len - 1 - i) & 1 == 1); 88 | } 89 | 90 | bits 91 | } 92 | 93 | b.iter(|| { 94 | assert_eq!(vec![false, false], bit_string_from_code_and_length(0b00, 2)); 95 | assert_eq!(vec![false, true, true], bit_string_from_code_and_length(0b011, 3)); 96 | assert_eq!(vec![true, false, false, true, true], bit_string_from_code_and_length(0b10011, 5)); 97 | }); 98 | } 99 | 100 | #[bench] 101 | fn bench_bitstring_version_2(b: &mut Bencher) { 102 | fn bit_string_from_code_and_length(code: usize, bits: &mut[bool]) { 103 | let len = bits.len(); 104 | for (i, mut b) in bits.iter_mut().enumerate() { 105 | *b = code & (1 << (len - 1 - i)) != 0; 106 | } 107 | } 108 | 109 | b.iter(|| { 110 | let mut bits_0 = vec![false; 2]; 111 | bit_string_from_code_and_length(0b00, &mut bits_0); 112 | assert_eq!(vec![false, false], bits_0); 113 | let mut bits_1 = vec![false; 3]; 114 | bit_string_from_code_and_length(0b011, &mut bits_1); 115 | assert_eq!(vec![false, true, true], bits_1); 116 | let mut bits_2 = vec![false; 5]; 117 | bit_string_from_code_and_length(0b10011, &mut bits_2); 118 | assert_eq!(vec![true, false, false, true, true], bits_2); 119 | }); 120 | } 121 | 122 | -------------------------------------------------------------------------------- /data/.gitattributes: -------------------------------------------------------------------------------- 1 | * -text 2 | -------------------------------------------------------------------------------- /data/10x10y: -------------------------------------------------------------------------------- 1 | XXXXXXXXXXYYYYYYYYYY -------------------------------------------------------------------------------- /data/10x10y.compressed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ende76/brotli-rs/43785f25e5761ff69f7beef7fc280dbd459629ee/data/10x10y.compressed -------------------------------------------------------------------------------- /data/64x: -------------------------------------------------------------------------------- 1 | XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -------------------------------------------------------------------------------- /data/64x.compressed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ende76/brotli-rs/43785f25e5761ff69f7beef7fc280dbd459629ee/data/64x.compressed -------------------------------------------------------------------------------- /data/alice29.txt.compressed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ende76/brotli-rs/43785f25e5761ff69f7beef7fc280dbd459629ee/data/alice29.txt.compressed -------------------------------------------------------------------------------- /data/asyoulik.txt.compressed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ende76/brotli-rs/43785f25e5761ff69f7beef7fc280dbd459629ee/data/asyoulik.txt.compressed -------------------------------------------------------------------------------- /data/backward65536.compressed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ende76/brotli-rs/43785f25e5761ff69f7beef7fc280dbd459629ee/data/backward65536.compressed -------------------------------------------------------------------------------- /data/compressed_file: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ende76/brotli-rs/43785f25e5761ff69f7beef7fc280dbd459629ee/data/compressed_file -------------------------------------------------------------------------------- /data/compressed_file.compressed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ende76/brotli-rs/43785f25e5761ff69f7beef7fc280dbd459629ee/data/compressed_file.compressed -------------------------------------------------------------------------------- /data/compressed_repeated: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ende76/brotli-rs/43785f25e5761ff69f7beef7fc280dbd459629ee/data/compressed_repeated -------------------------------------------------------------------------------- /data/compressed_repeated.compressed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ende76/brotli-rs/43785f25e5761ff69f7beef7fc280dbd459629ee/data/compressed_repeated.compressed -------------------------------------------------------------------------------- /data/empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ende76/brotli-rs/43785f25e5761ff69f7beef7fc280dbd459629ee/data/empty -------------------------------------------------------------------------------- /data/empty.compressed: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /data/empty.compressed.00: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /data/empty.compressed.01: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ende76/brotli-rs/43785f25e5761ff69f7beef7fc280dbd459629ee/data/empty.compressed.01 -------------------------------------------------------------------------------- /data/empty.compressed.02: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ende76/brotli-rs/43785f25e5761ff69f7beef7fc280dbd459629ee/data/empty.compressed.02 -------------------------------------------------------------------------------- /data/empty.compressed.03: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ende76/brotli-rs/43785f25e5761ff69f7beef7fc280dbd459629ee/data/empty.compressed.03 -------------------------------------------------------------------------------- /data/empty.compressed.04: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ende76/brotli-rs/43785f25e5761ff69f7beef7fc280dbd459629ee/data/empty.compressed.04 -------------------------------------------------------------------------------- /data/empty.compressed.05: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ende76/brotli-rs/43785f25e5761ff69f7beef7fc280dbd459629ee/data/empty.compressed.05 -------------------------------------------------------------------------------- /data/empty.compressed.06: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ende76/brotli-rs/43785f25e5761ff69f7beef7fc280dbd459629ee/data/empty.compressed.06 -------------------------------------------------------------------------------- /data/empty.compressed.07: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ende76/brotli-rs/43785f25e5761ff69f7beef7fc280dbd459629ee/data/empty.compressed.07 -------------------------------------------------------------------------------- /data/empty.compressed.08: -------------------------------------------------------------------------------- 1 | 3 -------------------------------------------------------------------------------- /data/empty.compressed.09: -------------------------------------------------------------------------------- 1 | 5 -------------------------------------------------------------------------------- /data/empty.compressed.10: -------------------------------------------------------------------------------- 1 | 7 -------------------------------------------------------------------------------- /data/empty.compressed.11: -------------------------------------------------------------------------------- 1 | 9 -------------------------------------------------------------------------------- /data/empty.compressed.12: -------------------------------------------------------------------------------- 1 | ; -------------------------------------------------------------------------------- /data/empty.compressed.13: -------------------------------------------------------------------------------- 1 | = -------------------------------------------------------------------------------- /data/empty.compressed.14: -------------------------------------------------------------------------------- 1 | ? -------------------------------------------------------------------------------- /data/empty.compressed.15: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /data/empty.compressed.16: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ende76/brotli-rs/43785f25e5761ff69f7beef7fc280dbd459629ee/data/empty.compressed.16 -------------------------------------------------------------------------------- /data/frewsxcv_01.compressed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ende76/brotli-rs/43785f25e5761ff69f7beef7fc280dbd459629ee/data/frewsxcv_01.compressed -------------------------------------------------------------------------------- /data/frewsxcv_02.compressed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ende76/brotli-rs/43785f25e5761ff69f7beef7fc280dbd459629ee/data/frewsxcv_02.compressed -------------------------------------------------------------------------------- /data/frewsxcv_03.compressed: -------------------------------------------------------------------------------- 1 | 00@ -------------------------------------------------------------------------------- /data/frewsxcv_04.compressed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ende76/brotli-rs/43785f25e5761ff69f7beef7fc280dbd459629ee/data/frewsxcv_04.compressed -------------------------------------------------------------------------------- /data/frewsxcv_05.compressed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ende76/brotli-rs/43785f25e5761ff69f7beef7fc280dbd459629ee/data/frewsxcv_05.compressed -------------------------------------------------------------------------------- /data/frewsxcv_06.compressed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ende76/brotli-rs/43785f25e5761ff69f7beef7fc280dbd459629ee/data/frewsxcv_06.compressed -------------------------------------------------------------------------------- /data/frewsxcv_07.compressed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ende76/brotli-rs/43785f25e5761ff69f7beef7fc280dbd459629ee/data/frewsxcv_07.compressed -------------------------------------------------------------------------------- /data/frewsxcv_08.compressed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ende76/brotli-rs/43785f25e5761ff69f7beef7fc280dbd459629ee/data/frewsxcv_08.compressed -------------------------------------------------------------------------------- /data/frewsxcv_09.compressed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ende76/brotli-rs/43785f25e5761ff69f7beef7fc280dbd459629ee/data/frewsxcv_09.compressed -------------------------------------------------------------------------------- /data/lcet10.txt.compressed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ende76/brotli-rs/43785f25e5761ff69f7beef7fc280dbd459629ee/data/lcet10.txt.compressed -------------------------------------------------------------------------------- /data/mapsdatazrh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ende76/brotli-rs/43785f25e5761ff69f7beef7fc280dbd459629ee/data/mapsdatazrh -------------------------------------------------------------------------------- /data/mapsdatazrh.compressed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ende76/brotli-rs/43785f25e5761ff69f7beef7fc280dbd459629ee/data/mapsdatazrh.compressed -------------------------------------------------------------------------------- /data/metablock_reset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ende76/brotli-rs/43785f25e5761ff69f7beef7fc280dbd459629ee/data/metablock_reset -------------------------------------------------------------------------------- /data/metablock_reset.compressed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ende76/brotli-rs/43785f25e5761ff69f7beef7fc280dbd459629ee/data/metablock_reset.compressed -------------------------------------------------------------------------------- /data/monkey: -------------------------------------------------------------------------------- 1 | znxcvnmz,xvnm.,zxcnv.,xcn.z,vn.zvn.zxcvn.,zxcn.vn.v,znm.,vnzx.,vnzxc.vn.z,vnz.,nv.z,nvmzxc,nvzxcvcnm.,vczxvnzxcnvmxc.zmcnvzm.,nvmc,nzxmc,vn.mnnmzxc,vnxcnmv,znvzxcnmv,.xcnvm,zxcnzxv.zx,qweryweurqioweupropqwutioweupqrioweutiopweuriopweuriopqwurioputiopqwuriowuqerioupqweropuweropqwurweuqriopuropqwuriopuqwriopuqweopruioqweurqweuriouqweopruioupqiytioqtyiowtyqptypryoqweutioioqtweqruowqeytiowquiourowetyoqwupiotweuqiorweuqroipituqwiorqwtioweuriouytuioerytuioweryuitoweytuiweyuityeruirtyuqriqweuropqweiruioqweurioqwuerioqwyuituierwotueryuiotweyrtuiwertyioweryrueioqptyioruyiopqwtjkasdfhlafhlasdhfjklashjkfhasjklfhklasjdfhklasdhfjkalsdhfklasdhjkflahsjdkfhklasfhjkasdfhasfjkasdhfklsdhalghhaf;hdklasfhjklashjklfasdhfasdjklfhsdjklafsd;hkldadfjjklasdhfjasddfjklfhakjklasdjfkl;asdjfasfljasdfhjklasdfhjkaghjkashf;djfklasdjfkljasdklfjklasdjfkljasdfkljaklfj -------------------------------------------------------------------------------- /data/monkey.compressed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ende76/brotli-rs/43785f25e5761ff69f7beef7fc280dbd459629ee/data/monkey.compressed -------------------------------------------------------------------------------- /data/plrabn12.txt.compressed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ende76/brotli-rs/43785f25e5761ff69f7beef7fc280dbd459629ee/data/plrabn12.txt.compressed -------------------------------------------------------------------------------- /data/quickfox: -------------------------------------------------------------------------------- 1 | The quick brown fox jumps over the lazy dog -------------------------------------------------------------------------------- /data/quickfox.compressed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ende76/brotli-rs/43785f25e5761ff69f7beef7fc280dbd459629ee/data/quickfox.compressed -------------------------------------------------------------------------------- /data/quickfox_repeated.compressed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ende76/brotli-rs/43785f25e5761ff69f7beef7fc280dbd459629ee/data/quickfox_repeated.compressed -------------------------------------------------------------------------------- /data/random_chunks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ende76/brotli-rs/43785f25e5761ff69f7beef7fc280dbd459629ee/data/random_chunks -------------------------------------------------------------------------------- /data/random_org_10k.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ende76/brotli-rs/43785f25e5761ff69f7beef7fc280dbd459629ee/data/random_org_10k.bin -------------------------------------------------------------------------------- /data/random_org_10k.bin.compressed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ende76/brotli-rs/43785f25e5761ff69f7beef7fc280dbd459629ee/data/random_org_10k.bin.compressed -------------------------------------------------------------------------------- /data/ukkonooa: -------------------------------------------------------------------------------- 1 | ukko nooa, ukko nooa oli kunnon mies, kun han meni saunaan, pisti laukun naulaan, ukko nooa, ukko nooa oli kunnon mies. -------------------------------------------------------------------------------- /data/ukkonooa.compressed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ende76/brotli-rs/43785f25e5761ff69f7beef7fc280dbd459629ee/data/ukkonooa.compressed -------------------------------------------------------------------------------- /data/x: -------------------------------------------------------------------------------- 1 | X -------------------------------------------------------------------------------- /data/x.compressed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ende76/brotli-rs/43785f25e5761ff69f7beef7fc280dbd459629ee/data/x.compressed -------------------------------------------------------------------------------- /data/x.compressed.00: -------------------------------------------------------------------------------- 1 | X -------------------------------------------------------------------------------- /data/x.compressed.01: -------------------------------------------------------------------------------- 1 | ,XX -------------------------------------------------------------------------------- /data/x.compressed.02: -------------------------------------------------------------------------------- 1 | X -------------------------------------------------------------------------------- /data/x.compressed.03: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ende76/brotli-rs/43785f25e5761ff69f7beef7fc280dbd459629ee/data/x.compressed.03 -------------------------------------------------------------------------------- /data/xxxxxyyyyy.txt: -------------------------------------------------------------------------------- 1 | xxxxxyyyyy -------------------------------------------------------------------------------- /data/xyzzy: -------------------------------------------------------------------------------- 1 | Xyzzy -------------------------------------------------------------------------------- /data/xyzzy.compressed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ende76/brotli-rs/43785f25e5761ff69f7beef7fc280dbd459629ee/data/xyzzy.compressed -------------------------------------------------------------------------------- /data/zeros.compressed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ende76/brotli-rs/43785f25e5761ff69f7beef7fc280dbd459629ee/data/zeros.compressed -------------------------------------------------------------------------------- /docs/analysis.afl-00.compressed.txt: -------------------------------------------------------------------------------- 1 | Analysis of frewsxcv.compressed: 2 | 0x01 0xe6 0x00 0x76 0x42 0x10 0x01 0x1c 0x24 0x24 0x3c 0xd7 0xd7 0xd7 0x01 0x1c 3 | 4 | Brotli Stream Header 5 | ==================== 6 | 0x01 = 0000 0001 7 | 8 | 000 0001 # WBITS => decodes to 17 9 | # window size = 1 << WBITS - 16 10 | 11 | Brotli Meta-Block Header 12 | ======================== 13 | [0] 14 | 15 | 0 # ISLAST => false 16 | 17 | 0xe6 = 1110 0110 18 | 19 | 10 # MNIBBLES => 6 20 | 21 | 0x42 0x76 0x00 = 0100 0010 0111 0110 0000 0000 [1110 01] 22 | 23 | 1001 1101 1000 0000 0011 1001 = 24 | 25 | 0x9d 0x80 0x39 26 | # MLEN - 1 = 10321977 => MLEN = 10321978 27 | 28 | [0100 00] 29 | 30 | 0 # ISUNCOMPRESSED => false 31 | 32 | 0 # NBLTYPESL = 1 33 | 0 # NBLTYPESI = 1 34 | 0 # NBLTYPESD = 1 35 | 01 # NPOSTFIX = 1 36 | 37 | 0x10 = 0001 0000 38 | 39 | 0000 # NDIRECT = 0 40 | 01 # CMODESL = [1] 41 | 0 # NTREESL = 1 42 | 0 # NTREESD = 1 43 | 44 | 0x01 = 0000 0001 45 | 46 | # prefix code literals 47 | 01 # simple prefix code 48 | 00 # NSYM - 1 = 0 => NSYM == 1 49 | 50 | 0x1c = 0001 1100 [0000] 51 | 52 | 1100 0000 # symbol 0xc0 = 192 53 | 54 | # prefix code insert and copy lengths 55 | 01 # simple prefix code 56 | 00 # NSYM - 1 = 0 => NSYM == 1 57 | 58 | 0x24 0x24 = 0010 0100 0010 0100 59 | 60 | 00 0010 0100 # symbol 36 61 | 62 | # prefix code distances 63 | # alpabet size 16 + 96 = 112 64 | [0010 01] 65 | 66 | 01 # simple prefix code 67 | 10 # NSYM - 1 = 2 => NSYM == 3 68 | 69 | 0xd7 0xd7 0x3c = 1101 0111 1101 0111 0011 1100 [00] 70 | 71 | 111 0000 # symbol 0x70 = 112 72 | 011 1001 # symbol 0x39 = 57 73 | 111 1101 # symbol 0x7d = 125 74 | 75 | Stream should be rejected as invalid here. 76 | Symbol 125 >= alphabet size 112 77 | 78 | 79 | -------------------------------------------------------------------------------- /docs/analysis.afl-01.compressed.txt: -------------------------------------------------------------------------------- 1 | Analysis of afl-01.compressed: 2 | 0x1b 0x30 0x30 0x30 0x24 0x30 0xa2 0xcf 0x64 0x04 0x00 0xf1 … 0xfe 0xff 0xff … 0xff 3 | 0xff 0xff 0xff 0xff 0xa2 0xa2 0xb3 0xc3 0xa2 0xa2 0xa2 0xa2 0xa2 0xa2 0xa2 0xa2 4 | 0xa2 0xa2 0xa2 0x93 0xa2 0xa2 0xac 0x9b 0x7a 0xbd 0xe1 0x97 0x9d 0x10 0x8e 0xc2 5 | 0x82 0x36 0x0e 0x9c 0xe0 0x7f 0x03 0xf7 0x8b 0x9e 0x38 0xe6 0xc3 0x90 0x03 0xc3 6 | 0xcc 0xbd 0xc2 0xda 0x66 0xf1 0xfe 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 7 | 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xef 0xff 0xff 8 | 0xff 0xff 0xff 0xff 0x1e 9 | 10 | Brotli Stream Header 11 | ==================== 12 | 0x1b = 0001 1011 13 | 14 | 1011 # WBITS => decodes to 22 15 | # window size = 1 << WBITS - 16 16 | 17 | Brotli Meta-Block Header 18 | ======================== 19 | [0001] 20 | 21 | 1 # ISLAST => true 22 | 0 # ISLASTEMPTY => false 23 | 00 # MNIBBLES => 4 24 | 25 | 0x30 0x30 # MLEN - 1 = 12336 => MLEN = 12337 26 | 27 | 0x30 = 0011 0000 28 | 29 | 0 # NBLTYPESL = 1 30 | 0 # NBLTYPESI = 1 31 | 0 # NBLTYPESD = 1 32 | 10 # NPOSTFIX = 2 33 | 34 | 0x24 = 0010 0100 [001] 35 | 36 | 0001 # NDIRECT = 1 << 2 == 4 37 | 10 # CMODESL = [2] 38 | 0 # NTREESL = 1 39 | 0 # NTREESD = 1 40 | 41 | # prefix code literals 42 | 01 # simple prefix code 43 | 0x30 = 0011 0000 [0] 44 | 00 # NSYM - 1 = 0 => NSYM == 1 45 | 46 | 0xa2 = 1010 0010 [0011 000] 47 | 48 | 0001 1000 # symbol 0x18 = 24 49 | 50 | # prefix code insert and copy lengths 51 | 01 # simple prefix code 52 | 00 # NSYM - 1 = 0 => NSYM == 1 53 | 54 | 0xcf = 1100 1111 [101] 55 | 56 | 10 0111 1101 # symbol 0x027d = 637 57 | 58 | # prefix code distances 59 | # alpabet size 16 + 4 + 48 * 4 = 20 + 192 = 212 60 | # bit width = 8 61 | 0x64 = 0110 0100 [1] 62 | 63 | 01 # simple prefix code 64 | 10 # NSYM - 1 = 2 => NSYM == 3 65 | 66 | 0xf1 0x00 0x04 = 1111 0001 0000 0000 0000 0100 [0110 0] 67 | 68 | 1000 1100 # symbol 0x8c = 140 69 | 0000 0000 # symbol 0x00 = 0 70 | 0010 0000 # symbol 0x20 = 32 71 | 72 | [1111 0] 73 | 74 | [no bits consumed] # insert-and-copy-length code 637 75 | # insert length code = 23 76 | # copy length code = 13 77 | 78 | 0xff 0xff 0xfe = 1111 1111 1111 1111 1111 1110 [1111 0] 79 | 80 | 1111 1111 1111 1111 1101 1110 = 0xffffde 81 | # 24 extra bits for insert length = 16777182 82 | # => insert length = 22594 + 16777182 = 16799776 83 | 84 | Stream should be rejected as invalid here. 85 | Insert Length > MLEN 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /docs/analysis.afl-02.compressed.txt: -------------------------------------------------------------------------------- 1 | Analysis of afl-02.compressed: 2 | 0x12 0x1b 0x00 0x1e 0x11 0x00 0x05 0x09 0x21 0x51 … 0x51 … 0x00 0x05 0x04 0x8a 0x05 3 | 0xf5 0x21 0x1e 0x11 0x00 0x05 0x7b 0x21 0x00 0x05 0x14 0x52 4 | 5 | Brotli Stream Header 6 | ==================== 7 | 0x12 = 0001 0010 8 | 9 | 0 # WBITS => decodes to 16 10 | # window size = 1 << WBITS - 16 11 | 12 | Brotli Meta-Block Header 13 | ======================== 14 | 15 | 1 # ISLAST => true 16 | 0 # ISLASTEMPTY => false 17 | 10 # MNIBBLES => 6 18 | 19 | 0x1e 0x00 0x1b = 0001 1110 0000 0000 0001 1011 [000] 20 | 21 | 1111 0000 0000 0000 1101 1000 22 | 23 | 0xf0 0x00 0xd8 # MLEN - 1 = 15728856 => MLEN = 15728857 24 | 25 | 0x11 = 0001 0001 [000] 26 | 27 | 0 # NBLTYPESL = 1 28 | 0 # NBLTYPESI = 1 29 | 0 # NBLTYPESD = 1 30 | 01 # NPOSTFIX = 1 31 | 32 | 33 | 34 | 0100 # NDIRECT = 4 << 1 == 8 35 | 00 # CMODESL = [0] 36 | 37 | 0x00 = 0000 0000 38 | 39 | 0 # NTREESL = 1 40 | 0 # NTREESD = 1 41 | 42 | # prefix code literals 43 | 00 # complex prefix code, HSKIP 0 44 | 45 | 00 # code length 1 = 0 46 | 00 # code length 2 = 0 47 | 48 | 0x05 = 0000 0101 49 | 01 # code length 3 = 4 50 | 01 # code length 4 = 4 51 | 00 # code length 0 = 0 52 | 00 # code length 5 = 0 53 | 54 | 0x09 = 0000 1001 55 | 01 # code length 17 = 4 56 | 10 # code length 6 = 3 57 | 00 # code length 16 = 0 58 | 00 # code length 7 = 0 59 | 60 | 0x21 = 0010 0001 61 | 01 # code length 8 = 4 62 | 00 # code length 9 = 0 63 | 10 # code length 10 = 3 64 | 00 # code length 11 = 0 65 | 66 | 0x51 = 0101 0001 67 | 01 # code length 12 = 4 68 | 00 # code length 13 = 0 69 | 01 # code length 14 = 4 70 | 01 # code length 15 = 4 71 | 72 | Stream should be rejected as invalid here. 73 | 32 >> Codelength does not add up to 32 over all non-zero code lengths. 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /docs/analysis.afl-03.compressed.txt: -------------------------------------------------------------------------------- 1 | Analysis of afl-03.compressed: 2 | 0x12 0x1b 0x00 0x1e 0x11 0x04 0x43 0x05 0xf5 0x21 0x1e 0x11 0x10 0x05 0x05 0xd9 3 | 0x21 … 0x3d … 0x11 0x10 0x05 0xf5 0x21 0x00 0x05 0x78 0x78 0x78 0x78 0x21 0x00 0x05 4 | 0x78 0x4e 0x78 0x78 5 | 6 | Brotli Stream Header 7 | ==================== 8 | 0x12 = 0001 0010 9 | 10 | 0 # WBITS => decodes to 16 11 | # window size = 1 << WBITS - 16 12 | 13 | Brotli Meta-Block Header 14 | ======================== 15 | 16 | 1 # ISLAST => true 17 | 0 # ISLASTEMPTY => false 18 | 10 # MNIBBLES => 6 19 | 20 | 0x1e 0x00 0x1b = 0001 1110 0000 0000 0001 1011 [000] 21 | 22 | 1111 0000 0000 0000 1101 1000 23 | 24 | 0xf0 0x00 0xd8 # MLEN - 1 = 15728856 => MLEN = 15728857 25 | 26 | 0x11 = 0001 0001 [000] 27 | 28 | 0 # NBLTYPESL = 1 29 | 0 # NBLTYPESI = 1 30 | 0 # NBLTYPESD = 1 31 | 01 # NPOSTFIX = 1 32 | 0100 # NDIRECT = 4 << 1 == 8 33 | 00 # CMODESL = [0] 34 | 35 | 0x04 = 0000 0100 36 | 37 | 0 # NTREESL = 1 38 | 0 # NTREESD = 1 39 | 40 | # prefix code literals 41 | # alphabet size 256 42 | 01 # simple prefix code 43 | 00 # NSYM - 1 == 0 => NSYM == 1 44 | 45 | 0x43 = 0100 0011 [00] 46 | 47 | 0000 1100 # symbol 0x0c = 12 48 | 49 | # prefix code insert-and-copy lengths 50 | # alphabet size 704 51 | 01 # simple prefix code 52 | 53 | 0x05 = 0000 0101 54 | 55 | 01 # NSYM - 1 == 1 => NSYM == 2 56 | 57 | 0xf5 = 1111 0101 [0000 01] 58 | 59 | 01 0100 0001 # symbol 0x141 = 256 + 64 + 1 = 321 60 | 61 | 0x21 = 0010 0001 [1111] 62 | 63 | 10 0001 1111 # symbol 0x21f = 512 + 16 + 15 = 543 64 | 65 | 0x1e = 0001 1110 [00] 66 | 67 | # prefix code distances 68 | # alphabet size 16 + 8 + (48 << 1) = 24 + 96 = 120 69 | 00 # complex prefix code, HSKIP 0 70 | 71 | 10 # code length 1 = 3 72 | 0111 # code length 2 = 1 73 | 00 # code length 3 = 0 74 | 75 | 0x11 = 0001 0001 76 | 77 | 01 # code length 4 = 4 78 | 00 # code length 0 = 0 79 | 01 # code length 5 = 4 80 | 00 # code length 17 = 0 81 | 82 | 0x10 = 0001 0000 83 | 84 | 00 # code length 6 = 0 85 | 00 # code length 16 = 0 86 | 01 # code length 7 = 4 87 | 00 # code length 8 = 0 88 | 89 | 0x05 = 0000 0101 90 | 91 | 01 # code length 9 = 4 92 | 01 # code length 10 = 4 93 | 00 # code length 11 = 0 94 | 00 # code length 12 = 0 95 | 96 | 0x05 = 0000 0101 97 | 98 | 01 # code length 13 = 4 99 | 100 | [0000 01] 101 | 102 | 001 # code length code 1 = 1 103 | 0 # code length code 2 = 2 104 | 0 # code length code 2 = 2 105 | 106 | 0xd9 = 1101 1001 [0] 107 | 108 | // continue at section 9.3. Format of the meta-block data 109 | 110 | 0 # insert-and-copy length code 321 111 | # insert length code = 8 112 | # copy length code = 9 113 | 01 # 2 extra bits insert length = 1 => 11 114 | 0 # 1 extra bit copy length = 0 => 12 115 | [no bits consumed] # 11 * literal 0x0c 116 | 11 # distance code 2 117 | 0 # insert-and-copy length code 321 118 | # insert length code = 8 119 | # copy length code = 9 120 | 11 # 2 extra bits insert length = 3 => 13 121 | 122 | 0x21 = 0010 0001 123 | 124 | 1 # 1 extra bit copy length = 1 => 13 125 | [no bits consumed] # 13 * literal 0x0c 126 | 0 # distance code 0 127 | 0 # insert-and-copy length code 321 128 | # insert length code = 8 129 | # copy length code = 9 130 | 00 # 2 extra bits insert length = 0 => 10 131 | 1 # 1 extra bit copy length = 1 => 13 132 | [no bits consumed] # 10 * literal 0x0c 133 | 0 # distance code 0 134 | 0 # insert-and-copy length code 321 135 | # insert length code = 8 136 | # copy length code = 9 137 | 138 | 0x3d = 0011 1101 139 | 140 | 01 # 2 extra bits insert length = 1 => 11 141 | 1 # 1 extra bit copy length = 1 => 13 142 | [no bits consumed] # 11 * literal 0x0c 143 | 11 # distance code 2 144 | 1 # insert-and-copy length code 543 145 | # insert length code = 8 146 | # copy length code = 9 147 | 148 | [Ending analysis here. It turns out that this file just keeps 149 | accumulating literals until it goes over the very high limit 150 | of mlean. That will always take a while.] 151 | 152 | -------------------------------------------------------------------------------- /docs/analysis.afl-04.compressed.txt: -------------------------------------------------------------------------------- 1 | Analysis of afl-04.compressed: 2 | 0x9d 0x82 0x82 0x82 0x00 0x20 0x82 0x82 0x82 0x82 … 0x82 … 0x82 0x00 0xe6 0x00 0xe2 3 | 0xe2 0xe2 0xe2 0xe2 0xe2 0xe2 0x00 0x00 0x00 0x82 0x82 0x80 0x00 0x0d 0x23 0x00 4 | 0x82 0x82 0x00 0x82 0x82 0x82 0x00 0x0d 0x9b 0x30 5 | 6 | Brotli Stream Header 7 | ==================== 8 | 0x9d = 1001 1101 9 | 10 | 1101 # WBITS => decodes to 23 11 | # window size = (1 << WBITS) - 16 12 | 13 | Brotli Meta-Block Header 14 | ======================== 15 | 16 | 1 # ISLAST => true 17 | 0 # ISLASTEMPTY => false 18 | 10 # MNIBBLES => 6 19 | 20 | 0x82 0x82 0x82 # MLEN - 1 = 8553090 => MLEN = 8553091 21 | 22 | 0x00 = 0000 0000 23 | 24 | 0 # NBLTYPESL = 1 25 | 0 # NBLTYPESI = 1 26 | 0 # NBLTYPESD = 1 27 | 00 # NPOSTFIX = 0 28 | 29 | 0x20 = 0010 0000 [000] 30 | 0000 # NDIRECT = 0 << 0 == 0 31 | 00 # CMODESL = [0] 32 | 0 # NTREESL = 1 33 | 0 # NTREESD = 1 34 | 35 | 0x82 = 1000 0010 [001] 36 | 37 | # prefix code literals 38 | # alphabet size 256 39 | 01 # simple prefix code 40 | 00 # NSYM - 1 == 0 => NSYM == 1 41 | 42 | 0x82 = 1000 0010 [1000 001] 43 | 44 | 0100 0001 # symbol 0x41 = 65 45 | 46 | # prefix code insert-and-copy lengths 47 | # alphabet size 704 48 | 01 # simple prefix code 49 | 00 # NSYM - 1 == 0 => NSYM == 1 50 | 51 | 0x82 = 1000 0010 [100] 52 | 53 | 00 0001 0100 # symbol 0x014 = 20 54 | 55 | 0x82 = 1000 0010 [1] 56 | 57 | # prefix code distances 58 | # alphabet size 16 + 0 + (48 << 0) = 64 59 | 01 # simple prefix code 60 | 01 # NSYM - 1 == 1 => NSYM == 2 61 | 62 | 0x82 = 1000 0010 [1000 0] 63 | 64 | 01 0000 # symbol 0x10 = 16 65 | 00 0001 # symbol 0x01 = 1 66 | 67 | [1] 68 | 69 | # @NOTE loop starts here 70 | 71 | [no bits consumed] # insert-and-copy length code 20 72 | # insert length code = 2 73 | # copy length code = 4 74 | [no bits consumed] # 2 * literal 65 75 | [no bits consumed] # distance code implicitly 0 => distance = 4 76 | 77 | [This loop keeps going, inserting literals 65 until it exceeds MLEN. 78 | At that point, the stream must get rejected as invalid.] 79 | 80 | -------------------------------------------------------------------------------- /docs/analysis.frewsxcv.compressed.txt: -------------------------------------------------------------------------------- 1 | Analysis of frewsxcv.compressed: 2 | 0x1b 0x3f 0xff 0xff 0xdb 0x4f 0xe2 0x99 0x80 … 0x12 … 3 | 4 | Brotli Stream Header 5 | ==================== 6 | 0x1b = 0001 1011 7 | 8 | 1011 # WBITS => decodes to 22 9 | # window size = 1 << WBITS - 16 = 4194288 10 | 11 | Brotli Meta-Block Header 12 | ======================== 13 | [0001] 14 | 15 | 1 # ISLAST => true => this is the last meta Meta-Block 16 | 0 # ISLASTEMPTY => false 17 | 00 # MNIBBLES => 0 + 4 18 | 19 | 0xff 0x3f # MLEN - 1 = 65343 => MLEN = 65344 20 | 21 | 0xff = 1111 1111 22 | 23 | 1111 # NBLTYPESL => 129-256 24 | 25 | 0xdb = 1101 1011 [1111] 26 | 27 | 011 1111 # extra bits 15 + 16 + 32 = 63 => NBLTYPESL = 192 28 | 29 | [1101 1] 30 | 31 | 11 # Complex prefix code, HSKIP == 3 32 | 33 | 01 # code length 4 == 3 34 | 35 | 0x4f = 0100 1111 [1] 36 | 37 | 1111 # code length 0 == 5 38 | 10 # code length 5 == 4 39 | 01 # code length 17 == 3 40 | 41 | 0xe2 = 1110 0010 [0] 42 | 43 | 00 # code length 6 == 0 44 | 10 # code length 16 == 4 45 | 00 # code length 7 == 0 46 | 47 | 0x99 = 1001 1001 [111] 48 | 49 | 1111 # code length 8 == 5 50 | 00 # code length 9 == 0 51 | 110 # code length 10 == 2 52 | 01 # code length 11 == 3 53 | 54 | 0x80 = 1000 0000 55 | 56 | 00 # code length 12 == 0 57 | 00 # code length 13 == 0 58 | 00 # code length 14 == 0 59 | 01 # code length 15 == 3 60 | 61 | # Code Lengths = [5, 0, 0, 0, 3, 4, 0, 0, 5, 0, 2, 3, 0, 0, 0, 3, 4, 3] 62 | # Symbols = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17] 63 | 64 | # 0 65 | # / \ 66 | # left <-- / \ --> right 67 | # / \ 68 | # / \ 69 | # / \ 70 | # / \ 71 | # / \ 72 | # / \ 73 | # / \ 74 | # / \ 75 | # * * 76 | # / \ / \ 77 | # / \ / \ 78 | # / \ / \ 79 | # / \ / \ 80 | # *10 * * * 81 | # / \ / \ / \ 82 | # / \ / \ / \ 83 | # *4 *11 *15 *17 * * 84 | # / \ / \ 85 | # 5 16 * * 86 | # / \ 87 | # 0 8 88 | 0x12 = 0001 0010 89 | 90 | 010 # code length code 4 91 | 010 # code length code 4 92 | 00 # code length code 10 93 | 94 | [input stream ends, should be rejected as invalid here] 95 | 96 | -------------------------------------------------------------------------------- /docs/analysis_alice29.txt.compressed.txt: -------------------------------------------------------------------------------- 1 | Analysis of alice29.txt.compressed: 2 | 0x5b 0x18 0x52 0x12 0x45 … 0xa0 … 0x3b 0x1c 0xab 0x40 0x0f 0x7d 0x2e 0x8a 0x1a 0xd2 … 3 | 4 | Brotli Stream Header 5 | ==================== 6 | 0x5b = 0101 1011 7 | 8 | 1011 # WBITS => decodes to 22 9 | # window size = 1 << WBITS - 16 = 4194288 10 | 11 | Brotli Meta-Block Header 12 | ======================== 13 | [0101] 14 | 15 | 1 # ISLAST => true => this is the last meta Meta-Block 16 | 0 # ISLASTEMPTY => false => the Meta-Block is not empty 17 | 18 | 01 # MNIBBLES => 1 => MNIBBLES = 5 19 | 20 | 0x18 0x52 0x12 = 0001 1000 0101 0010 0001 0010 21 | 22 | 1000 0101 0010 0001 0010 23 | # MLEN - 1 = 152088 => MLEN = 152089 24 | 25 | 0001 # NBLTYPESL => 2 26 | 27 | 0x45 = 0100 0101 28 | 29 | 01 # simple prefix code 30 | 01 # NSYM - 1 = 1 => NSYM = 2 31 | 00 # Symbol 00 32 | 01 # Symbol 01 33 | # Simple Prefix Tree = 34 | # 0 35 | # / 36 | # \ 37 | # 1 38 | 39 | 0xa0 = 1010 0000 40 | 00 # complex prefix code, HSKIP = 0 41 | 00 # Codelength Symbol = 0 42 | 01 # Codelength Symbol = 3 43 | 01 # Codelength Symbol = 3 44 | 0x3b = 0011 1011 45 | 110 # Codelength Symbol = 2 46 | 1110 # Codelength Symbol = 1 47 | # Checksum 32 reached here, code lengths come out as [0, 3, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 48 | # rearrange to [1, 0, 3, 3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] for symbols 0...17 49 | # 0 50 | # / 4 51 | # \/ 2 52 | # \/ 53 | # \ 54 | # 3 55 | 0x1c = 0001 1100 [0] 56 | 0 # Symbol 0 57 | 0 # Symbol 0 58 | 0 # Symbol 0 59 | 111 # Symbol 3 60 | 0 # Symbol 0 61 | 0 # Symbol 0 62 | 0 # Symbol 0 63 | 0xab = 1010 1011 64 | 110 # Symbol 2 65 | 10 # Symbol 4 66 | 10 # Symbol 4 67 | 0x40 = 0100 0000 [1] 68 | 10 # Symbol 4 69 | 0 # Symbol 0 70 | 0 # Symbol 0 71 | 0 # Symbol 0 72 | 0 # Symbol 0 73 | 0 # Symbol 0 74 | 10 # Symbol 4 75 | 0x0f = 0000 1111 76 | 111 # Symbol 3 77 | 10 # Symbol 4 78 | 0 # Symbol 0 79 | 0 # Symbol 0 80 | 0 # Symbol 0 81 | 0x7d = 0111 1101 82 | 10 # Symbol 4 83 | 111 # Symbol 3 84 | # Checksum 32768, Code lengths come out to [0, 0, 0, 3, 0, 0, 0, 2, 4, 4, 4, 0, 0, 0, 0, 0, 4, 3, 4, 0, 0, 0, 4, 3] 85 | 86 | # 7 87 | # / 3 88 | # /\/ 89 | # \ \ 90 | # \ 17 23 91 | # \ / 8 92 | # \/\/ 93 | # \ \ 94 | # \ 9 10 95 | # \ / 96 | # \/\ 97 | # \ 16 98 | # \ 18 99 | # \/ 100 | # \ 101 | # 22 102 | 0x2e = 0010 1110 [011] 103 | 1100 # block count code 10, base length 81, extra bits 4 104 | 0111 # extra bits = 7 => block count = 88 -------------------------------------------------------------------------------- /docs/analysis_asyoulik.txt.compressed.txt: -------------------------------------------------------------------------------- 1 | Analysis of asyoulik.txt.compressed: 2 | 0x5b 0xfa 0xe8 0x11 … 0x51 … 0xc9 0xec 0xab 0x8a 0xb4 0x9d 0x95 0x1e 0x7b 0xe0 0xab … 3 | 4 | Brotli Stream Header 5 | ==================== 6 | 0x5b = 0101 1011 7 | 8 | 1011 # WBITS => decodes to 22 9 | # window size = 1 << WBITS - 16 = 4194288 10 | 11 | Brotli Meta-Block Header 12 | ======================== 13 | [0101] 14 | 15 | 1 # ISLAST => true => this is the last meta Meta-Block 16 | 0 # ISLASTEMPTY => false => the Meta-Block is not empty 17 | 18 | 01 # MNIBBLES => 1 => MNIBBLES = 5 19 | 20 | 0x11 0xe8 0xfa = 0001 0001 1110 1000 1111 1010 21 | 22 | 0001 1110 1000 1111 1010 23 | # MLEN - 1 = 125178 => MLEN = 125179 24 | 25 | 0001 # NBLTYPESL => 2 26 | 27 | 0x51 = 0101 0001 28 | 29 | 01 # simple prefix code 30 | 00 # NSYM - 1 = 0 => NSYM = 1 31 | -------------------------------------------------------------------------------- /docs/analysis_empty.compressed.01.txt: -------------------------------------------------------------------------------- 1 | Analysis of empty.compressed: 2 | 0x81 0x01 3 | 4 | Brotli Stream Header 5 | ==================== 6 | 1000 0001 7 | 8 | 000 0001 # WBITS => decodes to 17 9 | # window size = 1 << WBITS - 16 = 131056 10 | 11 | Brotli Meta-Block Header 12 | ======================== 13 | 0000 0001 [1] 14 | 15 | 1 # ISLAST => true => this is the last meta Meta-Block 16 | 1 # ISLASTEMPTY => true => the Meta-Block is empty, stream ends at this bit -------------------------------------------------------------------------------- /docs/analysis_empty.compressed.02.txt: -------------------------------------------------------------------------------- 1 | Analysis of empty.compressed: 2 | 0xa1 0x01 3 | 4 | Brotli Stream Header 5 | ==================== 6 | 1010 0001 7 | 8 | 010 0001 # WBITS => decodes to 10 9 | # window size = 1 << WBITS - 16 = 1008 10 | 11 | Brotli Meta-Block Header 12 | ======================== 13 | 0000 0001 [1] 14 | 15 | 1 # ISLAST => true => this is the last meta Meta-Block 16 | 1 # ISLASTEMPTY => true => the Meta-Block is empty, stream ends at this bit -------------------------------------------------------------------------------- /docs/analysis_empty.compressed.15.txt: -------------------------------------------------------------------------------- 1 | Analysis of empty.compressed: 2 | 0x1a 3 | 4 | Brotli Stream Header 5 | ==================== 6 | 0001 1010 7 | 8 | 0 # WBITS => decodes to 16 9 | # window size = 1 << WBITS - 16 = 65520 10 | 11 | Brotli Meta-Block Header 12 | ======================== 13 | 0001 101 14 | 15 | 1 # ISLAST => true => this is the last meta Meta-Block 16 | 0 # ISLASTEMPTY => false => the Meta-Block is not empty 17 | 11 # MNIBBLES => 3 => MNIBBLES == 0 => 18 | # Meta-Block is empty, i.e. does not generate 19 | # uncompressed bytes 20 | 0 # reserved bit, MUST be zero 21 | 00 # MSKIPBYTES => 0 22 | End of Stream -------------------------------------------------------------------------------- /docs/analysis_empty.compressed.16.txt: -------------------------------------------------------------------------------- 1 | Analysis of empty.compressed: 2 | 0x81 0x16 0x00 0x58 3 | 4 | Brotli Stream Header 5 | ==================== 6 | 0x81 = 1000 0001 7 | 8 | 000 0001 # WBITS => decodes to 17 9 | # window size = 1 << WBITS - 16 = 131056 10 | 11 | Brotli Meta-Block Header 12 | ======================== 13 | 0x16 = 0001 0110 [1] 14 | 15 | 1 # ISLAST => true => this is the last meta Meta-Block 16 | 0 # ISLASTEMPTY => false => the Meta-Block is not empty 17 | 11 # MNIBBLES => 3 => MNIBBLES == 0 => 18 | # Meta-Block is empty, i.e. does not generate 19 | # uncompressed bytes 20 | 0 # reserved bit, MUST be zero 21 | 01 # MSKIPBYTES => 1 22 | 23 | 0x00 = 0000 0000 [000] 24 | 25 | 0000 0000 # MSKIPLEN - 1 => MSKIPLEN == 1 26 | 27 | [000] # fill bits until next byte boundary 28 | # MUST be zero 29 | 30 | 31 | End of Stream -------------------------------------------------------------------------------- /docs/analysis_empty.compressed.17.txt: -------------------------------------------------------------------------------- 1 | Analysis of empty.compressed.17: 2 | 0x01 0x03 0x06 [0x06 repeated "many times"] 0x03 3 | 4 | Brotli Stream Header 5 | ==================== 6 | 0x01 = 0000 0001 7 | 8 | 000 0001 # WBITS => decodes to 17 9 | # window size = 1 << WBITS - 16 = 131056 10 | 11 | Brotli Meta-Block Header 12 | ======================== 13 | 0x03 = 0000 0011 [0] 14 | 15 | 0 # ISLAST => false => this is not the last meta Meta-Block 16 | 11 # MNIBBLES => 3 => MNIBBLES == 0 => 17 | # Meta-Block is empty, i.e. does not generate 18 | # uncompressed bytes 19 | 0 # reserved bit, MUST be zero 20 | 00 # MSKIPBYTES => 0 21 | 22 | [000] # fill bits until next byte boundary 23 | # MUST be zero 24 | 25 | Brotli Meta-Block Header [repeated] 26 | ======================== 27 | 0x06 = 0000 0110 28 | 29 | 0 # ISLAST => false => this is not the last meta Meta-Block 30 | 11 # MNIBBLES => 3 => MNIBBLES == 0 => 31 | # Meta-Block is empty, i.e. does not generate 32 | # uncompressed bytes 33 | 0 # reserved bit, MUST be zero 34 | 00 # MSKIPBYTES => 0 35 | 36 | [00] # fill bits until next byte boundary 37 | # MUST be zero 38 | 39 | Brotli Meta-Block Header 40 | ======================== 41 | 0x03 = 0000 0011 42 | 43 | 1 # ISLAST => true => this is not the last meta Meta-Block 44 | 1 # ISLASTEMPTY => true => Meta-Block is empty, stream ends here 45 | 46 | [0000 00] # trailing bits 47 | # MUST be zero 48 | 49 | End of Stream -------------------------------------------------------------------------------- /docs/analysis_empty.compressed.txt: -------------------------------------------------------------------------------- 1 | Analysis of empty.compressed: 2 | 0x06 3 | 4 | Brotli Stream Header 5 | ==================== 6 | 0000 0110 7 | 8 | 0 # WBITS => decodes to 16 9 | # window size = 1 << WBITS - 16 = 65520 10 | 11 | Brotli Meta-Block Header 12 | ======================== 13 | [0000 011] 14 | 15 | 1 # ISLAST => true => this is the last meta Meta-Block 16 | 1 # ISLASTEMPTY => true => the Meta-Block is empty, stream ends at this bit -------------------------------------------------------------------------------- /docs/analysis_quickfox_repeated.txt: -------------------------------------------------------------------------------- 1 | Analysis of quickfox_repeated.compressed: 2 | 0x5b 0xff 0xaf 0x02 0xc0 0x22 0x79 0x5c 0xfb 0x5a 0x8c 0x42 0x3b 0xf4 0x25 0x55 0x19 0x5a 0x92 0x99 0xb1 0x35 c81 3 | 0x9e 0x9e 0x0a 0x7b 0x4b 0x90 0xb9 0x3c 0x98 0xc8 0x09 0x40 0xf3 0xe6 0xd9 0x4d 0xe4 0x6d 0x65 0x1b 0x27 0x87 0x13 0x5f 4 | 0xa6 0xe9 0x30 0x96 0x7b 0x3c 0x15 0xd8 0x53 0x1c 5 | 6 | Brotli Stream Header 7 | ==================== 8 | 0x5b = 0101 1011 9 | 10 | 1011 # WBITS => decodes to 22 11 | # window size = 1 << WBITS - 16 = 4194288 12 | 13 | Brotli Meta-Block Header 14 | ======================== 15 | [0101] 16 | 17 | 1 # ISLAST => true => this is the last meta Meta-Block 18 | 0 # ISLASTEMPTY => false => block is not empty 19 | 01 # MNIBBLES => 1 => MNIBBLES == 5 nibbles to represent the uncompressed length 20 | 21 | 0x02 0xaf 0xff = 0000 0010 1010 1111 1111 1111 22 | 23 | 0010 1010 1111 1111 1111 24 | # MLEN - 1 == 176127 => MLEN == 176128 25 | [0000] 26 | 27 | 0 # NBLTYPESL => 1 28 | 0 # NBLTYPESI => 1 29 | 0 # NBLTYPESD => 1 30 | 31 | 0xc0 = 1100 0000 [0] 32 | 33 | 00 # NPOSTFIX => 0 34 | 0000 # NDIRECT => 0 35 | 36 | 10 # Context Mode for literal block type 0 => 2 37 | 38 | 0x22 = 0010 0010 [1] 39 | 40 | 1010 # NTREESL => 5-8 + 2 extra bits 41 | 00 # 2 extra bits == 0 => NTREESL = 5 42 | 43 | 0x79 = 0111 1001 [001] 44 | 45 | 01001 # RLEMAX == 5 46 | 10 # HSKIP = 2 47 | # => code lengths [1: 0, 2: 0] 48 | 1110 # => code lengths [1: 0, 2: 0, 3: 1] sum = 32 >> 1 = 16 49 | 50 | 0x5c = 0101 1100 51 | 52 | 00 # => code lengths [1: 0, 2: 0, 3: 1, 4: 0] 53 | 1110 # => code lengths [1: 0, 2: 0, 3: 1, 4: 0, 0: 1] sum = 16 + 32 >> 1 = 16 + 16 = 32 => done with code lengths 54 | 55 | # codelengths = [0: 1, 1: 0, 2: 0, 3: 1, 4..17: 0] 56 | 57 | [01] 58 | 59 | 1 # codelength symbol == 3 => codelengths == [3] => sum = 32768 >> 3 = 4096 60 | 0 # codelength symbol == 0 => codelengths == [3, 0] => sum = 4096 61 | 62 | 0xfb = 1111 1011 63 | 1 # codelength symbol == 3 => codelengths == [3, 0, 3] => sum = 4096 + 32768 >> 3 = 4096 + 4096 = 8192 64 | 1 # codelength symbol == 3 => codelengths == [3, 0, 3, 3] => sum = 8192 + 32768 >> 3 = 8192 + 4096 = 12288 65 | 0 # codelength symbol == 0 => codelengths == [3, 0, 3, 3, 0] => sum = 12288 66 | 1 # codelength symbol == 3 => codelengths == [3, 0, 3, 3, 0, 3] => sum = 12288 + 32768 >> 3 = 12288 + 4096 = 16384 67 | 1 # codelength symbol == 3 => codelengths == [3, 0, 3, 3, 0, 3, 3] => sum = 16384 + 32768 >> 3 = 16384 + 4096 = 20480 68 | 1 # codelength symbol == 3 => codelengths == [3, 0, 3, 3, 0, 3, 3, 3] => sum = 20480 + 32768 >> 3 = 20480 + 4096 = 24576 69 | 1 # codelength symbol == 3 => codelengths == [3, 0, 3, 3, 0, 3, 3, 3, 3] => sum = 24576 + 32768 >> 3 = 24576 + 4096 = 28672 70 | 1 # codelength symbol == 3 => codelengths == [3, 0, 3, 3, 0, 3, 3, 3, 3, 3] => sum = 28672 + 32768 >> 3 = 28672 + 4096 = 32768 71 | 72 | 0x5a = 0101 1010 73 | 74 | 010 # run length code = 3 + 3 extra bits 75 | 011 # 3 extra bits == 3 => repeat a zero 2^3 + 3 = 11 times 76 | # context map literals = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 77 | 78 | 0x8c = 1000 1100 [01] 79 | 100 # symbol == 6 => value == 1 80 | # context map literals = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1] 81 | 82 | 011 # run length code 5 => 32 + 5 extra bits 83 | 84 | 0x42 = 0100 0010 [1000] 85 | 86 | 01000 # 5 extra bits == 8 => repeat a zero 2^5 + 8 = 40 times 87 | # context map literals = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 88 | # 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 89 | # 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 90 | # 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 91 | # 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 92 | # 0, 0,] 93 | 94 | 100 # symbol == 6 => value == 1 95 | # context map literals = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96 | # 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 97 | # 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 98 | # 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 99 | # 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100 | # 0, 0, 1,] 101 | 102 | 001 # run length code = 2 + 2 extra bits 103 | 104 | 0x3b = 0011 1011 [0] 105 | 106 | 10 # 2 extra bits = 2 => repeat a zero 2^2 + 2 = 6 times 107 | # context map literals = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 108 | # 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 109 | # 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 110 | # 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 111 | # 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 112 | # 0, 0, 1, 0, 0, 0, 0, 0, 0,] 113 | 101 # symbol == 7 => value == 2 114 | # context map literals = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 115 | # 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 116 | # 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 117 | # 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118 | # 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 119 | # 0, 0, 1, 0, 0, 0, 0, 0, 0, 2,] 120 | 110 # symbol == 8 => value == 3 121 | # context map literals = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 122 | # 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 123 | # 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 124 | # 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 125 | # 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 126 | # 0, 0, 1, 0, 0, 0, 0, 0, 0, 2, 127 | # 3,] 128 | 129 | 0xf4 = 1111 0100 [0] 130 | 131 | 000 # symbol == 0 => value == 0 132 | # context map literals = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 133 | # 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 134 | # 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 135 | # 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 136 | # 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 137 | # 0, 0, 1, 0, 0, 0, 0, 0, 0, 2, 138 | # 3, 0,] 139 | 101 # symbol == 7 => value == 2 140 | # context map literals = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 141 | # 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 142 | # 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 143 | # 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 144 | # 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 145 | # 0, 0, 1, 0, 0, 0, 0, 0, 0, 2, 146 | # 3, 0, 2, ] 147 | 111 # symbol == 9 => value == 4 148 | # context map literals = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 149 | # 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 150 | # 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 151 | # 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 152 | # 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 153 | # 0, 0, 1, 0, 0, 0, 0, 0, 0, 2, 154 | # 3, 0, 2, 4] 155 | # 64 is the size of the literal context map for NBLTYPESL == 1 156 | 157 | 0x5b 0xff 0xaf 0x02 0xc0 0x22 0x79 0x5c 0xfb 0x5a 0x8c 0x42 0x3b 0xf4 0x25 0x55 0x19 0x5a 0x92 0x99 0xb1 0x35 0xc8 0x19 158 | 0x9e 0x9e 0x0a 0x7b 0x4b 0x90 0xb9 0x3c 0x98 0xc8 0x09 0x40 0xf3 0xe6 0xd9 0x4d 0xe4 0x6d 0x65 0x1b 0x27 0x87 0x13 0x5f 159 | 0xa6 0xe9 0x30 0x96 0x7b 0x3c 0x15 0xd8 0x53 0x1c 160 | 161 | 0x25 = 0010 0101 162 | 163 | 1 # IMTF => true => we do an inverse move to front transformation on the context map 164 | # we assume that our implementation of inverse_move_to_front_transform() works correctly 165 | 166 | 0 # NTREESD => 1 167 | 01 # Simple Prefix Code #1 168 | 10 # NSYM - 1 == 2 => NSYM == 3 169 | 170 | 0x55 = 0101 0101 [00] 171 | 0101 0100 # Symbol #1 => 0x54 == 84 172 | 173 | 0x19 = 0001 1001 [01] 174 | 0110 0101 # Symbol #2 => 0x65 == 101 175 | 176 | 0x5a = 0101 1010 [00] 177 | 0110 1000 # Symbol #3 => 0x68 == 104 178 | 179 | 0x92 = 1001 0010 [01] 180 | 181 | 01 # Simple Prefix Code 182 | 10 # NSYM - 1 == 2 => NSYM == 3 183 | 184 | 0x99 = 1001 1001 [1001 00] 185 | 0110 0100 # Symbol #1 => 0x64 == 100 186 | 187 | 0xb1 = 1011 0001 [1001 10] 188 | 0110 0110 # Symbol #2 => 0x66 == 102 189 | 190 | 0x35 = 0011 0101 [1011 00] 191 | 0110 1100 # Symbol #3 => 0x6c == 108 192 | 193 | [0011 01] 194 | 01 # Simple Prefix Code 195 | 11 # NSYM - 1 == 3 => NSYM == 4 196 | 197 | 0xc8 = 1100 1000 [00] 198 | 0010 0000 # Symbol #1 => 0x20 == 32 199 | 200 | 0x19 = 0001 1001 [11] 201 | 0110 0111 # Symbol #2 => 0x67 => 103 202 | 203 | 0x9e = 1001 1110 [00] 204 | 0111 1000 # Symbol #3 => 0x78 => 120 205 | 206 | 0x9e = 1001 1110 [10] 207 | 0111 1010 # Symbol #4 => 0x7a => 122 208 | 209 | 0 # Tree Select => false => Code Lengths = [2, 2, 2, 2] 210 | 211 | 0x5b 0xff 0xaf 0x02 0xc0 0x22 0x79 0x5c 0xfb 0x5a 0x8c 0x42 0x3b 0xf4 0x25 0x55 0x19 0x5a 0x92 0x99 0xb1 0x35 0xc8 0x19 212 | 0x9e … 0x9e … 0x0a 0x7b 0x4b 0x90 0xb9 0x3c 0x98 0xc8 0x09 0x40 0xf3 0xe6 0xd9 0x4d 0xe4 0x6d 0x65 0x1b 0x27 0x87 0x13 0x5f 213 | 0xa6 0xe9 0x30 0x96 0x7b 0x3c 0x15 0xd8 0x53 0x1c 214 | 215 | /// Analysis ends prematurely here, because at this point, a bug in the implementation was found. 216 | /// That bug was the reason to start this fairly lengthy analysis. 217 | /// The bug in question was that for a simple prefix code, in the case of NSYM == 4, the tree select flag 218 | /// was being read _before_ the symbols, instead of after, which of course created all kinds of subtle havoc. 219 | 220 | 221 | End of Stream 222 | 223 | 224 | 225 | -------------------------------------------------------------------------------- /docs/analysis_x.compressed.00.txt: -------------------------------------------------------------------------------- 1 | Analysis of x.compressed.00: 2 | 0x00 0x00 0x10 0x58 0x03 3 | 4 | Brotli Stream Header 5 | ==================== 6 | 0x00 = 0000 0000 7 | 8 | 0 # WBITS => decodes to 16 9 | # window size = 1 << WBITS - 16 = 65520 10 | 11 | Brotli Meta-Block Header 12 | ======================== 13 | [0000 000] 14 | 15 | 0 # ISLAST => false => this is not the last meta Meta-Block 16 | 00 # MNIBBLES => 0 => MNIBBLES == 4 17 | 18 | 0x10 0x00 = 0001 0000 0000 0000 [0000] 19 | 20 | 0000 0000 0000 0000 21 | # MLEN - 1 == 0 => MLEN == 1 22 | 23 | [0001] 24 | 25 | 1 # ISUNCOMPRESSED => true 26 | 27 | 000 # ignore bits up to the next byte boundary 28 | 29 | 0x58 # literal 'X' 30 | 31 | 0x03 = 0000 0011 32 | 33 | 1 # ISLAST => true 34 | 1 # ISLASTEMPTY => true => brotli stream ends here 35 | 36 | [0000 00] # trailing bits 37 | # MUST be zero 38 | 39 | End of Stream -------------------------------------------------------------------------------- /docs/analysis_x.compressed.03.txt: -------------------------------------------------------------------------------- 1 | Analysis of x.compressed.03: 2 | 0xa1, 0x00, 0x00, 0x00, 0x00, 0x81, 0x15, 0x08, 0x04, 0x00, 3 | 4 | Brotli Stream Header 5 | ==================== 6 | 0xa1 = 1010 0001 7 | 8 | 010 0001 # WBITS => decodes to 10 9 | # window size = 1 << WBITS - 16 = 1008 10 | 11 | Brotli Meta-Block Header 12 | ======================== 13 | 0x00 = 0000 0000 [1] 14 | 15 | 1 # ISLAST => true => this is the last meta Meta-Block 16 | 0 # ISLASTEMPTY => false 17 | 00 # MNIBBLES => 0 => MNIBBLES == 4 18 | 19 | 0x00 0x00 = 0000 0000 0000 0000 [0000 0] 20 | 21 | 000 0000 0000 0000 0 22 | # MLEN - 1 == 0 => MLEN == 1 23 | 24 | [0000 0] 25 | 26 | 0 # NBLTYPESL => 1 27 | 0 # NBLTYPESI => 1 28 | 0 # NBLTYPESD => 1 29 | 00 # NPOSTFIX => 0 30 | 31 | 0x00 = 0000 0000 32 | 33 | 0000 # NDIRECT => 0 34 | 00 # Context mode for one literal block type => 0 35 | 0 # NTREESL => 1 36 | 0 # NTREESD => 1 37 | 38 | 0x81 = 1000 0001 39 | 40 | 01 # value => 1 => simple prefix code 41 | 00 # NSYM - 1 == 0 => NSYM == 1 42 | 43 | 0x15 = 0001 0101 [1000] 44 | 45 | 0101 1000 # 1 literal symbol (alphabet size 256 => 8-bit) 0x58 46 | 47 | [0001] 48 | 49 | 01 # value => 1 => simple prefix code 50 | 00 # NSYM - 1 == 0 => NSYM == 1 51 | 52 | 0x04 0x08 = 0000 0100 0000 1000 53 | 54 | 00 0000 1000 # 1 insert and copy length symbol (alphabet size 704 => 10-bit) 0x0008 55 | 56 | [0000 01] 57 | 58 | 01 # value => 1 => simple prefix code 59 | 00 # NSYM - 1 == 0 => NSYM == 1 60 | 61 | 0x00 = 0000 0000 [00] 62 | 63 | 0000 00 # 1 distance symbol (alphabet size (16 + NDIRECT + (48 << NPOSTFIX)) == 64 => 6-bit) 64 | 65 | [no bits consumed] # insert-and-copy-length-code 8 66 | # insert length code = 1 67 | # copy length code = 0 68 | [no bits consumed] # literal symbol 0x58 69 | 70 | [0000 00] # trailing bits 71 | # MUST be zero 72 | 73 | End of Stream -------------------------------------------------------------------------------- /docs/analysis_x.compressed.txt: -------------------------------------------------------------------------------- 1 | Analysis of x.compressed: 2 | 0x0b 0x00 0x80 0x58 0x03 3 | 4 | Brotli Stream Header 5 | ==================== 6 | 0x0b = 0000 1011 7 | 8 | 1011 # WBITS => decodes to 22 9 | # window size = 1 << WBITS - 16 = 4194288 10 | 11 | Brotli Meta-Block Header 12 | ======================== 13 | 0x00 = 0000 0000 [0000] 14 | 15 | 0 # ISLAST => false => this is not the last meta Meta-Block 16 | 00 # MNIBBLES => 0 => MNIBBLES == 4 => 17 | 18 | 0x80 = 1000 0000 [0000 0000 0] 19 | 20 | 0000 0000 0000 0000 # MLEN - 1 == 0 => MLEN == 1 21 | 1 # ISUNCOMPRESSED => true 22 | 23 | # ignore bits up to the next byte 24 | # boundary; we are already on the 25 | # boundary, so there is nothing 26 | # for us to ignore in this case 27 | # ignored bits MUST be zero 28 | 29 | 0x58 # MLEN (== 1) bytes of literal data 30 | 31 | Brotli Meta-Block Header 32 | ======================== 33 | 0x03 = 0000 0011 34 | 35 | 1 # ISLAST => true => this is the last meta Meta-Block 36 | 1 # ISLASTEMPTY => true => the Meta-Block is empty, stream ends at this bit 37 | 38 | [0000 00] # trailing bits 39 | # MUST be zero 40 | 41 | End of Stream -------------------------------------------------------------------------------- /docs/bench_notes.txt: -------------------------------------------------------------------------------- 1 | Before: 2 | 3 | test bench_alice ... bench: 11,801,719 ns/iter (+/- 1,348,880) 4 | test bench_bitstring_version_0 ... bench: 125 ns/iter (+/- 29) 5 | test bench_bitstring_version_1 ... bench: 148 ns/iter (+/- 84) 6 | test bench_bitstring_version_2 ... bench: 127 ns/iter (+/- 54) 7 | test bench_monkey ... bench: 97,598 ns/iter (+/- 13,658) 8 | 9 | After: 10 | 11 | test bench_alice ... bench: 11,603,086 ns/iter (+/- 1,120,652) 12 | test bench_bitstring_version_0 ... bench: 126 ns/iter (+/- 46) 13 | test bench_bitstring_version_1 ... bench: 146 ns/iter (+/- 62) 14 | test bench_bitstring_version_2 ... bench: 125 ns/iter (+/- 10) 15 | test bench_monkey ... bench: 96,182 ns/iter (+/- 14,372) 16 | -------------------------------------------------------------------------------- /docs/notes_afl.txt: -------------------------------------------------------------------------------- 1 | Create RAM disk for afl to write on, to avoid pummeling the SSD 2 | (see http://www.cipherdyne.org/blog/2014/12/ram-disks-and-saving-your-ssd-from-afl-fuzzing.html ) 3 | 4 | # mkdir /tmp/afl-ramdisk && chmod 777 /tmp/afl-ramdisk 5 | # mount -t tmpfs -o size=512M tmpfs /tmp/afl-ramdisk 6 | $ mv fwknop.git /tmp/afl-ramdisk 7 | $ cd /tmp/afl-ramdisk/fwknop.git/test/afl/ 8 | $ ./fuzzing-wrappers/server-digest-cache.sh 9 | 10 | Start parallel fuzzers in master/slave configuration: 11 | 12 | Master: 13 | 14 | afl-fuzz -i - -o afl-findings -M fuzzer01 -t 500 -m 250 ./target/release/main 15 | 16 | Slaves: 17 | 18 | afl-fuzz -i - -o afl-findings -S fuzzer02 -t 500 -m 250 target/release/main 19 | afl-fuzz -i - -o afl-findings -S fuzzer03 -t 500 -m 250 target/release/main 20 | afl-fuzz -i - -o afl-findings -S fuzzer04 -t 500 -m 250 target/release/main 21 | -------------------------------------------------------------------------------- /src/bitreader/mod.rs: -------------------------------------------------------------------------------- 1 | use std::error::Error; 2 | use std::fmt; 3 | use std::fmt::{ Display, Formatter }; 4 | use std::io; 5 | use std::io::{ BufReader, ErrorKind, Read }; 6 | use std::result::Result; 7 | 8 | /// Wrapper for a Reader, providing convenience methods to read the stream bit-by-bit. 9 | /// 10 | /// # Examples 11 | /// 12 | /// extern crate compression; 13 | /// 14 | /// use compression::bitreader::BitReader; 15 | /// use std::fs::File; 16 | /// 17 | /// let f = try!(File::open("filename")); 18 | /// let mut br = BitReader::new(f); 19 | /// let byte: u8 = br.read_u8().unwrap(); 20 | #[derive(Debug)] 21 | pub struct BitReader { 22 | inner: BufReader, 23 | bit_pos: u8, 24 | current_byte: Option, 25 | global_bit_pos: usize, 26 | } 27 | 28 | impl BitReader { 29 | /// Creates a BitReader from a Read. 30 | pub fn new(inner: R) -> BitReader { 31 | BitReader{ 32 | inner: BufReader::new(inner), 33 | bit_pos: 0, 34 | current_byte: None, 35 | global_bit_pos: 0, 36 | } 37 | } 38 | 39 | fn read_exact(&mut self, mut buf: &mut [u8]) -> io::Result<()> { 40 | while !buf.is_empty() { 41 | match self.inner.read(buf) { 42 | Ok(0) => break, 43 | Ok(n) => { let tmp = buf; buf = &mut tmp[n..]; } 44 | Err(ref e) if e.kind() == ErrorKind::Interrupted => {} 45 | Err(e) => return Err(e), 46 | } 47 | } 48 | if !buf.is_empty() { 49 | Err(io::Error::new(ErrorKind::Other, "EOF")) 50 | } else { 51 | Ok(()) 52 | } 53 | } 54 | 55 | /// Reads a u8 from the stream, reading exactly one byte, or, more precisely, 8 bits, which might 56 | /// not be aligned to byte boundaries. 57 | /// Returns a BitReaderError if the stream ends prematurely. 58 | pub fn read_u8(&mut self) -> Result { 59 | let mut buf = &mut [0u8]; 60 | 61 | // println!("bit pos = {:?}", self.global_bit_pos); 62 | 63 | match (self.bit_pos, self.current_byte, self.read_exact(buf)) { 64 | (_, Some(byte), Ok(())) => { 65 | self.current_byte = Some(buf[0]); 66 | self.global_bit_pos += 8; 67 | Ok((byte >> self.bit_pos) | (buf[0] << (8 - self.bit_pos))) 68 | }, 69 | (_, None, Ok(())) => { 70 | self.global_bit_pos += 8; 71 | Ok(buf[0]) 72 | }, 73 | (0, Some(byte), Err(_)) => { 74 | self.current_byte = None; 75 | self.global_bit_pos += 8; 76 | Ok(byte) 77 | }, 78 | (_, _, Err(e)) => if e.description() == "EOF" { 79 | Err(BitReaderError::EOF) 80 | } else { 81 | Err(BitReaderError::Unspecified) 82 | }, 83 | } 84 | } 85 | 86 | /// Reads a u8 from 4 bits. 87 | /// Returns a BitReaderError if the stream ends prematurely. 88 | pub fn read_u8_from_nibble(&mut self) -> Result { 89 | let mut buf = &mut [0u8]; 90 | 91 | // println!("bit pos = {:?}", self.global_bit_pos); 92 | 93 | match (self.bit_pos, self.current_byte) { 94 | (0, None) => match self.read_exact(buf) { 95 | Ok(()) => { 96 | self.global_bit_pos += 4; 97 | self.bit_pos = 4; 98 | self.current_byte = Some(buf[0]); 99 | Ok(buf[0] & 0x0f) 100 | }, 101 | Err(e) => if e.description() == "EOF" { 102 | Err(BitReaderError::EOF) 103 | } else { 104 | Err(BitReaderError::Unspecified) 105 | }, 106 | }, 107 | (0...3, Some(byte)) => { 108 | self.global_bit_pos += 4; 109 | self.bit_pos += 4; 110 | Ok((byte >> (self.bit_pos - 4)) & 0x0f) 111 | }, 112 | (4, Some(byte)) => { 113 | self.global_bit_pos += 4; 114 | self.bit_pos = 0; 115 | self.current_byte = None; 116 | Ok((byte >> 4) & 0x0f) 117 | }, 118 | (bit_pos @ 5...7, Some(byte)) => { 119 | match self.read_exact(buf) { 120 | Ok(()) => { 121 | self.global_bit_pos += 4; 122 | self.bit_pos = self.bit_pos - 4; 123 | self.current_byte = Some(buf[0]); 124 | Ok(((byte >> (bit_pos)) | (buf[0] << (8 - bit_pos))) & 0x0f) 125 | }, 126 | Err(e) => if e.description() == "EOF" { 127 | Err(BitReaderError::EOF) 128 | } else { 129 | Err(BitReaderError::Unspecified) 130 | }, 131 | } 132 | }, 133 | _ => unreachable!(), // confirmed unreachable, code controls bit_pos to have value 0...7 134 | } 135 | } 136 | 137 | /// Reads a u32 from n bits. 138 | /// Only supports little endian, i.e. the least significant bit comes first in the stream. 139 | /// Returns a BitReaderError if the stream ends prematurely, or if n exceeds the number of possible bits. 140 | pub fn read_u32_from_n_bits(&mut self, n: usize) -> Result { 141 | if n > 32 { 142 | return Err(BitReaderError::TooManyBitsForU32); 143 | } 144 | 145 | let mut my_u32 = 0; 146 | 147 | // println!("bit pos = {:?}", self.global_bit_pos); 148 | 149 | for i in 0..n { 150 | match self.read_bit() { 151 | Ok(true) => my_u32 = my_u32 | (1 << i), 152 | Ok(false) => {}, 153 | Err(_) => return Err(BitReaderError::Unspecified), 154 | } 155 | } 156 | 157 | Ok(my_u32) 158 | } 159 | 160 | /// Reads a u32 from n nibbles (4 bits). 161 | /// Only supports little endian, i.e. the least significant nibble comes first in the stream. 162 | /// Returns a BitReaderError if the stream ends prematurely, or if n exceeds the number of possible nibbles. 163 | pub fn read_u32_from_n_nibbles(&mut self, n: usize) -> Result { 164 | let mut my_u32 = 0; 165 | 166 | for i in 0..n { 167 | match self.read_u8_from_nibble() { 168 | Ok(my_u8) => my_u32 = my_u32 | ((my_u8 as u32) << (4 * i)), 169 | Err(e) => return Err(e), 170 | } 171 | } 172 | 173 | Ok(my_u32) 174 | } 175 | 176 | /// Reads one bit from the stream, returns a bool result. 177 | /// Returns a BitReaderError if the stream ends prematurely. 178 | pub fn read_bit(&mut self) -> Result { 179 | // println!("bit pos = {:?}", self.global_bit_pos); 180 | 181 | match (self.current_byte, self.bit_pos) { 182 | (Some(byte), bit_pos) => { 183 | self.bit_pos = (self.bit_pos + 1) % 8; 184 | self.global_bit_pos += 1; 185 | if self.bit_pos == 0 { 186 | self.current_byte = None; 187 | } 188 | Ok(byte >> bit_pos & 1 == 1) 189 | }, 190 | (None, _) => { 191 | let mut buf = &mut [0u8; 1]; 192 | match self.read_exact(buf) { 193 | Ok(()) => { 194 | self.current_byte = Some(buf[0]); 195 | self.bit_pos = 1; 196 | self.global_bit_pos += 1; 197 | Ok(buf[0] & 1 == 1) 198 | }, 199 | Err(_) => Err(BitReaderError::Unspecified), 200 | } 201 | } 202 | } 203 | } 204 | 205 | /// Reads one bit from the stream, returns a usize result. 206 | /// Returns a BitReaderError if the stream ends prematurely. 207 | pub fn read_bit_as_usize(&mut self) -> Result { 208 | // println!("bit pos = {:?}", self.global_bit_pos); 209 | 210 | match (self.current_byte, self.bit_pos) { 211 | (Some(byte), bit_pos) => { 212 | self.bit_pos = (self.bit_pos + 1) % 8; 213 | self.global_bit_pos += 1; 214 | if self.bit_pos == 0 { 215 | self.current_byte = None; 216 | } 217 | Ok((byte as usize) >> bit_pos & 1) 218 | }, 219 | (None, _) => { 220 | let mut buf = &mut [0u8; 1]; 221 | match self.read_exact(buf) { 222 | Ok(()) => { 223 | self.current_byte = Some(buf[0]); 224 | self.bit_pos = 1; 225 | self.global_bit_pos += 1; 226 | Ok((buf[0] as usize) & 1) 227 | }, 228 | Err(_) => Err(BitReaderError::Unspecified), 229 | } 230 | } 231 | } 232 | } 233 | 234 | /// Reads a u8 from n bits from the stream. 235 | /// Returns a BitReaderError if the stream ends prematurely, or if n exceeds the 236 | /// possible number of bits. 237 | pub fn read_u8_from_n_bits(&mut self, n: usize) -> Result { 238 | if n > 8 { 239 | return Err(BitReaderError::TooManyBitsForU8); 240 | } 241 | 242 | let mut my_u8 = 0; 243 | 244 | for i in 0..n { 245 | match self.read_bit() { 246 | Ok(true) => my_u8 = my_u8 | (1 << i), 247 | Ok(false) => {}, 248 | Err(_) => return Err(BitReaderError::Unspecified), 249 | } 250 | } 251 | 252 | Ok(my_u8) 253 | } 254 | 255 | /// Reads u8 from bits up to the next byte boundary. 256 | /// Returns a BitReaderError if the stream ends prematurely. 257 | pub fn read_u8_from_byte_tail(&mut self) -> Result { 258 | let bit_pos = self.bit_pos.clone(); 259 | 260 | if bit_pos == 0 { 261 | 262 | Ok(0) 263 | } else { 264 | 265 | self.read_u8_from_n_bits(8 - bit_pos as usize) 266 | } 267 | } 268 | 269 | /// Reads a u16 from n bits from the stream. 270 | /// Returns a BitReaderError if the stream ends prematurely, or if n exceeds the 271 | /// possible number of bits. 272 | pub fn read_u16_from_n_bits(&mut self, n: usize) -> Result { 273 | if n > 16 { 274 | return Err(BitReaderError::TooManyBitsForU16); 275 | } 276 | 277 | let mut my_u16 = 0; 278 | 279 | for i in 0..n { 280 | match self.read_bit() { 281 | Ok(true) => my_u16 = my_u16 | (1 << i), 282 | Ok(false) => {}, 283 | Err(_) => return Err(BitReaderError::Unspecified), 284 | } 285 | } 286 | 287 | Ok(my_u16) 288 | } 289 | 290 | /// Reads a vector of u8 of a given length. 291 | /// Returns a BitReaderError if the stream ends prematurely. 292 | pub fn read_fixed_length_string(&mut self, len: usize) -> Result, BitReaderError> { 293 | let mut my_string = Vec::with_capacity(len); 294 | 295 | for _ in 0..len { 296 | match self.read_u8() { 297 | Ok(byte) => my_string.push(byte), 298 | Err(_) => return Err(BitReaderError::Unspecified), 299 | } 300 | } 301 | 302 | Ok(my_string) 303 | } 304 | } 305 | 306 | /// Error types that can be returned by the decompressor 307 | #[derive(Debug, Clone, PartialEq, Copy)] 308 | pub enum BitReaderError { 309 | /// Unspecified error 310 | Unspecified, 311 | /// Tried to read u8 from more than 8 bits. 312 | TooManyBitsForU8, 313 | /// Tried to read u16 from more than 16 bits. 314 | TooManyBitsForU16, 315 | /// Tried to read u32 from more than 32 bits. 316 | TooManyBitsForU32, 317 | /// Unexpected end of file 318 | EOF, 319 | } 320 | 321 | impl Display for BitReaderError { 322 | fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { 323 | fmt.write_str(self.description()) 324 | } 325 | } 326 | 327 | impl Error for BitReaderError { 328 | fn description(&self) -> &str { 329 | match *self { 330 | BitReaderError::TooManyBitsForU8 => "Tried reading u8 from more than 8 bits", 331 | BitReaderError::TooManyBitsForU16 => "Tried reading u16 from more than 16 bits", 332 | BitReaderError::TooManyBitsForU32 => "Tried reading u32 from more than 32 bits", 333 | BitReaderError::EOF => "EOF", 334 | _ => "Generic error", 335 | } 336 | } 337 | } 338 | 339 | mod tests { 340 | #[test] 341 | fn should_read_one_u8() { 342 | use super::*; 343 | use std::io::Cursor; 344 | 345 | let expected = 0x1f; 346 | let mut br = BitReader::new(Cursor::new(vec![expected, 0x8b])); 347 | 348 | match br.read_u8() { 349 | Ok(byte) => assert_eq!(expected, byte), 350 | Err(_) => panic!("Should have read one byte"), 351 | } 352 | } 353 | 354 | #[test] 355 | fn should_read_two_u8() { 356 | use super::*; 357 | use std::io::Cursor; 358 | 359 | let (expected0, expected1) = (0x1f, 0x8b); 360 | let mut br = BitReader::new(Cursor::new(vec![expected0, expected1])); 361 | 362 | match (br.read_u8(), br.read_u8()) { 363 | (Ok(my_u8_0), Ok(my_u8_1)) => assert_eq!((expected0, expected1), (my_u8_0, my_u8_1)), 364 | _ => panic!("Should have read two bytes"), 365 | } 366 | } 367 | 368 | #[test] 369 | fn should_read_one_set_bit() { 370 | use super::*; 371 | use std::io::Cursor; 372 | 373 | let mut br = BitReader::new(Cursor::new(vec![3])); 374 | 375 | match br.read_bit() { 376 | Ok(my_bit) => assert!(my_bit), 377 | _ => panic!("Should have read one set bit"), 378 | } 379 | } 380 | 381 | #[test] 382 | fn should_read_some_bits() { 383 | use super::*; 384 | use std::io::Cursor; 385 | 386 | let mut br = BitReader::new(Cursor::new(vec![134, 1])); 387 | 388 | match (br.read_bit(), br.read_bit(), br.read_bit(), br.read_bit(), br.read_bit(), 389 | br.read_bit(), br.read_bit(), br.read_bit(), br.read_bit(), br.read_bit()) { 390 | (Ok(my_bit_0), Ok(my_bit_1), Ok(my_bit_2), Ok(my_bit_3), Ok(my_bit_4), 391 | Ok(my_bit_5), Ok(my_bit_6), Ok(my_bit_7), Ok(my_bit_8), Ok(my_bit_9)) => { 392 | assert!(!my_bit_0); 393 | assert!(my_bit_1); 394 | assert!(my_bit_2); 395 | assert!(!my_bit_3); 396 | assert!(!my_bit_4); 397 | assert!(!my_bit_5); 398 | assert!(!my_bit_6); 399 | assert!(my_bit_7); 400 | assert!(my_bit_8); 401 | assert!(!my_bit_9); 402 | }, 403 | _ => panic!("Should have read 10 bits"), 404 | } 405 | } 406 | 407 | #[test] 408 | fn should_read_u8_after_bit() { 409 | use super::*; 410 | use std::io::Cursor; 411 | 412 | let mut br = BitReader::new(Cursor::new(vec![0b10001101, 0b00010101])); 413 | 414 | match (br.read_bit(), br.read_u8()) { 415 | (Ok(my_bit), Ok(my_u8)) => { 416 | assert!(my_bit); 417 | assert_eq!(0b11000110, my_u8); 418 | }, 419 | _ => panic!("Should have read one set bit and one u8"), 420 | } 421 | } 422 | 423 | #[test] 424 | fn should_read_fixed_length_string() { 425 | use super::*; 426 | use std::io::Cursor; 427 | 428 | let mut br = BitReader::new(Cursor::new(vec![ 429 | 0x78, 0x78, 0x78, 0x78, 0x78, 430 | 0x79, 0x79, 0x79, 0x79, 0x79, 431 | 0x2e, 0x74, 0x78, 0x74, 0x00, 432 | 0x78, 0x78, 0x78, 0x78, 0x78, 433 | 0x79, 0x79, 0x79, 0x79, 0x79, 434 | 0x2e, 0x74, 0x78, 0x74, 0x00, 435 | ])); 436 | 437 | match br.read_fixed_length_string(14) { 438 | Ok(my_vec) => assert_eq!("xxxxxyyyyy.txt", &(String::from_utf8(my_vec).unwrap())), 439 | _ => panic!("Should have read fixed-length string"), 440 | } 441 | } 442 | 443 | #[test] 444 | fn should_read_29u8_from_5_bits() { 445 | use super::*; 446 | use std::io::Cursor; 447 | 448 | let mut br = BitReader::new(Cursor::new(vec![157])); 449 | 450 | match br.read_u8_from_n_bits(5) { 451 | Ok(my_u8) => assert_eq!(29, my_u8), 452 | _ => panic!("Should have read 29u8"), 453 | } 454 | } 455 | 456 | #[test] 457 | fn should_read_3784u16_from_11_bits() { 458 | use super::*; 459 | use std::io::Cursor; 460 | 461 | let mut br = BitReader::new(Cursor::new(vec![0b11001000, 0b11111110])); 462 | 463 | match br.read_u16_from_n_bits(11) { 464 | Ok(my_u16) => assert_eq!(1736, my_u16), 465 | _ => panic!("Should have read 3784u16"), 466 | } 467 | } 468 | 469 | #[test] 470 | fn should_read_19u8_from_byte_tail() { 471 | use super::*; 472 | use std::io::Cursor; 473 | 474 | let mut br = BitReader::new(Cursor::new(vec![0b10011101])); 475 | let _ = br.read_bit(); 476 | let _ = br.read_bit(); 477 | let _ = br.read_bit(); 478 | 479 | match br.read_u8_from_byte_tail() { 480 | Ok(my_u8) => assert_eq!(19, my_u8), 481 | _ => panic!("Should have read 19u8"), 482 | } 483 | } 484 | 485 | #[test] 486 | fn should_read_10u8_from_nibble() { 487 | use super::*; 488 | use std::io::Cursor; 489 | 490 | let mut br = BitReader::new(Cursor::new(vec![0b11010101])); 491 | let _ = br.read_bit(); 492 | let _ = br.read_bit(); 493 | let _ = br.read_bit(); 494 | 495 | match br.read_u8_from_nibble() { 496 | Ok(my_u8) => assert_eq!(10, my_u8), 497 | _ => panic!("Should have read 10u8"), 498 | } 499 | } 500 | 501 | #[test] 502 | fn should_read_10u8_nibble_twice() { 503 | use super::*; 504 | use std::io::Cursor; 505 | 506 | let mut br = BitReader::new(Cursor::new(vec![0b10101010])); 507 | 508 | match br.read_u8_from_nibble() { 509 | Ok(my_u8) => assert_eq!(10, my_u8), 510 | _ => panic!("Should have read 10u8"), 511 | } 512 | 513 | match br.read_u8_from_nibble() { 514 | Ok(my_u8) => assert_eq!(10, my_u8), 515 | _ => panic!("Should have read 10u8"), 516 | } 517 | } 518 | 519 | #[test] 520 | fn should_read_7u8_nibble_four_times() { 521 | use super::*; 522 | use std::io::Cursor; 523 | 524 | let mut br = BitReader::new(Cursor::new(vec![0b11101111, 0b11101110, 0b11101110])); 525 | let _ = br.read_bit(); 526 | 527 | match br.read_u8_from_nibble() { 528 | Ok(my_u8) => assert_eq!(7, my_u8), 529 | _ => panic!("Should have read 7u8"), 530 | } 531 | 532 | match br.read_u8_from_nibble() { 533 | Ok(my_u8) => assert_eq!(7, my_u8), 534 | _ => panic!("Should have read 7u8"), 535 | } 536 | 537 | match br.read_u8_from_nibble() { 538 | Ok(my_u8) => assert_eq!(7, my_u8), 539 | _ => panic!("Should have read 7u8"), 540 | } 541 | 542 | match br.read_u8_from_nibble() { 543 | Ok(my_u8) => assert_eq!(7, my_u8), 544 | _ => panic!("Should have read 7u8"), 545 | } 546 | } 547 | 548 | #[test] 549 | fn should_read_524527u32_from_5_nibbles() { 550 | use super::*; 551 | use std::io::Cursor; 552 | 553 | let mut br = BitReader::new(Cursor::new(vec![0b1110_1111, 0, 0b1110_1000])); 554 | 555 | match br.read_u32_from_n_nibbles(5) { 556 | Ok(my_u32) => assert_eq!(524527, my_u32), 557 | _ => panic!("Should have read 524527u32"), 558 | } 559 | } 560 | } 561 | -------------------------------------------------------------------------------- /src/huffman/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod tree; 2 | 3 | fn bit_string_from_code_and_length(code: usize, len: usize) -> Vec { 4 | let mut bits = vec![false; len]; 5 | 6 | for i in 0..len { 7 | bits[len - i - 1] = (code >> i) & 1 == 1; 8 | } 9 | 10 | bits 11 | } 12 | 13 | #[test] 14 | fn should_honor_leading_zeroes() { 15 | assert_eq!(vec![false, false], bit_string_from_code_and_length(0b00, 2)); 16 | assert_eq!(vec![false, true, true], bit_string_from_code_and_length(0b011, 3)); 17 | } 18 | 19 | pub fn codes_from_lengths_and_symbols(lengths: &[usize], symbols: &[u16]) -> tree::Tree { 20 | let max_length = lengths.iter().fold(0, |acc, &len| if len > acc { len } else { acc }); 21 | let mut bl_count = vec![0; max_length + 1]; 22 | for &len in lengths { 23 | bl_count[len] += 1; 24 | } 25 | 26 | let mut code = 0; 27 | let mut next_code = vec![0; max_length + 1]; 28 | for bits in 1..max_length + 1 { 29 | code = (code + bl_count[bits - 1]) << 1; 30 | next_code[bits] = code; 31 | } 32 | 33 | let mut codes = tree::Tree::with_max_depth(max_length); 34 | for i in 0..lengths.len() { 35 | let len = lengths[i]; 36 | if len > 0 || max_length == 0 { 37 | codes.insert(&bit_string_from_code_and_length(next_code[len], len), symbols[i]); 38 | next_code[len] += 1; 39 | } 40 | } 41 | 42 | codes 43 | } 44 | 45 | pub fn codes_from_lengths(lengths: &[usize]) -> tree::Tree { 46 | let symbols = (0..lengths.len() as u16).collect::>(); 47 | 48 | codes_from_lengths_and_symbols(lengths, &symbols) 49 | } 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /src/huffman/tree/mod.rs: -------------------------------------------------------------------------------- 1 | use ::bitreader::BitReader; 2 | use std::io::Read; 3 | 4 | pub type Symbol = u16; 5 | 6 | #[derive(Debug, Clone, PartialEq)] 7 | pub struct Tree { 8 | buf: Vec>, 9 | len: usize, 10 | last_symbol: Option, 11 | } 12 | 13 | // Index structure in self.buf[]: 14 | // 15 | // 16 | // 0 ^ 17 | // / \ | 18 | // left <-- / \ --> right | 19 | // / \ | 20 | // / \ 21 | // / \ Max Code Length == Max Number of Edges in a Path == Max Tree Depth 22 | // 1 2 (in this example it's 3) 23 | // / \ / \ 24 | // / \ / \ | 25 | // 3 4 5 6 | 26 | // / \ / \ / \ / \ | 27 | // 7 8 9 10 11 12 13 14 v 28 | // … 29 | // 30 | // Length of self.buf[] = 2^(codelength + 1) - 1 31 | // 32 | 33 | impl Tree { 34 | pub fn with_max_depth(max_depth: usize) -> Tree { 35 | Tree { 36 | buf: vec![None; (1 << (max_depth + 1)) - 1], 37 | len: 0, 38 | last_symbol: None, 39 | } 40 | } 41 | 42 | pub fn from_raw_data(buf: Vec>, len: usize, last_symbol: Option) -> Tree { 43 | Tree { 44 | buf: buf, 45 | len: len, 46 | last_symbol: last_symbol, 47 | } 48 | } 49 | 50 | pub fn insert(&mut self, code: &[bool], symbol: Symbol) { 51 | self.len += 1; 52 | self.last_symbol = Some(symbol); 53 | 54 | let insert_at_index = (1 << code.len()) - 1 + code.iter().fold(0, |acc, &bit| (acc << 1) + if bit { 1 } else { 0 }); 55 | 56 | if insert_at_index > self.buf.len() - 1 { 57 | panic!("Index {:?} exceeds MAX_INDEX at insert (code = {:?})", insert_at_index, code); 58 | } 59 | 60 | self.buf[insert_at_index] = Some(symbol) 61 | } 62 | 63 | fn lookup(&self, r: &mut BitReader) -> Result, ::bitreader::BitReaderError> { 64 | let mut pseudo_code = 1; 65 | loop { 66 | pseudo_code = (pseudo_code << 1) + match r.read_bit_as_usize() { 67 | Ok(b) => b, 68 | Err(e) => return Err(e), 69 | }; 70 | 71 | let lookup_index = pseudo_code - 1; 72 | 73 | if lookup_index > self.buf.len() - 1 { 74 | return Ok(None); 75 | } 76 | 77 | match self.buf[lookup_index] { 78 | Some(symbol) => return Ok(Some(symbol)), 79 | None => {}, 80 | } 81 | } 82 | } 83 | 84 | pub fn lookup_symbol(&self, mut r: &mut BitReader) -> Result, ::bitreader::BitReaderError, > { 85 | // println!("self.len = {:?}", self.len); 86 | 87 | match self.len { 88 | 0 => Ok(None), 89 | 1 => Ok(self.last_symbol), 90 | _ => self.lookup(&mut r), 91 | } 92 | } 93 | } 94 | 95 | 96 | mod tests { 97 | #[test] 98 | fn should_insert_and_lookup_first_level_leaf_on_left() { 99 | use ::bitreader::BitReader; 100 | use super::Tree; 101 | use std::io::Cursor; 102 | 103 | let mut lookup_stream = BitReader::new(Cursor::new(vec![0])); 104 | let mut tree = Tree::with_max_depth(1); 105 | tree.insert(&vec![false], 666); 106 | 107 | assert_eq!(tree.lookup_symbol(&mut lookup_stream), Ok(Some(666))); 108 | } 109 | 110 | #[test] 111 | fn should_insert_and_lookup_first_level_leaf_on_right() { 112 | use ::bitreader::BitReader; 113 | use super::Tree; 114 | use std::io::Cursor; 115 | 116 | let mut lookup_stream = BitReader::new(Cursor::new(vec![1])); 117 | let mut tree = Tree::with_max_depth(1); 118 | tree.insert(&vec![true], 666); 119 | 120 | assert_eq!(tree.lookup_symbol(&mut lookup_stream), Ok(Some(666))); 121 | } 122 | 123 | #[test] 124 | fn should_insert_first_level_leaf_on_left_then_on_right() { 125 | use ::bitreader::BitReader; 126 | use super::Tree; 127 | use std::io::Cursor; 128 | 129 | let mut lookup_stream = BitReader::new(Cursor::new(vec![2])); 130 | let mut tree = Tree::with_max_depth(1); 131 | tree.insert(&vec![false], 667); 132 | tree.insert(&vec![true], 666); 133 | 134 | assert_eq!(tree.lookup_symbol(&mut lookup_stream), Ok(Some(667))); 135 | assert_eq!(tree.lookup_symbol(&mut lookup_stream), Ok(Some(666))); 136 | } 137 | 138 | #[test] 139 | fn should_insert_first_level_leaf_on_right_then_on_left() { 140 | use ::bitreader::BitReader; 141 | use super::Tree; 142 | use std::io::Cursor; 143 | 144 | let mut lookup_stream = BitReader::new(Cursor::new(vec![1])); 145 | let mut tree = Tree::with_max_depth(1); 146 | tree.insert(&vec![true], 666); 147 | tree.insert(&vec![false], 667); 148 | 149 | assert_eq!(tree.lookup_symbol(&mut lookup_stream), Ok(Some(666))); 150 | assert_eq!(tree.lookup_symbol(&mut lookup_stream), Ok(Some(667))); 151 | } 152 | 153 | #[test] 154 | fn should_insert_second_level_leaf_left_right() { 155 | use ::bitreader::BitReader; 156 | use super::Tree; 157 | use std::io::Cursor; 158 | 159 | let mut lookup_stream = BitReader::new(Cursor::new(vec![2])); 160 | let mut tree = Tree::with_max_depth(2); 161 | tree.insert(&vec![false, true], 6666); 162 | 163 | assert_eq!(tree.lookup_symbol(&mut lookup_stream), Ok(Some(6666))); 164 | } 165 | 166 | #[test] 167 | fn should_insert_second_level_leaf_right_left() { 168 | use ::bitreader::BitReader; 169 | use super::Tree; 170 | use std::io::Cursor; 171 | 172 | let mut lookup_stream = BitReader::new(Cursor::new(vec![1])); 173 | let mut tree = Tree::with_max_depth(2); 174 | tree.insert(&vec![true, false], 6666); 175 | 176 | assert_eq!(tree.lookup_symbol(&mut lookup_stream), Ok(Some(6666))); 177 | } 178 | 179 | #[test] 180 | fn should_lookup_first_level_leaf_left() { 181 | use ::bitreader::BitReader; 182 | use super::Tree; 183 | use std::io::Cursor; 184 | 185 | let mut lookup_stream = BitReader::new(Cursor::new(vec![0b11001])); 186 | let mut tree = Tree::with_max_depth(2); 187 | tree.insert(&vec![true, false], 6666); 188 | tree.insert(&vec![false], 666); 189 | tree.insert(&vec![true, true], 6667); 190 | 191 | assert_eq!(tree.lookup_symbol(&mut lookup_stream), Ok(Some(6666))); 192 | assert_eq!(tree.lookup_symbol(&mut lookup_stream), Ok(Some(666))); 193 | assert_eq!(tree.lookup_symbol(&mut lookup_stream), Ok(Some(6667))); 194 | } 195 | 196 | #[test] 197 | fn should_lookup_first_level_leaf_right() { 198 | use ::bitreader::BitReader; 199 | use super::Tree; 200 | use std::io::Cursor; 201 | 202 | let mut lookup_stream = BitReader::new(Cursor::new(vec![0b10100])); 203 | let mut tree = Tree::with_max_depth(2); 204 | tree.insert(&vec![false, false], 6666); 205 | tree.insert(&vec![true], 666); 206 | tree.insert(&vec![false, true], 6667); 207 | 208 | assert_eq!(tree.lookup_symbol(&mut lookup_stream), Ok(Some(6666))); 209 | assert_eq!(tree.lookup_symbol(&mut lookup_stream), Ok(Some(666))); 210 | assert_eq!(tree.lookup_symbol(&mut lookup_stream), Ok(Some(6667))); 211 | } 212 | } 213 | -------------------------------------------------------------------------------- /src/lookuptable/mod.rs: -------------------------------------------------------------------------------- 1 | pub const LUT_0: [usize; 256] = [ 2 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 0, 4, 0, 0, 3 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4 | 8, 12, 16, 12, 12, 20, 12, 16, 24, 28, 12, 12, 32, 12, 36, 12, 5 | 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 32, 32, 24, 40, 28, 12, 6 | 12, 48, 52, 52, 52, 48, 52, 52, 52, 48, 52, 52, 52, 52, 52, 48, 7 | 52, 52, 52, 52, 52, 48, 52, 52, 52, 52, 52, 24, 12, 28, 12, 12, 8 | 12, 56, 60, 60, 60, 56, 60, 60, 60, 56, 60, 60, 60, 60, 60, 56, 9 | 60, 60, 60, 60, 60, 56, 60, 60, 60, 60, 60, 24, 12, 28, 12, 0, 10 | 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 11 | 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 12 | 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 13 | 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 14 | 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 15 | 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 16 | 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 17 | 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3 18 | ]; 19 | 20 | pub const LUT_1: [usize; 256] =[ 21 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23 | 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 24 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 25 | 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 26 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 27 | 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 28 | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 0, 29 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 36 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 37 | ]; 38 | 39 | pub const LUT_2: [usize; 256] = [ 40 | 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 41 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 42 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 43 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 44 | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 45 | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 46 | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 47 | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 48 | 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 49 | 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 50 | 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 51 | 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 52 | 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 53 | 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 54 | 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 55 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7 56 | ]; 57 | 58 | 59 | // @NOTE Code to generate INSERT_LENGTHS_AND_COPY_LENGTHS below 60 | // 61 | // let mut table = vec![((0, 0), (0, 0)); 704]; 62 | 63 | // for insert_and_copy_length in 0..704 { 64 | // let (mut insert_length_code, mut copy_length_code) = match insert_and_copy_length { 65 | // 0...63 => (0, 0), 66 | // 64...127 => (0, 8), 67 | // 128...191 => (0, 0), 68 | // 192...255 => (0, 8), 69 | // 256...319 => (8, 0), 70 | // 320...383 => (8, 8), 71 | // 384...447 => (0, 16), 72 | // 448...511 => (16, 0), 73 | // 512...575 => (8, 16), 74 | // 576...639 => (16, 8), 75 | // 640...703 => (16, 16), 76 | // _ => unreachable!(), 77 | // }; 78 | 79 | // insert_length_code += 0x07 & (insert_and_copy_length >> 3); 80 | // copy_length_code += 0x07 & insert_and_copy_length; 81 | 82 | // // debug(&format!("(insert code, copy code) = {:?}", (insert_length_code, copy_length_code))); 83 | 84 | // let (insert_length, extra_bits_insert) = match insert_length_code { 85 | // 0...5 => (insert_length_code, 0), 86 | // 6...7 => (6 + 2 * (insert_length_code - 6) , 1), 87 | // 8...9 => (10 + 4 * (insert_length_code - 8) , 2), 88 | // 10...11 => (18 + 8 * (insert_length_code - 10) , 3), 89 | // 12...13 => (34 + 16 * (insert_length_code - 12) , 4), 90 | // 14...15 => (66 + 32 * (insert_length_code - 14) , 5), 91 | // 16 => (130, 6), 92 | // 17 => (194, 7), 93 | // 18 => (322, 8), 94 | // 19 => (578, 9), 95 | // 20 => (1090, 10), 96 | // 21 => (2114, 12), 97 | // 22 => (6210, 14), 98 | // 23 => (22594, 24), 99 | // _ => unreachable!(), // confirmed unreachable, possible value is entirely defined in code above 100 | // }; 101 | 102 | // let (copy_length, extra_bits_copy) = match copy_length_code { 103 | // 0...7 => (copy_length_code + 2, 0), 104 | // 8...9 => (10 + 2 * (copy_length_code - 8) , 1), 105 | // 10...11 => (14 + 4 * (copy_length_code - 10) , 2), 106 | // 12...13 => (22 + 8 * (copy_length_code - 12) , 3), 107 | // 14...15 => (38 + 16 * (copy_length_code - 14) , 4), 108 | // 16...17 => (70 + 32 * (copy_length_code - 16) , 5), 109 | // 18 => (134, 6), 110 | // 19 => (198, 7), 111 | // 20 => (326, 8), 112 | // 21 => (582, 9), 113 | // 22 => (1094, 10), 114 | // 23 => (2118, 24), 115 | // _ => unreachable!(), // confirmed unreachable, possible value is entirely defined in code above 116 | // }; 117 | 118 | // table[insert_and_copy_length] = ((insert_length, extra_bits_insert), (copy_length, extra_bits_copy)); 119 | // } 120 | 121 | // println!("{:?}", table); 122 | 123 | pub const INSERT_LENGTHS_AND_COPY_LENGTHS: [((u32, usize), (u32, usize)); 704] = [((0, 0), (2, 0)), ((0, 0), (3, 0)), ((0, 0), (4, 0)), ((0, 0), (5, 0)), ((0, 0), (6, 0)), ((0, 0), (7, 0)), ((0, 0), (8, 0)), ((0, 0), (9, 0)), ((1, 0), (2, 0)), ((1, 0), (3, 0)), ((1, 0), (4, 0)), ((1, 0), (5, 0)), ((1, 0), (6, 0)), ((1, 0), (7, 0)), ((1, 0), (8, 0)), ((1, 0), (9, 0)), ((2, 0), (2, 0)), ((2, 0), (3, 0)), ((2, 0), (4, 0)), ((2, 0), (5, 0)), ((2, 0), (6, 0)), ((2, 0), (7, 0)), ((2, 0), (8, 0)), ((2, 0), (9, 0)), ((3, 0), (2, 0)), ((3, 0), (3, 0)), ((3, 0), (4, 0)), ((3, 0), (5, 0)), ((3, 0), (6, 0)), ((3, 0), (7, 0)), ((3, 0), (8, 0)), ((3, 0), (9, 0)), ((4, 0), (2, 0)), ((4, 0), (3, 0)), ((4, 0), (4, 0)), ((4, 0), (5, 0)), ((4, 0), (6, 0)), ((4, 0), (7, 0)), ((4, 0), (8, 0)), ((4, 0), (9, 0)), ((5, 0), (2, 0)), ((5, 0), (3, 0)), ((5, 0), (4, 0)), ((5, 0), (5, 0)), ((5, 0), (6, 0)), ((5, 0), (7, 0)), ((5, 0), (8, 0)), ((5, 0), (9, 0)), ((6, 1), (2, 0)), ((6, 1), (3, 0)), ((6, 1), (4, 0)), ((6, 1), (5, 0)), ((6, 1), (6, 0)), ((6, 1), (7, 0)), ((6, 1), (8, 0)), ((6, 1), (9, 0)), ((8, 1), (2, 0)), ((8, 1), (3, 0)), ((8, 1), (4, 0)), ((8, 1), (5, 0)), ((8, 1), (6, 0)), ((8, 1), (7, 0)), ((8, 1), (8, 0)), ((8, 1), (9, 0)), ((0, 0), (10, 1)), ((0, 0), (12, 1)), ((0, 0), (14, 2)), ((0, 0), (18, 2)), ((0, 0), (22, 3)), ((0, 0), (30, 3)), ((0, 0), (38, 4)), ((0, 0), (54, 4)), ((1, 0), (10, 1)), ((1, 0), (12, 1)), ((1, 0), (14, 2)), ((1, 0), (18, 2)), ((1, 0), (22, 3)), ((1, 0), (30, 3)), ((1, 0), (38, 4)), ((1, 0), (54, 4)), ((2, 0), (10, 1)), ((2, 0), (12, 1)), ((2, 0), (14, 2)), ((2, 0), (18, 2)), ((2, 0), (22, 3)), ((2, 0), (30, 3)), ((2, 0), (38, 4)), ((2, 0), (54, 4)), ((3, 0), (10, 1)), ((3, 0), (12, 1)), ((3, 0), (14, 2)), ((3, 0), (18, 2)), ((3, 0), (22, 3)), ((3, 0), (30, 3)), ((3, 0), (38, 4)), ((3, 0), (54, 4)), ((4, 0), (10, 1)), ((4, 0), (12, 1)), ((4, 0), (14, 2)), ((4, 0), (18, 2)), ((4, 0), (22, 3)), ((4, 0), (30, 3)), ((4, 0), (38, 4)), ((4, 0), (54, 4)), ((5, 0), (10, 1)), ((5, 0), (12, 1)), ((5, 0), (14, 2)), ((5, 0), (18, 2)), ((5, 0), (22, 3)), ((5, 0), (30, 3)), ((5, 0), (38, 4)), ((5, 0), (54, 4)), ((6, 1), (10, 1)), ((6, 1), (12, 1)), ((6, 1), (14, 2)), ((6, 1), (18, 2)), ((6, 1), (22, 3)), ((6, 1), (30, 3)), ((6, 1), (38, 4)), ((6, 1), (54, 4)), ((8, 1), (10, 1)), ((8, 1), (12, 1)), ((8, 1), (14, 2)), ((8, 1), (18, 2)), ((8, 1), (22, 3)), ((8, 1), (30, 3)), ((8, 1), (38, 4)), ((8, 1), (54, 4)), ((0, 0), (2, 0)), ((0, 0), (3, 0)), ((0, 0), (4, 0)), ((0, 0), (5, 0)), ((0, 0), (6, 0)), ((0, 0), (7, 0)), ((0, 0), (8, 0)), ((0, 0), (9, 0)), ((1, 0), (2, 0)), ((1, 0), (3, 0)), ((1, 0), (4, 0)), ((1, 0), (5, 0)), ((1, 0), (6, 0)), ((1, 0), (7, 0)), ((1, 0), (8, 0)), ((1, 0), (9, 0)), ((2, 0), (2, 0)), ((2, 0), (3, 0)), ((2, 0), (4, 0)), ((2, 0), (5, 0)), ((2, 0), (6, 0)), ((2, 0), (7, 0)), ((2, 0), (8, 0)), ((2, 0), (9, 0)), ((3, 0), (2, 0)), ((3, 0), (3, 0)), ((3, 0), (4, 0)), ((3, 0), (5, 0)), ((3, 0), (6, 0)), ((3, 0), (7, 0)), ((3, 0), (8, 0)), ((3, 0), (9, 0)), ((4, 0), (2, 0)), ((4, 0), (3, 0)), ((4, 0), (4, 0)), ((4, 0), (5, 0)), ((4, 0), (6, 0)), ((4, 0), (7, 0)), ((4, 0), (8, 0)), ((4, 0), (9, 0)), ((5, 0), (2, 0)), ((5, 0), (3, 0)), ((5, 0), (4, 0)), ((5, 0), (5, 0)), ((5, 0), (6, 0)), ((5, 0), (7, 0)), ((5, 0), (8, 0)), ((5, 0), (9, 0)), ((6, 1), (2, 0)), ((6, 1), (3, 0)), ((6, 1), (4, 0)), ((6, 1), (5, 0)), ((6, 1), (6, 0)), ((6, 1), (7, 0)), ((6, 1), (8, 0)), ((6, 1), (9, 0)), ((8, 1), (2, 0)), ((8, 1), (3, 0)), ((8, 1), (4, 0)), ((8, 1), (5, 0)), ((8, 1), (6, 0)), ((8, 1), (7, 0)), ((8, 1), (8, 0)), ((8, 1), (9, 0)), ((0, 0), (10, 1)), ((0, 0), (12, 1)), ((0, 0), (14, 2)), ((0, 0), (18, 2)), ((0, 0), (22, 3)), ((0, 0), (30, 3)), ((0, 0), (38, 4)), ((0, 0), (54, 4)), ((1, 0), (10, 1)), ((1, 0), (12, 1)), ((1, 0), (14, 2)), ((1, 0), (18, 2)), ((1, 0), (22, 3)), ((1, 0), (30, 3)), ((1, 0), (38, 4)), ((1, 0), (54, 4)), ((2, 0), (10, 1)), ((2, 0), (12, 1)), ((2, 0), (14, 2)), ((2, 0), (18, 2)), ((2, 0), (22, 3)), ((2, 0), (30, 3)), ((2, 0), (38, 4)), ((2, 0), (54, 4)), ((3, 0), (10, 1)), ((3, 0), (12, 1)), ((3, 0), (14, 2)), ((3, 0), (18, 2)), ((3, 0), (22, 3)), ((3, 0), (30, 3)), ((3, 0), (38, 4)), ((3, 0), (54, 4)), ((4, 0), (10, 1)), ((4, 0), (12, 1)), ((4, 0), (14, 2)), ((4, 0), (18, 2)), ((4, 0), (22, 3)), ((4, 0), (30, 3)), ((4, 0), (38, 4)), ((4, 0), (54, 4)), ((5, 0), (10, 1)), ((5, 0), (12, 1)), ((5, 0), (14, 2)), ((5, 0), (18, 2)), ((5, 0), (22, 3)), ((5, 0), (30, 3)), ((5, 0), (38, 4)), ((5, 0), (54, 4)), ((6, 1), (10, 1)), ((6, 1), (12, 1)), ((6, 1), (14, 2)), ((6, 1), (18, 2)), ((6, 1), (22, 3)), ((6, 1), (30, 3)), ((6, 1), (38, 4)), ((6, 1), (54, 4)), ((8, 1), (10, 1)), ((8, 1), (12, 1)), ((8, 1), (14, 2)), ((8, 1), (18, 2)), ((8, 1), (22, 3)), ((8, 1), (30, 3)), ((8, 1), (38, 4)), ((8, 1), (54, 4)), ((10, 2), (2, 0)), ((10, 2), (3, 0)), ((10, 2), (4, 0)), ((10, 2), (5, 0)), ((10, 2), (6, 0)), ((10, 2), (7, 0)), ((10, 2), (8, 0)), ((10, 2), (9, 0)), ((14, 2), (2, 0)), ((14, 2), (3, 0)), ((14, 2), (4, 0)), ((14, 2), (5, 0)), ((14, 2), (6, 0)), ((14, 2), (7, 0)), ((14, 2), (8, 0)), ((14, 2), (9, 0)), ((18, 3), (2, 0)), ((18, 3), (3, 0)), ((18, 3), (4, 0)), ((18, 3), (5, 0)), ((18, 3), (6, 0)), ((18, 3), (7, 0)), ((18, 3), (8, 0)), ((18, 3), (9, 0)), ((26, 3), (2, 0)), ((26, 3), (3, 0)), ((26, 3), (4, 0)), ((26, 3), (5, 0)), ((26, 3), (6, 0)), ((26, 3), (7, 0)), ((26, 3), (8, 0)), ((26, 3), (9, 0)), ((34, 4), (2, 0)), ((34, 4), (3, 0)), ((34, 4), (4, 0)), ((34, 4), (5, 0)), ((34, 4), (6, 0)), ((34, 4), (7, 0)), ((34, 4), (8, 0)), ((34, 4), (9, 0)), ((50, 4), (2, 0)), ((50, 4), (3, 0)), ((50, 4), (4, 0)), ((50, 4), (5, 0)), ((50, 4), (6, 0)), ((50, 4), (7, 0)), ((50, 4), (8, 0)), ((50, 4), (9, 0)), ((66, 5), (2, 0)), ((66, 5), (3, 0)), ((66, 5), (4, 0)), ((66, 5), (5, 0)), ((66, 5), (6, 0)), ((66, 5), (7, 0)), ((66, 5), (8, 0)), ((66, 5), (9, 0)), ((98, 5), (2, 0)), ((98, 5), (3, 0)), ((98, 5), (4, 0)), ((98, 5), (5, 0)), ((98, 5), (6, 0)), ((98, 5), (7, 0)), ((98, 5), (8, 0)), ((98, 5), (9, 0)), ((10, 2), (10, 1)), ((10, 2), (12, 1)), ((10, 2), (14, 2)), ((10, 2), (18, 2)), ((10, 2), (22, 3)), ((10, 2), (30, 3)), ((10, 2), (38, 4)), ((10, 2), (54, 4)), ((14, 2), (10, 1)), ((14, 2), (12, 1)), ((14, 2), (14, 2)), ((14, 2), (18, 2)), ((14, 2), (22, 3)), ((14, 2), (30, 3)), ((14, 2), (38, 4)), ((14, 2), (54, 4)), ((18, 3), (10, 1)), ((18, 3), (12, 1)), ((18, 3), (14, 2)), ((18, 3), (18, 2)), ((18, 3), (22, 3)), ((18, 3), (30, 3)), ((18, 3), (38, 4)), ((18, 3), (54, 4)), ((26, 3), (10, 1)), ((26, 3), (12, 1)), ((26, 3), (14, 2)), ((26, 3), (18, 2)), ((26, 3), (22, 3)), ((26, 3), (30, 3)), ((26, 3), (38, 4)), ((26, 3), (54, 4)), ((34, 4), (10, 1)), ((34, 4), (12, 1)), ((34, 4), (14, 2)), ((34, 4), (18, 2)), ((34, 4), (22, 3)), ((34, 4), (30, 3)), ((34, 4), (38, 4)), ((34, 4), (54, 4)), ((50, 4), (10, 1)), ((50, 4), (12, 1)), ((50, 4), (14, 2)), ((50, 4), (18, 2)), ((50, 4), (22, 3)), ((50, 4), (30, 3)), ((50, 4), (38, 4)), ((50, 4), (54, 4)), ((66, 5), (10, 1)), ((66, 5), (12, 1)), ((66, 5), (14, 2)), ((66, 5), (18, 2)), ((66, 5), (22, 3)), ((66, 5), (30, 3)), ((66, 5), (38, 4)), ((66, 5), (54, 4)), ((98, 5), (10, 1)), ((98, 5), (12, 1)), ((98, 5), (14, 2)), ((98, 5), (18, 2)), ((98, 5), (22, 3)), ((98, 5), (30, 3)), ((98, 5), (38, 4)), ((98, 5), (54, 4)), ((0, 0), (70, 5)), ((0, 0), (102, 5)), ((0, 0), (134, 6)), ((0, 0), (198, 7)), ((0, 0), (326, 8)), ((0, 0), (582, 9)), ((0, 0), (1094, 10)), ((0, 0), (2118, 24)), ((1, 0), (70, 5)), ((1, 0), (102, 5)), ((1, 0), (134, 6)), ((1, 0), (198, 7)), ((1, 0), (326, 8)), ((1, 0), (582, 9)), ((1, 0), (1094, 10)), ((1, 0), (2118, 24)), ((2, 0), (70, 5)), ((2, 0), (102, 5)), ((2, 0), (134, 6)), ((2, 0), (198, 7)), ((2, 0), (326, 8)), ((2, 0), (582, 9)), ((2, 0), (1094, 10)), ((2, 0), (2118, 24)), ((3, 0), (70, 5)), ((3, 0), (102, 5)), ((3, 0), (134, 6)), ((3, 0), (198, 7)), ((3, 0), (326, 8)), ((3, 0), (582, 9)), ((3, 0), (1094, 10)), ((3, 0), (2118, 24)), ((4, 0), (70, 5)), ((4, 0), (102, 5)), ((4, 0), (134, 6)), ((4, 0), (198, 7)), ((4, 0), (326, 8)), ((4, 0), (582, 9)), ((4, 0), (1094, 10)), ((4, 0), (2118, 24)), ((5, 0), (70, 5)), ((5, 0), (102, 5)), ((5, 0), (134, 6)), ((5, 0), (198, 7)), ((5, 0), (326, 8)), ((5, 0), (582, 9)), ((5, 0), (1094, 10)), ((5, 0), (2118, 24)), ((6, 1), (70, 5)), ((6, 1), (102, 5)), ((6, 1), (134, 6)), ((6, 1), (198, 7)), ((6, 1), (326, 8)), ((6, 1), (582, 9)), ((6, 1), (1094, 10)), ((6, 1), (2118, 24)), ((8, 1), (70, 5)), ((8, 1), (102, 5)), ((8, 1), (134, 6)), ((8, 1), (198, 7)), ((8, 1), (326, 8)), ((8, 1), (582, 9)), ((8, 1), (1094, 10)), ((8, 1), (2118, 24)), ((130, 6), (2, 0)), ((130, 6), (3, 0)), ((130, 6), (4, 0)), ((130, 6), (5, 0)), ((130, 6), (6, 0)), ((130, 6), (7, 0)), ((130, 6), (8, 0)), ((130, 6), (9, 0)), ((194, 7), (2, 0)), ((194, 7), (3, 0)), ((194, 7), (4, 0)), ((194, 7), (5, 0)), ((194, 7), (6, 0)), ((194, 7), (7, 0)), ((194, 7), (8, 0)), ((194, 7), (9, 0)), ((322, 8), (2, 0)), ((322, 8), (3, 0)), ((322, 8), (4, 0)), ((322, 8), (5, 0)), ((322, 8), (6, 0)), ((322, 8), (7, 0)), ((322, 8), (8, 0)), ((322, 8), (9, 0)), ((578, 9), (2, 0)), ((578, 9), (3, 0)), ((578, 9), (4, 0)), ((578, 9), (5, 0)), ((578, 9), (6, 0)), ((578, 9), (7, 0)), ((578, 9), (8, 0)), ((578, 9), (9, 0)), ((1090, 10), (2, 0)), ((1090, 10), (3, 0)), ((1090, 10), (4, 0)), ((1090, 10), (5, 0)), ((1090, 10), (6, 0)), ((1090, 10), (7, 0)), ((1090, 10), (8, 0)), ((1090, 10), (9, 0)), ((2114, 12), (2, 0)), ((2114, 12), (3, 0)), ((2114, 12), (4, 0)), ((2114, 12), (5, 0)), ((2114, 12), (6, 0)), ((2114, 12), (7, 0)), ((2114, 12), (8, 0)), ((2114, 12), (9, 0)), ((6210, 14), (2, 0)), ((6210, 14), (3, 0)), ((6210, 14), (4, 0)), ((6210, 14), (5, 0)), ((6210, 14), (6, 0)), ((6210, 14), (7, 0)), ((6210, 14), (8, 0)), ((6210, 14), (9, 0)), ((22594, 24), (2, 0)), ((22594, 24), (3, 0)), ((22594, 24), (4, 0)), ((22594, 24), (5, 0)), ((22594, 24), (6, 0)), ((22594, 24), (7, 0)), ((22594, 24), (8, 0)), ((22594, 24), (9, 0)), ((10, 2), (70, 5)), ((10, 2), (102, 5)), ((10, 2), (134, 6)), ((10, 2), (198, 7)), ((10, 2), (326, 8)), ((10, 2), (582, 9)), ((10, 2), (1094, 10)), ((10, 2), (2118, 24)), ((14, 2), (70, 5)), ((14, 2), (102, 5)), ((14, 2), (134, 6)), ((14, 2), (198, 7)), ((14, 2), (326, 8)), ((14, 2), (582, 9)), ((14, 2), (1094, 10)), ((14, 2), (2118, 24)), ((18, 3), (70, 5)), ((18, 3), (102, 5)), ((18, 3), (134, 6)), ((18, 3), (198, 7)), ((18, 3), (326, 8)), ((18, 3), (582, 9)), ((18, 3), (1094, 10)), ((18, 3), (2118, 24)), ((26, 3), (70, 5)), ((26, 3), (102, 5)), ((26, 3), (134, 6)), ((26, 3), (198, 7)), ((26, 3), (326, 8)), ((26, 3), (582, 9)), ((26, 3), (1094, 10)), ((26, 3), (2118, 24)), ((34, 4), (70, 5)), ((34, 4), (102, 5)), ((34, 4), (134, 6)), ((34, 4), (198, 7)), ((34, 4), (326, 8)), ((34, 4), (582, 9)), ((34, 4), (1094, 10)), ((34, 4), (2118, 24)), ((50, 4), (70, 5)), ((50, 4), (102, 5)), ((50, 4), (134, 6)), ((50, 4), (198, 7)), ((50, 4), (326, 8)), ((50, 4), (582, 9)), ((50, 4), (1094, 10)), ((50, 4), (2118, 24)), ((66, 5), (70, 5)), ((66, 5), (102, 5)), ((66, 5), (134, 6)), ((66, 5), (198, 7)), ((66, 5), (326, 8)), ((66, 5), (582, 9)), ((66, 5), (1094, 10)), ((66, 5), (2118, 24)), ((98, 5), (70, 5)), ((98, 5), (102, 5)), ((98, 5), (134, 6)), ((98, 5), (198, 7)), ((98, 5), (326, 8)), ((98, 5), (582, 9)), ((98, 5), (1094, 10)), ((98, 5), (2118, 24)), ((130, 6), (10, 1)), ((130, 6), (12, 1)), ((130, 6), (14, 2)), ((130, 6), (18, 2)), ((130, 6), (22, 3)), ((130, 6), (30, 3)), ((130, 6), (38, 4)), ((130, 6), (54, 4)), ((194, 7), (10, 1)), ((194, 7), (12, 1)), ((194, 7), (14, 2)), ((194, 7), (18, 2)), ((194, 7), (22, 3)), ((194, 7), (30, 3)), ((194, 7), (38, 4)), ((194, 7), (54, 4)), ((322, 8), (10, 1)), ((322, 8), (12, 1)), ((322, 8), (14, 2)), ((322, 8), (18, 2)), ((322, 8), (22, 3)), ((322, 8), (30, 3)), ((322, 8), (38, 4)), ((322, 8), (54, 4)), ((578, 9), (10, 1)), ((578, 9), (12, 1)), ((578, 9), (14, 2)), ((578, 9), (18, 2)), ((578, 9), (22, 3)), ((578, 9), (30, 3)), ((578, 9), (38, 4)), ((578, 9), (54, 4)), ((1090, 10), (10, 1)), ((1090, 10), (12, 1)), ((1090, 10), (14, 2)), ((1090, 10), (18, 2)), ((1090, 10), (22, 3)), ((1090, 10), (30, 3)), ((1090, 10), (38, 4)), ((1090, 10), (54, 4)), ((2114, 12), (10, 1)), ((2114, 12), (12, 1)), ((2114, 12), (14, 2)), ((2114, 12), (18, 2)), ((2114, 12), (22, 3)), ((2114, 12), (30, 3)), ((2114, 12), (38, 4)), ((2114, 12), (54, 4)), ((6210, 14), (10, 1)), ((6210, 14), (12, 1)), ((6210, 14), (14, 2)), ((6210, 14), (18, 2)), ((6210, 14), (22, 3)), ((6210, 14), (30, 3)), ((6210, 14), (38, 4)), ((6210, 14), (54, 4)), ((22594, 24), (10, 1)), ((22594, 24), (12, 1)), ((22594, 24), (14, 2)), ((22594, 24), (18, 2)), ((22594, 24), (22, 3)), ((22594, 24), (30, 3)), ((22594, 24), (38, 4)), ((22594, 24), (54, 4)), ((130, 6), (70, 5)), ((130, 6), (102, 5)), ((130, 6), (134, 6)), ((130, 6), (198, 7)), ((130, 6), (326, 8)), ((130, 6), (582, 9)), ((130, 6), (1094, 10)), ((130, 6), (2118, 24)), ((194, 7), (70, 5)), ((194, 7), (102, 5)), ((194, 7), (134, 6)), ((194, 7), (198, 7)), ((194, 7), (326, 8)), ((194, 7), (582, 9)), ((194, 7), (1094, 10)), ((194, 7), (2118, 24)), ((322, 8), (70, 5)), ((322, 8), (102, 5)), ((322, 8), (134, 6)), ((322, 8), (198, 7)), ((322, 8), (326, 8)), ((322, 8), (582, 9)), ((322, 8), (1094, 10)), ((322, 8), (2118, 24)), ((578, 9), (70, 5)), ((578, 9), (102, 5)), ((578, 9), (134, 6)), ((578, 9), (198, 7)), ((578, 9), (326, 8)), ((578, 9), (582, 9)), ((578, 9), (1094, 10)), ((578, 9), (2118, 24)), ((1090, 10), (70, 5)), ((1090, 10), (102, 5)), ((1090, 10), (134, 6)), ((1090, 10), (198, 7)), ((1090, 10), (326, 8)), ((1090, 10), (582, 9)), ((1090, 10), (1094, 10)), ((1090, 10), (2118, 24)), ((2114, 12), (70, 5)), ((2114, 12), (102, 5)), ((2114, 12), (134, 6)), ((2114, 12), (198, 7)), ((2114, 12), (326, 8)), ((2114, 12), (582, 9)), ((2114, 12), (1094, 10)), ((2114, 12), (2118, 24)), ((6210, 14), (70, 5)), ((6210, 14), (102, 5)), ((6210, 14), (134, 6)), ((6210, 14), (198, 7)), ((6210, 14), (326, 8)), ((6210, 14), (582, 9)), ((6210, 14), (1094, 10)), ((6210, 14), (2118, 24)), ((22594, 24), (70, 5)), ((22594, 24), (102, 5)), ((22594, 24), (134, 6)), ((22594, 24), (198, 7)), ((22594, 24), (326, 8)), ((22594, 24), (582, 9)), ((22594, 24), (1094, 10)), ((22594, 24), (2118, 24))]; 124 | 125 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | extern crate brotli; 2 | 3 | use std::io::Read; 4 | use brotli::Decompressor; 5 | use std::fs; 6 | use std::path::Path; 7 | 8 | // fn visit_dirs(dir: &Path) -> io::Result<()> { 9 | // if try!(fs::metadata(dir)).is_dir() { 10 | // for entry in try!(fs::read_dir(dir)) { 11 | // let entry = try!(entry); 12 | // if try!(fs::metadata(entry.path())).is_dir() { 13 | // ; 14 | // } else { 15 | // if entry.file_name().to_str().unwrap().starts_with("id") { 16 | // println!("{:?}:", &entry.path()); 17 | // let mut input = Vec::new(); 18 | // let res = Decompressor::new(std::fs::File::open(&entry.path()).unwrap()).read_to_end(&mut input); 19 | // 20 | // println!("output length = {:?}", input.len()); 21 | // println!("res = {:?}\n===========\n", res); 22 | // } 23 | // 24 | // } 25 | // } 26 | // } 27 | // Ok(()) 28 | // } 29 | 30 | 31 | 32 | fn main() { 33 | // let mut input = Vec::new(); 34 | // let res = Decompressor::new(std::fs::File::open("data/alice29.txt.compressed").unwrap()).read_to_end(&mut input); 35 | 36 | // match res { 37 | // Ok(_) => { 38 | // std::io::stdout().write(&input).unwrap(); 39 | // }, 40 | // Err(_) => println!("{:?}", res), 41 | // }; 42 | 43 | // for i in 1..7 { 44 | // let _ = visit_dirs(Path::new(&format!("afl-findings/fuzzer0{}/crashes", i))); 45 | // let _ = visit_dirs(Path::new(&format!("afl-findings/fuzzer0{}/hangs", i))); 46 | // } 47 | 48 | 49 | { 50 | let dir = Path::new("data"); 51 | 52 | if fs::metadata(dir).unwrap().is_dir() { 53 | for entry in fs::read_dir(dir).unwrap() { 54 | let entry = entry.unwrap(); 55 | if fs::metadata(entry.path()).unwrap().is_dir() { 56 | ; 57 | } else { 58 | if entry.file_name().to_str().unwrap().ends_with("compressed") { 59 | println!("{:?}:", &entry.path()); 60 | let mut input = Vec::new(); 61 | let res = Decompressor::new(std::fs::File::open(&entry.path()).unwrap()).read_to_end(&mut input); 62 | 63 | println!("output length = {:?}", input.len()); 64 | println!("res = {:?}\n===========\n", res); 65 | } 66 | 67 | } 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/ringbuffer/mod.rs: -------------------------------------------------------------------------------- 1 | use std::error::Error; 2 | use std::fmt; 3 | use std::fmt::{ Debug, Display, Formatter }; 4 | 5 | #[derive(Debug, Clone, PartialEq)] 6 | /// RingBuffer to store elements in a fixed size list, overwriting 7 | /// the oldest elements when its capacity is full. 8 | pub struct RingBuffer { 9 | buf: Vec, 10 | pos: usize, 11 | cap: usize, 12 | } 13 | 14 | impl RingBuffer { 15 | /// Creates a new RingBuffer populated with the elements in v, 16 | /// with capacity == v.len(). 17 | /// Takes ownership of v. 18 | pub fn from_vec(v: Vec) -> RingBuffer { 19 | let c = v.len(); 20 | RingBuffer { 21 | buf: v.iter().rev().cloned().collect::>(), 22 | pos: c - 1, 23 | cap: c, 24 | } 25 | } 26 | 27 | /// Creates a new RingBuffer with a max capacity of c. 28 | pub fn with_capacity(c: usize) -> RingBuffer { 29 | RingBuffer { 30 | buf: Vec::with_capacity(c), 31 | pos: 0, 32 | cap: c, 33 | } 34 | } 35 | 36 | /// Returns a result containing the nth element from the back, 37 | /// i.e. the 0th element is the last element that has been pushed. 38 | /// Returns RingBufferError::ParameterExceededSize, if n exceeds 39 | /// the buffers length or number of stored items. 40 | pub fn nth(&self, n: usize) -> Result<&T, RingBufferError> { 41 | let len = self.buf.len(); 42 | 43 | if n >= len { 44 | Err(RingBufferError::ParameterExceededSize) 45 | } else { 46 | Ok(&self.buf[(self.pos + len - n) % len]) 47 | } 48 | } 49 | 50 | pub fn slice_tail(&self, n: usize, buf: &mut [T]) -> Result<(), RingBufferError> { 51 | let len = self.buf.len(); 52 | 53 | if n >= len { 54 | Err(RingBufferError::ParameterExceededSize) 55 | } else { 56 | for (i, mut item) in buf.iter_mut().enumerate() { 57 | *item = self.buf[(self.pos + len - n + i) % len]; 58 | } 59 | Ok(()) 60 | } 61 | } 62 | 63 | /// Pushes an item to the end of the ring buffer. 64 | pub fn push(&mut self, item: T) { 65 | let len = self.buf.len(); 66 | if len < self.cap { 67 | self.buf.push(item); 68 | self.pos = len; 69 | } else { 70 | self.pos = (self.pos + 1) % len; 71 | self.buf[self.pos] = item; 72 | } 73 | } 74 | } 75 | 76 | #[test] 77 | fn should_retrieve_last_item() { 78 | let mut buf = RingBuffer::with_capacity(2); 79 | let item = 15; 80 | buf.push(item); 81 | 82 | assert_eq!(item, *buf.nth(0).unwrap());; 83 | } 84 | 85 | #[derive(Debug, Clone, PartialEq)] 86 | pub enum RingBufferError { 87 | ParameterExceededSize, 88 | } 89 | 90 | impl Display for RingBufferError { 91 | fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { 92 | 93 | fmt.write_str(self.description()) 94 | } 95 | } 96 | 97 | impl Error for RingBufferError { 98 | fn description(&self) -> &str { 99 | match *self { 100 | RingBufferError::ParameterExceededSize => "Index parameter exceeded ring buffer size", 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/transformation/mod.rs: -------------------------------------------------------------------------------- 1 | use std::cmp::{ max, min }; 2 | 3 | fn uppercase_all(base_word: &[u8]) -> Vec { 4 | let l = base_word.len(); 5 | let mut v = Vec::with_capacity(l); 6 | let mut i = 0; 7 | 8 | while i < l { 9 | match base_word[i] { 10 | 0...96|123...191 => { 11 | v.push(base_word[i]); 12 | i += 1; 13 | }, 14 | 97...122 => { 15 | v.push(base_word[i] ^ 32); 16 | i += 1; 17 | }, 18 | 192...223 => { 19 | v.push(base_word[i]); 20 | if i + 1 < l { 21 | v.push(base_word[i + 1] ^ 32); 22 | } 23 | i += 2; 24 | }, 25 | 224...255 => { 26 | v.push(base_word[i]); 27 | if i + 1 < l { 28 | v.push(base_word[i + 1]); 29 | } 30 | if i + 2 < l { 31 | v.push(base_word[i + 2] ^ 5); 32 | } 33 | i = i + 3; 34 | }, 35 | _ => unreachable!(), // confirmed unreachable, all byte values covered 36 | } 37 | } 38 | 39 | v 40 | } 41 | 42 | fn uppercase_first(base_word: &[u8]) -> Vec { 43 | let l = base_word.len(); 44 | 45 | if l == 0 { 46 | return Vec::new(); 47 | } 48 | 49 | let mut v = Vec::with_capacity(l); 50 | let i; 51 | 52 | match base_word[0] { 53 | 1...96|123...191 => { 54 | v.push(base_word[0]); 55 | i = 1; 56 | }, 57 | 97...122 => { 58 | v.push(base_word[0] ^ 32); 59 | i = 1; 60 | }, 61 | 192...223 => { 62 | v.push(base_word[0]); 63 | if 1 < l { 64 | v.push(base_word[1] ^ 32); 65 | } 66 | i = 2; 67 | }, 68 | 224...255 => { 69 | v.push(base_word[0]); 70 | if 1 < l { 71 | v.push(base_word[1]); 72 | } 73 | if 2 < l { 74 | v.push(base_word[2] ^ 5); 75 | } 76 | i = 3; 77 | }, 78 | _ => unreachable!(), // confirmed unreachable, all byte values covered 79 | } 80 | 81 | [v, Vec::from(&base_word[i..])].concat() 82 | } 83 | 84 | pub fn transformation(id: usize, base_word: &[u8]) -> Vec { 85 | match id { 86 | 0 => Vec::from(base_word), 87 | 1 => [Vec::from(base_word), vec![0x20]].concat(), 88 | 2 => [vec![0x20], Vec::from(base_word), vec![0x20]].concat(), 89 | 3 => Vec::from(&base_word[min(1, base_word.len() - 1)..]), 90 | 4 => [uppercase_first(base_word), vec![0x20]].concat(), 91 | 5 => [Vec::from(base_word), vec![0x20, 0x74, 0x68, 0x65, 0x20]].concat(), 92 | 6 => [vec![0x20], Vec::from(base_word)].concat(), 93 | 7 => [vec![0x73, 0x20], Vec::from(base_word), vec![0x20]].concat(), 94 | 8 => [Vec::from(base_word), vec![0x20, 0x6f, 0x66, 0x20]].concat(), 95 | 9 => uppercase_first(base_word), 96 | 10 => [Vec::from(base_word), vec![0x20, 0x61, 0x6e, 0x64, 0x20]].concat(), 97 | 11 => Vec::from(&base_word[min(2, base_word.len() - 1)..]), 98 | 12 => Vec::from(&base_word[..max(1, base_word.len()) - 1]), 99 | 13 => [vec![0x2c, 0x20], Vec::from(base_word), vec![0x20]].concat(), 100 | 14 => [Vec::from(base_word), vec![0x2c, 0x20]].concat(), 101 | 15 => [vec![0x20], uppercase_first(base_word), vec![0x20]].concat(), 102 | 16 => [Vec::from(base_word), vec![0x20, 0x69, 0x6e, 0x20]].concat(), 103 | 17 => [Vec::from(base_word), vec![0x20, 0x74, 0x6f, 0x20]].concat(), 104 | 18 => [vec![0x65, 0x20], Vec::from(base_word), vec![0x20]].concat(), 105 | 19 => [Vec::from(base_word), vec![0x22]].concat(), 106 | 20 => [Vec::from(base_word), vec![0x2e]].concat(), 107 | 21 => [Vec::from(base_word), vec![0x22, 0x3e]].concat(), 108 | 22 => [Vec::from(base_word), vec![0x0a]].concat(), 109 | 23 => Vec::from(&base_word[..max(3, base_word.len()) - 3]), 110 | 24 => [Vec::from(base_word), vec![0x5d]].concat(), 111 | 25 => [Vec::from(base_word), vec![0x20, 0x66, 0x6f, 0x72, 0x20]].concat(), 112 | 26 => Vec::from(&base_word[min(3, base_word.len() - 1)..]), 113 | 27 => Vec::from(&base_word[..max(2, base_word.len()) - 2]), 114 | 28 => [Vec::from(base_word), vec![0x20, 0x61, 0x20]].concat(), 115 | 29 => [Vec::from(base_word), vec![0x20, 0x74, 0x68, 0x61, 0x74, 0x20]].concat(), 116 | 30 => [vec![0x20], uppercase_first(base_word)].concat(), 117 | 31 => [Vec::from(base_word), vec![0x2e, 0x20]].concat(), 118 | 32 => [vec![0x2e], Vec::from(base_word)].concat(), 119 | 33 => [vec![0x20], Vec::from(base_word), vec![0x2c, 0x20]].concat(), 120 | 34 => Vec::from(&base_word[min(4, base_word.len() - 1)..]), 121 | 35 => [Vec::from(base_word), vec![0x20, 0x77, 0x69, 0x74, 0x68, 0x20]].concat(), 122 | 36 => [Vec::from(base_word), vec![0x27]].concat(), 123 | 37 => [Vec::from(base_word), vec![0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20]].concat(), 124 | 38 => [Vec::from(base_word), vec![0x20, 0x62, 0x79, 0x20]].concat(), 125 | 39 => Vec::from(&base_word[min(5, base_word.len() - 1)..]), 126 | 40 => Vec::from(&base_word[min(6, base_word.len() - 1)..]), 127 | 41 => [vec![0x20, 0x74, 0x68, 0x65, 0x20], Vec::from(base_word)].concat(), 128 | 42 => Vec::from(&base_word[..max(4, base_word.len()) - 4]), 129 | 43 => [Vec::from(base_word), vec![0x2e, 0x20, 0x54, 0x68, 0x65, 0x20]].concat(), 130 | 44 => uppercase_all(base_word), 131 | 45 => [Vec::from(base_word), vec![0x20, 0x6f, 0x6e, 0x20]].concat(), 132 | 46 => [Vec::from(base_word), vec![0x20, 0x61, 0x73, 0x20]].concat(), 133 | 47 => [Vec::from(base_word), vec![0x20, 0x69, 0x73, 0x20]].concat(), 134 | 48 => Vec::from(&base_word[..max(7, base_word.len()) - 7]), 135 | 49 => [Vec::from(&base_word[..max(1, base_word.len()) - 1]), vec![0x69, 0x6e, 0x67, 0x20]].concat(), 136 | 50 => [Vec::from(base_word), vec![0x0a, 0x09]].concat(), 137 | 51 => [Vec::from(base_word), vec![0x3a]].concat(), 138 | 52 => [vec![0x20], Vec::from(base_word), vec![0x2e, 0x20]].concat(), 139 | 53 => [Vec::from(base_word), vec![0x65, 0x64, 0x20]].concat(), 140 | 54 => Vec::from(&base_word[min(9, base_word.len() - 1)..]), 141 | 55 => Vec::from(&base_word[min(7, base_word.len() - 1)..]), 142 | 56 => Vec::from(&base_word[..max(6, base_word.len()) - 6]), 143 | 57 => [Vec::from(base_word), vec![0x28]].concat(), 144 | 58 => [uppercase_first(base_word), vec![0x2c, 0x20]].concat(), 145 | 59 => Vec::from(&base_word[..max(8, base_word.len()) - 8]), 146 | 60 => [Vec::from(base_word), vec![0x20, 0x61, 0x74, 0x20]].concat(), 147 | 61 => [Vec::from(base_word), vec![0x6c, 0x79, 0x20]].concat(), 148 | 62 => [vec![0x20, 0x74, 0x68, 0x65, 0x20], Vec::from(base_word), vec![0x20, 0x6f, 0x66, 0x20]].concat(), 149 | 63 => Vec::from(&base_word[..max(5, base_word.len()) - 5]), 150 | 64 => Vec::from(&base_word[..max(base_word.len(), 9) - 9]), 151 | 65 => [vec![0x20], uppercase_first(base_word), vec![0x2c, 0x20]].concat(), 152 | 66 => [uppercase_first(base_word), vec![0x22]].concat(), 153 | 67 => [vec![0x2e], Vec::from(base_word), vec![0x28]].concat(), 154 | 68 => [uppercase_all(base_word), vec![0x20]].concat(), 155 | 69 => [uppercase_first(base_word), vec![0x22, 0x3e]].concat(), 156 | 70 => [Vec::from(base_word), vec![0x3d, 0x22]].concat(), 157 | 71 => [vec![0x20], Vec::from(base_word), vec![0x2e]].concat(), 158 | 72 => [vec![0x2e, 0x63, 0x6f, 0x6d, 0x2f], Vec::from(base_word)].concat(), 159 | 73 => [vec![0x20, 0x74, 0x68, 0x65, 0x20], Vec::from(base_word), vec![0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20]].concat(), 160 | 74 => [uppercase_first(base_word), vec![0x27]].concat(), 161 | 75 => [Vec::from(base_word), vec![0x2e, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20]].concat(), 162 | 76 => [Vec::from(base_word), vec![0x2c]].concat(), 163 | 77 => [vec![0x2e], Vec::from(base_word), vec![0x20]].concat(), 164 | 78 => [uppercase_first(base_word), vec![0x28]].concat(), 165 | 79 => [uppercase_first(base_word), vec![0x2e]].concat(), 166 | 80 => [Vec::from(base_word), vec![0x20, 0x6e, 0x6f, 0x74, 0x20]].concat(), 167 | 81 => [vec![0x20], Vec::from(base_word), vec![0x3d, 0x22]].concat(), 168 | 82 => [Vec::from(base_word), vec![0x65, 0x72, 0x20]].concat(), 169 | 83 => [vec![0x20], uppercase_all(base_word), vec![0x20]].concat(), 170 | 84 => [Vec::from(base_word), vec![0x61, 0x6c, 0x20]].concat(), 171 | 85 => [vec![0x20], uppercase_all(base_word)].concat(), 172 | 86 => [Vec::from(base_word), vec![0x3d, 0x27]].concat(), 173 | 87 => [uppercase_all(base_word), vec![0x22]].concat(), 174 | 88 => [uppercase_first(base_word), vec![0x2e, 0x20]].concat(), 175 | 89 => [vec![0x20], Vec::from(base_word), vec![0x28]].concat(), 176 | 90 => [Vec::from(base_word), vec![0x66, 0x75, 0x6c, 0x20]].concat(), 177 | 91 => [vec![0x20], uppercase_first(base_word), vec![0x2e, 0x20]].concat(), 178 | 92 => [Vec::from(base_word), vec![0x69, 0x76, 0x65, 0x20]].concat(), 179 | 93 => [Vec::from(base_word), vec![0x6c, 0x65, 0x73, 0x73, 0x20]].concat(), 180 | 94 => [uppercase_all(base_word), vec![0x27]].concat(), 181 | 95 => [Vec::from(base_word), vec![0x65, 0x73, 0x74, 0x20]].concat(), 182 | 96 => [vec![0x20], uppercase_first(base_word), vec![0x2e]].concat(), 183 | 97 => [uppercase_all(base_word), vec![0x22, 0x3e]].concat(), 184 | 98 => [vec![0x20], Vec::from(base_word), vec![0x3d, 0x27]].concat(), 185 | 99 => [uppercase_first(base_word), vec![0x2c]].concat(), 186 | 100 => [Vec::from(base_word), vec![0x69, 0x7a, 0x65, 0x20]].concat(), 187 | 101 => [uppercase_all(base_word), vec![0x2e]].concat(), 188 | 102 => [vec![0xc2, 0xa0], Vec::from(base_word)].concat(), 189 | 103 => [vec![0x20], Vec::from(base_word), vec![0x2c]].concat(), 190 | 104 => [uppercase_first(base_word), vec![0x3d, 0x22]].concat(), 191 | 105 => [uppercase_all(base_word), vec![0x3d, 0x22]].concat(), 192 | 106 => [Vec::from(base_word), vec![0x6f, 0x75, 0x73, 0x20]].concat(), 193 | 107 => [uppercase_all(base_word), vec![0x2c, 0x20]].concat(), 194 | 108 => [uppercase_first(base_word), vec![0x3d, 0x27]].concat(), 195 | 109 => [vec![0x20], uppercase_first(base_word), vec![0x2c]].concat(), 196 | 110 => [vec![0x20], uppercase_all(base_word), vec![0x3d, 0x22]].concat(), 197 | 111 => [vec![0x20], uppercase_all(base_word), vec![0x2c, 0x20]].concat(), 198 | 112 => [uppercase_all(base_word), vec![0x2c]].concat(), 199 | 113 => [uppercase_all(base_word), vec![0x28]].concat(), 200 | 114 => [uppercase_all(base_word), vec![0x2e, 0x20]].concat(), 201 | 115 => [vec![0x20], uppercase_all(base_word), vec![0x2e]].concat(), 202 | 116 => [uppercase_all(base_word), vec![0x3d, 0x27]].concat(), 203 | 117 => [vec![0x20], uppercase_all(base_word), vec![0x2e, 0x20]].concat(), 204 | 118 => [vec![0x20], uppercase_first(base_word), vec![0x3d, 0x22]].concat(), 205 | 119 => [vec![0x20], uppercase_all(base_word), vec![0x3d, 0x27]].concat(), 206 | 120 => [vec![0x20], uppercase_first(base_word), vec![0x3d, 0x27]].concat(), 207 | _ => unreachable!(), // confirmed unreachable, transform_id is checked prior to call 208 | } 209 | } 210 | 211 | #[cfg(test)] 212 | mod tests { 213 | use super::transformation; 214 | 215 | #[test] 216 | fn should_transform_0 () { 217 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 218 | 219 | let expected = "ä bäse wörd"; 220 | 221 | assert_eq!(String::from_utf8(transformation(0, &base_word)).unwrap(), String::from(expected)); 222 | } 223 | 224 | #[test] 225 | fn should_transform_1 () { 226 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 227 | 228 | let expected = "ä bäse wörd "; 229 | 230 | assert_eq!(String::from_utf8(transformation(1, &base_word)).unwrap(), String::from(expected)); 231 | } 232 | 233 | #[test] 234 | fn should_transform_2 () { 235 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 236 | 237 | let expected = " ä bäse wörd "; 238 | 239 | assert_eq!(String::from_utf8(transformation(2, &base_word)).unwrap(), String::from(expected)); 240 | } 241 | 242 | #[test] 243 | fn should_transform_3 () { 244 | let base_word = String::from("a bäse wörd").bytes().collect::>(); 245 | 246 | let expected = " bäse wörd"; 247 | 248 | assert_eq!(String::from_utf8(transformation(3, &base_word)).unwrap(), String::from(expected)); 249 | } 250 | 251 | #[test] 252 | fn should_transform_4 () { 253 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 254 | 255 | let expected = "Ä bäse wörd "; 256 | 257 | assert_eq!(String::from_utf8(transformation(4, &base_word)).unwrap(), String::from(expected)); 258 | } 259 | 260 | #[test] 261 | fn should_transform_5 () { 262 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 263 | 264 | let expected = "ä bäse wörd the "; 265 | 266 | assert_eq!(String::from_utf8(transformation(5, &base_word)).unwrap(), String::from(expected)); 267 | } 268 | 269 | #[test] 270 | fn should_transform_6 () { 271 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 272 | 273 | let expected = " ä bäse wörd"; 274 | 275 | assert_eq!(String::from_utf8(transformation(6, &base_word)).unwrap(), String::from(expected)); 276 | } 277 | 278 | #[test] 279 | fn should_transform_7 () { 280 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 281 | 282 | let expected = "s ä bäse wörd "; 283 | 284 | assert_eq!(String::from_utf8(transformation(7, &base_word)).unwrap(), String::from(expected)); 285 | } 286 | 287 | #[test] 288 | fn should_transform_8 () { 289 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 290 | 291 | let expected = "ä bäse wörd of "; 292 | 293 | assert_eq!(String::from_utf8(transformation(8, &base_word)).unwrap(), String::from(expected)); 294 | } 295 | 296 | #[test] 297 | fn should_transform_9 () { 298 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 299 | 300 | let expected = "Ä bäse wörd"; 301 | 302 | assert_eq!(String::from_utf8(transformation(9, &base_word)).unwrap(), String::from(expected)); 303 | } 304 | 305 | #[test] 306 | fn should_transform_10 () { 307 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 308 | 309 | let expected = "ä bäse wörd and "; 310 | 311 | assert_eq!(String::from_utf8(transformation(10, &base_word)).unwrap(), String::from(expected)); 312 | } 313 | 314 | #[test] 315 | fn should_transform_11 () { 316 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 317 | 318 | let expected = " bäse wörd"; 319 | 320 | assert_eq!(String::from_utf8(transformation(11, &base_word)).unwrap(), String::from(expected)); 321 | } 322 | 323 | #[test] 324 | fn should_transform_12 () { 325 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 326 | 327 | let expected = "ä bäse wör"; 328 | 329 | assert_eq!(String::from_utf8(transformation(12, &base_word)).unwrap(), String::from(expected)); 330 | } 331 | 332 | #[test] 333 | fn should_transform_13 () { 334 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 335 | 336 | let expected = ", ä bäse wörd "; 337 | 338 | assert_eq!(String::from_utf8(transformation(13, &base_word)).unwrap(), String::from(expected)); 339 | } 340 | #[test] 341 | fn should_transform_14 () { 342 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 343 | 344 | let expected = "ä bäse wörd, "; 345 | 346 | assert_eq!(String::from_utf8(transformation(14, &base_word)).unwrap(), String::from(expected)); 347 | } 348 | 349 | #[test] 350 | fn should_transform_15 () { 351 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 352 | 353 | let expected = " Ä bäse wörd "; 354 | 355 | assert_eq!(String::from_utf8(transformation(15, &base_word)).unwrap(), String::from(expected)); 356 | } 357 | 358 | #[test] 359 | fn should_transform_16 () { 360 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 361 | 362 | let expected = "ä bäse wörd in "; 363 | 364 | assert_eq!(String::from_utf8(transformation(16, &base_word)).unwrap(), String::from(expected)); 365 | } 366 | 367 | #[test] 368 | fn should_transform_17 () { 369 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 370 | 371 | let expected = "ä bäse wörd to "; 372 | 373 | assert_eq!(String::from_utf8(transformation(17, &base_word)).unwrap(), String::from(expected)); 374 | } 375 | 376 | #[test] 377 | fn should_transform_18 () { 378 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 379 | 380 | let expected = "e ä bäse wörd "; 381 | 382 | assert_eq!(String::from_utf8(transformation(18, &base_word)).unwrap(), String::from(expected)); 383 | } 384 | 385 | #[test] 386 | fn should_transform_19 () { 387 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 388 | 389 | let expected = "ä bäse wörd\""; 390 | 391 | assert_eq!(String::from_utf8(transformation(19, &base_word)).unwrap(), String::from(expected)); 392 | } 393 | 394 | #[test] 395 | fn should_transform_20 () { 396 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 397 | 398 | let expected = "ä bäse wörd."; 399 | 400 | assert_eq!(String::from_utf8(transformation(20, &base_word)).unwrap(), String::from(expected)); 401 | } 402 | 403 | #[test] 404 | fn should_transform_21 () { 405 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 406 | 407 | let expected = "ä bäse wörd\">"; 408 | 409 | assert_eq!(String::from_utf8(transformation(21, &base_word)).unwrap(), String::from(expected)); 410 | } 411 | 412 | #[test] 413 | fn should_transform_22 () { 414 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 415 | 416 | let expected = "ä bäse wörd\n"; 417 | 418 | assert_eq!(String::from_utf8(transformation(22, &base_word)).unwrap(), String::from(expected)); 419 | } 420 | 421 | #[test] 422 | fn should_transform_23 () { 423 | let base_word = String::from("ä bäse word").bytes().collect::>(); 424 | 425 | let expected = "ä bäse w"; 426 | 427 | assert_eq!(String::from_utf8(transformation(23, &base_word)).unwrap(), String::from(expected)); 428 | } 429 | 430 | #[test] 431 | fn should_transform_24 () { 432 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 433 | 434 | let expected = "ä bäse wörd]"; 435 | 436 | assert_eq!(String::from_utf8(transformation(24, &base_word)).unwrap(), String::from(expected)); 437 | } 438 | 439 | #[test] 440 | fn should_transform_25 () { 441 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 442 | 443 | let expected = "ä bäse wörd for "; 444 | 445 | assert_eq!(String::from_utf8(transformation(25, &base_word)).unwrap(), String::from(expected)); 446 | } 447 | 448 | #[test] 449 | fn should_transform_26 () { 450 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 451 | 452 | let expected = "bäse wörd"; 453 | 454 | assert_eq!(String::from_utf8(transformation(26, &base_word)).unwrap(), String::from(expected)); 455 | } 456 | 457 | #[test] 458 | fn should_transform_27 () { 459 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 460 | 461 | let expected = "ä bäse wö"; 462 | 463 | assert_eq!(String::from_utf8(transformation(27, &base_word)).unwrap(), String::from(expected)); 464 | } 465 | 466 | #[test] 467 | fn should_transform_28 () { 468 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 469 | 470 | let expected = "ä bäse wörd a "; 471 | 472 | assert_eq!(String::from_utf8(transformation(28, &base_word)).unwrap(), String::from(expected)); 473 | } 474 | 475 | #[test] 476 | fn should_transform_29 () { 477 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 478 | 479 | let expected = "ä bäse wörd that "; 480 | 481 | assert_eq!(String::from_utf8(transformation(29, &base_word)).unwrap(), String::from(expected)); 482 | } 483 | 484 | #[test] 485 | fn should_transform_30 () { 486 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 487 | 488 | let expected = " Ä bäse wörd"; 489 | 490 | assert_eq!(String::from_utf8(transformation(30, &base_word)).unwrap(), String::from(expected)); 491 | } 492 | 493 | #[test] 494 | fn should_transform_31 () { 495 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 496 | 497 | let expected = "ä bäse wörd. "; 498 | 499 | assert_eq!(String::from_utf8(transformation(31, &base_word)).unwrap(), String::from(expected)); 500 | } 501 | 502 | #[test] 503 | fn should_transform_32 () { 504 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 505 | 506 | let expected = ".ä bäse wörd"; 507 | 508 | assert_eq!(String::from_utf8(transformation(32, &base_word)).unwrap(), String::from(expected)); 509 | } 510 | 511 | #[test] 512 | fn should_transform_33 () { 513 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 514 | 515 | let expected = " ä bäse wörd, "; 516 | 517 | assert_eq!(String::from_utf8(transformation(33, &base_word)).unwrap(), String::from(expected)); 518 | } 519 | 520 | #[test] 521 | fn should_transform_34 () { 522 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 523 | 524 | let expected = "äse wörd"; 525 | 526 | assert_eq!(String::from_utf8(transformation(34, &base_word)).unwrap(), String::from(expected)); 527 | } 528 | 529 | #[test] 530 | fn should_transform_35 () { 531 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 532 | 533 | let expected = "ä bäse wörd with "; 534 | 535 | assert_eq!(String::from_utf8(transformation(35, &base_word)).unwrap(), String::from(expected)); 536 | } 537 | 538 | #[test] 539 | fn should_transform_36 () { 540 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 541 | 542 | let expected = "ä bäse wörd'"; 543 | 544 | assert_eq!(String::from_utf8(transformation(36, &base_word)).unwrap(), String::from(expected)); 545 | } 546 | 547 | #[test] 548 | fn should_transform_37 () { 549 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 550 | 551 | let expected = "ä bäse wörd from "; 552 | 553 | assert_eq!(String::from_utf8(transformation(37, &base_word)).unwrap(), String::from(expected)); 554 | } 555 | 556 | #[test] 557 | fn should_transform_38 () { 558 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 559 | 560 | let expected = "ä bäse wörd by "; 561 | 562 | assert_eq!(String::from_utf8(transformation(38, &base_word)).unwrap(), String::from(expected)); 563 | } 564 | 565 | #[test] 566 | fn should_transform_39 () { 567 | let base_word = String::from("ä base wörd").bytes().collect::>(); 568 | 569 | let expected = "se wörd"; 570 | 571 | assert_eq!(String::from_utf8(transformation(39, &base_word)).unwrap(), String::from(expected)); 572 | } 573 | 574 | #[test] 575 | fn should_transform_40 () { 576 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 577 | 578 | let expected = "se wörd"; 579 | 580 | assert_eq!(String::from_utf8(transformation(40, &base_word)).unwrap(), String::from(expected)); 581 | } 582 | 583 | #[test] 584 | fn should_transform_41 () { 585 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 586 | 587 | let expected = " the ä bäse wörd"; 588 | 589 | assert_eq!(String::from_utf8(transformation(41, &base_word)).unwrap(), String::from(expected)); 590 | } 591 | 592 | #[test] 593 | fn should_transform_42 () { 594 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 595 | 596 | let expected = "ä bäse w"; 597 | 598 | assert_eq!(String::from_utf8(transformation(42, &base_word)).unwrap(), String::from(expected)); 599 | } 600 | 601 | #[test] 602 | fn should_transform_43 () { 603 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 604 | 605 | let expected = "ä bäse wörd. The "; 606 | 607 | assert_eq!(String::from_utf8(transformation(43, &base_word)).unwrap(), String::from(expected)); 608 | } 609 | 610 | #[test] 611 | fn should_transform_44 () { 612 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 613 | 614 | let expected = "Ä BÄSE WÖRD"; 615 | 616 | assert_eq!(String::from_utf8(transformation(44, &base_word)).unwrap(), String::from(expected)); 617 | } 618 | 619 | #[test] 620 | fn should_transform_45 () { 621 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 622 | 623 | let expected = "ä bäse wörd on "; 624 | 625 | assert_eq!(String::from_utf8(transformation(45, &base_word)).unwrap(), String::from(expected)); 626 | } 627 | 628 | #[test] 629 | fn should_transform_46 () { 630 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 631 | 632 | let expected = "ä bäse wörd as "; 633 | 634 | assert_eq!(String::from_utf8(transformation(46, &base_word)).unwrap(), String::from(expected)); 635 | } 636 | 637 | #[test] 638 | fn should_transform_47 () { 639 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 640 | 641 | let expected = "ä bäse wörd is "; 642 | 643 | assert_eq!(String::from_utf8(transformation(47, &base_word)).unwrap(), String::from(expected)); 644 | } 645 | 646 | #[test] 647 | fn should_transform_48 () { 648 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 649 | 650 | let expected = "ä bäs"; 651 | 652 | assert_eq!(String::from_utf8(transformation(48, &base_word)).unwrap(), String::from(expected)); 653 | } 654 | 655 | #[test] 656 | fn should_transform_49 () { 657 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 658 | 659 | let expected = "ä bäse wöring "; 660 | 661 | assert_eq!(String::from_utf8(transformation(49, &base_word)).unwrap(), String::from(expected)); 662 | } 663 | 664 | #[test] 665 | fn should_transform_50 () { 666 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 667 | 668 | let expected = "ä bäse wörd\n\t"; 669 | 670 | assert_eq!(String::from_utf8(transformation(50, &base_word)).unwrap(), String::from(expected)); 671 | } 672 | 673 | #[test] 674 | fn should_transform_51 () { 675 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 676 | 677 | let expected = "ä bäse wörd:"; 678 | 679 | assert_eq!(String::from_utf8(transformation(51, &base_word)).unwrap(), String::from(expected)); 680 | } 681 | 682 | #[test] 683 | fn should_transform_52 () { 684 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 685 | 686 | let expected = " ä bäse wörd. "; 687 | 688 | assert_eq!(String::from_utf8(transformation(52, &base_word)).unwrap(), String::from(expected)); 689 | } 690 | 691 | #[test] 692 | fn should_transform_53 () { 693 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 694 | 695 | let expected = "ä bäse wörded "; 696 | 697 | assert_eq!(String::from_utf8(transformation(53, &base_word)).unwrap(), String::from(expected)); 698 | } 699 | 700 | #[test] 701 | fn should_transform_54 () { 702 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 703 | 704 | let expected = "wörd"; 705 | 706 | assert_eq!(String::from_utf8(transformation(54, &base_word)).unwrap(), String::from(expected)); 707 | } 708 | 709 | #[test] 710 | fn should_transform_55 () { 711 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 712 | 713 | let expected = "e wörd"; 714 | 715 | assert_eq!(String::from_utf8(transformation(55, &base_word)).unwrap(), String::from(expected)); 716 | } 717 | 718 | #[test] 719 | fn should_transform_56 () { 720 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 721 | 722 | let expected = "ä bäse"; 723 | 724 | assert_eq!(String::from_utf8(transformation(56, &base_word)).unwrap(), String::from(expected)); 725 | } 726 | 727 | #[test] 728 | fn should_transform_57 () { 729 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 730 | 731 | let expected = "ä bäse wörd("; 732 | 733 | assert_eq!(String::from_utf8(transformation(57, &base_word)).unwrap(), String::from(expected)); 734 | } 735 | 736 | #[test] 737 | fn should_transform_58 () { 738 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 739 | 740 | let expected = "Ä bäse wörd, "; 741 | 742 | assert_eq!(String::from_utf8(transformation(58, &base_word)).unwrap(), String::from(expected)); 743 | } 744 | 745 | #[test] 746 | fn should_transform_59 () { 747 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 748 | 749 | let expected = "ä bä"; 750 | 751 | assert_eq!(String::from_utf8(transformation(59, &base_word)).unwrap(), String::from(expected)); 752 | } 753 | 754 | #[test] 755 | fn should_transform_60 () { 756 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 757 | 758 | let expected = "ä bäse wörd at "; 759 | 760 | assert_eq!(String::from_utf8(transformation(60, &base_word)).unwrap(), String::from(expected)); 761 | } 762 | 763 | #[test] 764 | fn should_transform_61 () { 765 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 766 | 767 | let expected = "ä bäse wördly "; 768 | 769 | assert_eq!(String::from_utf8(transformation(61, &base_word)).unwrap(), String::from(expected)); 770 | } 771 | 772 | #[test] 773 | fn should_transform_62 () { 774 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 775 | 776 | let expected = " the ä bäse wörd of "; 777 | 778 | assert_eq!(String::from_utf8(transformation(62, &base_word)).unwrap(), String::from(expected)); 779 | } 780 | 781 | #[test] 782 | fn should_transform_63 () { 783 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 784 | 785 | let expected = "ä bäse "; 786 | 787 | assert_eq!(String::from_utf8(transformation(63, &base_word)).unwrap(), String::from(expected)); 788 | } 789 | 790 | #[test] 791 | fn should_transform_64 () { 792 | let base_word = String::from("ä base wörd").bytes().collect::>(); 793 | 794 | let expected = "ä b"; 795 | 796 | assert_eq!(String::from_utf8(transformation(64, &base_word)).unwrap(), String::from(expected)); 797 | } 798 | 799 | #[test] 800 | fn should_transform_65 () { 801 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 802 | 803 | let expected = " Ä bäse wörd, "; 804 | 805 | assert_eq!(String::from_utf8(transformation(65, &base_word)).unwrap(), String::from(expected)); 806 | } 807 | 808 | #[test] 809 | fn should_transform_66 () { 810 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 811 | 812 | let expected = "Ä bäse wörd\""; 813 | 814 | assert_eq!(String::from_utf8(transformation(66, &base_word)).unwrap(), String::from(expected)); 815 | } 816 | 817 | #[test] 818 | fn should_transform_67 () { 819 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 820 | 821 | let expected = ".ä bäse wörd("; 822 | 823 | assert_eq!(String::from_utf8(transformation(67, &base_word)).unwrap(), String::from(expected)); 824 | } 825 | 826 | #[test] 827 | fn should_transform_68 () { 828 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 829 | 830 | let expected = "Ä BÄSE WÖRD "; 831 | 832 | assert_eq!(String::from_utf8(transformation(68, &base_word)).unwrap(), String::from(expected)); 833 | } 834 | 835 | #[test] 836 | fn should_transform_69 () { 837 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 838 | 839 | let expected = "Ä bäse wörd\">"; 840 | 841 | assert_eq!(String::from_utf8(transformation(69, &base_word)).unwrap(), String::from(expected)); 842 | } 843 | 844 | #[test] 845 | fn should_transform_70 () { 846 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 847 | 848 | let expected = "ä bäse wörd=\""; 849 | 850 | assert_eq!(String::from_utf8(transformation(70, &base_word)).unwrap(), String::from(expected)); 851 | } 852 | 853 | #[test] 854 | fn should_transform_71 () { 855 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 856 | 857 | let expected = " ä bäse wörd."; 858 | 859 | assert_eq!(String::from_utf8(transformation(71, &base_word)).unwrap(), String::from(expected)); 860 | } 861 | 862 | #[test] 863 | fn should_transform_72 () { 864 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 865 | 866 | let expected = ".com/ä bäse wörd"; 867 | 868 | assert_eq!(String::from_utf8(transformation(72, &base_word)).unwrap(), String::from(expected)); 869 | } 870 | 871 | #[test] 872 | fn should_transform_73 () { 873 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 874 | 875 | let expected = " the ä bäse wörd of the "; 876 | 877 | assert_eq!(String::from_utf8(transformation(73, &base_word)).unwrap(), String::from(expected)); 878 | } 879 | 880 | #[test] 881 | fn should_transform_74 () { 882 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 883 | 884 | let expected = "Ä bäse wörd'"; 885 | 886 | assert_eq!(String::from_utf8(transformation(74, &base_word)).unwrap(), String::from(expected)); 887 | } 888 | 889 | #[test] 890 | fn should_transform_75 () { 891 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 892 | 893 | let expected = "ä bäse wörd. This "; 894 | 895 | assert_eq!(String::from_utf8(transformation(75, &base_word)).unwrap(), String::from(expected)); 896 | } 897 | 898 | #[test] 899 | fn should_transform_76 () { 900 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 901 | 902 | let expected = "ä bäse wörd,"; 903 | 904 | assert_eq!(String::from_utf8(transformation(76, &base_word)).unwrap(), String::from(expected)); 905 | } 906 | 907 | #[test] 908 | fn should_transform_77 () { 909 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 910 | 911 | let expected = ".ä bäse wörd "; 912 | 913 | assert_eq!(String::from_utf8(transformation(77, &base_word)).unwrap(), String::from(expected)); 914 | } 915 | 916 | #[test] 917 | fn should_transform_78 () { 918 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 919 | 920 | let expected = "Ä bäse wörd("; 921 | 922 | assert_eq!(String::from_utf8(transformation(78, &base_word)).unwrap(), String::from(expected)); 923 | } 924 | 925 | #[test] 926 | fn should_transform_79 () { 927 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 928 | 929 | let expected = "Ä bäse wörd."; 930 | 931 | assert_eq!(String::from_utf8(transformation(79, &base_word)).unwrap(), String::from(expected)); 932 | } 933 | 934 | #[test] 935 | fn should_transform_80 () { 936 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 937 | 938 | let expected = "ä bäse wörd not "; 939 | 940 | assert_eq!(String::from_utf8(transformation(80, &base_word)).unwrap(), String::from(expected)); 941 | } 942 | 943 | #[test] 944 | fn should_transform_81 () { 945 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 946 | 947 | let expected = " ä bäse wörd=\""; 948 | 949 | assert_eq!(String::from_utf8(transformation(81, &base_word)).unwrap(), String::from(expected)); 950 | } 951 | 952 | #[test] 953 | fn should_transform_82 () { 954 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 955 | 956 | let expected = "ä bäse wörder "; 957 | 958 | assert_eq!(String::from_utf8(transformation(82, &base_word)).unwrap(), String::from(expected)); 959 | } 960 | 961 | #[test] 962 | fn should_transform_83 () { 963 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 964 | 965 | let expected = " Ä BÄSE WÖRD "; 966 | 967 | assert_eq!(String::from_utf8(transformation(83, &base_word)).unwrap(), String::from(expected)); 968 | } 969 | 970 | #[test] 971 | fn should_transform_84 () { 972 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 973 | 974 | let expected = "ä bäse wördal "; 975 | 976 | assert_eq!(String::from_utf8(transformation(84, &base_word)).unwrap(), String::from(expected)); 977 | } 978 | 979 | #[test] 980 | fn should_transform_85 () { 981 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 982 | 983 | let expected = " Ä BÄSE WÖRD"; 984 | 985 | assert_eq!(String::from_utf8(transformation(85, &base_word)).unwrap(), String::from(expected)); 986 | } 987 | 988 | #[test] 989 | fn should_transform_86 () { 990 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 991 | 992 | let expected = "ä bäse wörd='"; 993 | 994 | assert_eq!(String::from_utf8(transformation(86, &base_word)).unwrap(), String::from(expected)); 995 | } 996 | 997 | #[test] 998 | fn should_transform_87 () { 999 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 1000 | 1001 | let expected = "Ä BÄSE WÖRD\""; 1002 | 1003 | assert_eq!(String::from_utf8(transformation(87, &base_word)).unwrap(), String::from(expected)); 1004 | } 1005 | 1006 | #[test] 1007 | fn should_transform_88 () { 1008 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 1009 | 1010 | let expected = "Ä bäse wörd. "; 1011 | 1012 | assert_eq!(String::from_utf8(transformation(88, &base_word)).unwrap(), String::from(expected)); 1013 | } 1014 | 1015 | #[test] 1016 | fn should_transform_89 () { 1017 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 1018 | 1019 | let expected = " ä bäse wörd("; 1020 | 1021 | assert_eq!(String::from_utf8(transformation(89, &base_word)).unwrap(), String::from(expected)); 1022 | } 1023 | 1024 | #[test] 1025 | fn should_transform_90 () { 1026 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 1027 | 1028 | let expected = "ä bäse wördful "; 1029 | 1030 | assert_eq!(String::from_utf8(transformation(90, &base_word)).unwrap(), String::from(expected)); 1031 | } 1032 | 1033 | #[test] 1034 | fn should_transform_91 () { 1035 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 1036 | 1037 | let expected = " Ä bäse wörd. "; 1038 | 1039 | assert_eq!(String::from_utf8(transformation(91, &base_word)).unwrap(), String::from(expected)); 1040 | } 1041 | 1042 | #[test] 1043 | fn should_transform_92 () { 1044 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 1045 | 1046 | let expected = "ä bäse wördive "; 1047 | 1048 | assert_eq!(String::from_utf8(transformation(92, &base_word)).unwrap(), String::from(expected)); 1049 | } 1050 | 1051 | #[test] 1052 | fn should_transform_93 () { 1053 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 1054 | 1055 | let expected = "ä bäse wördless "; 1056 | 1057 | assert_eq!(String::from_utf8(transformation(93, &base_word)).unwrap(), String::from(expected)); 1058 | } 1059 | 1060 | #[test] 1061 | fn should_transform_94 () { 1062 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 1063 | 1064 | let expected = "Ä BÄSE WÖRD'"; 1065 | 1066 | assert_eq!(String::from_utf8(transformation(94, &base_word)).unwrap(), String::from(expected)); 1067 | } 1068 | 1069 | #[test] 1070 | fn should_transform_95 () { 1071 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 1072 | 1073 | let expected = "ä bäse wördest "; 1074 | 1075 | assert_eq!(String::from_utf8(transformation(95, &base_word)).unwrap(), String::from(expected)); 1076 | } 1077 | 1078 | #[test] 1079 | fn should_transform_96 () { 1080 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 1081 | 1082 | let expected = " Ä bäse wörd."; 1083 | 1084 | assert_eq!(String::from_utf8(transformation(96, &base_word)).unwrap(), String::from(expected)); 1085 | } 1086 | 1087 | #[test] 1088 | fn should_transform_97 () { 1089 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 1090 | 1091 | let expected = "Ä BÄSE WÖRD\">"; 1092 | 1093 | assert_eq!(String::from_utf8(transformation(97, &base_word)).unwrap(), String::from(expected)); 1094 | } 1095 | 1096 | #[test] 1097 | fn should_transform_98 () { 1098 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 1099 | 1100 | let expected = " ä bäse wörd='"; 1101 | 1102 | assert_eq!(String::from_utf8(transformation(98, &base_word)).unwrap(), String::from(expected)); 1103 | } 1104 | 1105 | #[test] 1106 | fn should_transform_99 () { 1107 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 1108 | 1109 | let expected = "Ä bäse wörd,"; 1110 | 1111 | assert_eq!(String::from_utf8(transformation(99, &base_word)).unwrap(), String::from(expected)); 1112 | } 1113 | 1114 | #[test] 1115 | fn should_transform_100 () { 1116 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 1117 | 1118 | let expected = "ä bäse wördize "; 1119 | 1120 | assert_eq!(String::from_utf8(transformation(100, &base_word)).unwrap(), String::from(expected)); 1121 | } 1122 | 1123 | #[test] 1124 | fn should_transform_101 () { 1125 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 1126 | 1127 | let expected = "Ä BÄSE WÖRD."; 1128 | 1129 | assert_eq!(String::from_utf8(transformation(101, &base_word)).unwrap(), String::from(expected)); 1130 | } 1131 | 1132 | #[test] 1133 | fn should_transform_102 () { 1134 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 1135 | 1136 | let expected = [vec![0xc2, 0xa0], base_word.clone()].concat(); 1137 | 1138 | assert_eq!(transformation(102, &base_word), expected); 1139 | } 1140 | 1141 | #[test] 1142 | fn should_transform_103 () { 1143 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 1144 | 1145 | let expected = " ä bäse wörd,"; 1146 | 1147 | assert_eq!(String::from_utf8(transformation(103, &base_word)).unwrap(), String::from(expected)); 1148 | } 1149 | 1150 | #[test] 1151 | fn should_transform_104 () { 1152 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 1153 | 1154 | let expected = "Ä bäse wörd=\""; 1155 | 1156 | assert_eq!(String::from_utf8(transformation(104, &base_word)).unwrap(), String::from(expected)); 1157 | } 1158 | 1159 | #[test] 1160 | fn should_transform_105 () { 1161 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 1162 | 1163 | let expected = "Ä BÄSE WÖRD=\""; 1164 | 1165 | assert_eq!(String::from_utf8(transformation(105, &base_word)).unwrap(), String::from(expected)); 1166 | } 1167 | 1168 | #[test] 1169 | fn should_transform_106 () { 1170 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 1171 | 1172 | let expected = "ä bäse wördous "; 1173 | 1174 | assert_eq!(String::from_utf8(transformation(106, &base_word)).unwrap(), String::from(expected)); 1175 | } 1176 | 1177 | #[test] 1178 | fn should_transform_107 () { 1179 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 1180 | 1181 | let expected = "Ä BÄSE WÖRD, "; 1182 | 1183 | assert_eq!(String::from_utf8(transformation(107, &base_word)).unwrap(), String::from(expected)); 1184 | } 1185 | 1186 | #[test] 1187 | fn should_transform_108 () { 1188 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 1189 | 1190 | let expected = "Ä bäse wörd='"; 1191 | 1192 | assert_eq!(String::from_utf8(transformation(108, &base_word)).unwrap(), String::from(expected)); 1193 | } 1194 | 1195 | #[test] 1196 | fn should_transform_109 () { 1197 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 1198 | 1199 | let expected = " Ä bäse wörd,"; 1200 | 1201 | assert_eq!(String::from_utf8(transformation(109, &base_word)).unwrap(), String::from(expected)); 1202 | } 1203 | 1204 | #[test] 1205 | fn should_transform_110 () { 1206 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 1207 | 1208 | let expected = " Ä BÄSE WÖRD=\""; 1209 | 1210 | assert_eq!(String::from_utf8(transformation(110, &base_word)).unwrap(), String::from(expected)); 1211 | } 1212 | 1213 | #[test] 1214 | fn should_transform_111 () { 1215 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 1216 | 1217 | let expected = " Ä BÄSE WÖRD, "; 1218 | 1219 | assert_eq!(String::from_utf8(transformation(111, &base_word)).unwrap(), String::from(expected)); 1220 | } 1221 | 1222 | #[test] 1223 | fn should_transform_112 () { 1224 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 1225 | 1226 | let expected = "Ä BÄSE WÖRD,"; 1227 | 1228 | assert_eq!(String::from_utf8(transformation(112, &base_word)).unwrap(), String::from(expected)); 1229 | } 1230 | 1231 | #[test] 1232 | fn should_transform_113 () { 1233 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 1234 | 1235 | let expected = "Ä BÄSE WÖRD("; 1236 | 1237 | assert_eq!(String::from_utf8(transformation(113, &base_word)).unwrap(), String::from(expected)); 1238 | } 1239 | 1240 | #[test] 1241 | fn should_transform_114 () { 1242 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 1243 | 1244 | let expected = "Ä BÄSE WÖRD. "; 1245 | 1246 | assert_eq!(String::from_utf8(transformation(114, &base_word)).unwrap(), String::from(expected)); 1247 | } 1248 | 1249 | #[test] 1250 | fn should_transform_115 () { 1251 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 1252 | 1253 | let expected = " Ä BÄSE WÖRD."; 1254 | 1255 | assert_eq!(String::from_utf8(transformation(115, &base_word)).unwrap(), String::from(expected)); 1256 | } 1257 | 1258 | #[test] 1259 | fn should_transform_116 () { 1260 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 1261 | 1262 | let expected = "Ä BÄSE WÖRD='"; 1263 | 1264 | assert_eq!(String::from_utf8(transformation(116, &base_word)).unwrap(), String::from(expected)); 1265 | } 1266 | 1267 | #[test] 1268 | fn should_transform_117 () { 1269 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 1270 | 1271 | let expected = " Ä BÄSE WÖRD. "; 1272 | 1273 | assert_eq!(String::from_utf8(transformation(117, &base_word)).unwrap(), String::from(expected)); 1274 | } 1275 | 1276 | #[test] 1277 | fn should_transform_118 () { 1278 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 1279 | 1280 | let expected = " Ä bäse wörd=\""; 1281 | 1282 | assert_eq!(String::from_utf8(transformation(118, &base_word)).unwrap(), String::from(expected)); 1283 | } 1284 | 1285 | #[test] 1286 | fn should_transform_119 () { 1287 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 1288 | 1289 | let expected = " Ä BÄSE WÖRD='"; 1290 | 1291 | assert_eq!(String::from_utf8(transformation(119, &base_word)).unwrap(), String::from(expected)); 1292 | } 1293 | 1294 | #[test] 1295 | fn should_transform_120 () { 1296 | let base_word = String::from("ä bäse wörd").bytes().collect::>(); 1297 | 1298 | let expected = " Ä bäse wörd='"; 1299 | 1300 | assert_eq!(String::from_utf8(transformation(120, &base_word)).unwrap(), String::from(expected)); 1301 | } 1302 | } 1303 | -------------------------------------------------------------------------------- /tests/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate brotli; 2 | 3 | 4 | #[test] 5 | /// Brotli: Empty file 6 | fn should_decompress_to_empty_string() { 7 | use std::io::{ Cursor, Read }; 8 | use brotli::Decompressor; 9 | 10 | let brotli_stream = Cursor::new(vec![ 11 | 0x06 12 | ]); 13 | 14 | let mut decompressed = &mut String::new(); 15 | let _ = Decompressor::new(brotli_stream).read_to_string(&mut decompressed); 16 | 17 | assert_eq!("", decompressed); 18 | } 19 | 20 | #[test] 21 | /// Brotli: Empty file #01 22 | fn should_decompress_to_empty_string_01() { 23 | use std::io::{ Cursor, Read }; 24 | use brotli::Decompressor; 25 | 26 | let brotli_stream = Cursor::new(vec![ 27 | 0x81, 0x01 28 | ]); 29 | 30 | let mut decompressed = &mut String::new(); 31 | let _ = Decompressor::new(brotli_stream).read_to_string(&mut decompressed); 32 | 33 | assert_eq!("", decompressed); 34 | } 35 | 36 | #[test] 37 | #[should_panic(expected="non-zero bit")] 38 | fn should_reject_invalid_stream_with_trailing_non_zero_bits() { 39 | use std::io::{ Cursor, Read }; 40 | use brotli::Decompressor; 41 | 42 | let brotli_stream = Cursor::new(vec![ 43 | 0xa1, 0x03, 44 | ]); 45 | 46 | let mut decompressed = &mut String::new(); 47 | let result = Decompressor::new(brotli_stream).read_to_string(&mut decompressed); 48 | 49 | match result { 50 | Err(e) => panic!("{:?}", e), 51 | _ => {}, 52 | } 53 | } 54 | 55 | #[test] 56 | /// Brotli: Empty file #15 57 | fn should_decompress_to_empty_string_15() { 58 | use std::io::{ Cursor, Read }; 59 | use brotli::Decompressor; 60 | 61 | let brotli_stream = Cursor::new(vec![ 62 | 0x1a, 63 | ]); 64 | 65 | let mut decompressed = &mut String::new(); 66 | let _ = Decompressor::new(brotli_stream).read_to_string(&mut decompressed); 67 | 68 | assert_eq!("", decompressed); 69 | } 70 | 71 | #[test] 72 | /// Brotli: Empty file #16 73 | fn should_decompress_to_empty_string_16() { 74 | use std::io::{ Cursor, Read }; 75 | use brotli::Decompressor; 76 | 77 | let brotli_stream = Cursor::new(vec![ 78 | 0x81, 0x16, 0x00, 0x58 79 | ]); 80 | 81 | let mut decompressed = &mut String::new(); 82 | let _ = Decompressor::new(brotli_stream).read_to_string(&mut decompressed); 83 | 84 | assert_eq!("", decompressed); 85 | } 86 | 87 | #[test] 88 | /// Brotli: Empty file 89 | #[should_panic(expected="More uncompressed bytes than expected in meta-block")] 90 | fn should_reject_invalid_stream_with_transformed_item_trailing_bytes() { 91 | use std::io::{ Cursor, Read }; 92 | use brotli::Decompressor; 93 | 94 | let brotli_stream = Cursor::new(vec![ 95 | 0x1b, 0x14, 0x00, 0x00, 0x24, 0x00, 0x62, 0x98, 0xc8, 0x0e 96 | ]); 97 | 98 | let mut decompressed = &mut String::new(); 99 | let result = Decompressor::new(brotli_stream).read_to_string(&mut decompressed); 100 | 101 | match result { 102 | Err(e) => panic!("{:?}", e), 103 | _ => {}, 104 | } 105 | } 106 | 107 | #[test] 108 | /// Brotli: transformed dictionary item to be 1 byte longer 109 | fn should_decompress_transformed_item() { 110 | use std::io::{ Cursor, Read }; 111 | use brotli::Decompressor; 112 | 113 | let brotli_stream = Cursor::new(vec![ 114 | 0x1b, 0x15, 0x00, 0x00, 0x24, 0x00, 0x62, 0x98, 0xc8, 0x0e 115 | ]); 116 | 117 | let mut decompressed = &mut String::new(); 118 | let _ = Decompressor::new(brotli_stream).read_to_string(&mut decompressed); 119 | 120 | assert_eq!("often referred to as ", decompressed); 121 | } 122 | 123 | 124 | 125 | #[test] 126 | /// Brotli: Empty file 127 | #[should_panic(expected="Expected end-of-stream, but stream did not end")] 128 | fn should_reject_invalid_stream_with_trailing_bytes() { 129 | use std::io::{ Cursor, Read }; 130 | use brotli::Decompressor; 131 | 132 | let brotli_stream = Cursor::new(vec![ 133 | 0x1a, 0xff 134 | ]); 135 | 136 | let mut decompressed = &mut String::new(); 137 | let result = Decompressor::new(brotli_stream).read_to_string(&mut decompressed); 138 | 139 | match result { 140 | Err(e) => panic!("{:?}", e), 141 | _ => {}, 142 | } 143 | } 144 | 145 | 146 | #[test] 147 | /// Brotli: Empty file #17 148 | fn should_decompress_to_empty_string_17() { 149 | use std::fs::{ File }; 150 | use std::io::{ Read }; 151 | use brotli::Decompressor; 152 | 153 | let brotli_stream = File::open("data/empty.compressed.17").unwrap(); 154 | 155 | let mut decompressed = &mut String::new(); 156 | let _ = Decompressor::new(brotli_stream).read_to_string(&mut decompressed); 157 | 158 | assert_eq!("", decompressed); 159 | } 160 | 161 | #[test] 162 | /// Brotli: X file 163 | fn should_decompress_to_x() { 164 | use std::io::{ Cursor, Read }; 165 | use brotli::Decompressor; 166 | 167 | let brotli_stream = Cursor::new(vec![ 168 | 0x0b, 0x00, 0x80, 0x58, 0x03, 169 | ]); 170 | 171 | let mut decompressed = &mut String::new(); 172 | let _ = Decompressor::new(brotli_stream).read_to_string(&mut decompressed); 173 | 174 | assert_eq!("X", decompressed); 175 | } 176 | 177 | #[test] 178 | /// Brotli: X file #03 179 | fn should_decompress_to_x_03() { 180 | use std::io::{ Cursor, Read }; 181 | use brotli::Decompressor; 182 | 183 | let brotli_stream = Cursor::new(vec![ 184 | 0xa1, 0x00, 0x00, 0x00, 0x00, 0x81, 0x15, 0x08, 0x04, 0x00, 185 | ]); 186 | 187 | let mut decompressed = &mut String::new(); 188 | let _ = Decompressor::new(brotli_stream).read_to_string(&mut decompressed); 189 | 190 | assert_eq!("X", decompressed); 191 | } 192 | 193 | #[test] 194 | /// Brotli: 10x10y 195 | fn should_decompress_to_10x10y() { 196 | use std::io::{ Cursor, Read }; 197 | use brotli::Decompressor; 198 | 199 | let brotli_stream = Cursor::new(vec![ 200 | 0x1b, 0x13, 0x00, 0x00, 0xa4, 0xb0, 0xb2, 0xea, 0x81, 0x47, 0x02, 0x8a, 201 | ]); 202 | 203 | let mut decompressed = &mut String::new(); 204 | let _ = Decompressor::new(brotli_stream).read_to_string(&mut decompressed); 205 | 206 | assert_eq!("XXXXXXXXXXYYYYYYYYYY", decompressed); 207 | } 208 | 209 | #[test] 210 | /// Brotli: ukkonooa 211 | /// introduces complex prefix trees, multiple trees, non-zero context maps 212 | fn should_decompress_ukkonooa() { 213 | use std::io::{ Cursor, Read }; 214 | use brotli::Decompressor; 215 | 216 | let brotli_stream = Cursor::new(vec![ 217 | 0x1b, 0x76, 0x00, 0x00, 0x14, 0x4a, 0xac, 0x9b, 0x7a, 0xbd, 0xe1, 0x97, 0x9d, 0x7f, 0x8e, 0xc2, 218 | 0x82, 0x36, 0x0e, 0x9c, 0xe0, 0x90, 0x03, 0xf7, 0x8b, 0x9e, 0x38, 0xe6, 0xb6, 0x00, 0xab, 0xc3, 219 | 0xca, 0xa0, 0xc2, 0xda, 0x66, 0x36, 0xdc, 0xcd, 0x80, 0x8d, 0x2e, 0x21, 0xd7, 0x6e, 0xe3, 0xea, 220 | 0x4c, 0xb8, 0xf0, 0xd2, 0xb8, 0xc7, 0xc2, 0x70, 0x4d, 0x3a, 0xf0, 0x69, 0x7e, 0xa1, 0xb8, 0x45, 221 | 0x73, 0xab, 0xc4, 0x57, 0x1e, 222 | ]); 223 | 224 | let mut decompressed = &mut String::new(); 225 | let _ = Decompressor::new(brotli_stream).read_to_string(&mut decompressed); 226 | 227 | assert_eq!("ukko nooa, ukko nooa oli kunnon mies, kun han meni saunaan, pisti laukun naulaan, ukko nooa, ukko nooa oli kunnon mies.", decompressed); 228 | } 229 | 230 | 231 | #[test] 232 | /// Dictionary unending 233 | fn should_decompress_ends_with_truncated_dictionary() { 234 | use std::io::{ Cursor, Read }; 235 | use brotli::Decompressor; 236 | 237 | let brotli_stream = Cursor::new(vec![0x1b, 0x0d, 0x00, 0x00, 0x24, 0x00, 0x62, 0x98, 0x28, 0x0b, 0x3f]); 238 | let mut decompressed = &mut String::new(); 239 | let _ = Decompressor::new(brotli_stream).read_to_string(&mut decompressed); 240 | 241 | assert_eq!("number of diff", decompressed); 242 | } 243 | 244 | #[test] 245 | /// Brotli: monkey 246 | /// introduces static dictionary reference, multiple trees for literals 247 | fn should_decompress_monkey() { 248 | use std::io::{ Cursor, Read }; 249 | use brotli::Decompressor; 250 | 251 | let brotli_stream = Cursor::new(vec![ 252 | 0x1b, 0x4a, 0x03, 0x00, 0x8c, 0x94, 0x6e, 0xde, 0xb4, 0xd7, 0x96, 0xb1, 0x78, 0x86, 0xf2, 0x2d, 253 | 0xe1, 0x1a, 0xbc, 0x0b, 0x1c, 0xba, 0xa9, 0xc7, 0xf7, 0xcc, 0x6e, 0xb2, 0x42, 0x34, 0x51, 0x44, 254 | 0x8b, 0x4e, 0x13, 0x08, 0xa0, 0xcd, 0x6e, 0xe8, 0x2c, 0xa5, 0x53, 0xa1, 0x9c, 0x5d, 0x2c, 0x1d, 255 | 0x23, 0x1a, 0xd2, 0x56, 0xbe, 0xdb, 0xeb, 0x26, 0xba, 0x03, 0x65, 0x7c, 0x96, 0x6a, 0xa2, 0x76, 256 | 0xec, 0xef, 0x87, 0x47, 0x33, 0xd6, 0x27, 0x0e, 0x63, 0x95, 0xe2, 0x1d, 0x8d, 0x2c, 0xc5, 0xd1, 257 | 0x28, 0x9f, 0x60, 0x94, 0x6f, 0x02, 0x8b, 0xdd, 0xaa, 0x64, 0x94, 0x2c, 0x1e, 0x3b, 0x65, 0x7c, 258 | 0x07, 0x45, 0x5a, 0xb2, 0xe2, 0xfc, 0x49, 0x81, 0x2c, 0x9f, 0x40, 0xae, 0xef, 0x68, 0x81, 0xac, 259 | 0x16, 0x7a, 0x0f, 0xf5, 0x3b, 0x6d, 0x1c, 0xb9, 0x1e, 0x2d, 0x5f, 0xd5, 0xc8, 0xaf, 0x5e, 0x85, 260 | 0xaa, 0x05, 0xbe, 0x53, 0x75, 0xc2, 0xb0, 0x22, 0x8a, 0x15, 0xc6, 0xa3, 0xb1, 0xe6, 0x42, 0x14, 261 | 0xf4, 0x84, 0x54, 0x53, 0x19, 0x5f, 0xbe, 0xc3, 0xf2, 0x1d, 0xd1, 0xb7, 0xe5, 0xdd, 0xb6, 0xd9, 262 | 0x23, 0xc6, 0xf6, 0x9f, 0x9e, 0xf6, 0x4d, 0x65, 0x30, 0xfb, 0xc0, 0x71, 0x45, 0x04, 0xad, 0x03, 263 | 0xb5, 0xbe, 0xc9, 0xcb, 0xfd, 0xe2, 0x50, 0x5a, 0x46, 0x74, 0x04, 0x0d, 0xff, 0x20, 0x04, 0x77, 264 | 0xb2, 0x6d, 0x27, 0xbf, 0x47, 0xa9, 0x9d, 0x1b, 0x96, 0x2c, 0x62, 0x90, 0x23, 0x8b, 0xe0, 0xf8, 265 | 0x1d, 0xcf, 0xaf, 0x1d, 0x3d, 0xee, 0x8a, 0xc8, 0x75, 0x23, 0x66, 0xdd, 0xde, 0xd6, 0x6d, 0xe3, 266 | 0x2a, 0x82, 0x8a, 0x78, 0x8a, 0xdb, 0xe6, 0x20, 0x4c, 0xb7, 0x5c, 0x63, 0xba, 0x30, 0xe3, 0x3f, 267 | 0xb6, 0xee, 0x8c, 0x22, 0xa2, 0x2a, 0xb0, 0x22, 0x0a, 0x99, 0xff, 0x3d, 0x62, 0x51, 0xee, 0x08, 268 | 0xf6, 0x3d, 0x4a, 0xe4, 0xcc, 0xef, 0x22, 0x87, 0x11, 0xe2, 0x83, 0x28, 0xe4, 0xf5, 0x8f, 0x35, 269 | 0x19, 0x63, 0x5b, 0xe1, 0x5a, 0x92, 0x73, 0xdd, 0xa1, 0x50, 0x9d, 0x38, 0x5c, 0xeb, 0xb5, 0x03, 270 | 0x6a, 0x64, 0x90, 0x94, 0xc8, 0x8d, 0xfb, 0x2f, 0x8a, 0x86, 0x22, 0xcc, 0x1d, 0x87, 0xe0, 0x48, 271 | 0x0a, 0x96, 0x77, 0x90, 0x39, 0xc6, 0x23, 0x23, 0x48, 0xfb, 0x11, 0x47, 0x56, 0xca, 0x20, 0xe3, 272 | 0x42, 0x81, 0xf7, 0x77, 0x32, 0xc1, 0xa5, 0x5c, 0x40, 0x21, 0x65, 0x17, 0x40, 0x29, 0x17, 0x17, 273 | 0x6c, 0x56, 0x32, 0x98, 0x38, 0x06, 0xdc, 0x99, 0x4d, 0x33, 0x29, 0xbb, 0x02, 0xdf, 0x4c, 0x26, 274 | 0x93, 0x6c, 0x17, 0x82, 0x86, 0x20, 0xd7, 0x03, 0x79, 0x7d, 0x9a, 0x00, 0xd7, 0x87, 0x00, 0xe7, 275 | 0x0b, 0x66, 0xe3, 0x4c, 0x66, 0x71, 0x67, 0x08, 0x32, 0xf9, 0x08, 0x3e, 0x81, 0x33, 0xcd, 0x17, 276 | 0x72, 0x31, 0xf0, 0xb8, 0x94, 0x52, 0x4b, 0x90, 0x31, 0x8e, 0x68, 0xc1, 0xef, 0x90, 0xc9, 0xe5, 277 | 0xf2, 0x61, 0x09, 0x72, 0x25, 0xad, 0xec, 0xc5, 0x62, 0xc0, 0x0b, 0x12, 0x05, 0xf7, 0x91, 0x75, 278 | 0x0d, 0xee, 0x61, 0x2e, 0x2e, 0x19, 0x09, 0xc2, 0x03, 279 | ]); 280 | 281 | let mut decompressed = &mut String::new(); 282 | let _ = Decompressor::new(brotli_stream).read_to_string(&mut decompressed); 283 | 284 | assert_eq!("znxcvnmz,xvnm.,zxcnv.,xcn.z,vn.zvn.zxcvn.,zxcn.vn.v,znm.,vnzx.,vnzxc.vn.z,vnz.,nv.z,nvmzxc,nvzxcvcnm.,vczxvnzxcnvmxc.zmcnvzm.,nvmc,nzxmc,vn.mnnmzxc,vnxcnmv,znvzxcnmv,.xcnvm,zxcnzxv.zx,qweryweurqioweupropqwutioweupqrioweutiopweuriopweuriopqwurioputiopqwuriowuqerioupqweropuweropqwurweuqriopuropqwuriopuqwriopuqweopruioqweurqweuriouqweopruioupqiytioqtyiowtyqptypryoqweutioioqtweqruowqeytiowquiourowetyoqwupiotweuqiorweuqroipituqwiorqwtioweuriouytuioerytuioweryuitoweytuiweyuityeruirtyuqriqweuropqweiruioqweurioqwuerioqwyuituierwotueryuiotweyrtuiwertyioweryrueioqptyioruyiopqwtjkasdfhlafhlasdhfjklashjkfhasjklfhklasjdfhklasdhfjkalsdhfklasdhjkflahsjdkfhklasfhjkasdfhasfjkasdhfklsdhalghhaf;hdklasfhjklashjklfasdhfasdjklfhsdjklafsd;hkldadfjjklasdhfjasddfjklfhakjklasdjfkl;asdjfasfljasdfhjklasdfhjkaghjkashf;djfklasdjfkljasdklfjklasdjfkljasdfkljaklfj", decompressed); 285 | } 286 | 287 | #[test] 288 | /// Brotli: zeros 289 | /// introduces "Signed" context id computation 290 | fn should_decompress_zeros() { 291 | use std::io::{ Cursor, Read }; 292 | use brotli::Decompressor; 293 | 294 | let brotli_stream = Cursor::new(vec![ 295 | 0x5b, 0xff, 0xff, 0x03, 0x60, 0x02, 0x20, 0x1e, 0x0b, 0x28, 0xf7, 0x7e, 0x00, 296 | ]); 297 | 298 | let mut decompressed = &mut String::new(); 299 | let _ = Decompressor::new(brotli_stream).read_to_string(&mut decompressed); 300 | 301 | let mut expected = &mut String::new(); 302 | let _ = std::fs::File::open("data/zeros").unwrap().read_to_string(&mut expected); 303 | 304 | assert_eq!(expected, decompressed); 305 | } 306 | 307 | #[test] 308 | /// Brotli: quickfox_repeated 309 | /// introduces simple prefix code with NSYM = 4, which uses tree_select flag 310 | fn should_decompress_quickfox_repeated() { 311 | use std::io::{ Read }; 312 | use brotli::Decompressor; 313 | 314 | let brotli_stream = std::fs::File::open("data/quickfox_repeated.compressed").unwrap(); 315 | 316 | let mut decompressed = &mut String::new(); 317 | let _ = Decompressor::new(brotli_stream).read_to_string(&mut decompressed); 318 | 319 | let mut expected = &mut String::new(); 320 | let _ = std::fs::File::open("data/quickfox_repeated").unwrap().read_to_string(&mut expected); 321 | 322 | assert!(expected == decompressed); 323 | } 324 | 325 | #[test] 326 | /// Brotli: asyoulik.txt 327 | /// introduces block switch commands for literals and distances 328 | fn should_decompress_asyoulik_txt() { 329 | use std::io::{ Read }; 330 | use brotli::Decompressor; 331 | 332 | let brotli_stream = std::fs::File::open("data/asyoulik.txt.compressed").unwrap(); 333 | 334 | let mut decompressed = &mut Vec::new(); 335 | let _ = Decompressor::new(brotli_stream).read_to_end(&mut decompressed); 336 | 337 | let mut expected = &mut Vec::new(); 338 | let _ = std::fs::File::open("data/asyoulik.txt").unwrap().read_to_end(&mut expected); 339 | 340 | assert!(expected == decompressed); 341 | } 342 | 343 | #[test] 344 | /// Brotli: alice29.txt 345 | /// introduces NBLTYPESI >= 2 346 | fn should_decompress_alice29_txt() { 347 | use std::io::{ Read }; 348 | use brotli::Decompressor; 349 | 350 | let brotli_stream = std::fs::File::open("data/alice29.txt.compressed").unwrap(); 351 | 352 | let mut decompressed = &mut Vec::new(); 353 | let _ = Decompressor::new(brotli_stream).read_to_end(&mut decompressed); 354 | 355 | let mut expected = &mut Vec::new(); 356 | let _ = std::fs::File::open("data/alice29.txt").unwrap().read_to_end(&mut expected); 357 | 358 | assert!(expected == decompressed); 359 | } 360 | 361 | #[test] 362 | /// Brotli: metablock_reset.txt 363 | /// introduces a new metablock with a different max number of btype_l 364 | fn should_decompress_metablock_reset() { 365 | use std::io::{ Read }; 366 | use brotli::Decompressor; 367 | 368 | let brotli_stream = std::fs::File::open("data/metablock_reset.compressed").unwrap(); 369 | 370 | let mut decompressed = &mut Vec::new(); 371 | let _ = Decompressor::new(brotli_stream).read_to_end(&mut decompressed); 372 | 373 | let mut expected = &mut Vec::new(); 374 | let _ = std::fs::File::open("data/metablock_reset").unwrap().read_to_end(&mut expected); 375 | 376 | assert!(expected == decompressed); 377 | } 378 | 379 | #[test] 380 | #[should_panic(expected = "Code length check sum")] 381 | /// frewsxcv_00: fuzzer-test 382 | /// exposes endless-loop vulnerability, if runlength code lengths are not bounded by alphabet size 383 | /// found and reported by Corey Farwell – https://github.com/ende76/brotli-rs/issues/2 384 | fn should_reject_frewsxcv_00() { 385 | use std::io::{ Cursor, Read }; 386 | use brotli::Decompressor; 387 | 388 | let mut input = vec![]; 389 | let result = Decompressor::new(Cursor::new(vec![0x1b, 0x3f, 0xff, 0xff, 0xdb, 0x4f, 0xe2, 0x99, 0x80, 0x12])).read_to_end(&mut input); 390 | 391 | match result { 392 | Err(e) => panic!("{:?}", e), 393 | _ => {}, 394 | } 395 | } 396 | 397 | #[test] 398 | #[should_panic(expected = "unexpected EOF")] 399 | /// frewsxcv: fuzzer-test 400 | /// exposes uncaught panic in read() implementation 401 | /// found and reported by Corey Farwell – https://github.com/ende76/brotli-rs/issues/3 402 | fn should_reject_frewsxcv_01() { 403 | use std::io::Read; 404 | use brotli::Decompressor; 405 | 406 | let mut input = vec![]; 407 | let result = Decompressor::new(&b"\xb1".to_vec() as &[u8]).read_to_end(&mut input); 408 | 409 | match result { 410 | Err(e) => panic!("{:?}", e), 411 | _ => {}, 412 | } 413 | } 414 | 415 | #[test] 416 | #[should_panic(expected = "invalid symbol")] 417 | /// frewsxcv: fuzzer-test 418 | /// exposes panic in "unreachable" branch in insert-and-copy-length decoding 419 | /// found and reported by Corey Farwell – https://github.com/ende76/brotli-rs/issues/4 420 | fn should_reject_frewsxcv_02() { 421 | use std::io::Read; 422 | use brotli::Decompressor; 423 | 424 | let mut input = vec![]; 425 | let result = Decompressor::new(&b"\x1b\x30\x30\x30\x24\x30\xe2\xd9\x30\x30".to_vec() as &[u8]).read_to_end(&mut input); 426 | 427 | match result { 428 | Err(e) => panic!("{:?}", e), 429 | _ => {}, 430 | } 431 | } 432 | 433 | #[test] 434 | #[should_panic(expected = "invalid complex prefix code")] 435 | /// frewsxcv: fuzzer-test 436 | /// exposes index-out-of-bounds error created by an invalid stream that results in all-zero codelengths for a complex prefix code 437 | /// found and reported by Corey Farwell – https://github.com/ende76/brotli-rs/issues/5 438 | fn should_reject_frewsxcv_03() { 439 | use std::io::Read; 440 | use brotli::Decompressor; 441 | let mut input = vec![]; 442 | let result = Decompressor::new(&b"\x30\x30\x40\x00\x00\x00\x00\x00".to_vec() as &[u8]).read_to_end(&mut input); 443 | 444 | match result { 445 | Err(e) => panic!("{:?}", e), 446 | _ => {}, 447 | } 448 | } 449 | 450 | #[test] 451 | #[should_panic(expected = "Code length check sum")] 452 | /// frewsxcv: fuzzer-test 453 | /// edge case for block type value, which _looks_ like a u8 but is just slightly bigger 454 | /// found and reported by Corey Farwell – https://github.com/ende76/brotli-rs/issues/6 455 | fn should_reject_frewsxcv_04() { 456 | use std::io::Read; 457 | use brotli::Decompressor; 458 | let mut input = vec![]; 459 | let result = Decompressor::new(&b"\x1b\x3f\x00\xff\xff\xb0\xe2\x99\x80\x12".to_vec() as &[u8]).read_to_end(&mut input); 460 | 461 | match result { 462 | Err(e) => panic!("{:?}", e), 463 | _ => {}, 464 | } 465 | } 466 | 467 | #[test] 468 | #[should_panic(expected = "unexpected EOF")] 469 | /// frewsxcv: fuzzer-test 470 | /// exposes wrong bound checks on tree lookup array bounds 471 | /// found and reported by Corey Farwell – https://github.com/ende76/brotli-rs/issues/7 472 | fn should_reject_frewsxcv_05() { 473 | use std::io::Read; 474 | use brotli::Decompressor; 475 | let mut input = vec![]; 476 | let result = Decompressor::new(&b"\x11\x3f\x00\x00\x24\xb0\xe2\x99\x80\x12".to_vec() as &[u8]).read_to_end(&mut input); 477 | 478 | match result { 479 | Err(e) => panic!("{:?}", e), 480 | _ => {}, 481 | } 482 | } 483 | 484 | #[test] 485 | #[should_panic(expected="Run length")] 486 | /// frewsxcv: fuzzer-test 487 | /// exposes shift overflow if too small a type has been chosen for runlength code 488 | /// found and reported by Corey Farwell – https://github.com/ende76/brotli-rs/issues/8 489 | fn should_reject_frewsxcv_06() { 490 | use std::io::Read; 491 | use brotli::Decompressor; 492 | let mut input = vec![]; 493 | let result = Decompressor::new(&b"\x15\x3f\x60\x00\x15\x3f\x60\x00\x27\xb0\xdb\xa8\x80\x25\x27\xb0\xdb\x40\x80\x12".to_vec() as &[u8]).read_to_end(&mut input); 494 | 495 | match result { 496 | Err(e) => panic!("{:?}", e), 497 | _ => {}, 498 | } 499 | } 500 | 501 | #[test] 502 | #[should_panic(expected="Code length check sum")] 503 | /// frewsxcv: fuzzer-test 504 | /// exposes case where runlength checksum does not add up to 32 505 | /// found and reported by Corey Farwell – https://github.com/ende76/brotli-rs/issues/9 506 | fn should_reject_frewsxcv_07() { 507 | use std::io::Read; 508 | use brotli::Decompressor; 509 | let mut input = vec![]; 510 | let result = Decompressor::new(&b"\x12\x1b\x00\x1e\x11\x00\x05\x09\x21\x00\x05\x04\x43\x05\xf5\x21\x1e\x11\x00\x05\xf5\x21\x00\x05\x04\x43".to_vec() as &[u8]).read_to_end(&mut input); 511 | 512 | match result { 513 | Err(e) => panic!("{:?}", e), 514 | _ => {}, 515 | } 516 | } 517 | 518 | #[test] 519 | #[should_panic(expected="unexpected EOF")] 520 | /// frewsxcv: fuzzer-test 521 | /// exposes uncaught byte value 0 in transformation code 522 | /// found and reported by Corey Farwell – https://github.com/ende76/brotli-rs/issues/10 523 | fn should_reject_frewsxcv_08() { 524 | use std::io::Read; 525 | use brotli::Decompressor; 526 | 527 | let mut input = vec![]; 528 | let result = Decompressor::new(&b"\x1b\x3f\x01\xf0\x24\xb0\xc2\xa4\x80\x54\xff\xd7\x24\xb0\x12".to_vec() as &[u8]).read_to_end(&mut input); 529 | 530 | match result { 531 | Err(e) => panic!("{:?}", e), 532 | _ => {}, 533 | } 534 | } 535 | 536 | #[test] 537 | #[should_panic(expected="non-positive distance")] 538 | /// frewsxcv: fuzzer-test 539 | /// exposes uncaught non-positive distances 540 | /// found and reported by Corey Farwell – https://github.com/ende76/brotli-rs/issues/10 541 | fn should_reject_frewsxcv_09() { 542 | use std::io::Read; 543 | use brotli::Decompressor; 544 | 545 | let mut input = vec![]; 546 | let result = Decompressor::new(&b"\x5b\xff\x00\x01\x40\x0a\x00\xab\x16\x7b\xac\x14\x48\x4e\x73\xed\x01\x92\x03".to_vec() as &[u8]).read_to_end(&mut input); 547 | 548 | match result { 549 | Err(e) => panic!("{:?}", e), 550 | _ => {}, 551 | } 552 | } 553 | 554 | #[test] 555 | #[should_panic(expected="invalid symbol")] 556 | /// frewsxcv: fuzzer-test 557 | /// exposes uncaught invalid block type in block switch command 558 | /// found and reported by Corey Farwell – https://github.com/ende76/brotli-rs/issues/10 559 | fn should_reject_frewsxcv_10() { 560 | use std::io::Read; 561 | use brotli::Decompressor; 562 | 563 | let mut input = vec![]; 564 | let result = Decompressor::new(&b"\x51\xac\x00\x48\x2f\x73\x14\x01\x14\x00\x00\x01\x00\x14\x14\xff\x00\x02\x00\x00\x00\x00\x00\x64\x14\x24\x14\x14\x14\x14\x14\x80\x00\x00\x14\xff\xff\x00\x00\x14\x14\x14\x14\x14\x14\x80\x00\x80".to_vec() as &[u8]).read_to_end(&mut input); 565 | 566 | match result { 567 | Err(e) => panic!("{:?}", e), 568 | _ => {}, 569 | } 570 | } 571 | 572 | #[test] 573 | #[should_panic(expected="invalid symbol")] 574 | /// afl: fuzzer-test 575 | /// exposes uncaught invalid block type in block switch command 576 | fn should_reject_afl_00() { 577 | use std::io::Read; 578 | use brotli::Decompressor; 579 | 580 | let mut input = vec![]; 581 | let result = Decompressor::new(&b"\x01\xe6\x00\x76\x42\x10\x01\x1c\x24\x24\x3c\xd7\xd7\xd7\x01\x1c".to_vec() as &[u8]).read_to_end(&mut input); 582 | 583 | match result { 584 | Err(e) => panic!("{:?}", e), 585 | _ => {}, 586 | } 587 | 588 | } 589 | 590 | #[test] 591 | #[should_panic(expected="invalid symbol")] 592 | /// afl: fuzzer-test 593 | /// exposes failure to reject simple prefix code with duplicate symbols 594 | fn should_reject_afl_01() { 595 | use std::io::Read; 596 | use brotli::Decompressor; 597 | 598 | let mut input = vec![]; 599 | let result = Decompressor::new(&b"\x9b\x01\x10\xed\xa3\xb0\x96\xd2\x81\x47\x00\x00\x01\x1e\x07\xa4\xce\xb2\xea\x81\x4b\x02\x8a".to_vec() as &[u8]).read_to_end(&mut input); 600 | 601 | match result { 602 | Err(e) => panic!("{:?}", e), 603 | _ => {}, 604 | } 605 | } 606 | 607 | fn inverse_move_to_front_transform(v: &mut[u8]) { 608 | let mut mtf: Vec = vec![0; 256]; 609 | let v_len = v.len(); 610 | 611 | for i in 0..256 { 612 | mtf[i] = i as u8; 613 | } 614 | 615 | for i in 0..v_len { 616 | let index = v[i] as usize; 617 | let value = mtf[index]; 618 | v[i] = value; 619 | 620 | for j in (1..index+1).rev() { 621 | mtf[j] = mtf[j - 1]; 622 | } 623 | mtf[0] = value; 624 | } 625 | } 626 | 627 | fn move_to_front_transform(v: &mut[u8]) { 628 | let mut alphabet: Vec = vec![0; 256]; 629 | let v_len = v.len(); 630 | 631 | for i in 0..256 { 632 | alphabet[i] = i as u8; 633 | } 634 | 635 | for i in 0..v_len { 636 | let value = v[i]; 637 | let mut index = 0; 638 | loop { 639 | if alphabet[index] == value { 640 | break; 641 | } 642 | index += 1 643 | } 644 | 645 | for j in (1..index+1).rev() { 646 | alphabet[j] = alphabet[j - 1]; 647 | } 648 | alphabet[0] = value; 649 | v[i] = index as u8; 650 | } 651 | } 652 | 653 | #[test] 654 | fn should_not_change() { 655 | let mut v: Vec = vec![0, 0, 0, 1]; 656 | let expected = v.clone(); 657 | 658 | inverse_move_to_front_transform(&mut v); 659 | 660 | assert_eq!(expected, v); 661 | } 662 | 663 | 664 | #[test] 665 | fn should_compose_to_identity() { 666 | let mut v: Vec = vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 2, 2, 2, 2, 1, 1, 3, 3, 3, 3, 3, 3, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5]; 667 | let expected = v.clone(); 668 | 669 | inverse_move_to_front_transform(&mut v); 670 | move_to_front_transform(&mut v); 671 | 672 | assert_eq!(expected, v); 673 | } 674 | 675 | 676 | --------------------------------------------------------------------------------