mirror of
https://github.com/google/brotli.git
synced 2026-02-04 13:44:57 +00:00
Compare commits
432 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8ca2312c61 | ||
|
|
ee771daf20 | ||
|
|
42aee32891 | ||
|
|
392c06bac0 | ||
|
|
1964cdb1b9 | ||
|
|
61605b1cb3 | ||
|
|
4b0f27b6f9 | ||
|
|
1e4425a372 | ||
|
|
f038020bd7 | ||
|
|
4d5a32bf45 | ||
|
|
34e43eb020 | ||
|
|
b3142143f6 | ||
|
|
0e7ea31e6b | ||
|
|
da2e091eb7 | ||
|
|
30576423b8 | ||
|
|
9cf25439ad | ||
|
|
82d3c163cb | ||
|
|
4876ada111 | ||
|
|
f1c80224e8 | ||
|
|
ed93810e27 | ||
|
|
7cc02a1687 | ||
|
|
54481d4ebe | ||
|
|
a896e79d4f | ||
|
|
947f74e908 | ||
|
|
916e4a46a8 | ||
|
|
e4e56a3203 | ||
|
|
2c5f2d1198 | ||
|
|
f3b0ceed2d | ||
|
|
1f6ab76bff | ||
|
|
5c79b32b14 | ||
|
|
d74b0a4a22 | ||
|
|
dbcb332b66 | ||
|
|
c0d785dfe2 | ||
|
|
466613c266 | ||
|
|
1406898440 | ||
|
|
0bef8a6936 | ||
|
|
9686382ff3 | ||
|
|
85d46ce6b5 | ||
|
|
3d8eef20a6 | ||
|
|
41a22f07f2 | ||
|
|
98a89b1563 | ||
|
|
35d4992ac8 | ||
|
|
3287b89bd4 | ||
|
|
4bf850a56a | ||
|
|
0557c81d1e | ||
|
|
f5e1f0641d | ||
|
|
0903aad0d7 | ||
|
|
447385795f | ||
|
|
8fea9e31c8 | ||
|
|
20ed1374ff | ||
|
|
310f2119cf | ||
|
|
30c7d2f97d | ||
|
|
79ea7296d4 | ||
|
|
7880aa1307 | ||
|
|
25190700e2 | ||
|
|
cb29dec4ed | ||
|
|
643b22949d | ||
|
|
e7b0c08b51 | ||
|
|
9a4ba5932b | ||
|
|
3cc6172f58 | ||
|
|
103b25fb1e | ||
|
|
ea7d6c3737 | ||
|
|
7b345944d6 | ||
|
|
6a4c96b110 | ||
|
|
29e040b8cb | ||
|
|
bf6231d685 | ||
|
|
377afe9e4f | ||
|
|
bf2e456437 | ||
|
|
8a7201c602 | ||
|
|
12203bb586 | ||
|
|
172fe58fab | ||
|
|
bf88e69b29 | ||
|
|
a47d747506 | ||
|
|
564ddad5ac | ||
|
|
51a9318883 | ||
|
|
400b1e1e6c | ||
|
|
5f84f3b412 | ||
|
|
39d91926a1 | ||
|
|
15fb8bfedc | ||
|
|
b80c3ad14f | ||
|
|
8ab7027a3a | ||
|
|
61ebc6cbad | ||
|
|
ab9b7b07c7 | ||
|
|
42c5139b80 | ||
|
|
81fb9d557c | ||
|
|
434b582d49 | ||
|
|
5a7338e952 | ||
|
|
f2022b9ea3 | ||
|
|
fe2d7039aa | ||
|
|
2903f45e7d | ||
|
|
63270dbfc0 | ||
|
|
4cb7828376 | ||
|
|
418237cff4 | ||
|
|
c02288edf3 | ||
|
|
b15ca9af07 | ||
|
|
7bd1bd4463 | ||
|
|
7a08d69430 | ||
|
|
964ca075d1 | ||
|
|
ddb803acc3 | ||
|
|
998a28bde4 | ||
|
|
3efb30f96b | ||
|
|
405b434d85 | ||
|
|
3d469dc62f | ||
|
|
00ad1d4a3f | ||
|
|
ee5f3bb959 | ||
|
|
08bdaebbf8 | ||
|
|
bddbb9660c | ||
|
|
271be11429 | ||
|
|
9c91b6a295 | ||
|
|
ff59b386c6 | ||
|
|
00c6df4d2f | ||
|
|
781b865c92 | ||
|
|
e095150b91 | ||
|
|
dcc24d051d | ||
|
|
5189ec1f56 | ||
|
|
6270bb54fa | ||
|
|
0e0ed5f0cc | ||
|
|
9b7beb425d | ||
|
|
cecc0acc0b | ||
|
|
e9668c8cb0 | ||
|
|
93d0ac53aa | ||
|
|
3487b6917d | ||
|
|
adc546b73a | ||
|
|
b3d7283f96 | ||
|
|
fa308ddae5 | ||
|
|
98cde63332 | ||
|
|
9c55070564 | ||
|
|
e45f18ccca | ||
|
|
c710db0510 | ||
|
|
440e03642b | ||
|
|
a1e3ab25ce | ||
|
|
28b1183715 | ||
|
|
ad3c0d5f47 | ||
|
|
67d78bc41d | ||
|
|
d144c5833a | ||
|
|
b01b63a467 | ||
|
|
4034fe3654 | ||
|
|
281b0aa562 | ||
|
|
57610b7174 | ||
|
|
eb3a31e2d3 | ||
|
|
28ce91caf6 | ||
|
|
7ef8b920dc | ||
|
|
95b81fcc29 | ||
|
|
d019271c8b | ||
|
|
ef9e12f004 | ||
|
|
ef8922cee7 | ||
|
|
91d96d3d93 | ||
|
|
cf25e52f9b | ||
|
|
841f672884 | ||
|
|
5c66724029 | ||
|
|
0ea9927a2b | ||
|
|
3a444a6f2d | ||
|
|
39904bdfe8 | ||
|
|
2dfaadcef3 | ||
|
|
b08dc48782 | ||
|
|
90833a88cd | ||
|
|
2b6efcbdcc | ||
|
|
8c6d25f7f8 | ||
|
|
782aadd0ff | ||
|
|
1054ecc262 | ||
|
|
cec846f88e | ||
|
|
cefec3ce9d | ||
|
|
f25050c0d0 | ||
|
|
d405b7f114 | ||
|
|
0e37f9391d | ||
|
|
aa54821999 | ||
|
|
a4d0581dfd | ||
|
|
c766253ccc | ||
|
|
45f4cc75bf | ||
|
|
ca43fd5d99 | ||
|
|
d3471e6ff8 | ||
|
|
cb63a61918 | ||
|
|
28482c4024 | ||
|
|
4c4b1297c6 | ||
|
|
f2372f2f57 | ||
|
|
7347e81db5 | ||
|
|
4303850b01 | ||
|
|
1c380db165 | ||
|
|
664952333f | ||
|
|
9018ef374f | ||
|
|
350100a5bb | ||
|
|
f1bdfaa803 | ||
|
|
b93502da88 | ||
|
|
2a01fd8f31 | ||
|
|
3b83a05447 | ||
|
|
39bcecf455 | ||
|
|
a528bce9f6 | ||
|
|
fe754f3459 | ||
|
|
8a626fd486 | ||
|
|
04388304a6 | ||
|
|
bb809ac908 | ||
|
|
d01a4caaa8 | ||
|
|
1b3a5ccb6e | ||
|
|
443af10a80 | ||
|
|
c1c76e993f | ||
|
|
709c4672d4 | ||
|
|
a76d96e730 | ||
|
|
a813a6a1e4 | ||
|
|
f964a1e8ac | ||
|
|
cdbe7fc739 | ||
|
|
b6f2d49feb | ||
|
|
9351fa7ffb | ||
|
|
9717649c31 | ||
|
|
ccec9628e4 | ||
|
|
c1362a7903 | ||
|
|
200f37984a | ||
|
|
d5e697b3c7 | ||
|
|
adbc354d23 | ||
|
|
02458f3443 | ||
|
|
3396c67fea | ||
|
|
033940f97c | ||
|
|
2ad58d8603 | ||
|
|
26b1fec26b | ||
|
|
1045ab52df | ||
|
|
3bd5b9c0a2 | ||
|
|
082c9626a4 | ||
|
|
2b3334d559 | ||
|
|
fa084310d1 | ||
|
|
0ef82f0c0d | ||
|
|
79a5e80a59 | ||
|
|
7cf649decd | ||
|
|
4c57a6484b | ||
|
|
6b6adb7ae8 | ||
|
|
428d056ddc | ||
|
|
6046f00d41 | ||
|
|
fef82ea104 | ||
|
|
96b255b95c | ||
|
|
0d1a0a4dfd | ||
|
|
a6eacaa3e3 | ||
|
|
421be80782 | ||
|
|
adac2b0e7d | ||
|
|
bf867c126b | ||
|
|
a1851fe3f7 | ||
|
|
6ba678a7ce | ||
|
|
563078a462 | ||
|
|
0dff3e5b0d | ||
|
|
c536542bc7 | ||
|
|
2b6d8654d4 | ||
|
|
8b0e23084c | ||
|
|
0adb12e0a4 | ||
|
|
9b83be233e | ||
|
|
4855abb020 | ||
|
|
75ea7317ef | ||
|
|
cff5803216 | ||
|
|
3ad47114b8 | ||
|
|
53947c15f5 | ||
|
|
662b00ee63 | ||
|
|
ce9c16e882 | ||
|
|
63402aa8af | ||
|
|
91d1b2d623 | ||
|
|
c308b90e7b | ||
|
|
9da1c56448 | ||
|
|
cd158a41f4 | ||
|
|
39527d4a3c | ||
|
|
cf95fbb9c5 | ||
|
|
e8569f79fc | ||
|
|
896ea7a9a9 | ||
|
|
7561c2d847 | ||
|
|
2ce85662c5 | ||
|
|
741610efd3 | ||
|
|
ed738e842d | ||
|
|
e7313b0c4e | ||
|
|
c1bd196833 | ||
|
|
2a5a088b03 | ||
|
|
feb6d8bc80 | ||
|
|
3ebb2d30ab | ||
|
|
0f2157cc5e | ||
|
|
9ff341daaf | ||
|
|
8c7923045a | ||
|
|
a560089843 | ||
|
|
0b89871d86 | ||
|
|
ac2c7bb179 | ||
|
|
117b68b745 | ||
|
|
4125f2587c | ||
|
|
257884a3c5 | ||
|
|
d639a81d35 | ||
|
|
802475e724 | ||
|
|
27a9a80992 | ||
|
|
0300be36ba | ||
|
|
4fc753e707 | ||
|
|
0b8d3c6107 | ||
|
|
dbfebd13dc | ||
|
|
779a49bfd6 | ||
|
|
acc265655d | ||
|
|
4b827e4ce4 | ||
|
|
c3dc7d039c | ||
|
|
c2848d5537 | ||
|
|
de52bc7ce0 | ||
|
|
d1fadddc94 | ||
|
|
2d0947f1ea | ||
|
|
2e6164d7b0 | ||
|
|
70e7b1ae4a | ||
|
|
413b098564 | ||
|
|
dd3eb162b0 | ||
|
|
11b8d7cb8a | ||
|
|
28257b2e67 | ||
|
|
bc32ae12d5 | ||
|
|
6ee96e291d | ||
|
|
e252f1fc15 | ||
|
|
11abde4c96 | ||
|
|
efe140adae | ||
|
|
ffbe112328 | ||
|
|
e1f5788fb0 | ||
|
|
c0a43495ea | ||
|
|
3afc509b84 | ||
|
|
e9c47ed469 | ||
|
|
e5dba91c38 | ||
|
|
745fd08ef2 | ||
|
|
f29c44ed38 | ||
|
|
cb1ced3a25 | ||
|
|
57c36a4f27 | ||
|
|
6db17c87f5 | ||
|
|
6f7f5a163d | ||
|
|
e07b6148fd | ||
|
|
ec107cf015 | ||
|
|
534076fa67 | ||
|
|
50ebce107f | ||
|
|
bfa15d4046 | ||
|
|
1d8452b783 | ||
|
|
ed1995b6bd | ||
|
|
38e9add9d2 | ||
|
|
b2c86d1871 | ||
|
|
04f294b18a | ||
|
|
1e61e972fb | ||
|
|
2ce0feba3c | ||
|
|
36533a866e | ||
|
|
71fe6cac06 | ||
|
|
e3ea91d5c9 | ||
|
|
0ea4603880 | ||
|
|
ce92c95601 | ||
|
|
0ff60731f8 | ||
|
|
81181ecfb6 | ||
|
|
a2cc451df2 | ||
|
|
c8df4b3049 | ||
|
|
509d4419bd | ||
|
|
81dc1c86c3 | ||
|
|
a7b7839fd4 | ||
|
|
3152d995b3 | ||
|
|
c48ebca4a8 | ||
|
|
9b53703237 | ||
|
|
641bec0e30 | ||
|
|
3914999fcc | ||
|
|
f842c1bcf9 | ||
|
|
ae212a792e | ||
|
|
a8f5813b84 | ||
|
|
388d0d53fb | ||
|
|
6d03dfbedd | ||
|
|
9801a2c5d6 | ||
|
|
f09b2555ac | ||
|
|
c9eb85691f | ||
|
|
f4153a09f8 | ||
|
|
e83c7b8e8f | ||
|
|
4ec67035c0 | ||
|
|
8376f72ed6 | ||
|
|
27dd726540 | ||
|
|
62662f87cd | ||
|
|
698e3a7f9d | ||
|
|
a10269cea1 | ||
|
|
0e42caf359 | ||
|
|
68f1b90ad0 | ||
|
|
19d86fb9a6 | ||
|
|
630b5084ee | ||
|
|
ce222e317e | ||
|
|
0a3944c8c9 | ||
|
|
bdcfb123c8 | ||
|
|
f8c6717745 | ||
|
|
bbe5d72ba3 | ||
|
|
2f9277ff2f | ||
|
|
63be8a9940 | ||
|
|
2a51a85aa8 | ||
|
|
5692e422da | ||
|
|
f16845614d | ||
|
|
0e8afdc968 | ||
|
|
4969984a95 | ||
|
|
fcda9db7fd | ||
|
|
685d7baea9 | ||
|
|
60b2a7ada5 | ||
|
|
f6b3aa6d0f | ||
|
|
f2ca32eda6 | ||
|
|
97006561ea | ||
|
|
0cd2e3926e | ||
|
|
90fd2b60cc | ||
|
|
7e8e207ce2 | ||
|
|
09b0992b6a | ||
|
|
0545759b2e | ||
|
|
e61745a6b7 | ||
|
|
db361a0bb9 | ||
|
|
d518e55ba7 | ||
|
|
d052918255 | ||
|
|
665e81dc9b | ||
|
|
223d80cfbe | ||
|
|
0c5603e07b | ||
|
|
e8155d67b0 | ||
|
|
fc823290a7 | ||
|
|
5519352661 | ||
|
|
d2ea198232 | ||
|
|
31754d4ffc | ||
|
|
8f093f5e84 | ||
|
|
f0db711f46 | ||
|
|
7f740f1308 | ||
|
|
f83aa5169e | ||
|
|
924b2b2b9d | ||
|
|
0503d8b766 | ||
|
|
f503cb709c | ||
|
|
36ac0feaf9 | ||
|
|
666c3280cc | ||
|
|
4b5771bee7 | ||
|
|
c435f06675 | ||
|
|
5c3a9a937b | ||
|
|
afc4a74273 | ||
|
|
35ef5c554d | ||
|
|
ca21dac8e5 | ||
|
|
3d1767186d | ||
|
|
f1124c8524 | ||
|
|
c8b37e8fd1 | ||
|
|
40f0fdcdc1 | ||
|
|
78e7bbc3c3 | ||
|
|
4b2b2d4f83 | ||
|
|
9cd01c0437 | ||
|
|
8109882ecf | ||
|
|
5805f99a53 | ||
|
|
d0ffe60b87 | ||
|
|
d6d98957ca | ||
|
|
a1e44975a7 | ||
|
|
a799e34c7f | ||
|
|
7a153ebb09 | ||
|
|
ce8951c3e9 | ||
|
|
f7cbc97c96 | ||
|
|
cc7a74f15f | ||
|
|
c94c6f805c | ||
|
|
9402ac5c08 | ||
|
|
67f059eaf5 |
6
.bazelignore
Normal file
6
.bazelignore
Normal file
@@ -0,0 +1,6 @@
|
||||
# Exclude Bazel roots (workspaces)
|
||||
c/fuzz
|
||||
go
|
||||
java
|
||||
js
|
||||
research
|
||||
54
.gitattributes
vendored
Normal file
54
.gitattributes
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
tests/testdata/* binary
|
||||
|
||||
# Exclude everything
|
||||
**/** export-ignore
|
||||
|
||||
# Add top-level files
|
||||
.bazelignore !export-ignore
|
||||
BUILD.bazel !export-ignore
|
||||
CHANGELOG.md !export-ignore
|
||||
CMakeLists.txt !export-ignore
|
||||
CONTRIBUTING.md !export-ignore
|
||||
LICENSE !export-ignore
|
||||
MANIFEST.in !export-ignore
|
||||
README !export-ignore
|
||||
README.md !export-ignore
|
||||
SECURITY.md !export-ignore
|
||||
setup.cfg !export-ignore
|
||||
setup.py !export-ignore
|
||||
WORKSPACE.bazel !export-ignore
|
||||
|
||||
# Add sources
|
||||
c !export-ignore
|
||||
c/** !export-ignore
|
||||
c/common/dictionary.bin* export-ignore
|
||||
c/fuzz export-ignore
|
||||
|
||||
# Add man pages
|
||||
docs !export-ignore
|
||||
docs/** !export-ignore
|
||||
docs/brotli-comparison-study-2015-09-22.pdf export-ignore
|
||||
|
||||
# Add python bindings + tests
|
||||
python !export-ignore
|
||||
python/** !export-ignore
|
||||
|
||||
# Add go bindings + tests
|
||||
go !export-ignore
|
||||
go/** !export-ignore
|
||||
|
||||
# Add more build files.
|
||||
scripts !export-ignore
|
||||
scripts/download_testdata.sh !export-ignore
|
||||
scripts/libbrotli*.pc.in !export-ignore
|
||||
|
||||
# Add testdata
|
||||
tests !export-ignore
|
||||
tests/*.sh !export-ignore
|
||||
tests/*.cmake !export-ignore
|
||||
tests/testdata !export-ignore
|
||||
tests/testdata/empty !export-ignore
|
||||
tests/testdata/empty.compressed !export-ignore
|
||||
tests/testdata/ukkonooa !export-ignore
|
||||
tests/testdata/ukkonooa.compressed !export-ignore
|
||||
tests/testdata/zerosukkanooa.compressed !export-ignore
|
||||
11
.github/dependabot.yml
vendored
Normal file
11
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
# Copyright 2023 Google Inc. All Rights Reserved.
|
||||
#
|
||||
# Distributed under MIT license.
|
||||
# See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
357
.github/workflows/build_test.yml
vendored
Normal file
357
.github/workflows/build_test.yml
vendored
Normal file
@@ -0,0 +1,357 @@
|
||||
# Copyright 2021 Google Inc. All Rights Reserved.
|
||||
#
|
||||
# Distributed under MIT license.
|
||||
# See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
|
||||
# Workflow for building and running tests under Ubuntu
|
||||
|
||||
name: Build/Test
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
types: [opened, reopened, labeled, unlabeled, synchronize]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
|
||||
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
|
||||
|
||||
jobs:
|
||||
build_test:
|
||||
name: Build and test ${{ matrix.name }}
|
||||
runs-on: ${{ matrix.os || 'ubuntu-latest' }}
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- name: cmake:gcc
|
||||
build_system: cmake
|
||||
c_compiler: gcc
|
||||
cxx_compiler: g++
|
||||
|
||||
- name: cmake:gcc-old
|
||||
build_system: cmake
|
||||
c_compiler: gcc
|
||||
cxx_compiler: g++
|
||||
os: ubuntu-22.04
|
||||
|
||||
- name: cmake:clang
|
||||
build_system: cmake
|
||||
c_compiler: clang
|
||||
cxx_compiler: clang
|
||||
|
||||
- name: cmake:clang-old
|
||||
build_system: cmake
|
||||
c_compiler: clang
|
||||
cxx_compiler: clang
|
||||
os: ubuntu-22.04
|
||||
|
||||
- name: cmake:package
|
||||
build_system: cmake
|
||||
cmake_args: -DBROTLI_BUILD_FOR_PACKAGE=ON
|
||||
|
||||
- name: cmake:static
|
||||
build_system: cmake
|
||||
cmake_args: -DBUILD_SHARED_LIBS=OFF
|
||||
|
||||
- name: cmake:clang:asan
|
||||
build_system: cmake
|
||||
sanitizer: address
|
||||
c_compiler: clang
|
||||
cxx_compiler: clang++
|
||||
|
||||
- name: cmake:clang:tsan
|
||||
build_system: cmake
|
||||
sanitizer: thread
|
||||
c_compiler: clang
|
||||
cxx_compiler: clang++
|
||||
|
||||
- name: cmake:clang:ubsan
|
||||
build_system: cmake
|
||||
sanitizer: undefined
|
||||
c_compiler: clang
|
||||
cxx_compiler: clang++
|
||||
c_flags: -fno-sanitize-recover=undefined,integer
|
||||
|
||||
- name: cmake:qemu-arm-neon-gcc
|
||||
build_system: cmake
|
||||
c_compiler: arm-linux-gnueabihf-gcc
|
||||
cxx_compiler: arm-linux-gnueabihf-g++
|
||||
c_flags: -march=armv7-a -mfloat-abi=hard -mfpu=neon
|
||||
extra_apt_pkgs: gcc-arm-linux-gnueabihf libc6-dev-armhf-cross qemu-user
|
||||
|
||||
- name: cmake-osx:clang
|
||||
build_system: cmake
|
||||
c_compiler: clang
|
||||
cxx_compiler: clang++
|
||||
os: macos-latest
|
||||
|
||||
- name: cmake-osx:gcc
|
||||
build_system: cmake
|
||||
c_compiler: gcc
|
||||
cxx_compiler: g++
|
||||
os: macos-latest
|
||||
|
||||
- name: cmake-win64:msvc-rel
|
||||
build_system: cmake
|
||||
cmake_generator: Visual Studio 17 2022
|
||||
cmake_config: Release
|
||||
os: windows-latest
|
||||
|
||||
- name: cmake-win64:msvc-dbg
|
||||
build_system: cmake
|
||||
cmake_generator: Visual Studio 17 2022
|
||||
cmake_config: Debug
|
||||
os: windows-latest
|
||||
|
||||
- name: fuzz:clang
|
||||
build_system: fuzz
|
||||
c_compiler: clang
|
||||
cxx_compiler: clang++
|
||||
|
||||
- name: python3.10:clang
|
||||
build_system: python
|
||||
python_version: "3.10"
|
||||
c_compiler: clang
|
||||
cxx_compiler: clang++
|
||||
|
||||
- name: python3.10-win
|
||||
build_system: python
|
||||
python_version: "3.10"
|
||||
# TODO: investigate why win-builds can't run tests
|
||||
py_setuptools_cmd: build_ext
|
||||
os: windows-2022
|
||||
|
||||
- name: maven
|
||||
build_system: maven
|
||||
|
||||
- name: bazel:root
|
||||
build_system: bazel
|
||||
bazel_project: .
|
||||
|
||||
- name: bazel:go
|
||||
build_system: bazel
|
||||
bazel_project: go
|
||||
|
||||
- name: bazel:java
|
||||
build_system: bazel
|
||||
bazel_project: java
|
||||
|
||||
- name: bazel:research
|
||||
build_system: bazel
|
||||
bazel_project: research
|
||||
|
||||
- name: bazel-osx:root
|
||||
build_system: bazel
|
||||
bazel_project: .
|
||||
os: macos-latest
|
||||
|
||||
- name: bazel-osx:go
|
||||
build_system: bazel
|
||||
bazel_project: go
|
||||
os: macos-latest
|
||||
|
||||
- name: bazel-osx:java
|
||||
build_system: bazel
|
||||
bazel_project: java
|
||||
os: macos-latest
|
||||
|
||||
- name: bazel-osx:research
|
||||
build_system: bazel
|
||||
bazel_project: research
|
||||
os: macos-latest
|
||||
|
||||
- name: bazel-win:root
|
||||
build_system: bazel
|
||||
bazel_project: .
|
||||
os: windows-latest
|
||||
|
||||
# TODO(eustas): restore when go is fixed
|
||||
#- name: bazel-win:go
|
||||
# build_system: bazel
|
||||
# bazel_project: go
|
||||
# os: windows-latest
|
||||
|
||||
# TODO(eustas): restore when kotlin is fixed
|
||||
#- name: bazel-win:java
|
||||
# build_system: bazel
|
||||
# bazel_project: java
|
||||
# os: windows-latest
|
||||
|
||||
- name: bazel-win:research
|
||||
build_system: bazel
|
||||
bazel_project: research
|
||||
os: windows-latest
|
||||
|
||||
env:
|
||||
CC: ${{ matrix.c_compiler || 'gcc' }}
|
||||
CXX: ${{ matrix.cxx_compiler || 'gcc' }}
|
||||
|
||||
steps:
|
||||
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Install extra deps @ Ubuntu
|
||||
if: ${{ runner.os == 'Linux' }}
|
||||
# Already installed: bazel, clang{13-15}, cmake, gcc{9.5-13.1}, java{8,11,17,21}, maven, python{3.10}
|
||||
run: |
|
||||
EXTRA_PACKAGES="${{ matrix.extra_apt_pkgs || '' }}"
|
||||
sudo apt update
|
||||
sudo apt install -y ${EXTRA_PACKAGES}
|
||||
|
||||
- name: Checkout the source
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
submodules: false
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Configure / Build / Test with CMake
|
||||
if: ${{ matrix.build_system == 'cmake' }}
|
||||
run: |
|
||||
export ASAN_OPTIONS=detect_leaks=0
|
||||
declare -a CMAKE_OPTIONS=(${{ matrix.cmake_args || '' }})
|
||||
CMAKE_OPTIONS+=("-DCMAKE_VERBOSE_MAKEFILE=ON")
|
||||
[ ! -z '${{ matrix.c_compiler || '' }}' ] && CMAKE_OPTIONS+=(-DCMAKE_C_COMPILER='${{ matrix.c_compiler }}')
|
||||
[ ! -z '${{ matrix.cxx_compiler || '' }}' ] && CMAKE_OPTIONS+=(-DCMAKE_CXX_COMPILER='${{ matrix.cxx_compiler }}')
|
||||
[ ! -z '${{ matrix.sanitizer || '' }}' ] && CMAKE_OPTIONS+=(-DENABLE_SANITIZER='${{ matrix.sanitizer }}')
|
||||
[ ! -z '${{ matrix.cmake_generator || '' }}' ] && export CMAKE_GENERATOR='${{ matrix.cmake_generator }}'
|
||||
declare -a CMAKE_BUILD_OPTIONS=()
|
||||
[ ! -z '${{ matrix.cmake_config || '' }}' ] && CMAKE_BUILD_OPTIONS+=(--config '${{ matrix.cmake_config }}')
|
||||
declare -a CMAKE_TEST_OPTIONS=()
|
||||
[ ! -z '${{ matrix.cmake_config || '' }}' ] && CMAKE_TEST_OPTIONS+=(-C '${{ matrix.cmake_config }}')
|
||||
|
||||
cmake -B out . ${CMAKE_OPTIONS[*]} -DCMAKE_C_FLAGS='${{ matrix.c_flags || '' }}'
|
||||
cmake --build out ${CMAKE_BUILD_OPTIONS[*]}
|
||||
cd out; ctest ${CMAKE_TEST_OPTIONS[*]}; cd ..
|
||||
|
||||
- name: Quick Fuzz
|
||||
if: ${{ matrix.build_system == 'fuzz' }}
|
||||
run: |
|
||||
mkdir ${RUNNER_TEMP}/decode_corpora
|
||||
unzip java/org/brotli/integration/fuzz_data.zip -d ${RUNNER_TEMP}/decode_corpora
|
||||
cd ${GITHUB_WORKSPACE}/c/fuzz
|
||||
bazelisk build --config=asan-libfuzzer :decode_fuzzer
|
||||
for f in `ls ${RUNNER_TEMP}/decode_corpora`
|
||||
do
|
||||
echo "Testing $f"
|
||||
./bazel-bin/decode_fuzzer_bin ${RUNNER_TEMP}/decode_corpora/$f
|
||||
done
|
||||
|
||||
- name: Build with Bazel
|
||||
if: ${{ matrix.build_system == 'bazel' }}
|
||||
run: |
|
||||
cd ${GITHUB_WORKSPACE}/${{ matrix.bazel_project }}
|
||||
bazelisk build -c opt ...:all --java_runtime_version=remotejdk_21
|
||||
|
||||
- name: Fix symlinks for Bazel (Windows)
|
||||
if: ${{ matrix.build_system == 'bazel' && runner.os == 'Windows' && matrix.bazel_project == 'java' }}
|
||||
shell: python
|
||||
run: |
|
||||
import fnmatch
|
||||
import os
|
||||
import os.path
|
||||
from shutil import copyfile
|
||||
os.chdir('${{ matrix.bazel_project }}')
|
||||
print('Searching for manifests in ' + os.getcwd())
|
||||
matches = []
|
||||
for root, dirnames, filenames in os.walk('bazel-bin\\org\\brotli'):
|
||||
for filename in fnmatch.filter(filenames, '*.runfiles_manifest'):
|
||||
matches.append(os.path.join(root, filename))
|
||||
for match in matches:
|
||||
print('Scanning manifest ' + match)
|
||||
runfiles = match[:-len('_manifest')]
|
||||
with open(match) as manifest:
|
||||
for entry in manifest:
|
||||
entry = entry.strip()
|
||||
if not entry.startswith("_main"):
|
||||
continue
|
||||
if entry.startswith("_main/external"):
|
||||
continue
|
||||
(alias, space, link) = entry.partition(' ')
|
||||
if alias.endswith('.jar') or alias.endswith('.exe'):
|
||||
continue
|
||||
link = link.replace('/', '\\')
|
||||
alias = alias.replace('/', '\\')
|
||||
dst = os.path.join(runfiles, alias)
|
||||
if not os.path.exists(dst):
|
||||
print(link + ' -> ' + dst)
|
||||
parent = os.path.dirname(dst)
|
||||
if not os.path.exists(parent):
|
||||
os.makedirs(parent)
|
||||
copyfile(link, dst)
|
||||
print('Finished resolving symlinks')
|
||||
|
||||
- name: Test with Bazel
|
||||
if: ${{ matrix.build_system == 'bazel' }}
|
||||
run: |
|
||||
cd ${GITHUB_WORKSPACE}/${{ matrix.bazel_project }}
|
||||
bazelisk query "tests(...)" --output=label > ${RUNNER_TEMP}/tests.lst
|
||||
[ -s ${RUNNER_TEMP}/tests.lst ] && bazelisk test -c opt ...:all --java_runtime_version=remotejdk_21
|
||||
bazelisk clean
|
||||
|
||||
- name: Build / Test with Maven
|
||||
if: ${{ matrix.build_system == 'maven' }}
|
||||
run: |
|
||||
export MAVEN_OPTS=-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn
|
||||
cd java/org/brotli
|
||||
mvn -B install
|
||||
# TODO(eustas): nuke maven build?
|
||||
# cd integration
|
||||
# mvn -B verify
|
||||
|
||||
- uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
|
||||
if: ${{ matrix.build_system == 'python' }}
|
||||
with:
|
||||
python-version: ${{ matrix.python_version }}
|
||||
|
||||
# TODO(eustas): use modern setuptools (split out testing)
|
||||
- name: Build / Test with Python
|
||||
if: ${{ matrix.build_system == 'python' }}
|
||||
run: |
|
||||
python -VV
|
||||
python -c "import sys; sys.exit('Invalid python version') if '.'.join(map(str,sys.version_info[0:2])) != '${{ matrix.python_version }}' else True"
|
||||
pip install setuptools==51.3.3
|
||||
python setup.py ${{ matrix.py_setuptools_cmd || 'test'}}
|
||||
|
||||
build_test_py27:
|
||||
name: Build and test with Python 2.7
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ubuntu:22.04
|
||||
steps:
|
||||
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Install deps
|
||||
run: |
|
||||
apt update
|
||||
apt install -y curl gcc python2.7 python2.7-dev
|
||||
curl https://bootstrap.pypa.io/pip/2.7/get-pip.py --output get-pip.py
|
||||
python2.7 get-pip.py
|
||||
python2.7 -m pip install distutils-pytest==0.1
|
||||
|
||||
- name: Checkout the source
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
submodules: false
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Build / Test
|
||||
run: |
|
||||
python2.7 -VV
|
||||
python2.7 -c "import sys; sys.exit('Invalid python version') if '.'.join(map(str,sys.version_info[0:2])) != '2.7' else True"
|
||||
python2.7 setup.py test
|
||||
70
.github/workflows/build_test_wasm.yml
vendored
Normal file
70
.github/workflows/build_test_wasm.yml
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
# Copyright 2025 Google Inc. All Rights Reserved.
|
||||
#
|
||||
# Distributed under MIT license.
|
||||
# See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
|
||||
# Workflow for building and running tests with WASM
|
||||
|
||||
name: Build/Test WASM
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
types: [opened, reopened, labeled, unlabeled, synchronize]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
|
||||
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
|
||||
|
||||
jobs:
|
||||
build_test_wasm:
|
||||
name: Build and test with WASM
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
CCACHE_DIR: ${{ github.workspace }}/.ccache
|
||||
BUILD_TARGET: wasm32
|
||||
EM_VERSION: 3.1.51
|
||||
# As of 28.08.2025 ubuntu-latest is 24.04; it is shipped with node 22.18
|
||||
NODE_VERSION: 22
|
||||
|
||||
steps:
|
||||
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
submodules: true
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Install node
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
|
||||
with:
|
||||
node-version: ${{env.NODE_VERSION}}
|
||||
|
||||
- name: Get non-EMSDK node path
|
||||
run: which node >> $HOME/.base_node_path
|
||||
|
||||
- name: Install emsdk
|
||||
uses: mymindstorm/setup-emsdk@6ab9eb1bda2574c4ddb79809fc9247783eaf9021 # v14
|
||||
with:
|
||||
version: ${{env.EM_VERSION}}
|
||||
no-cache: true
|
||||
|
||||
- name: Set EMSDK node version
|
||||
run: |
|
||||
echo "NODE_JS='$(cat $HOME/.base_node_path)'" >> $EMSDK/.emscripten
|
||||
emsdk construct_env
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
LDFLAGS=" -s ALLOW_MEMORY_GROWTH=1 -s NODERAWFS=1 " emcmake cmake -B out .
|
||||
cmake --build out
|
||||
cd out; ctest --output-on-failure; cd ..
|
||||
81
.github/workflows/codeql.yml
vendored
Normal file
81
.github/workflows/codeql.yml
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ "master" ]
|
||||
schedule:
|
||||
- cron: '18 15 * * 0'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
|
||||
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: 'ubuntu-latest'
|
||||
timeout-minutes: 360
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'cpp', 'java', 'javascript', 'python' ]
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby', 'swift' ]
|
||||
|
||||
steps:
|
||||
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@f443b600d91635bebf5b0d9ebc620189c0d6fba5 # v3.29.5
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# CodeQL is currently crashing on files with large lists:
|
||||
# https://github.com/github/codeql/issues/13656
|
||||
config: |
|
||||
paths-ignore:
|
||||
- research
|
||||
- js/test_data.*
|
||||
|
||||
- if: matrix.language == 'cpp'
|
||||
name: Build CPP
|
||||
uses: github/codeql-action/autobuild@f443b600d91635bebf5b0d9ebc620189c0d6fba5 # v3.29.5
|
||||
|
||||
- if: matrix.language == 'cpp' || matrix.language == 'java'
|
||||
name: Build Java
|
||||
run: |
|
||||
cd ${GITHUB_WORKSPACE}/java
|
||||
bazelisk build --spawn_strategy=local --nouse_action_cache -c opt ...:all
|
||||
|
||||
- if: matrix.language == 'javascript'
|
||||
name: Build JS
|
||||
uses: github/codeql-action/autobuild@f443b600d91635bebf5b0d9ebc620189c0d6fba5 # v3.29.5
|
||||
|
||||
- if: matrix.language == 'cpp' || matrix.language == 'python'
|
||||
name: Build Python
|
||||
run: |
|
||||
python setup.py build_ext
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@f443b600d91635bebf5b0d9ebc620189c0d6fba5 # v3.29.5
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
||||
ref: "${{ github.ref != 'master' && github.ref || '/refs/heads/master' }}"
|
||||
sha: "${{ github.sha }}"
|
||||
47
.github/workflows/fuzz.yml
vendored
Normal file
47
.github/workflows/fuzz.yml
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
# Copyright 2020 Google Inc. All Rights Reserved.
|
||||
#
|
||||
# Distributed under MIT license.
|
||||
# See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
|
||||
# Workflow for building / running oss-fuzz.
|
||||
|
||||
name: CIFuzz
|
||||
|
||||
on: [pull_request]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
|
||||
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
|
||||
|
||||
jobs:
|
||||
Fuzzing:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Build Fuzzers
|
||||
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@3e6a7fd7bcd631647ab9beed1fe0897498e6af39 # 22.09.2025
|
||||
with:
|
||||
oss-fuzz-project-name: 'brotli'
|
||||
dry-run: false
|
||||
|
||||
- name: Run Fuzzers
|
||||
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@3e6a7fd7bcd631647ab9beed1fe0897498e6af39 # 22.09.2025
|
||||
with:
|
||||
oss-fuzz-project-name: 'brotli'
|
||||
fuzz-seconds: 600
|
||||
dry-run: false
|
||||
|
||||
- name: Upload Crash
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
if: failure()
|
||||
with:
|
||||
name: artifacts
|
||||
path: ./out/artifacts
|
||||
50
.github/workflows/lint.yml
vendored
Normal file
50
.github/workflows/lint.yml
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
# Copyright 2025 Google Inc. All Rights Reserved.
|
||||
#
|
||||
# Distributed under MIT license.
|
||||
# See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
|
||||
# Workflow for checking typos and buildifier, formatting, etc.
|
||||
|
||||
name: "Lint"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
pull_request:
|
||||
branches: [ "master" ]
|
||||
schedule:
|
||||
- cron: '18 15 * * 0'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
|
||||
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
|
||||
|
||||
jobs:
|
||||
check:
|
||||
name: Lint
|
||||
runs-on: 'ubuntu-latest'
|
||||
|
||||
steps:
|
||||
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
|
||||
- name: Install tools
|
||||
run: |
|
||||
eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
|
||||
brew install buildifier typos-cli
|
||||
|
||||
- name: Check typos
|
||||
run: |
|
||||
eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
|
||||
./scripts/check_typos.sh
|
||||
|
||||
# TODO(eustas): run buildifier
|
||||
245
.github/workflows/release.yaml
vendored
Normal file
245
.github/workflows/release.yaml
vendored
Normal file
@@ -0,0 +1,245 @@
|
||||
# Copyright 2023 Google Inc. All Rights Reserved.
|
||||
#
|
||||
# Distributed under MIT license.
|
||||
# See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
|
||||
# Workflow for building the release binaries.
|
||||
|
||||
name: Release build / deploy
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- v*.*.*
|
||||
release:
|
||||
types: [ published ]
|
||||
pull_request:
|
||||
types: [opened, reopened, labeled, unlabeled, synchronize]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
|
||||
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
|
||||
|
||||
jobs:
|
||||
windows_build:
|
||||
name: Windows Build (vcpkg / ${{ matrix.triplet }})
|
||||
runs-on: ${{ matrix.runs_on }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- triplet: x86-windows-dynamic
|
||||
arch: '-A Win32'
|
||||
build_shared_libs: 'ON'
|
||||
runs_on: windows-latest
|
||||
- triplet: x64-windows-dynamic
|
||||
arch: '-A x64'
|
||||
build_shared_libs: 'ON'
|
||||
runs_on: windows-latest
|
||||
- triplet: arm64-windows-dynamic
|
||||
arch: '-A ARM64'
|
||||
build_shared_libs: 'ON'
|
||||
runs_on: windows-11-arm
|
||||
- triplet: x86-windows-static
|
||||
arch: '-A Win32'
|
||||
build_shared_libs: 'OFF'
|
||||
runs_on: windows-latest
|
||||
- triplet: x64-windows-static
|
||||
arch: '-A x64'
|
||||
build_shared_libs: 'OFF'
|
||||
runs_on: windows-latest
|
||||
- triplet: arm64-windows-static
|
||||
arch: '-A ARM64'
|
||||
build_shared_libs: 'OFF'
|
||||
runs_on: windows-11-arm
|
||||
|
||||
env:
|
||||
VCPKG_VERSION: '2022.11.14'
|
||||
VCPKG_ROOT: vcpkg
|
||||
VCPKG_DISABLE_METRICS: 1
|
||||
|
||||
steps:
|
||||
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout the source
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
submodules: false
|
||||
fetch-depth: 1
|
||||
|
||||
- uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
|
||||
id: cache-vcpkg
|
||||
with:
|
||||
path: vcpkg
|
||||
key: release-${{ runner.os }}-vcpkg-${{ env.VCPKG_VERSION }}-${{ matrix.triplet }}
|
||||
|
||||
- name: Download vcpkg
|
||||
if: steps.cache-vcpkg.outputs.cache-hit != 'true'
|
||||
shell: 'powershell'
|
||||
run: |
|
||||
Invoke-WebRequest -Uri "https://github.com/microsoft/vcpkg/archive/refs/tags/${{ env.VCPKG_VERSION }}.zip" -OutFile "vcpkg.zip"
|
||||
|
||||
- name: Bootstrap vcpkg
|
||||
if: steps.cache-vcpkg.outputs.cache-hit != 'true'
|
||||
shell: 'bash'
|
||||
run: |
|
||||
set -x
|
||||
unzip -q vcpkg.zip
|
||||
rm -rf ${VCPKG_ROOT}
|
||||
mv vcpkg-${VCPKG_VERSION} ${VCPKG_ROOT}
|
||||
${VCPKG_ROOT}/bootstrap-vcpkg.sh
|
||||
|
||||
- name: Configure
|
||||
shell: 'bash'
|
||||
run: |
|
||||
set -x
|
||||
mkdir out
|
||||
cmake -Bout -H. ${{ matrix.arch }} \
|
||||
-DBUILD_TESTING=OFF \
|
||||
-DBUILD_SHARED_LIBS=${{ matrix.build_shared_libs }} \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_INSTALL_PREFIX=`pwd`/prefix \
|
||||
-DCMAKE_TOOLCHAIN_FILE=${VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake \
|
||||
-DVCPKG_TARGET_TRIPLET=${{ matrix.triplet }} \
|
||||
#
|
||||
|
||||
- name: Build
|
||||
shell: 'bash'
|
||||
run: |
|
||||
set -x
|
||||
cmake --build out --config Release
|
||||
|
||||
- name: Install
|
||||
shell: 'bash'
|
||||
run: |
|
||||
set -x
|
||||
cmake --build out --config Release --target install
|
||||
cp LICENSE prefix/bin/LICENSE.brotli
|
||||
|
||||
- name: Package release zip
|
||||
shell: 'powershell'
|
||||
run: |
|
||||
Compress-Archive -Path prefix\bin\* `
|
||||
-DestinationPath brotli-${{matrix.triplet}}.zip
|
||||
|
||||
- name: Upload package
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
with:
|
||||
name: brotli-${{matrix.triplet}}
|
||||
path: brotli-${{matrix.triplet}}.zip
|
||||
compression-level: 0
|
||||
|
||||
testdata_upload:
|
||||
name: Upload testdata
|
||||
runs-on: 'ubuntu-latest'
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
steps:
|
||||
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout the source
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
submodules: false
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Compress testdata
|
||||
run: |
|
||||
tar cvfJ testdata.txz tests/testdata
|
||||
|
||||
- name: Upload archive
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
with:
|
||||
name: testdata
|
||||
path: testdata.txz
|
||||
compression-level: 0
|
||||
|
||||
publish_release_assets:
|
||||
name: Publish release assets
|
||||
needs: [windows_build, testdata_upload]
|
||||
if: github.event_name == 'release'
|
||||
runs-on: [ubuntu-latest]
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
steps:
|
||||
- name: Checkout the source
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
submodules: false
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Download all artifacts
|
||||
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
|
||||
with:
|
||||
path: release_assets
|
||||
merge-multiple: true
|
||||
|
||||
- name: Publish assets
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
gh release upload ${{ github.event.release.tag_name }} ./release_assets/*
|
||||
|
||||
archive_build:
|
||||
needs: publish_release_assets
|
||||
name: Build and test from archive
|
||||
runs-on: 'ubuntu-latest'
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
steps:
|
||||
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout the source
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
submodules: false
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Archive
|
||||
run: |
|
||||
git archive HEAD -o archive.tgz
|
||||
|
||||
- name: Pick tag
|
||||
run: |
|
||||
echo "BROTLI_TAG=$(git describe --tags --abbrev=0)" >> $GITHUB_ENV
|
||||
|
||||
- name: Extract
|
||||
run: |
|
||||
mkdir archive
|
||||
cd archive
|
||||
tar xvzf ../archive.tgz
|
||||
|
||||
- name: Download testdata
|
||||
run: |
|
||||
cd archive
|
||||
scripts/download_testdata.sh
|
||||
|
||||
- name: Configure and Build
|
||||
run: |
|
||||
cd archive
|
||||
cmake -B out .
|
||||
cmake --build out
|
||||
|
||||
- name: Test
|
||||
run: |
|
||||
cd archive
|
||||
cd out
|
||||
ctest
|
||||
82
.github/workflows/scorecard.yml
vendored
Normal file
82
.github/workflows/scorecard.yml
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
# This workflow uses actions that are not certified by GitHub. They are provided
|
||||
# by a third-party and are governed by separate terms of service, privacy
|
||||
# policy, and support documentation.
|
||||
|
||||
name: Scorecard supply-chain security
|
||||
|
||||
on:
|
||||
# For Branch-Protection check. Only the default branch is supported. See
|
||||
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection
|
||||
branch_protection_rule:
|
||||
# To guarantee Maintained check is occasionally updated. See
|
||||
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained
|
||||
schedule:
|
||||
- cron: '23 21 * * 1'
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
|
||||
# Declare default permissions as read only.
|
||||
permissions: read-all
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
|
||||
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
|
||||
|
||||
jobs:
|
||||
analysis:
|
||||
name: Scorecard analysis
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
# Needed to upload the results to code-scanning dashboard.
|
||||
security-events: write
|
||||
# Needed to publish results and get a badge (see publish_results below).
|
||||
id-token: write
|
||||
# Uncomment the permissions below if installing in a private repository.
|
||||
# contents: read
|
||||
# actions: read
|
||||
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: "Checkout code"
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: "Run analysis"
|
||||
uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3
|
||||
with:
|
||||
results_file: results.sarif
|
||||
results_format: sarif
|
||||
# (Optional) "write" PAT token. Uncomment the `repo_token` line below if:
|
||||
# - you want to enable the Branch-Protection check on a *public* repository, or
|
||||
# - you are installing Scorecard on a *private* repository
|
||||
# To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat.
|
||||
# repo_token: ${{ secrets.SCORECARD_TOKEN }}
|
||||
|
||||
# Public repositories:
|
||||
# - Publish results to OpenSSF REST API for easy access by consumers
|
||||
# - Allows the repository to include the Scorecard badge.
|
||||
# - See https://github.com/ossf/scorecard-action#publishing-results.
|
||||
# For private repositories:
|
||||
# - `publish_results` will always be set to `false`, regardless
|
||||
# of the value entered here.
|
||||
publish_results: true
|
||||
|
||||
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
|
||||
# format to the repository Actions tab.
|
||||
- name: "Upload artifact"
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
with:
|
||||
name: SARIF file
|
||||
path: results.sarif
|
||||
retention-days: 5
|
||||
|
||||
# Upload the results to GitHub's code scanning dashboard.
|
||||
- name: "Upload to code-scanning"
|
||||
uses: github/codeql-action/upload-sarif@17783bfb99b07f70fae080b654aed0c514057477 # v2.23.3
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,5 +1,7 @@
|
||||
# C
|
||||
*.d
|
||||
*.o
|
||||
*.obj
|
||||
bin/
|
||||
buildfiles/
|
||||
**/obj/
|
||||
|
||||
6
.gitmodules
vendored
6
.gitmodules
vendored
@@ -1,6 +0,0 @@
|
||||
[submodule "research/esaxx"]
|
||||
path = research/esaxx
|
||||
url = https://github.com/hillbig/esaxx
|
||||
[submodule "research/libdivsufsort"]
|
||||
path = research/libdivsufsort
|
||||
url = https://github.com/y-256/libdivsufsort.git
|
||||
212
.travis.yml
212
.travis.yml
@@ -1,212 +0,0 @@
|
||||
language: c
|
||||
sudo: false
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
matrix:
|
||||
include:
|
||||
###
|
||||
## Linux builds using various versions of GCC.
|
||||
###
|
||||
- os: linux
|
||||
env: BUILD_SYSTEM=cmake C_COMPILER=gcc-7 CXX_COMPILER=g++-7
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- gcc-7
|
||||
- g++-7
|
||||
- os: linux
|
||||
env: BUILD_SYSTEM=cmake C_COMPILER=gcc-4.4 CXX_COMPILER=g++-4.4
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- gcc-4.4
|
||||
- g++-4.4
|
||||
|
||||
###
|
||||
## Test that Autotools build works.
|
||||
###
|
||||
- os: linux
|
||||
env: BUILD_SYSTEM=autotools C_COMPILER=gcc-5 CXX_COMPILER=g++-5
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- gcc-5
|
||||
- g++-5
|
||||
|
||||
###
|
||||
## Test that fuzzer is compiling / working.
|
||||
###
|
||||
- os: linux
|
||||
env: BUILD_SYSTEM=fuzz C_COMPILER=clang-5.0 CXX_COMPILER=clang++-5.0 ASAN_OPTIONS=detect_leaks=0
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-trusty-5.0
|
||||
packages:
|
||||
- clang-5.0
|
||||
|
||||
###
|
||||
## clang on Linux
|
||||
###
|
||||
- os: linux
|
||||
env: BUILD_SYSTEM=cmake C_COMPILER=clang-5.0 CXX_COMPILER=clang++-5.0
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- llvm-toolchain-trusty-5.0
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- clang-5.0
|
||||
- os: linux
|
||||
env: BUILD_SYSTEM=cmake C_COMPILER=clang-3.5 CXX_COMPILER=clang++-3.5
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- llvm-toolchain-trusty-3.5
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- clang-3.5
|
||||
|
||||
###
|
||||
## PGI Community Edition on Linux
|
||||
###
|
||||
- os: linux
|
||||
env: BUILD_SYSTEM=cmake C_COMPILER=pgcc CXX_COMPILER=pgc++
|
||||
|
||||
###
|
||||
## Python 2.7 and 3.6 builds on Linux
|
||||
###
|
||||
- os: linux
|
||||
language: python
|
||||
python: 2.7
|
||||
env: BUILD_SYSTEM=python C_COMPILER=gcc-5 CXX_COMPILER=g++-5
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- gcc-5
|
||||
- g++-5
|
||||
- os: linux
|
||||
language: python
|
||||
python: 3.6
|
||||
env: BUILD_SYSTEM=python C_COMPILER=gcc-5 CXX_COMPILER=g++-5
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- gcc-5
|
||||
- g++-5
|
||||
|
||||
###
|
||||
## CMake on OS X
|
||||
##
|
||||
## These all work, but it seems unnecessary to actually build them
|
||||
## all since we already test all these versions of GCC on Linux.
|
||||
## We'll just test 4.4 and the most recent version.
|
||||
###
|
||||
- os: osx
|
||||
env: BUILD_SYSTEM=cmake C_COMPILER=gcc CXX_COMPILER=g++
|
||||
- os: osx
|
||||
env: BUILD_SYSTEM=cmake C_COMPILER=gcc-4.9 CXX_COMPILER=g++-4.9
|
||||
- os: osx
|
||||
env: BUILD_SYSTEM=cmake
|
||||
|
||||
###
|
||||
## Python 2.7 OS X build (using the system /usr/bin/python)
|
||||
###
|
||||
- os: osx
|
||||
env: BUILD_SYSTEM=python C_COMPILER=gcc CXX_COMPILER=g++
|
||||
|
||||
###
|
||||
## Sanitizers
|
||||
###
|
||||
- os: linux
|
||||
env: BUILD_SYSTEM=cmake C_COMPILER=clang-5.0 CXX_COMPILER=clang++-5.0 SANITIZER=address ASAN_OPTIONS=detect_leaks=0
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-trusty-5.0
|
||||
packages:
|
||||
- clang-5.0
|
||||
- os: linux
|
||||
env: BUILD_SYSTEM=cmake C_COMPILER=clang-5.0 CXX_COMPILER=clang++-5.0 SANITIZER=thread
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-trusty-5.0
|
||||
packages:
|
||||
- clang-5.0
|
||||
- os: linux
|
||||
env: BUILD_SYSTEM=cmake C_COMPILER=clang-5.0 CXX_COMPILER=clang++-5.0 SANITIZER=undefined CFLAGS="-fno-sanitize-recover=undefined,integer"
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-trusty-5.0
|
||||
packages:
|
||||
- clang-5.0
|
||||
|
||||
- os: linux
|
||||
env: BUILD_SYSTEM=maven
|
||||
language: java
|
||||
|
||||
- os: linux
|
||||
sudo: required
|
||||
language: java
|
||||
jdk: oraclejdk9
|
||||
env: BUILD_SYSTEM=bazel
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- sourceline: "deb [arch=amd64] http://storage.googleapis.com/bazel-apt stable jdk1.8"
|
||||
key_url: "https://storage.googleapis.com/bazel-apt/doc/apt-key.pub.gpg"
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- bazel
|
||||
|
||||
- os: osx
|
||||
env: BUILD_SYSTEM=bazel
|
||||
# Latest image with Java 1.8 (required to install Bazel).
|
||||
osx_image: xcode9.3
|
||||
language: java
|
||||
|
||||
before_install:
|
||||
###
|
||||
## If we use the matrix to set CC/CXX Travis, overwrites the values,
|
||||
## so instead we use C/CXX_COMPILER, then copy the values to CC/CXX
|
||||
## here (after Travis has set CC/CXX).
|
||||
###
|
||||
- if [ -n "${C_COMPILER}" ]; then export CC="${C_COMPILER}"; fi
|
||||
- if [ -n "${CXX_COMPILER}" ]; then export CXX="${CXX_COMPILER}"; fi
|
||||
- scripts/.travis.sh before_install
|
||||
install:
|
||||
- scripts/.travis.sh install
|
||||
script:
|
||||
- scripts/.travis.sh script
|
||||
after_success:
|
||||
- scripts/.travis.sh after_success
|
||||
|
||||
before_deploy:
|
||||
- scripts/.travis.sh before_deploy
|
||||
|
||||
deploy:
|
||||
- provider: bintray
|
||||
file: "scripts/.bintray.json"
|
||||
user: "eustas"
|
||||
key:
|
||||
secure: "Kbam/lTAdz72fZivbs6riJT+Y4PbuKP7r6t5PAWxJxAAykjwnYTRe3zF472g9HCE14KYMsdB+KSYSgg6TGJnqGC9gL9xhhGU9U/WmA+vbMWS/MSnMWpK9IRpp77pM2i2NKZD4v33JuEwKFCBJP3Vj6QQ5Qd1NKdobuXJyznhgnw="
|
||||
on:
|
||||
condition: "${BUILD_SYSTEM} = bazel"
|
||||
skip_cleanup: true
|
||||
@@ -10,43 +10,34 @@ licenses(["notice"]) # MIT
|
||||
exports_files(["LICENSE"])
|
||||
|
||||
config_setting(
|
||||
name = "darwin",
|
||||
values = {"cpu": "darwin"},
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "darwin_x86_64",
|
||||
values = {"cpu": "darwin_x86_64"},
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "windows",
|
||||
values = {"cpu": "x64_windows"},
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "windows_msvc",
|
||||
values = {"cpu": "x64_windows_msvc"},
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "windows_msys",
|
||||
values = {"cpu": "x64_windows_msys"},
|
||||
name = "clang-cl",
|
||||
flag_values = {
|
||||
"@bazel_tools//tools/cpp:compiler": "clang-cl",
|
||||
},
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "msvc",
|
||||
values = {"compiler": "msvc-cl"},
|
||||
flag_values = {
|
||||
"@bazel_tools//tools/cpp:compiler": "msvc-cl",
|
||||
},
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
STRICT_C_OPTIONS = select({
|
||||
":msvc": [],
|
||||
":clang-cl": [
|
||||
"/W4",
|
||||
"-Wconversion",
|
||||
"-Wlong-long",
|
||||
"-Wmissing-declarations",
|
||||
"-Wmissing-prototypes",
|
||||
"-Wno-strict-aliasing",
|
||||
"-Wshadow",
|
||||
"-Wsign-compare",
|
||||
"-Wno-sign-conversion",
|
||||
],
|
||||
"//conditions:default": [
|
||||
"--pedantic-errors",
|
||||
"-Wall",
|
||||
@@ -101,7 +92,7 @@ cc_library(
|
||||
name = "brotli_inc",
|
||||
hdrs = [":public_headers"],
|
||||
copts = STRICT_C_OPTIONS,
|
||||
includes = ["c/include"],
|
||||
strip_include_prefix = "c/include",
|
||||
)
|
||||
|
||||
cc_library(
|
||||
@@ -125,7 +116,11 @@ cc_library(
|
||||
srcs = [":enc_sources"],
|
||||
hdrs = [":enc_headers"],
|
||||
copts = STRICT_C_OPTIONS,
|
||||
linkopts = ["-lm"],
|
||||
linkopts = select({
|
||||
":clang-cl": [],
|
||||
":msvc": [],
|
||||
"//conditions:default": ["-lm"],
|
||||
}),
|
||||
deps = [":brotlicommon"],
|
||||
)
|
||||
|
||||
291
CHANGELOG.md
Normal file
291
CHANGELOG.md
Normal file
@@ -0,0 +1,291 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## Unreleased
|
||||
|
||||
## [1.2.0] - 2025-10-xx
|
||||
|
||||
### SECURITY
|
||||
- python: added `Decompressor::can_accept_more_data` method and optional
|
||||
`output_buffer_limit` argument `Decompressor::process`;
|
||||
that allows mitigation of unexpectedly large output;
|
||||
reported by Charles Chan (https://github.com/charleswhchan)
|
||||
|
||||
### Added
|
||||
- **decoder / encoder: added static initialization to reduce binary size**
|
||||
- python: allow limiting decoder output (see SECURITY section)
|
||||
- CLI: `brcat` alias; allow decoding concatenated brotli streams
|
||||
- kt: pure Kotlin decoder
|
||||
- cgo: support "raw" dictionaries
|
||||
- build: Bazel modules
|
||||
|
||||
### Removed
|
||||
- java: dropped `finalize()` for native entities
|
||||
|
||||
### Fixed
|
||||
- java: in `compress` pass correct length to native encoder
|
||||
|
||||
### Improved
|
||||
- build: install man pages
|
||||
- build: updated / fixed / refined Bazel buildfiles
|
||||
- encoder: faster encoding
|
||||
- cgo: link via pkg-config
|
||||
- python: modernize extension / allow multi-phase module initialization
|
||||
|
||||
### Changed
|
||||
- decoder / encoder: static tables use "small" model (allows 2GiB+ binaries)
|
||||
|
||||
|
||||
## [1.1.0] - 2023-08-28
|
||||
|
||||
### Added
|
||||
- decoder: `BrotliDecoderAttachDictionary`
|
||||
- decoder: `BrotliDecoderOnFinish` callback behind `BROTLI_REPORTING`
|
||||
- decoder: `BrotliDecoderSetMetadataCallbacks`
|
||||
- encoder: `BrotliEncoderPrepareDictionary`,
|
||||
`BrotliEncoderDestroyPreparedDictionary`,
|
||||
`BrotliEncoderAttachPreparedDictionary`
|
||||
- decoder: `BrotliEncoderOnFinish` callback behind `BROTLI_REPORTING`
|
||||
- common: `BrotliSharedDictionaryCreateInstance`,
|
||||
`BrotliSharedDictionaryDestroyInstance`,
|
||||
`BrotliSharedDictionaryAttach`
|
||||
- CLI: `--dictionary` option
|
||||
- java: encoder wrapper: `Parameters.mode`
|
||||
- java: `Brotli{Input|Output}Stream.attachDictionary`
|
||||
- java: wrapper: partial byte array input
|
||||
- typescript: decoder (transpiled from Java)
|
||||
|
||||
### Removed
|
||||
- build: `BROTLI_BUILD_PORTABLE` option
|
||||
|
||||
### Fixed
|
||||
- java: JNI decoder failed sometimes on power of 2 payloads
|
||||
|
||||
### Improved
|
||||
- java / js: smaller decoder footprint
|
||||
- decoder: faster decoding
|
||||
- encoder: faster encoding
|
||||
- encoder: smaller stack frames
|
||||
|
||||
|
||||
## [1.0.9] - 2020-08-27
|
||||
|
||||
Re-release of 1.0.8.
|
||||
|
||||
|
||||
## [1.0.8] - 2020-08-27
|
||||
|
||||
### SECURITY
|
||||
- CVE-2020-8927: potential overflow when input chunk is >2GiB
|
||||
|
||||
### Added
|
||||
- encoder: `BROTLI_PARAM_STREAM_OFFSET`
|
||||
|
||||
### Improved
|
||||
- CLI: better reporting
|
||||
- CLI: workaround for "lying feof"
|
||||
- java: faster decoding
|
||||
- java: support "large window"
|
||||
- encoder: use less memory
|
||||
- release: filter sources for the tarball
|
||||
|
||||
|
||||
## [1.0.7] - 2018-10-23
|
||||
|
||||
### Improved
|
||||
- decoder: faster decoding on ARM CPU
|
||||
|
||||
|
||||
## [1.0.6] - 2018-09-13
|
||||
|
||||
### Fixed
|
||||
- build: AutoMake and CMake build
|
||||
- java: JDK 8<->9 incompatibility
|
||||
|
||||
|
||||
## [1.0.5] - 2018-06-27
|
||||
|
||||
### Added
|
||||
- scripts: extraction of static dictionary from RFC
|
||||
|
||||
### Improved
|
||||
- encoder: better compression at quality 1
|
||||
- encoder: better compression with "large window"
|
||||
|
||||
|
||||
## [1.0.4] - 2018-03-29
|
||||
|
||||
### Added
|
||||
- encoder: `BROTLI_PARAM_NPOSTFIX`, `BROTLI_PARAM_NDIRECT`
|
||||
- CLI: `--large_window` option
|
||||
|
||||
### Improved
|
||||
- encoder: better compression
|
||||
|
||||
|
||||
## [1.0.3] - 2018-03-02
|
||||
|
||||
### Added
|
||||
- decoder: `BROTLI_DECODER_PARAM_LARGE_WINDOW` enum
|
||||
- encoder: `BROTLI_PARAM_LARGE_WINDOW` enum
|
||||
- java: `BrotliInputStream.setEager`
|
||||
|
||||
### Fixed
|
||||
- build: AutoMake build in some environments
|
||||
- encoder: fix one-shot q=10 1-byte input compression
|
||||
|
||||
### Improved
|
||||
- encoder: better font compression
|
||||
|
||||
|
||||
## [1.0.2] - 2017-11-28
|
||||
|
||||
### Added
|
||||
- build: AutoMake
|
||||
- research: better dictionary generators
|
||||
|
||||
|
||||
## [1.0.1] - 2017-09-22
|
||||
|
||||
### Changed
|
||||
- clarifications in `README.md`
|
||||
|
||||
|
||||
## [1.0.0] - 2017-09-20
|
||||
|
||||
### Added
|
||||
- decoder: `BrotliDecoderSetParameter`
|
||||
- csharp: decoder (transpiled from Java)
|
||||
- java: JNI wrappers
|
||||
- javascript: decoder (transpiled from Java)
|
||||
- python: streaming decompression
|
||||
- research: dictionary generator
|
||||
|
||||
### Changed
|
||||
- CLI: rename `bro` to `brotli`
|
||||
|
||||
### Removed
|
||||
- decoder: `BrotliDecoderSetCustomDictionary`
|
||||
- encoder: `BrotliEncoderSetCustomDictionary`
|
||||
|
||||
### Improved
|
||||
- java: faster decoding
|
||||
- encoder: faster compression
|
||||
|
||||
|
||||
## [0.6.0] - 2017-04-10
|
||||
|
||||
### Added
|
||||
- CLI: `--no-copy-stat option
|
||||
- java: pure java decoder
|
||||
- build: fuzzers
|
||||
- research: `brotlidump` tool to explore brotli streams
|
||||
- go: wrapper
|
||||
|
||||
### Removed
|
||||
- decoder: API with plain `Brotli` prefix
|
||||
|
||||
### Deprecated
|
||||
- encoder: `BrotliEncoderInputBlockSize`, `BrotliEncoderCopyInputToRingBuffer`,
|
||||
`BrotliEncoderWriteData`
|
||||
|
||||
### Improved
|
||||
- encoder: faster compression
|
||||
- encoder: denser compression
|
||||
- decoder: faster decompression
|
||||
- python: release GIL
|
||||
- python: use zero-copy API
|
||||
|
||||
|
||||
## [0.5.2] - 2016-08-11
|
||||
|
||||
### Added
|
||||
- common: `BROTLI_BOOL`, `BROTLI_TRUE`, `BROTLI_FALSE`
|
||||
- decoder: API with `BrotliDecoder` prefix instead of plain `Brotli`
|
||||
- build: Bazel, CMake
|
||||
|
||||
### Deprecated
|
||||
- decoder: API with plain `Brotli` prefix
|
||||
|
||||
### Changed
|
||||
- boolean argument / result types are re-branded as `BROTLI_BOOL`
|
||||
|
||||
### Improved
|
||||
- build: reduced amount of warnings in various build environments
|
||||
- encoder: faster compression
|
||||
- encoder: lower memory usage
|
||||
|
||||
|
||||
## [0.5.0] - 2016-06-15
|
||||
|
||||
### Added
|
||||
- common: library has been assembled from shared parts of decoder and encoder
|
||||
- encoder: C API
|
||||
|
||||
### Removed
|
||||
- encoder: C++ API
|
||||
|
||||
|
||||
## [0.4.0] - 2016-06-14
|
||||
|
||||
### Added
|
||||
- encoder: faster compression modes (quality 0 and 1)
|
||||
- decoder: `BrotliGetErrorCode`, `BrotliErrorString` and
|
||||
`BROTLI_ERROR_CODES_LIST`
|
||||
|
||||
### Removed
|
||||
- decoder: deprecated streaming API (using `BrotliInput`)
|
||||
|
||||
### Fixed
|
||||
- decoder: possible pointer underflow
|
||||
|
||||
### Improved
|
||||
- encoder: faster compression
|
||||
|
||||
|
||||
## [0.3.0] - 2015-12-22
|
||||
|
||||
### LICENSE
|
||||
License have been upgraded to more permissive MIT.
|
||||
|
||||
### Added
|
||||
- CLI: `--window` option
|
||||
- `tools/version.h` file
|
||||
- decoder: low level streaming API
|
||||
- decoder: custom memory manager API
|
||||
|
||||
### Deprecated
|
||||
- decoder: streaming API using `BrotliInput` struct
|
||||
|
||||
### Fixed
|
||||
- decoder: processing of uncompressed blocks
|
||||
- encoder: possible division by zero
|
||||
|
||||
### Improved
|
||||
- encoder: faster decompression
|
||||
- build: more portable builds for various CPU architectures
|
||||
|
||||
|
||||
## [0.2.0] - 2015-09-01
|
||||
|
||||
### Added
|
||||
- CLI: `--verbose` and `--repeat` options
|
||||
|
||||
### Fixed
|
||||
- decoder: processing of uncompressed blocks
|
||||
- encoder: block stitching on quality 10 / 11
|
||||
|
||||
### Improved
|
||||
- build: CI/CD integration
|
||||
- build: better test coverage
|
||||
- encoder: better compression of UTF-8 content
|
||||
- encoder: faster decompression
|
||||
|
||||
|
||||
## [0.1.0] - 2015-08-11
|
||||
|
||||
Initial release.
|
||||
363
CMakeLists.txt
363
CMakeLists.txt
@@ -1,78 +1,85 @@
|
||||
# Ubuntu 12.04 LTS has CMake 2.8.7, and is an important target since
|
||||
# several CI services, such as Travis and Drone, use it. Solaris 11
|
||||
# has 2.8.6, and it's not difficult to support if you already have to
|
||||
# support 2.8.7.
|
||||
cmake_minimum_required(VERSION 2.8.6)
|
||||
# Available CMake versions:
|
||||
# - Ubuntu 20.04 LTS : 3.16.3
|
||||
# - Solaris 11.4 SRU 15 : 3.15
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
|
||||
# Since this project's version is loaded from other files, this policy
|
||||
# will help suppress the warning generated by cmake.
|
||||
# This policy is set because we can't provide "VERSION" in "project" command.
|
||||
# Use `cmake --help-policy CMP0048` for more information.
|
||||
cmake_policy(SET CMP0048 NEW)
|
||||
project(brotli C)
|
||||
|
||||
if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||
message(STATUS "Setting build type to Release as none was specified")
|
||||
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build" FORCE)
|
||||
else()
|
||||
message(STATUS "Build type is '${CMAKE_BUILD_TYPE}'")
|
||||
endif()
|
||||
|
||||
include(CheckCSourceCompiles)
|
||||
check_c_source_compiles(
|
||||
"#if defined(__EMSCRIPTEN__)
|
||||
int main() {return 0;}
|
||||
#endif"
|
||||
BROTLI_EMSCRIPTEN
|
||||
)
|
||||
if (BROTLI_EMSCRIPTEN)
|
||||
message("-- Compiler is EMSCRIPTEN")
|
||||
else()
|
||||
message("-- Compiler is not EMSCRIPTEN")
|
||||
endif()
|
||||
|
||||
if (BROTLI_EMSCRIPTEN)
|
||||
message(STATUS "Switching to static build for EMSCRIPTEN")
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
endif()
|
||||
|
||||
# Reflect CMake variable as a build option.
|
||||
option(BUILD_SHARED_LIBS "Build shared libraries" ON)
|
||||
set(BROTLI_BUILD_TOOLS ON CACHE BOOL "Build/install CLI tools")
|
||||
set(BROTLI_BUILD_FOR_PACKAGE OFF CACHE BOOL "Build/install both shared and static libraries")
|
||||
|
||||
if (BROTLI_BUILD_FOR_PACKAGE AND NOT BUILD_SHARED_LIBS)
|
||||
message(FATAL_ERROR "Both BROTLI_BUILD_FOR_PACKAGE and BUILD_SHARED_LIBS are set")
|
||||
endif()
|
||||
|
||||
# If Brotli is being bundled in another project, we don't want to
|
||||
# install anything. However, we want to let people override this, so
|
||||
# we'll use the BROTLI_BUNDLED_MODE variable to let them do that; just
|
||||
# set it to OFF in your project before you add_subdirectory(brotli).
|
||||
get_directory_property(BROTLI_PARENT_DIRECTORY PARENT_DIRECTORY)
|
||||
if(NOT DEFINED BROTLI_BUNDLED_MODE)
|
||||
if (NOT DEFINED BROTLI_BUNDLED_MODE)
|
||||
# Bundled mode hasn't been set one way or the other, set the default
|
||||
# depending on whether or not we are the top-level project.
|
||||
if(BROTLI_PARENT_DIRECTORY)
|
||||
if (BROTLI_PARENT_DIRECTORY)
|
||||
set(BROTLI_BUNDLED_MODE ON)
|
||||
else()
|
||||
set(BROTLI_BUNDLED_MODE OFF)
|
||||
endif()
|
||||
endif()
|
||||
endif() # BROTLI_BUNDLED_MODE
|
||||
mark_as_advanced(BROTLI_BUNDLED_MODE)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
# Parse version information from common/version.h. Normally we would
|
||||
# define these values here and write them out to configuration file(s)
|
||||
# (i.e., config.h), but in this case we parse them from
|
||||
# common/version.h to be less intrusive.
|
||||
function(hex_to_dec HEXADECIMAL DECIMAL)
|
||||
string(TOUPPER "${HEXADECIMAL}" _tail)
|
||||
set(_decimal 0)
|
||||
string(LENGTH "${_tail}" _tail_length)
|
||||
while (_tail_length GREATER 0)
|
||||
math(EXPR _decimal "${_decimal} * 16")
|
||||
string(SUBSTRING "${_tail}" 0 1 _digit)
|
||||
string(SUBSTRING "${_tail}" 1 -1 _tail)
|
||||
if (_digit STREQUAL "A")
|
||||
math(EXPR _decimal "${_decimal} + 10")
|
||||
elseif (_digit STREQUAL "B")
|
||||
math(EXPR _decimal "${_decimal} + 11")
|
||||
elseif (_digit STREQUAL "C")
|
||||
math(EXPR _decimal "${_decimal} + 12")
|
||||
elseif (_digit STREQUAL "D")
|
||||
math(EXPR _decimal "${_decimal} + 13")
|
||||
elseif (_digit STREQUAL "E")
|
||||
math(EXPR _decimal "${_decimal} + 14")
|
||||
elseif (_digit STREQUAL "F")
|
||||
math(EXPR _decimal "${_decimal} + 15")
|
||||
else()
|
||||
math(EXPR _decimal "${_decimal} + ${_digit}")
|
||||
endif()
|
||||
string(LENGTH "${_tail}" _tail_length)
|
||||
endwhile()
|
||||
set(${DECIMAL} ${_decimal} PARENT_SCOPE)
|
||||
endfunction(hex_to_dec)
|
||||
# Reads macro from .h file; it is expected to be a single-line define.
|
||||
function(read_macro PATH MACRO OUTPUT)
|
||||
file(STRINGS ${PATH} _line REGEX "^#define +${MACRO} +(.+)$")
|
||||
string(REGEX REPLACE "^#define +${MACRO} +(.+)$" "\\1" _val "${_line}")
|
||||
set(${OUTPUT} ${_val} PARENT_SCOPE)
|
||||
endfunction(read_macro)
|
||||
|
||||
# Version information
|
||||
file(STRINGS "c/common/version.h" _brotli_version_line REGEX "^#define BROTLI_VERSION (0x[0-9a-fA-F]+)$")
|
||||
string(REGEX REPLACE "^#define BROTLI_VERSION 0x([0-9a-fA-F]+)$" "\\1" _brotli_version_hex "${_brotli_version_line}")
|
||||
hex_to_dec("${_brotli_version_hex}" _brotli_version)
|
||||
math(EXPR BROTLI_VERSION_MAJOR "${_brotli_version} >> 24")
|
||||
math(EXPR BROTLI_VERSION_MINOR "(${_brotli_version} >> 12) & 4095")
|
||||
math(EXPR BROTLI_VERSION_PATCH "${_brotli_version} & 4095")
|
||||
read_macro("c/common/version.h" "BROTLI_VERSION_MAJOR" BROTLI_VERSION_MAJOR)
|
||||
read_macro("c/common/version.h" "BROTLI_VERSION_MINOR" BROTLI_VERSION_MINOR)
|
||||
read_macro("c/common/version.h" "BROTLI_VERSION_PATCH" BROTLI_VERSION_PATCH)
|
||||
set(BROTLI_VERSION "${BROTLI_VERSION_MAJOR}.${BROTLI_VERSION_MINOR}.${BROTLI_VERSION_PATCH}")
|
||||
mark_as_advanced(BROTLI_VERSION BROTLI_VERSION_MAJOR BROTLI_VERSION_MINOR BROTLI_VERSION_PATCH)
|
||||
|
||||
# ABI Version information
|
||||
file(STRINGS "c/common/version.h" _brotli_abi_info_line REGEX "^#define BROTLI_ABI_VERSION (0x[0-9a-fA-F]+)$")
|
||||
string(REGEX REPLACE "^#define BROTLI_ABI_VERSION 0x([0-9a-fA-F]+)$" "\\1" _brotli_abi_info_hex "${_brotli_abi_info_line}")
|
||||
hex_to_dec("${_brotli_abi_info_hex}" _brotli_abi_info)
|
||||
math(EXPR BROTLI_ABI_CURRENT "${_brotli_abi_info} >> 24")
|
||||
math(EXPR BROTLI_ABI_REVISION "(${_brotli_abi_info} >> 12) & 4095")
|
||||
math(EXPR BROTLI_ABI_AGE "${_brotli_abi_info} & 4095")
|
||||
read_macro("c/common/version.h" "BROTLI_ABI_CURRENT" BROTLI_ABI_CURRENT)
|
||||
read_macro("c/common/version.h" "BROTLI_ABI_REVISION" BROTLI_ABI_REVISION)
|
||||
read_macro("c/common/version.h" "BROTLI_ABI_AGE" BROTLI_ABI_AGE)
|
||||
math(EXPR BROTLI_ABI_COMPATIBILITY "${BROTLI_ABI_CURRENT} - ${BROTLI_ABI_AGE}")
|
||||
mark_as_advanced(BROTLI_ABI_CURRENT BROTLI_ABI_REVISION BROTLI_ABI_AGE BROTLI_ABI_COMPATIBILITY)
|
||||
|
||||
@@ -80,127 +87,112 @@ if (ENABLE_SANITIZER)
|
||||
set(CMAKE_C_FLAGS " ${CMAKE_C_FLAGS} -fsanitize=${ENABLE_SANITIZER}")
|
||||
set(CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -fsanitize=${ENABLE_SANITIZER}")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=${ENABLE_SANITIZER}")
|
||||
|
||||
# By default, brotli depends on undefined behavior, but setting
|
||||
# BROTLI_BUILD_PORTABLE should result in a build which does not.
|
||||
if(ENABLE_SANITIZER STREQUAL "undefined")
|
||||
add_definitions(-DBROTLI_BUILD_PORTABLE)
|
||||
endif()
|
||||
endif ()
|
||||
|
||||
include(CheckFunctionExists)
|
||||
include(CheckLibraryExists)
|
||||
set(LIBM_LIBRARY)
|
||||
CHECK_FUNCTION_EXISTS(log2 LOG2_RES)
|
||||
if(NOT LOG2_RES)
|
||||
set(orig_req_libs "${CMAKE_REQUIRED_LIBRARIES}")
|
||||
set(CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES};m")
|
||||
CHECK_FUNCTION_EXISTS(log2 LOG2_LIBM_RES)
|
||||
if(LOG2_LIBM_RES)
|
||||
set(LIBM_LIBRARY "m")
|
||||
else()
|
||||
message(FATAL_ERROR "log2() not found")
|
||||
set(LIBM_DEP)
|
||||
CHECK_LIBRARY_EXISTS(m log2 "" HAVE_LIB_M)
|
||||
if (HAVE_LIB_M)
|
||||
set(LIBM_LIBRARY "m")
|
||||
if (NOT BUILD_SHARED_LIBS)
|
||||
set(LIBM_DEP "-lm")
|
||||
endif()
|
||||
|
||||
set(CMAKE_REQUIRED_LIBRARIES "${orig_req_libs}")
|
||||
unset(LOG2_LIBM_RES)
|
||||
unset(orig_req_libs)
|
||||
endif()
|
||||
unset(LOG2_RES)
|
||||
|
||||
set(BROTLI_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/c/include")
|
||||
mark_as_advanced(BROTLI_INCLUDE_DIRS)
|
||||
|
||||
set(BROTLI_LIBRARIES_CORE brotlienc brotlidec brotlicommon)
|
||||
set(BROTLI_LIBRARIES ${BROTLI_LIBRARIES_CORE} ${LIBM_LIBRARY})
|
||||
if (BROTLI_BUILD_FOR_PACKAGE)
|
||||
set(BROTLI_SHARED_LIBRARIES brotlienc brotlidec brotlicommon)
|
||||
set(BROTLI_STATIC_LIBRARIES brotlienc-static brotlidec-static brotlicommon-static)
|
||||
set(BROTLI_LIBRARIES ${BROTLI_SHARED_LIBRARIES} ${LIBM_LIBRARY})
|
||||
else() # NOT BROTLI_BUILD_FOR_PACKAGE
|
||||
if (BUILD_SHARED_LIBS)
|
||||
set(BROTLI_SHARED_LIBRARIES brotlienc brotlidec brotlicommon)
|
||||
set(BROTLI_STATIC_LIBRARIES)
|
||||
else() # NOT BUILD_SHARED_LIBS
|
||||
set(BROTLI_SHARED_LIBRARIES)
|
||||
set(BROTLI_STATIC_LIBRARIES brotlienc brotlidec brotlicommon)
|
||||
endif()
|
||||
set(BROTLI_LIBRARIES ${BROTLI_SHARED_LIBRARIES} ${BROTLI_STATIC_LIBRARIES} ${LIBM_LIBRARY})
|
||||
endif() # BROTLI_BUILD_FOR_PACKAGE
|
||||
mark_as_advanced(BROTLI_LIBRARIES)
|
||||
|
||||
set(BROTLI_LIBRARIES_CORE_STATIC brotlienc-static brotlidec-static brotlicommon-static)
|
||||
set(BROTLI_LIBRARIES_STATIC ${BROTLI_LIBRARIES_CORE_STATIC} ${LIBM_LIBRARY})
|
||||
mark_as_advanced(BROTLI_LIBRARIES_STATIC)
|
||||
if (MSVC)
|
||||
message(STATUS "Defining _CRT_SECURE_NO_WARNINGS to avoid warnings about security")
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
add_definitions(-DOS_LINUX)
|
||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
|
||||
add_definitions(-DOS_FREEBSD)
|
||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
add_definitions(-DOS_MACOSX)
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
endif()
|
||||
|
||||
function(transform_sources_list INPUT_FILE OUTPUT_FILE)
|
||||
file(READ ${INPUT_FILE} TEXT)
|
||||
string(REGEX REPLACE "\\\\\n" "~continuation~" TEXT ${TEXT})
|
||||
string(REGEX REPLACE "([a-zA-Z_][a-zA-Z0-9_]*)[\t ]*=[\t ]*([^\n]*)" "SET(\\1 \\2)" TEXT ${TEXT})
|
||||
string(REPLACE "~continuation~" "\n" TEXT ${TEXT})
|
||||
file(WRITE ${OUTPUT_FILE} ${TEXT})
|
||||
endfunction()
|
||||
file(GLOB_RECURSE BROTLI_COMMON_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} c/common/*.c)
|
||||
file(GLOB_RECURSE BROTLI_DEC_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} c/dec/*.c)
|
||||
file(GLOB_RECURSE BROTLI_ENC_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} c/enc/*.c)
|
||||
|
||||
transform_sources_list("scripts/sources.lst" "${CMAKE_CURRENT_BINARY_DIR}/sources.lst.cmake")
|
||||
include("${CMAKE_CURRENT_BINARY_DIR}/sources.lst.cmake")
|
||||
add_library(brotlicommon ${BROTLI_COMMON_SOURCES})
|
||||
add_library(brotlidec ${BROTLI_DEC_SOURCES})
|
||||
add_library(brotlienc ${BROTLI_ENC_SOURCES})
|
||||
|
||||
add_library(brotlicommon SHARED ${BROTLI_COMMON_C})
|
||||
add_library(brotlidec SHARED ${BROTLI_DEC_C})
|
||||
add_library(brotlienc SHARED ${BROTLI_ENC_C})
|
||||
|
||||
add_library(brotlicommon-static STATIC ${BROTLI_COMMON_C})
|
||||
add_library(brotlidec-static STATIC ${BROTLI_DEC_C})
|
||||
add_library(brotlienc-static STATIC ${BROTLI_ENC_C})
|
||||
if (BROTLI_BUILD_FOR_PACKAGE)
|
||||
add_library(brotlicommon-static STATIC ${BROTLI_COMMON_SOURCES})
|
||||
add_library(brotlidec-static STATIC ${BROTLI_DEC_SOURCES})
|
||||
add_library(brotlienc-static STATIC ${BROTLI_ENC_SOURCES})
|
||||
endif()
|
||||
|
||||
# Older CMake versions does not understand INCLUDE_DIRECTORIES property.
|
||||
include_directories(${BROTLI_INCLUDE_DIRS})
|
||||
|
||||
foreach(lib brotlicommon brotlidec brotlienc)
|
||||
target_compile_definitions(${lib} PUBLIC "BROTLI_SHARED_COMPILATION" )
|
||||
string(TOUPPER "${lib}" LIB)
|
||||
set_target_properties (${lib} PROPERTIES DEFINE_SYMBOL "${LIB}_SHARED_COMPILATION" )
|
||||
endforeach()
|
||||
if (BUILD_SHARED_LIBS)
|
||||
foreach(lib ${BROTLI_SHARED_LIBRARIES})
|
||||
target_compile_definitions(${lib} PUBLIC "BROTLI_SHARED_COMPILATION" )
|
||||
string(TOUPPER "${lib}" LIB)
|
||||
set_target_properties (${lib} PROPERTIES DEFINE_SYMBOL "${LIB}_SHARED_COMPILATION")
|
||||
endforeach()
|
||||
endif() # BUILD_SHARED_LIBS
|
||||
|
||||
foreach(lib brotlicommon brotlidec brotlienc brotlicommon-static brotlidec-static brotlienc-static)
|
||||
foreach(lib ${BROTLI_SHARED_LIBRARIES} ${BROTLI_STATIC_LIBRARIES})
|
||||
target_link_libraries(${lib} ${LIBM_LIBRARY})
|
||||
set_property(TARGET ${lib} APPEND PROPERTY INCLUDE_DIRECTORIES ${BROTLI_INCLUDE_DIRS})
|
||||
set_target_properties(${lib} PROPERTIES
|
||||
VERSION "${BROTLI_ABI_COMPATIBILITY}.${BROTLI_ABI_AGE}.${BROTLI_ABI_REVISION}"
|
||||
SOVERSION "${BROTLI_ABI_COMPATIBILITY}"
|
||||
POSITION_INDEPENDENT_CODE TRUE)
|
||||
set_property(TARGET ${lib} APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${BROTLI_INCLUDE_DIRS}")
|
||||
endforeach()
|
||||
SOVERSION "${BROTLI_ABI_COMPATIBILITY}")
|
||||
if (NOT BROTLI_EMSCRIPTEN)
|
||||
set_target_properties(${lib} PROPERTIES POSITION_INDEPENDENT_CODE TRUE)
|
||||
endif()
|
||||
set_property(TARGET ${lib} APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${BROTLI_INCLUDE_DIRS}>")
|
||||
endforeach() # BROTLI_xxx_LIBRARIES
|
||||
|
||||
target_link_libraries(brotlidec brotlicommon)
|
||||
target_link_libraries(brotlienc brotlicommon)
|
||||
|
||||
target_link_libraries(brotlidec-static brotlicommon-static)
|
||||
target_link_libraries(brotlienc-static brotlicommon-static)
|
||||
|
||||
# For projects stuck on older versions of CMake, this will set the
|
||||
# BROTLI_INCLUDE_DIRS and BROTLI_LIBRARIES variables so they still
|
||||
# have a relatively easy way to use Brotli:
|
||||
#
|
||||
# include_directories(${BROTLI_INCLUDE_DIRS})
|
||||
# target_link_libraries(foo ${BROTLI_LIBRARIES})
|
||||
if(BROTLI_PARENT_DIRECTORY)
|
||||
if (BROTLI_PARENT_DIRECTORY)
|
||||
set(BROTLI_INCLUDE_DIRS "${BROTLI_INCLUDE_DIRS}" PARENT_SCOPE)
|
||||
set(BROTLI_LIBRARIES "${BROTLI_LIBRARIES}" PARENT_SCOPE)
|
||||
endif()
|
||||
|
||||
# Build the brotli executable
|
||||
add_executable(brotli ${BROTLI_CLI_C})
|
||||
target_link_libraries(brotli ${BROTLI_LIBRARIES_STATIC})
|
||||
if (BROTLI_BUILD_TOOLS)
|
||||
add_executable(brotli c/tools/brotli.c)
|
||||
target_link_libraries(brotli ${BROTLI_LIBRARIES})
|
||||
endif()
|
||||
|
||||
# Installation
|
||||
if(NOT BROTLI_BUNDLED_MODE)
|
||||
install(
|
||||
TARGETS brotli
|
||||
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
|
||||
)
|
||||
if (NOT BROTLI_BUNDLED_MODE)
|
||||
if (BROTLI_BUILD_TOOLS)
|
||||
install(
|
||||
TARGETS brotli
|
||||
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
|
||||
)
|
||||
endif()
|
||||
|
||||
install(
|
||||
TARGETS ${BROTLI_LIBRARIES_CORE}
|
||||
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
||||
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
||||
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
|
||||
)
|
||||
|
||||
install(
|
||||
TARGETS ${BROTLI_LIBRARIES_CORE_STATIC}
|
||||
TARGETS ${BROTLI_SHARED_LIBRARIES} ${BROTLI_STATIC_LIBRARIES}
|
||||
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
||||
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
||||
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
|
||||
@@ -210,24 +202,53 @@ if(NOT BROTLI_BUNDLED_MODE)
|
||||
DIRECTORY ${BROTLI_INCLUDE_DIRS}/brotli
|
||||
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
|
||||
)
|
||||
endif()
|
||||
endif() # BROTLI_BUNDLED_MODE
|
||||
|
||||
# Tests
|
||||
|
||||
# If we're targeting Windows but not running on Windows, we need Wine
|
||||
# to run the tests...
|
||||
if(NOT BROTLI_DISABLE_TESTS)
|
||||
if(WIN32 AND NOT CMAKE_HOST_WIN32)
|
||||
find_program(BROTLI_WINE NAMES wine)
|
||||
# Integration tests, those depend on `brotli` binary
|
||||
if (NOT BROTLI_DISABLE_TESTS AND BROTLI_BUILD_TOOLS)
|
||||
# If we're targeting Windows but not running on Windows, we need Wine
|
||||
# to run the tests...
|
||||
if (WIN32 AND NOT CMAKE_HOST_WIN32)
|
||||
find_program(BROTLI_WRAPPER NAMES wine)
|
||||
|
||||
if(NOT BROTLI_WINE)
|
||||
if (NOT BROTLI_WRAPPER)
|
||||
message(STATUS "wine not found, disabling tests")
|
||||
set(BROTLI_DISABLE_TESTS TRUE)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endif() # WIN32 emulation
|
||||
if (BROTLI_EMSCRIPTEN)
|
||||
find_program(BROTLI_WRAPPER NAMES node)
|
||||
if (NOT BROTLI_WRAPPER)
|
||||
message(STATUS "node not found, disabling tests")
|
||||
set(BROTLI_DISABLE_TESTS TRUE)
|
||||
endif()
|
||||
endif() # BROTLI_EMSCRIPTEN
|
||||
endif() # BROTLI_DISABLE_TESTS
|
||||
|
||||
# NB: BROTLI_DISABLE_TESTS might have changed.
|
||||
if (NOT BROTLI_DISABLE_TESTS AND BROTLI_BUILD_TOOLS)
|
||||
# If our compiler is a cross-compiler that we know about (arm/aarch64),
|
||||
# then we need to use qemu to execute the tests.
|
||||
if ("${CMAKE_C_COMPILER}" MATCHES "^.*/arm-linux-gnueabihf-.*$")
|
||||
message(STATUS "Detected arm-linux-gnueabihf cross-compilation")
|
||||
set(BROTLI_WRAPPER "qemu-arm")
|
||||
set(BROTLI_WRAPPER_LD_PREFIX "/usr/arm-linux-gnueabihf")
|
||||
endif()
|
||||
|
||||
if ("${CMAKE_C_COMPILER}" MATCHES "^.*/arm-linux-gnueabi-.*$")
|
||||
message(STATUS "Detected arm-linux-gnueabi cross-compilation")
|
||||
set(BROTLI_WRAPPER "qemu-arm")
|
||||
set(BROTLI_WRAPPER_LD_PREFIX "/usr/arm-linux-gnueabi")
|
||||
endif()
|
||||
|
||||
if ("${CMAKE_C_COMPILER}" MATCHES "^.*/aarch64-linux-gnu-.*$")
|
||||
message(STATUS "Detected aarch64-linux-gnu cross-compilation")
|
||||
set(BROTLI_WRAPPER "qemu-aarch64")
|
||||
set(BROTLI_WRAPPER_LD_PREFIX "/usr/aarch64-linux-gnu")
|
||||
endif()
|
||||
|
||||
if(NOT BROTLI_DISABLE_TESTS)
|
||||
include(CTest)
|
||||
enable_testing()
|
||||
|
||||
@@ -246,16 +267,21 @@ if(NOT BROTLI_DISABLE_TESTS)
|
||||
set(OUTPUT_FILE "${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_NAME}")
|
||||
set(INPUT_FILE "${CMAKE_CURRENT_SOURCE_DIR}/${INPUT}")
|
||||
|
||||
foreach(quality 1 6 9 11)
|
||||
add_test(NAME "${BROTLI_TEST_PREFIX}roundtrip/${INPUT}/${quality}"
|
||||
COMMAND "${CMAKE_COMMAND}"
|
||||
-DBROTLI_WRAPPER=${BROTLI_WINE}
|
||||
-DBROTLI_CLI=$<TARGET_FILE:brotli>
|
||||
-DQUALITY=${quality}
|
||||
-DINPUT=${INPUT_FILE}
|
||||
-DOUTPUT=${OUTPUT_FILE}.${quality}
|
||||
-P ${CMAKE_CURRENT_SOURCE_DIR}/tests/run-roundtrip-test.cmake)
|
||||
endforeach()
|
||||
if (EXISTS "${INPUT_FILE}")
|
||||
foreach(quality 1 6 9 11)
|
||||
add_test(NAME "${BROTLI_TEST_PREFIX}roundtrip/${INPUT}/${quality}"
|
||||
COMMAND "${CMAKE_COMMAND}"
|
||||
-DBROTLI_WRAPPER=${BROTLI_WRAPPER}
|
||||
-DBROTLI_WRAPPER_LD_PREFIX=${BROTLI_WRAPPER_LD_PREFIX}
|
||||
-DBROTLI_CLI=$<TARGET_FILE:brotli>
|
||||
-DQUALITY=${quality}
|
||||
-DINPUT=${INPUT_FILE}
|
||||
-DOUTPUT=${OUTPUT_FILE}.${quality}
|
||||
-P ${CMAKE_CURRENT_SOURCE_DIR}/tests/run-roundtrip-test.cmake)
|
||||
endforeach()
|
||||
else()
|
||||
message(NOTICE "Test file ${INPUT} does not exist; OK on tarball builds; consider running scripts/download_testdata.sh before configuring.")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
file(GLOB_RECURSE
|
||||
@@ -264,14 +290,18 @@ if(NOT BROTLI_DISABLE_TESTS)
|
||||
tests/testdata/*.compressed*)
|
||||
|
||||
foreach(INPUT ${COMPATIBILITY_INPUTS})
|
||||
add_test(NAME "${BROTLI_TEST_PREFIX}compatibility/${INPUT}"
|
||||
COMMAND "${CMAKE_COMMAND}"
|
||||
-DBROTLI_WRAPPER=${BROTLI_WINE}
|
||||
-DBROTLI_CLI=$<TARGET_FILE:brotli>
|
||||
-DINPUT=${CMAKE_CURRENT_SOURCE_DIR}/${INPUT}
|
||||
-P ${CMAKE_CURRENT_SOURCE_DIR}/tests/run-compatibility-test.cmake)
|
||||
string(REGEX REPLACE "([a-zA-Z0-9\\.]+)\\.compressed(\\.[0-9]+)?$" "\\1" UNCOMPRESSED_INPUT "${INPUT}")
|
||||
if (EXISTS ${UNCOMPRESSED_INPUT})
|
||||
add_test(NAME "${BROTLI_TEST_PREFIX}compatibility/${INPUT}"
|
||||
COMMAND "${CMAKE_COMMAND}"
|
||||
-DBROTLI_WRAPPER=${BROTLI_WRAPPER}
|
||||
-DBROTLI_WRAPPER_LD_PREFIX=${BROTLI_WRAPPER_LD_PREFIX}
|
||||
-DBROTLI_CLI=$<TARGET_FILE:brotli>
|
||||
-DINPUT=${CMAKE_CURRENT_SOURCE_DIR}/${INPUT}
|
||||
-P ${CMAKE_CURRENT_SOURCE_DIR}/tests/run-compatibility-test.cmake)
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
endif() # BROTLI_DISABLE_TESTS
|
||||
|
||||
# Generate a pkg-config files
|
||||
|
||||
@@ -291,19 +321,19 @@ function(generate_pkg_config_path outvar path)
|
||||
get_filename_component(value_full "${value}" ABSOLUTE)
|
||||
string(LENGTH "${value}" value_length)
|
||||
|
||||
if(path_length EQUAL value_length AND path STREQUAL value)
|
||||
if (path_length EQUAL value_length AND path STREQUAL value)
|
||||
set("${outvar}" "\${${name}}")
|
||||
break()
|
||||
elseif(path_length GREATER value_length)
|
||||
elseif (path_length GREATER value_length)
|
||||
# We might be in a subdirectory of the value, but we have to be
|
||||
# careful about a prefix matching but not being a subdirectory
|
||||
# (for example, /usr/lib64 is not a subdirectory of /usr/lib).
|
||||
# We'll do this by making sure the next character is a directory
|
||||
# separator.
|
||||
string(SUBSTRING "${path}" ${value_length} 1 sep)
|
||||
if(sep STREQUAL "/")
|
||||
if (sep STREQUAL "/")
|
||||
string(SUBSTRING "${path}" 0 ${value_length} s)
|
||||
if(s STREQUAL value)
|
||||
if (s STREQUAL value)
|
||||
string(SUBSTRING "${path}" "${value_length}" -1 suffix)
|
||||
set("${outvar}" "\${${name}}${suffix}")
|
||||
break()
|
||||
@@ -324,6 +354,7 @@ function(transform_pc_file INPUT_FILE OUTPUT_FILE VERSION)
|
||||
set(PREFIX "${CMAKE_INSTALL_PREFIX}")
|
||||
string(REGEX REPLACE "@prefix@" "${PREFIX}" TEXT ${TEXT})
|
||||
string(REGEX REPLACE "@exec_prefix@" "${PREFIX}" TEXT ${TEXT})
|
||||
string(REGEX REPLACE "@libm@" "${LIBM_DEP}" TEXT ${TEXT})
|
||||
|
||||
generate_pkg_config_path(LIBDIR "${CMAKE_INSTALL_FULL_LIBDIR}" prefix "${PREFIX}")
|
||||
string(REGEX REPLACE "@libdir@" "${LIBDIR}" TEXT ${TEXT})
|
||||
@@ -342,15 +373,23 @@ transform_pc_file("scripts/libbrotlidec.pc.in" "${CMAKE_CURRENT_BINARY_DIR}/libb
|
||||
|
||||
transform_pc_file("scripts/libbrotlienc.pc.in" "${CMAKE_CURRENT_BINARY_DIR}/libbrotlienc.pc" "${BROTLI_VERSION}")
|
||||
|
||||
if(NOT BROTLI_BUNDLED_MODE)
|
||||
if (NOT BROTLI_BUNDLED_MODE)
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libbrotlicommon.pc"
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libbrotlidec.pc"
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libbrotlienc.pc"
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
|
||||
endif() # BROTLI_BUNDLED_MODE
|
||||
|
||||
if (BROTLI_BUILD_TOOLS)
|
||||
install(FILES "docs/brotli.1"
|
||||
DESTINATION "${CMAKE_INSTALL_FULL_MANDIR}/man1")
|
||||
endif()
|
||||
|
||||
install(FILES docs/constants.h.3 docs/decode.h.3 docs/encode.h.3 docs/types.h.3
|
||||
DESTINATION "${CMAKE_INSTALL_FULL_MANDIR}/man3")
|
||||
|
||||
if (ENABLE_COVERAGE STREQUAL "yes")
|
||||
SETUP_TARGET_FOR_COVERAGE(coverage test coverage)
|
||||
endif ()
|
||||
setup_target_for_coverage(coverage test coverage)
|
||||
endif()
|
||||
|
||||
@@ -21,6 +21,11 @@ frustration later on.
|
||||
All submissions, including submissions by project members, require review. We
|
||||
use Github pull requests for this purpose.
|
||||
|
||||
### Code style
|
||||
Code should follow applicable formatting and style guides described in
|
||||
[Google Style Guides](https://google.github.io/styleguide/). C code should be
|
||||
C89 compatible.
|
||||
|
||||
### The small print
|
||||
Contributions made by corporations are covered by a different agreement than
|
||||
the one above, the [Software Grant and Corporate Contributor License Agreement]
|
||||
|
||||
@@ -12,6 +12,8 @@ include python/_brotli.cc
|
||||
include python/bro.py
|
||||
include python/brotli.py
|
||||
include python/README.md
|
||||
include python/tests/*
|
||||
include README.md
|
||||
include setup.py
|
||||
include tests/testdata/*
|
||||
include c/tools/brotli.c
|
||||
|
||||
12
MODULE.bazel
Normal file
12
MODULE.bazel
Normal file
@@ -0,0 +1,12 @@
|
||||
# Copyright 2025 The Brotli Authors. All rights reserved.
|
||||
#
|
||||
# Distributed under MIT license.
|
||||
# See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
|
||||
"""Brotli reference implementation"""
|
||||
|
||||
module(
|
||||
name = "brotli",
|
||||
version = "1.2.0",
|
||||
repo_name = "org_brotli",
|
||||
)
|
||||
43
Makefile
43
Makefile
@@ -1,43 +0,0 @@
|
||||
OS := $(shell uname)
|
||||
LIBSOURCES = $(wildcard c/common/*.c) $(wildcard c/dec/*.c) \
|
||||
$(wildcard c/enc/*.c)
|
||||
SOURCES = $(LIBSOURCES) c/tools/brotli.c
|
||||
BINDIR = bin
|
||||
OBJDIR = $(BINDIR)/obj
|
||||
LIBOBJECTS = $(addprefix $(OBJDIR)/, $(LIBSOURCES:.c=.o))
|
||||
OBJECTS = $(addprefix $(OBJDIR)/, $(SOURCES:.c=.o))
|
||||
LIB_A = libbrotli.a
|
||||
EXECUTABLE = brotli
|
||||
DIRS = $(OBJDIR)/c/common $(OBJDIR)/c/dec $(OBJDIR)/c/enc \
|
||||
$(OBJDIR)/c/tools $(BINDIR)/tmp
|
||||
CFLAGS += -O2
|
||||
ifeq ($(os), Darwin)
|
||||
CPPFLAGS += -DOS_MACOSX
|
||||
endif
|
||||
|
||||
all: test
|
||||
@:
|
||||
|
||||
.PHONY: all clean test
|
||||
|
||||
$(DIRS):
|
||||
mkdir -p $@
|
||||
|
||||
$(EXECUTABLE): $(OBJECTS)
|
||||
$(CC) $(LDFLAGS) $(OBJECTS) -lm -o $(BINDIR)/$(EXECUTABLE)
|
||||
|
||||
lib: $(LIBOBJECTS)
|
||||
rm -f $(LIB_A)
|
||||
ar -crs $(LIB_A) $(LIBOBJECTS)
|
||||
|
||||
test: $(EXECUTABLE)
|
||||
tests/compatibility_test.sh
|
||||
tests/roundtrip_test.sh
|
||||
|
||||
clean:
|
||||
rm -rf $(BINDIR) $(LIB_A)
|
||||
|
||||
.SECONDEXPANSION:
|
||||
$(OBJECTS): $$(patsubst %.o,%.c,$$(patsubst $$(OBJDIR)/%,%,$$@)) | $(DIRS)
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -Ic/include \
|
||||
-c $(patsubst %.o,%.c,$(patsubst $(OBJDIR)/%,%,$@)) -o $@
|
||||
38
Makefile.am
38
Makefile.am
@@ -1,38 +0,0 @@
|
||||
AUTOMAKE_OPTIONS = foreign nostdinc subdir-objects
|
||||
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
# Actual ABI version is substituted by bootstrap
|
||||
LIBBROTLI_VERSION_INFO = -version-info 0:0:0
|
||||
|
||||
bin_PROGRAMS = brotli
|
||||
lib_LTLIBRARIES = libbrotlicommon.la libbrotlidec.la libbrotlienc.la
|
||||
|
||||
include scripts/sources.lst
|
||||
|
||||
brotliincludedir = $(includedir)/brotli
|
||||
brotliinclude_HEADERS = $(BROTLI_INCLUDE)
|
||||
|
||||
AM_CFLAGS = -I$(top_srcdir)/c/include
|
||||
|
||||
brotli_SOURCES = $(BROTLI_CLI_C)
|
||||
brotli_LDADD = libbrotlidec.la libbrotlienc.la libbrotlicommon.la -lm
|
||||
#brotli_LDFLAGS = -static
|
||||
|
||||
libbrotlicommon_la_SOURCES = $(BROTLI_COMMON_C) $(BROTLI_COMMON_H)
|
||||
libbrotlicommon_la_LDFLAGS = $(AM_LDFLAGS) $(LIBBROTLI_VERSION_INFO) $(LDFLAGS)
|
||||
libbrotlidec_la_SOURCES = $(BROTLI_DEC_C) $(BROTLI_DEC_H)
|
||||
libbrotlidec_la_LDFLAGS = $(AM_LDFLAGS) $(LIBBROTLI_VERSION_INFO) $(LDFLAGS)
|
||||
libbrotlidec_la_LIBADD = libbrotlicommon.la -lm
|
||||
libbrotlienc_la_SOURCES = $(BROTLI_ENC_C) $(BROTLI_ENC_H)
|
||||
libbrotlienc_la_LDFLAGS = $(AM_LDFLAGS) $(LIBBROTLI_VERSION_INFO) $(LDFLAGS)
|
||||
libbrotlienc_la_LIBADD = libbrotlicommon.la -lm
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = \
|
||||
scripts/libbrotlicommon.pc \
|
||||
scripts/libbrotlidec.pc \
|
||||
scripts/libbrotlienc.pc
|
||||
pkgincludedir= $(brotliincludedir)
|
||||
|
||||
dist_doc_DATA = README
|
||||
6
README
6
README
@@ -1,4 +1,4 @@
|
||||
BROTLI DATA COMPRESSIOM LIBRARY
|
||||
BROTLI DATA COMPRESSION LIBRARY
|
||||
|
||||
Brotli is a generic-purpose lossless compression algorithm that compresses data
|
||||
using a combination of a modern variant of the LZ77 algorithm, Huffman coding
|
||||
@@ -7,9 +7,9 @@ currently available general-purpose compression methods. It is similar in speed
|
||||
with deflate but offers more dense compression.
|
||||
|
||||
The specification of the Brotli Compressed Data Format is defined in RFC 7932
|
||||
https://tools.ietf.org/html/rfc7932
|
||||
https://datatracker.ietf.org/doc/html/rfc7932
|
||||
|
||||
Brotli is open-sourced under the MIT License, see the LICENSE file.
|
||||
|
||||
Brotli mailing list:
|
||||
https://groups.google.com/forum/#!forum/brotli
|
||||
https://groups.google.com/g/brotli
|
||||
|
||||
81
README.md
81
README.md
@@ -1,3 +1,7 @@
|
||||
<p align="center">
|
||||
<img src="https://github.com/google/brotli/actions/workflows/build_test.yml/badge.svg" alt="GitHub Actions Build Status" href="https://github.com/google/brotli/actions?query=branch%3Amaster">
|
||||
<img src="https://oss-fuzz-build-logs.storage.googleapis.com/badges/brotli.svg" alt="Fuzzing Status" href="https://oss-fuzz-build-logs.storage.googleapis.com/index.html#brotli">
|
||||
</p>
|
||||
<p align="center"><img src="https://brotli.org/brotli.svg" alt="Brotli" width="64"></p>
|
||||
|
||||
### Introduction
|
||||
@@ -8,36 +12,47 @@ and 2nd order context modeling, with a compression ratio comparable to the best
|
||||
currently available general-purpose compression methods. It is similar in speed
|
||||
with deflate but offers more dense compression.
|
||||
|
||||
The specification of the Brotli Compressed Data Format is defined in [RFC 7932](https://tools.ietf.org/html/rfc7932).
|
||||
The specification of the Brotli Compressed Data Format is defined in
|
||||
[RFC 7932](https://datatracker.ietf.org/doc/html/rfc7932).
|
||||
|
||||
Brotli is open-sourced under the MIT License, see the LICENSE file.
|
||||
|
||||
Brotli mailing list:
|
||||
https://groups.google.com/forum/#!forum/brotli
|
||||
> **Please note:** brotli is a "stream" format; it does not contain
|
||||
> meta-information, like checksums or uncompressed data length. It is possible
|
||||
> to modify "raw" ranges of the compressed stream and the decoder will not
|
||||
> notice that.
|
||||
|
||||
[](https://travis-ci.org/google/brotli)
|
||||
[](https://ci.appveyor.com/project/szabadka/brotli)
|
||||
### Installation
|
||||
|
||||
In most Linux distributions, installing `brotli` is just a matter of using
|
||||
the package management system. For example in Debian-based distributions:
|
||||
`apt install brotli` will install `brotli`. On MacOS, you can use
|
||||
[Homebrew](https://brew.sh/): `brew install brotli`.
|
||||
|
||||
[](https://repology.org/project/brotli/versions)
|
||||
|
||||
Of course you can also build brotli from sources.
|
||||
|
||||
### Build instructions
|
||||
|
||||
#### Autotools-style CMake
|
||||
#### Vcpkg
|
||||
|
||||
[configure-cmake](https://github.com/nemequ/configure-cmake) is an
|
||||
autotools-style configure script for CMake-based projects (not supported on Windows).
|
||||
You can download and install brotli using the
|
||||
[vcpkg](https://github.com/Microsoft/vcpkg/) dependency manager:
|
||||
|
||||
The basic commands to build, test and install brotli are:
|
||||
git clone https://github.com/Microsoft/vcpkg.git
|
||||
cd vcpkg
|
||||
./bootstrap-vcpkg.sh
|
||||
./vcpkg integrate install
|
||||
./vcpkg install brotli
|
||||
|
||||
$ mkdir out && cd out
|
||||
$ ../configure-cmake
|
||||
$ make
|
||||
$ make test
|
||||
$ make install
|
||||
|
||||
By default, debug binaries are built. To generate "release" `Makefile` specify `--disable-debug` option to `configure-cmake`.
|
||||
The brotli port in vcpkg is kept up to date by Microsoft team members and
|
||||
community contributors. If the version is out of date, please [create an issue
|
||||
or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository.
|
||||
|
||||
#### Bazel
|
||||
|
||||
See [Bazel](http://www.bazel.build/)
|
||||
See [Bazel](https://www.bazel.build/)
|
||||
|
||||
#### CMake
|
||||
|
||||
@@ -49,10 +64,6 @@ The basic commands to build and install brotli are:
|
||||
|
||||
You can use other [CMake](https://cmake.org/) configuration.
|
||||
|
||||
#### Premake5
|
||||
|
||||
See [Premake5](https://premake.github.io/)
|
||||
|
||||
#### Python
|
||||
|
||||
To install the latest release of the Python module, run the following:
|
||||
@@ -66,20 +77,38 @@ To install the tip-of-the-tree version, run:
|
||||
See the [Python readme](python/README.md) for more details on installing
|
||||
from source, development, and testing.
|
||||
|
||||
### Contributing
|
||||
|
||||
We glad to answer/library related questions in
|
||||
[brotli mailing list](https://groups.google.com/g/brotli).
|
||||
|
||||
Regular issues / feature requests should be reported in
|
||||
[issue tracker](https://github.com/google/brotli/issues).
|
||||
|
||||
For reporting vulnerability please read [SECURITY](SECURITY.md).
|
||||
|
||||
For contributing changes please read [CONTRIBUTING](CONTRIBUTING.md).
|
||||
|
||||
### Benchmarks
|
||||
* [Squash Compression Benchmark](https://quixdb.github.io/squash-benchmark/) / [Unstable Squash Compression Benchmark](https://quixdb.github.io/squash-benchmark/unstable/)
|
||||
* [Large Text Compression Benchmark](http://mattmahoney.net/dc/text.html)
|
||||
* [Large Text Compression Benchmark](https://mattmahoney.net/dc/text.html)
|
||||
* [Lzturbo Benchmark](https://sites.google.com/site/powturbo/home/benchmark)
|
||||
|
||||
### Related projects
|
||||
> **Disclaimer:** Brotli authors take no responsibility for the third party projects mentioned in this section.
|
||||
|
||||
Independent [decoder](https://github.com/madler/brotli) implementation by Mark Adler, based entirely on format specification.
|
||||
Independent [decoder](https://github.com/madler/brotli) implementation
|
||||
by Mark Adler, based entirely on format specification.
|
||||
|
||||
JavaScript port of brotli [decoder](https://github.com/devongovett/brotli.js). Could be used directly via `npm install brotli`
|
||||
JavaScript port of brotli [decoder](https://github.com/devongovett/brotli.js).
|
||||
Could be used directly via `npm install brotli`
|
||||
|
||||
Hand ported [decoder / encoder](https://github.com/dominikhlbg/BrotliHaxe) in haxe by Dominik Homberger. Output source code: JavaScript, PHP, Python, Java and C#
|
||||
Hand ported [decoder / encoder](https://github.com/dominikhlbg/BrotliHaxe)
|
||||
in haxe by Dominik Homberger.
|
||||
Output source code: JavaScript, PHP, Python, Java and C#
|
||||
|
||||
7Zip [plugin](https://github.com/mcmilk/7-Zip-Zstd)
|
||||
|
||||
Dart [native bindings](https://github.com/thosakwe/brotli)
|
||||
Dart compression framework with
|
||||
[fast FFI-based Brotli implementation](https://pub.dev/documentation/es_compression/latest/brotli/)
|
||||
with ready-to-use prebuilt binaries for Win/Linux/Mac
|
||||
|
||||
6
SECURITY.md
Normal file
6
SECURITY.md
Normal file
@@ -0,0 +1,6 @@
|
||||
### Reporting
|
||||
|
||||
To report a security issue, please use [https://g.co/vulnz](https://g.co/vulnz).
|
||||
We use g.co/vulnz for our intake, and do coordination and disclosure here on
|
||||
GitHub (including using GitHub Security Advisory). The Google Security Team will
|
||||
respond within 5 working days of your report on g.co/vulnz.
|
||||
21
WORKSPACE
21
WORKSPACE
@@ -1,21 +0,0 @@
|
||||
workspace(name = "org_brotli")
|
||||
|
||||
local_repository(
|
||||
name = "ignore_org_brotli_go",
|
||||
path = "go",
|
||||
)
|
||||
|
||||
local_repository(
|
||||
name = "ignore_org_brotli_java",
|
||||
path = "java",
|
||||
)
|
||||
|
||||
local_repository(
|
||||
name = "ignore_org_brotli_js",
|
||||
path = "js",
|
||||
)
|
||||
|
||||
local_repository(
|
||||
name = "ignore_org_brotli_research",
|
||||
path = "research",
|
||||
)
|
||||
31
bootstrap
31
bootstrap
@@ -1,31 +0,0 @@
|
||||
# !/bin/sh -e
|
||||
|
||||
REQUIRED='is required, but not installed.'
|
||||
bc -v >/dev/null 2>&1 || { echo >&2 "'bc' $REQUIRED"; exit 1; }
|
||||
if [ `uname -s` != "FreeBSD" ]; then
|
||||
sed --version >/dev/null 2>&1 || { echo >&2 "'sed' $REQUIRED"; exit 1; }
|
||||
fi
|
||||
autoreconf --version >/dev/null 2>&1 || { echo >&2 "'autoconf' $REQUIRED"; exit 1; }
|
||||
|
||||
# If libtool is not installed -> "error: Libtool library used but 'LIBTOOL' is undefined"
|
||||
|
||||
mkdir m4 2>/dev/null
|
||||
|
||||
BROTLI_ABI_HEX=`sed -n 's/#define BROTLI_ABI_VERSION 0x//p' c/common/version.h`
|
||||
BROTLI_ABI_INT=`echo "ibase=16;$BROTLI_ABI_HEX" | bc`
|
||||
BROTLI_ABI_CURRENT=`expr $BROTLI_ABI_INT / 16777216`
|
||||
BROTLI_ABI_REVISION=`expr $BROTLI_ABI_INT / 4096 % 4096`
|
||||
BROTLI_ABI_AGE=`expr $BROTLI_ABI_INT % 4096`
|
||||
BROTLI_ABI_INFO="$BROTLI_ABI_CURRENT:$BROTLI_ABI_REVISION:$BROTLI_ABI_AGE"
|
||||
|
||||
BROTLI_VERSION_HEX=`sed -n 's/#define BROTLI_VERSION 0x//p' c/common/version.h`
|
||||
BROTLI_VERSION_INT=`echo "ibase=16;$BROTLI_VERSION_HEX" | bc`
|
||||
BROTLI_VERSION_MAJOR=`expr $BROTLI_VERSION_INT / 16777216`
|
||||
BROTLI_VERSION_MINOR=`expr $BROTLI_VERSION_INT / 4096 % 4096`
|
||||
BROTLI_VERSION_PATCH=`expr $BROTLI_VERSION_INT % 4096`
|
||||
BROTLI_VERSION="$BROTLI_VERSION_MAJOR.$BROTLI_VERSION_MINOR.$BROTLI_VERSION_PATCH"
|
||||
|
||||
sed -i.bak -r "s/[0-9]+:[0-9]+:[0-9]+/$BROTLI_ABI_INFO/" Makefile.am
|
||||
sed -i.bak -r "s/\[[0-9]+\.[0-9]+\.[0-9]+\]/[$BROTLI_VERSION]/" configure.ac
|
||||
|
||||
autoreconf --install --force --symlink || exit $
|
||||
15
c/common/constants.c
Normal file
15
c/common/constants.c
Normal file
@@ -0,0 +1,15 @@
|
||||
/* Copyright 2013 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "constants.h"
|
||||
|
||||
const BROTLI_MODEL("small")
|
||||
BrotliPrefixCodeRange _kBrotliPrefixCodeRanges[BROTLI_NUM_BLOCK_LEN_SYMBOLS] = {
|
||||
{1, 2}, {5, 2}, {9, 2}, {13, 2}, {17, 3}, {25, 3},
|
||||
{33, 3}, {41, 3}, {49, 4}, {65, 4}, {81, 4}, {97, 4},
|
||||
{113, 5}, {145, 5}, {177, 5}, {209, 5}, {241, 6}, {305, 6},
|
||||
{369, 7}, {497, 8}, {753, 9}, {1265, 10}, {2289, 11}, {4337, 12},
|
||||
{8433, 13}, {16625, 24}};
|
||||
@@ -4,9 +4,16 @@
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Common constants used in decoder and encoder API.
|
||||
*/
|
||||
|
||||
#ifndef BROTLI_COMMON_CONSTANTS_H_
|
||||
#define BROTLI_COMMON_CONSTANTS_H_
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
/* Specification: 7.3. Encoding of the context map */
|
||||
#define BROTLI_CONTEXT_MAP_MAX_RLE 16
|
||||
|
||||
@@ -29,12 +36,31 @@
|
||||
#define BROTLI_INITIAL_REPEATED_CODE_LENGTH 8
|
||||
|
||||
/* "Large Window Brotli" */
|
||||
|
||||
/**
|
||||
* The theoretical maximum number of distance bits specified for large window
|
||||
* brotli, for 64-bit encoders and decoders. Even when in practice 32-bit
|
||||
* encoders and decoders only support up to 30 max distance bits, the value is
|
||||
* set to 62 because it affects the large window brotli file format.
|
||||
* Specifically, it affects the encoding of simple huffman tree for distances,
|
||||
* see Specification RFC 7932 chapter 3.4.
|
||||
*/
|
||||
#define BROTLI_LARGE_MAX_DISTANCE_BITS 62U
|
||||
#define BROTLI_LARGE_MIN_WBITS 10
|
||||
/**
|
||||
* The maximum supported large brotli window bits by the encoder and decoder.
|
||||
* Large window brotli allows up to 62 bits, however the current encoder and
|
||||
* decoder, designed for 32-bit integers, only support up to 30 bits maximum.
|
||||
*/
|
||||
#define BROTLI_LARGE_MAX_WBITS 30
|
||||
|
||||
/* Specification: 4. Encoding of distances */
|
||||
#define BROTLI_NUM_DISTANCE_SHORT_CODES 16
|
||||
/**
|
||||
* Maximal number of "postfix" bits.
|
||||
*
|
||||
* Number of "postfix" bits is stored as 2 bits in meta-block header.
|
||||
*/
|
||||
#define BROTLI_MAX_NPOSTFIX 3
|
||||
#define BROTLI_MAX_NDIRECT 120
|
||||
#define BROTLI_MAX_DISTANCE_BITS 24U
|
||||
@@ -45,9 +71,22 @@
|
||||
#define BROTLI_NUM_DISTANCE_SYMBOLS \
|
||||
BROTLI_DISTANCE_ALPHABET_SIZE( \
|
||||
BROTLI_MAX_NDIRECT, BROTLI_MAX_NPOSTFIX, BROTLI_LARGE_MAX_DISTANCE_BITS)
|
||||
|
||||
/* ((1 << 26) - 4) is the maximal distance that can be expressed in RFC 7932
|
||||
brotli stream using NPOSTFIX = 0 and NDIRECT = 0. With other NPOSTFIX and
|
||||
NDIRECT values distances up to ((1 << 29) + 88) could be expressed. */
|
||||
#define BROTLI_MAX_DISTANCE 0x3FFFFFC
|
||||
|
||||
/* ((1 << 31) - 4) is the safe distance limit. Using this number as a limit
|
||||
allows safe distance calculation without overflows, given the distance
|
||||
alphabet size is limited to corresponding size
|
||||
(see kLargeWindowDistanceCodeLimits). */
|
||||
#define BROTLI_MAX_ALLOWED_DISTANCE 0x7FFFFFFC
|
||||
|
||||
|
||||
/* Specification: 4. Encoding of Literal Insertion Lengths and Copy Lengths */
|
||||
#define BROTLI_NUM_INS_COPY_CODES 24
|
||||
|
||||
/* 7.1. Context modes and context ID lookup for literals */
|
||||
/* "context IDs for literals are in the range of 0..63" */
|
||||
#define BROTLI_LITERAL_CONTEXT_BITS 6
|
||||
@@ -61,4 +100,99 @@
|
||||
#define BROTLI_WINDOW_GAP 16
|
||||
#define BROTLI_MAX_BACKWARD_LIMIT(W) (((size_t)1 << (W)) - BROTLI_WINDOW_GAP)
|
||||
|
||||
typedef struct BrotliDistanceCodeLimit {
|
||||
uint32_t max_alphabet_size;
|
||||
uint32_t max_distance;
|
||||
} BrotliDistanceCodeLimit;
|
||||
|
||||
/* This function calculates maximal size of distance alphabet, such that the
|
||||
distances greater than the given values can not be represented.
|
||||
|
||||
This limits are designed to support fast and safe 32-bit decoders.
|
||||
"32-bit" means that signed integer values up to ((1 << 31) - 1) could be
|
||||
safely expressed.
|
||||
|
||||
Brotli distance alphabet symbols do not represent consecutive distance
|
||||
ranges. Each distance alphabet symbol (excluding direct distances and short
|
||||
codes), represent interleaved (for NPOSTFIX > 0) range of distances.
|
||||
A "group" of consecutive (1 << NPOSTFIX) symbols represent non-interleaved
|
||||
range. Two consecutive groups require the same amount of "extra bits".
|
||||
|
||||
It is important that distance alphabet represents complete "groups".
|
||||
To avoid complex logic on encoder side about interleaved ranges
|
||||
it was decided to restrict both sides to complete distance code "groups".
|
||||
*/
|
||||
BROTLI_UNUSED_FUNCTION BrotliDistanceCodeLimit BrotliCalculateDistanceCodeLimit(
|
||||
uint32_t max_distance, uint32_t npostfix, uint32_t ndirect) {
|
||||
BrotliDistanceCodeLimit result;
|
||||
/* Marking this function as unused, because not all files
|
||||
including "constants.h" use it -> compiler warns about that. */
|
||||
BROTLI_UNUSED(&BrotliCalculateDistanceCodeLimit);
|
||||
if (max_distance <= ndirect) {
|
||||
/* This case never happens / exists only for the sake of completeness. */
|
||||
result.max_alphabet_size = max_distance + BROTLI_NUM_DISTANCE_SHORT_CODES;
|
||||
result.max_distance = max_distance;
|
||||
return result;
|
||||
} else {
|
||||
/* The first prohibited value. */
|
||||
uint32_t forbidden_distance = max_distance + 1;
|
||||
/* Subtract "directly" encoded region. */
|
||||
uint32_t offset = forbidden_distance - ndirect - 1;
|
||||
uint32_t ndistbits = 0;
|
||||
uint32_t tmp;
|
||||
uint32_t half;
|
||||
uint32_t group;
|
||||
/* Postfix for the last dcode in the group. */
|
||||
uint32_t postfix = (1u << npostfix) - 1;
|
||||
uint32_t extra;
|
||||
uint32_t start;
|
||||
/* Remove postfix and "head-start". */
|
||||
offset = (offset >> npostfix) + 4;
|
||||
/* Calculate the number of distance bits. */
|
||||
tmp = offset / 2;
|
||||
/* Poor-man's log2floor, to avoid extra dependencies. */
|
||||
while (tmp != 0) {ndistbits++; tmp = tmp >> 1;}
|
||||
/* One bit is covered with subrange addressing ("half"). */
|
||||
ndistbits--;
|
||||
/* Find subrange. */
|
||||
half = (offset >> ndistbits) & 1;
|
||||
/* Calculate the "group" part of dcode. */
|
||||
group = ((ndistbits - 1) << 1) | half;
|
||||
/* Calculated "group" covers the prohibited distance value. */
|
||||
if (group == 0) {
|
||||
/* This case is added for correctness; does not occur for limit > 128. */
|
||||
result.max_alphabet_size = ndirect + BROTLI_NUM_DISTANCE_SHORT_CODES;
|
||||
result.max_distance = ndirect;
|
||||
return result;
|
||||
}
|
||||
/* Decrement "group", so it is the last permitted "group". */
|
||||
group--;
|
||||
/* After group was decremented, ndistbits and half must be recalculated. */
|
||||
ndistbits = (group >> 1) + 1;
|
||||
/* The last available distance in the subrange has all extra bits set. */
|
||||
extra = (1u << ndistbits) - 1;
|
||||
/* Calculate region start. NB: ndistbits >= 1. */
|
||||
start = (1u << (ndistbits + 1)) - 4;
|
||||
/* Move to subregion. */
|
||||
start += (group & 1) << ndistbits;
|
||||
/* Calculate the alphabet size. */
|
||||
result.max_alphabet_size = ((group << npostfix) | postfix) + ndirect +
|
||||
BROTLI_NUM_DISTANCE_SHORT_CODES + 1;
|
||||
/* Calculate the maximal distance representable by alphabet. */
|
||||
result.max_distance = ((start + extra) << npostfix) + postfix + ndirect + 1;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/* Represents the range of values belonging to a prefix code:
|
||||
[offset, offset + 2^nbits) */
|
||||
typedef struct {
|
||||
uint16_t offset;
|
||||
uint8_t nbits;
|
||||
} BrotliPrefixCodeRange;
|
||||
|
||||
/* "Soft-private", it is exported, but not "advertised" as API. */
|
||||
BROTLI_COMMON_API extern const BROTLI_MODEL("small")
|
||||
BrotliPrefixCodeRange _kBrotliPrefixCodeRanges[BROTLI_NUM_BLOCK_LEN_SYMBOLS];
|
||||
|
||||
#endif /* BROTLI_COMMON_CONSTANTS_H_ */
|
||||
|
||||
156
c/common/context.c
Normal file
156
c/common/context.c
Normal file
@@ -0,0 +1,156 @@
|
||||
#include "context.h"
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
/* Common context lookup table for all context modes. */
|
||||
const BROTLI_MODEL("small") uint8_t _kBrotliContextLookupTable[2048] = {
|
||||
/* CONTEXT_LSB6, last byte. */
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
||||
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
|
||||
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
||||
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
|
||||
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
||||
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
|
||||
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
||||
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
|
||||
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
|
||||
|
||||
/* CONTEXT_LSB6, second last byte, */
|
||||
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, 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, 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, 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, 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,
|
||||
|
||||
/* CONTEXT_MSB6, last byte. */
|
||||
0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,
|
||||
4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7,
|
||||
8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11,
|
||||
12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15,
|
||||
16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19,
|
||||
20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23,
|
||||
24, 24, 24, 24, 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27,
|
||||
28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31,
|
||||
32, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 34, 35, 35, 35, 35,
|
||||
36, 36, 36, 36, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39,
|
||||
40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43,
|
||||
44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47,
|
||||
48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 51, 51, 51, 51,
|
||||
52, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54, 54, 55, 55, 55, 55,
|
||||
56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59,
|
||||
60, 60, 60, 60, 61, 61, 61, 61, 62, 62, 62, 62, 63, 63, 63, 63,
|
||||
|
||||
/* CONTEXT_MSB6, second last byte, */
|
||||
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, 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, 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, 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, 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,
|
||||
|
||||
/* CONTEXT_UTF8, last byte. */
|
||||
/* ASCII range. */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 0, 4, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
8, 12, 16, 12, 12, 20, 12, 16, 24, 28, 12, 12, 32, 12, 36, 12,
|
||||
44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 32, 32, 24, 40, 28, 12,
|
||||
12, 48, 52, 52, 52, 48, 52, 52, 52, 48, 52, 52, 52, 52, 52, 48,
|
||||
52, 52, 52, 52, 52, 48, 52, 52, 52, 52, 52, 24, 12, 28, 12, 12,
|
||||
12, 56, 60, 60, 60, 56, 60, 60, 60, 56, 60, 60, 60, 60, 60, 56,
|
||||
60, 60, 60, 60, 60, 56, 60, 60, 60, 60, 60, 24, 12, 28, 12, 0,
|
||||
/* UTF8 continuation byte range. */
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
/* UTF8 lead byte range. */
|
||||
2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
|
||||
2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
|
||||
2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
|
||||
2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
|
||||
|
||||
/* CONTEXT_UTF8 second last byte. */
|
||||
/* ASCII range. */
|
||||
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, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1,
|
||||
1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1,
|
||||
1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 0,
|
||||
/* UTF8 continuation byte range. */
|
||||
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, 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,
|
||||
/* UTF8 lead byte range. */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
|
||||
/* CONTEXT_SIGNED, last byte, same as the above values shifted by 3 bits. */
|
||||
0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
||||
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
|
||||
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
|
||||
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
|
||||
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
|
||||
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
|
||||
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
|
||||
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
|
||||
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
|
||||
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
|
||||
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
|
||||
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
|
||||
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
|
||||
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
|
||||
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
|
||||
48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 56,
|
||||
|
||||
/* CONTEXT_SIGNED, second last byte. */
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 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, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7,
|
||||
};
|
||||
157
c/common/context.h
Executable file → Normal file
157
c/common/context.h
Executable file → Normal file
@@ -88,7 +88,7 @@
|
||||
#ifndef BROTLI_COMMON_CONTEXT_H_
|
||||
#define BROTLI_COMMON_CONTEXT_H_
|
||||
|
||||
#include <brotli/types.h>
|
||||
#include "platform.h"
|
||||
|
||||
typedef enum ContextType {
|
||||
CONTEXT_LSB6 = 0,
|
||||
@@ -97,163 +97,14 @@ typedef enum ContextType {
|
||||
CONTEXT_SIGNED = 3
|
||||
} ContextType;
|
||||
|
||||
/* "Soft-private", it is exported, but not "advertised" as API. */
|
||||
/* Common context lookup table for all context modes. */
|
||||
static const uint8_t kContextLookup[2048] = {
|
||||
/* CONTEXT_LSB6, last byte. */
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
||||
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
|
||||
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
||||
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
|
||||
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
||||
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
|
||||
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
||||
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
|
||||
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
|
||||
|
||||
/* CONTEXT_LSB6, second last byte, */
|
||||
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, 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, 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, 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, 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,
|
||||
|
||||
/* CONTEXT_MSB6, last byte. */
|
||||
0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,
|
||||
4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7,
|
||||
8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11,
|
||||
12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15,
|
||||
16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19,
|
||||
20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23,
|
||||
24, 24, 24, 24, 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27,
|
||||
28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31,
|
||||
32, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 34, 35, 35, 35, 35,
|
||||
36, 36, 36, 36, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39,
|
||||
40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43,
|
||||
44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47,
|
||||
48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 51, 51, 51, 51,
|
||||
52, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54, 54, 55, 55, 55, 55,
|
||||
56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59,
|
||||
60, 60, 60, 60, 61, 61, 61, 61, 62, 62, 62, 62, 63, 63, 63, 63,
|
||||
|
||||
/* CONTEXT_MSB6, second last byte, */
|
||||
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, 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, 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, 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, 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,
|
||||
|
||||
/* CONTEXT_UTF8, last byte. */
|
||||
/* ASCII range. */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 0, 4, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
8, 12, 16, 12, 12, 20, 12, 16, 24, 28, 12, 12, 32, 12, 36, 12,
|
||||
44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 32, 32, 24, 40, 28, 12,
|
||||
12, 48, 52, 52, 52, 48, 52, 52, 52, 48, 52, 52, 52, 52, 52, 48,
|
||||
52, 52, 52, 52, 52, 48, 52, 52, 52, 52, 52, 24, 12, 28, 12, 12,
|
||||
12, 56, 60, 60, 60, 56, 60, 60, 60, 56, 60, 60, 60, 60, 60, 56,
|
||||
60, 60, 60, 60, 60, 56, 60, 60, 60, 60, 60, 24, 12, 28, 12, 0,
|
||||
/* UTF8 continuation byte range. */
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
/* UTF8 lead byte range. */
|
||||
2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
|
||||
2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
|
||||
2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
|
||||
2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
|
||||
|
||||
/* CONTEXT_UTF8 second last byte. */
|
||||
/* ASCII range. */
|
||||
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, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1,
|
||||
1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1,
|
||||
1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 0,
|
||||
/* UTF8 continuation byte range. */
|
||||
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, 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,
|
||||
/* UTF8 lead byte range. */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
|
||||
/* CONTEXT_SIGNED, last byte, same as the above values shifted by 3 bits. */
|
||||
0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
||||
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
|
||||
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
|
||||
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
|
||||
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
|
||||
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
|
||||
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
|
||||
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
|
||||
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
|
||||
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
|
||||
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
|
||||
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
|
||||
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
|
||||
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
|
||||
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
|
||||
48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 56,
|
||||
|
||||
/* CONTEXT_SIGNED, second last byte. */
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 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, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7,
|
||||
};
|
||||
BROTLI_COMMON_API extern const uint8_t _kBrotliContextLookupTable[2048];
|
||||
|
||||
typedef const uint8_t* ContextLut;
|
||||
|
||||
/* typeof(MODE) == ContextType; returns ContextLut */
|
||||
#define BROTLI_CONTEXT_LUT(MODE) (&kContextLookup[(MODE) << 9])
|
||||
#define BROTLI_CONTEXT_LUT(MODE) (&_kBrotliContextLookupTable[(MODE) << 9])
|
||||
|
||||
/* typeof(LUT) == ContextLut */
|
||||
#define BROTLI_CONTEXT(P1, P2, LUT) ((LUT)[P1] | ((LUT) + 256)[P2])
|
||||
|
||||
0
c/common/dictionary.bin.br
Executable file → Normal file
0
c/common/dictionary.bin.br
Executable file → Normal file
File diff suppressed because it is too large
Load Diff
@@ -9,8 +9,7 @@
|
||||
#ifndef BROTLI_COMMON_DICTIONARY_H_
|
||||
#define BROTLI_COMMON_DICTIONARY_H_
|
||||
|
||||
#include <brotli/port.h>
|
||||
#include <brotli/types.h>
|
||||
#include "platform.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
|
||||
5847
c/common/dictionary_inc.h
Normal file
5847
c/common/dictionary_inc.h
Normal file
File diff suppressed because it is too large
Load Diff
19
c/common/platform.c
Normal file
19
c/common/platform.c
Normal file
@@ -0,0 +1,19 @@
|
||||
/* Copyright 2016 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
/* Default brotli_alloc_func */
|
||||
void* BrotliDefaultAllocFunc(void* opaque, size_t size) {
|
||||
BROTLI_UNUSED(opaque);
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
/* Default brotli_free_func */
|
||||
void BrotliDefaultFreeFunc(void* opaque, void* address) {
|
||||
BROTLI_UNUSED(opaque);
|
||||
free(address);
|
||||
}
|
||||
436
c/common/platform.h
Executable file → Normal file
436
c/common/platform.h
Executable file → Normal file
@@ -12,33 +12,27 @@
|
||||
* BROTLI_BUILD_BIG_ENDIAN forces to use big-endian optimizations
|
||||
* BROTLI_BUILD_ENDIAN_NEUTRAL disables endian-aware optimizations
|
||||
* BROTLI_BUILD_LITTLE_ENDIAN forces to use little-endian optimizations
|
||||
* BROTLI_BUILD_PORTABLE disables dangerous optimizations, like unaligned
|
||||
read and overlapping memcpy; this reduces decompression speed by 5%
|
||||
* BROTLI_BUILD_NO_RBIT disables "rbit" optimization for ARM CPUs
|
||||
* BROTLI_BUILD_NO_UNALIGNED_READ_FAST forces off the fast-unaligned-read
|
||||
optimizations (mainly for testing purposes)
|
||||
* BROTLI_DEBUG dumps file name and line number when decoder detects stream
|
||||
or memory error
|
||||
* BROTLI_ENABLE_LOG enables asserts and dumps various state information
|
||||
* BROTLI_ENABLE_DUMP overrides default "dump" behaviour
|
||||
*/
|
||||
|
||||
#ifndef BROTLI_COMMON_PLATFORM_H_
|
||||
#define BROTLI_COMMON_PLATFORM_H_
|
||||
|
||||
#include <string.h> /* memcpy */
|
||||
#include <stdlib.h> /* malloc, free */
|
||||
#include <string.h> /* IWYU pragma: export memcmp, memcpy, memset */
|
||||
#include <stdlib.h> /* IWYU pragma: export exit, free, malloc */
|
||||
#include <sys/types.h> /* should include endian.h for us */
|
||||
|
||||
#include <brotli/port.h>
|
||||
#include <brotli/types.h>
|
||||
#include <brotli/port.h> /* IWYU pragma: export */
|
||||
#include <brotli/types.h> /* IWYU pragma: export */
|
||||
|
||||
#if defined(OS_LINUX) || defined(OS_CYGWIN)
|
||||
#include <endian.h>
|
||||
#elif defined(OS_FREEBSD)
|
||||
#include <machine/endian.h>
|
||||
#elif defined(OS_MACOSX)
|
||||
#include <machine/endian.h>
|
||||
/* Let's try and follow the Linux convention */
|
||||
#define BROTLI_X_BYTE_ORDER BYTE_ORDER
|
||||
#define BROTLI_X_LITTLE_ENDIAN LITTLE_ENDIAN
|
||||
#define BROTLI_X_BIG_ENDIAN BIG_ENDIAN
|
||||
#if BROTLI_MSVC_VERSION_CHECK(18, 0, 0)
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
#if defined(BROTLI_ENABLE_LOG) || defined(BROTLI_DEBUG)
|
||||
@@ -71,7 +65,7 @@ OR:
|
||||
*/
|
||||
#if BROTLI_GNUC_HAS_BUILTIN(__builtin_expect, 3, 0, 0) || \
|
||||
BROTLI_INTEL_VERSION_CHECK(16, 0, 0) || \
|
||||
BROTLI_SUNPRO_VERSION_CHECK(5, 12, 0) || \
|
||||
BROTLI_SUNPRO_VERSION_CHECK(5, 15, 0) || \
|
||||
BROTLI_ARM_VERSION_CHECK(4, 1, 0) || \
|
||||
BROTLI_IBM_VERSION_CHECK(10, 1, 0) || \
|
||||
BROTLI_TI_VERSION_CHECK(7, 3, 0) || \
|
||||
@@ -153,24 +147,6 @@ OR:
|
||||
#define BROTLI_NOINLINE
|
||||
#endif
|
||||
|
||||
/* BROTLI_INTERNAL could be defined to override visibility, e.g. for tests. */
|
||||
#if !defined(BROTLI_INTERNAL)
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
#define BROTLI_INTERNAL
|
||||
#elif BROTLI_GNUC_VERSION_CHECK(3, 3, 0) || \
|
||||
BROTLI_TI_VERSION_CHECK(8, 0, 0) || \
|
||||
BROTLI_INTEL_VERSION_CHECK(16, 0, 0) || \
|
||||
BROTLI_ARM_VERSION_CHECK(4, 1, 0) || \
|
||||
BROTLI_IBM_VERSION_CHECK(13, 1, 0) || \
|
||||
BROTLI_SUNPRO_VERSION_CHECK(5, 11, 0) || \
|
||||
(BROTLI_TI_VERSION_CHECK(7, 3, 0) && \
|
||||
defined(__TI_GNU_ATTRIBUTE_SUPPORT__) && defined(__TI_EABI__))
|
||||
#define BROTLI_INTERNAL __attribute__ ((visibility ("hidden")))
|
||||
#else
|
||||
#define BROTLI_INTERNAL
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* <<< <<< <<< end of hedley macros. */
|
||||
|
||||
#if BROTLI_GNUC_HAS_ATTRIBUTE(unused, 2, 7, 0) || \
|
||||
@@ -180,6 +156,12 @@ OR:
|
||||
#define BROTLI_UNUSED_FUNCTION static BROTLI_INLINE
|
||||
#endif
|
||||
|
||||
#if BROTLI_GNUC_HAS_ATTRIBUTE(aligned, 2, 7, 0)
|
||||
#define BROTLI_ALIGNED(N) __attribute__((aligned(N)))
|
||||
#else
|
||||
#define BROTLI_ALIGNED(N)
|
||||
#endif
|
||||
|
||||
#if (defined(__ARM_ARCH) && (__ARM_ARCH == 7)) || \
|
||||
(defined(M_ARM) && (M_ARM == 7))
|
||||
#define BROTLI_TARGET_ARMV7
|
||||
@@ -197,6 +179,10 @@ OR:
|
||||
|
||||
#endif /* ARMv8 */
|
||||
|
||||
#if defined(__ARM_NEON__) || defined(__ARM_NEON)
|
||||
#define BROTLI_TARGET_NEON
|
||||
#endif
|
||||
|
||||
#if defined(__i386) || defined(_M_IX86)
|
||||
#define BROTLI_TARGET_X86
|
||||
#endif
|
||||
@@ -213,15 +199,34 @@ OR:
|
||||
#define BROTLI_TARGET_RISCV64
|
||||
#endif
|
||||
|
||||
#if defined(__loongarch_lp64)
|
||||
#define BROTLI_TARGET_LOONGARCH64
|
||||
#endif
|
||||
|
||||
/* This does not seem to be an indicator of z/Architecture (64-bit); neither
|
||||
that allows to use unaligned loads. */
|
||||
#if defined(__s390x__)
|
||||
#define BROTLI_TARGET_S390X
|
||||
#endif
|
||||
|
||||
#if defined(__mips64)
|
||||
#define BROTLI_TARGET_MIPS64
|
||||
#endif
|
||||
|
||||
#if defined(BROTLI_TARGET_X64) || defined(BROTLI_TARGET_ARMV8_64) || \
|
||||
defined(BROTLI_TARGET_POWERPC64) || defined(BROTLI_TARGET_RISCV64) || \
|
||||
defined(BROTLI_TARGET_LOONGARCH64) || defined(BROTLI_TARGET_MIPS64)
|
||||
#define BROTLI_TARGET_64_BITS 1
|
||||
#else
|
||||
#define BROTLI_TARGET_64_BITS 0
|
||||
#endif
|
||||
|
||||
#if defined(BROTLI_BUILD_64_BIT)
|
||||
#define BROTLI_64_BITS 1
|
||||
#elif defined(BROTLI_BUILD_32_BIT)
|
||||
#define BROTLI_64_BITS 0
|
||||
#elif defined(BROTLI_TARGET_X64) || defined(BROTLI_TARGET_ARMV8_64) || \
|
||||
defined(BROTLI_TARGET_POWERPC64) || defined(BROTLI_TARGET_RISCV64)
|
||||
#define BROTLI_64_BITS 1
|
||||
#else
|
||||
#define BROTLI_64_BITS 0
|
||||
#define BROTLI_64_BITS BROTLI_TARGET_64_BITS
|
||||
#endif
|
||||
|
||||
#if (BROTLI_64_BITS)
|
||||
@@ -243,13 +248,12 @@ OR:
|
||||
#define BROTLI_LITTLE_ENDIAN 1
|
||||
#elif defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
|
||||
#define BROTLI_BIG_ENDIAN 1
|
||||
#elif defined(BROTLI_X_BYTE_ORDER)
|
||||
#if BROTLI_X_BYTE_ORDER == BROTLI_X_LITTLE_ENDIAN
|
||||
/* Likely target platform is iOS / OSX. */
|
||||
#elif defined(BYTE_ORDER) && (BYTE_ORDER == LITTLE_ENDIAN)
|
||||
#define BROTLI_LITTLE_ENDIAN 1
|
||||
#elif BROTLI_X_BYTE_ORDER == BROTLI_X_BIG_ENDIAN
|
||||
#elif defined(BYTE_ORDER) && (BYTE_ORDER == BIG_ENDIAN)
|
||||
#define BROTLI_BIG_ENDIAN 1
|
||||
#endif
|
||||
#endif /* BROTLI_X_BYTE_ORDER */
|
||||
|
||||
#if !defined(BROTLI_LITTLE_ENDIAN)
|
||||
#define BROTLI_LITTLE_ENDIAN 0
|
||||
@@ -259,25 +263,60 @@ OR:
|
||||
#define BROTLI_BIG_ENDIAN 0
|
||||
#endif
|
||||
|
||||
#if defined(BROTLI_X_BYTE_ORDER)
|
||||
#undef BROTLI_X_BYTE_ORDER
|
||||
#undef BROTLI_X_LITTLE_ENDIAN
|
||||
#undef BROTLI_X_BIG_ENDIAN
|
||||
#endif
|
||||
|
||||
#if defined(BROTLI_BUILD_PORTABLE)
|
||||
#define BROTLI_ALIGNED_READ (!!1)
|
||||
#elif defined(BROTLI_TARGET_X86) || defined(BROTLI_TARGET_X64) || \
|
||||
#if defined(BROTLI_BUILD_NO_UNALIGNED_READ_FAST)
|
||||
#define BROTLI_UNALIGNED_READ_FAST (!!0)
|
||||
#elif defined(BROTLI_TARGET_X86) || defined(BROTLI_TARGET_X64) || \
|
||||
defined(BROTLI_TARGET_ARMV7) || defined(BROTLI_TARGET_ARMV8_ANY) || \
|
||||
defined(BROTLI_TARGET_RISCV64)
|
||||
/* Allow unaligned read only for white-listed CPUs. */
|
||||
#define BROTLI_ALIGNED_READ (!!0)
|
||||
defined(BROTLI_TARGET_RISCV64) || defined(BROTLI_TARGET_LOONGARCH64)
|
||||
/* These targets are known to generate efficient code for unaligned reads
|
||||
* (e.g. a single instruction, not multiple 1-byte loads, shifted and or'd
|
||||
* together). */
|
||||
#define BROTLI_UNALIGNED_READ_FAST (!!1)
|
||||
#else
|
||||
#define BROTLI_ALIGNED_READ (!!1)
|
||||
#define BROTLI_UNALIGNED_READ_FAST (!!0)
|
||||
#endif
|
||||
|
||||
#if BROTLI_ALIGNED_READ
|
||||
/* Portable unaligned memory access: read / write values via memcpy. */
|
||||
#if !defined(BROTLI_USE_PACKED_FOR_UNALIGNED)
|
||||
#if defined(__mips__) && (!defined(__mips_isa_rev) || __mips_isa_rev < 6)
|
||||
#define BROTLI_USE_PACKED_FOR_UNALIGNED 1
|
||||
#else
|
||||
#define BROTLI_USE_PACKED_FOR_UNALIGNED 0
|
||||
#endif
|
||||
#endif /* defined(BROTLI_USE_PACKED_FOR_UNALIGNED) */
|
||||
|
||||
#if BROTLI_USE_PACKED_FOR_UNALIGNED
|
||||
|
||||
typedef union BrotliPackedValue {
|
||||
uint16_t u16;
|
||||
uint32_t u32;
|
||||
uint64_t u64;
|
||||
size_t szt;
|
||||
} __attribute__ ((packed)) BrotliPackedValue;
|
||||
|
||||
static BROTLI_INLINE uint16_t BrotliUnalignedRead16(const void* p) {
|
||||
const BrotliPackedValue* address = (const BrotliPackedValue*)p;
|
||||
return address->u16;
|
||||
}
|
||||
static BROTLI_INLINE uint32_t BrotliUnalignedRead32(const void* p) {
|
||||
const BrotliPackedValue* address = (const BrotliPackedValue*)p;
|
||||
return address->u32;
|
||||
}
|
||||
static BROTLI_INLINE uint64_t BrotliUnalignedRead64(const void* p) {
|
||||
const BrotliPackedValue* address = (const BrotliPackedValue*)p;
|
||||
return address->u64;
|
||||
}
|
||||
static BROTLI_INLINE size_t BrotliUnalignedReadSizeT(const void* p) {
|
||||
const BrotliPackedValue* address = (const BrotliPackedValue*)p;
|
||||
return address->szt;
|
||||
}
|
||||
static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) {
|
||||
BrotliPackedValue* address = (BrotliPackedValue*)p;
|
||||
address->u64 = v;
|
||||
}
|
||||
|
||||
#else /* not BROTLI_USE_PACKED_FOR_UNALIGNED */
|
||||
|
||||
static BROTLI_INLINE uint16_t BrotliUnalignedRead16(const void* p) {
|
||||
uint16_t t;
|
||||
memcpy(&t, p, sizeof t);
|
||||
@@ -293,79 +332,42 @@ static BROTLI_INLINE uint64_t BrotliUnalignedRead64(const void* p) {
|
||||
memcpy(&t, p, sizeof t);
|
||||
return t;
|
||||
}
|
||||
static BROTLI_INLINE size_t BrotliUnalignedReadSizeT(const void* p) {
|
||||
size_t t;
|
||||
memcpy(&t, p, sizeof t);
|
||||
return t;
|
||||
}
|
||||
static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) {
|
||||
memcpy(p, &v, sizeof v);
|
||||
}
|
||||
#else /* BROTLI_ALIGNED_READ */
|
||||
/* Unaligned memory access is allowed: just cast pointer to requested type. */
|
||||
#if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) || \
|
||||
defined(MEMORY_SANITIZER)
|
||||
/* Consider we have an unaligned load/store of 4 bytes from address 0x...05.
|
||||
AddressSanitizer will treat it as a 3-byte access to the range 05:07 and
|
||||
will miss a bug if 08 is the first unaddressable byte.
|
||||
ThreadSanitizer will also treat this as a 3-byte access to 05:07 and will
|
||||
miss a race between this access and some other accesses to 08.
|
||||
MemorySanitizer will correctly propagate the shadow on unaligned stores
|
||||
and correctly report bugs on unaligned loads, but it may not properly
|
||||
update and report the origin of the uninitialized memory.
|
||||
For all three tools, replacing an unaligned access with a tool-specific
|
||||
callback solves the problem. */
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
uint16_t __sanitizer_unaligned_load16(const void* p);
|
||||
uint32_t __sanitizer_unaligned_load32(const void* p);
|
||||
uint64_t __sanitizer_unaligned_load64(const void* p);
|
||||
void __sanitizer_unaligned_store64(void* p, uint64_t v);
|
||||
#if defined(__cplusplus)
|
||||
} /* extern "C" */
|
||||
#endif /* __cplusplus */
|
||||
#define BrotliUnalignedRead16 __sanitizer_unaligned_load16
|
||||
#define BrotliUnalignedRead32 __sanitizer_unaligned_load32
|
||||
#define BrotliUnalignedRead64 __sanitizer_unaligned_load64
|
||||
#define BrotliUnalignedWrite64 __sanitizer_unaligned_store64
|
||||
|
||||
#endif /* BROTLI_USE_PACKED_FOR_UNALIGNED */
|
||||
|
||||
#if BROTLI_GNUC_HAS_BUILTIN(__builtin_bswap16, 4, 3, 0)
|
||||
#define BROTLI_BSWAP16(V) ((uint16_t)__builtin_bswap16(V))
|
||||
#else
|
||||
static BROTLI_INLINE uint16_t BrotliUnalignedRead16(const void* p) {
|
||||
return *(const uint16_t*)p;
|
||||
}
|
||||
static BROTLI_INLINE uint32_t BrotliUnalignedRead32(const void* p) {
|
||||
return *(const uint32_t*)p;
|
||||
}
|
||||
#if (BROTLI_64_BITS)
|
||||
static BROTLI_INLINE uint64_t BrotliUnalignedRead64(const void* p) {
|
||||
return *(const uint64_t*)p;
|
||||
}
|
||||
static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) {
|
||||
*(uint64_t*)p = v;
|
||||
}
|
||||
#else /* BROTLI_64_BITS */
|
||||
/* Avoid emitting LDRD / STRD, which require properly aligned address. */
|
||||
/* If __attribute__(aligned) is available, use that. Otherwise, memcpy. */
|
||||
#define BROTLI_BSWAP16(V) ((uint16_t)( \
|
||||
(((V) & 0xFFU) << 8) | \
|
||||
(((V) >> 8) & 0xFFU)))
|
||||
#endif
|
||||
|
||||
#if BROTLI_GNUC_HAS_ATTRIBUTE(aligned, 2, 7, 0)
|
||||
typedef __attribute__((aligned(1))) uint64_t brotli_unaligned_uint64_t;
|
||||
#if BROTLI_GNUC_HAS_BUILTIN(__builtin_bswap32, 4, 3, 0)
|
||||
#define BROTLI_BSWAP32(V) ((uint32_t)__builtin_bswap32(V))
|
||||
#else
|
||||
#define BROTLI_BSWAP32(V) ((uint32_t)( \
|
||||
(((V) & 0xFFU) << 24) | (((V) & 0xFF00U) << 8) | \
|
||||
(((V) >> 8) & 0xFF00U) | (((V) >> 24) & 0xFFU)))
|
||||
#endif
|
||||
|
||||
static BROTLI_INLINE uint64_t BrotliUnalignedRead64(const void* p) {
|
||||
return (uint64_t) ((brotli_unaligned_uint64_t*) p)[0];
|
||||
}
|
||||
static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) {
|
||||
brotli_unaligned_uint64_t* dwords = (brotli_unaligned_uint64_t*) p;
|
||||
dwords[0] = (brotli_unaligned_uint64_t) v;
|
||||
}
|
||||
#else /* BROTLI_GNUC_HAS_ATTRIBUTE(aligned, 2, 7, 0) */
|
||||
static BROTLI_INLINE uint64_t BrotliUnalignedRead64(const void* p) {
|
||||
uint64_t v;
|
||||
memcpy(&v, p, sizeof(uint64_t));
|
||||
return v;
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) {
|
||||
memcpy(p, &v, sizeof(uint64_t));
|
||||
}
|
||||
#endif /* BROTLI_GNUC_HAS_ATTRIBUTE(aligned, 2, 7, 0) */
|
||||
#endif /* BROTLI_64_BITS */
|
||||
#endif /* ASAN / TSAN / MSAN */
|
||||
#endif /* BROTLI_ALIGNED_READ */
|
||||
#if BROTLI_GNUC_HAS_BUILTIN(__builtin_bswap64, 4, 3, 0)
|
||||
#define BROTLI_BSWAP64(V) ((uint64_t)__builtin_bswap64(V))
|
||||
#else
|
||||
#define BROTLI_BSWAP64(V) ((uint64_t)( \
|
||||
(((V) & 0xFFU) << 56) | (((V) & 0xFF00U) << 40) | \
|
||||
(((V) & 0xFF0000U) << 24) | (((V) & 0xFF000000U) << 8) | \
|
||||
(((V) >> 8) & 0xFF000000U) | (((V) >> 24) & 0xFF0000U) | \
|
||||
(((V) >> 40) & 0xFF00U) | (((V) >> 56) & 0xFFU)))
|
||||
#endif
|
||||
|
||||
#if BROTLI_LITTLE_ENDIAN
|
||||
/* Straight endianness. Just read / write values. */
|
||||
@@ -374,32 +376,20 @@ static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) {
|
||||
#define BROTLI_UNALIGNED_LOAD64LE BrotliUnalignedRead64
|
||||
#define BROTLI_UNALIGNED_STORE64LE BrotliUnalignedWrite64
|
||||
#elif BROTLI_BIG_ENDIAN /* BROTLI_LITTLE_ENDIAN */
|
||||
/* Explain compiler to byte-swap values. */
|
||||
#define BROTLI_BSWAP16_(V) ((uint16_t)( \
|
||||
(((V) & 0xFFU) << 8) | \
|
||||
(((V) >> 8) & 0xFFU)))
|
||||
static BROTLI_INLINE uint16_t BROTLI_UNALIGNED_LOAD16LE(const void* p) {
|
||||
uint16_t value = BrotliUnalignedRead16(p);
|
||||
return BROTLI_BSWAP16_(value);
|
||||
return BROTLI_BSWAP16(value);
|
||||
}
|
||||
#define BROTLI_BSWAP32_(V) ( \
|
||||
(((V) & 0xFFU) << 24) | (((V) & 0xFF00U) << 8) | \
|
||||
(((V) >> 8) & 0xFF00U) | (((V) >> 24) & 0xFFU))
|
||||
static BROTLI_INLINE uint32_t BROTLI_UNALIGNED_LOAD32LE(const void* p) {
|
||||
uint32_t value = BrotliUnalignedRead32(p);
|
||||
return BROTLI_BSWAP32_(value);
|
||||
return BROTLI_BSWAP32(value);
|
||||
}
|
||||
#define BROTLI_BSWAP64_(V) ( \
|
||||
(((V) & 0xFFU) << 56) | (((V) & 0xFF00U) << 40) | \
|
||||
(((V) & 0xFF0000U) << 24) | (((V) & 0xFF000000U) << 8) | \
|
||||
(((V) >> 8) & 0xFF000000U) | (((V) >> 24) & 0xFF0000U) | \
|
||||
(((V) >> 40) & 0xFF00U) | (((V) >> 56) & 0xFFU))
|
||||
static BROTLI_INLINE uint64_t BROTLI_UNALIGNED_LOAD64LE(const void* p) {
|
||||
uint64_t value = BrotliUnalignedRead64(p);
|
||||
return BROTLI_BSWAP64_(value);
|
||||
return BROTLI_BSWAP64(value);
|
||||
}
|
||||
static BROTLI_INLINE void BROTLI_UNALIGNED_STORE64LE(void* p, uint64_t v) {
|
||||
uint64_t value = BROTLI_BSWAP64_(v);
|
||||
uint64_t value = BROTLI_BSWAP64(v);
|
||||
BrotliUnalignedWrite64(p, value);
|
||||
}
|
||||
#else /* BROTLI_LITTLE_ENDIAN */
|
||||
@@ -441,6 +431,16 @@ static BROTLI_INLINE void BROTLI_UNALIGNED_STORE64LE(void* p, uint64_t v) {
|
||||
}
|
||||
#endif /* BROTLI_LITTLE_ENDIAN */
|
||||
|
||||
static BROTLI_INLINE void* BROTLI_UNALIGNED_LOAD_PTR(const void* p) {
|
||||
void* v;
|
||||
memcpy(&v, p, sizeof(void*));
|
||||
return v;
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void BROTLI_UNALIGNED_STORE_PTR(void* p, const void* v) {
|
||||
memcpy(p, &v, sizeof(void*));
|
||||
}
|
||||
|
||||
/* BROTLI_IS_CONSTANT macros returns true for compile-time constants. */
|
||||
#if BROTLI_GNUC_HAS_BUILTIN(__builtin_constant_p, 3, 0, 1) || \
|
||||
BROTLI_INTEL_VERSION_CHECK(16, 0, 0)
|
||||
@@ -456,14 +456,24 @@ static BROTLI_INLINE void BROTLI_UNALIGNED_STORE64LE(void* p, uint64_t v) {
|
||||
#endif
|
||||
|
||||
#if defined(BROTLI_ENABLE_LOG)
|
||||
#define BROTLI_DCHECK(x) assert(x)
|
||||
#define BROTLI_LOG(x) printf x
|
||||
#else
|
||||
#define BROTLI_DCHECK(x)
|
||||
#define BROTLI_LOG(x)
|
||||
#endif
|
||||
|
||||
#if defined(BROTLI_DEBUG) || defined(BROTLI_ENABLE_LOG)
|
||||
#define BROTLI_ENABLE_DUMP_DEFAULT 1
|
||||
#define BROTLI_DCHECK(x) assert(x)
|
||||
#else
|
||||
#define BROTLI_ENABLE_DUMP_DEFAULT 0
|
||||
#define BROTLI_DCHECK(x)
|
||||
#endif
|
||||
|
||||
#if !defined(BROTLI_ENABLE_DUMP)
|
||||
#define BROTLI_ENABLE_DUMP BROTLI_ENABLE_DUMP_DEFAULT
|
||||
#endif
|
||||
|
||||
#if BROTLI_ENABLE_DUMP
|
||||
static BROTLI_INLINE void BrotliDump(const char* f, int l, const char* fn) {
|
||||
fprintf(stderr, "%s:%d (%s)\n", f, l, fn);
|
||||
fflush(stderr);
|
||||
@@ -473,11 +483,13 @@ static BROTLI_INLINE void BrotliDump(const char* f, int l, const char* fn) {
|
||||
#define BROTLI_DUMP() (void)(0)
|
||||
#endif
|
||||
|
||||
/* TODO: add appropriate icc/sunpro/arm/ibm/ti checks. */
|
||||
/* BrotliRBit assumes brotli_reg_t fits native CPU register type. */
|
||||
#if (BROTLI_64_BITS == BROTLI_TARGET_64_BITS)
|
||||
/* TODO(eustas): add appropriate icc/sunpro/arm/ibm/ti checks. */
|
||||
#if (BROTLI_GNUC_VERSION_CHECK(3, 0, 0) || defined(__llvm__)) && \
|
||||
!defined(BROTLI_BUILD_NO_RBIT)
|
||||
#if defined(BROTLI_TARGET_ARMV7) || defined(BROTLI_TARGET_ARMV8_ANY)
|
||||
/* TODO: detect ARMv6T2 and enable this code for it. */
|
||||
/* TODO(eustas): detect ARMv6T2 and enable this code for it. */
|
||||
static BROTLI_INLINE brotli_reg_t BrotliRBit(brotli_reg_t input) {
|
||||
brotli_reg_t output;
|
||||
__asm__("rbit %0, %1\n" : "=r"(output) : "r"(input));
|
||||
@@ -486,15 +498,14 @@ static BROTLI_INLINE brotli_reg_t BrotliRBit(brotli_reg_t input) {
|
||||
#define BROTLI_RBIT(x) BrotliRBit(x)
|
||||
#endif /* armv7 / armv8 */
|
||||
#endif /* gcc || clang */
|
||||
#endif /* brotli_reg_t is native */
|
||||
#if !defined(BROTLI_RBIT)
|
||||
static BROTLI_INLINE void BrotliRBit(void) { /* Should break build if used. */ }
|
||||
#endif /* BROTLI_RBIT */
|
||||
|
||||
#define BROTLI_REPEAT(N, X) { \
|
||||
if ((N & 1) != 0) {X;} \
|
||||
if ((N & 2) != 0) {X; X;} \
|
||||
if ((N & 4) != 0) {X; X; X; X;} \
|
||||
}
|
||||
#define BROTLI_REPEAT_4(X) {X; X; X; X;}
|
||||
#define BROTLI_REPEAT_5(X) {X; X; X; X; X;}
|
||||
#define BROTLI_REPEAT_6(X) {X; X; X; X; X; X;}
|
||||
|
||||
#define BROTLI_UNUSED(X) (void)(X)
|
||||
|
||||
@@ -513,16 +524,57 @@ BROTLI_MIN_MAX(size_t) BROTLI_MIN_MAX(uint32_t) BROTLI_MIN_MAX(uint8_t)
|
||||
(A)[(J)] = __brotli_swap_tmp; \
|
||||
}
|
||||
|
||||
/* Default brotli_alloc_func */
|
||||
static void* BrotliDefaultAllocFunc(void* opaque, size_t size) {
|
||||
BROTLI_UNUSED(opaque);
|
||||
return malloc(size);
|
||||
#if BROTLI_64_BITS
|
||||
#if BROTLI_GNUC_HAS_BUILTIN(__builtin_ctzll, 3, 4, 0) || \
|
||||
BROTLI_INTEL_VERSION_CHECK(16, 0, 0)
|
||||
#define BROTLI_TZCNT64 __builtin_ctzll
|
||||
#elif BROTLI_MSVC_VERSION_CHECK(18, 0, 0)
|
||||
#if defined(BROTLI_TARGET_X64) && !defined(_M_ARM64EC)
|
||||
#define BROTLI_TZCNT64 _tzcnt_u64
|
||||
#else /* BROTLI_TARGET_X64 */
|
||||
static BROTLI_INLINE uint32_t BrotliBsf64Msvc(uint64_t x) {
|
||||
uint32_t lsb;
|
||||
_BitScanForward64(&lsb, x);
|
||||
return lsb;
|
||||
}
|
||||
#define BROTLI_TZCNT64 BrotliBsf64Msvc
|
||||
#endif /* BROTLI_TARGET_X64 */
|
||||
#endif /* __builtin_ctzll */
|
||||
#endif /* BROTLI_64_BITS */
|
||||
|
||||
#if BROTLI_GNUC_HAS_BUILTIN(__builtin_clz, 3, 4, 0) || \
|
||||
BROTLI_INTEL_VERSION_CHECK(16, 0, 0)
|
||||
#define BROTLI_BSR32(x) (31u ^ (uint32_t)__builtin_clz(x))
|
||||
#elif BROTLI_MSVC_VERSION_CHECK(18, 0, 0)
|
||||
static BROTLI_INLINE uint32_t BrotliBsr32Msvc(uint32_t x) {
|
||||
unsigned long msb;
|
||||
_BitScanReverse(&msb, x);
|
||||
return (uint32_t)msb;
|
||||
}
|
||||
#define BROTLI_BSR32 BrotliBsr32Msvc
|
||||
#endif /* __builtin_clz */
|
||||
|
||||
/* Default brotli_alloc_func */
|
||||
BROTLI_COMMON_API void* BrotliDefaultAllocFunc(void* opaque, size_t size);
|
||||
|
||||
/* Default brotli_free_func */
|
||||
static void BrotliDefaultFreeFunc(void* opaque, void* address) {
|
||||
BROTLI_UNUSED(opaque);
|
||||
free(address);
|
||||
BROTLI_COMMON_API void BrotliDefaultFreeFunc(void* opaque, void* address);
|
||||
|
||||
/* Circular logical rotates. */
|
||||
static BROTLI_INLINE uint16_t BrotliRotateRight16(uint16_t const value,
|
||||
size_t count) {
|
||||
count &= 0x0F; /* for fickle pattern recognition */
|
||||
return (value >> count) | (uint16_t)(value << ((0U - count) & 0x0F));
|
||||
}
|
||||
static BROTLI_INLINE uint32_t BrotliRotateRight32(uint32_t const value,
|
||||
size_t count) {
|
||||
count &= 0x1F; /* for fickle pattern recognition */
|
||||
return (value >> count) | (uint32_t)(value << ((0U - count) & 0x1F));
|
||||
}
|
||||
static BROTLI_INLINE uint64_t BrotliRotateRight64(uint64_t const value,
|
||||
size_t count) {
|
||||
count &= 0x3F; /* for fickle pattern recognition */
|
||||
return (value >> count) | (uint64_t)(value << ((0U - count) & 0x3F));
|
||||
}
|
||||
|
||||
BROTLI_UNUSED_FUNCTION void BrotliSuppressUnusedFunctions(void) {
|
||||
@@ -530,11 +582,14 @@ BROTLI_UNUSED_FUNCTION void BrotliSuppressUnusedFunctions(void) {
|
||||
BROTLI_UNUSED(&BrotliUnalignedRead16);
|
||||
BROTLI_UNUSED(&BrotliUnalignedRead32);
|
||||
BROTLI_UNUSED(&BrotliUnalignedRead64);
|
||||
BROTLI_UNUSED(&BrotliUnalignedReadSizeT);
|
||||
BROTLI_UNUSED(&BrotliUnalignedWrite64);
|
||||
BROTLI_UNUSED(&BROTLI_UNALIGNED_LOAD16LE);
|
||||
BROTLI_UNUSED(&BROTLI_UNALIGNED_LOAD32LE);
|
||||
BROTLI_UNUSED(&BROTLI_UNALIGNED_LOAD64LE);
|
||||
BROTLI_UNUSED(&BROTLI_UNALIGNED_STORE64LE);
|
||||
BROTLI_UNUSED(&BROTLI_UNALIGNED_LOAD_PTR);
|
||||
BROTLI_UNUSED(&BROTLI_UNALIGNED_STORE_PTR);
|
||||
BROTLI_UNUSED(&BrotliRBit);
|
||||
BROTLI_UNUSED(&brotli_min_double);
|
||||
BROTLI_UNUSED(&brotli_max_double);
|
||||
@@ -550,9 +605,76 @@ BROTLI_UNUSED_FUNCTION void BrotliSuppressUnusedFunctions(void) {
|
||||
BROTLI_UNUSED(&brotli_max_uint8_t);
|
||||
BROTLI_UNUSED(&BrotliDefaultAllocFunc);
|
||||
BROTLI_UNUSED(&BrotliDefaultFreeFunc);
|
||||
#if defined(BROTLI_DEBUG) || defined(BROTLI_ENABLE_LOG)
|
||||
BROTLI_UNUSED(&BrotliRotateRight16);
|
||||
BROTLI_UNUSED(&BrotliRotateRight32);
|
||||
BROTLI_UNUSED(&BrotliRotateRight64);
|
||||
#if BROTLI_ENABLE_DUMP
|
||||
BROTLI_UNUSED(&BrotliDump);
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_I86)) && \
|
||||
!defined(_M_ARM64EC)
|
||||
/* _mm_prefetch() is not defined outside of x86/x64 */
|
||||
/* https://msdn.microsoft.com/fr-fr/library/84szxsww(v=vs.90).aspx */
|
||||
#include <mmintrin.h>
|
||||
#define PREFETCH_L1(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T0)
|
||||
#define PREFETCH_L2(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T1)
|
||||
#elif BROTLI_GNUC_HAS_BUILTIN(__builtin_prefetch, 3, 1, 0)
|
||||
#define PREFETCH_L1(ptr) \
|
||||
__builtin_prefetch((ptr), 0 /* rw==read */, 3 /* locality */)
|
||||
#define PREFETCH_L2(ptr) \
|
||||
__builtin_prefetch((ptr), 0 /* rw==read */, 2 /* locality */)
|
||||
#elif defined(__aarch64__)
|
||||
#define PREFETCH_L1(ptr) \
|
||||
do { \
|
||||
__asm__ __volatile__("prfm pldl1keep, %0" ::"Q"(*(ptr))); \
|
||||
} while (0)
|
||||
#define PREFETCH_L2(ptr) \
|
||||
do { \
|
||||
__asm__ __volatile__("prfm pldl2keep, %0" ::"Q"(*(ptr))); \
|
||||
} while (0)
|
||||
#else
|
||||
#define PREFETCH_L1(ptr) \
|
||||
do { \
|
||||
(void)(ptr); \
|
||||
} while (0) /* disabled */
|
||||
#define PREFETCH_L2(ptr) \
|
||||
do { \
|
||||
(void)(ptr); \
|
||||
} while (0) /* disabled */
|
||||
#endif
|
||||
|
||||
/* The SIMD matchers are only faster at certain quality levels. */
|
||||
#if defined(_M_X64) && defined(BROTLI_TZCNT64)
|
||||
#define BROTLI_MAX_SIMD_QUALITY 7
|
||||
#elif defined(BROTLI_TZCNT64)
|
||||
#define BROTLI_MAX_SIMD_QUALITY 6
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define BROTLI_CRASH() __debugbreak(), (void)abort()
|
||||
#elif BROTLI_GNUC_HAS_BUILTIN(__builtin_trap, 3, 0, 0)
|
||||
#define BROTLI_CRASH() (void)__builtin_trap()
|
||||
#else
|
||||
#define BROTLI_CRASH() (void)abort()
|
||||
#endif
|
||||
|
||||
/* Make BROTLI_TEST=0 act same as undefined. */
|
||||
#if defined(BROTLI_TEST) && ((1-BROTLI_TEST-1) == 0)
|
||||
#undef BROTLI_TEST
|
||||
#endif
|
||||
|
||||
#if BROTLI_GNUC_HAS_ATTRIBUTE(model, 3, 0, 3)
|
||||
#define BROTLI_MODEL(M) __attribute__((model(M)))
|
||||
#else
|
||||
#define BROTLI_MODEL(M) /* M */
|
||||
#endif
|
||||
|
||||
#if BROTLI_GNUC_HAS_ATTRIBUTE(cold, 4, 3, 0)
|
||||
#define BROTLI_COLD __attribute__((cold))
|
||||
#else
|
||||
#define BROTLI_COLD /* cold */
|
||||
#endif
|
||||
|
||||
#endif /* BROTLI_COMMON_PLATFORM_H_ */
|
||||
|
||||
517
c/common/shared_dictionary.c
Normal file
517
c/common/shared_dictionary.c
Normal file
@@ -0,0 +1,517 @@
|
||||
/* Copyright 2017 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/* Shared Dictionary definition and utilities. */
|
||||
|
||||
#include <brotli/shared_dictionary.h>
|
||||
|
||||
#include "dictionary.h"
|
||||
#include "platform.h"
|
||||
#include "shared_dictionary_internal.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(BROTLI_EXPERIMENTAL)
|
||||
|
||||
#define BROTLI_NUM_ENCODED_LENGTHS (SHARED_BROTLI_MAX_DICTIONARY_WORD_LENGTH \
|
||||
- SHARED_BROTLI_MIN_DICTIONARY_WORD_LENGTH + 1)
|
||||
|
||||
/* Max allowed by spec */
|
||||
#define BROTLI_MAX_SIZE_BITS 15u
|
||||
|
||||
/* Returns BROTLI_TRUE on success, BROTLI_FALSE on failure. */
|
||||
static BROTLI_BOOL ReadBool(const uint8_t* encoded, size_t size, size_t* pos,
|
||||
BROTLI_BOOL* result) {
|
||||
uint8_t value;
|
||||
size_t position = *pos;
|
||||
if (position >= size) return BROTLI_FALSE; /* past file end */
|
||||
value = encoded[position++];
|
||||
if (value > 1) return BROTLI_FALSE; /* invalid bool */
|
||||
*result = TO_BROTLI_BOOL(value);
|
||||
*pos = position;
|
||||
return BROTLI_TRUE; /* success */
|
||||
}
|
||||
|
||||
/* Returns BROTLI_TRUE on success, BROTLI_FALSE on failure. */
|
||||
static BROTLI_BOOL ReadUint8(const uint8_t* encoded, size_t size, size_t* pos,
|
||||
uint8_t* result) {
|
||||
size_t position = *pos;
|
||||
if (position + sizeof(uint8_t) > size) return BROTLI_FALSE;
|
||||
*result = encoded[position++];
|
||||
*pos = position;
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
|
||||
/* Returns BROTLI_TRUE on success, BROTLI_FALSE on failure. */
|
||||
static BROTLI_BOOL ReadUint16(const uint8_t* encoded, size_t size, size_t* pos,
|
||||
uint16_t* result) {
|
||||
size_t position = *pos;
|
||||
if (position + sizeof(uint16_t) > size) return BROTLI_FALSE;
|
||||
*result = BROTLI_UNALIGNED_LOAD16LE(&encoded[position]);
|
||||
position += 2;
|
||||
*pos = position;
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
|
||||
/* Reads a varint into a uint32_t, and returns error if it's too large */
|
||||
/* Returns BROTLI_TRUE on success, BROTLI_FALSE on failure. */
|
||||
static BROTLI_BOOL ReadVarint32(const uint8_t* encoded, size_t size,
|
||||
size_t* pos, uint32_t* result) {
|
||||
int num = 0;
|
||||
uint8_t byte;
|
||||
*result = 0;
|
||||
for (;;) {
|
||||
if (*pos >= size) return BROTLI_FALSE;
|
||||
byte = encoded[(*pos)++];
|
||||
if (num == 4 && byte > 15) return BROTLI_FALSE;
|
||||
*result |= (uint32_t)(byte & 127) << (num * 7);
|
||||
if (byte < 128) return BROTLI_TRUE;
|
||||
num++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns the total length of word list. */
|
||||
static size_t BrotliSizeBitsToOffsets(const uint8_t* size_bits_by_length,
|
||||
uint32_t* offsets_by_length) {
|
||||
uint32_t pos = 0;
|
||||
uint32_t i;
|
||||
for (i = 0; i <= SHARED_BROTLI_MAX_DICTIONARY_WORD_LENGTH; i++) {
|
||||
offsets_by_length[i] = pos;
|
||||
if (size_bits_by_length[i] != 0) {
|
||||
pos += i << size_bits_by_length[i];
|
||||
}
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
static BROTLI_BOOL ParseWordList(size_t size, const uint8_t* encoded,
|
||||
size_t* pos, BrotliDictionary* out) {
|
||||
size_t offset;
|
||||
size_t i;
|
||||
size_t position = *pos;
|
||||
if (position + BROTLI_NUM_ENCODED_LENGTHS > size) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
|
||||
memset(out->size_bits_by_length, 0, SHARED_BROTLI_MIN_DICTIONARY_WORD_LENGTH);
|
||||
memcpy(out->size_bits_by_length + SHARED_BROTLI_MIN_DICTIONARY_WORD_LENGTH,
|
||||
&encoded[position], BROTLI_NUM_ENCODED_LENGTHS);
|
||||
for (i = SHARED_BROTLI_MIN_DICTIONARY_WORD_LENGTH;
|
||||
i <= SHARED_BROTLI_MAX_DICTIONARY_WORD_LENGTH; i++) {
|
||||
if (out->size_bits_by_length[i] > BROTLI_MAX_SIZE_BITS) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
}
|
||||
position += BROTLI_NUM_ENCODED_LENGTHS;
|
||||
offset = BrotliSizeBitsToOffsets(
|
||||
out->size_bits_by_length, out->offsets_by_length);
|
||||
|
||||
out->data = &encoded[position];
|
||||
out->data_size = offset;
|
||||
position += offset;
|
||||
if (position > size) return BROTLI_FALSE;
|
||||
*pos = position;
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
|
||||
/* Computes the cutOffTransforms of a BrotliTransforms which already has the
|
||||
transforms data correctly filled in. */
|
||||
static void ComputeCutoffTransforms(BrotliTransforms* transforms) {
|
||||
uint32_t i;
|
||||
for (i = 0; i < BROTLI_TRANSFORMS_MAX_CUT_OFF + 1; i++) {
|
||||
transforms->cutOffTransforms[i] = -1;
|
||||
}
|
||||
for (i = 0; i < transforms->num_transforms; i++) {
|
||||
const uint8_t* prefix = BROTLI_TRANSFORM_PREFIX(transforms, i);
|
||||
uint8_t type = BROTLI_TRANSFORM_TYPE(transforms, i);
|
||||
const uint8_t* suffix = BROTLI_TRANSFORM_SUFFIX(transforms, i);
|
||||
if (type <= BROTLI_TRANSFORM_OMIT_LAST_9 && *prefix == 0 && *suffix == 0 &&
|
||||
transforms->cutOffTransforms[type] == -1) {
|
||||
transforms->cutOffTransforms[type] = (int16_t)i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static BROTLI_BOOL ParsePrefixSuffixTable(size_t size, const uint8_t* encoded,
|
||||
size_t* pos, BrotliTransforms* out, uint16_t* out_table,
|
||||
size_t* out_table_size) {
|
||||
size_t position = *pos;
|
||||
size_t offset = 0;
|
||||
size_t stringlet_count = 0; /* NUM_PREFIX_SUFFIX */
|
||||
size_t data_length = 0;
|
||||
|
||||
/* PREFIX_SUFFIX_LENGTH */
|
||||
if (!ReadUint16(encoded, size, &position, &out->prefix_suffix_size)) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
data_length = out->prefix_suffix_size;
|
||||
|
||||
/* Must at least have space for null terminator. */
|
||||
if (data_length < 1) return BROTLI_FALSE;
|
||||
out->prefix_suffix = &encoded[position];
|
||||
if (position + data_length >= size) return BROTLI_FALSE;
|
||||
while (BROTLI_TRUE) {
|
||||
/* STRING_LENGTH */
|
||||
size_t stringlet_len = encoded[position + offset];
|
||||
out_table[stringlet_count] = (uint16_t)offset;
|
||||
stringlet_count++;
|
||||
offset++;
|
||||
if (stringlet_len == 0) {
|
||||
if (offset == data_length) {
|
||||
break;
|
||||
} else {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
}
|
||||
if (stringlet_count > 255) return BROTLI_FALSE;
|
||||
offset += stringlet_len;
|
||||
if (offset >= data_length) return BROTLI_FALSE;
|
||||
}
|
||||
|
||||
position += data_length;
|
||||
*pos = position;
|
||||
*out_table_size = (uint16_t)stringlet_count;
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
|
||||
static BROTLI_BOOL ParseTransformsList(size_t size, const uint8_t* encoded,
|
||||
size_t* pos, BrotliTransforms* out, uint16_t* prefix_suffix_table,
|
||||
size_t* prefix_suffix_count) {
|
||||
uint32_t i;
|
||||
BROTLI_BOOL has_params = BROTLI_FALSE;
|
||||
BROTLI_BOOL prefix_suffix_ok = BROTLI_FALSE;
|
||||
size_t position = *pos;
|
||||
size_t stringlet_cnt = 0;
|
||||
if (position >= size) return BROTLI_FALSE;
|
||||
|
||||
prefix_suffix_ok = ParsePrefixSuffixTable(
|
||||
size, encoded, &position, out, prefix_suffix_table, &stringlet_cnt);
|
||||
if (!prefix_suffix_ok) return BROTLI_FALSE;
|
||||
out->prefix_suffix_map = prefix_suffix_table;
|
||||
*prefix_suffix_count = stringlet_cnt;
|
||||
|
||||
out->num_transforms = encoded[position++];
|
||||
out->transforms = &encoded[position];
|
||||
position += (size_t)out->num_transforms * 3;
|
||||
if (position > size) return BROTLI_FALSE;
|
||||
/* Check for errors and read extra parameters. */
|
||||
for (i = 0; i < out->num_transforms; i++) {
|
||||
uint8_t prefix_id = BROTLI_TRANSFORM_PREFIX_ID(out, i);
|
||||
uint8_t type = BROTLI_TRANSFORM_TYPE(out, i);
|
||||
uint8_t suffix_id = BROTLI_TRANSFORM_SUFFIX_ID(out, i);
|
||||
if (prefix_id >= stringlet_cnt) return BROTLI_FALSE;
|
||||
if (type >= BROTLI_NUM_TRANSFORM_TYPES) return BROTLI_FALSE;
|
||||
if (suffix_id >= stringlet_cnt) return BROTLI_FALSE;
|
||||
if (type == BROTLI_TRANSFORM_SHIFT_FIRST ||
|
||||
type == BROTLI_TRANSFORM_SHIFT_ALL) {
|
||||
has_params = BROTLI_TRUE;
|
||||
}
|
||||
}
|
||||
if (has_params) {
|
||||
out->params = &encoded[position];
|
||||
position += (size_t)out->num_transforms * 2;
|
||||
if (position > size) return BROTLI_FALSE;
|
||||
for (i = 0; i < out->num_transforms; i++) {
|
||||
uint8_t type = BROTLI_TRANSFORM_TYPE(out, i);
|
||||
if (type != BROTLI_TRANSFORM_SHIFT_FIRST &&
|
||||
type != BROTLI_TRANSFORM_SHIFT_ALL) {
|
||||
if (out->params[i * 2] != 0 || out->params[i * 2 + 1] != 0) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out->params = NULL;
|
||||
}
|
||||
ComputeCutoffTransforms(out);
|
||||
*pos = position;
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
|
||||
static BROTLI_BOOL DryParseDictionary(const uint8_t* encoded,
|
||||
size_t size, uint32_t* num_prefix, BROTLI_BOOL* is_custom_static_dict) {
|
||||
size_t pos = 0;
|
||||
uint32_t chunk_size = 0;
|
||||
uint8_t num_word_lists;
|
||||
uint8_t num_transform_lists;
|
||||
*is_custom_static_dict = BROTLI_FALSE;
|
||||
*num_prefix = 0;
|
||||
|
||||
/* Skip magic header bytes. */
|
||||
pos += 2;
|
||||
|
||||
/* LZ77_DICTIONARY_LENGTH */
|
||||
if (!ReadVarint32(encoded, size, &pos, &chunk_size)) return BROTLI_FALSE;
|
||||
if (chunk_size != 0) {
|
||||
/* This limitation is not specified but the 32-bit Brotli decoder for now */
|
||||
if (chunk_size > 1073741823) return BROTLI_FALSE;
|
||||
*num_prefix = 1;
|
||||
if (pos + chunk_size > size) return BROTLI_FALSE;
|
||||
pos += chunk_size;
|
||||
}
|
||||
|
||||
if (!ReadUint8(encoded, size, &pos, &num_word_lists)) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
if (!ReadUint8(encoded, size, &pos, &num_transform_lists)) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
|
||||
if (num_word_lists > 0 || num_transform_lists > 0) {
|
||||
*is_custom_static_dict = BROTLI_TRUE;
|
||||
}
|
||||
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
|
||||
static BROTLI_BOOL ParseDictionary(const uint8_t* encoded, size_t size,
|
||||
BrotliSharedDictionary* dict) {
|
||||
uint32_t i;
|
||||
size_t pos = 0;
|
||||
uint32_t chunk_size = 0;
|
||||
size_t total_prefix_suffix_count = 0;
|
||||
size_t transform_list_start[SHARED_BROTLI_NUM_DICTIONARY_CONTEXTS];
|
||||
uint16_t temporary_prefix_suffix_table[256];
|
||||
|
||||
/* Skip magic header bytes. */
|
||||
pos += 2;
|
||||
|
||||
/* LZ77_DICTIONARY_LENGTH */
|
||||
if (!ReadVarint32(encoded, size, &pos, &chunk_size)) return BROTLI_FALSE;
|
||||
if (chunk_size != 0) {
|
||||
if (pos + chunk_size > size) return BROTLI_FALSE;
|
||||
dict->prefix_size[dict->num_prefix] = chunk_size;
|
||||
dict->prefix[dict->num_prefix] = &encoded[pos];
|
||||
dict->num_prefix++;
|
||||
/* LZ77_DICTIONARY_LENGTH bytes. */
|
||||
pos += chunk_size;
|
||||
}
|
||||
|
||||
/* NUM_WORD_LISTS */
|
||||
if (!ReadUint8(encoded, size, &pos, &dict->num_word_lists)) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
if (dict->num_word_lists > SHARED_BROTLI_NUM_DICTIONARY_CONTEXTS) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
|
||||
if (dict->num_word_lists != 0) {
|
||||
dict->words_instances = (BrotliDictionary*)dict->alloc_func(
|
||||
dict->memory_manager_opaque,
|
||||
dict->num_word_lists * sizeof(*dict->words_instances));
|
||||
if (!dict->words_instances) return BROTLI_FALSE; /* OOM */
|
||||
}
|
||||
for (i = 0; i < dict->num_word_lists; i++) {
|
||||
if (!ParseWordList(size, encoded, &pos, &dict->words_instances[i])) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* NUM_TRANSFORM_LISTS */
|
||||
if (!ReadUint8(encoded, size, &pos, &dict->num_transform_lists)) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
if (dict->num_transform_lists > SHARED_BROTLI_NUM_DICTIONARY_CONTEXTS) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
|
||||
if (dict->num_transform_lists != 0) {
|
||||
dict->transforms_instances = (BrotliTransforms*)dict->alloc_func(
|
||||
dict->memory_manager_opaque,
|
||||
dict->num_transform_lists * sizeof(*dict->transforms_instances));
|
||||
if (!dict->transforms_instances) return BROTLI_FALSE; /* OOM */
|
||||
}
|
||||
for (i = 0; i < dict->num_transform_lists; i++) {
|
||||
BROTLI_BOOL ok = BROTLI_FALSE;
|
||||
size_t prefix_suffix_count = 0;
|
||||
transform_list_start[i] = pos;
|
||||
dict->transforms_instances[i].prefix_suffix_map =
|
||||
temporary_prefix_suffix_table;
|
||||
ok = ParseTransformsList(
|
||||
size, encoded, &pos, &dict->transforms_instances[i],
|
||||
temporary_prefix_suffix_table, &prefix_suffix_count);
|
||||
if (!ok) return BROTLI_FALSE;
|
||||
total_prefix_suffix_count += prefix_suffix_count;
|
||||
}
|
||||
if (total_prefix_suffix_count != 0) {
|
||||
dict->prefix_suffix_maps = (uint16_t*)dict->alloc_func(
|
||||
dict->memory_manager_opaque,
|
||||
total_prefix_suffix_count * sizeof(*dict->prefix_suffix_maps));
|
||||
if (!dict->prefix_suffix_maps) return BROTLI_FALSE; /* OOM */
|
||||
}
|
||||
total_prefix_suffix_count = 0;
|
||||
for (i = 0; i < dict->num_transform_lists; i++) {
|
||||
size_t prefix_suffix_count = 0;
|
||||
size_t position = transform_list_start[i];
|
||||
uint16_t* prefix_suffix_map =
|
||||
&dict->prefix_suffix_maps[total_prefix_suffix_count];
|
||||
BROTLI_BOOL ok = ParsePrefixSuffixTable(
|
||||
size, encoded, &position, &dict->transforms_instances[i],
|
||||
prefix_suffix_map, &prefix_suffix_count);
|
||||
if (!ok) return BROTLI_FALSE;
|
||||
dict->transforms_instances[i].prefix_suffix_map = prefix_suffix_map;
|
||||
total_prefix_suffix_count += prefix_suffix_count;
|
||||
}
|
||||
|
||||
if (dict->num_word_lists != 0 || dict->num_transform_lists != 0) {
|
||||
if (!ReadUint8(encoded, size, &pos, &dict->num_dictionaries)) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
if (dict->num_dictionaries == 0 ||
|
||||
dict->num_dictionaries > SHARED_BROTLI_NUM_DICTIONARY_CONTEXTS) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
for (i = 0; i < dict->num_dictionaries; i++) {
|
||||
uint8_t words_index;
|
||||
uint8_t transforms_index;
|
||||
if (!ReadUint8(encoded, size, &pos, &words_index)) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
if (words_index > dict->num_word_lists) return BROTLI_FALSE;
|
||||
if (!ReadUint8(encoded, size, &pos, &transforms_index)) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
if (transforms_index > dict->num_transform_lists) return BROTLI_FALSE;
|
||||
dict->words[i] = words_index == dict->num_word_lists ?
|
||||
BrotliGetDictionary() : &dict->words_instances[words_index];
|
||||
dict->transforms[i] = transforms_index == dict->num_transform_lists ?
|
||||
BrotliGetTransforms(): &dict->transforms_instances[transforms_index];
|
||||
}
|
||||
/* CONTEXT_ENABLED */
|
||||
if (!ReadBool(encoded, size, &pos, &dict->context_based)) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
|
||||
/* CONTEXT_MAP */
|
||||
if (dict->context_based) {
|
||||
for (i = 0; i < SHARED_BROTLI_NUM_DICTIONARY_CONTEXTS; i++) {
|
||||
if (!ReadUint8(encoded, size, &pos, &dict->context_map[i])) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
if (dict->context_map[i] >= dict->num_dictionaries) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
dict->context_based = BROTLI_FALSE;
|
||||
dict->num_dictionaries = 1;
|
||||
dict->words[0] = BrotliGetDictionary();
|
||||
dict->transforms[0] = BrotliGetTransforms();
|
||||
}
|
||||
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
|
||||
/* Decodes shared dictionary and verifies correctness.
|
||||
Returns BROTLI_TRUE if dictionary is valid, BROTLI_FALSE otherwise.
|
||||
The BrotliSharedDictionary must already have been initialized. If the
|
||||
BrotliSharedDictionary already contains data, compound dictionaries
|
||||
will be appended, but an error will be returned if it already has
|
||||
custom words or transforms.
|
||||
TODO(lode): link to RFC for shared brotli once published. */
|
||||
static BROTLI_BOOL DecodeSharedDictionary(
|
||||
const uint8_t* encoded, size_t size, BrotliSharedDictionary* dict) {
|
||||
uint32_t num_prefix = 0;
|
||||
BROTLI_BOOL is_custom_static_dict = BROTLI_FALSE;
|
||||
BROTLI_BOOL has_custom_static_dict =
|
||||
dict->num_word_lists > 0 || dict->num_transform_lists > 0;
|
||||
|
||||
/* Check magic header bytes. */
|
||||
if (size < 2) return BROTLI_FALSE;
|
||||
if (encoded[0] != 0x91 || encoded[1] != 0) return BROTLI_FALSE;
|
||||
|
||||
if (!DryParseDictionary(encoded, size, &num_prefix, &is_custom_static_dict)) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
|
||||
if (num_prefix + dict->num_prefix > SHARED_BROTLI_MAX_COMPOUND_DICTS) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
|
||||
/* Cannot combine different static dictionaries, only prefix dictionaries */
|
||||
if (has_custom_static_dict && is_custom_static_dict) return BROTLI_FALSE;
|
||||
|
||||
return ParseDictionary(encoded, size, dict);
|
||||
}
|
||||
|
||||
#endif /* BROTLI_EXPERIMENTAL */
|
||||
|
||||
void BrotliSharedDictionaryDestroyInstance(
|
||||
BrotliSharedDictionary* dict) {
|
||||
if (!dict) {
|
||||
return;
|
||||
} else {
|
||||
brotli_free_func free_func = dict->free_func;
|
||||
void* opaque = dict->memory_manager_opaque;
|
||||
/* Cleanup. */
|
||||
free_func(opaque, dict->words_instances);
|
||||
free_func(opaque, dict->transforms_instances);
|
||||
free_func(opaque, dict->prefix_suffix_maps);
|
||||
/* Self-destruction. */
|
||||
free_func(opaque, dict);
|
||||
}
|
||||
}
|
||||
|
||||
BROTLI_BOOL BrotliSharedDictionaryAttach(
|
||||
BrotliSharedDictionary* dict, BrotliSharedDictionaryType type,
|
||||
size_t data_size, const uint8_t data[BROTLI_ARRAY_PARAM(data_size)]) {
|
||||
if (!dict) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
#if defined(BROTLI_EXPERIMENTAL)
|
||||
if (type == BROTLI_SHARED_DICTIONARY_SERIALIZED) {
|
||||
return DecodeSharedDictionary(data, data_size, dict);
|
||||
}
|
||||
#endif /* BROTLI_EXPERIMENTAL */
|
||||
if (type == BROTLI_SHARED_DICTIONARY_RAW) {
|
||||
if (dict->num_prefix >= SHARED_BROTLI_MAX_COMPOUND_DICTS) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
dict->prefix_size[dict->num_prefix] = data_size;
|
||||
dict->prefix[dict->num_prefix] = data;
|
||||
dict->num_prefix++;
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
|
||||
BrotliSharedDictionary* BrotliSharedDictionaryCreateInstance(
|
||||
brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque) {
|
||||
BrotliSharedDictionary* dict = 0;
|
||||
if (!alloc_func && !free_func) {
|
||||
dict = (BrotliSharedDictionary*)malloc(sizeof(BrotliSharedDictionary));
|
||||
} else if (alloc_func && free_func) {
|
||||
dict = (BrotliSharedDictionary*)alloc_func(
|
||||
opaque, sizeof(BrotliSharedDictionary));
|
||||
}
|
||||
if (dict == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* TODO(eustas): explicitly initialize all the fields? */
|
||||
memset(dict, 0, sizeof(BrotliSharedDictionary));
|
||||
|
||||
dict->context_based = BROTLI_FALSE;
|
||||
dict->num_dictionaries = 1;
|
||||
dict->num_word_lists = 0;
|
||||
dict->num_transform_lists = 0;
|
||||
|
||||
dict->words[0] = BrotliGetDictionary();
|
||||
dict->transforms[0] = BrotliGetTransforms();
|
||||
|
||||
dict->alloc_func = alloc_func ? alloc_func : BrotliDefaultAllocFunc;
|
||||
dict->free_func = free_func ? free_func : BrotliDefaultFreeFunc;
|
||||
dict->memory_manager_opaque = opaque;
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
75
c/common/shared_dictionary_internal.h
Normal file
75
c/common/shared_dictionary_internal.h
Normal file
@@ -0,0 +1,75 @@
|
||||
/* Copyright 2017 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/* (Transparent) Shared Dictionary definition. */
|
||||
|
||||
#ifndef BROTLI_COMMON_SHARED_DICTIONARY_INTERNAL_H_
|
||||
#define BROTLI_COMMON_SHARED_DICTIONARY_INTERNAL_H_
|
||||
|
||||
#include <brotli/shared_dictionary.h>
|
||||
|
||||
#include "dictionary.h"
|
||||
#include "platform.h"
|
||||
#include "transform.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct BrotliSharedDictionaryStruct {
|
||||
/* LZ77 prefixes (compound dictionary). */
|
||||
uint32_t num_prefix; /* max SHARED_BROTLI_MAX_COMPOUND_DICTS */
|
||||
size_t prefix_size[SHARED_BROTLI_MAX_COMPOUND_DICTS];
|
||||
const uint8_t* prefix[SHARED_BROTLI_MAX_COMPOUND_DICTS];
|
||||
|
||||
/* If set, the context map is used to select word and transform list from 64
|
||||
contexts, if not set, the context map is not used and only words[0] and
|
||||
transforms[0] are to be used. */
|
||||
BROTLI_BOOL context_based;
|
||||
|
||||
uint8_t context_map[SHARED_BROTLI_NUM_DICTIONARY_CONTEXTS];
|
||||
|
||||
/* Amount of word_list+transform_list combinations. */
|
||||
uint8_t num_dictionaries;
|
||||
|
||||
/* Must use num_dictionaries values. */
|
||||
const BrotliDictionary* words[SHARED_BROTLI_NUM_DICTIONARY_CONTEXTS];
|
||||
|
||||
/* Must use num_dictionaries values. */
|
||||
const BrotliTransforms* transforms[SHARED_BROTLI_NUM_DICTIONARY_CONTEXTS];
|
||||
|
||||
/* Amount of custom word lists. May be 0 if only Brotli's built-in is used */
|
||||
uint8_t num_word_lists;
|
||||
|
||||
/* Contents of the custom words lists. Must be NULL if num_word_lists is 0. */
|
||||
BrotliDictionary* words_instances;
|
||||
|
||||
/* Amount of custom transform lists. May be 0 if only Brotli's built-in is
|
||||
used */
|
||||
uint8_t num_transform_lists;
|
||||
|
||||
/* Contents of the custom transform lists. Must be NULL if num_transform_lists
|
||||
is 0. */
|
||||
BrotliTransforms* transforms_instances;
|
||||
|
||||
/* Concatenated prefix_suffix_maps of the custom transform lists. Must be NULL
|
||||
if num_transform_lists is 0. */
|
||||
uint16_t* prefix_suffix_maps;
|
||||
|
||||
/* Memory management */
|
||||
brotli_alloc_func alloc_func;
|
||||
brotli_free_func free_func;
|
||||
void* memory_manager_opaque;
|
||||
};
|
||||
|
||||
typedef struct BrotliSharedDictionaryStruct BrotliSharedDictionaryInternal;
|
||||
#define BrotliSharedDictionary BrotliSharedDictionaryInternal
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* BROTLI_COMMON_SHARED_DICTIONARY_INTERNAL_H_ */
|
||||
56
c/common/static_init.h
Normal file
56
c/common/static_init.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/* Copyright 2025 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/*
|
||||
Central point for static initialization.
|
||||
|
||||
In case of "lazy" mode `BrotliXxxLazyStaticInit` is not provided by the
|
||||
library. Embedder is responsible for providing it. This function should call
|
||||
`BrotliXxxLazyStaticInitInner` on the first invocation. This function should
|
||||
not return until execution of `BrotliXxxLazyStaticInitInner` is finished.
|
||||
In C or before C++11 it is possible to call `BrotliXxxLazyStaticInitInner`
|
||||
on start-up path and then `BrotliEncoderLazyStaticInit` is could be no-op;
|
||||
another option is to use available thread execution controls to meet the
|
||||
requirements. For possible C++11 implementation see static_init_lazy.cc.
|
||||
*/
|
||||
|
||||
#ifndef THIRD_PARTY_BROTLI_COMMON_STATIC_INIT_H_
|
||||
#define THIRD_PARTY_BROTLI_COMMON_STATIC_INIT_H_
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Static data is "initialized" in compile time. */
|
||||
#define BROTLI_STATIC_INIT_NONE 0
|
||||
/* Static data is initialized before "main". */
|
||||
#define BROTLI_STATIC_INIT_EARLY 1
|
||||
/* Static data is initialized when first encoder is created. */
|
||||
#define BROTLI_STATIC_INIT_LAZY 2
|
||||
|
||||
#define BROTLI_STATIC_INIT_DEFAULT BROTLI_STATIC_INIT_NONE
|
||||
|
||||
#if !defined(BROTLI_STATIC_INIT)
|
||||
#define BROTLI_STATIC_INIT BROTLI_STATIC_INIT_DEFAULT
|
||||
#endif
|
||||
|
||||
#if (BROTLI_STATIC_INIT != BROTLI_STATIC_INIT_NONE) && \
|
||||
(BROTLI_STATIC_INIT != BROTLI_STATIC_INIT_EARLY) && \
|
||||
(BROTLI_STATIC_INIT != BROTLI_STATIC_INIT_LAZY)
|
||||
#error Invalid value for BROTLI_STATIC_INIT
|
||||
#endif
|
||||
|
||||
#if (BROTLI_STATIC_INIT == BROTLI_STATIC_INIT_EARLY)
|
||||
#if defined(BROTLI_EXTERNAL_DICTIONARY_DATA)
|
||||
#error BROTLI_STATIC_INIT_EARLY will fail with BROTLI_EXTERNAL_DICTIONARY_DATA
|
||||
#endif
|
||||
#endif /* BROTLI_STATIC_INIT */
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif // THIRD_PARTY_BROTLI_COMMON_STATIC_INIT_H_
|
||||
80
c/common/transform.c
Executable file → Normal file
80
c/common/transform.c
Executable file → Normal file
@@ -4,14 +4,15 @@
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "./transform.h"
|
||||
#include "platform.h"
|
||||
#include "transform.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* RFC 7932 transforms string data */
|
||||
static const char kPrefixSuffix[217] =
|
||||
static const BROTLI_MODEL("small") char kPrefixSuffix[217] =
|
||||
"\1 \2, \10 of the \4 of \2s \1.\5 and \4 "
|
||||
/* 0x _0 _2 __5 _E _3 _6 _8 _E */
|
||||
"in \1\"\4 to \2\">\1\n\2. \1]\5 for \3 a \6 "
|
||||
@@ -24,10 +25,10 @@ static const char kPrefixSuffix[217] =
|
||||
/* 8x _0 _ _3 _8 _C _E _ _1 _7 _F */
|
||||
" not \3er \3al \4ful \4ive \5less \4es"
|
||||
/* Ax _5 _9 _D _2 _7 _D */
|
||||
"t \4ize \2\xc2\xa0\4ous \5 the \2e \0";
|
||||
/* Cx _2 _7___ ___ _A _F _5 _8 */
|
||||
"t \4ize \2\xc2\xa0\4ous \5 the \2e "; /* \0 - implicit trailing zero. */
|
||||
/* Cx _2 _7___ ___ _A _F _5 _8 */
|
||||
|
||||
static const uint16_t kPrefixSuffixMap[50] = {
|
||||
static const BROTLI_MODEL("small") uint16_t kPrefixSuffixMap[50] = {
|
||||
0x00, 0x02, 0x05, 0x0E, 0x13, 0x16, 0x18, 0x1E, 0x23, 0x25,
|
||||
0x2A, 0x2D, 0x2F, 0x32, 0x34, 0x3A, 0x3E, 0x45, 0x47, 0x4E,
|
||||
0x55, 0x5A, 0x5C, 0x63, 0x68, 0x6D, 0x72, 0x77, 0x7A, 0x7C,
|
||||
@@ -36,7 +37,7 @@ static const uint16_t kPrefixSuffixMap[50] = {
|
||||
};
|
||||
|
||||
/* RFC 7932 transforms */
|
||||
static const uint8_t kTransformsData[] = {
|
||||
static const BROTLI_MODEL("small") uint8_t kTransformsData[] = {
|
||||
49, BROTLI_TRANSFORM_IDENTITY, 49,
|
||||
49, BROTLI_TRANSFORM_IDENTITY, 0,
|
||||
0, BROTLI_TRANSFORM_IDENTITY, 0,
|
||||
@@ -160,12 +161,14 @@ static const uint8_t kTransformsData[] = {
|
||||
0, BROTLI_TRANSFORM_UPPERCASE_FIRST, 34,
|
||||
};
|
||||
|
||||
static BrotliTransforms kBrotliTransforms = {
|
||||
static const BROTLI_MODEL("small")
|
||||
BrotliTransforms kBrotliTransforms = {
|
||||
sizeof(kPrefixSuffix),
|
||||
(const uint8_t*)kPrefixSuffix,
|
||||
kPrefixSuffixMap,
|
||||
sizeof(kTransformsData) / (3 * sizeof(kTransformsData[0])),
|
||||
kTransformsData,
|
||||
NULL, /* no extra parameters */
|
||||
{0, 12, 27, 23, 42, 63, 56, 48, 59, 64}
|
||||
};
|
||||
|
||||
@@ -190,12 +193,54 @@ static int ToUpperCase(uint8_t* p) {
|
||||
return 3;
|
||||
}
|
||||
|
||||
static int Shift(uint8_t* word, int word_len, uint16_t parameter) {
|
||||
/* Limited sign extension: scalar < (1 << 24). */
|
||||
uint32_t scalar =
|
||||
(parameter & 0x7FFFu) + (0x1000000u - (parameter & 0x8000u));
|
||||
if (word[0] < 0x80) {
|
||||
/* 1-byte rune / 0sssssss / 7 bit scalar (ASCII). */
|
||||
scalar += (uint32_t)word[0];
|
||||
word[0] = (uint8_t)(scalar & 0x7Fu);
|
||||
return 1;
|
||||
} else if (word[0] < 0xC0) {
|
||||
/* Continuation / 10AAAAAA. */
|
||||
return 1;
|
||||
} else if (word[0] < 0xE0) {
|
||||
/* 2-byte rune / 110sssss AAssssss / 11 bit scalar. */
|
||||
if (word_len < 2) return 1;
|
||||
scalar += (uint32_t)((word[1] & 0x3Fu) | ((word[0] & 0x1Fu) << 6u));
|
||||
word[0] = (uint8_t)(0xC0 | ((scalar >> 6u) & 0x1F));
|
||||
word[1] = (uint8_t)((word[1] & 0xC0) | (scalar & 0x3F));
|
||||
return 2;
|
||||
} else if (word[0] < 0xF0) {
|
||||
/* 3-byte rune / 1110ssss AAssssss BBssssss / 16 bit scalar. */
|
||||
if (word_len < 3) return word_len;
|
||||
scalar += (uint32_t)((word[2] & 0x3Fu) | ((word[1] & 0x3Fu) << 6u) |
|
||||
((word[0] & 0x0Fu) << 12u));
|
||||
word[0] = (uint8_t)(0xE0 | ((scalar >> 12u) & 0x0F));
|
||||
word[1] = (uint8_t)((word[1] & 0xC0) | ((scalar >> 6u) & 0x3F));
|
||||
word[2] = (uint8_t)((word[2] & 0xC0) | (scalar & 0x3F));
|
||||
return 3;
|
||||
} else if (word[0] < 0xF8) {
|
||||
/* 4-byte rune / 11110sss AAssssss BBssssss CCssssss / 21 bit scalar. */
|
||||
if (word_len < 4) return word_len;
|
||||
scalar += (uint32_t)((word[3] & 0x3Fu) | ((word[2] & 0x3Fu) << 6u) |
|
||||
((word[1] & 0x3Fu) << 12u) | ((word[0] & 0x07u) << 18u));
|
||||
word[0] = (uint8_t)(0xF0 | ((scalar >> 18u) & 0x07));
|
||||
word[1] = (uint8_t)((word[1] & 0xC0) | ((scalar >> 12u) & 0x3F));
|
||||
word[2] = (uint8_t)((word[2] & 0xC0) | ((scalar >> 6u) & 0x3F));
|
||||
word[3] = (uint8_t)((word[3] & 0xC0) | (scalar & 0x3F));
|
||||
return 4;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int BrotliTransformDictionaryWord(uint8_t* dst, const uint8_t* word, int len,
|
||||
const BrotliTransforms* transforms, int transfom_idx) {
|
||||
const BrotliTransforms* transforms, int transform_idx) {
|
||||
int idx = 0;
|
||||
const uint8_t* prefix = BROTLI_TRANSFORM_PREFIX(transforms, transfom_idx);
|
||||
uint8_t type = BROTLI_TRANSFORM_TYPE(transforms, transfom_idx);
|
||||
const uint8_t* suffix = BROTLI_TRANSFORM_SUFFIX(transforms, transfom_idx);
|
||||
const uint8_t* prefix = BROTLI_TRANSFORM_PREFIX(transforms, transform_idx);
|
||||
uint8_t type = BROTLI_TRANSFORM_TYPE(transforms, transform_idx);
|
||||
const uint8_t* suffix = BROTLI_TRANSFORM_SUFFIX(transforms, transform_idx);
|
||||
{
|
||||
int prefix_len = *prefix++;
|
||||
while (prefix_len--) { dst[idx++] = *prefix++; }
|
||||
@@ -221,6 +266,19 @@ int BrotliTransformDictionaryWord(uint8_t* dst, const uint8_t* word, int len,
|
||||
uppercase += step;
|
||||
len -= step;
|
||||
}
|
||||
} else if (t == BROTLI_TRANSFORM_SHIFT_FIRST) {
|
||||
uint16_t param = (uint16_t)(transforms->params[transform_idx * 2]
|
||||
+ (transforms->params[transform_idx * 2 + 1] << 8u));
|
||||
Shift(&dst[idx - len], len, param);
|
||||
} else if (t == BROTLI_TRANSFORM_SHIFT_ALL) {
|
||||
uint16_t param = (uint16_t)(transforms->params[transform_idx * 2]
|
||||
+ (transforms->params[transform_idx * 2 + 1] << 8u));
|
||||
uint8_t* shift = &dst[idx - len];
|
||||
while (len > 0) {
|
||||
int step = Shift(shift, len, param);
|
||||
shift += step;
|
||||
len -= step;
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
|
||||
8
c/common/transform.h
Executable file → Normal file
8
c/common/transform.h
Executable file → Normal file
@@ -8,8 +8,7 @@
|
||||
#ifndef BROTLI_COMMON_TRANSFORM_H_
|
||||
#define BROTLI_COMMON_TRANSFORM_H_
|
||||
|
||||
#include <brotli/port.h>
|
||||
#include <brotli/types.h>
|
||||
#include "platform.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
@@ -37,6 +36,8 @@ enum BrotliWordTransformType {
|
||||
BROTLI_TRANSFORM_OMIT_FIRST_7 = 18,
|
||||
BROTLI_TRANSFORM_OMIT_FIRST_8 = 19,
|
||||
BROTLI_TRANSFORM_OMIT_FIRST_9 = 20,
|
||||
BROTLI_TRANSFORM_SHIFT_FIRST = 21,
|
||||
BROTLI_TRANSFORM_SHIFT_ALL = 22,
|
||||
BROTLI_NUM_TRANSFORM_TYPES /* Counts transforms, not a transform itself. */
|
||||
};
|
||||
|
||||
@@ -50,6 +51,9 @@ typedef struct BrotliTransforms {
|
||||
uint32_t num_transforms;
|
||||
/* Each entry is a [prefix_id, transform, suffix_id] triplet. */
|
||||
const uint8_t* transforms;
|
||||
/* Shift for BROTLI_TRANSFORM_SHIFT_FIRST and BROTLI_TRANSFORM_SHIFT_ALL,
|
||||
must be NULL if and only if no such transforms are present. */
|
||||
const uint8_t* params;
|
||||
/* Indices of transforms like ["", BROTLI_TRANSFORM_OMIT_LAST_#, ""].
|
||||
0-th element corresponds to ["", BROTLI_TRANSFORM_IDENTITY, ""].
|
||||
-1, if cut-off transform does not exist. */
|
||||
|
||||
@@ -9,18 +9,43 @@
|
||||
#ifndef BROTLI_COMMON_VERSION_H_
|
||||
#define BROTLI_COMMON_VERSION_H_
|
||||
|
||||
/* This macro should only be used when library is compiled together with client.
|
||||
If library is dynamically linked, use BrotliDecoderVersion and
|
||||
/* Compose 3 components into a single number. In a hexadecimal representation
|
||||
B and C components occupy exactly 3 digits. */
|
||||
#define BROTLI_MAKE_HEX_VERSION(A, B, C) ((A << 24) | (B << 12) | C)
|
||||
|
||||
/* Those macros should only be used when library is compiled together with
|
||||
the client. If library is dynamically linked, use BrotliDecoderVersion and
|
||||
BrotliEncoderVersion methods. */
|
||||
|
||||
/* Semantic version, calculated as (MAJOR << 24) | (MINOR << 12) | PATCH */
|
||||
#define BROTLI_VERSION 0x1000006
|
||||
#define BROTLI_VERSION_MAJOR 1
|
||||
#define BROTLI_VERSION_MINOR 2
|
||||
#define BROTLI_VERSION_PATCH 0
|
||||
|
||||
#define BROTLI_VERSION BROTLI_MAKE_HEX_VERSION( \
|
||||
BROTLI_VERSION_MAJOR, BROTLI_VERSION_MINOR, BROTLI_VERSION_PATCH)
|
||||
|
||||
/* This macro is used by build system to produce Libtool-friendly soname. See
|
||||
https://www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html
|
||||
Version evolution rules:
|
||||
- interfaces added (or change is compatible) -> current+1:0:age+1
|
||||
- interfaces removed (or changed is incompatible) -> current+1:0:0
|
||||
- interfaces not changed -> current:revision+1:age
|
||||
*/
|
||||
|
||||
/* ABI version, calculated as (CURRENT << 24) | (REVISION << 12) | AGE */
|
||||
#define BROTLI_ABI_VERSION 0x1006000
|
||||
#define BROTLI_ABI_CURRENT 3
|
||||
#define BROTLI_ABI_REVISION 0
|
||||
#define BROTLI_ABI_AGE 2
|
||||
|
||||
#if BROTLI_VERSION_MAJOR != (BROTLI_ABI_CURRENT - BROTLI_ABI_AGE)
|
||||
#error ABI/API version inconsistency
|
||||
#endif
|
||||
|
||||
#if BROTLI_VERSION_MINOR != BROTLI_ABI_AGE
|
||||
#error ABI/API version inconsistency
|
||||
#endif
|
||||
|
||||
#if BROTLI_VERSION_PATCH != BROTLI_ABI_REVISION
|
||||
#error ABI/API version inconsistency
|
||||
#endif
|
||||
|
||||
#endif /* BROTLI_COMMON_VERSION_H_ */
|
||||
|
||||
@@ -6,18 +6,29 @@
|
||||
|
||||
/* Bit reading helpers */
|
||||
|
||||
#include "./bit_reader.h"
|
||||
#include "bit_reader.h"
|
||||
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
const BROTLI_MODEL("small")
|
||||
brotli_reg_t kBrotliBitMask[33] = { 0x00000000,
|
||||
0x00000001, 0x00000003, 0x00000007, 0x0000000F,
|
||||
0x0000001F, 0x0000003F, 0x0000007F, 0x000000FF,
|
||||
0x000001FF, 0x000003FF, 0x000007FF, 0x00000FFF,
|
||||
0x00001FFF, 0x00003FFF, 0x00007FFF, 0x0000FFFF,
|
||||
0x0001FFFF, 0x0003FFFF, 0x0007FFFF, 0x000FFFFF,
|
||||
0x001FFFFF, 0x003FFFFF, 0x007FFFFF, 0x00FFFFFF,
|
||||
0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF, 0x0FFFFFFF,
|
||||
0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF
|
||||
};
|
||||
|
||||
void BrotliInitBitReader(BrotliBitReader* const br) {
|
||||
br->val_ = 0;
|
||||
br->bit_pos_ = sizeof(br->val_) << 3;
|
||||
br->bit_pos_ = 0;
|
||||
}
|
||||
|
||||
BROTLI_BOOL BrotliWarmupBitReader(BrotliBitReader* const br) {
|
||||
@@ -25,10 +36,11 @@ BROTLI_BOOL BrotliWarmupBitReader(BrotliBitReader* const br) {
|
||||
/* Fixing alignment after unaligned BrotliFillWindow would result accumulator
|
||||
overflow. If unalignment is caused by BrotliSafeReadBits, then there is
|
||||
enough space in accumulator to fix alignment. */
|
||||
if (!BROTLI_ALIGNED_READ) {
|
||||
if (BROTLI_UNALIGNED_READ_FAST) {
|
||||
aligned_read_mask = 0;
|
||||
}
|
||||
if (BrotliGetAvailableBits(br) == 0) {
|
||||
br->val_ = 0;
|
||||
if (!BrotliPullByte(br)) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
@@ -43,6 +55,23 @@ BROTLI_BOOL BrotliWarmupBitReader(BrotliBitReader* const br) {
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
|
||||
BROTLI_BOOL BrotliSafeReadBits32Slow(BrotliBitReader* const br,
|
||||
brotli_reg_t n_bits, brotli_reg_t* val) {
|
||||
brotli_reg_t low_val;
|
||||
brotli_reg_t high_val;
|
||||
BrotliBitReaderState memento;
|
||||
BROTLI_DCHECK(n_bits <= 32);
|
||||
BROTLI_DCHECK(n_bits > 24);
|
||||
BrotliBitReaderSaveState(br, &memento);
|
||||
if (!BrotliSafeReadBits(br, 16, &low_val) ||
|
||||
!BrotliSafeReadBits(br, n_bits - 16, &high_val)) {
|
||||
BrotliBitReaderRestoreState(br, &memento);
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
*val = low_val | (high_val << 16);
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
@@ -9,10 +9,8 @@
|
||||
#ifndef BROTLI_DEC_BIT_READER_H_
|
||||
#define BROTLI_DEC_BIT_READER_H_
|
||||
|
||||
#include <string.h> /* memcpy */
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
@@ -20,57 +18,74 @@ extern "C" {
|
||||
|
||||
#define BROTLI_SHORT_FILL_BIT_WINDOW_READ (sizeof(brotli_reg_t) >> 1)
|
||||
|
||||
static const uint32_t kBitMask[33] = { 0x00000000,
|
||||
0x00000001, 0x00000003, 0x00000007, 0x0000000F,
|
||||
0x0000001F, 0x0000003F, 0x0000007F, 0x000000FF,
|
||||
0x000001FF, 0x000003FF, 0x000007FF, 0x00000FFF,
|
||||
0x00001FFF, 0x00003FFF, 0x00007FFF, 0x0000FFFF,
|
||||
0x0001FFFF, 0x0003FFFF, 0x0007FFFF, 0x000FFFFF,
|
||||
0x001FFFFF, 0x003FFFFF, 0x007FFFFF, 0x00FFFFFF,
|
||||
0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF, 0x0FFFFFFF,
|
||||
0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF
|
||||
};
|
||||
/* 162 bits + 7 bytes */
|
||||
#define BROTLI_FAST_INPUT_SLACK 28
|
||||
|
||||
static BROTLI_INLINE uint32_t BitMask(uint32_t n) {
|
||||
BROTLI_INTERNAL extern const brotli_reg_t kBrotliBitMask[33];
|
||||
|
||||
static BROTLI_INLINE brotli_reg_t BitMask(brotli_reg_t n) {
|
||||
if (BROTLI_IS_CONSTANT(n) || BROTLI_HAS_UBFX) {
|
||||
/* Masking with this expression turns to a single
|
||||
"Unsigned Bit Field Extract" UBFX instruction on ARM. */
|
||||
return ~((0xFFFFFFFFu) << n);
|
||||
return ~(~((brotli_reg_t)0) << n);
|
||||
} else {
|
||||
return kBitMask[n];
|
||||
return kBrotliBitMask[n];
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
brotli_reg_t val_; /* pre-fetched bits */
|
||||
uint32_t bit_pos_; /* current bit-reading position in val_ */
|
||||
brotli_reg_t bit_pos_; /* current bit-reading position in val_ */
|
||||
const uint8_t* next_in; /* the byte we're reading from */
|
||||
size_t avail_in;
|
||||
const uint8_t* guard_in; /* position from which "fast-path" is prohibited */
|
||||
const uint8_t* last_in; /* == next_in + avail_in */
|
||||
} BrotliBitReader;
|
||||
|
||||
typedef struct {
|
||||
brotli_reg_t val_;
|
||||
uint32_t bit_pos_;
|
||||
brotli_reg_t bit_pos_;
|
||||
const uint8_t* next_in;
|
||||
size_t avail_in;
|
||||
} BrotliBitReaderState;
|
||||
|
||||
/* Initializes the BrotliBitReader fields. */
|
||||
BROTLI_INTERNAL void BrotliInitBitReader(BrotliBitReader* const br);
|
||||
BROTLI_INTERNAL void BrotliInitBitReader(BrotliBitReader* br);
|
||||
|
||||
/* Ensures that accumulator is not empty.
|
||||
May consume up to sizeof(brotli_reg_t) - 1 bytes of input.
|
||||
Returns BROTLI_FALSE if data is required but there is no input available.
|
||||
For BROTLI_ALIGNED_READ this function also prepares bit reader for aligned
|
||||
reading. */
|
||||
BROTLI_INTERNAL BROTLI_BOOL BrotliWarmupBitReader(BrotliBitReader* const br);
|
||||
For !BROTLI_UNALIGNED_READ_FAST this function also prepares bit reader for
|
||||
aligned reading. */
|
||||
BROTLI_INTERNAL BROTLI_BOOL BrotliWarmupBitReader(BrotliBitReader* br);
|
||||
|
||||
/* Fallback for BrotliSafeReadBits32. Extracted as noninlined method to unburden
|
||||
the main code-path. Never called for RFC brotli streams, required only for
|
||||
"large-window" mode and other extensions. */
|
||||
BROTLI_INTERNAL BROTLI_NOINLINE BROTLI_BOOL BrotliSafeReadBits32Slow(
|
||||
BrotliBitReader* br, brotli_reg_t n_bits, brotli_reg_t* val);
|
||||
|
||||
static BROTLI_INLINE size_t
|
||||
BrotliBitReaderGetAvailIn(BrotliBitReader* const br) {
|
||||
return (size_t)(br->last_in - br->next_in);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void BrotliBitReaderSaveState(
|
||||
BrotliBitReader* const from, BrotliBitReaderState* to) {
|
||||
to->val_ = from->val_;
|
||||
to->bit_pos_ = from->bit_pos_;
|
||||
to->next_in = from->next_in;
|
||||
to->avail_in = from->avail_in;
|
||||
to->avail_in = BrotliBitReaderGetAvailIn(from);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void BrotliBitReaderSetInput(
|
||||
BrotliBitReader* const br, const uint8_t* next_in, size_t avail_in) {
|
||||
br->next_in = next_in;
|
||||
br->last_in = (avail_in == 0) ? next_in : (next_in + avail_in);
|
||||
if (avail_in + 1 > BROTLI_FAST_INPUT_SLACK) {
|
||||
br->guard_in = next_in + (avail_in + 1 - BROTLI_FAST_INPUT_SLACK);
|
||||
} else {
|
||||
br->guard_in = next_in;
|
||||
}
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void BrotliBitReaderRestoreState(
|
||||
@@ -78,25 +93,40 @@ static BROTLI_INLINE void BrotliBitReaderRestoreState(
|
||||
to->val_ = from->val_;
|
||||
to->bit_pos_ = from->bit_pos_;
|
||||
to->next_in = from->next_in;
|
||||
to->avail_in = from->avail_in;
|
||||
BrotliBitReaderSetInput(to, from->next_in, from->avail_in);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE uint32_t BrotliGetAvailableBits(
|
||||
static BROTLI_INLINE brotli_reg_t BrotliGetAvailableBits(
|
||||
const BrotliBitReader* br) {
|
||||
return (BROTLI_64_BITS ? 64 : 32) - br->bit_pos_;
|
||||
return br->bit_pos_;
|
||||
}
|
||||
|
||||
/* Returns amount of unread bytes the bit reader still has buffered from the
|
||||
BrotliInput, including whole bytes in br->val_. */
|
||||
BrotliInput, including whole bytes in br->val_. Result is capped with
|
||||
maximal ring-buffer size (larger number won't be utilized anyway). */
|
||||
static BROTLI_INLINE size_t BrotliGetRemainingBytes(BrotliBitReader* br) {
|
||||
return br->avail_in + (BrotliGetAvailableBits(br) >> 3);
|
||||
static const size_t kCap = (size_t)1 << BROTLI_LARGE_MAX_WBITS;
|
||||
size_t avail_in = BrotliBitReaderGetAvailIn(br);
|
||||
if (avail_in > kCap) return kCap;
|
||||
return avail_in + (BrotliGetAvailableBits(br) >> 3);
|
||||
}
|
||||
|
||||
/* Checks if there is at least |num| bytes left in the input ring-buffer
|
||||
(excluding the bits remaining in br->val_). */
|
||||
static BROTLI_INLINE BROTLI_BOOL BrotliCheckInputAmount(
|
||||
BrotliBitReader* const br, size_t num) {
|
||||
return TO_BROTLI_BOOL(br->avail_in >= num);
|
||||
BrotliBitReader* const br) {
|
||||
return TO_BROTLI_BOOL(br->next_in < br->guard_in);
|
||||
}
|
||||
|
||||
/* Load more bits into accumulator. */
|
||||
static BROTLI_INLINE brotli_reg_t BrotliBitReaderLoadBits(brotli_reg_t val,
|
||||
brotli_reg_t new_bits,
|
||||
brotli_reg_t count,
|
||||
brotli_reg_t offset) {
|
||||
BROTLI_DCHECK(
|
||||
!((val >> offset) & ~new_bits & ~(~((brotli_reg_t)0) << count)));
|
||||
(void)count;
|
||||
return val | (new_bits << offset);
|
||||
}
|
||||
|
||||
/* Guarantees that there are at least |n_bits| + 1 bits in accumulator.
|
||||
@@ -104,49 +134,51 @@ static BROTLI_INLINE BROTLI_BOOL BrotliCheckInputAmount(
|
||||
|n_bits| should be in the range [1..24] for regular build. For portable
|
||||
non-64-bit little-endian build only 16 bits are safe to request. */
|
||||
static BROTLI_INLINE void BrotliFillBitWindow(
|
||||
BrotliBitReader* const br, uint32_t n_bits) {
|
||||
BrotliBitReader* const br, brotli_reg_t n_bits) {
|
||||
#if (BROTLI_64_BITS)
|
||||
if (!BROTLI_ALIGNED_READ && BROTLI_IS_CONSTANT(n_bits) && (n_bits <= 8)) {
|
||||
if (br->bit_pos_ >= 56) {
|
||||
br->val_ >>= 56;
|
||||
br->bit_pos_ ^= 56; /* here same as -= 56 because of the if condition */
|
||||
br->val_ |= BROTLI_UNALIGNED_LOAD64LE(br->next_in) << 8;
|
||||
br->avail_in -= 7;
|
||||
if (BROTLI_UNALIGNED_READ_FAST && BROTLI_IS_CONSTANT(n_bits) &&
|
||||
(n_bits <= 8)) {
|
||||
brotli_reg_t bit_pos = br->bit_pos_;
|
||||
if (bit_pos <= 8) {
|
||||
br->val_ = BrotliBitReaderLoadBits(br->val_,
|
||||
BROTLI_UNALIGNED_LOAD64LE(br->next_in), 56, bit_pos);
|
||||
br->bit_pos_ = bit_pos + 56;
|
||||
br->next_in += 7;
|
||||
}
|
||||
} else if (
|
||||
!BROTLI_ALIGNED_READ && BROTLI_IS_CONSTANT(n_bits) && (n_bits <= 16)) {
|
||||
if (br->bit_pos_ >= 48) {
|
||||
br->val_ >>= 48;
|
||||
br->bit_pos_ ^= 48; /* here same as -= 48 because of the if condition */
|
||||
br->val_ |= BROTLI_UNALIGNED_LOAD64LE(br->next_in) << 16;
|
||||
br->avail_in -= 6;
|
||||
} else if (BROTLI_UNALIGNED_READ_FAST && BROTLI_IS_CONSTANT(n_bits) &&
|
||||
(n_bits <= 16)) {
|
||||
brotli_reg_t bit_pos = br->bit_pos_;
|
||||
if (bit_pos <= 16) {
|
||||
br->val_ = BrotliBitReaderLoadBits(br->val_,
|
||||
BROTLI_UNALIGNED_LOAD64LE(br->next_in), 48, bit_pos);
|
||||
br->bit_pos_ = bit_pos + 48;
|
||||
br->next_in += 6;
|
||||
}
|
||||
} else {
|
||||
if (br->bit_pos_ >= 32) {
|
||||
br->val_ >>= 32;
|
||||
br->bit_pos_ ^= 32; /* here same as -= 32 because of the if condition */
|
||||
br->val_ |= ((uint64_t)BROTLI_UNALIGNED_LOAD32LE(br->next_in)) << 32;
|
||||
br->avail_in -= BROTLI_SHORT_FILL_BIT_WINDOW_READ;
|
||||
brotli_reg_t bit_pos = br->bit_pos_;
|
||||
if (bit_pos <= 32) {
|
||||
br->val_ = BrotliBitReaderLoadBits(br->val_,
|
||||
(uint64_t)BROTLI_UNALIGNED_LOAD32LE(br->next_in), 32, bit_pos);
|
||||
br->bit_pos_ = bit_pos + 32;
|
||||
br->next_in += BROTLI_SHORT_FILL_BIT_WINDOW_READ;
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (!BROTLI_ALIGNED_READ && BROTLI_IS_CONSTANT(n_bits) && (n_bits <= 8)) {
|
||||
if (br->bit_pos_ >= 24) {
|
||||
br->val_ >>= 24;
|
||||
br->bit_pos_ ^= 24; /* here same as -= 24 because of the if condition */
|
||||
br->val_ |= BROTLI_UNALIGNED_LOAD32LE(br->next_in) << 8;
|
||||
br->avail_in -= 3;
|
||||
if (BROTLI_UNALIGNED_READ_FAST && BROTLI_IS_CONSTANT(n_bits) &&
|
||||
(n_bits <= 8)) {
|
||||
brotli_reg_t bit_pos = br->bit_pos_;
|
||||
if (bit_pos <= 8) {
|
||||
br->val_ = BrotliBitReaderLoadBits(br->val_,
|
||||
BROTLI_UNALIGNED_LOAD32LE(br->next_in), 24, bit_pos);
|
||||
br->bit_pos_ = bit_pos + 24;
|
||||
br->next_in += 3;
|
||||
}
|
||||
} else {
|
||||
if (br->bit_pos_ >= 16) {
|
||||
br->val_ >>= 16;
|
||||
br->bit_pos_ ^= 16; /* here same as -= 16 because of the if condition */
|
||||
br->val_ |= ((uint32_t)BROTLI_UNALIGNED_LOAD16LE(br->next_in)) << 16;
|
||||
br->avail_in -= BROTLI_SHORT_FILL_BIT_WINDOW_READ;
|
||||
brotli_reg_t bit_pos = br->bit_pos_;
|
||||
if (bit_pos <= 16) {
|
||||
br->val_ = BrotliBitReaderLoadBits(br->val_,
|
||||
(uint32_t)BROTLI_UNALIGNED_LOAD16LE(br->next_in), 16, bit_pos);
|
||||
br->bit_pos_ = bit_pos + 16;
|
||||
br->next_in += BROTLI_SHORT_FILL_BIT_WINDOW_READ;
|
||||
}
|
||||
}
|
||||
@@ -162,17 +194,12 @@ static BROTLI_INLINE void BrotliFillBitWindow16(BrotliBitReader* const br) {
|
||||
/* Tries to pull one byte of input to accumulator.
|
||||
Returns BROTLI_FALSE if there is no input available. */
|
||||
static BROTLI_INLINE BROTLI_BOOL BrotliPullByte(BrotliBitReader* const br) {
|
||||
if (br->avail_in == 0) {
|
||||
if (br->next_in == br->last_in) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
br->val_ >>= 8;
|
||||
#if (BROTLI_64_BITS)
|
||||
br->val_ |= ((uint64_t)*br->next_in) << 56;
|
||||
#else
|
||||
br->val_ |= ((uint32_t)*br->next_in) << 24;
|
||||
#endif
|
||||
br->bit_pos_ -= 8;
|
||||
--br->avail_in;
|
||||
br->val_ = BrotliBitReaderLoadBits(br->val_,
|
||||
(brotli_reg_t)*br->next_in, 8, br->bit_pos_);
|
||||
br->bit_pos_ += 8;
|
||||
++br->next_in;
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
@@ -181,79 +208,90 @@ static BROTLI_INLINE BROTLI_BOOL BrotliPullByte(BrotliBitReader* const br) {
|
||||
The number of valid bits could be calculated by BrotliGetAvailableBits. */
|
||||
static BROTLI_INLINE brotli_reg_t BrotliGetBitsUnmasked(
|
||||
BrotliBitReader* const br) {
|
||||
return br->val_ >> br->bit_pos_;
|
||||
return br->val_;
|
||||
}
|
||||
|
||||
/* Like BrotliGetBits, but does not mask the result.
|
||||
The result contains at least 16 valid bits. */
|
||||
static BROTLI_INLINE uint32_t BrotliGet16BitsUnmasked(
|
||||
static BROTLI_INLINE brotli_reg_t BrotliGet16BitsUnmasked(
|
||||
BrotliBitReader* const br) {
|
||||
BrotliFillBitWindow(br, 16);
|
||||
return (uint32_t)BrotliGetBitsUnmasked(br);
|
||||
return (brotli_reg_t)BrotliGetBitsUnmasked(br);
|
||||
}
|
||||
|
||||
/* Returns the specified number of bits from |br| without advancing bit
|
||||
position. */
|
||||
static BROTLI_INLINE uint32_t BrotliGetBits(
|
||||
BrotliBitReader* const br, uint32_t n_bits) {
|
||||
static BROTLI_INLINE brotli_reg_t BrotliGetBits(
|
||||
BrotliBitReader* const br, brotli_reg_t n_bits) {
|
||||
BrotliFillBitWindow(br, n_bits);
|
||||
return (uint32_t)BrotliGetBitsUnmasked(br) & BitMask(n_bits);
|
||||
return BrotliGetBitsUnmasked(br) & BitMask(n_bits);
|
||||
}
|
||||
|
||||
/* Tries to peek the specified amount of bits. Returns BROTLI_FALSE, if there
|
||||
is not enough input. */
|
||||
static BROTLI_INLINE BROTLI_BOOL BrotliSafeGetBits(
|
||||
BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) {
|
||||
BrotliBitReader* const br, brotli_reg_t n_bits, brotli_reg_t* val) {
|
||||
while (BrotliGetAvailableBits(br) < n_bits) {
|
||||
if (!BrotliPullByte(br)) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
}
|
||||
*val = (uint32_t)BrotliGetBitsUnmasked(br) & BitMask(n_bits);
|
||||
*val = BrotliGetBitsUnmasked(br) & BitMask(n_bits);
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
|
||||
/* Advances the bit pos by |n_bits|. */
|
||||
static BROTLI_INLINE void BrotliDropBits(
|
||||
BrotliBitReader* const br, uint32_t n_bits) {
|
||||
br->bit_pos_ += n_bits;
|
||||
BrotliBitReader* const br, brotli_reg_t n_bits) {
|
||||
br->bit_pos_ -= n_bits;
|
||||
br->val_ >>= n_bits;
|
||||
}
|
||||
|
||||
/* Make sure that there are no spectre bits in accumulator.
|
||||
This is important for the cases when some bytes are skipped
|
||||
(i.e. never placed into accumulator). */
|
||||
static BROTLI_INLINE void BrotliBitReaderNormalize(BrotliBitReader* br) {
|
||||
/* Actually, it is enough to normalize when br->bit_pos_ == 0 */
|
||||
if (br->bit_pos_ < (sizeof(brotli_reg_t) << 3u)) {
|
||||
br->val_ &= (((brotli_reg_t)1) << br->bit_pos_) - 1;
|
||||
}
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void BrotliBitReaderUnload(BrotliBitReader* br) {
|
||||
uint32_t unused_bytes = BrotliGetAvailableBits(br) >> 3;
|
||||
uint32_t unused_bits = unused_bytes << 3;
|
||||
br->avail_in += unused_bytes;
|
||||
br->next_in -= unused_bytes;
|
||||
if (unused_bits == sizeof(br->val_) << 3) {
|
||||
br->val_ = 0;
|
||||
} else {
|
||||
br->val_ <<= unused_bits;
|
||||
}
|
||||
br->bit_pos_ += unused_bits;
|
||||
brotli_reg_t unused_bytes = BrotliGetAvailableBits(br) >> 3;
|
||||
brotli_reg_t unused_bits = unused_bytes << 3;
|
||||
br->next_in =
|
||||
(unused_bytes == 0) ? br->next_in : (br->next_in - unused_bytes);
|
||||
br->bit_pos_ -= unused_bits;
|
||||
BrotliBitReaderNormalize(br);
|
||||
}
|
||||
|
||||
/* Reads the specified number of bits from |br| and advances the bit pos.
|
||||
Precondition: accumulator MUST contain at least |n_bits|. */
|
||||
static BROTLI_INLINE void BrotliTakeBits(
|
||||
BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) {
|
||||
*val = (uint32_t)BrotliGetBitsUnmasked(br) & BitMask(n_bits);
|
||||
BROTLI_LOG(("[BrotliReadBits] %d %d %d val: %6x\n",
|
||||
(int)br->avail_in, (int)br->bit_pos_, (int)n_bits, (int)*val));
|
||||
static BROTLI_INLINE void BrotliTakeBits(BrotliBitReader* const br,
|
||||
brotli_reg_t n_bits,
|
||||
brotli_reg_t* val) {
|
||||
*val = BrotliGetBitsUnmasked(br) & BitMask(n_bits);
|
||||
BROTLI_LOG(("[BrotliTakeBits] %d %d %d val: %6x\n",
|
||||
(int)BrotliBitReaderGetAvailIn(br), (int)br->bit_pos_,
|
||||
(int)n_bits, (int)*val));
|
||||
BrotliDropBits(br, n_bits);
|
||||
}
|
||||
|
||||
/* Reads the specified number of bits from |br| and advances the bit pos.
|
||||
Assumes that there is enough input to perform BrotliFillBitWindow. */
|
||||
static BROTLI_INLINE uint32_t BrotliReadBits(
|
||||
BrotliBitReader* const br, uint32_t n_bits) {
|
||||
Assumes that there is enough input to perform BrotliFillBitWindow.
|
||||
Up to 24 bits are allowed to be requested from this method. */
|
||||
static BROTLI_INLINE brotli_reg_t BrotliReadBits24(
|
||||
BrotliBitReader* const br, brotli_reg_t n_bits) {
|
||||
BROTLI_DCHECK(n_bits <= 24);
|
||||
if (BROTLI_64_BITS || (n_bits <= 16)) {
|
||||
uint32_t val;
|
||||
brotli_reg_t val;
|
||||
BrotliFillBitWindow(br, n_bits);
|
||||
BrotliTakeBits(br, n_bits, &val);
|
||||
return val;
|
||||
} else {
|
||||
uint32_t low_val;
|
||||
uint32_t high_val;
|
||||
brotli_reg_t low_val;
|
||||
brotli_reg_t high_val;
|
||||
BrotliFillBitWindow(br, 16);
|
||||
BrotliTakeBits(br, 16, &low_val);
|
||||
BrotliFillBitWindow(br, 8);
|
||||
@@ -262,10 +300,32 @@ static BROTLI_INLINE uint32_t BrotliReadBits(
|
||||
}
|
||||
}
|
||||
|
||||
/* Same as BrotliReadBits24, but allows reading up to 32 bits. */
|
||||
static BROTLI_INLINE brotli_reg_t BrotliReadBits32(
|
||||
BrotliBitReader* const br, brotli_reg_t n_bits) {
|
||||
BROTLI_DCHECK(n_bits <= 32);
|
||||
if (BROTLI_64_BITS || (n_bits <= 16)) {
|
||||
brotli_reg_t val;
|
||||
BrotliFillBitWindow(br, n_bits);
|
||||
BrotliTakeBits(br, n_bits, &val);
|
||||
return val;
|
||||
} else {
|
||||
brotli_reg_t low_val;
|
||||
brotli_reg_t high_val;
|
||||
BrotliFillBitWindow(br, 16);
|
||||
BrotliTakeBits(br, 16, &low_val);
|
||||
BrotliFillBitWindow(br, 16);
|
||||
BrotliTakeBits(br, n_bits - 16, &high_val);
|
||||
return low_val | (high_val << 16);
|
||||
}
|
||||
}
|
||||
|
||||
/* Tries to read the specified amount of bits. Returns BROTLI_FALSE, if there
|
||||
is not enough input. |n_bits| MUST be positive. */
|
||||
is not enough input. |n_bits| MUST be positive.
|
||||
Up to 24 bits are allowed to be requested from this method. */
|
||||
static BROTLI_INLINE BROTLI_BOOL BrotliSafeReadBits(
|
||||
BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) {
|
||||
BrotliBitReader* const br, brotli_reg_t n_bits, brotli_reg_t* val) {
|
||||
BROTLI_DCHECK(n_bits <= 24);
|
||||
while (BrotliGetAvailableBits(br) < n_bits) {
|
||||
if (!BrotliPullByte(br)) {
|
||||
return BROTLI_FALSE;
|
||||
@@ -275,17 +335,42 @@ static BROTLI_INLINE BROTLI_BOOL BrotliSafeReadBits(
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
|
||||
/* Same as BrotliSafeReadBits, but allows reading up to 32 bits. */
|
||||
static BROTLI_INLINE BROTLI_BOOL BrotliSafeReadBits32(
|
||||
BrotliBitReader* const br, brotli_reg_t n_bits, brotli_reg_t* val) {
|
||||
BROTLI_DCHECK(n_bits <= 32);
|
||||
if (BROTLI_64_BITS || (n_bits <= 24)) {
|
||||
while (BrotliGetAvailableBits(br) < n_bits) {
|
||||
if (!BrotliPullByte(br)) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
}
|
||||
BrotliTakeBits(br, n_bits, val);
|
||||
return BROTLI_TRUE;
|
||||
} else {
|
||||
return BrotliSafeReadBits32Slow(br, n_bits, val);
|
||||
}
|
||||
}
|
||||
|
||||
/* Advances the bit reader position to the next byte boundary and verifies
|
||||
that any skipped bits are set to zero. */
|
||||
static BROTLI_INLINE BROTLI_BOOL BrotliJumpToByteBoundary(BrotliBitReader* br) {
|
||||
uint32_t pad_bits_count = BrotliGetAvailableBits(br) & 0x7;
|
||||
uint32_t pad_bits = 0;
|
||||
brotli_reg_t pad_bits_count = BrotliGetAvailableBits(br) & 0x7;
|
||||
brotli_reg_t pad_bits = 0;
|
||||
if (pad_bits_count != 0) {
|
||||
BrotliTakeBits(br, pad_bits_count, &pad_bits);
|
||||
}
|
||||
BrotliBitReaderNormalize(br);
|
||||
return TO_BROTLI_BOOL(pad_bits == 0);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void BrotliDropBytes(BrotliBitReader* br, size_t num) {
|
||||
/* Check detour is legal: accumulator must to be empty. */
|
||||
BROTLI_DCHECK(br->bit_pos_ == 0);
|
||||
BROTLI_DCHECK(br->val_ == 0);
|
||||
br->next_in += num;
|
||||
}
|
||||
|
||||
/* Copies remaining input bytes stored in the bit reader to the output. Value
|
||||
|num| may not be larger than BrotliGetRemainingBytes. The bit reader must be
|
||||
warmed up again after this. */
|
||||
@@ -297,9 +382,34 @@ static BROTLI_INLINE void BrotliCopyBytes(uint8_t* dest,
|
||||
++dest;
|
||||
--num;
|
||||
}
|
||||
memcpy(dest, br->next_in, num);
|
||||
br->avail_in -= num;
|
||||
br->next_in += num;
|
||||
BrotliBitReaderNormalize(br);
|
||||
if (num > 0) {
|
||||
memcpy(dest, br->next_in, num);
|
||||
BrotliDropBytes(br, num);
|
||||
}
|
||||
}
|
||||
|
||||
BROTLI_UNUSED_FUNCTION void BrotliBitReaderSuppressUnusedFunctions(void) {
|
||||
BROTLI_UNUSED(&BrotliBitReaderSuppressUnusedFunctions);
|
||||
|
||||
BROTLI_UNUSED(&BrotliBitReaderGetAvailIn);
|
||||
BROTLI_UNUSED(&BrotliBitReaderLoadBits);
|
||||
BROTLI_UNUSED(&BrotliBitReaderRestoreState);
|
||||
BROTLI_UNUSED(&BrotliBitReaderSaveState);
|
||||
BROTLI_UNUSED(&BrotliBitReaderSetInput);
|
||||
BROTLI_UNUSED(&BrotliBitReaderUnload);
|
||||
BROTLI_UNUSED(&BrotliCheckInputAmount);
|
||||
BROTLI_UNUSED(&BrotliCopyBytes);
|
||||
BROTLI_UNUSED(&BrotliFillBitWindow16);
|
||||
BROTLI_UNUSED(&BrotliGet16BitsUnmasked);
|
||||
BROTLI_UNUSED(&BrotliGetBits);
|
||||
BROTLI_UNUSED(&BrotliGetRemainingBytes);
|
||||
BROTLI_UNUSED(&BrotliJumpToByteBoundary);
|
||||
BROTLI_UNUSED(&BrotliReadBits24);
|
||||
BROTLI_UNUSED(&BrotliReadBits32);
|
||||
BROTLI_UNUSED(&BrotliSafeGetBits);
|
||||
BROTLI_UNUSED(&BrotliSafeReadBits);
|
||||
BROTLI_UNUSED(&BrotliSafeReadBits32);
|
||||
}
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
|
||||
1403
c/dec/decode.c
1403
c/dec/decode.c
File diff suppressed because it is too large
Load Diff
@@ -6,13 +6,10 @@
|
||||
|
||||
/* Utilities for building Huffman decoding tables. */
|
||||
|
||||
#include "./huffman.h"
|
||||
|
||||
#include <string.h> /* memcpy, memset */
|
||||
#include "huffman.h"
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
@@ -25,7 +22,8 @@ extern "C" {
|
||||
((sizeof(brotli_reg_t) << 3) - BROTLI_REVERSE_BITS_MAX)
|
||||
#else
|
||||
#define BROTLI_REVERSE_BITS_BASE 0
|
||||
static uint8_t kReverseBits[1 << BROTLI_REVERSE_BITS_MAX] = {
|
||||
static BROTLI_MODEL("small")
|
||||
uint8_t kReverseBits[1 << BROTLI_REVERSE_BITS_MAX] = {
|
||||
0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,
|
||||
0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
|
||||
0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
|
||||
@@ -117,11 +115,13 @@ void BrotliBuildCodeLengthsHuffmanTable(HuffmanCode* table,
|
||||
int bits_count;
|
||||
BROTLI_DCHECK(BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH <=
|
||||
BROTLI_REVERSE_BITS_MAX);
|
||||
BROTLI_DCHECK(BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH == 5);
|
||||
|
||||
/* Generate offsets into sorted symbol table by code length. */
|
||||
symbol = -1;
|
||||
bits = 1;
|
||||
BROTLI_REPEAT(BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH, {
|
||||
/* BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH == 5 */
|
||||
BROTLI_REPEAT_5({
|
||||
symbol += count[bits];
|
||||
offset[bits] = symbol;
|
||||
bits++;
|
||||
@@ -132,7 +132,7 @@ void BrotliBuildCodeLengthsHuffmanTable(HuffmanCode* table,
|
||||
/* Sort symbols by length, by symbol order within each length. */
|
||||
symbol = BROTLI_CODE_LENGTH_CODES;
|
||||
do {
|
||||
BROTLI_REPEAT(6, {
|
||||
BROTLI_REPEAT_6({
|
||||
symbol--;
|
||||
sorted[offset[code_lengths[symbol]]--] = symbol;
|
||||
});
|
||||
@@ -142,8 +142,7 @@ void BrotliBuildCodeLengthsHuffmanTable(HuffmanCode* table,
|
||||
|
||||
/* Special case: all symbols but one have 0 code length. */
|
||||
if (offset[0] == 0) {
|
||||
code.bits = 0;
|
||||
code.value = (uint16_t)sorted[0];
|
||||
code = ConstructHuffmanCode(0, (uint16_t)sorted[0]);
|
||||
for (key = 0; key < (brotli_reg_t)table_size; ++key) {
|
||||
table[key] = code;
|
||||
}
|
||||
@@ -157,9 +156,8 @@ void BrotliBuildCodeLengthsHuffmanTable(HuffmanCode* table,
|
||||
bits = 1;
|
||||
step = 2;
|
||||
do {
|
||||
code.bits = (uint8_t)bits;
|
||||
for (bits_count = count[bits]; bits_count != 0; --bits_count) {
|
||||
code.value = (uint16_t)sorted[symbol++];
|
||||
code = ConstructHuffmanCode((uint8_t)bits, (uint16_t)sorted[symbol++]);
|
||||
ReplicateValue(&table[BrotliReverseBits(key)], step, table_size, code);
|
||||
key += key_step;
|
||||
}
|
||||
@@ -211,11 +209,10 @@ uint32_t BrotliBuildHuffmanTable(HuffmanCode* root_table,
|
||||
bits = 1;
|
||||
step = 2;
|
||||
do {
|
||||
code.bits = (uint8_t)bits;
|
||||
symbol = bits - (BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1);
|
||||
for (bits_count = count[bits]; bits_count != 0; --bits_count) {
|
||||
symbol = symbol_lists[symbol];
|
||||
code.value = (uint16_t)symbol;
|
||||
code = ConstructHuffmanCode((uint8_t)bits, (uint16_t)symbol);
|
||||
ReplicateValue(&table[BrotliReverseBits(key)], step, table_size, code);
|
||||
key += key_step;
|
||||
}
|
||||
@@ -244,14 +241,13 @@ uint32_t BrotliBuildHuffmanTable(HuffmanCode* root_table,
|
||||
total_size += table_size;
|
||||
sub_key = BrotliReverseBits(key);
|
||||
key += key_step;
|
||||
root_table[sub_key].bits = (uint8_t)(table_bits + root_bits);
|
||||
root_table[sub_key].value =
|
||||
(uint16_t)(((size_t)(table - root_table)) - sub_key);
|
||||
root_table[sub_key] = ConstructHuffmanCode(
|
||||
(uint8_t)(table_bits + root_bits),
|
||||
(uint16_t)(((size_t)(table - root_table)) - sub_key));
|
||||
sub_key = 0;
|
||||
}
|
||||
code.bits = (uint8_t)(len - root_bits);
|
||||
symbol = symbol_lists[symbol];
|
||||
code.value = (uint16_t)symbol;
|
||||
code = ConstructHuffmanCode((uint8_t)(len - root_bits), (uint16_t)symbol);
|
||||
ReplicateValue(
|
||||
&table[BrotliReverseBits(sub_key)], step, table_size, code);
|
||||
sub_key += sub_key_step;
|
||||
@@ -270,35 +266,28 @@ uint32_t BrotliBuildSimpleHuffmanTable(HuffmanCode* table,
|
||||
const uint32_t goal_size = 1U << root_bits;
|
||||
switch (num_symbols) {
|
||||
case 0:
|
||||
table[0].bits = 0;
|
||||
table[0].value = val[0];
|
||||
table[0] = ConstructHuffmanCode(0, val[0]);
|
||||
break;
|
||||
case 1:
|
||||
table[0].bits = 1;
|
||||
table[1].bits = 1;
|
||||
if (val[1] > val[0]) {
|
||||
table[0].value = val[0];
|
||||
table[1].value = val[1];
|
||||
table[0] = ConstructHuffmanCode(1, val[0]);
|
||||
table[1] = ConstructHuffmanCode(1, val[1]);
|
||||
} else {
|
||||
table[0].value = val[1];
|
||||
table[1].value = val[0];
|
||||
table[0] = ConstructHuffmanCode(1, val[1]);
|
||||
table[1] = ConstructHuffmanCode(1, val[0]);
|
||||
}
|
||||
table_size = 2;
|
||||
break;
|
||||
case 2:
|
||||
table[0].bits = 1;
|
||||
table[0].value = val[0];
|
||||
table[2].bits = 1;
|
||||
table[2].value = val[0];
|
||||
table[0] = ConstructHuffmanCode(1, val[0]);
|
||||
table[2] = ConstructHuffmanCode(1, val[0]);
|
||||
if (val[2] > val[1]) {
|
||||
table[1].value = val[1];
|
||||
table[3].value = val[2];
|
||||
table[1] = ConstructHuffmanCode(2, val[1]);
|
||||
table[3] = ConstructHuffmanCode(2, val[2]);
|
||||
} else {
|
||||
table[1].value = val[2];
|
||||
table[3].value = val[1];
|
||||
table[1] = ConstructHuffmanCode(2, val[2]);
|
||||
table[3] = ConstructHuffmanCode(2, val[1]);
|
||||
}
|
||||
table[1].bits = 2;
|
||||
table[3].bits = 2;
|
||||
table_size = 4;
|
||||
break;
|
||||
case 3: {
|
||||
@@ -312,33 +301,27 @@ uint32_t BrotliBuildSimpleHuffmanTable(HuffmanCode* table,
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i = 0; i < 4; ++i) {
|
||||
table[i].bits = 2;
|
||||
}
|
||||
table[0].value = val[0];
|
||||
table[2].value = val[1];
|
||||
table[1].value = val[2];
|
||||
table[3].value = val[3];
|
||||
table[0] = ConstructHuffmanCode(2, val[0]);
|
||||
table[2] = ConstructHuffmanCode(2, val[1]);
|
||||
table[1] = ConstructHuffmanCode(2, val[2]);
|
||||
table[3] = ConstructHuffmanCode(2, val[3]);
|
||||
table_size = 4;
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
int i;
|
||||
if (val[3] < val[2]) {
|
||||
uint16_t t = val[3];
|
||||
val[3] = val[2];
|
||||
val[2] = t;
|
||||
}
|
||||
for (i = 0; i < 7; ++i) {
|
||||
table[i].value = val[0];
|
||||
table[i].bits = (uint8_t)(1 + (i & 1));
|
||||
}
|
||||
table[1].value = val[1];
|
||||
table[3].value = val[2];
|
||||
table[5].value = val[1];
|
||||
table[7].value = val[3];
|
||||
table[3].bits = 3;
|
||||
table[7].bits = 3;
|
||||
table[0] = ConstructHuffmanCode(1, val[0]);
|
||||
table[1] = ConstructHuffmanCode(2, val[1]);
|
||||
table[2] = ConstructHuffmanCode(1, val[0]);
|
||||
table[3] = ConstructHuffmanCode(3, val[2]);
|
||||
table[4] = ConstructHuffmanCode(1, val[0]);
|
||||
table[5] = ConstructHuffmanCode(2, val[1]);
|
||||
table[6] = ConstructHuffmanCode(1, val[0]);
|
||||
table[7] = ConstructHuffmanCode(3, val[3]);
|
||||
table_size = 8;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#define BROTLI_DEC_HUFFMAN_H_
|
||||
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
@@ -18,12 +17,6 @@ extern "C" {
|
||||
|
||||
#define BROTLI_HUFFMAN_MAX_CODE_LENGTH 15
|
||||
|
||||
/* Maximum possible Huffman table size for an alphabet size of (index * 32),
|
||||
max code length 15 and root table bits 8. */
|
||||
static const uint16_t kMaxHuffmanTableSize[] = {
|
||||
256, 402, 436, 468, 500, 534, 566, 598, 630, 662, 694, 726, 758, 790, 822,
|
||||
854, 886, 920, 952, 984, 1016, 1048, 1080, 1112, 1144, 1176, 1208, 1240, 1272,
|
||||
1304, 1336, 1368, 1400, 1432, 1464, 1496, 1528};
|
||||
/* BROTLI_NUM_BLOCK_LEN_SYMBOLS == 26 */
|
||||
#define BROTLI_HUFFMAN_MAX_SIZE_26 396
|
||||
/* BROTLI_MAX_BLOCK_TYPE_SYMBOLS == 258 */
|
||||
@@ -33,11 +26,66 @@ static const uint16_t kMaxHuffmanTableSize[] = {
|
||||
|
||||
#define BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH 5
|
||||
|
||||
#if ((defined(BROTLI_TARGET_ARMV7) || defined(BROTLI_TARGET_ARMV8_32)) && \
|
||||
BROTLI_GNUC_HAS_ATTRIBUTE(aligned, 2, 7, 0))
|
||||
#define BROTLI_HUFFMAN_CODE_FAST_LOAD
|
||||
#endif
|
||||
|
||||
#if !defined(BROTLI_HUFFMAN_CODE_FAST_LOAD)
|
||||
/* Do not create this struct directly - use the ConstructHuffmanCode
|
||||
* constructor below! */
|
||||
typedef struct {
|
||||
uint8_t bits; /* number of bits used for this symbol */
|
||||
uint16_t value; /* symbol value or table offset */
|
||||
} HuffmanCode;
|
||||
|
||||
static BROTLI_INLINE HuffmanCode ConstructHuffmanCode(const uint8_t bits,
|
||||
const uint16_t value) {
|
||||
HuffmanCode h;
|
||||
h.bits = bits;
|
||||
h.value = value;
|
||||
return h;
|
||||
}
|
||||
|
||||
/* Please use the following macros to optimize HuffmanCode accesses in hot
|
||||
* paths.
|
||||
*
|
||||
* For example, assuming |table| contains a HuffmanCode pointer:
|
||||
*
|
||||
* BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(table);
|
||||
* BROTLI_HC_ADJUST_TABLE_INDEX(table, index_into_table);
|
||||
* *bits = BROTLI_HC_GET_BITS(table);
|
||||
* *value = BROTLI_HC_GET_VALUE(table);
|
||||
* BROTLI_HC_ADJUST_TABLE_INDEX(table, offset);
|
||||
* *bits2 = BROTLI_HC_GET_BITS(table);
|
||||
* *value2 = BROTLI_HC_GET_VALUE(table);
|
||||
*
|
||||
*/
|
||||
|
||||
#define BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(H)
|
||||
#define BROTLI_HC_ADJUST_TABLE_INDEX(H, V) H += (V)
|
||||
|
||||
/* These must be given a HuffmanCode pointer! */
|
||||
#define BROTLI_HC_FAST_LOAD_BITS(H) (H->bits)
|
||||
#define BROTLI_HC_FAST_LOAD_VALUE(H) (H->value)
|
||||
|
||||
#else /* BROTLI_HUFFMAN_CODE_FAST_LOAD */
|
||||
|
||||
typedef BROTLI_ALIGNED(4) uint32_t HuffmanCode;
|
||||
|
||||
static BROTLI_INLINE HuffmanCode ConstructHuffmanCode(const uint8_t bits,
|
||||
const uint16_t value) {
|
||||
return (HuffmanCode) ((value & 0xFFFF) << 16) | (bits & 0xFF);
|
||||
}
|
||||
|
||||
#define BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(H) uint32_t __fastload_##H = (*H)
|
||||
#define BROTLI_HC_ADJUST_TABLE_INDEX(H, V) H += (V); __fastload_##H = (*H)
|
||||
|
||||
/* These must be given a HuffmanCode pointer! */
|
||||
#define BROTLI_HC_FAST_LOAD_BITS(H) ((__fastload_##H) & 0xFF)
|
||||
#define BROTLI_HC_FAST_LOAD_VALUE(H) ((__fastload_##H) >> 16)
|
||||
#endif /* BROTLI_HUFFMAN_CODE_FAST_LOAD */
|
||||
|
||||
/* Builds Huffman lookup table assuming code lengths are in symbol order. */
|
||||
BROTLI_INTERNAL void BrotliBuildCodeLengthsHuffmanTable(HuffmanCode* root_table,
|
||||
const uint8_t* const code_lengths, uint16_t* count);
|
||||
@@ -45,7 +93,7 @@ BROTLI_INTERNAL void BrotliBuildCodeLengthsHuffmanTable(HuffmanCode* root_table,
|
||||
/* Builds Huffman lookup table assuming code lengths are in symbol order.
|
||||
Returns size of resulting table. */
|
||||
BROTLI_INTERNAL uint32_t BrotliBuildHuffmanTable(HuffmanCode* root_table,
|
||||
int root_bits, const uint16_t* const symbol_lists, uint16_t* count_arg);
|
||||
int root_bits, const uint16_t* const symbol_lists, uint16_t* count);
|
||||
|
||||
/* Builds a simple Huffman table. The |num_symbols| parameter is to be
|
||||
interpreted as follows: 0 means 1 symbol, 1 means 2 symbols,
|
||||
@@ -55,13 +103,13 @@ BROTLI_INTERNAL uint32_t BrotliBuildSimpleHuffmanTable(HuffmanCode* table,
|
||||
int root_bits, uint16_t* symbols, uint32_t num_symbols);
|
||||
|
||||
/* Contains a collection of Huffman trees with the same alphabet size. */
|
||||
/* max_symbol is needed due to simple codes since log2(alphabet_size) could be
|
||||
greater than log2(max_symbol). */
|
||||
/* alphabet_size_limit is needed due to simple codes, since
|
||||
log2(alphabet_size_max) could be greater than log2(alphabet_size_limit). */
|
||||
typedef struct {
|
||||
HuffmanCode** htrees;
|
||||
HuffmanCode* codes;
|
||||
uint16_t alphabet_size;
|
||||
uint16_t max_symbol;
|
||||
uint16_t alphabet_size_max;
|
||||
uint16_t alphabet_size_limit;
|
||||
uint16_t num_htrees;
|
||||
} HuffmanTreeGroup;
|
||||
|
||||
|
||||
67
c/dec/prefix.c
Normal file
67
c/dec/prefix.c
Normal file
@@ -0,0 +1,67 @@
|
||||
/* Copyright 2025 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "prefix.h"
|
||||
|
||||
#include "../common/platform.h" /* IWYU pragma: keep */
|
||||
#include "../common/static_init.h"
|
||||
|
||||
#if (BROTLI_STATIC_INIT != BROTLI_STATIC_INIT_NONE)
|
||||
#include "../common/constants.h"
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if (BROTLI_STATIC_INIT == BROTLI_STATIC_INIT_NONE)
|
||||
/* Embed kCmdLut. */
|
||||
#include "prefix_inc.h"
|
||||
#else
|
||||
BROTLI_COLD BROTLI_BOOL BrotliDecoderInitCmdLut(CmdLutElement* items) {
|
||||
static const uint8_t kInsertLengthExtraBits[24] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03,
|
||||
0x04, 0x04, 0x05, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0C, 0x0E, 0x18};
|
||||
static const uint8_t kCopyLengthExtraBits[24] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02,
|
||||
0x03, 0x03, 0x04, 0x04, 0x05, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x18};
|
||||
static const uint8_t kCellPos[11] = {0, 1, 0, 1, 8, 9, 2, 16, 10, 17, 18};
|
||||
|
||||
uint16_t insert_length_offsets[24];
|
||||
uint16_t copy_length_offsets[24];
|
||||
insert_length_offsets[0] = 0;
|
||||
copy_length_offsets[0] = 2;
|
||||
for (size_t i = 0; i < 23; ++i) {
|
||||
insert_length_offsets[i + 1] =
|
||||
insert_length_offsets[i] + (uint16_t)(1u << kInsertLengthExtraBits[i]);
|
||||
copy_length_offsets[i + 1] =
|
||||
copy_length_offsets[i] + (uint16_t)(1u << kCopyLengthExtraBits[i]);
|
||||
}
|
||||
|
||||
for (size_t symbol = 0; symbol < BROTLI_NUM_COMMAND_SYMBOLS; ++symbol) {
|
||||
CmdLutElement* item = items + symbol;
|
||||
const size_t cell_idx = symbol >> 6;
|
||||
const size_t cell_pos = kCellPos[cell_idx];
|
||||
const size_t copy_code = ((cell_pos << 3) & 0x18) + (symbol & 0x7);
|
||||
const uint16_t copy_len_offset = copy_length_offsets[copy_code];
|
||||
const size_t insert_code = (cell_pos & 0x18) + ((symbol >> 3) & 0x7);
|
||||
item->copy_len_extra_bits = kCopyLengthExtraBits[copy_code];
|
||||
item->context = (copy_len_offset > 4) ? 3 : ((uint8_t)copy_len_offset - 2);
|
||||
item->copy_len_offset = copy_len_offset;
|
||||
item->distance_code = (cell_idx >= 2) ? -1 : 0;
|
||||
item->insert_len_extra_bits = kInsertLengthExtraBits[insert_code];
|
||||
item->insert_len_offset = insert_length_offsets[insert_code];
|
||||
}
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
|
||||
BROTLI_MODEL("small")
|
||||
CmdLutElement kCmdLut[BROTLI_NUM_COMMAND_SYMBOLS];
|
||||
#endif /* BROTLI_STATIC_INIT */
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
741
c/dec/prefix.h
741
c/dec/prefix.h
@@ -11,25 +11,12 @@
|
||||
#define BROTLI_DEC_PREFIX_H_
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include <brotli/types.h>
|
||||
#include "../common/platform.h" /* IWYU pragma: keep */
|
||||
#include "../common/static_init.h"
|
||||
|
||||
/* Represents the range of values belonging to a prefix code:
|
||||
[offset, offset + 2^nbits) */
|
||||
struct PrefixCodeRange {
|
||||
uint16_t offset;
|
||||
uint8_t nbits;
|
||||
};
|
||||
|
||||
static const struct PrefixCodeRange
|
||||
kBlockLengthPrefixCode[BROTLI_NUM_BLOCK_LEN_SYMBOLS] = {
|
||||
{ 1, 2}, { 5, 2}, { 9, 2}, { 13, 2},
|
||||
{ 17, 3}, { 25, 3}, { 33, 3}, { 41, 3},
|
||||
{ 49, 4}, { 65, 4}, { 81, 4}, { 97, 4},
|
||||
{ 113, 5}, { 145, 5}, { 177, 5}, { 209, 5},
|
||||
{ 241, 6}, { 305, 6}, { 369, 7}, { 497, 8},
|
||||
{ 753, 9}, { 1265, 10}, {2289, 11}, {4337, 12},
|
||||
{8433, 13}, {16625, 24}
|
||||
};
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct CmdLutElement {
|
||||
uint8_t insert_len_extra_bits;
|
||||
@@ -40,711 +27,17 @@ typedef struct CmdLutElement {
|
||||
uint16_t copy_len_offset;
|
||||
} CmdLutElement;
|
||||
|
||||
static const CmdLutElement kCmdLut[BROTLI_NUM_COMMAND_SYMBOLS] = {
|
||||
{ 0x00, 0x00, 0, 0x00, 0x0000, 0x0002 },
|
||||
{ 0x00, 0x00, 0, 0x01, 0x0000, 0x0003 },
|
||||
{ 0x00, 0x00, 0, 0x02, 0x0000, 0x0004 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0000, 0x0005 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0000, 0x0006 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0000, 0x0007 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0000, 0x0008 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0000, 0x0009 },
|
||||
{ 0x00, 0x00, 0, 0x00, 0x0001, 0x0002 },
|
||||
{ 0x00, 0x00, 0, 0x01, 0x0001, 0x0003 },
|
||||
{ 0x00, 0x00, 0, 0x02, 0x0001, 0x0004 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0001, 0x0005 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0001, 0x0006 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0001, 0x0007 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0001, 0x0008 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0001, 0x0009 },
|
||||
{ 0x00, 0x00, 0, 0x00, 0x0002, 0x0002 },
|
||||
{ 0x00, 0x00, 0, 0x01, 0x0002, 0x0003 },
|
||||
{ 0x00, 0x00, 0, 0x02, 0x0002, 0x0004 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0002, 0x0005 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0002, 0x0006 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0002, 0x0007 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0002, 0x0008 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0002, 0x0009 },
|
||||
{ 0x00, 0x00, 0, 0x00, 0x0003, 0x0002 },
|
||||
{ 0x00, 0x00, 0, 0x01, 0x0003, 0x0003 },
|
||||
{ 0x00, 0x00, 0, 0x02, 0x0003, 0x0004 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0003, 0x0005 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0003, 0x0006 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0003, 0x0007 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0003, 0x0008 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0003, 0x0009 },
|
||||
{ 0x00, 0x00, 0, 0x00, 0x0004, 0x0002 },
|
||||
{ 0x00, 0x00, 0, 0x01, 0x0004, 0x0003 },
|
||||
{ 0x00, 0x00, 0, 0x02, 0x0004, 0x0004 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0004, 0x0005 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0004, 0x0006 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0004, 0x0007 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0004, 0x0008 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0004, 0x0009 },
|
||||
{ 0x00, 0x00, 0, 0x00, 0x0005, 0x0002 },
|
||||
{ 0x00, 0x00, 0, 0x01, 0x0005, 0x0003 },
|
||||
{ 0x00, 0x00, 0, 0x02, 0x0005, 0x0004 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0005, 0x0005 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0005, 0x0006 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0005, 0x0007 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0005, 0x0008 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0005, 0x0009 },
|
||||
{ 0x01, 0x00, 0, 0x00, 0x0006, 0x0002 },
|
||||
{ 0x01, 0x00, 0, 0x01, 0x0006, 0x0003 },
|
||||
{ 0x01, 0x00, 0, 0x02, 0x0006, 0x0004 },
|
||||
{ 0x01, 0x00, 0, 0x03, 0x0006, 0x0005 },
|
||||
{ 0x01, 0x00, 0, 0x03, 0x0006, 0x0006 },
|
||||
{ 0x01, 0x00, 0, 0x03, 0x0006, 0x0007 },
|
||||
{ 0x01, 0x00, 0, 0x03, 0x0006, 0x0008 },
|
||||
{ 0x01, 0x00, 0, 0x03, 0x0006, 0x0009 },
|
||||
{ 0x01, 0x00, 0, 0x00, 0x0008, 0x0002 },
|
||||
{ 0x01, 0x00, 0, 0x01, 0x0008, 0x0003 },
|
||||
{ 0x01, 0x00, 0, 0x02, 0x0008, 0x0004 },
|
||||
{ 0x01, 0x00, 0, 0x03, 0x0008, 0x0005 },
|
||||
{ 0x01, 0x00, 0, 0x03, 0x0008, 0x0006 },
|
||||
{ 0x01, 0x00, 0, 0x03, 0x0008, 0x0007 },
|
||||
{ 0x01, 0x00, 0, 0x03, 0x0008, 0x0008 },
|
||||
{ 0x01, 0x00, 0, 0x03, 0x0008, 0x0009 },
|
||||
{ 0x00, 0x01, 0, 0x03, 0x0000, 0x000a },
|
||||
{ 0x00, 0x01, 0, 0x03, 0x0000, 0x000c },
|
||||
{ 0x00, 0x02, 0, 0x03, 0x0000, 0x000e },
|
||||
{ 0x00, 0x02, 0, 0x03, 0x0000, 0x0012 },
|
||||
{ 0x00, 0x03, 0, 0x03, 0x0000, 0x0016 },
|
||||
{ 0x00, 0x03, 0, 0x03, 0x0000, 0x001e },
|
||||
{ 0x00, 0x04, 0, 0x03, 0x0000, 0x0026 },
|
||||
{ 0x00, 0x04, 0, 0x03, 0x0000, 0x0036 },
|
||||
{ 0x00, 0x01, 0, 0x03, 0x0001, 0x000a },
|
||||
{ 0x00, 0x01, 0, 0x03, 0x0001, 0x000c },
|
||||
{ 0x00, 0x02, 0, 0x03, 0x0001, 0x000e },
|
||||
{ 0x00, 0x02, 0, 0x03, 0x0001, 0x0012 },
|
||||
{ 0x00, 0x03, 0, 0x03, 0x0001, 0x0016 },
|
||||
{ 0x00, 0x03, 0, 0x03, 0x0001, 0x001e },
|
||||
{ 0x00, 0x04, 0, 0x03, 0x0001, 0x0026 },
|
||||
{ 0x00, 0x04, 0, 0x03, 0x0001, 0x0036 },
|
||||
{ 0x00, 0x01, 0, 0x03, 0x0002, 0x000a },
|
||||
{ 0x00, 0x01, 0, 0x03, 0x0002, 0x000c },
|
||||
{ 0x00, 0x02, 0, 0x03, 0x0002, 0x000e },
|
||||
{ 0x00, 0x02, 0, 0x03, 0x0002, 0x0012 },
|
||||
{ 0x00, 0x03, 0, 0x03, 0x0002, 0x0016 },
|
||||
{ 0x00, 0x03, 0, 0x03, 0x0002, 0x001e },
|
||||
{ 0x00, 0x04, 0, 0x03, 0x0002, 0x0026 },
|
||||
{ 0x00, 0x04, 0, 0x03, 0x0002, 0x0036 },
|
||||
{ 0x00, 0x01, 0, 0x03, 0x0003, 0x000a },
|
||||
{ 0x00, 0x01, 0, 0x03, 0x0003, 0x000c },
|
||||
{ 0x00, 0x02, 0, 0x03, 0x0003, 0x000e },
|
||||
{ 0x00, 0x02, 0, 0x03, 0x0003, 0x0012 },
|
||||
{ 0x00, 0x03, 0, 0x03, 0x0003, 0x0016 },
|
||||
{ 0x00, 0x03, 0, 0x03, 0x0003, 0x001e },
|
||||
{ 0x00, 0x04, 0, 0x03, 0x0003, 0x0026 },
|
||||
{ 0x00, 0x04, 0, 0x03, 0x0003, 0x0036 },
|
||||
{ 0x00, 0x01, 0, 0x03, 0x0004, 0x000a },
|
||||
{ 0x00, 0x01, 0, 0x03, 0x0004, 0x000c },
|
||||
{ 0x00, 0x02, 0, 0x03, 0x0004, 0x000e },
|
||||
{ 0x00, 0x02, 0, 0x03, 0x0004, 0x0012 },
|
||||
{ 0x00, 0x03, 0, 0x03, 0x0004, 0x0016 },
|
||||
{ 0x00, 0x03, 0, 0x03, 0x0004, 0x001e },
|
||||
{ 0x00, 0x04, 0, 0x03, 0x0004, 0x0026 },
|
||||
{ 0x00, 0x04, 0, 0x03, 0x0004, 0x0036 },
|
||||
{ 0x00, 0x01, 0, 0x03, 0x0005, 0x000a },
|
||||
{ 0x00, 0x01, 0, 0x03, 0x0005, 0x000c },
|
||||
{ 0x00, 0x02, 0, 0x03, 0x0005, 0x000e },
|
||||
{ 0x00, 0x02, 0, 0x03, 0x0005, 0x0012 },
|
||||
{ 0x00, 0x03, 0, 0x03, 0x0005, 0x0016 },
|
||||
{ 0x00, 0x03, 0, 0x03, 0x0005, 0x001e },
|
||||
{ 0x00, 0x04, 0, 0x03, 0x0005, 0x0026 },
|
||||
{ 0x00, 0x04, 0, 0x03, 0x0005, 0x0036 },
|
||||
{ 0x01, 0x01, 0, 0x03, 0x0006, 0x000a },
|
||||
{ 0x01, 0x01, 0, 0x03, 0x0006, 0x000c },
|
||||
{ 0x01, 0x02, 0, 0x03, 0x0006, 0x000e },
|
||||
{ 0x01, 0x02, 0, 0x03, 0x0006, 0x0012 },
|
||||
{ 0x01, 0x03, 0, 0x03, 0x0006, 0x0016 },
|
||||
{ 0x01, 0x03, 0, 0x03, 0x0006, 0x001e },
|
||||
{ 0x01, 0x04, 0, 0x03, 0x0006, 0x0026 },
|
||||
{ 0x01, 0x04, 0, 0x03, 0x0006, 0x0036 },
|
||||
{ 0x01, 0x01, 0, 0x03, 0x0008, 0x000a },
|
||||
{ 0x01, 0x01, 0, 0x03, 0x0008, 0x000c },
|
||||
{ 0x01, 0x02, 0, 0x03, 0x0008, 0x000e },
|
||||
{ 0x01, 0x02, 0, 0x03, 0x0008, 0x0012 },
|
||||
{ 0x01, 0x03, 0, 0x03, 0x0008, 0x0016 },
|
||||
{ 0x01, 0x03, 0, 0x03, 0x0008, 0x001e },
|
||||
{ 0x01, 0x04, 0, 0x03, 0x0008, 0x0026 },
|
||||
{ 0x01, 0x04, 0, 0x03, 0x0008, 0x0036 },
|
||||
{ 0x00, 0x00, -1, 0x00, 0x0000, 0x0002 },
|
||||
{ 0x00, 0x00, -1, 0x01, 0x0000, 0x0003 },
|
||||
{ 0x00, 0x00, -1, 0x02, 0x0000, 0x0004 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0000, 0x0005 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0000, 0x0006 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0000, 0x0007 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0000, 0x0008 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0000, 0x0009 },
|
||||
{ 0x00, 0x00, -1, 0x00, 0x0001, 0x0002 },
|
||||
{ 0x00, 0x00, -1, 0x01, 0x0001, 0x0003 },
|
||||
{ 0x00, 0x00, -1, 0x02, 0x0001, 0x0004 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0001, 0x0005 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0001, 0x0006 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0001, 0x0007 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0001, 0x0008 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0001, 0x0009 },
|
||||
{ 0x00, 0x00, -1, 0x00, 0x0002, 0x0002 },
|
||||
{ 0x00, 0x00, -1, 0x01, 0x0002, 0x0003 },
|
||||
{ 0x00, 0x00, -1, 0x02, 0x0002, 0x0004 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0002, 0x0005 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0002, 0x0006 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0002, 0x0007 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0002, 0x0008 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0002, 0x0009 },
|
||||
{ 0x00, 0x00, -1, 0x00, 0x0003, 0x0002 },
|
||||
{ 0x00, 0x00, -1, 0x01, 0x0003, 0x0003 },
|
||||
{ 0x00, 0x00, -1, 0x02, 0x0003, 0x0004 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0003, 0x0005 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0003, 0x0006 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0003, 0x0007 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0003, 0x0008 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0003, 0x0009 },
|
||||
{ 0x00, 0x00, -1, 0x00, 0x0004, 0x0002 },
|
||||
{ 0x00, 0x00, -1, 0x01, 0x0004, 0x0003 },
|
||||
{ 0x00, 0x00, -1, 0x02, 0x0004, 0x0004 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0004, 0x0005 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0004, 0x0006 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0004, 0x0007 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0004, 0x0008 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0004, 0x0009 },
|
||||
{ 0x00, 0x00, -1, 0x00, 0x0005, 0x0002 },
|
||||
{ 0x00, 0x00, -1, 0x01, 0x0005, 0x0003 },
|
||||
{ 0x00, 0x00, -1, 0x02, 0x0005, 0x0004 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0005, 0x0005 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0005, 0x0006 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0005, 0x0007 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0005, 0x0008 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0005, 0x0009 },
|
||||
{ 0x01, 0x00, -1, 0x00, 0x0006, 0x0002 },
|
||||
{ 0x01, 0x00, -1, 0x01, 0x0006, 0x0003 },
|
||||
{ 0x01, 0x00, -1, 0x02, 0x0006, 0x0004 },
|
||||
{ 0x01, 0x00, -1, 0x03, 0x0006, 0x0005 },
|
||||
{ 0x01, 0x00, -1, 0x03, 0x0006, 0x0006 },
|
||||
{ 0x01, 0x00, -1, 0x03, 0x0006, 0x0007 },
|
||||
{ 0x01, 0x00, -1, 0x03, 0x0006, 0x0008 },
|
||||
{ 0x01, 0x00, -1, 0x03, 0x0006, 0x0009 },
|
||||
{ 0x01, 0x00, -1, 0x00, 0x0008, 0x0002 },
|
||||
{ 0x01, 0x00, -1, 0x01, 0x0008, 0x0003 },
|
||||
{ 0x01, 0x00, -1, 0x02, 0x0008, 0x0004 },
|
||||
{ 0x01, 0x00, -1, 0x03, 0x0008, 0x0005 },
|
||||
{ 0x01, 0x00, -1, 0x03, 0x0008, 0x0006 },
|
||||
{ 0x01, 0x00, -1, 0x03, 0x0008, 0x0007 },
|
||||
{ 0x01, 0x00, -1, 0x03, 0x0008, 0x0008 },
|
||||
{ 0x01, 0x00, -1, 0x03, 0x0008, 0x0009 },
|
||||
{ 0x00, 0x01, -1, 0x03, 0x0000, 0x000a },
|
||||
{ 0x00, 0x01, -1, 0x03, 0x0000, 0x000c },
|
||||
{ 0x00, 0x02, -1, 0x03, 0x0000, 0x000e },
|
||||
{ 0x00, 0x02, -1, 0x03, 0x0000, 0x0012 },
|
||||
{ 0x00, 0x03, -1, 0x03, 0x0000, 0x0016 },
|
||||
{ 0x00, 0x03, -1, 0x03, 0x0000, 0x001e },
|
||||
{ 0x00, 0x04, -1, 0x03, 0x0000, 0x0026 },
|
||||
{ 0x00, 0x04, -1, 0x03, 0x0000, 0x0036 },
|
||||
{ 0x00, 0x01, -1, 0x03, 0x0001, 0x000a },
|
||||
{ 0x00, 0x01, -1, 0x03, 0x0001, 0x000c },
|
||||
{ 0x00, 0x02, -1, 0x03, 0x0001, 0x000e },
|
||||
{ 0x00, 0x02, -1, 0x03, 0x0001, 0x0012 },
|
||||
{ 0x00, 0x03, -1, 0x03, 0x0001, 0x0016 },
|
||||
{ 0x00, 0x03, -1, 0x03, 0x0001, 0x001e },
|
||||
{ 0x00, 0x04, -1, 0x03, 0x0001, 0x0026 },
|
||||
{ 0x00, 0x04, -1, 0x03, 0x0001, 0x0036 },
|
||||
{ 0x00, 0x01, -1, 0x03, 0x0002, 0x000a },
|
||||
{ 0x00, 0x01, -1, 0x03, 0x0002, 0x000c },
|
||||
{ 0x00, 0x02, -1, 0x03, 0x0002, 0x000e },
|
||||
{ 0x00, 0x02, -1, 0x03, 0x0002, 0x0012 },
|
||||
{ 0x00, 0x03, -1, 0x03, 0x0002, 0x0016 },
|
||||
{ 0x00, 0x03, -1, 0x03, 0x0002, 0x001e },
|
||||
{ 0x00, 0x04, -1, 0x03, 0x0002, 0x0026 },
|
||||
{ 0x00, 0x04, -1, 0x03, 0x0002, 0x0036 },
|
||||
{ 0x00, 0x01, -1, 0x03, 0x0003, 0x000a },
|
||||
{ 0x00, 0x01, -1, 0x03, 0x0003, 0x000c },
|
||||
{ 0x00, 0x02, -1, 0x03, 0x0003, 0x000e },
|
||||
{ 0x00, 0x02, -1, 0x03, 0x0003, 0x0012 },
|
||||
{ 0x00, 0x03, -1, 0x03, 0x0003, 0x0016 },
|
||||
{ 0x00, 0x03, -1, 0x03, 0x0003, 0x001e },
|
||||
{ 0x00, 0x04, -1, 0x03, 0x0003, 0x0026 },
|
||||
{ 0x00, 0x04, -1, 0x03, 0x0003, 0x0036 },
|
||||
{ 0x00, 0x01, -1, 0x03, 0x0004, 0x000a },
|
||||
{ 0x00, 0x01, -1, 0x03, 0x0004, 0x000c },
|
||||
{ 0x00, 0x02, -1, 0x03, 0x0004, 0x000e },
|
||||
{ 0x00, 0x02, -1, 0x03, 0x0004, 0x0012 },
|
||||
{ 0x00, 0x03, -1, 0x03, 0x0004, 0x0016 },
|
||||
{ 0x00, 0x03, -1, 0x03, 0x0004, 0x001e },
|
||||
{ 0x00, 0x04, -1, 0x03, 0x0004, 0x0026 },
|
||||
{ 0x00, 0x04, -1, 0x03, 0x0004, 0x0036 },
|
||||
{ 0x00, 0x01, -1, 0x03, 0x0005, 0x000a },
|
||||
{ 0x00, 0x01, -1, 0x03, 0x0005, 0x000c },
|
||||
{ 0x00, 0x02, -1, 0x03, 0x0005, 0x000e },
|
||||
{ 0x00, 0x02, -1, 0x03, 0x0005, 0x0012 },
|
||||
{ 0x00, 0x03, -1, 0x03, 0x0005, 0x0016 },
|
||||
{ 0x00, 0x03, -1, 0x03, 0x0005, 0x001e },
|
||||
{ 0x00, 0x04, -1, 0x03, 0x0005, 0x0026 },
|
||||
{ 0x00, 0x04, -1, 0x03, 0x0005, 0x0036 },
|
||||
{ 0x01, 0x01, -1, 0x03, 0x0006, 0x000a },
|
||||
{ 0x01, 0x01, -1, 0x03, 0x0006, 0x000c },
|
||||
{ 0x01, 0x02, -1, 0x03, 0x0006, 0x000e },
|
||||
{ 0x01, 0x02, -1, 0x03, 0x0006, 0x0012 },
|
||||
{ 0x01, 0x03, -1, 0x03, 0x0006, 0x0016 },
|
||||
{ 0x01, 0x03, -1, 0x03, 0x0006, 0x001e },
|
||||
{ 0x01, 0x04, -1, 0x03, 0x0006, 0x0026 },
|
||||
{ 0x01, 0x04, -1, 0x03, 0x0006, 0x0036 },
|
||||
{ 0x01, 0x01, -1, 0x03, 0x0008, 0x000a },
|
||||
{ 0x01, 0x01, -1, 0x03, 0x0008, 0x000c },
|
||||
{ 0x01, 0x02, -1, 0x03, 0x0008, 0x000e },
|
||||
{ 0x01, 0x02, -1, 0x03, 0x0008, 0x0012 },
|
||||
{ 0x01, 0x03, -1, 0x03, 0x0008, 0x0016 },
|
||||
{ 0x01, 0x03, -1, 0x03, 0x0008, 0x001e },
|
||||
{ 0x01, 0x04, -1, 0x03, 0x0008, 0x0026 },
|
||||
{ 0x01, 0x04, -1, 0x03, 0x0008, 0x0036 },
|
||||
{ 0x02, 0x00, -1, 0x00, 0x000a, 0x0002 },
|
||||
{ 0x02, 0x00, -1, 0x01, 0x000a, 0x0003 },
|
||||
{ 0x02, 0x00, -1, 0x02, 0x000a, 0x0004 },
|
||||
{ 0x02, 0x00, -1, 0x03, 0x000a, 0x0005 },
|
||||
{ 0x02, 0x00, -1, 0x03, 0x000a, 0x0006 },
|
||||
{ 0x02, 0x00, -1, 0x03, 0x000a, 0x0007 },
|
||||
{ 0x02, 0x00, -1, 0x03, 0x000a, 0x0008 },
|
||||
{ 0x02, 0x00, -1, 0x03, 0x000a, 0x0009 },
|
||||
{ 0x02, 0x00, -1, 0x00, 0x000e, 0x0002 },
|
||||
{ 0x02, 0x00, -1, 0x01, 0x000e, 0x0003 },
|
||||
{ 0x02, 0x00, -1, 0x02, 0x000e, 0x0004 },
|
||||
{ 0x02, 0x00, -1, 0x03, 0x000e, 0x0005 },
|
||||
{ 0x02, 0x00, -1, 0x03, 0x000e, 0x0006 },
|
||||
{ 0x02, 0x00, -1, 0x03, 0x000e, 0x0007 },
|
||||
{ 0x02, 0x00, -1, 0x03, 0x000e, 0x0008 },
|
||||
{ 0x02, 0x00, -1, 0x03, 0x000e, 0x0009 },
|
||||
{ 0x03, 0x00, -1, 0x00, 0x0012, 0x0002 },
|
||||
{ 0x03, 0x00, -1, 0x01, 0x0012, 0x0003 },
|
||||
{ 0x03, 0x00, -1, 0x02, 0x0012, 0x0004 },
|
||||
{ 0x03, 0x00, -1, 0x03, 0x0012, 0x0005 },
|
||||
{ 0x03, 0x00, -1, 0x03, 0x0012, 0x0006 },
|
||||
{ 0x03, 0x00, -1, 0x03, 0x0012, 0x0007 },
|
||||
{ 0x03, 0x00, -1, 0x03, 0x0012, 0x0008 },
|
||||
{ 0x03, 0x00, -1, 0x03, 0x0012, 0x0009 },
|
||||
{ 0x03, 0x00, -1, 0x00, 0x001a, 0x0002 },
|
||||
{ 0x03, 0x00, -1, 0x01, 0x001a, 0x0003 },
|
||||
{ 0x03, 0x00, -1, 0x02, 0x001a, 0x0004 },
|
||||
{ 0x03, 0x00, -1, 0x03, 0x001a, 0x0005 },
|
||||
{ 0x03, 0x00, -1, 0x03, 0x001a, 0x0006 },
|
||||
{ 0x03, 0x00, -1, 0x03, 0x001a, 0x0007 },
|
||||
{ 0x03, 0x00, -1, 0x03, 0x001a, 0x0008 },
|
||||
{ 0x03, 0x00, -1, 0x03, 0x001a, 0x0009 },
|
||||
{ 0x04, 0x00, -1, 0x00, 0x0022, 0x0002 },
|
||||
{ 0x04, 0x00, -1, 0x01, 0x0022, 0x0003 },
|
||||
{ 0x04, 0x00, -1, 0x02, 0x0022, 0x0004 },
|
||||
{ 0x04, 0x00, -1, 0x03, 0x0022, 0x0005 },
|
||||
{ 0x04, 0x00, -1, 0x03, 0x0022, 0x0006 },
|
||||
{ 0x04, 0x00, -1, 0x03, 0x0022, 0x0007 },
|
||||
{ 0x04, 0x00, -1, 0x03, 0x0022, 0x0008 },
|
||||
{ 0x04, 0x00, -1, 0x03, 0x0022, 0x0009 },
|
||||
{ 0x04, 0x00, -1, 0x00, 0x0032, 0x0002 },
|
||||
{ 0x04, 0x00, -1, 0x01, 0x0032, 0x0003 },
|
||||
{ 0x04, 0x00, -1, 0x02, 0x0032, 0x0004 },
|
||||
{ 0x04, 0x00, -1, 0x03, 0x0032, 0x0005 },
|
||||
{ 0x04, 0x00, -1, 0x03, 0x0032, 0x0006 },
|
||||
{ 0x04, 0x00, -1, 0x03, 0x0032, 0x0007 },
|
||||
{ 0x04, 0x00, -1, 0x03, 0x0032, 0x0008 },
|
||||
{ 0x04, 0x00, -1, 0x03, 0x0032, 0x0009 },
|
||||
{ 0x05, 0x00, -1, 0x00, 0x0042, 0x0002 },
|
||||
{ 0x05, 0x00, -1, 0x01, 0x0042, 0x0003 },
|
||||
{ 0x05, 0x00, -1, 0x02, 0x0042, 0x0004 },
|
||||
{ 0x05, 0x00, -1, 0x03, 0x0042, 0x0005 },
|
||||
{ 0x05, 0x00, -1, 0x03, 0x0042, 0x0006 },
|
||||
{ 0x05, 0x00, -1, 0x03, 0x0042, 0x0007 },
|
||||
{ 0x05, 0x00, -1, 0x03, 0x0042, 0x0008 },
|
||||
{ 0x05, 0x00, -1, 0x03, 0x0042, 0x0009 },
|
||||
{ 0x05, 0x00, -1, 0x00, 0x0062, 0x0002 },
|
||||
{ 0x05, 0x00, -1, 0x01, 0x0062, 0x0003 },
|
||||
{ 0x05, 0x00, -1, 0x02, 0x0062, 0x0004 },
|
||||
{ 0x05, 0x00, -1, 0x03, 0x0062, 0x0005 },
|
||||
{ 0x05, 0x00, -1, 0x03, 0x0062, 0x0006 },
|
||||
{ 0x05, 0x00, -1, 0x03, 0x0062, 0x0007 },
|
||||
{ 0x05, 0x00, -1, 0x03, 0x0062, 0x0008 },
|
||||
{ 0x05, 0x00, -1, 0x03, 0x0062, 0x0009 },
|
||||
{ 0x02, 0x01, -1, 0x03, 0x000a, 0x000a },
|
||||
{ 0x02, 0x01, -1, 0x03, 0x000a, 0x000c },
|
||||
{ 0x02, 0x02, -1, 0x03, 0x000a, 0x000e },
|
||||
{ 0x02, 0x02, -1, 0x03, 0x000a, 0x0012 },
|
||||
{ 0x02, 0x03, -1, 0x03, 0x000a, 0x0016 },
|
||||
{ 0x02, 0x03, -1, 0x03, 0x000a, 0x001e },
|
||||
{ 0x02, 0x04, -1, 0x03, 0x000a, 0x0026 },
|
||||
{ 0x02, 0x04, -1, 0x03, 0x000a, 0x0036 },
|
||||
{ 0x02, 0x01, -1, 0x03, 0x000e, 0x000a },
|
||||
{ 0x02, 0x01, -1, 0x03, 0x000e, 0x000c },
|
||||
{ 0x02, 0x02, -1, 0x03, 0x000e, 0x000e },
|
||||
{ 0x02, 0x02, -1, 0x03, 0x000e, 0x0012 },
|
||||
{ 0x02, 0x03, -1, 0x03, 0x000e, 0x0016 },
|
||||
{ 0x02, 0x03, -1, 0x03, 0x000e, 0x001e },
|
||||
{ 0x02, 0x04, -1, 0x03, 0x000e, 0x0026 },
|
||||
{ 0x02, 0x04, -1, 0x03, 0x000e, 0x0036 },
|
||||
{ 0x03, 0x01, -1, 0x03, 0x0012, 0x000a },
|
||||
{ 0x03, 0x01, -1, 0x03, 0x0012, 0x000c },
|
||||
{ 0x03, 0x02, -1, 0x03, 0x0012, 0x000e },
|
||||
{ 0x03, 0x02, -1, 0x03, 0x0012, 0x0012 },
|
||||
{ 0x03, 0x03, -1, 0x03, 0x0012, 0x0016 },
|
||||
{ 0x03, 0x03, -1, 0x03, 0x0012, 0x001e },
|
||||
{ 0x03, 0x04, -1, 0x03, 0x0012, 0x0026 },
|
||||
{ 0x03, 0x04, -1, 0x03, 0x0012, 0x0036 },
|
||||
{ 0x03, 0x01, -1, 0x03, 0x001a, 0x000a },
|
||||
{ 0x03, 0x01, -1, 0x03, 0x001a, 0x000c },
|
||||
{ 0x03, 0x02, -1, 0x03, 0x001a, 0x000e },
|
||||
{ 0x03, 0x02, -1, 0x03, 0x001a, 0x0012 },
|
||||
{ 0x03, 0x03, -1, 0x03, 0x001a, 0x0016 },
|
||||
{ 0x03, 0x03, -1, 0x03, 0x001a, 0x001e },
|
||||
{ 0x03, 0x04, -1, 0x03, 0x001a, 0x0026 },
|
||||
{ 0x03, 0x04, -1, 0x03, 0x001a, 0x0036 },
|
||||
{ 0x04, 0x01, -1, 0x03, 0x0022, 0x000a },
|
||||
{ 0x04, 0x01, -1, 0x03, 0x0022, 0x000c },
|
||||
{ 0x04, 0x02, -1, 0x03, 0x0022, 0x000e },
|
||||
{ 0x04, 0x02, -1, 0x03, 0x0022, 0x0012 },
|
||||
{ 0x04, 0x03, -1, 0x03, 0x0022, 0x0016 },
|
||||
{ 0x04, 0x03, -1, 0x03, 0x0022, 0x001e },
|
||||
{ 0x04, 0x04, -1, 0x03, 0x0022, 0x0026 },
|
||||
{ 0x04, 0x04, -1, 0x03, 0x0022, 0x0036 },
|
||||
{ 0x04, 0x01, -1, 0x03, 0x0032, 0x000a },
|
||||
{ 0x04, 0x01, -1, 0x03, 0x0032, 0x000c },
|
||||
{ 0x04, 0x02, -1, 0x03, 0x0032, 0x000e },
|
||||
{ 0x04, 0x02, -1, 0x03, 0x0032, 0x0012 },
|
||||
{ 0x04, 0x03, -1, 0x03, 0x0032, 0x0016 },
|
||||
{ 0x04, 0x03, -1, 0x03, 0x0032, 0x001e },
|
||||
{ 0x04, 0x04, -1, 0x03, 0x0032, 0x0026 },
|
||||
{ 0x04, 0x04, -1, 0x03, 0x0032, 0x0036 },
|
||||
{ 0x05, 0x01, -1, 0x03, 0x0042, 0x000a },
|
||||
{ 0x05, 0x01, -1, 0x03, 0x0042, 0x000c },
|
||||
{ 0x05, 0x02, -1, 0x03, 0x0042, 0x000e },
|
||||
{ 0x05, 0x02, -1, 0x03, 0x0042, 0x0012 },
|
||||
{ 0x05, 0x03, -1, 0x03, 0x0042, 0x0016 },
|
||||
{ 0x05, 0x03, -1, 0x03, 0x0042, 0x001e },
|
||||
{ 0x05, 0x04, -1, 0x03, 0x0042, 0x0026 },
|
||||
{ 0x05, 0x04, -1, 0x03, 0x0042, 0x0036 },
|
||||
{ 0x05, 0x01, -1, 0x03, 0x0062, 0x000a },
|
||||
{ 0x05, 0x01, -1, 0x03, 0x0062, 0x000c },
|
||||
{ 0x05, 0x02, -1, 0x03, 0x0062, 0x000e },
|
||||
{ 0x05, 0x02, -1, 0x03, 0x0062, 0x0012 },
|
||||
{ 0x05, 0x03, -1, 0x03, 0x0062, 0x0016 },
|
||||
{ 0x05, 0x03, -1, 0x03, 0x0062, 0x001e },
|
||||
{ 0x05, 0x04, -1, 0x03, 0x0062, 0x0026 },
|
||||
{ 0x05, 0x04, -1, 0x03, 0x0062, 0x0036 },
|
||||
{ 0x00, 0x05, -1, 0x03, 0x0000, 0x0046 },
|
||||
{ 0x00, 0x05, -1, 0x03, 0x0000, 0x0066 },
|
||||
{ 0x00, 0x06, -1, 0x03, 0x0000, 0x0086 },
|
||||
{ 0x00, 0x07, -1, 0x03, 0x0000, 0x00c6 },
|
||||
{ 0x00, 0x08, -1, 0x03, 0x0000, 0x0146 },
|
||||
{ 0x00, 0x09, -1, 0x03, 0x0000, 0x0246 },
|
||||
{ 0x00, 0x0a, -1, 0x03, 0x0000, 0x0446 },
|
||||
{ 0x00, 0x18, -1, 0x03, 0x0000, 0x0846 },
|
||||
{ 0x00, 0x05, -1, 0x03, 0x0001, 0x0046 },
|
||||
{ 0x00, 0x05, -1, 0x03, 0x0001, 0x0066 },
|
||||
{ 0x00, 0x06, -1, 0x03, 0x0001, 0x0086 },
|
||||
{ 0x00, 0x07, -1, 0x03, 0x0001, 0x00c6 },
|
||||
{ 0x00, 0x08, -1, 0x03, 0x0001, 0x0146 },
|
||||
{ 0x00, 0x09, -1, 0x03, 0x0001, 0x0246 },
|
||||
{ 0x00, 0x0a, -1, 0x03, 0x0001, 0x0446 },
|
||||
{ 0x00, 0x18, -1, 0x03, 0x0001, 0x0846 },
|
||||
{ 0x00, 0x05, -1, 0x03, 0x0002, 0x0046 },
|
||||
{ 0x00, 0x05, -1, 0x03, 0x0002, 0x0066 },
|
||||
{ 0x00, 0x06, -1, 0x03, 0x0002, 0x0086 },
|
||||
{ 0x00, 0x07, -1, 0x03, 0x0002, 0x00c6 },
|
||||
{ 0x00, 0x08, -1, 0x03, 0x0002, 0x0146 },
|
||||
{ 0x00, 0x09, -1, 0x03, 0x0002, 0x0246 },
|
||||
{ 0x00, 0x0a, -1, 0x03, 0x0002, 0x0446 },
|
||||
{ 0x00, 0x18, -1, 0x03, 0x0002, 0x0846 },
|
||||
{ 0x00, 0x05, -1, 0x03, 0x0003, 0x0046 },
|
||||
{ 0x00, 0x05, -1, 0x03, 0x0003, 0x0066 },
|
||||
{ 0x00, 0x06, -1, 0x03, 0x0003, 0x0086 },
|
||||
{ 0x00, 0x07, -1, 0x03, 0x0003, 0x00c6 },
|
||||
{ 0x00, 0x08, -1, 0x03, 0x0003, 0x0146 },
|
||||
{ 0x00, 0x09, -1, 0x03, 0x0003, 0x0246 },
|
||||
{ 0x00, 0x0a, -1, 0x03, 0x0003, 0x0446 },
|
||||
{ 0x00, 0x18, -1, 0x03, 0x0003, 0x0846 },
|
||||
{ 0x00, 0x05, -1, 0x03, 0x0004, 0x0046 },
|
||||
{ 0x00, 0x05, -1, 0x03, 0x0004, 0x0066 },
|
||||
{ 0x00, 0x06, -1, 0x03, 0x0004, 0x0086 },
|
||||
{ 0x00, 0x07, -1, 0x03, 0x0004, 0x00c6 },
|
||||
{ 0x00, 0x08, -1, 0x03, 0x0004, 0x0146 },
|
||||
{ 0x00, 0x09, -1, 0x03, 0x0004, 0x0246 },
|
||||
{ 0x00, 0x0a, -1, 0x03, 0x0004, 0x0446 },
|
||||
{ 0x00, 0x18, -1, 0x03, 0x0004, 0x0846 },
|
||||
{ 0x00, 0x05, -1, 0x03, 0x0005, 0x0046 },
|
||||
{ 0x00, 0x05, -1, 0x03, 0x0005, 0x0066 },
|
||||
{ 0x00, 0x06, -1, 0x03, 0x0005, 0x0086 },
|
||||
{ 0x00, 0x07, -1, 0x03, 0x0005, 0x00c6 },
|
||||
{ 0x00, 0x08, -1, 0x03, 0x0005, 0x0146 },
|
||||
{ 0x00, 0x09, -1, 0x03, 0x0005, 0x0246 },
|
||||
{ 0x00, 0x0a, -1, 0x03, 0x0005, 0x0446 },
|
||||
{ 0x00, 0x18, -1, 0x03, 0x0005, 0x0846 },
|
||||
{ 0x01, 0x05, -1, 0x03, 0x0006, 0x0046 },
|
||||
{ 0x01, 0x05, -1, 0x03, 0x0006, 0x0066 },
|
||||
{ 0x01, 0x06, -1, 0x03, 0x0006, 0x0086 },
|
||||
{ 0x01, 0x07, -1, 0x03, 0x0006, 0x00c6 },
|
||||
{ 0x01, 0x08, -1, 0x03, 0x0006, 0x0146 },
|
||||
{ 0x01, 0x09, -1, 0x03, 0x0006, 0x0246 },
|
||||
{ 0x01, 0x0a, -1, 0x03, 0x0006, 0x0446 },
|
||||
{ 0x01, 0x18, -1, 0x03, 0x0006, 0x0846 },
|
||||
{ 0x01, 0x05, -1, 0x03, 0x0008, 0x0046 },
|
||||
{ 0x01, 0x05, -1, 0x03, 0x0008, 0x0066 },
|
||||
{ 0x01, 0x06, -1, 0x03, 0x0008, 0x0086 },
|
||||
{ 0x01, 0x07, -1, 0x03, 0x0008, 0x00c6 },
|
||||
{ 0x01, 0x08, -1, 0x03, 0x0008, 0x0146 },
|
||||
{ 0x01, 0x09, -1, 0x03, 0x0008, 0x0246 },
|
||||
{ 0x01, 0x0a, -1, 0x03, 0x0008, 0x0446 },
|
||||
{ 0x01, 0x18, -1, 0x03, 0x0008, 0x0846 },
|
||||
{ 0x06, 0x00, -1, 0x00, 0x0082, 0x0002 },
|
||||
{ 0x06, 0x00, -1, 0x01, 0x0082, 0x0003 },
|
||||
{ 0x06, 0x00, -1, 0x02, 0x0082, 0x0004 },
|
||||
{ 0x06, 0x00, -1, 0x03, 0x0082, 0x0005 },
|
||||
{ 0x06, 0x00, -1, 0x03, 0x0082, 0x0006 },
|
||||
{ 0x06, 0x00, -1, 0x03, 0x0082, 0x0007 },
|
||||
{ 0x06, 0x00, -1, 0x03, 0x0082, 0x0008 },
|
||||
{ 0x06, 0x00, -1, 0x03, 0x0082, 0x0009 },
|
||||
{ 0x07, 0x00, -1, 0x00, 0x00c2, 0x0002 },
|
||||
{ 0x07, 0x00, -1, 0x01, 0x00c2, 0x0003 },
|
||||
{ 0x07, 0x00, -1, 0x02, 0x00c2, 0x0004 },
|
||||
{ 0x07, 0x00, -1, 0x03, 0x00c2, 0x0005 },
|
||||
{ 0x07, 0x00, -1, 0x03, 0x00c2, 0x0006 },
|
||||
{ 0x07, 0x00, -1, 0x03, 0x00c2, 0x0007 },
|
||||
{ 0x07, 0x00, -1, 0x03, 0x00c2, 0x0008 },
|
||||
{ 0x07, 0x00, -1, 0x03, 0x00c2, 0x0009 },
|
||||
{ 0x08, 0x00, -1, 0x00, 0x0142, 0x0002 },
|
||||
{ 0x08, 0x00, -1, 0x01, 0x0142, 0x0003 },
|
||||
{ 0x08, 0x00, -1, 0x02, 0x0142, 0x0004 },
|
||||
{ 0x08, 0x00, -1, 0x03, 0x0142, 0x0005 },
|
||||
{ 0x08, 0x00, -1, 0x03, 0x0142, 0x0006 },
|
||||
{ 0x08, 0x00, -1, 0x03, 0x0142, 0x0007 },
|
||||
{ 0x08, 0x00, -1, 0x03, 0x0142, 0x0008 },
|
||||
{ 0x08, 0x00, -1, 0x03, 0x0142, 0x0009 },
|
||||
{ 0x09, 0x00, -1, 0x00, 0x0242, 0x0002 },
|
||||
{ 0x09, 0x00, -1, 0x01, 0x0242, 0x0003 },
|
||||
{ 0x09, 0x00, -1, 0x02, 0x0242, 0x0004 },
|
||||
{ 0x09, 0x00, -1, 0x03, 0x0242, 0x0005 },
|
||||
{ 0x09, 0x00, -1, 0x03, 0x0242, 0x0006 },
|
||||
{ 0x09, 0x00, -1, 0x03, 0x0242, 0x0007 },
|
||||
{ 0x09, 0x00, -1, 0x03, 0x0242, 0x0008 },
|
||||
{ 0x09, 0x00, -1, 0x03, 0x0242, 0x0009 },
|
||||
{ 0x0a, 0x00, -1, 0x00, 0x0442, 0x0002 },
|
||||
{ 0x0a, 0x00, -1, 0x01, 0x0442, 0x0003 },
|
||||
{ 0x0a, 0x00, -1, 0x02, 0x0442, 0x0004 },
|
||||
{ 0x0a, 0x00, -1, 0x03, 0x0442, 0x0005 },
|
||||
{ 0x0a, 0x00, -1, 0x03, 0x0442, 0x0006 },
|
||||
{ 0x0a, 0x00, -1, 0x03, 0x0442, 0x0007 },
|
||||
{ 0x0a, 0x00, -1, 0x03, 0x0442, 0x0008 },
|
||||
{ 0x0a, 0x00, -1, 0x03, 0x0442, 0x0009 },
|
||||
{ 0x0c, 0x00, -1, 0x00, 0x0842, 0x0002 },
|
||||
{ 0x0c, 0x00, -1, 0x01, 0x0842, 0x0003 },
|
||||
{ 0x0c, 0x00, -1, 0x02, 0x0842, 0x0004 },
|
||||
{ 0x0c, 0x00, -1, 0x03, 0x0842, 0x0005 },
|
||||
{ 0x0c, 0x00, -1, 0x03, 0x0842, 0x0006 },
|
||||
{ 0x0c, 0x00, -1, 0x03, 0x0842, 0x0007 },
|
||||
{ 0x0c, 0x00, -1, 0x03, 0x0842, 0x0008 },
|
||||
{ 0x0c, 0x00, -1, 0x03, 0x0842, 0x0009 },
|
||||
{ 0x0e, 0x00, -1, 0x00, 0x1842, 0x0002 },
|
||||
{ 0x0e, 0x00, -1, 0x01, 0x1842, 0x0003 },
|
||||
{ 0x0e, 0x00, -1, 0x02, 0x1842, 0x0004 },
|
||||
{ 0x0e, 0x00, -1, 0x03, 0x1842, 0x0005 },
|
||||
{ 0x0e, 0x00, -1, 0x03, 0x1842, 0x0006 },
|
||||
{ 0x0e, 0x00, -1, 0x03, 0x1842, 0x0007 },
|
||||
{ 0x0e, 0x00, -1, 0x03, 0x1842, 0x0008 },
|
||||
{ 0x0e, 0x00, -1, 0x03, 0x1842, 0x0009 },
|
||||
{ 0x18, 0x00, -1, 0x00, 0x5842, 0x0002 },
|
||||
{ 0x18, 0x00, -1, 0x01, 0x5842, 0x0003 },
|
||||
{ 0x18, 0x00, -1, 0x02, 0x5842, 0x0004 },
|
||||
{ 0x18, 0x00, -1, 0x03, 0x5842, 0x0005 },
|
||||
{ 0x18, 0x00, -1, 0x03, 0x5842, 0x0006 },
|
||||
{ 0x18, 0x00, -1, 0x03, 0x5842, 0x0007 },
|
||||
{ 0x18, 0x00, -1, 0x03, 0x5842, 0x0008 },
|
||||
{ 0x18, 0x00, -1, 0x03, 0x5842, 0x0009 },
|
||||
{ 0x02, 0x05, -1, 0x03, 0x000a, 0x0046 },
|
||||
{ 0x02, 0x05, -1, 0x03, 0x000a, 0x0066 },
|
||||
{ 0x02, 0x06, -1, 0x03, 0x000a, 0x0086 },
|
||||
{ 0x02, 0x07, -1, 0x03, 0x000a, 0x00c6 },
|
||||
{ 0x02, 0x08, -1, 0x03, 0x000a, 0x0146 },
|
||||
{ 0x02, 0x09, -1, 0x03, 0x000a, 0x0246 },
|
||||
{ 0x02, 0x0a, -1, 0x03, 0x000a, 0x0446 },
|
||||
{ 0x02, 0x18, -1, 0x03, 0x000a, 0x0846 },
|
||||
{ 0x02, 0x05, -1, 0x03, 0x000e, 0x0046 },
|
||||
{ 0x02, 0x05, -1, 0x03, 0x000e, 0x0066 },
|
||||
{ 0x02, 0x06, -1, 0x03, 0x000e, 0x0086 },
|
||||
{ 0x02, 0x07, -1, 0x03, 0x000e, 0x00c6 },
|
||||
{ 0x02, 0x08, -1, 0x03, 0x000e, 0x0146 },
|
||||
{ 0x02, 0x09, -1, 0x03, 0x000e, 0x0246 },
|
||||
{ 0x02, 0x0a, -1, 0x03, 0x000e, 0x0446 },
|
||||
{ 0x02, 0x18, -1, 0x03, 0x000e, 0x0846 },
|
||||
{ 0x03, 0x05, -1, 0x03, 0x0012, 0x0046 },
|
||||
{ 0x03, 0x05, -1, 0x03, 0x0012, 0x0066 },
|
||||
{ 0x03, 0x06, -1, 0x03, 0x0012, 0x0086 },
|
||||
{ 0x03, 0x07, -1, 0x03, 0x0012, 0x00c6 },
|
||||
{ 0x03, 0x08, -1, 0x03, 0x0012, 0x0146 },
|
||||
{ 0x03, 0x09, -1, 0x03, 0x0012, 0x0246 },
|
||||
{ 0x03, 0x0a, -1, 0x03, 0x0012, 0x0446 },
|
||||
{ 0x03, 0x18, -1, 0x03, 0x0012, 0x0846 },
|
||||
{ 0x03, 0x05, -1, 0x03, 0x001a, 0x0046 },
|
||||
{ 0x03, 0x05, -1, 0x03, 0x001a, 0x0066 },
|
||||
{ 0x03, 0x06, -1, 0x03, 0x001a, 0x0086 },
|
||||
{ 0x03, 0x07, -1, 0x03, 0x001a, 0x00c6 },
|
||||
{ 0x03, 0x08, -1, 0x03, 0x001a, 0x0146 },
|
||||
{ 0x03, 0x09, -1, 0x03, 0x001a, 0x0246 },
|
||||
{ 0x03, 0x0a, -1, 0x03, 0x001a, 0x0446 },
|
||||
{ 0x03, 0x18, -1, 0x03, 0x001a, 0x0846 },
|
||||
{ 0x04, 0x05, -1, 0x03, 0x0022, 0x0046 },
|
||||
{ 0x04, 0x05, -1, 0x03, 0x0022, 0x0066 },
|
||||
{ 0x04, 0x06, -1, 0x03, 0x0022, 0x0086 },
|
||||
{ 0x04, 0x07, -1, 0x03, 0x0022, 0x00c6 },
|
||||
{ 0x04, 0x08, -1, 0x03, 0x0022, 0x0146 },
|
||||
{ 0x04, 0x09, -1, 0x03, 0x0022, 0x0246 },
|
||||
{ 0x04, 0x0a, -1, 0x03, 0x0022, 0x0446 },
|
||||
{ 0x04, 0x18, -1, 0x03, 0x0022, 0x0846 },
|
||||
{ 0x04, 0x05, -1, 0x03, 0x0032, 0x0046 },
|
||||
{ 0x04, 0x05, -1, 0x03, 0x0032, 0x0066 },
|
||||
{ 0x04, 0x06, -1, 0x03, 0x0032, 0x0086 },
|
||||
{ 0x04, 0x07, -1, 0x03, 0x0032, 0x00c6 },
|
||||
{ 0x04, 0x08, -1, 0x03, 0x0032, 0x0146 },
|
||||
{ 0x04, 0x09, -1, 0x03, 0x0032, 0x0246 },
|
||||
{ 0x04, 0x0a, -1, 0x03, 0x0032, 0x0446 },
|
||||
{ 0x04, 0x18, -1, 0x03, 0x0032, 0x0846 },
|
||||
{ 0x05, 0x05, -1, 0x03, 0x0042, 0x0046 },
|
||||
{ 0x05, 0x05, -1, 0x03, 0x0042, 0x0066 },
|
||||
{ 0x05, 0x06, -1, 0x03, 0x0042, 0x0086 },
|
||||
{ 0x05, 0x07, -1, 0x03, 0x0042, 0x00c6 },
|
||||
{ 0x05, 0x08, -1, 0x03, 0x0042, 0x0146 },
|
||||
{ 0x05, 0x09, -1, 0x03, 0x0042, 0x0246 },
|
||||
{ 0x05, 0x0a, -1, 0x03, 0x0042, 0x0446 },
|
||||
{ 0x05, 0x18, -1, 0x03, 0x0042, 0x0846 },
|
||||
{ 0x05, 0x05, -1, 0x03, 0x0062, 0x0046 },
|
||||
{ 0x05, 0x05, -1, 0x03, 0x0062, 0x0066 },
|
||||
{ 0x05, 0x06, -1, 0x03, 0x0062, 0x0086 },
|
||||
{ 0x05, 0x07, -1, 0x03, 0x0062, 0x00c6 },
|
||||
{ 0x05, 0x08, -1, 0x03, 0x0062, 0x0146 },
|
||||
{ 0x05, 0x09, -1, 0x03, 0x0062, 0x0246 },
|
||||
{ 0x05, 0x0a, -1, 0x03, 0x0062, 0x0446 },
|
||||
{ 0x05, 0x18, -1, 0x03, 0x0062, 0x0846 },
|
||||
{ 0x06, 0x01, -1, 0x03, 0x0082, 0x000a },
|
||||
{ 0x06, 0x01, -1, 0x03, 0x0082, 0x000c },
|
||||
{ 0x06, 0x02, -1, 0x03, 0x0082, 0x000e },
|
||||
{ 0x06, 0x02, -1, 0x03, 0x0082, 0x0012 },
|
||||
{ 0x06, 0x03, -1, 0x03, 0x0082, 0x0016 },
|
||||
{ 0x06, 0x03, -1, 0x03, 0x0082, 0x001e },
|
||||
{ 0x06, 0x04, -1, 0x03, 0x0082, 0x0026 },
|
||||
{ 0x06, 0x04, -1, 0x03, 0x0082, 0x0036 },
|
||||
{ 0x07, 0x01, -1, 0x03, 0x00c2, 0x000a },
|
||||
{ 0x07, 0x01, -1, 0x03, 0x00c2, 0x000c },
|
||||
{ 0x07, 0x02, -1, 0x03, 0x00c2, 0x000e },
|
||||
{ 0x07, 0x02, -1, 0x03, 0x00c2, 0x0012 },
|
||||
{ 0x07, 0x03, -1, 0x03, 0x00c2, 0x0016 },
|
||||
{ 0x07, 0x03, -1, 0x03, 0x00c2, 0x001e },
|
||||
{ 0x07, 0x04, -1, 0x03, 0x00c2, 0x0026 },
|
||||
{ 0x07, 0x04, -1, 0x03, 0x00c2, 0x0036 },
|
||||
{ 0x08, 0x01, -1, 0x03, 0x0142, 0x000a },
|
||||
{ 0x08, 0x01, -1, 0x03, 0x0142, 0x000c },
|
||||
{ 0x08, 0x02, -1, 0x03, 0x0142, 0x000e },
|
||||
{ 0x08, 0x02, -1, 0x03, 0x0142, 0x0012 },
|
||||
{ 0x08, 0x03, -1, 0x03, 0x0142, 0x0016 },
|
||||
{ 0x08, 0x03, -1, 0x03, 0x0142, 0x001e },
|
||||
{ 0x08, 0x04, -1, 0x03, 0x0142, 0x0026 },
|
||||
{ 0x08, 0x04, -1, 0x03, 0x0142, 0x0036 },
|
||||
{ 0x09, 0x01, -1, 0x03, 0x0242, 0x000a },
|
||||
{ 0x09, 0x01, -1, 0x03, 0x0242, 0x000c },
|
||||
{ 0x09, 0x02, -1, 0x03, 0x0242, 0x000e },
|
||||
{ 0x09, 0x02, -1, 0x03, 0x0242, 0x0012 },
|
||||
{ 0x09, 0x03, -1, 0x03, 0x0242, 0x0016 },
|
||||
{ 0x09, 0x03, -1, 0x03, 0x0242, 0x001e },
|
||||
{ 0x09, 0x04, -1, 0x03, 0x0242, 0x0026 },
|
||||
{ 0x09, 0x04, -1, 0x03, 0x0242, 0x0036 },
|
||||
{ 0x0a, 0x01, -1, 0x03, 0x0442, 0x000a },
|
||||
{ 0x0a, 0x01, -1, 0x03, 0x0442, 0x000c },
|
||||
{ 0x0a, 0x02, -1, 0x03, 0x0442, 0x000e },
|
||||
{ 0x0a, 0x02, -1, 0x03, 0x0442, 0x0012 },
|
||||
{ 0x0a, 0x03, -1, 0x03, 0x0442, 0x0016 },
|
||||
{ 0x0a, 0x03, -1, 0x03, 0x0442, 0x001e },
|
||||
{ 0x0a, 0x04, -1, 0x03, 0x0442, 0x0026 },
|
||||
{ 0x0a, 0x04, -1, 0x03, 0x0442, 0x0036 },
|
||||
{ 0x0c, 0x01, -1, 0x03, 0x0842, 0x000a },
|
||||
{ 0x0c, 0x01, -1, 0x03, 0x0842, 0x000c },
|
||||
{ 0x0c, 0x02, -1, 0x03, 0x0842, 0x000e },
|
||||
{ 0x0c, 0x02, -1, 0x03, 0x0842, 0x0012 },
|
||||
{ 0x0c, 0x03, -1, 0x03, 0x0842, 0x0016 },
|
||||
{ 0x0c, 0x03, -1, 0x03, 0x0842, 0x001e },
|
||||
{ 0x0c, 0x04, -1, 0x03, 0x0842, 0x0026 },
|
||||
{ 0x0c, 0x04, -1, 0x03, 0x0842, 0x0036 },
|
||||
{ 0x0e, 0x01, -1, 0x03, 0x1842, 0x000a },
|
||||
{ 0x0e, 0x01, -1, 0x03, 0x1842, 0x000c },
|
||||
{ 0x0e, 0x02, -1, 0x03, 0x1842, 0x000e },
|
||||
{ 0x0e, 0x02, -1, 0x03, 0x1842, 0x0012 },
|
||||
{ 0x0e, 0x03, -1, 0x03, 0x1842, 0x0016 },
|
||||
{ 0x0e, 0x03, -1, 0x03, 0x1842, 0x001e },
|
||||
{ 0x0e, 0x04, -1, 0x03, 0x1842, 0x0026 },
|
||||
{ 0x0e, 0x04, -1, 0x03, 0x1842, 0x0036 },
|
||||
{ 0x18, 0x01, -1, 0x03, 0x5842, 0x000a },
|
||||
{ 0x18, 0x01, -1, 0x03, 0x5842, 0x000c },
|
||||
{ 0x18, 0x02, -1, 0x03, 0x5842, 0x000e },
|
||||
{ 0x18, 0x02, -1, 0x03, 0x5842, 0x0012 },
|
||||
{ 0x18, 0x03, -1, 0x03, 0x5842, 0x0016 },
|
||||
{ 0x18, 0x03, -1, 0x03, 0x5842, 0x001e },
|
||||
{ 0x18, 0x04, -1, 0x03, 0x5842, 0x0026 },
|
||||
{ 0x18, 0x04, -1, 0x03, 0x5842, 0x0036 },
|
||||
{ 0x06, 0x05, -1, 0x03, 0x0082, 0x0046 },
|
||||
{ 0x06, 0x05, -1, 0x03, 0x0082, 0x0066 },
|
||||
{ 0x06, 0x06, -1, 0x03, 0x0082, 0x0086 },
|
||||
{ 0x06, 0x07, -1, 0x03, 0x0082, 0x00c6 },
|
||||
{ 0x06, 0x08, -1, 0x03, 0x0082, 0x0146 },
|
||||
{ 0x06, 0x09, -1, 0x03, 0x0082, 0x0246 },
|
||||
{ 0x06, 0x0a, -1, 0x03, 0x0082, 0x0446 },
|
||||
{ 0x06, 0x18, -1, 0x03, 0x0082, 0x0846 },
|
||||
{ 0x07, 0x05, -1, 0x03, 0x00c2, 0x0046 },
|
||||
{ 0x07, 0x05, -1, 0x03, 0x00c2, 0x0066 },
|
||||
{ 0x07, 0x06, -1, 0x03, 0x00c2, 0x0086 },
|
||||
{ 0x07, 0x07, -1, 0x03, 0x00c2, 0x00c6 },
|
||||
{ 0x07, 0x08, -1, 0x03, 0x00c2, 0x0146 },
|
||||
{ 0x07, 0x09, -1, 0x03, 0x00c2, 0x0246 },
|
||||
{ 0x07, 0x0a, -1, 0x03, 0x00c2, 0x0446 },
|
||||
{ 0x07, 0x18, -1, 0x03, 0x00c2, 0x0846 },
|
||||
{ 0x08, 0x05, -1, 0x03, 0x0142, 0x0046 },
|
||||
{ 0x08, 0x05, -1, 0x03, 0x0142, 0x0066 },
|
||||
{ 0x08, 0x06, -1, 0x03, 0x0142, 0x0086 },
|
||||
{ 0x08, 0x07, -1, 0x03, 0x0142, 0x00c6 },
|
||||
{ 0x08, 0x08, -1, 0x03, 0x0142, 0x0146 },
|
||||
{ 0x08, 0x09, -1, 0x03, 0x0142, 0x0246 },
|
||||
{ 0x08, 0x0a, -1, 0x03, 0x0142, 0x0446 },
|
||||
{ 0x08, 0x18, -1, 0x03, 0x0142, 0x0846 },
|
||||
{ 0x09, 0x05, -1, 0x03, 0x0242, 0x0046 },
|
||||
{ 0x09, 0x05, -1, 0x03, 0x0242, 0x0066 },
|
||||
{ 0x09, 0x06, -1, 0x03, 0x0242, 0x0086 },
|
||||
{ 0x09, 0x07, -1, 0x03, 0x0242, 0x00c6 },
|
||||
{ 0x09, 0x08, -1, 0x03, 0x0242, 0x0146 },
|
||||
{ 0x09, 0x09, -1, 0x03, 0x0242, 0x0246 },
|
||||
{ 0x09, 0x0a, -1, 0x03, 0x0242, 0x0446 },
|
||||
{ 0x09, 0x18, -1, 0x03, 0x0242, 0x0846 },
|
||||
{ 0x0a, 0x05, -1, 0x03, 0x0442, 0x0046 },
|
||||
{ 0x0a, 0x05, -1, 0x03, 0x0442, 0x0066 },
|
||||
{ 0x0a, 0x06, -1, 0x03, 0x0442, 0x0086 },
|
||||
{ 0x0a, 0x07, -1, 0x03, 0x0442, 0x00c6 },
|
||||
{ 0x0a, 0x08, -1, 0x03, 0x0442, 0x0146 },
|
||||
{ 0x0a, 0x09, -1, 0x03, 0x0442, 0x0246 },
|
||||
{ 0x0a, 0x0a, -1, 0x03, 0x0442, 0x0446 },
|
||||
{ 0x0a, 0x18, -1, 0x03, 0x0442, 0x0846 },
|
||||
{ 0x0c, 0x05, -1, 0x03, 0x0842, 0x0046 },
|
||||
{ 0x0c, 0x05, -1, 0x03, 0x0842, 0x0066 },
|
||||
{ 0x0c, 0x06, -1, 0x03, 0x0842, 0x0086 },
|
||||
{ 0x0c, 0x07, -1, 0x03, 0x0842, 0x00c6 },
|
||||
{ 0x0c, 0x08, -1, 0x03, 0x0842, 0x0146 },
|
||||
{ 0x0c, 0x09, -1, 0x03, 0x0842, 0x0246 },
|
||||
{ 0x0c, 0x0a, -1, 0x03, 0x0842, 0x0446 },
|
||||
{ 0x0c, 0x18, -1, 0x03, 0x0842, 0x0846 },
|
||||
{ 0x0e, 0x05, -1, 0x03, 0x1842, 0x0046 },
|
||||
{ 0x0e, 0x05, -1, 0x03, 0x1842, 0x0066 },
|
||||
{ 0x0e, 0x06, -1, 0x03, 0x1842, 0x0086 },
|
||||
{ 0x0e, 0x07, -1, 0x03, 0x1842, 0x00c6 },
|
||||
{ 0x0e, 0x08, -1, 0x03, 0x1842, 0x0146 },
|
||||
{ 0x0e, 0x09, -1, 0x03, 0x1842, 0x0246 },
|
||||
{ 0x0e, 0x0a, -1, 0x03, 0x1842, 0x0446 },
|
||||
{ 0x0e, 0x18, -1, 0x03, 0x1842, 0x0846 },
|
||||
{ 0x18, 0x05, -1, 0x03, 0x5842, 0x0046 },
|
||||
{ 0x18, 0x05, -1, 0x03, 0x5842, 0x0066 },
|
||||
{ 0x18, 0x06, -1, 0x03, 0x5842, 0x0086 },
|
||||
{ 0x18, 0x07, -1, 0x03, 0x5842, 0x00c6 },
|
||||
{ 0x18, 0x08, -1, 0x03, 0x5842, 0x0146 },
|
||||
{ 0x18, 0x09, -1, 0x03, 0x5842, 0x0246 },
|
||||
{ 0x18, 0x0a, -1, 0x03, 0x5842, 0x0446 },
|
||||
{ 0x18, 0x18, -1, 0x03, 0x5842, 0x0846 },
|
||||
};
|
||||
#if (BROTLI_STATIC_INIT == BROTLI_STATIC_INIT_NONE)
|
||||
BROTLI_INTERNAL extern const BROTLI_MODEL("small")
|
||||
CmdLutElement kCmdLut[BROTLI_NUM_COMMAND_SYMBOLS];
|
||||
#else
|
||||
BROTLI_INTERNAL BROTLI_BOOL BrotliDecoderInitCmdLut(CmdLutElement* items);
|
||||
BROTLI_INTERNAL extern BROTLI_MODEL("small")
|
||||
CmdLutElement kCmdLut[BROTLI_NUM_COMMAND_SYMBOLS];
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* BROTLI_DEC_PREFIX_H_ */
|
||||
|
||||
707
c/dec/prefix_inc.h
Normal file
707
c/dec/prefix_inc.h
Normal file
@@ -0,0 +1,707 @@
|
||||
const BROTLI_MODEL("small")
|
||||
CmdLutElement kCmdLut[BROTLI_NUM_COMMAND_SYMBOLS] = {
|
||||
{ 0x00, 0x00, 0, 0x00, 0x0000, 0x0002 },
|
||||
{ 0x00, 0x00, 0, 0x01, 0x0000, 0x0003 },
|
||||
{ 0x00, 0x00, 0, 0x02, 0x0000, 0x0004 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0000, 0x0005 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0000, 0x0006 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0000, 0x0007 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0000, 0x0008 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0000, 0x0009 },
|
||||
{ 0x00, 0x00, 0, 0x00, 0x0001, 0x0002 },
|
||||
{ 0x00, 0x00, 0, 0x01, 0x0001, 0x0003 },
|
||||
{ 0x00, 0x00, 0, 0x02, 0x0001, 0x0004 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0001, 0x0005 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0001, 0x0006 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0001, 0x0007 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0001, 0x0008 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0001, 0x0009 },
|
||||
{ 0x00, 0x00, 0, 0x00, 0x0002, 0x0002 },
|
||||
{ 0x00, 0x00, 0, 0x01, 0x0002, 0x0003 },
|
||||
{ 0x00, 0x00, 0, 0x02, 0x0002, 0x0004 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0002, 0x0005 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0002, 0x0006 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0002, 0x0007 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0002, 0x0008 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0002, 0x0009 },
|
||||
{ 0x00, 0x00, 0, 0x00, 0x0003, 0x0002 },
|
||||
{ 0x00, 0x00, 0, 0x01, 0x0003, 0x0003 },
|
||||
{ 0x00, 0x00, 0, 0x02, 0x0003, 0x0004 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0003, 0x0005 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0003, 0x0006 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0003, 0x0007 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0003, 0x0008 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0003, 0x0009 },
|
||||
{ 0x00, 0x00, 0, 0x00, 0x0004, 0x0002 },
|
||||
{ 0x00, 0x00, 0, 0x01, 0x0004, 0x0003 },
|
||||
{ 0x00, 0x00, 0, 0x02, 0x0004, 0x0004 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0004, 0x0005 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0004, 0x0006 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0004, 0x0007 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0004, 0x0008 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0004, 0x0009 },
|
||||
{ 0x00, 0x00, 0, 0x00, 0x0005, 0x0002 },
|
||||
{ 0x00, 0x00, 0, 0x01, 0x0005, 0x0003 },
|
||||
{ 0x00, 0x00, 0, 0x02, 0x0005, 0x0004 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0005, 0x0005 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0005, 0x0006 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0005, 0x0007 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0005, 0x0008 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0005, 0x0009 },
|
||||
{ 0x01, 0x00, 0, 0x00, 0x0006, 0x0002 },
|
||||
{ 0x01, 0x00, 0, 0x01, 0x0006, 0x0003 },
|
||||
{ 0x01, 0x00, 0, 0x02, 0x0006, 0x0004 },
|
||||
{ 0x01, 0x00, 0, 0x03, 0x0006, 0x0005 },
|
||||
{ 0x01, 0x00, 0, 0x03, 0x0006, 0x0006 },
|
||||
{ 0x01, 0x00, 0, 0x03, 0x0006, 0x0007 },
|
||||
{ 0x01, 0x00, 0, 0x03, 0x0006, 0x0008 },
|
||||
{ 0x01, 0x00, 0, 0x03, 0x0006, 0x0009 },
|
||||
{ 0x01, 0x00, 0, 0x00, 0x0008, 0x0002 },
|
||||
{ 0x01, 0x00, 0, 0x01, 0x0008, 0x0003 },
|
||||
{ 0x01, 0x00, 0, 0x02, 0x0008, 0x0004 },
|
||||
{ 0x01, 0x00, 0, 0x03, 0x0008, 0x0005 },
|
||||
{ 0x01, 0x00, 0, 0x03, 0x0008, 0x0006 },
|
||||
{ 0x01, 0x00, 0, 0x03, 0x0008, 0x0007 },
|
||||
{ 0x01, 0x00, 0, 0x03, 0x0008, 0x0008 },
|
||||
{ 0x01, 0x00, 0, 0x03, 0x0008, 0x0009 },
|
||||
{ 0x00, 0x01, 0, 0x03, 0x0000, 0x000a },
|
||||
{ 0x00, 0x01, 0, 0x03, 0x0000, 0x000c },
|
||||
{ 0x00, 0x02, 0, 0x03, 0x0000, 0x000e },
|
||||
{ 0x00, 0x02, 0, 0x03, 0x0000, 0x0012 },
|
||||
{ 0x00, 0x03, 0, 0x03, 0x0000, 0x0016 },
|
||||
{ 0x00, 0x03, 0, 0x03, 0x0000, 0x001e },
|
||||
{ 0x00, 0x04, 0, 0x03, 0x0000, 0x0026 },
|
||||
{ 0x00, 0x04, 0, 0x03, 0x0000, 0x0036 },
|
||||
{ 0x00, 0x01, 0, 0x03, 0x0001, 0x000a },
|
||||
{ 0x00, 0x01, 0, 0x03, 0x0001, 0x000c },
|
||||
{ 0x00, 0x02, 0, 0x03, 0x0001, 0x000e },
|
||||
{ 0x00, 0x02, 0, 0x03, 0x0001, 0x0012 },
|
||||
{ 0x00, 0x03, 0, 0x03, 0x0001, 0x0016 },
|
||||
{ 0x00, 0x03, 0, 0x03, 0x0001, 0x001e },
|
||||
{ 0x00, 0x04, 0, 0x03, 0x0001, 0x0026 },
|
||||
{ 0x00, 0x04, 0, 0x03, 0x0001, 0x0036 },
|
||||
{ 0x00, 0x01, 0, 0x03, 0x0002, 0x000a },
|
||||
{ 0x00, 0x01, 0, 0x03, 0x0002, 0x000c },
|
||||
{ 0x00, 0x02, 0, 0x03, 0x0002, 0x000e },
|
||||
{ 0x00, 0x02, 0, 0x03, 0x0002, 0x0012 },
|
||||
{ 0x00, 0x03, 0, 0x03, 0x0002, 0x0016 },
|
||||
{ 0x00, 0x03, 0, 0x03, 0x0002, 0x001e },
|
||||
{ 0x00, 0x04, 0, 0x03, 0x0002, 0x0026 },
|
||||
{ 0x00, 0x04, 0, 0x03, 0x0002, 0x0036 },
|
||||
{ 0x00, 0x01, 0, 0x03, 0x0003, 0x000a },
|
||||
{ 0x00, 0x01, 0, 0x03, 0x0003, 0x000c },
|
||||
{ 0x00, 0x02, 0, 0x03, 0x0003, 0x000e },
|
||||
{ 0x00, 0x02, 0, 0x03, 0x0003, 0x0012 },
|
||||
{ 0x00, 0x03, 0, 0x03, 0x0003, 0x0016 },
|
||||
{ 0x00, 0x03, 0, 0x03, 0x0003, 0x001e },
|
||||
{ 0x00, 0x04, 0, 0x03, 0x0003, 0x0026 },
|
||||
{ 0x00, 0x04, 0, 0x03, 0x0003, 0x0036 },
|
||||
{ 0x00, 0x01, 0, 0x03, 0x0004, 0x000a },
|
||||
{ 0x00, 0x01, 0, 0x03, 0x0004, 0x000c },
|
||||
{ 0x00, 0x02, 0, 0x03, 0x0004, 0x000e },
|
||||
{ 0x00, 0x02, 0, 0x03, 0x0004, 0x0012 },
|
||||
{ 0x00, 0x03, 0, 0x03, 0x0004, 0x0016 },
|
||||
{ 0x00, 0x03, 0, 0x03, 0x0004, 0x001e },
|
||||
{ 0x00, 0x04, 0, 0x03, 0x0004, 0x0026 },
|
||||
{ 0x00, 0x04, 0, 0x03, 0x0004, 0x0036 },
|
||||
{ 0x00, 0x01, 0, 0x03, 0x0005, 0x000a },
|
||||
{ 0x00, 0x01, 0, 0x03, 0x0005, 0x000c },
|
||||
{ 0x00, 0x02, 0, 0x03, 0x0005, 0x000e },
|
||||
{ 0x00, 0x02, 0, 0x03, 0x0005, 0x0012 },
|
||||
{ 0x00, 0x03, 0, 0x03, 0x0005, 0x0016 },
|
||||
{ 0x00, 0x03, 0, 0x03, 0x0005, 0x001e },
|
||||
{ 0x00, 0x04, 0, 0x03, 0x0005, 0x0026 },
|
||||
{ 0x00, 0x04, 0, 0x03, 0x0005, 0x0036 },
|
||||
{ 0x01, 0x01, 0, 0x03, 0x0006, 0x000a },
|
||||
{ 0x01, 0x01, 0, 0x03, 0x0006, 0x000c },
|
||||
{ 0x01, 0x02, 0, 0x03, 0x0006, 0x000e },
|
||||
{ 0x01, 0x02, 0, 0x03, 0x0006, 0x0012 },
|
||||
{ 0x01, 0x03, 0, 0x03, 0x0006, 0x0016 },
|
||||
{ 0x01, 0x03, 0, 0x03, 0x0006, 0x001e },
|
||||
{ 0x01, 0x04, 0, 0x03, 0x0006, 0x0026 },
|
||||
{ 0x01, 0x04, 0, 0x03, 0x0006, 0x0036 },
|
||||
{ 0x01, 0x01, 0, 0x03, 0x0008, 0x000a },
|
||||
{ 0x01, 0x01, 0, 0x03, 0x0008, 0x000c },
|
||||
{ 0x01, 0x02, 0, 0x03, 0x0008, 0x000e },
|
||||
{ 0x01, 0x02, 0, 0x03, 0x0008, 0x0012 },
|
||||
{ 0x01, 0x03, 0, 0x03, 0x0008, 0x0016 },
|
||||
{ 0x01, 0x03, 0, 0x03, 0x0008, 0x001e },
|
||||
{ 0x01, 0x04, 0, 0x03, 0x0008, 0x0026 },
|
||||
{ 0x01, 0x04, 0, 0x03, 0x0008, 0x0036 },
|
||||
{ 0x00, 0x00, -1, 0x00, 0x0000, 0x0002 },
|
||||
{ 0x00, 0x00, -1, 0x01, 0x0000, 0x0003 },
|
||||
{ 0x00, 0x00, -1, 0x02, 0x0000, 0x0004 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0000, 0x0005 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0000, 0x0006 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0000, 0x0007 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0000, 0x0008 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0000, 0x0009 },
|
||||
{ 0x00, 0x00, -1, 0x00, 0x0001, 0x0002 },
|
||||
{ 0x00, 0x00, -1, 0x01, 0x0001, 0x0003 },
|
||||
{ 0x00, 0x00, -1, 0x02, 0x0001, 0x0004 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0001, 0x0005 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0001, 0x0006 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0001, 0x0007 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0001, 0x0008 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0001, 0x0009 },
|
||||
{ 0x00, 0x00, -1, 0x00, 0x0002, 0x0002 },
|
||||
{ 0x00, 0x00, -1, 0x01, 0x0002, 0x0003 },
|
||||
{ 0x00, 0x00, -1, 0x02, 0x0002, 0x0004 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0002, 0x0005 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0002, 0x0006 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0002, 0x0007 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0002, 0x0008 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0002, 0x0009 },
|
||||
{ 0x00, 0x00, -1, 0x00, 0x0003, 0x0002 },
|
||||
{ 0x00, 0x00, -1, 0x01, 0x0003, 0x0003 },
|
||||
{ 0x00, 0x00, -1, 0x02, 0x0003, 0x0004 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0003, 0x0005 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0003, 0x0006 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0003, 0x0007 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0003, 0x0008 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0003, 0x0009 },
|
||||
{ 0x00, 0x00, -1, 0x00, 0x0004, 0x0002 },
|
||||
{ 0x00, 0x00, -1, 0x01, 0x0004, 0x0003 },
|
||||
{ 0x00, 0x00, -1, 0x02, 0x0004, 0x0004 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0004, 0x0005 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0004, 0x0006 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0004, 0x0007 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0004, 0x0008 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0004, 0x0009 },
|
||||
{ 0x00, 0x00, -1, 0x00, 0x0005, 0x0002 },
|
||||
{ 0x00, 0x00, -1, 0x01, 0x0005, 0x0003 },
|
||||
{ 0x00, 0x00, -1, 0x02, 0x0005, 0x0004 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0005, 0x0005 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0005, 0x0006 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0005, 0x0007 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0005, 0x0008 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0005, 0x0009 },
|
||||
{ 0x01, 0x00, -1, 0x00, 0x0006, 0x0002 },
|
||||
{ 0x01, 0x00, -1, 0x01, 0x0006, 0x0003 },
|
||||
{ 0x01, 0x00, -1, 0x02, 0x0006, 0x0004 },
|
||||
{ 0x01, 0x00, -1, 0x03, 0x0006, 0x0005 },
|
||||
{ 0x01, 0x00, -1, 0x03, 0x0006, 0x0006 },
|
||||
{ 0x01, 0x00, -1, 0x03, 0x0006, 0x0007 },
|
||||
{ 0x01, 0x00, -1, 0x03, 0x0006, 0x0008 },
|
||||
{ 0x01, 0x00, -1, 0x03, 0x0006, 0x0009 },
|
||||
{ 0x01, 0x00, -1, 0x00, 0x0008, 0x0002 },
|
||||
{ 0x01, 0x00, -1, 0x01, 0x0008, 0x0003 },
|
||||
{ 0x01, 0x00, -1, 0x02, 0x0008, 0x0004 },
|
||||
{ 0x01, 0x00, -1, 0x03, 0x0008, 0x0005 },
|
||||
{ 0x01, 0x00, -1, 0x03, 0x0008, 0x0006 },
|
||||
{ 0x01, 0x00, -1, 0x03, 0x0008, 0x0007 },
|
||||
{ 0x01, 0x00, -1, 0x03, 0x0008, 0x0008 },
|
||||
{ 0x01, 0x00, -1, 0x03, 0x0008, 0x0009 },
|
||||
{ 0x00, 0x01, -1, 0x03, 0x0000, 0x000a },
|
||||
{ 0x00, 0x01, -1, 0x03, 0x0000, 0x000c },
|
||||
{ 0x00, 0x02, -1, 0x03, 0x0000, 0x000e },
|
||||
{ 0x00, 0x02, -1, 0x03, 0x0000, 0x0012 },
|
||||
{ 0x00, 0x03, -1, 0x03, 0x0000, 0x0016 },
|
||||
{ 0x00, 0x03, -1, 0x03, 0x0000, 0x001e },
|
||||
{ 0x00, 0x04, -1, 0x03, 0x0000, 0x0026 },
|
||||
{ 0x00, 0x04, -1, 0x03, 0x0000, 0x0036 },
|
||||
{ 0x00, 0x01, -1, 0x03, 0x0001, 0x000a },
|
||||
{ 0x00, 0x01, -1, 0x03, 0x0001, 0x000c },
|
||||
{ 0x00, 0x02, -1, 0x03, 0x0001, 0x000e },
|
||||
{ 0x00, 0x02, -1, 0x03, 0x0001, 0x0012 },
|
||||
{ 0x00, 0x03, -1, 0x03, 0x0001, 0x0016 },
|
||||
{ 0x00, 0x03, -1, 0x03, 0x0001, 0x001e },
|
||||
{ 0x00, 0x04, -1, 0x03, 0x0001, 0x0026 },
|
||||
{ 0x00, 0x04, -1, 0x03, 0x0001, 0x0036 },
|
||||
{ 0x00, 0x01, -1, 0x03, 0x0002, 0x000a },
|
||||
{ 0x00, 0x01, -1, 0x03, 0x0002, 0x000c },
|
||||
{ 0x00, 0x02, -1, 0x03, 0x0002, 0x000e },
|
||||
{ 0x00, 0x02, -1, 0x03, 0x0002, 0x0012 },
|
||||
{ 0x00, 0x03, -1, 0x03, 0x0002, 0x0016 },
|
||||
{ 0x00, 0x03, -1, 0x03, 0x0002, 0x001e },
|
||||
{ 0x00, 0x04, -1, 0x03, 0x0002, 0x0026 },
|
||||
{ 0x00, 0x04, -1, 0x03, 0x0002, 0x0036 },
|
||||
{ 0x00, 0x01, -1, 0x03, 0x0003, 0x000a },
|
||||
{ 0x00, 0x01, -1, 0x03, 0x0003, 0x000c },
|
||||
{ 0x00, 0x02, -1, 0x03, 0x0003, 0x000e },
|
||||
{ 0x00, 0x02, -1, 0x03, 0x0003, 0x0012 },
|
||||
{ 0x00, 0x03, -1, 0x03, 0x0003, 0x0016 },
|
||||
{ 0x00, 0x03, -1, 0x03, 0x0003, 0x001e },
|
||||
{ 0x00, 0x04, -1, 0x03, 0x0003, 0x0026 },
|
||||
{ 0x00, 0x04, -1, 0x03, 0x0003, 0x0036 },
|
||||
{ 0x00, 0x01, -1, 0x03, 0x0004, 0x000a },
|
||||
{ 0x00, 0x01, -1, 0x03, 0x0004, 0x000c },
|
||||
{ 0x00, 0x02, -1, 0x03, 0x0004, 0x000e },
|
||||
{ 0x00, 0x02, -1, 0x03, 0x0004, 0x0012 },
|
||||
{ 0x00, 0x03, -1, 0x03, 0x0004, 0x0016 },
|
||||
{ 0x00, 0x03, -1, 0x03, 0x0004, 0x001e },
|
||||
{ 0x00, 0x04, -1, 0x03, 0x0004, 0x0026 },
|
||||
{ 0x00, 0x04, -1, 0x03, 0x0004, 0x0036 },
|
||||
{ 0x00, 0x01, -1, 0x03, 0x0005, 0x000a },
|
||||
{ 0x00, 0x01, -1, 0x03, 0x0005, 0x000c },
|
||||
{ 0x00, 0x02, -1, 0x03, 0x0005, 0x000e },
|
||||
{ 0x00, 0x02, -1, 0x03, 0x0005, 0x0012 },
|
||||
{ 0x00, 0x03, -1, 0x03, 0x0005, 0x0016 },
|
||||
{ 0x00, 0x03, -1, 0x03, 0x0005, 0x001e },
|
||||
{ 0x00, 0x04, -1, 0x03, 0x0005, 0x0026 },
|
||||
{ 0x00, 0x04, -1, 0x03, 0x0005, 0x0036 },
|
||||
{ 0x01, 0x01, -1, 0x03, 0x0006, 0x000a },
|
||||
{ 0x01, 0x01, -1, 0x03, 0x0006, 0x000c },
|
||||
{ 0x01, 0x02, -1, 0x03, 0x0006, 0x000e },
|
||||
{ 0x01, 0x02, -1, 0x03, 0x0006, 0x0012 },
|
||||
{ 0x01, 0x03, -1, 0x03, 0x0006, 0x0016 },
|
||||
{ 0x01, 0x03, -1, 0x03, 0x0006, 0x001e },
|
||||
{ 0x01, 0x04, -1, 0x03, 0x0006, 0x0026 },
|
||||
{ 0x01, 0x04, -1, 0x03, 0x0006, 0x0036 },
|
||||
{ 0x01, 0x01, -1, 0x03, 0x0008, 0x000a },
|
||||
{ 0x01, 0x01, -1, 0x03, 0x0008, 0x000c },
|
||||
{ 0x01, 0x02, -1, 0x03, 0x0008, 0x000e },
|
||||
{ 0x01, 0x02, -1, 0x03, 0x0008, 0x0012 },
|
||||
{ 0x01, 0x03, -1, 0x03, 0x0008, 0x0016 },
|
||||
{ 0x01, 0x03, -1, 0x03, 0x0008, 0x001e },
|
||||
{ 0x01, 0x04, -1, 0x03, 0x0008, 0x0026 },
|
||||
{ 0x01, 0x04, -1, 0x03, 0x0008, 0x0036 },
|
||||
{ 0x02, 0x00, -1, 0x00, 0x000a, 0x0002 },
|
||||
{ 0x02, 0x00, -1, 0x01, 0x000a, 0x0003 },
|
||||
{ 0x02, 0x00, -1, 0x02, 0x000a, 0x0004 },
|
||||
{ 0x02, 0x00, -1, 0x03, 0x000a, 0x0005 },
|
||||
{ 0x02, 0x00, -1, 0x03, 0x000a, 0x0006 },
|
||||
{ 0x02, 0x00, -1, 0x03, 0x000a, 0x0007 },
|
||||
{ 0x02, 0x00, -1, 0x03, 0x000a, 0x0008 },
|
||||
{ 0x02, 0x00, -1, 0x03, 0x000a, 0x0009 },
|
||||
{ 0x02, 0x00, -1, 0x00, 0x000e, 0x0002 },
|
||||
{ 0x02, 0x00, -1, 0x01, 0x000e, 0x0003 },
|
||||
{ 0x02, 0x00, -1, 0x02, 0x000e, 0x0004 },
|
||||
{ 0x02, 0x00, -1, 0x03, 0x000e, 0x0005 },
|
||||
{ 0x02, 0x00, -1, 0x03, 0x000e, 0x0006 },
|
||||
{ 0x02, 0x00, -1, 0x03, 0x000e, 0x0007 },
|
||||
{ 0x02, 0x00, -1, 0x03, 0x000e, 0x0008 },
|
||||
{ 0x02, 0x00, -1, 0x03, 0x000e, 0x0009 },
|
||||
{ 0x03, 0x00, -1, 0x00, 0x0012, 0x0002 },
|
||||
{ 0x03, 0x00, -1, 0x01, 0x0012, 0x0003 },
|
||||
{ 0x03, 0x00, -1, 0x02, 0x0012, 0x0004 },
|
||||
{ 0x03, 0x00, -1, 0x03, 0x0012, 0x0005 },
|
||||
{ 0x03, 0x00, -1, 0x03, 0x0012, 0x0006 },
|
||||
{ 0x03, 0x00, -1, 0x03, 0x0012, 0x0007 },
|
||||
{ 0x03, 0x00, -1, 0x03, 0x0012, 0x0008 },
|
||||
{ 0x03, 0x00, -1, 0x03, 0x0012, 0x0009 },
|
||||
{ 0x03, 0x00, -1, 0x00, 0x001a, 0x0002 },
|
||||
{ 0x03, 0x00, -1, 0x01, 0x001a, 0x0003 },
|
||||
{ 0x03, 0x00, -1, 0x02, 0x001a, 0x0004 },
|
||||
{ 0x03, 0x00, -1, 0x03, 0x001a, 0x0005 },
|
||||
{ 0x03, 0x00, -1, 0x03, 0x001a, 0x0006 },
|
||||
{ 0x03, 0x00, -1, 0x03, 0x001a, 0x0007 },
|
||||
{ 0x03, 0x00, -1, 0x03, 0x001a, 0x0008 },
|
||||
{ 0x03, 0x00, -1, 0x03, 0x001a, 0x0009 },
|
||||
{ 0x04, 0x00, -1, 0x00, 0x0022, 0x0002 },
|
||||
{ 0x04, 0x00, -1, 0x01, 0x0022, 0x0003 },
|
||||
{ 0x04, 0x00, -1, 0x02, 0x0022, 0x0004 },
|
||||
{ 0x04, 0x00, -1, 0x03, 0x0022, 0x0005 },
|
||||
{ 0x04, 0x00, -1, 0x03, 0x0022, 0x0006 },
|
||||
{ 0x04, 0x00, -1, 0x03, 0x0022, 0x0007 },
|
||||
{ 0x04, 0x00, -1, 0x03, 0x0022, 0x0008 },
|
||||
{ 0x04, 0x00, -1, 0x03, 0x0022, 0x0009 },
|
||||
{ 0x04, 0x00, -1, 0x00, 0x0032, 0x0002 },
|
||||
{ 0x04, 0x00, -1, 0x01, 0x0032, 0x0003 },
|
||||
{ 0x04, 0x00, -1, 0x02, 0x0032, 0x0004 },
|
||||
{ 0x04, 0x00, -1, 0x03, 0x0032, 0x0005 },
|
||||
{ 0x04, 0x00, -1, 0x03, 0x0032, 0x0006 },
|
||||
{ 0x04, 0x00, -1, 0x03, 0x0032, 0x0007 },
|
||||
{ 0x04, 0x00, -1, 0x03, 0x0032, 0x0008 },
|
||||
{ 0x04, 0x00, -1, 0x03, 0x0032, 0x0009 },
|
||||
{ 0x05, 0x00, -1, 0x00, 0x0042, 0x0002 },
|
||||
{ 0x05, 0x00, -1, 0x01, 0x0042, 0x0003 },
|
||||
{ 0x05, 0x00, -1, 0x02, 0x0042, 0x0004 },
|
||||
{ 0x05, 0x00, -1, 0x03, 0x0042, 0x0005 },
|
||||
{ 0x05, 0x00, -1, 0x03, 0x0042, 0x0006 },
|
||||
{ 0x05, 0x00, -1, 0x03, 0x0042, 0x0007 },
|
||||
{ 0x05, 0x00, -1, 0x03, 0x0042, 0x0008 },
|
||||
{ 0x05, 0x00, -1, 0x03, 0x0042, 0x0009 },
|
||||
{ 0x05, 0x00, -1, 0x00, 0x0062, 0x0002 },
|
||||
{ 0x05, 0x00, -1, 0x01, 0x0062, 0x0003 },
|
||||
{ 0x05, 0x00, -1, 0x02, 0x0062, 0x0004 },
|
||||
{ 0x05, 0x00, -1, 0x03, 0x0062, 0x0005 },
|
||||
{ 0x05, 0x00, -1, 0x03, 0x0062, 0x0006 },
|
||||
{ 0x05, 0x00, -1, 0x03, 0x0062, 0x0007 },
|
||||
{ 0x05, 0x00, -1, 0x03, 0x0062, 0x0008 },
|
||||
{ 0x05, 0x00, -1, 0x03, 0x0062, 0x0009 },
|
||||
{ 0x02, 0x01, -1, 0x03, 0x000a, 0x000a },
|
||||
{ 0x02, 0x01, -1, 0x03, 0x000a, 0x000c },
|
||||
{ 0x02, 0x02, -1, 0x03, 0x000a, 0x000e },
|
||||
{ 0x02, 0x02, -1, 0x03, 0x000a, 0x0012 },
|
||||
{ 0x02, 0x03, -1, 0x03, 0x000a, 0x0016 },
|
||||
{ 0x02, 0x03, -1, 0x03, 0x000a, 0x001e },
|
||||
{ 0x02, 0x04, -1, 0x03, 0x000a, 0x0026 },
|
||||
{ 0x02, 0x04, -1, 0x03, 0x000a, 0x0036 },
|
||||
{ 0x02, 0x01, -1, 0x03, 0x000e, 0x000a },
|
||||
{ 0x02, 0x01, -1, 0x03, 0x000e, 0x000c },
|
||||
{ 0x02, 0x02, -1, 0x03, 0x000e, 0x000e },
|
||||
{ 0x02, 0x02, -1, 0x03, 0x000e, 0x0012 },
|
||||
{ 0x02, 0x03, -1, 0x03, 0x000e, 0x0016 },
|
||||
{ 0x02, 0x03, -1, 0x03, 0x000e, 0x001e },
|
||||
{ 0x02, 0x04, -1, 0x03, 0x000e, 0x0026 },
|
||||
{ 0x02, 0x04, -1, 0x03, 0x000e, 0x0036 },
|
||||
{ 0x03, 0x01, -1, 0x03, 0x0012, 0x000a },
|
||||
{ 0x03, 0x01, -1, 0x03, 0x0012, 0x000c },
|
||||
{ 0x03, 0x02, -1, 0x03, 0x0012, 0x000e },
|
||||
{ 0x03, 0x02, -1, 0x03, 0x0012, 0x0012 },
|
||||
{ 0x03, 0x03, -1, 0x03, 0x0012, 0x0016 },
|
||||
{ 0x03, 0x03, -1, 0x03, 0x0012, 0x001e },
|
||||
{ 0x03, 0x04, -1, 0x03, 0x0012, 0x0026 },
|
||||
{ 0x03, 0x04, -1, 0x03, 0x0012, 0x0036 },
|
||||
{ 0x03, 0x01, -1, 0x03, 0x001a, 0x000a },
|
||||
{ 0x03, 0x01, -1, 0x03, 0x001a, 0x000c },
|
||||
{ 0x03, 0x02, -1, 0x03, 0x001a, 0x000e },
|
||||
{ 0x03, 0x02, -1, 0x03, 0x001a, 0x0012 },
|
||||
{ 0x03, 0x03, -1, 0x03, 0x001a, 0x0016 },
|
||||
{ 0x03, 0x03, -1, 0x03, 0x001a, 0x001e },
|
||||
{ 0x03, 0x04, -1, 0x03, 0x001a, 0x0026 },
|
||||
{ 0x03, 0x04, -1, 0x03, 0x001a, 0x0036 },
|
||||
{ 0x04, 0x01, -1, 0x03, 0x0022, 0x000a },
|
||||
{ 0x04, 0x01, -1, 0x03, 0x0022, 0x000c },
|
||||
{ 0x04, 0x02, -1, 0x03, 0x0022, 0x000e },
|
||||
{ 0x04, 0x02, -1, 0x03, 0x0022, 0x0012 },
|
||||
{ 0x04, 0x03, -1, 0x03, 0x0022, 0x0016 },
|
||||
{ 0x04, 0x03, -1, 0x03, 0x0022, 0x001e },
|
||||
{ 0x04, 0x04, -1, 0x03, 0x0022, 0x0026 },
|
||||
{ 0x04, 0x04, -1, 0x03, 0x0022, 0x0036 },
|
||||
{ 0x04, 0x01, -1, 0x03, 0x0032, 0x000a },
|
||||
{ 0x04, 0x01, -1, 0x03, 0x0032, 0x000c },
|
||||
{ 0x04, 0x02, -1, 0x03, 0x0032, 0x000e },
|
||||
{ 0x04, 0x02, -1, 0x03, 0x0032, 0x0012 },
|
||||
{ 0x04, 0x03, -1, 0x03, 0x0032, 0x0016 },
|
||||
{ 0x04, 0x03, -1, 0x03, 0x0032, 0x001e },
|
||||
{ 0x04, 0x04, -1, 0x03, 0x0032, 0x0026 },
|
||||
{ 0x04, 0x04, -1, 0x03, 0x0032, 0x0036 },
|
||||
{ 0x05, 0x01, -1, 0x03, 0x0042, 0x000a },
|
||||
{ 0x05, 0x01, -1, 0x03, 0x0042, 0x000c },
|
||||
{ 0x05, 0x02, -1, 0x03, 0x0042, 0x000e },
|
||||
{ 0x05, 0x02, -1, 0x03, 0x0042, 0x0012 },
|
||||
{ 0x05, 0x03, -1, 0x03, 0x0042, 0x0016 },
|
||||
{ 0x05, 0x03, -1, 0x03, 0x0042, 0x001e },
|
||||
{ 0x05, 0x04, -1, 0x03, 0x0042, 0x0026 },
|
||||
{ 0x05, 0x04, -1, 0x03, 0x0042, 0x0036 },
|
||||
{ 0x05, 0x01, -1, 0x03, 0x0062, 0x000a },
|
||||
{ 0x05, 0x01, -1, 0x03, 0x0062, 0x000c },
|
||||
{ 0x05, 0x02, -1, 0x03, 0x0062, 0x000e },
|
||||
{ 0x05, 0x02, -1, 0x03, 0x0062, 0x0012 },
|
||||
{ 0x05, 0x03, -1, 0x03, 0x0062, 0x0016 },
|
||||
{ 0x05, 0x03, -1, 0x03, 0x0062, 0x001e },
|
||||
{ 0x05, 0x04, -1, 0x03, 0x0062, 0x0026 },
|
||||
{ 0x05, 0x04, -1, 0x03, 0x0062, 0x0036 },
|
||||
{ 0x00, 0x05, -1, 0x03, 0x0000, 0x0046 },
|
||||
{ 0x00, 0x05, -1, 0x03, 0x0000, 0x0066 },
|
||||
{ 0x00, 0x06, -1, 0x03, 0x0000, 0x0086 },
|
||||
{ 0x00, 0x07, -1, 0x03, 0x0000, 0x00c6 },
|
||||
{ 0x00, 0x08, -1, 0x03, 0x0000, 0x0146 },
|
||||
{ 0x00, 0x09, -1, 0x03, 0x0000, 0x0246 },
|
||||
{ 0x00, 0x0a, -1, 0x03, 0x0000, 0x0446 },
|
||||
{ 0x00, 0x18, -1, 0x03, 0x0000, 0x0846 },
|
||||
{ 0x00, 0x05, -1, 0x03, 0x0001, 0x0046 },
|
||||
{ 0x00, 0x05, -1, 0x03, 0x0001, 0x0066 },
|
||||
{ 0x00, 0x06, -1, 0x03, 0x0001, 0x0086 },
|
||||
{ 0x00, 0x07, -1, 0x03, 0x0001, 0x00c6 },
|
||||
{ 0x00, 0x08, -1, 0x03, 0x0001, 0x0146 },
|
||||
{ 0x00, 0x09, -1, 0x03, 0x0001, 0x0246 },
|
||||
{ 0x00, 0x0a, -1, 0x03, 0x0001, 0x0446 },
|
||||
{ 0x00, 0x18, -1, 0x03, 0x0001, 0x0846 },
|
||||
{ 0x00, 0x05, -1, 0x03, 0x0002, 0x0046 },
|
||||
{ 0x00, 0x05, -1, 0x03, 0x0002, 0x0066 },
|
||||
{ 0x00, 0x06, -1, 0x03, 0x0002, 0x0086 },
|
||||
{ 0x00, 0x07, -1, 0x03, 0x0002, 0x00c6 },
|
||||
{ 0x00, 0x08, -1, 0x03, 0x0002, 0x0146 },
|
||||
{ 0x00, 0x09, -1, 0x03, 0x0002, 0x0246 },
|
||||
{ 0x00, 0x0a, -1, 0x03, 0x0002, 0x0446 },
|
||||
{ 0x00, 0x18, -1, 0x03, 0x0002, 0x0846 },
|
||||
{ 0x00, 0x05, -1, 0x03, 0x0003, 0x0046 },
|
||||
{ 0x00, 0x05, -1, 0x03, 0x0003, 0x0066 },
|
||||
{ 0x00, 0x06, -1, 0x03, 0x0003, 0x0086 },
|
||||
{ 0x00, 0x07, -1, 0x03, 0x0003, 0x00c6 },
|
||||
{ 0x00, 0x08, -1, 0x03, 0x0003, 0x0146 },
|
||||
{ 0x00, 0x09, -1, 0x03, 0x0003, 0x0246 },
|
||||
{ 0x00, 0x0a, -1, 0x03, 0x0003, 0x0446 },
|
||||
{ 0x00, 0x18, -1, 0x03, 0x0003, 0x0846 },
|
||||
{ 0x00, 0x05, -1, 0x03, 0x0004, 0x0046 },
|
||||
{ 0x00, 0x05, -1, 0x03, 0x0004, 0x0066 },
|
||||
{ 0x00, 0x06, -1, 0x03, 0x0004, 0x0086 },
|
||||
{ 0x00, 0x07, -1, 0x03, 0x0004, 0x00c6 },
|
||||
{ 0x00, 0x08, -1, 0x03, 0x0004, 0x0146 },
|
||||
{ 0x00, 0x09, -1, 0x03, 0x0004, 0x0246 },
|
||||
{ 0x00, 0x0a, -1, 0x03, 0x0004, 0x0446 },
|
||||
{ 0x00, 0x18, -1, 0x03, 0x0004, 0x0846 },
|
||||
{ 0x00, 0x05, -1, 0x03, 0x0005, 0x0046 },
|
||||
{ 0x00, 0x05, -1, 0x03, 0x0005, 0x0066 },
|
||||
{ 0x00, 0x06, -1, 0x03, 0x0005, 0x0086 },
|
||||
{ 0x00, 0x07, -1, 0x03, 0x0005, 0x00c6 },
|
||||
{ 0x00, 0x08, -1, 0x03, 0x0005, 0x0146 },
|
||||
{ 0x00, 0x09, -1, 0x03, 0x0005, 0x0246 },
|
||||
{ 0x00, 0x0a, -1, 0x03, 0x0005, 0x0446 },
|
||||
{ 0x00, 0x18, -1, 0x03, 0x0005, 0x0846 },
|
||||
{ 0x01, 0x05, -1, 0x03, 0x0006, 0x0046 },
|
||||
{ 0x01, 0x05, -1, 0x03, 0x0006, 0x0066 },
|
||||
{ 0x01, 0x06, -1, 0x03, 0x0006, 0x0086 },
|
||||
{ 0x01, 0x07, -1, 0x03, 0x0006, 0x00c6 },
|
||||
{ 0x01, 0x08, -1, 0x03, 0x0006, 0x0146 },
|
||||
{ 0x01, 0x09, -1, 0x03, 0x0006, 0x0246 },
|
||||
{ 0x01, 0x0a, -1, 0x03, 0x0006, 0x0446 },
|
||||
{ 0x01, 0x18, -1, 0x03, 0x0006, 0x0846 },
|
||||
{ 0x01, 0x05, -1, 0x03, 0x0008, 0x0046 },
|
||||
{ 0x01, 0x05, -1, 0x03, 0x0008, 0x0066 },
|
||||
{ 0x01, 0x06, -1, 0x03, 0x0008, 0x0086 },
|
||||
{ 0x01, 0x07, -1, 0x03, 0x0008, 0x00c6 },
|
||||
{ 0x01, 0x08, -1, 0x03, 0x0008, 0x0146 },
|
||||
{ 0x01, 0x09, -1, 0x03, 0x0008, 0x0246 },
|
||||
{ 0x01, 0x0a, -1, 0x03, 0x0008, 0x0446 },
|
||||
{ 0x01, 0x18, -1, 0x03, 0x0008, 0x0846 },
|
||||
{ 0x06, 0x00, -1, 0x00, 0x0082, 0x0002 },
|
||||
{ 0x06, 0x00, -1, 0x01, 0x0082, 0x0003 },
|
||||
{ 0x06, 0x00, -1, 0x02, 0x0082, 0x0004 },
|
||||
{ 0x06, 0x00, -1, 0x03, 0x0082, 0x0005 },
|
||||
{ 0x06, 0x00, -1, 0x03, 0x0082, 0x0006 },
|
||||
{ 0x06, 0x00, -1, 0x03, 0x0082, 0x0007 },
|
||||
{ 0x06, 0x00, -1, 0x03, 0x0082, 0x0008 },
|
||||
{ 0x06, 0x00, -1, 0x03, 0x0082, 0x0009 },
|
||||
{ 0x07, 0x00, -1, 0x00, 0x00c2, 0x0002 },
|
||||
{ 0x07, 0x00, -1, 0x01, 0x00c2, 0x0003 },
|
||||
{ 0x07, 0x00, -1, 0x02, 0x00c2, 0x0004 },
|
||||
{ 0x07, 0x00, -1, 0x03, 0x00c2, 0x0005 },
|
||||
{ 0x07, 0x00, -1, 0x03, 0x00c2, 0x0006 },
|
||||
{ 0x07, 0x00, -1, 0x03, 0x00c2, 0x0007 },
|
||||
{ 0x07, 0x00, -1, 0x03, 0x00c2, 0x0008 },
|
||||
{ 0x07, 0x00, -1, 0x03, 0x00c2, 0x0009 },
|
||||
{ 0x08, 0x00, -1, 0x00, 0x0142, 0x0002 },
|
||||
{ 0x08, 0x00, -1, 0x01, 0x0142, 0x0003 },
|
||||
{ 0x08, 0x00, -1, 0x02, 0x0142, 0x0004 },
|
||||
{ 0x08, 0x00, -1, 0x03, 0x0142, 0x0005 },
|
||||
{ 0x08, 0x00, -1, 0x03, 0x0142, 0x0006 },
|
||||
{ 0x08, 0x00, -1, 0x03, 0x0142, 0x0007 },
|
||||
{ 0x08, 0x00, -1, 0x03, 0x0142, 0x0008 },
|
||||
{ 0x08, 0x00, -1, 0x03, 0x0142, 0x0009 },
|
||||
{ 0x09, 0x00, -1, 0x00, 0x0242, 0x0002 },
|
||||
{ 0x09, 0x00, -1, 0x01, 0x0242, 0x0003 },
|
||||
{ 0x09, 0x00, -1, 0x02, 0x0242, 0x0004 },
|
||||
{ 0x09, 0x00, -1, 0x03, 0x0242, 0x0005 },
|
||||
{ 0x09, 0x00, -1, 0x03, 0x0242, 0x0006 },
|
||||
{ 0x09, 0x00, -1, 0x03, 0x0242, 0x0007 },
|
||||
{ 0x09, 0x00, -1, 0x03, 0x0242, 0x0008 },
|
||||
{ 0x09, 0x00, -1, 0x03, 0x0242, 0x0009 },
|
||||
{ 0x0a, 0x00, -1, 0x00, 0x0442, 0x0002 },
|
||||
{ 0x0a, 0x00, -1, 0x01, 0x0442, 0x0003 },
|
||||
{ 0x0a, 0x00, -1, 0x02, 0x0442, 0x0004 },
|
||||
{ 0x0a, 0x00, -1, 0x03, 0x0442, 0x0005 },
|
||||
{ 0x0a, 0x00, -1, 0x03, 0x0442, 0x0006 },
|
||||
{ 0x0a, 0x00, -1, 0x03, 0x0442, 0x0007 },
|
||||
{ 0x0a, 0x00, -1, 0x03, 0x0442, 0x0008 },
|
||||
{ 0x0a, 0x00, -1, 0x03, 0x0442, 0x0009 },
|
||||
{ 0x0c, 0x00, -1, 0x00, 0x0842, 0x0002 },
|
||||
{ 0x0c, 0x00, -1, 0x01, 0x0842, 0x0003 },
|
||||
{ 0x0c, 0x00, -1, 0x02, 0x0842, 0x0004 },
|
||||
{ 0x0c, 0x00, -1, 0x03, 0x0842, 0x0005 },
|
||||
{ 0x0c, 0x00, -1, 0x03, 0x0842, 0x0006 },
|
||||
{ 0x0c, 0x00, -1, 0x03, 0x0842, 0x0007 },
|
||||
{ 0x0c, 0x00, -1, 0x03, 0x0842, 0x0008 },
|
||||
{ 0x0c, 0x00, -1, 0x03, 0x0842, 0x0009 },
|
||||
{ 0x0e, 0x00, -1, 0x00, 0x1842, 0x0002 },
|
||||
{ 0x0e, 0x00, -1, 0x01, 0x1842, 0x0003 },
|
||||
{ 0x0e, 0x00, -1, 0x02, 0x1842, 0x0004 },
|
||||
{ 0x0e, 0x00, -1, 0x03, 0x1842, 0x0005 },
|
||||
{ 0x0e, 0x00, -1, 0x03, 0x1842, 0x0006 },
|
||||
{ 0x0e, 0x00, -1, 0x03, 0x1842, 0x0007 },
|
||||
{ 0x0e, 0x00, -1, 0x03, 0x1842, 0x0008 },
|
||||
{ 0x0e, 0x00, -1, 0x03, 0x1842, 0x0009 },
|
||||
{ 0x18, 0x00, -1, 0x00, 0x5842, 0x0002 },
|
||||
{ 0x18, 0x00, -1, 0x01, 0x5842, 0x0003 },
|
||||
{ 0x18, 0x00, -1, 0x02, 0x5842, 0x0004 },
|
||||
{ 0x18, 0x00, -1, 0x03, 0x5842, 0x0005 },
|
||||
{ 0x18, 0x00, -1, 0x03, 0x5842, 0x0006 },
|
||||
{ 0x18, 0x00, -1, 0x03, 0x5842, 0x0007 },
|
||||
{ 0x18, 0x00, -1, 0x03, 0x5842, 0x0008 },
|
||||
{ 0x18, 0x00, -1, 0x03, 0x5842, 0x0009 },
|
||||
{ 0x02, 0x05, -1, 0x03, 0x000a, 0x0046 },
|
||||
{ 0x02, 0x05, -1, 0x03, 0x000a, 0x0066 },
|
||||
{ 0x02, 0x06, -1, 0x03, 0x000a, 0x0086 },
|
||||
{ 0x02, 0x07, -1, 0x03, 0x000a, 0x00c6 },
|
||||
{ 0x02, 0x08, -1, 0x03, 0x000a, 0x0146 },
|
||||
{ 0x02, 0x09, -1, 0x03, 0x000a, 0x0246 },
|
||||
{ 0x02, 0x0a, -1, 0x03, 0x000a, 0x0446 },
|
||||
{ 0x02, 0x18, -1, 0x03, 0x000a, 0x0846 },
|
||||
{ 0x02, 0x05, -1, 0x03, 0x000e, 0x0046 },
|
||||
{ 0x02, 0x05, -1, 0x03, 0x000e, 0x0066 },
|
||||
{ 0x02, 0x06, -1, 0x03, 0x000e, 0x0086 },
|
||||
{ 0x02, 0x07, -1, 0x03, 0x000e, 0x00c6 },
|
||||
{ 0x02, 0x08, -1, 0x03, 0x000e, 0x0146 },
|
||||
{ 0x02, 0x09, -1, 0x03, 0x000e, 0x0246 },
|
||||
{ 0x02, 0x0a, -1, 0x03, 0x000e, 0x0446 },
|
||||
{ 0x02, 0x18, -1, 0x03, 0x000e, 0x0846 },
|
||||
{ 0x03, 0x05, -1, 0x03, 0x0012, 0x0046 },
|
||||
{ 0x03, 0x05, -1, 0x03, 0x0012, 0x0066 },
|
||||
{ 0x03, 0x06, -1, 0x03, 0x0012, 0x0086 },
|
||||
{ 0x03, 0x07, -1, 0x03, 0x0012, 0x00c6 },
|
||||
{ 0x03, 0x08, -1, 0x03, 0x0012, 0x0146 },
|
||||
{ 0x03, 0x09, -1, 0x03, 0x0012, 0x0246 },
|
||||
{ 0x03, 0x0a, -1, 0x03, 0x0012, 0x0446 },
|
||||
{ 0x03, 0x18, -1, 0x03, 0x0012, 0x0846 },
|
||||
{ 0x03, 0x05, -1, 0x03, 0x001a, 0x0046 },
|
||||
{ 0x03, 0x05, -1, 0x03, 0x001a, 0x0066 },
|
||||
{ 0x03, 0x06, -1, 0x03, 0x001a, 0x0086 },
|
||||
{ 0x03, 0x07, -1, 0x03, 0x001a, 0x00c6 },
|
||||
{ 0x03, 0x08, -1, 0x03, 0x001a, 0x0146 },
|
||||
{ 0x03, 0x09, -1, 0x03, 0x001a, 0x0246 },
|
||||
{ 0x03, 0x0a, -1, 0x03, 0x001a, 0x0446 },
|
||||
{ 0x03, 0x18, -1, 0x03, 0x001a, 0x0846 },
|
||||
{ 0x04, 0x05, -1, 0x03, 0x0022, 0x0046 },
|
||||
{ 0x04, 0x05, -1, 0x03, 0x0022, 0x0066 },
|
||||
{ 0x04, 0x06, -1, 0x03, 0x0022, 0x0086 },
|
||||
{ 0x04, 0x07, -1, 0x03, 0x0022, 0x00c6 },
|
||||
{ 0x04, 0x08, -1, 0x03, 0x0022, 0x0146 },
|
||||
{ 0x04, 0x09, -1, 0x03, 0x0022, 0x0246 },
|
||||
{ 0x04, 0x0a, -1, 0x03, 0x0022, 0x0446 },
|
||||
{ 0x04, 0x18, -1, 0x03, 0x0022, 0x0846 },
|
||||
{ 0x04, 0x05, -1, 0x03, 0x0032, 0x0046 },
|
||||
{ 0x04, 0x05, -1, 0x03, 0x0032, 0x0066 },
|
||||
{ 0x04, 0x06, -1, 0x03, 0x0032, 0x0086 },
|
||||
{ 0x04, 0x07, -1, 0x03, 0x0032, 0x00c6 },
|
||||
{ 0x04, 0x08, -1, 0x03, 0x0032, 0x0146 },
|
||||
{ 0x04, 0x09, -1, 0x03, 0x0032, 0x0246 },
|
||||
{ 0x04, 0x0a, -1, 0x03, 0x0032, 0x0446 },
|
||||
{ 0x04, 0x18, -1, 0x03, 0x0032, 0x0846 },
|
||||
{ 0x05, 0x05, -1, 0x03, 0x0042, 0x0046 },
|
||||
{ 0x05, 0x05, -1, 0x03, 0x0042, 0x0066 },
|
||||
{ 0x05, 0x06, -1, 0x03, 0x0042, 0x0086 },
|
||||
{ 0x05, 0x07, -1, 0x03, 0x0042, 0x00c6 },
|
||||
{ 0x05, 0x08, -1, 0x03, 0x0042, 0x0146 },
|
||||
{ 0x05, 0x09, -1, 0x03, 0x0042, 0x0246 },
|
||||
{ 0x05, 0x0a, -1, 0x03, 0x0042, 0x0446 },
|
||||
{ 0x05, 0x18, -1, 0x03, 0x0042, 0x0846 },
|
||||
{ 0x05, 0x05, -1, 0x03, 0x0062, 0x0046 },
|
||||
{ 0x05, 0x05, -1, 0x03, 0x0062, 0x0066 },
|
||||
{ 0x05, 0x06, -1, 0x03, 0x0062, 0x0086 },
|
||||
{ 0x05, 0x07, -1, 0x03, 0x0062, 0x00c6 },
|
||||
{ 0x05, 0x08, -1, 0x03, 0x0062, 0x0146 },
|
||||
{ 0x05, 0x09, -1, 0x03, 0x0062, 0x0246 },
|
||||
{ 0x05, 0x0a, -1, 0x03, 0x0062, 0x0446 },
|
||||
{ 0x05, 0x18, -1, 0x03, 0x0062, 0x0846 },
|
||||
{ 0x06, 0x01, -1, 0x03, 0x0082, 0x000a },
|
||||
{ 0x06, 0x01, -1, 0x03, 0x0082, 0x000c },
|
||||
{ 0x06, 0x02, -1, 0x03, 0x0082, 0x000e },
|
||||
{ 0x06, 0x02, -1, 0x03, 0x0082, 0x0012 },
|
||||
{ 0x06, 0x03, -1, 0x03, 0x0082, 0x0016 },
|
||||
{ 0x06, 0x03, -1, 0x03, 0x0082, 0x001e },
|
||||
{ 0x06, 0x04, -1, 0x03, 0x0082, 0x0026 },
|
||||
{ 0x06, 0x04, -1, 0x03, 0x0082, 0x0036 },
|
||||
{ 0x07, 0x01, -1, 0x03, 0x00c2, 0x000a },
|
||||
{ 0x07, 0x01, -1, 0x03, 0x00c2, 0x000c },
|
||||
{ 0x07, 0x02, -1, 0x03, 0x00c2, 0x000e },
|
||||
{ 0x07, 0x02, -1, 0x03, 0x00c2, 0x0012 },
|
||||
{ 0x07, 0x03, -1, 0x03, 0x00c2, 0x0016 },
|
||||
{ 0x07, 0x03, -1, 0x03, 0x00c2, 0x001e },
|
||||
{ 0x07, 0x04, -1, 0x03, 0x00c2, 0x0026 },
|
||||
{ 0x07, 0x04, -1, 0x03, 0x00c2, 0x0036 },
|
||||
{ 0x08, 0x01, -1, 0x03, 0x0142, 0x000a },
|
||||
{ 0x08, 0x01, -1, 0x03, 0x0142, 0x000c },
|
||||
{ 0x08, 0x02, -1, 0x03, 0x0142, 0x000e },
|
||||
{ 0x08, 0x02, -1, 0x03, 0x0142, 0x0012 },
|
||||
{ 0x08, 0x03, -1, 0x03, 0x0142, 0x0016 },
|
||||
{ 0x08, 0x03, -1, 0x03, 0x0142, 0x001e },
|
||||
{ 0x08, 0x04, -1, 0x03, 0x0142, 0x0026 },
|
||||
{ 0x08, 0x04, -1, 0x03, 0x0142, 0x0036 },
|
||||
{ 0x09, 0x01, -1, 0x03, 0x0242, 0x000a },
|
||||
{ 0x09, 0x01, -1, 0x03, 0x0242, 0x000c },
|
||||
{ 0x09, 0x02, -1, 0x03, 0x0242, 0x000e },
|
||||
{ 0x09, 0x02, -1, 0x03, 0x0242, 0x0012 },
|
||||
{ 0x09, 0x03, -1, 0x03, 0x0242, 0x0016 },
|
||||
{ 0x09, 0x03, -1, 0x03, 0x0242, 0x001e },
|
||||
{ 0x09, 0x04, -1, 0x03, 0x0242, 0x0026 },
|
||||
{ 0x09, 0x04, -1, 0x03, 0x0242, 0x0036 },
|
||||
{ 0x0a, 0x01, -1, 0x03, 0x0442, 0x000a },
|
||||
{ 0x0a, 0x01, -1, 0x03, 0x0442, 0x000c },
|
||||
{ 0x0a, 0x02, -1, 0x03, 0x0442, 0x000e },
|
||||
{ 0x0a, 0x02, -1, 0x03, 0x0442, 0x0012 },
|
||||
{ 0x0a, 0x03, -1, 0x03, 0x0442, 0x0016 },
|
||||
{ 0x0a, 0x03, -1, 0x03, 0x0442, 0x001e },
|
||||
{ 0x0a, 0x04, -1, 0x03, 0x0442, 0x0026 },
|
||||
{ 0x0a, 0x04, -1, 0x03, 0x0442, 0x0036 },
|
||||
{ 0x0c, 0x01, -1, 0x03, 0x0842, 0x000a },
|
||||
{ 0x0c, 0x01, -1, 0x03, 0x0842, 0x000c },
|
||||
{ 0x0c, 0x02, -1, 0x03, 0x0842, 0x000e },
|
||||
{ 0x0c, 0x02, -1, 0x03, 0x0842, 0x0012 },
|
||||
{ 0x0c, 0x03, -1, 0x03, 0x0842, 0x0016 },
|
||||
{ 0x0c, 0x03, -1, 0x03, 0x0842, 0x001e },
|
||||
{ 0x0c, 0x04, -1, 0x03, 0x0842, 0x0026 },
|
||||
{ 0x0c, 0x04, -1, 0x03, 0x0842, 0x0036 },
|
||||
{ 0x0e, 0x01, -1, 0x03, 0x1842, 0x000a },
|
||||
{ 0x0e, 0x01, -1, 0x03, 0x1842, 0x000c },
|
||||
{ 0x0e, 0x02, -1, 0x03, 0x1842, 0x000e },
|
||||
{ 0x0e, 0x02, -1, 0x03, 0x1842, 0x0012 },
|
||||
{ 0x0e, 0x03, -1, 0x03, 0x1842, 0x0016 },
|
||||
{ 0x0e, 0x03, -1, 0x03, 0x1842, 0x001e },
|
||||
{ 0x0e, 0x04, -1, 0x03, 0x1842, 0x0026 },
|
||||
{ 0x0e, 0x04, -1, 0x03, 0x1842, 0x0036 },
|
||||
{ 0x18, 0x01, -1, 0x03, 0x5842, 0x000a },
|
||||
{ 0x18, 0x01, -1, 0x03, 0x5842, 0x000c },
|
||||
{ 0x18, 0x02, -1, 0x03, 0x5842, 0x000e },
|
||||
{ 0x18, 0x02, -1, 0x03, 0x5842, 0x0012 },
|
||||
{ 0x18, 0x03, -1, 0x03, 0x5842, 0x0016 },
|
||||
{ 0x18, 0x03, -1, 0x03, 0x5842, 0x001e },
|
||||
{ 0x18, 0x04, -1, 0x03, 0x5842, 0x0026 },
|
||||
{ 0x18, 0x04, -1, 0x03, 0x5842, 0x0036 },
|
||||
{ 0x06, 0x05, -1, 0x03, 0x0082, 0x0046 },
|
||||
{ 0x06, 0x05, -1, 0x03, 0x0082, 0x0066 },
|
||||
{ 0x06, 0x06, -1, 0x03, 0x0082, 0x0086 },
|
||||
{ 0x06, 0x07, -1, 0x03, 0x0082, 0x00c6 },
|
||||
{ 0x06, 0x08, -1, 0x03, 0x0082, 0x0146 },
|
||||
{ 0x06, 0x09, -1, 0x03, 0x0082, 0x0246 },
|
||||
{ 0x06, 0x0a, -1, 0x03, 0x0082, 0x0446 },
|
||||
{ 0x06, 0x18, -1, 0x03, 0x0082, 0x0846 },
|
||||
{ 0x07, 0x05, -1, 0x03, 0x00c2, 0x0046 },
|
||||
{ 0x07, 0x05, -1, 0x03, 0x00c2, 0x0066 },
|
||||
{ 0x07, 0x06, -1, 0x03, 0x00c2, 0x0086 },
|
||||
{ 0x07, 0x07, -1, 0x03, 0x00c2, 0x00c6 },
|
||||
{ 0x07, 0x08, -1, 0x03, 0x00c2, 0x0146 },
|
||||
{ 0x07, 0x09, -1, 0x03, 0x00c2, 0x0246 },
|
||||
{ 0x07, 0x0a, -1, 0x03, 0x00c2, 0x0446 },
|
||||
{ 0x07, 0x18, -1, 0x03, 0x00c2, 0x0846 },
|
||||
{ 0x08, 0x05, -1, 0x03, 0x0142, 0x0046 },
|
||||
{ 0x08, 0x05, -1, 0x03, 0x0142, 0x0066 },
|
||||
{ 0x08, 0x06, -1, 0x03, 0x0142, 0x0086 },
|
||||
{ 0x08, 0x07, -1, 0x03, 0x0142, 0x00c6 },
|
||||
{ 0x08, 0x08, -1, 0x03, 0x0142, 0x0146 },
|
||||
{ 0x08, 0x09, -1, 0x03, 0x0142, 0x0246 },
|
||||
{ 0x08, 0x0a, -1, 0x03, 0x0142, 0x0446 },
|
||||
{ 0x08, 0x18, -1, 0x03, 0x0142, 0x0846 },
|
||||
{ 0x09, 0x05, -1, 0x03, 0x0242, 0x0046 },
|
||||
{ 0x09, 0x05, -1, 0x03, 0x0242, 0x0066 },
|
||||
{ 0x09, 0x06, -1, 0x03, 0x0242, 0x0086 },
|
||||
{ 0x09, 0x07, -1, 0x03, 0x0242, 0x00c6 },
|
||||
{ 0x09, 0x08, -1, 0x03, 0x0242, 0x0146 },
|
||||
{ 0x09, 0x09, -1, 0x03, 0x0242, 0x0246 },
|
||||
{ 0x09, 0x0a, -1, 0x03, 0x0242, 0x0446 },
|
||||
{ 0x09, 0x18, -1, 0x03, 0x0242, 0x0846 },
|
||||
{ 0x0a, 0x05, -1, 0x03, 0x0442, 0x0046 },
|
||||
{ 0x0a, 0x05, -1, 0x03, 0x0442, 0x0066 },
|
||||
{ 0x0a, 0x06, -1, 0x03, 0x0442, 0x0086 },
|
||||
{ 0x0a, 0x07, -1, 0x03, 0x0442, 0x00c6 },
|
||||
{ 0x0a, 0x08, -1, 0x03, 0x0442, 0x0146 },
|
||||
{ 0x0a, 0x09, -1, 0x03, 0x0442, 0x0246 },
|
||||
{ 0x0a, 0x0a, -1, 0x03, 0x0442, 0x0446 },
|
||||
{ 0x0a, 0x18, -1, 0x03, 0x0442, 0x0846 },
|
||||
{ 0x0c, 0x05, -1, 0x03, 0x0842, 0x0046 },
|
||||
{ 0x0c, 0x05, -1, 0x03, 0x0842, 0x0066 },
|
||||
{ 0x0c, 0x06, -1, 0x03, 0x0842, 0x0086 },
|
||||
{ 0x0c, 0x07, -1, 0x03, 0x0842, 0x00c6 },
|
||||
{ 0x0c, 0x08, -1, 0x03, 0x0842, 0x0146 },
|
||||
{ 0x0c, 0x09, -1, 0x03, 0x0842, 0x0246 },
|
||||
{ 0x0c, 0x0a, -1, 0x03, 0x0842, 0x0446 },
|
||||
{ 0x0c, 0x18, -1, 0x03, 0x0842, 0x0846 },
|
||||
{ 0x0e, 0x05, -1, 0x03, 0x1842, 0x0046 },
|
||||
{ 0x0e, 0x05, -1, 0x03, 0x1842, 0x0066 },
|
||||
{ 0x0e, 0x06, -1, 0x03, 0x1842, 0x0086 },
|
||||
{ 0x0e, 0x07, -1, 0x03, 0x1842, 0x00c6 },
|
||||
{ 0x0e, 0x08, -1, 0x03, 0x1842, 0x0146 },
|
||||
{ 0x0e, 0x09, -1, 0x03, 0x1842, 0x0246 },
|
||||
{ 0x0e, 0x0a, -1, 0x03, 0x1842, 0x0446 },
|
||||
{ 0x0e, 0x18, -1, 0x03, 0x1842, 0x0846 },
|
||||
{ 0x18, 0x05, -1, 0x03, 0x5842, 0x0046 },
|
||||
{ 0x18, 0x05, -1, 0x03, 0x5842, 0x0066 },
|
||||
{ 0x18, 0x06, -1, 0x03, 0x5842, 0x0086 },
|
||||
{ 0x18, 0x07, -1, 0x03, 0x5842, 0x00c6 },
|
||||
{ 0x18, 0x08, -1, 0x03, 0x5842, 0x0146 },
|
||||
{ 0x18, 0x09, -1, 0x03, 0x5842, 0x0246 },
|
||||
{ 0x18, 0x0a, -1, 0x03, 0x5842, 0x0446 },
|
||||
{ 0x18, 0x18, -1, 0x03, 0x5842, 0x0846 },
|
||||
};
|
||||
@@ -4,19 +4,34 @@
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "./state.h"
|
||||
#include "state.h"
|
||||
|
||||
#include <stdlib.h> /* free, malloc */
|
||||
|
||||
#include <brotli/types.h>
|
||||
#include "./huffman.h"
|
||||
#include "../common/dictionary.h"
|
||||
#include "../common/platform.h"
|
||||
#include "huffman.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef BROTLI_REPORTING
|
||||
/* When BROTLI_REPORTING is defined extra reporting module have to be linked. */
|
||||
void BrotliDecoderOnStart(const BrotliDecoderState* s);
|
||||
void BrotliDecoderOnFinish(const BrotliDecoderState* s);
|
||||
#define BROTLI_DECODER_ON_START(s) BrotliDecoderOnStart(s);
|
||||
#define BROTLI_DECODER_ON_FINISH(s) BrotliDecoderOnFinish(s);
|
||||
#else
|
||||
#if !defined(BROTLI_DECODER_ON_START)
|
||||
#define BROTLI_DECODER_ON_START(s) (void)(s);
|
||||
#endif
|
||||
#if !defined(BROTLI_DECODER_ON_FINISH)
|
||||
#define BROTLI_DECODER_ON_FINISH(s) (void)(s);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
BROTLI_BOOL BrotliDecoderStateInit(BrotliDecoderState* s,
|
||||
brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque) {
|
||||
BROTLI_DECODER_ON_START(s);
|
||||
if (!alloc_func) {
|
||||
s->alloc_func = BrotliDefaultAllocFunc;
|
||||
s->free_func = BrotliDefaultFreeFunc;
|
||||
@@ -33,10 +48,7 @@ BROTLI_BOOL BrotliDecoderStateInit(BrotliDecoderState* s,
|
||||
s->state = BROTLI_STATE_UNINITED;
|
||||
s->large_window = 0;
|
||||
s->substate_metablock_header = BROTLI_STATE_METABLOCK_HEADER_NONE;
|
||||
s->substate_tree_group = BROTLI_STATE_TREE_GROUP_NONE;
|
||||
s->substate_context_map = BROTLI_STATE_CONTEXT_MAP_NONE;
|
||||
s->substate_uncompressed = BROTLI_STATE_UNCOMPRESSED_NONE;
|
||||
s->substate_huffman = BROTLI_STATE_HUFFMAN_NONE;
|
||||
s->substate_decode_uint8 = BROTLI_STATE_DECODE_UINT8_NONE;
|
||||
s->substate_read_block_length = BROTLI_STATE_READ_BLOCK_LENGTH_NONE;
|
||||
|
||||
@@ -45,6 +57,7 @@ BROTLI_BOOL BrotliDecoderStateInit(BrotliDecoderState* s,
|
||||
s->pos = 0;
|
||||
s->rb_roundtrips = 0;
|
||||
s->partial_pos_out = 0;
|
||||
s->used_input = 0;
|
||||
|
||||
s->block_type_trees = NULL;
|
||||
s->block_len_trees = NULL;
|
||||
@@ -59,8 +72,6 @@ BROTLI_BOOL BrotliDecoderStateInit(BrotliDecoderState* s,
|
||||
s->context_map_slice = NULL;
|
||||
s->dist_context_map_slice = NULL;
|
||||
|
||||
s->sub_loop_counter = 0;
|
||||
|
||||
s->literal_hgroup.codes = NULL;
|
||||
s->literal_hgroup.htrees = NULL;
|
||||
s->insert_copy_hgroup.codes = NULL;
|
||||
@@ -84,22 +95,25 @@ BROTLI_BOOL BrotliDecoderStateInit(BrotliDecoderState* s,
|
||||
s->block_type_trees = NULL;
|
||||
s->block_len_trees = NULL;
|
||||
|
||||
/* Make small negative indexes addressable. */
|
||||
s->symbol_lists = &s->symbols_lists_array[BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1];
|
||||
|
||||
s->mtf_upper_bound = 63;
|
||||
|
||||
s->dictionary = BrotliGetDictionary();
|
||||
s->transforms = BrotliGetTransforms();
|
||||
s->compound_dictionary = NULL;
|
||||
s->dictionary =
|
||||
BrotliSharedDictionaryCreateInstance(alloc_func, free_func, opaque);
|
||||
if (!s->dictionary) return BROTLI_FALSE;
|
||||
|
||||
s->metadata_start_func = NULL;
|
||||
s->metadata_chunk_func = NULL;
|
||||
s->metadata_callback_opaque = 0;
|
||||
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
|
||||
void BrotliDecoderStateMetablockBegin(BrotliDecoderState* s) {
|
||||
s->meta_block_remaining_len = 0;
|
||||
s->block_length[0] = 1U << 24;
|
||||
s->block_length[1] = 1U << 24;
|
||||
s->block_length[2] = 1U << 24;
|
||||
s->block_length[0] = BROTLI_BLOCK_SIZE_CAP;
|
||||
s->block_length[1] = BROTLI_BLOCK_SIZE_CAP;
|
||||
s->block_length[2] = BROTLI_BLOCK_SIZE_CAP;
|
||||
s->num_block_types[0] = 1;
|
||||
s->num_block_types[1] = 1;
|
||||
s->num_block_types[2] = 1;
|
||||
@@ -137,25 +151,33 @@ void BrotliDecoderStateCleanupAfterMetablock(BrotliDecoderState* s) {
|
||||
void BrotliDecoderStateCleanup(BrotliDecoderState* s) {
|
||||
BrotliDecoderStateCleanupAfterMetablock(s);
|
||||
|
||||
BROTLI_DECODER_ON_FINISH(s);
|
||||
|
||||
BROTLI_DECODER_FREE(s, s->compound_dictionary);
|
||||
BrotliSharedDictionaryDestroyInstance(s->dictionary);
|
||||
s->dictionary = NULL;
|
||||
BROTLI_DECODER_FREE(s, s->ringbuffer);
|
||||
BROTLI_DECODER_FREE(s, s->block_type_trees);
|
||||
}
|
||||
|
||||
BROTLI_BOOL BrotliDecoderHuffmanTreeGroupInit(BrotliDecoderState* s,
|
||||
HuffmanTreeGroup* group, uint32_t alphabet_size, uint32_t max_symbol,
|
||||
uint32_t ntrees) {
|
||||
/* Pack two allocations into one */
|
||||
const size_t max_table_size = kMaxHuffmanTableSize[(alphabet_size + 31) >> 5];
|
||||
HuffmanTreeGroup* group, brotli_reg_t alphabet_size_max,
|
||||
brotli_reg_t alphabet_size_limit, brotli_reg_t ntrees) {
|
||||
/* 376 = 256 (1-st level table) + 4 + 7 + 15 + 31 + 63 (2-nd level mix-tables)
|
||||
This number is discovered "unlimited" "enough" calculator; it is actually
|
||||
a wee bigger than required in several cases (especially for alphabets with
|
||||
less than 16 symbols). */
|
||||
const size_t max_table_size = alphabet_size_limit + 376;
|
||||
const size_t code_size = sizeof(HuffmanCode) * ntrees * max_table_size;
|
||||
const size_t htree_size = sizeof(HuffmanCode*) * ntrees;
|
||||
/* Pointer alignment is, hopefully, wider than sizeof(HuffmanCode). */
|
||||
HuffmanCode** p = (HuffmanCode**)BROTLI_DECODER_ALLOC(s,
|
||||
code_size + htree_size);
|
||||
group->alphabet_size = (uint16_t)alphabet_size;
|
||||
group->max_symbol = (uint16_t)max_symbol;
|
||||
group->alphabet_size_max = (uint16_t)alphabet_size_max;
|
||||
group->alphabet_size_limit = (uint16_t)alphabet_size_limit;
|
||||
group->num_htrees = (uint16_t)ntrees;
|
||||
group->htrees = p;
|
||||
group->codes = (HuffmanCode*)(&p[ntrees]);
|
||||
group->codes = p ? (HuffmanCode*)(&p[ntrees]) : NULL;
|
||||
return !!p;
|
||||
}
|
||||
|
||||
|
||||
262
c/dec/state.h
262
c/dec/state.h
@@ -10,17 +10,105 @@
|
||||
#define BROTLI_DEC_STATE_H_
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include "../common/dictionary.h"
|
||||
#include "../common/platform.h"
|
||||
#include "../common/transform.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./bit_reader.h"
|
||||
#include "./huffman.h"
|
||||
#include <brotli/shared_dictionary.h>
|
||||
#include <brotli/decode.h>
|
||||
#include "bit_reader.h"
|
||||
#include "huffman.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Graphviz diagram that describes state transitions:
|
||||
|
||||
digraph States {
|
||||
graph [compound=true]
|
||||
concentrate=true
|
||||
node [shape="box"]
|
||||
|
||||
UNINITED -> {LARGE_WINDOW_BITS -> INITIALIZE}
|
||||
subgraph cluster_metablock_workflow {
|
||||
style="rounded"
|
||||
label=< <B>METABLOCK CYCLE</B> >
|
||||
METABLOCK_BEGIN -> METABLOCK_HEADER
|
||||
METABLOCK_HEADER:sw -> METADATA
|
||||
METABLOCK_HEADER:s -> UNCOMPRESSED
|
||||
METABLOCK_HEADER:se -> METABLOCK_DONE:ne
|
||||
METADATA:s -> METABLOCK_DONE:w
|
||||
UNCOMPRESSED:s -> METABLOCK_DONE:n
|
||||
METABLOCK_DONE:e -> METABLOCK_BEGIN:e [constraint="false"]
|
||||
}
|
||||
INITIALIZE -> METABLOCK_BEGIN
|
||||
METABLOCK_DONE -> DONE
|
||||
|
||||
subgraph cluster_compressed_metablock {
|
||||
style="rounded"
|
||||
label=< <B>COMPRESSED METABLOCK</B> >
|
||||
|
||||
subgraph cluster_command {
|
||||
style="rounded"
|
||||
label=< <B>HOT LOOP</B> >
|
||||
|
||||
_METABLOCK_DONE_PORT_ [shape=point style=invis]
|
||||
|
||||
{
|
||||
// Set different shape for nodes returning from "compressed metablock".
|
||||
node [shape=invhouse]; CMD_INNER CMD_POST_DECODE_LITERALS;
|
||||
CMD_POST_WRAP_COPY; CMD_INNER_WRITE; CMD_POST_WRITE_1;
|
||||
}
|
||||
|
||||
CMD_BEGIN -> CMD_INNER -> CMD_POST_DECODE_LITERALS -> CMD_POST_WRAP_COPY
|
||||
|
||||
// IO ("write") nodes are not in the hot loop!
|
||||
CMD_INNER_WRITE [style=dashed]
|
||||
CMD_INNER -> CMD_INNER_WRITE
|
||||
CMD_POST_WRITE_1 [style=dashed]
|
||||
CMD_POST_DECODE_LITERALS -> CMD_POST_WRITE_1
|
||||
CMD_POST_WRITE_2 [style=dashed]
|
||||
CMD_POST_WRAP_COPY -> CMD_POST_WRITE_2
|
||||
|
||||
CMD_POST_WRITE_1 -> CMD_BEGIN:s [constraint="false"]
|
||||
CMD_INNER_WRITE -> {CMD_INNER CMD_POST_DECODE_LITERALS}
|
||||
[constraint="false"]
|
||||
CMD_BEGIN:ne -> CMD_POST_DECODE_LITERALS [constraint="false"]
|
||||
CMD_POST_WRAP_COPY -> CMD_BEGIN [constraint="false"]
|
||||
CMD_POST_DECODE_LITERALS -> CMD_BEGIN:ne [constraint="false"]
|
||||
CMD_POST_WRITE_2 -> CMD_POST_WRAP_COPY [constraint="false"]
|
||||
{rank=same; CMD_BEGIN; CMD_INNER; CMD_POST_DECODE_LITERALS;
|
||||
CMD_POST_WRAP_COPY}
|
||||
{rank=same; CMD_INNER_WRITE; CMD_POST_WRITE_1; CMD_POST_WRITE_2}
|
||||
|
||||
{CMD_INNER CMD_POST_DECODE_LITERALS CMD_POST_WRAP_COPY} ->
|
||||
_METABLOCK_DONE_PORT_ [style=invis]
|
||||
{CMD_INNER_WRITE CMD_POST_WRITE_1} -> _METABLOCK_DONE_PORT_
|
||||
[constraint="false" style=invis]
|
||||
}
|
||||
|
||||
BEFORE_COMPRESSED_METABLOCK_HEADER:s -> HUFFMAN_CODE_0:n
|
||||
HUFFMAN_CODE_0 -> HUFFMAN_CODE_1 -> HUFFMAN_CODE_2 -> HUFFMAN_CODE_3
|
||||
HUFFMAN_CODE_0 -> METABLOCK_HEADER_2 -> CONTEXT_MODES -> CONTEXT_MAP_1
|
||||
CONTEXT_MAP_1 -> CONTEXT_MAP_2 -> TREE_GROUP
|
||||
TREE_GROUP -> BEFORE_COMPRESSED_METABLOCK_BODY:e
|
||||
BEFORE_COMPRESSED_METABLOCK_BODY:s -> CMD_BEGIN:n
|
||||
|
||||
HUFFMAN_CODE_3:e -> HUFFMAN_CODE_0:ne [constraint="false"]
|
||||
{rank=same; HUFFMAN_CODE_0; HUFFMAN_CODE_1; HUFFMAN_CODE_2; HUFFMAN_CODE_3}
|
||||
{rank=same; METABLOCK_HEADER_2; CONTEXT_MODES; CONTEXT_MAP_1; CONTEXT_MAP_2;
|
||||
TREE_GROUP}
|
||||
}
|
||||
METABLOCK_HEADER:e -> BEFORE_COMPRESSED_METABLOCK_HEADER:n
|
||||
|
||||
_METABLOCK_DONE_PORT_ -> METABLOCK_DONE:se
|
||||
[constraint="false" ltail=cluster_command]
|
||||
|
||||
UNINITED [shape=Mdiamond];
|
||||
DONE [shape=Msquare];
|
||||
}
|
||||
|
||||
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
BROTLI_STATE_UNINITED,
|
||||
BROTLI_STATE_LARGE_WINDOW_BITS,
|
||||
@@ -39,6 +127,7 @@ typedef enum {
|
||||
BROTLI_STATE_METABLOCK_DONE,
|
||||
BROTLI_STATE_COMMAND_POST_WRITE_1,
|
||||
BROTLI_STATE_COMMAND_POST_WRITE_2,
|
||||
BROTLI_STATE_BEFORE_COMPRESSED_METABLOCK_HEADER,
|
||||
BROTLI_STATE_HUFFMAN_CODE_0,
|
||||
BROTLI_STATE_HUFFMAN_CODE_1,
|
||||
BROTLI_STATE_HUFFMAN_CODE_2,
|
||||
@@ -46,6 +135,7 @@ typedef enum {
|
||||
BROTLI_STATE_CONTEXT_MAP_1,
|
||||
BROTLI_STATE_CONTEXT_MAP_2,
|
||||
BROTLI_STATE_TREE_GROUP,
|
||||
BROTLI_STATE_BEFORE_COMPRESSED_METABLOCK_BODY,
|
||||
BROTLI_STATE_DONE
|
||||
} BrotliRunningState;
|
||||
|
||||
@@ -98,6 +188,65 @@ typedef enum {
|
||||
BROTLI_STATE_READ_BLOCK_LENGTH_SUFFIX
|
||||
} BrotliRunningReadBlockLengthState;
|
||||
|
||||
/* BrotliDecoderState addon, used for Compound Dictionary functionality. */
|
||||
typedef struct BrotliDecoderCompoundDictionary {
|
||||
int num_chunks;
|
||||
int total_size;
|
||||
int br_index;
|
||||
int br_offset;
|
||||
int br_length;
|
||||
int br_copied;
|
||||
const uint8_t* chunks[16];
|
||||
int chunk_offsets[16];
|
||||
int block_bits;
|
||||
uint8_t block_map[256];
|
||||
} BrotliDecoderCompoundDictionary;
|
||||
|
||||
typedef struct BrotliMetablockHeaderArena {
|
||||
BrotliRunningTreeGroupState substate_tree_group;
|
||||
BrotliRunningContextMapState substate_context_map;
|
||||
BrotliRunningHuffmanState substate_huffman;
|
||||
|
||||
brotli_reg_t sub_loop_counter;
|
||||
|
||||
brotli_reg_t repeat_code_len;
|
||||
brotli_reg_t prev_code_len;
|
||||
|
||||
/* For ReadHuffmanCode. */
|
||||
brotli_reg_t symbol;
|
||||
brotli_reg_t repeat;
|
||||
brotli_reg_t space;
|
||||
|
||||
/* Huffman table for "histograms". */
|
||||
HuffmanCode table[32];
|
||||
/* List of heads of symbol chains. */
|
||||
uint16_t* symbol_lists;
|
||||
/* Storage from symbol_lists. */
|
||||
uint16_t symbols_lists_array[BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1 +
|
||||
BROTLI_NUM_COMMAND_SYMBOLS];
|
||||
/* Tails of symbol chains. */
|
||||
int next_symbol[32];
|
||||
uint8_t code_length_code_lengths[BROTLI_CODE_LENGTH_CODES];
|
||||
/* Population counts for the code lengths. */
|
||||
uint16_t code_length_histo[16];
|
||||
/* TODO(eustas): +2 bytes padding */
|
||||
|
||||
/* For HuffmanTreeGroupDecode. */
|
||||
int htree_index;
|
||||
HuffmanCode* next;
|
||||
|
||||
/* For DecodeContextMap. */
|
||||
brotli_reg_t context_index;
|
||||
brotli_reg_t max_run_length_prefix;
|
||||
brotli_reg_t code;
|
||||
HuffmanCode context_map_table[BROTLI_HUFFMAN_MAX_SIZE_272];
|
||||
} BrotliMetablockHeaderArena;
|
||||
|
||||
typedef struct BrotliMetablockBodyArena {
|
||||
uint8_t dist_extra_bits[544];
|
||||
brotli_reg_t dist_offset[544];
|
||||
} BrotliMetablockBodyArena;
|
||||
|
||||
struct BrotliDecoderStateStruct {
|
||||
BrotliRunningState state;
|
||||
|
||||
@@ -110,12 +259,13 @@ struct BrotliDecoderStateStruct {
|
||||
brotli_free_func free_func;
|
||||
void* memory_manager_opaque;
|
||||
|
||||
/* Temporary storage for remaining input. */
|
||||
/* Temporary storage for remaining input. Brotli stream format is designed in
|
||||
a way, that 64 bits are enough to make progress in decoding. */
|
||||
union {
|
||||
uint64_t u64;
|
||||
uint8_t u8[8];
|
||||
} buffer;
|
||||
uint32_t buffer_length;
|
||||
brotli_reg_t buffer_length;
|
||||
|
||||
int pos;
|
||||
int max_backward_distance;
|
||||
@@ -125,7 +275,8 @@ struct BrotliDecoderStateStruct {
|
||||
int dist_rb_idx;
|
||||
int dist_rb[4];
|
||||
int error_code;
|
||||
uint32_t sub_loop_counter;
|
||||
int meta_block_remaining_len;
|
||||
|
||||
uint8_t* ringbuffer;
|
||||
uint8_t* ringbuffer_end;
|
||||
HuffmanCode* htree_command;
|
||||
@@ -146,89 +297,71 @@ struct BrotliDecoderStateStruct {
|
||||
/* Distance context is actual after command is decoded and before distance is
|
||||
computed. After distance computation it is used as a temporary variable. */
|
||||
int distance_context;
|
||||
int meta_block_remaining_len;
|
||||
uint32_t block_length_index;
|
||||
uint32_t block_length[3];
|
||||
uint32_t num_block_types[3];
|
||||
uint32_t block_type_rb[6];
|
||||
uint32_t distance_postfix_bits;
|
||||
uint32_t num_direct_distance_codes;
|
||||
int distance_postfix_mask;
|
||||
uint32_t num_dist_htrees;
|
||||
brotli_reg_t block_length[3];
|
||||
brotli_reg_t block_length_index;
|
||||
brotli_reg_t num_block_types[3];
|
||||
brotli_reg_t block_type_rb[6];
|
||||
brotli_reg_t distance_postfix_bits;
|
||||
brotli_reg_t num_direct_distance_codes;
|
||||
brotli_reg_t num_dist_htrees;
|
||||
uint8_t* dist_context_map;
|
||||
HuffmanCode* literal_htree;
|
||||
uint8_t dist_htree_index;
|
||||
uint32_t repeat_code_len;
|
||||
uint32_t prev_code_len;
|
||||
|
||||
int copy_length;
|
||||
int distance_code;
|
||||
|
||||
/* For partial write operations. */
|
||||
size_t rb_roundtrips; /* how many times we went around the ring-buffer */
|
||||
size_t partial_pos_out; /* how much output to the user in total */
|
||||
|
||||
/* For ReadHuffmanCode. */
|
||||
uint32_t symbol;
|
||||
uint32_t repeat;
|
||||
uint32_t space;
|
||||
|
||||
HuffmanCode table[32];
|
||||
/* List of heads of symbol chains. */
|
||||
uint16_t* symbol_lists;
|
||||
/* Storage from symbol_lists. */
|
||||
uint16_t symbols_lists_array[BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1 +
|
||||
BROTLI_NUM_COMMAND_SYMBOLS];
|
||||
/* Tails of symbol chains. */
|
||||
int next_symbol[32];
|
||||
uint8_t code_length_code_lengths[BROTLI_CODE_LENGTH_CODES];
|
||||
/* Population counts for the code lengths. */
|
||||
uint16_t code_length_histo[16];
|
||||
|
||||
/* For HuffmanTreeGroupDecode. */
|
||||
int htree_index;
|
||||
HuffmanCode* next;
|
||||
|
||||
/* For DecodeContextMap. */
|
||||
uint32_t context_index;
|
||||
uint32_t max_run_length_prefix;
|
||||
uint32_t code;
|
||||
HuffmanCode context_map_table[BROTLI_HUFFMAN_MAX_SIZE_272];
|
||||
|
||||
/* For InverseMoveToFrontTransform. */
|
||||
uint32_t mtf_upper_bound;
|
||||
brotli_reg_t mtf_upper_bound;
|
||||
uint32_t mtf[64 + 1];
|
||||
|
||||
int copy_length;
|
||||
int distance_code;
|
||||
|
||||
uint8_t dist_htree_index;
|
||||
/* TODO(eustas): +3 bytes padding */
|
||||
|
||||
/* Less used attributes are at the end of this struct. */
|
||||
|
||||
brotli_decoder_metadata_start_func metadata_start_func;
|
||||
brotli_decoder_metadata_chunk_func metadata_chunk_func;
|
||||
void* metadata_callback_opaque;
|
||||
|
||||
/* For reporting. */
|
||||
uint64_t used_input; /* how many bytes of input are consumed */
|
||||
|
||||
/* States inside function calls. */
|
||||
BrotliRunningMetablockHeaderState substate_metablock_header;
|
||||
BrotliRunningTreeGroupState substate_tree_group;
|
||||
BrotliRunningContextMapState substate_context_map;
|
||||
BrotliRunningUncompressedState substate_uncompressed;
|
||||
BrotliRunningHuffmanState substate_huffman;
|
||||
BrotliRunningDecodeUint8State substate_decode_uint8;
|
||||
BrotliRunningReadBlockLengthState substate_read_block_length;
|
||||
|
||||
int new_ringbuffer_size;
|
||||
/* TODO(eustas): +4 bytes padding */
|
||||
|
||||
unsigned int is_last_metablock : 1;
|
||||
unsigned int is_uncompressed : 1;
|
||||
unsigned int is_metadata : 1;
|
||||
unsigned int should_wrap_ringbuffer : 1;
|
||||
unsigned int canny_ringbuffer_allocation : 1;
|
||||
unsigned int large_window : 1;
|
||||
unsigned int window_bits : 6;
|
||||
unsigned int size_nibbles : 8;
|
||||
uint32_t window_bits;
|
||||
/* TODO(eustas): +12 bits padding */
|
||||
|
||||
int new_ringbuffer_size;
|
||||
|
||||
uint32_t num_literal_htrees;
|
||||
brotli_reg_t num_literal_htrees;
|
||||
uint8_t* context_map;
|
||||
uint8_t* context_modes;
|
||||
|
||||
const BrotliDictionary* dictionary;
|
||||
const BrotliTransforms* transforms;
|
||||
BrotliSharedDictionary* dictionary;
|
||||
BrotliDecoderCompoundDictionary* compound_dictionary;
|
||||
|
||||
uint32_t trivial_literal_contexts[8]; /* 256 bits */
|
||||
|
||||
union {
|
||||
BrotliMetablockHeaderArena header;
|
||||
BrotliMetablockBodyArena body;
|
||||
} arena;
|
||||
};
|
||||
|
||||
typedef struct BrotliDecoderStateStruct BrotliDecoderStateInternal;
|
||||
@@ -241,8 +374,9 @@ BROTLI_INTERNAL void BrotliDecoderStateMetablockBegin(BrotliDecoderState* s);
|
||||
BROTLI_INTERNAL void BrotliDecoderStateCleanupAfterMetablock(
|
||||
BrotliDecoderState* s);
|
||||
BROTLI_INTERNAL BROTLI_BOOL BrotliDecoderHuffmanTreeGroupInit(
|
||||
BrotliDecoderState* s, HuffmanTreeGroup* group, uint32_t alphabet_size,
|
||||
uint32_t max_symbol, uint32_t ntrees);
|
||||
BrotliDecoderState* s, HuffmanTreeGroup* group,
|
||||
brotli_reg_t alphabet_size_max, brotli_reg_t alphabet_size_limit,
|
||||
brotli_reg_t ntrees);
|
||||
|
||||
#define BROTLI_DECODER_ALLOC(S, L) S->alloc_func(S->memory_manager_opaque, L)
|
||||
|
||||
@@ -251,6 +385,10 @@ BROTLI_INTERNAL BROTLI_BOOL BrotliDecoderHuffmanTreeGroupInit(
|
||||
X = NULL; \
|
||||
}
|
||||
|
||||
/* Literal/Command/Distance block size maximum; same as maximum metablock size;
|
||||
used as block size when there is no block switching. */
|
||||
#define BROTLI_BLOCK_SIZE_CAP (1U << 24)
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
53
c/dec/static_init.c
Normal file
53
c/dec/static_init.c
Normal file
@@ -0,0 +1,53 @@
|
||||
/* Copyright 2025 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "static_init.h"
|
||||
|
||||
#include "../common/platform.h"
|
||||
#include "../common/static_init.h"
|
||||
|
||||
#if (BROTLI_STATIC_INIT != BROTLI_STATIC_INIT_NONE)
|
||||
#include "../common/dictionary.h"
|
||||
#include "prefix.h"
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if (BROTLI_STATIC_INIT != BROTLI_STATIC_INIT_NONE)
|
||||
static BROTLI_BOOL DoBrotliDecoderStaticInit(void) {
|
||||
BROTLI_BOOL ok = BrotliDecoderInitCmdLut(kCmdLut);
|
||||
if (!ok) return BROTLI_FALSE;
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
#endif /* BROTLI_STATIC_INIT_NONE */
|
||||
|
||||
#if (BROTLI_STATIC_INIT == BROTLI_STATIC_INIT_EARLY)
|
||||
static BROTLI_BOOL kEarlyInitOk;
|
||||
static __attribute__((constructor)) void BrotliDecoderStaticInitEarly(void) {
|
||||
kEarlyInitOk = DoBrotliDecoderStaticInit();
|
||||
}
|
||||
#elif (BROTLI_STATIC_INIT == BROTLI_STATIC_INIT_LAZY)
|
||||
static BROTLI_BOOL kLazyInitOk;
|
||||
void BrotliDecoderLazyStaticInitInner(void) {
|
||||
kLazyInitOk = DoBrotliDecoderStaticInit();
|
||||
}
|
||||
#endif /* BROTLI_STATIC_INIT_EARLY */
|
||||
|
||||
BROTLI_BOOL BrotliDecoderEnsureStaticInit(void) {
|
||||
#if (BROTLI_STATIC_INIT == BROTLI_STATIC_INIT_NONE)
|
||||
return BROTLI_TRUE;
|
||||
#elif (BROTLI_STATIC_INIT == BROTLI_STATIC_INIT_EARLY)
|
||||
return kEarlyInitOk;
|
||||
#else
|
||||
return kLazyInitOk;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
30
c/dec/static_init.h
Normal file
30
c/dec/static_init.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/* Copyright 2025 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/* Central point for static initialization. */
|
||||
|
||||
#ifndef THIRD_PARTY_BROTLI_DEC_STATIC_INIT_H_
|
||||
#define THIRD_PARTY_BROTLI_DEC_STATIC_INIT_H_
|
||||
|
||||
#include "../common/platform.h"
|
||||
#include "../common/static_init.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if (BROTLI_STATIC_INIT == BROTLI_STATIC_INIT_LAZY)
|
||||
BROTLI_INTERNAL void BrotliDecoderLazyStaticInitInner(void);
|
||||
BROTLI_INTERNAL void BrotliDecoderLazyStaticInit(void);
|
||||
#endif /* BROTLI_STATIC_INIT */
|
||||
|
||||
BROTLI_INTERNAL BROTLI_BOOL BrotliDecoderEnsureStaticInit(void);
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif // THIRD_PARTY_BROTLI_DEC_STATIC_INIT_H_
|
||||
@@ -6,16 +6,17 @@
|
||||
|
||||
/* Function to find backward reference copies. */
|
||||
|
||||
#include "./backward_references.h"
|
||||
#include "backward_references.h"
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include "../common/dictionary.h"
|
||||
#include "../common/context.h"
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./command.h"
|
||||
#include "./dictionary_hash.h"
|
||||
#include "./memory.h"
|
||||
#include "./quality.h"
|
||||
#include "command.h"
|
||||
#include "compound_dictionary.h"
|
||||
#include "encoder_dict.h"
|
||||
#include "hash.h"
|
||||
#include "params.h"
|
||||
#include "quality.h" /* IWYU pragma: keep for inc */
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
@@ -51,67 +52,125 @@ static BROTLI_INLINE size_t ComputeDistanceCode(size_t distance,
|
||||
#define EXPORT_FN(X) EXPAND_CAT(X, EXPAND_CAT(PREFIX(), HASHER()))
|
||||
|
||||
#define PREFIX() N
|
||||
#define ENABLE_COMPOUND_DICTIONARY 0
|
||||
|
||||
#define HASHER() H2
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "./backward_references_inc.h"
|
||||
#include "backward_references_inc.h"
|
||||
#undef HASHER
|
||||
|
||||
#define HASHER() H3
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "./backward_references_inc.h"
|
||||
#include "backward_references_inc.h"
|
||||
#undef HASHER
|
||||
|
||||
#define HASHER() H4
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "./backward_references_inc.h"
|
||||
#include "backward_references_inc.h"
|
||||
#undef HASHER
|
||||
|
||||
#define HASHER() H5
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "./backward_references_inc.h"
|
||||
#include "backward_references_inc.h"
|
||||
#undef HASHER
|
||||
|
||||
#define HASHER() H6
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "./backward_references_inc.h"
|
||||
#include "backward_references_inc.h"
|
||||
#undef HASHER
|
||||
|
||||
#define HASHER() H40
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "./backward_references_inc.h"
|
||||
#include "backward_references_inc.h"
|
||||
#undef HASHER
|
||||
|
||||
#define HASHER() H41
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "./backward_references_inc.h"
|
||||
#include "backward_references_inc.h"
|
||||
#undef HASHER
|
||||
|
||||
#define HASHER() H42
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "./backward_references_inc.h"
|
||||
#include "backward_references_inc.h"
|
||||
#undef HASHER
|
||||
|
||||
#define HASHER() H54
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "./backward_references_inc.h"
|
||||
#include "backward_references_inc.h"
|
||||
#undef HASHER
|
||||
|
||||
#define HASHER() H35
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "./backward_references_inc.h"
|
||||
#include "backward_references_inc.h"
|
||||
#undef HASHER
|
||||
|
||||
#define HASHER() H55
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "./backward_references_inc.h"
|
||||
#include "backward_references_inc.h"
|
||||
#undef HASHER
|
||||
|
||||
#define HASHER() H65
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "./backward_references_inc.h"
|
||||
#include "backward_references_inc.h"
|
||||
#undef HASHER
|
||||
|
||||
#if defined(BROTLI_MAX_SIMD_QUALITY)
|
||||
#define HASHER() H58
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "backward_references_inc.h"
|
||||
#undef HASHER
|
||||
|
||||
#define HASHER() H68
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "backward_references_inc.h"
|
||||
#undef HASHER
|
||||
#endif
|
||||
|
||||
#undef ENABLE_COMPOUND_DICTIONARY
|
||||
#undef PREFIX
|
||||
#define PREFIX() D
|
||||
#define ENABLE_COMPOUND_DICTIONARY 1
|
||||
|
||||
#define HASHER() H5
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "backward_references_inc.h"
|
||||
#undef HASHER
|
||||
#define HASHER() H6
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "backward_references_inc.h"
|
||||
#undef HASHER
|
||||
#define HASHER() H40
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "backward_references_inc.h"
|
||||
#undef HASHER
|
||||
#define HASHER() H41
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "backward_references_inc.h"
|
||||
#undef HASHER
|
||||
#define HASHER() H42
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "backward_references_inc.h"
|
||||
#undef HASHER
|
||||
#define HASHER() H55
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "backward_references_inc.h"
|
||||
#undef HASHER
|
||||
#define HASHER() H65
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "backward_references_inc.h"
|
||||
#undef HASHER
|
||||
#if defined(BROTLI_MAX_SIMD_QUALITY)
|
||||
#define HASHER() H58
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "backward_references_inc.h"
|
||||
#undef HASHER
|
||||
#define HASHER() H68
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "backward_references_inc.h"
|
||||
#undef HASHER
|
||||
#endif
|
||||
|
||||
#undef ENABLE_COMPOUND_DICTIONARY
|
||||
#undef PREFIX
|
||||
|
||||
#undef EXPORT_FN
|
||||
@@ -119,22 +178,50 @@ static BROTLI_INLINE size_t ComputeDistanceCode(size_t distance,
|
||||
#undef CAT
|
||||
#undef EXPAND_CAT
|
||||
|
||||
void BrotliCreateBackwardReferences(
|
||||
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
|
||||
size_t ringbuffer_mask, const BrotliEncoderParams* params,
|
||||
HasherHandle hasher, int* dist_cache, size_t* last_insert_len,
|
||||
void BrotliCreateBackwardReferences(size_t num_bytes,
|
||||
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
||||
ContextLut literal_context_lut, const BrotliEncoderParams* params,
|
||||
Hasher* hasher, int* dist_cache, size_t* last_insert_len,
|
||||
Command* commands, size_t* num_commands, size_t* num_literals) {
|
||||
if (params->dictionary.compound.num_chunks != 0) {
|
||||
switch (params->hasher.type) {
|
||||
#define CASE_(N) \
|
||||
case N: \
|
||||
CreateBackwardReferencesDH ## N(num_bytes, \
|
||||
position, ringbuffer, ringbuffer_mask, \
|
||||
literal_context_lut, params, hasher, dist_cache, \
|
||||
last_insert_len, commands, num_commands, num_literals); \
|
||||
return;
|
||||
CASE_(5)
|
||||
CASE_(6)
|
||||
#if defined(BROTLI_MAX_SIMD_QUALITY)
|
||||
CASE_(58)
|
||||
CASE_(68)
|
||||
#endif
|
||||
CASE_(40)
|
||||
CASE_(41)
|
||||
CASE_(42)
|
||||
CASE_(55)
|
||||
CASE_(65)
|
||||
#undef CASE_
|
||||
default:
|
||||
BROTLI_DCHECK(BROTLI_FALSE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (params->hasher.type) {
|
||||
#define CASE_(N) \
|
||||
case N: \
|
||||
CreateBackwardReferencesNH ## N( \
|
||||
num_bytes, position, ringbuffer, \
|
||||
ringbuffer_mask, params, hasher, dist_cache, \
|
||||
CreateBackwardReferencesNH ## N(num_bytes, \
|
||||
position, ringbuffer, ringbuffer_mask, \
|
||||
literal_context_lut, params, hasher, dist_cache, \
|
||||
last_insert_len, commands, num_commands, num_literals); \
|
||||
return;
|
||||
FOR_GENERIC_HASHERS(CASE_)
|
||||
#undef CASE_
|
||||
default:
|
||||
BROTLI_DCHECK(BROTLI_FALSE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,13 +9,11 @@
|
||||
#ifndef BROTLI_ENC_BACKWARD_REFERENCES_H_
|
||||
#define BROTLI_ENC_BACKWARD_REFERENCES_H_
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include "../common/dictionary.h"
|
||||
#include "../common/context.h"
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./command.h"
|
||||
#include "./hash.h"
|
||||
#include "./quality.h"
|
||||
#include "command.h"
|
||||
#include "hash.h"
|
||||
#include "params.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
@@ -25,10 +23,10 @@ extern "C" {
|
||||
initially the total amount of commands output by previous
|
||||
CreateBackwardReferences calls, and must be incremented by the amount written
|
||||
by this call. */
|
||||
BROTLI_INTERNAL void BrotliCreateBackwardReferences(
|
||||
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
|
||||
size_t ringbuffer_mask, const BrotliEncoderParams* params,
|
||||
HasherHandle hasher, int* dist_cache, size_t* last_insert_len,
|
||||
BROTLI_INTERNAL void BrotliCreateBackwardReferences(size_t num_bytes,
|
||||
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
||||
ContextLut literal_context_lut, const BrotliEncoderParams* params,
|
||||
Hasher* hasher, int* dist_cache, size_t* last_insert_len,
|
||||
Command* commands, size_t* num_commands, size_t* num_literals);
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
|
||||
@@ -6,34 +6,36 @@
|
||||
|
||||
/* Function to find backward reference copies. */
|
||||
|
||||
#include "./backward_references_hq.h"
|
||||
|
||||
#include <string.h> /* memcpy, memset */
|
||||
#include "backward_references_hq.h"
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include "../common/context.h"
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./command.h"
|
||||
#include "./fast_log.h"
|
||||
#include "./find_match_length.h"
|
||||
#include "./literal_cost.h"
|
||||
#include "./memory.h"
|
||||
#include "./params.h"
|
||||
#include "./prefix.h"
|
||||
#include "./quality.h"
|
||||
#include "command.h"
|
||||
#include "compound_dictionary.h"
|
||||
#include "encoder_dict.h"
|
||||
#include "fast_log.h"
|
||||
#include "find_match_length.h"
|
||||
#include "hash.h"
|
||||
#include "literal_cost.h"
|
||||
#include "memory.h"
|
||||
#include "params.h"
|
||||
#include "prefix.h"
|
||||
#include "quality.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* BrotliCalculateDistanceCodeLimit(BROTLI_MAX_ALLOWED_DISTANCE, 3, 120). */
|
||||
#define BROTLI_MAX_EFFECTIVE_DISTANCE_ALPHABET_SIZE 544
|
||||
|
||||
static const float kInfinity = 1.7e38f; /* ~= 2 ^ 127 */
|
||||
|
||||
static const uint32_t kDistanceCacheIndex[] = {
|
||||
static const BROTLI_MODEL("small") uint32_t kDistanceCacheIndex[] = {
|
||||
0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
|
||||
};
|
||||
static const int kDistanceCacheOffset[] = {
|
||||
static const BROTLI_MODEL("small") int kDistanceCacheOffset[] = {
|
||||
0, 0, 0, 0, -1, 1, -2, 2, -3, 3, -1, 1, -2, 2, -3, 3
|
||||
};
|
||||
|
||||
@@ -71,6 +73,14 @@ static BROTLI_INLINE uint32_t ZopfliNodeCommandLength(const ZopfliNode* self) {
|
||||
return ZopfliNodeCopyLength(self) + (self->dcode_insert_length & 0x7FFFFFF);
|
||||
}
|
||||
|
||||
/* Temporary data for ZopfliCostModelSetFromCommands. */
|
||||
typedef struct ZopfliCostModelArena {
|
||||
uint32_t histogram_literal[BROTLI_NUM_LITERAL_SYMBOLS];
|
||||
uint32_t histogram_cmd[BROTLI_NUM_COMMAND_SYMBOLS];
|
||||
uint32_t histogram_dist[BROTLI_MAX_EFFECTIVE_DISTANCE_ALPHABET_SIZE];
|
||||
float cost_literal[BROTLI_NUM_LITERAL_SYMBOLS];
|
||||
} ZopfliCostModelArena;
|
||||
|
||||
/* Histogram based cost model for zopflification. */
|
||||
typedef struct ZopfliCostModel {
|
||||
/* The insert and copy length symbols. */
|
||||
@@ -81,19 +91,21 @@ typedef struct ZopfliCostModel {
|
||||
float* literal_costs_;
|
||||
float min_cost_cmd_;
|
||||
size_t num_bytes_;
|
||||
|
||||
/* Temporary data. */
|
||||
union {
|
||||
size_t literal_histograms[3 * 256];
|
||||
ZopfliCostModelArena arena;
|
||||
};
|
||||
} ZopfliCostModel;
|
||||
|
||||
static void InitZopfliCostModel(
|
||||
MemoryManager* m, ZopfliCostModel* self, const BrotliDistanceParams* dist,
|
||||
size_t num_bytes) {
|
||||
uint32_t distance_histogram_size = dist->alphabet_size;
|
||||
if (distance_histogram_size > BROTLI_MAX_EFFECTIVE_DISTANCE_ALPHABET_SIZE) {
|
||||
distance_histogram_size = BROTLI_MAX_EFFECTIVE_DISTANCE_ALPHABET_SIZE;
|
||||
}
|
||||
self->num_bytes_ = num_bytes;
|
||||
self->literal_costs_ = BROTLI_ALLOC(m, float, num_bytes + 2);
|
||||
self->cost_dist_ = BROTLI_ALLOC(m, float, dist->alphabet_size);
|
||||
self->distance_histogram_size = distance_histogram_size;
|
||||
self->cost_dist_ = BROTLI_ALLOC(m, float, dist->alphabet_size_limit);
|
||||
self->distance_histogram_size = dist->alphabet_size_limit;
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
}
|
||||
|
||||
@@ -141,18 +153,15 @@ static void ZopfliCostModelSetFromCommands(ZopfliCostModel* self,
|
||||
const Command* commands,
|
||||
size_t num_commands,
|
||||
size_t last_insert_len) {
|
||||
uint32_t histogram_literal[BROTLI_NUM_LITERAL_SYMBOLS];
|
||||
uint32_t histogram_cmd[BROTLI_NUM_COMMAND_SYMBOLS];
|
||||
uint32_t histogram_dist[BROTLI_MAX_EFFECTIVE_DISTANCE_ALPHABET_SIZE];
|
||||
float cost_literal[BROTLI_NUM_LITERAL_SYMBOLS];
|
||||
ZopfliCostModelArena* arena = &self->arena;
|
||||
size_t pos = position - last_insert_len;
|
||||
float min_cost_cmd = kInfinity;
|
||||
size_t i;
|
||||
float* cost_cmd = self->cost_cmd_;
|
||||
|
||||
memset(histogram_literal, 0, sizeof(histogram_literal));
|
||||
memset(histogram_cmd, 0, sizeof(histogram_cmd));
|
||||
memset(histogram_dist, 0, sizeof(histogram_dist));
|
||||
memset(arena->histogram_literal, 0, sizeof(arena->histogram_literal));
|
||||
memset(arena->histogram_cmd, 0, sizeof(arena->histogram_cmd));
|
||||
memset(arena->histogram_dist, 0, sizeof(arena->histogram_dist));
|
||||
|
||||
for (i = 0; i < num_commands; i++) {
|
||||
size_t inslength = commands[i].insert_len_;
|
||||
@@ -161,21 +170,21 @@ static void ZopfliCostModelSetFromCommands(ZopfliCostModel* self,
|
||||
size_t cmdcode = commands[i].cmd_prefix_;
|
||||
size_t j;
|
||||
|
||||
histogram_cmd[cmdcode]++;
|
||||
if (cmdcode >= 128) histogram_dist[distcode]++;
|
||||
arena->histogram_cmd[cmdcode]++;
|
||||
if (cmdcode >= 128) arena->histogram_dist[distcode]++;
|
||||
|
||||
for (j = 0; j < inslength; j++) {
|
||||
histogram_literal[ringbuffer[(pos + j) & ringbuffer_mask]]++;
|
||||
arena->histogram_literal[ringbuffer[(pos + j) & ringbuffer_mask]]++;
|
||||
}
|
||||
|
||||
pos += inslength + copylength;
|
||||
}
|
||||
|
||||
SetCost(histogram_literal, BROTLI_NUM_LITERAL_SYMBOLS, BROTLI_TRUE,
|
||||
cost_literal);
|
||||
SetCost(histogram_cmd, BROTLI_NUM_COMMAND_SYMBOLS, BROTLI_FALSE,
|
||||
SetCost(arena->histogram_literal, BROTLI_NUM_LITERAL_SYMBOLS, BROTLI_TRUE,
|
||||
arena->cost_literal);
|
||||
SetCost(arena->histogram_cmd, BROTLI_NUM_COMMAND_SYMBOLS, BROTLI_FALSE,
|
||||
cost_cmd);
|
||||
SetCost(histogram_dist, self->distance_histogram_size, BROTLI_FALSE,
|
||||
SetCost(arena->histogram_dist, self->distance_histogram_size, BROTLI_FALSE,
|
||||
self->cost_dist_);
|
||||
|
||||
for (i = 0; i < BROTLI_NUM_COMMAND_SYMBOLS; ++i) {
|
||||
@@ -190,7 +199,7 @@ static void ZopfliCostModelSetFromCommands(ZopfliCostModel* self,
|
||||
literal_costs[0] = 0.0;
|
||||
for (i = 0; i < num_bytes; ++i) {
|
||||
literal_carry +=
|
||||
cost_literal[ringbuffer[(position + i) & ringbuffer_mask]];
|
||||
arena->cost_literal[ringbuffer[(position + i) & ringbuffer_mask]];
|
||||
literal_costs[i + 1] = literal_costs[i] + literal_carry;
|
||||
literal_carry -= literal_costs[i + 1] - literal_costs[i];
|
||||
}
|
||||
@@ -208,7 +217,8 @@ static void ZopfliCostModelSetFromLiteralCosts(ZopfliCostModel* self,
|
||||
size_t num_bytes = self->num_bytes_;
|
||||
size_t i;
|
||||
BrotliEstimateBitCostsForLiterals(position, num_bytes, ringbuffer_mask,
|
||||
ringbuffer, &literal_costs[1]);
|
||||
ringbuffer, self->literal_histograms,
|
||||
&literal_costs[1]);
|
||||
literal_costs[0] = 0.0;
|
||||
for (i = 0; i < num_bytes; ++i) {
|
||||
literal_carry += literal_costs[i + 1];
|
||||
@@ -330,25 +340,25 @@ static size_t ComputeMinimumCopyLength(const float start_cost,
|
||||
REQUIRES: nodes[0..pos] satisfies that "ZopfliNode array invariant". */
|
||||
static uint32_t ComputeDistanceShortcut(const size_t block_start,
|
||||
const size_t pos,
|
||||
const size_t max_backward,
|
||||
const size_t max_backward_limit,
|
||||
const size_t gap,
|
||||
const ZopfliNode* nodes) {
|
||||
const size_t clen = ZopfliNodeCopyLength(&nodes[pos]);
|
||||
const size_t ilen = nodes[pos].dcode_insert_length & 0x7FFFFFF;
|
||||
const size_t c_len = ZopfliNodeCopyLength(&nodes[pos]);
|
||||
const size_t i_len = nodes[pos].dcode_insert_length & 0x7FFFFFF;
|
||||
const size_t dist = ZopfliNodeCopyDistance(&nodes[pos]);
|
||||
/* Since |block_start + pos| is the end position of the command, the copy part
|
||||
starts from |block_start + pos - clen|. Distances that are greater than
|
||||
this or greater than |max_backward| are static dictionary references, and
|
||||
do not update the last distances. Also distance code 0 (last distance)
|
||||
does not update the last distances. */
|
||||
starts from |block_start + pos - c_len|. Distances that are greater than
|
||||
this or greater than |max_backward_limit| + |gap| are static dictionary
|
||||
references, and do not update the last distances.
|
||||
Also distance code 0 (last distance) does not update the last distances. */
|
||||
if (pos == 0) {
|
||||
return 0;
|
||||
} else if (dist + clen <= block_start + pos + gap &&
|
||||
dist <= max_backward + gap &&
|
||||
} else if (dist + c_len <= block_start + pos + gap &&
|
||||
dist <= max_backward_limit + gap &&
|
||||
ZopfliNodeDistanceCode(&nodes[pos]) > 0) {
|
||||
return (uint32_t)pos;
|
||||
} else {
|
||||
return nodes[pos - clen - ilen].u.shortcut;
|
||||
return nodes[pos - c_len - i_len].u.shortcut;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -366,12 +376,12 @@ static void ComputeDistanceCache(const size_t pos,
|
||||
int idx = 0;
|
||||
size_t p = nodes[pos].u.shortcut;
|
||||
while (idx < 4 && p > 0) {
|
||||
const size_t ilen = nodes[p].dcode_insert_length & 0x7FFFFFF;
|
||||
const size_t clen = ZopfliNodeCopyLength(&nodes[p]);
|
||||
const size_t i_len = nodes[p].dcode_insert_length & 0x7FFFFFF;
|
||||
const size_t c_len = ZopfliNodeCopyLength(&nodes[p]);
|
||||
const size_t dist = ZopfliNodeCopyDistance(&nodes[p]);
|
||||
dist_cache[idx++] = (int)dist;
|
||||
/* Because of prerequisite, p >= clen + ilen >= 2. */
|
||||
p = nodes[p - clen - ilen].u.shortcut;
|
||||
/* Because of prerequisite, p >= c_len + i_len >= 2. */
|
||||
p = nodes[p - c_len - i_len].u.shortcut;
|
||||
}
|
||||
for (; idx < 4; ++idx) {
|
||||
dist_cache[idx] = *starting_dist_cache++;
|
||||
@@ -408,19 +418,25 @@ static size_t UpdateNodes(
|
||||
const int* starting_dist_cache, const size_t num_matches,
|
||||
const BackwardMatch* matches, const ZopfliCostModel* model,
|
||||
StartPosQueue* queue, ZopfliNode* nodes) {
|
||||
const size_t stream_offset = params->stream_offset;
|
||||
const size_t cur_ix = block_start + pos;
|
||||
const size_t cur_ix_masked = cur_ix & ringbuffer_mask;
|
||||
const size_t max_distance = BROTLI_MIN(size_t, cur_ix, max_backward_limit);
|
||||
const size_t dictionary_start = BROTLI_MIN(size_t,
|
||||
cur_ix + stream_offset, max_backward_limit);
|
||||
const size_t max_len = num_bytes - pos;
|
||||
const size_t max_zopfli_len = MaxZopfliLen(params);
|
||||
const size_t max_iters = MaxZopfliCandidates(params);
|
||||
size_t min_len;
|
||||
size_t result = 0;
|
||||
size_t k;
|
||||
size_t gap = 0;
|
||||
const CompoundDictionary* addon = ¶ms->dictionary.compound;
|
||||
size_t gap = addon->total_size;
|
||||
|
||||
EvaluateNode(block_start, pos, max_backward_limit, gap, starting_dist_cache,
|
||||
model, queue, nodes);
|
||||
BROTLI_DCHECK(cur_ix_masked + max_len <= ringbuffer_mask);
|
||||
|
||||
EvaluateNode(block_start + stream_offset, pos, max_backward_limit, gap,
|
||||
starting_dist_cache, model, queue, nodes);
|
||||
|
||||
{
|
||||
const PosData* posdata = StartPosQueueAt(queue, 0);
|
||||
@@ -453,10 +469,12 @@ static size_t UpdateNodes(
|
||||
if (cur_ix_masked + best_len > ringbuffer_mask) {
|
||||
break;
|
||||
}
|
||||
if (BROTLI_PREDICT_FALSE(backward > max_distance + gap)) {
|
||||
if (BROTLI_PREDICT_FALSE(backward > dictionary_start + gap)) {
|
||||
/* Word dictionary -> ignore. */
|
||||
continue;
|
||||
}
|
||||
if (backward <= max_distance) {
|
||||
/* Regular backward reference. */
|
||||
if (prev_ix >= cur_ix) {
|
||||
continue;
|
||||
}
|
||||
@@ -469,7 +487,27 @@ static size_t UpdateNodes(
|
||||
len = FindMatchLengthWithLimit(&ringbuffer[prev_ix],
|
||||
&ringbuffer[cur_ix_masked],
|
||||
max_len);
|
||||
} else if (backward > dictionary_start) {
|
||||
size_t d = 0;
|
||||
size_t offset;
|
||||
size_t limit;
|
||||
const uint8_t* source;
|
||||
offset = dictionary_start + 1 + addon->total_size - 1;
|
||||
while (offset >= backward + addon->chunk_offsets[d + 1]) d++;
|
||||
source = addon->chunk_source[d];
|
||||
offset = offset - addon->chunk_offsets[d] - backward;
|
||||
limit = addon->chunk_offsets[d + 1] - addon->chunk_offsets[d] - offset;
|
||||
limit = limit > max_len ? max_len : limit;
|
||||
if (best_len >= limit ||
|
||||
continuation != source[offset + best_len]) {
|
||||
continue;
|
||||
}
|
||||
len = FindMatchLengthWithLimit(&source[offset],
|
||||
&ringbuffer[cur_ix_masked],
|
||||
limit);
|
||||
} else {
|
||||
/* "Gray" area. It is addressable by decoder, but this encoder
|
||||
instance does not have that data -> should not touch it. */
|
||||
continue;
|
||||
}
|
||||
{
|
||||
@@ -504,7 +542,7 @@ static size_t UpdateNodes(
|
||||
BackwardMatch match = matches[j];
|
||||
size_t dist = match.distance;
|
||||
BROTLI_BOOL is_dictionary_match =
|
||||
TO_BROTLI_BOOL(dist > max_distance + gap);
|
||||
TO_BROTLI_BOOL(dist > dictionary_start + gap);
|
||||
/* We already tried all possible last distance matches, so we can use
|
||||
normal distance code here. */
|
||||
size_t dist_code = dist + BROTLI_NUM_DISTANCE_SHORT_CODES - 1;
|
||||
@@ -564,18 +602,15 @@ static size_t ComputeShortestPathFromNodes(size_t num_bytes,
|
||||
|
||||
/* REQUIRES: nodes != NULL and len(nodes) >= num_bytes + 1 */
|
||||
void BrotliZopfliCreateCommands(const size_t num_bytes,
|
||||
const size_t block_start,
|
||||
const size_t max_backward_limit,
|
||||
const ZopfliNode* nodes,
|
||||
int* dist_cache,
|
||||
size_t* last_insert_len,
|
||||
const BrotliEncoderParams* params,
|
||||
Command* commands,
|
||||
size_t* num_literals) {
|
||||
const size_t block_start, const ZopfliNode* nodes, int* dist_cache,
|
||||
size_t* last_insert_len, const BrotliEncoderParams* params,
|
||||
Command* commands, size_t* num_literals) {
|
||||
const size_t stream_offset = params->stream_offset;
|
||||
const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
|
||||
size_t pos = 0;
|
||||
uint32_t offset = nodes[0].u.next;
|
||||
size_t i;
|
||||
size_t gap = 0;
|
||||
size_t gap = params->dictionary.compound.total_size;
|
||||
for (i = 0; offset != BROTLI_UINT32_MAX; i++) {
|
||||
const ZopfliNode* next = &nodes[pos + offset];
|
||||
size_t copy_length = ZopfliNodeCopyLength(next);
|
||||
@@ -589,9 +624,10 @@ void BrotliZopfliCreateCommands(const size_t num_bytes,
|
||||
{
|
||||
size_t distance = ZopfliNodeCopyDistance(next);
|
||||
size_t len_code = ZopfliNodeLengthCode(next);
|
||||
size_t max_distance =
|
||||
BROTLI_MIN(size_t, block_start + pos, max_backward_limit);
|
||||
BROTLI_BOOL is_dictionary = TO_BROTLI_BOOL(distance > max_distance + gap);
|
||||
size_t dictionary_start = BROTLI_MIN(size_t,
|
||||
block_start + pos + stream_offset, max_backward_limit);
|
||||
BROTLI_BOOL is_dictionary =
|
||||
TO_BROTLI_BOOL(distance > dictionary_start + gap);
|
||||
size_t dist_code = ZopfliNodeDistanceCode(next);
|
||||
InitCommand(&commands[i], ¶ms->dist, insert_length,
|
||||
copy_length, (int)len_code - (int)copy_length, dist_code);
|
||||
@@ -610,18 +646,13 @@ void BrotliZopfliCreateCommands(const size_t num_bytes,
|
||||
*last_insert_len += num_bytes - pos;
|
||||
}
|
||||
|
||||
static size_t ZopfliIterate(size_t num_bytes,
|
||||
size_t position,
|
||||
const uint8_t* ringbuffer,
|
||||
size_t ringbuffer_mask,
|
||||
const BrotliEncoderParams* params,
|
||||
const size_t max_backward_limit,
|
||||
const size_t gap,
|
||||
const int* dist_cache,
|
||||
const ZopfliCostModel* model,
|
||||
const uint32_t* num_matches,
|
||||
const BackwardMatch* matches,
|
||||
ZopfliNode* nodes) {
|
||||
static size_t ZopfliIterate(size_t num_bytes, size_t position,
|
||||
const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
||||
const BrotliEncoderParams* params, const size_t gap, const int* dist_cache,
|
||||
const ZopfliCostModel* model, const uint32_t* num_matches,
|
||||
const BackwardMatch* matches, ZopfliNode* nodes) {
|
||||
const size_t stream_offset = params->stream_offset;
|
||||
const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
|
||||
const size_t max_zopfli_len = MaxZopfliLen(params);
|
||||
StartPosQueue queue;
|
||||
size_t cur_match_pos = 0;
|
||||
@@ -645,8 +676,8 @@ static size_t ZopfliIterate(size_t num_bytes,
|
||||
while (skip) {
|
||||
i++;
|
||||
if (i + 3 >= num_bytes) break;
|
||||
EvaluateNode(position, i, max_backward_limit, gap, dist_cache, model,
|
||||
&queue, nodes);
|
||||
EvaluateNode(position + stream_offset, i, max_backward_limit, gap,
|
||||
dist_cache, model, &queue, nodes);
|
||||
cur_match_pos += num_matches[i];
|
||||
skip--;
|
||||
}
|
||||
@@ -655,42 +686,88 @@ static size_t ZopfliIterate(size_t num_bytes,
|
||||
return ComputeShortestPathFromNodes(num_bytes, nodes);
|
||||
}
|
||||
|
||||
static void MergeMatches(BackwardMatch* dst,
|
||||
BackwardMatch* src1, size_t len1, BackwardMatch* src2, size_t len2) {
|
||||
while (len1 > 0 && len2 > 0) {
|
||||
size_t l1 = BackwardMatchLength(src1);
|
||||
size_t l2 = BackwardMatchLength(src2);
|
||||
if (l1 < l2 || ((l1 == l2) && (src1->distance < src2->distance))) {
|
||||
*dst++ = *src1++;
|
||||
len1--;
|
||||
} else {
|
||||
*dst++ = *src2++;
|
||||
len2--;
|
||||
}
|
||||
}
|
||||
while (len1-- > 0) *dst++ = *src1++;
|
||||
while (len2-- > 0) *dst++ = *src2++;
|
||||
}
|
||||
|
||||
/* REQUIRES: nodes != NULL and len(nodes) >= num_bytes + 1 */
|
||||
size_t BrotliZopfliComputeShortestPath(MemoryManager* m,
|
||||
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
|
||||
size_t ringbuffer_mask, const BrotliEncoderParams* params,
|
||||
const size_t max_backward_limit, const int* dist_cache, HasherHandle hasher,
|
||||
ZopfliNode* nodes) {
|
||||
size_t BrotliZopfliComputeShortestPath(MemoryManager* m, size_t num_bytes,
|
||||
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
||||
ContextLut literal_context_lut, const BrotliEncoderParams* params,
|
||||
const int* dist_cache, Hasher* hasher, ZopfliNode* nodes) {
|
||||
const size_t stream_offset = params->stream_offset;
|
||||
const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
|
||||
const size_t max_zopfli_len = MaxZopfliLen(params);
|
||||
ZopfliCostModel model;
|
||||
StartPosQueue queue;
|
||||
BackwardMatch matches[2 * (MAX_NUM_MATCHES_H10 + 64)];
|
||||
BackwardMatch* BROTLI_RESTRICT matches =
|
||||
BROTLI_ALLOC(m, BackwardMatch, 2 * (MAX_NUM_MATCHES_H10 + 64));
|
||||
const size_t store_end = num_bytes >= StoreLookaheadH10() ?
|
||||
position + num_bytes - StoreLookaheadH10() + 1 : position;
|
||||
size_t i;
|
||||
size_t gap = 0;
|
||||
size_t lz_matches_offset = 0;
|
||||
const CompoundDictionary* addon = ¶ms->dictionary.compound;
|
||||
size_t gap = addon->total_size;
|
||||
size_t lz_matches_offset =
|
||||
(addon->num_chunks != 0) ? (MAX_NUM_MATCHES_H10 + 128) : 0;
|
||||
ZopfliCostModel* model = BROTLI_ALLOC(m, ZopfliCostModel, 1);
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(model) || BROTLI_IS_NULL(matches)) {
|
||||
return 0;
|
||||
}
|
||||
nodes[0].length = 0;
|
||||
nodes[0].u.cost = 0;
|
||||
InitZopfliCostModel(m, &model, ¶ms->dist, num_bytes);
|
||||
InitZopfliCostModel(m, model, ¶ms->dist, num_bytes);
|
||||
if (BROTLI_IS_OOM(m)) return 0;
|
||||
ZopfliCostModelSetFromLiteralCosts(
|
||||
&model, position, ringbuffer, ringbuffer_mask);
|
||||
model, position, ringbuffer, ringbuffer_mask);
|
||||
InitStartPosQueue(&queue);
|
||||
for (i = 0; i + HashTypeLengthH10() - 1 < num_bytes; i++) {
|
||||
const size_t pos = position + i;
|
||||
const size_t max_distance = BROTLI_MIN(size_t, pos, max_backward_limit);
|
||||
const size_t dictionary_start = BROTLI_MIN(size_t,
|
||||
pos + stream_offset, max_backward_limit);
|
||||
size_t skip;
|
||||
size_t num_matches = FindAllMatchesH10(hasher, ¶ms->dictionary,
|
||||
ringbuffer, ringbuffer_mask, pos, num_bytes - i, max_distance, gap,
|
||||
params, &matches[lz_matches_offset]);
|
||||
size_t num_matches;
|
||||
int dict_id = 0;
|
||||
if (params->dictionary.contextual.context_based) {
|
||||
uint8_t p1 = pos >= 1 ?
|
||||
ringbuffer[(size_t)(pos - 1) & ringbuffer_mask] : 0;
|
||||
uint8_t p2 = pos >= 2 ?
|
||||
ringbuffer[(size_t)(pos - 2) & ringbuffer_mask] : 0;
|
||||
dict_id = params->dictionary.contextual.context_map[
|
||||
BROTLI_CONTEXT(p1, p2, literal_context_lut)];
|
||||
}
|
||||
num_matches = FindAllMatchesH10(&hasher->privat._H10,
|
||||
params->dictionary.contextual.dict[dict_id],
|
||||
ringbuffer, ringbuffer_mask, pos, num_bytes - i, max_distance,
|
||||
dictionary_start + gap, params, &matches[lz_matches_offset]);
|
||||
if (addon->num_chunks != 0) {
|
||||
size_t cd_matches = LookupAllCompoundDictionaryMatches(addon,
|
||||
ringbuffer, ringbuffer_mask, pos, 3, num_bytes - i,
|
||||
dictionary_start, params->dist.max_distance,
|
||||
&matches[lz_matches_offset - 64], 64);
|
||||
MergeMatches(matches, &matches[lz_matches_offset - 64], cd_matches,
|
||||
&matches[lz_matches_offset], num_matches);
|
||||
num_matches += cd_matches;
|
||||
}
|
||||
if (num_matches > 0 &&
|
||||
BackwardMatchLength(&matches[num_matches - 1]) > max_zopfli_len) {
|
||||
matches[0] = matches[num_matches - 1];
|
||||
num_matches = 1;
|
||||
}
|
||||
skip = UpdateNodes(num_bytes, position, i, ringbuffer, ringbuffer_mask,
|
||||
params, max_backward_limit, dist_cache, num_matches, matches, &model,
|
||||
params, max_backward_limit, dist_cache, num_matches, matches, model,
|
||||
&queue, nodes);
|
||||
if (skip < BROTLI_LONG_COPY_QUICK_STEP) skip = 0;
|
||||
if (num_matches == 1 && BackwardMatchLength(&matches[0]) > max_zopfli_len) {
|
||||
@@ -698,46 +775,48 @@ size_t BrotliZopfliComputeShortestPath(MemoryManager* m,
|
||||
}
|
||||
if (skip > 1) {
|
||||
/* Add the tail of the copy to the hasher. */
|
||||
StoreRangeH10(hasher, ringbuffer, ringbuffer_mask, pos + 1, BROTLI_MIN(
|
||||
StoreRangeH10(&hasher->privat._H10,
|
||||
ringbuffer, ringbuffer_mask, pos + 1, BROTLI_MIN(
|
||||
size_t, pos + skip, store_end));
|
||||
skip--;
|
||||
while (skip) {
|
||||
i++;
|
||||
if (i + HashTypeLengthH10() - 1 >= num_bytes) break;
|
||||
EvaluateNode(position, i, max_backward_limit, gap, dist_cache, &model,
|
||||
&queue, nodes);
|
||||
EvaluateNode(position + stream_offset, i, max_backward_limit, gap,
|
||||
dist_cache, model, &queue, nodes);
|
||||
skip--;
|
||||
}
|
||||
}
|
||||
}
|
||||
CleanupZopfliCostModel(m, &model);
|
||||
CleanupZopfliCostModel(m, model);
|
||||
BROTLI_FREE(m, model);
|
||||
BROTLI_FREE(m, matches);
|
||||
return ComputeShortestPathFromNodes(num_bytes, nodes);
|
||||
}
|
||||
|
||||
void BrotliCreateZopfliBackwardReferences(MemoryManager* m,
|
||||
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
|
||||
size_t ringbuffer_mask, const BrotliEncoderParams* params,
|
||||
HasherHandle hasher, int* dist_cache, size_t* last_insert_len,
|
||||
void BrotliCreateZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
|
||||
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
||||
ContextLut literal_context_lut, const BrotliEncoderParams* params,
|
||||
Hasher* hasher, int* dist_cache, size_t* last_insert_len,
|
||||
Command* commands, size_t* num_commands, size_t* num_literals) {
|
||||
const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
|
||||
ZopfliNode* nodes;
|
||||
nodes = BROTLI_ALLOC(m, ZopfliNode, num_bytes + 1);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
ZopfliNode* nodes = BROTLI_ALLOC(m, ZopfliNode, num_bytes + 1);
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(nodes)) return;
|
||||
BrotliInitZopfliNodes(nodes, num_bytes + 1);
|
||||
*num_commands += BrotliZopfliComputeShortestPath(m,
|
||||
num_bytes, position, ringbuffer, ringbuffer_mask,
|
||||
params, max_backward_limit, dist_cache, hasher, nodes);
|
||||
*num_commands += BrotliZopfliComputeShortestPath(m, num_bytes,
|
||||
position, ringbuffer, ringbuffer_mask, literal_context_lut, params,
|
||||
dist_cache, hasher, nodes);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
BrotliZopfliCreateCommands(num_bytes, position, max_backward_limit, nodes,
|
||||
dist_cache, last_insert_len, params, commands, num_literals);
|
||||
BrotliZopfliCreateCommands(num_bytes, position, nodes, dist_cache,
|
||||
last_insert_len, params, commands, num_literals);
|
||||
BROTLI_FREE(m, nodes);
|
||||
}
|
||||
|
||||
void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m,
|
||||
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
|
||||
size_t ringbuffer_mask, const BrotliEncoderParams* params,
|
||||
HasherHandle hasher, int* dist_cache, size_t* last_insert_len,
|
||||
void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
|
||||
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
||||
ContextLut literal_context_lut, const BrotliEncoderParams* params,
|
||||
Hasher* hasher, int* dist_cache, size_t* last_insert_len,
|
||||
Command* commands, size_t* num_commands, size_t* num_literals) {
|
||||
const size_t stream_offset = params->stream_offset;
|
||||
const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
|
||||
uint32_t* num_matches = BROTLI_ALLOC(m, uint32_t, num_bytes);
|
||||
size_t matches_size = 4 * num_bytes;
|
||||
@@ -749,26 +828,54 @@ void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m,
|
||||
size_t orig_last_insert_len;
|
||||
int orig_dist_cache[4];
|
||||
size_t orig_num_commands;
|
||||
ZopfliCostModel model;
|
||||
ZopfliCostModel* model = BROTLI_ALLOC(m, ZopfliCostModel, 1);
|
||||
ZopfliNode* nodes;
|
||||
BackwardMatch* matches = BROTLI_ALLOC(m, BackwardMatch, matches_size);
|
||||
size_t gap = 0;
|
||||
size_t shadow_matches = 0;
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
const CompoundDictionary* addon = ¶ms->dictionary.compound;
|
||||
size_t gap = addon->total_size;
|
||||
size_t shadow_matches =
|
||||
(addon->num_chunks != 0) ? (MAX_NUM_MATCHES_H10 + 128) : 0;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(model) ||
|
||||
BROTLI_IS_NULL(num_matches) || BROTLI_IS_NULL(matches)) {
|
||||
return;
|
||||
}
|
||||
for (i = 0; i + HashTypeLengthH10() - 1 < num_bytes; ++i) {
|
||||
const size_t pos = position + i;
|
||||
size_t max_distance = BROTLI_MIN(size_t, pos, max_backward_limit);
|
||||
size_t dictionary_start = BROTLI_MIN(size_t,
|
||||
pos + stream_offset, max_backward_limit);
|
||||
size_t max_length = num_bytes - i;
|
||||
size_t num_found_matches;
|
||||
size_t cur_match_end;
|
||||
size_t j;
|
||||
int dict_id = 0;
|
||||
if (params->dictionary.contextual.context_based) {
|
||||
uint8_t p1 = pos >= 1 ?
|
||||
ringbuffer[(size_t)(pos - 1) & ringbuffer_mask] : 0;
|
||||
uint8_t p2 = pos >= 2 ?
|
||||
ringbuffer[(size_t)(pos - 2) & ringbuffer_mask] : 0;
|
||||
dict_id = params->dictionary.contextual.context_map[
|
||||
BROTLI_CONTEXT(p1, p2, literal_context_lut)];
|
||||
}
|
||||
/* Ensure that we have enough free slots. */
|
||||
BROTLI_ENSURE_CAPACITY(m, BackwardMatch, matches, matches_size,
|
||||
cur_match_pos + MAX_NUM_MATCHES_H10 + shadow_matches);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
num_found_matches = FindAllMatchesH10(hasher,
|
||||
¶ms->dictionary, ringbuffer, ringbuffer_mask, pos, max_length,
|
||||
max_distance, gap, params, &matches[cur_match_pos + shadow_matches]);
|
||||
num_found_matches = FindAllMatchesH10(&hasher->privat._H10,
|
||||
params->dictionary.contextual.dict[dict_id],
|
||||
ringbuffer, ringbuffer_mask, pos, max_length,
|
||||
max_distance, dictionary_start + gap, params,
|
||||
&matches[cur_match_pos + shadow_matches]);
|
||||
if (addon->num_chunks != 0) {
|
||||
size_t cd_matches = LookupAllCompoundDictionaryMatches(addon,
|
||||
ringbuffer, ringbuffer_mask, pos, 3, max_length,
|
||||
dictionary_start, params->dist.max_distance,
|
||||
&matches[cur_match_pos + shadow_matches - 64], 64);
|
||||
MergeMatches(&matches[cur_match_pos],
|
||||
&matches[cur_match_pos + shadow_matches - 64], cd_matches,
|
||||
&matches[cur_match_pos + shadow_matches], num_found_matches);
|
||||
num_found_matches += cd_matches;
|
||||
}
|
||||
cur_match_end = cur_match_pos + num_found_matches;
|
||||
for (j = cur_match_pos; j + 1 < cur_match_end; ++j) {
|
||||
BROTLI_DCHECK(BackwardMatchLength(&matches[j]) <=
|
||||
@@ -782,7 +889,8 @@ void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m,
|
||||
matches[cur_match_pos++] = matches[cur_match_end - 1];
|
||||
num_matches[i] = 1;
|
||||
/* Add the tail of the copy to the hasher. */
|
||||
StoreRangeH10(hasher, ringbuffer, ringbuffer_mask, pos + 1,
|
||||
StoreRangeH10(&hasher->privat._H10,
|
||||
ringbuffer, ringbuffer_mask, pos + 1,
|
||||
BROTLI_MIN(size_t, pos + match_len, store_end));
|
||||
memset(&num_matches[i + 1], 0, skip * sizeof(num_matches[0]));
|
||||
i += skip;
|
||||
@@ -796,16 +904,16 @@ void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m,
|
||||
memcpy(orig_dist_cache, dist_cache, 4 * sizeof(dist_cache[0]));
|
||||
orig_num_commands = *num_commands;
|
||||
nodes = BROTLI_ALLOC(m, ZopfliNode, num_bytes + 1);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
InitZopfliCostModel(m, &model, ¶ms->dist, num_bytes);
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(nodes)) return;
|
||||
InitZopfliCostModel(m, model, ¶ms->dist, num_bytes);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
for (i = 0; i < 2; i++) {
|
||||
BrotliInitZopfliNodes(nodes, num_bytes + 1);
|
||||
if (i == 0) {
|
||||
ZopfliCostModelSetFromLiteralCosts(
|
||||
&model, position, ringbuffer, ringbuffer_mask);
|
||||
model, position, ringbuffer, ringbuffer_mask);
|
||||
} else {
|
||||
ZopfliCostModelSetFromCommands(&model, position, ringbuffer,
|
||||
ZopfliCostModelSetFromCommands(model, position, ringbuffer,
|
||||
ringbuffer_mask, commands, *num_commands - orig_num_commands,
|
||||
orig_last_insert_len);
|
||||
}
|
||||
@@ -814,12 +922,13 @@ void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m,
|
||||
*last_insert_len = orig_last_insert_len;
|
||||
memcpy(dist_cache, orig_dist_cache, 4 * sizeof(dist_cache[0]));
|
||||
*num_commands += ZopfliIterate(num_bytes, position, ringbuffer,
|
||||
ringbuffer_mask, params, max_backward_limit, gap, dist_cache,
|
||||
&model, num_matches, matches, nodes);
|
||||
BrotliZopfliCreateCommands(num_bytes, position, max_backward_limit,
|
||||
nodes, dist_cache, last_insert_len, params, commands, num_literals);
|
||||
ringbuffer_mask, params, gap, dist_cache, model, num_matches, matches,
|
||||
nodes);
|
||||
BrotliZopfliCreateCommands(num_bytes, position, nodes, dist_cache,
|
||||
last_insert_len, params, commands, num_literals);
|
||||
}
|
||||
CleanupZopfliCostModel(m, &model);
|
||||
CleanupZopfliCostModel(m, model);
|
||||
BROTLI_FREE(m, model);
|
||||
BROTLI_FREE(m, nodes);
|
||||
BROTLI_FREE(m, matches);
|
||||
BROTLI_FREE(m, num_matches);
|
||||
|
||||
@@ -9,29 +9,29 @@
|
||||
#ifndef BROTLI_ENC_BACKWARD_REFERENCES_HQ_H_
|
||||
#define BROTLI_ENC_BACKWARD_REFERENCES_HQ_H_
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include "../common/dictionary.h"
|
||||
#include "../common/context.h"
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./command.h"
|
||||
#include "./hash.h"
|
||||
#include "./memory.h"
|
||||
#include "./quality.h"
|
||||
#include "command.h"
|
||||
#include "hash.h"
|
||||
#include "memory.h"
|
||||
#include "params.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
BROTLI_INTERNAL void BrotliCreateZopfliBackwardReferences(MemoryManager* m,
|
||||
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
|
||||
size_t ringbuffer_mask, const BrotliEncoderParams* params,
|
||||
HasherHandle hasher, int* dist_cache, size_t* last_insert_len,
|
||||
size_t num_bytes,
|
||||
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
||||
ContextLut literal_context_lut, const BrotliEncoderParams* params,
|
||||
Hasher* hasher, int* dist_cache, size_t* last_insert_len,
|
||||
Command* commands, size_t* num_commands, size_t* num_literals);
|
||||
|
||||
BROTLI_INTERNAL void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m,
|
||||
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
|
||||
size_t ringbuffer_mask, const BrotliEncoderParams* params,
|
||||
HasherHandle hasher, int* dist_cache, size_t* last_insert_len,
|
||||
size_t num_bytes,
|
||||
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
||||
ContextLut literal_context_lut, const BrotliEncoderParams* params,
|
||||
Hasher* hasher, int* dist_cache, size_t* last_insert_len,
|
||||
Command* commands, size_t* num_commands, size_t* num_literals);
|
||||
|
||||
typedef struct ZopfliNode {
|
||||
@@ -74,15 +74,14 @@ BROTLI_INTERNAL void BrotliInitZopfliNodes(ZopfliNode* array, size_t length);
|
||||
(1) nodes[i].copy_length() >= 2
|
||||
(2) nodes[i].command_length() <= i and
|
||||
(3) nodes[i - nodes[i].command_length()].cost < kInfinity */
|
||||
BROTLI_INTERNAL size_t BrotliZopfliComputeShortestPath(MemoryManager* m,
|
||||
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
|
||||
size_t ringbuffer_mask, const BrotliEncoderParams* params,
|
||||
const size_t max_backward_limit, const int* dist_cache, HasherHandle hasher,
|
||||
ZopfliNode* nodes);
|
||||
BROTLI_INTERNAL size_t BrotliZopfliComputeShortestPath(
|
||||
MemoryManager* m, size_t num_bytes,
|
||||
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
||||
ContextLut literal_context_lut, const BrotliEncoderParams* params,
|
||||
const int* dist_cache, Hasher* hasher, ZopfliNode* nodes);
|
||||
|
||||
BROTLI_INTERNAL void BrotliZopfliCreateCommands(
|
||||
const size_t num_bytes, const size_t block_start,
|
||||
const size_t max_backward_limit, const ZopfliNode* nodes,
|
||||
const size_t num_bytes, const size_t block_start, const ZopfliNode* nodes,
|
||||
int* dist_cache, size_t* last_insert_len, const BrotliEncoderParams* params,
|
||||
Command* commands, size_t* num_literals);
|
||||
|
||||
|
||||
@@ -10,11 +10,13 @@
|
||||
static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
|
||||
size_t num_bytes, size_t position,
|
||||
const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
||||
const BrotliEncoderParams* params, HasherHandle hasher, int* dist_cache,
|
||||
size_t* last_insert_len, Command* commands, size_t* num_commands,
|
||||
size_t* num_literals) {
|
||||
ContextLut literal_context_lut, const BrotliEncoderParams* params,
|
||||
Hasher* hasher, int* dist_cache, size_t* last_insert_len,
|
||||
Command* commands, size_t* num_commands, size_t* num_literals) {
|
||||
HASHER()* privat = &hasher->privat.FN(_);
|
||||
/* Set maximum distance, see section 9.1. of the spec. */
|
||||
const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
|
||||
const size_t position_offset = params->stream_offset;
|
||||
|
||||
const Command* const orig_commands = commands;
|
||||
size_t insert_length = *last_insert_len;
|
||||
@@ -26,25 +28,42 @@ static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
|
||||
const size_t random_heuristics_window_size =
|
||||
LiteralSpreeLengthForSparseSearch(params);
|
||||
size_t apply_random_heuristics = position + random_heuristics_window_size;
|
||||
const size_t gap = 0;
|
||||
const size_t gap = params->dictionary.compound.total_size;
|
||||
|
||||
/* Minimum score to accept a backward reference. */
|
||||
const score_t kMinScore = BROTLI_SCORE_BASE + 100;
|
||||
|
||||
FN(PrepareDistanceCache)(hasher, dist_cache);
|
||||
FN(PrepareDistanceCache)(privat, dist_cache);
|
||||
|
||||
while (position + FN(HashTypeLength)() < pos_end) {
|
||||
size_t max_length = pos_end - position;
|
||||
size_t max_distance = BROTLI_MIN(size_t, position, max_backward_limit);
|
||||
size_t dictionary_start = BROTLI_MIN(size_t,
|
||||
position + position_offset, max_backward_limit);
|
||||
HasherSearchResult sr;
|
||||
int dict_id = 0;
|
||||
uint8_t p1 = 0;
|
||||
uint8_t p2 = 0;
|
||||
if (params->dictionary.contextual.context_based) {
|
||||
p1 = position >= 1 ?
|
||||
ringbuffer[(size_t)(position - 1) & ringbuffer_mask] : 0;
|
||||
p2 = position >= 2 ?
|
||||
ringbuffer[(size_t)(position - 2) & ringbuffer_mask] : 0;
|
||||
dict_id = params->dictionary.contextual.context_map[
|
||||
BROTLI_CONTEXT(p1, p2, literal_context_lut)];
|
||||
}
|
||||
sr.len = 0;
|
||||
sr.len_code_delta = 0;
|
||||
sr.distance = 0;
|
||||
sr.score = kMinScore;
|
||||
FN(FindLongestMatch)(hasher, ¶ms->dictionary,
|
||||
ringbuffer, ringbuffer_mask, dist_cache, position,
|
||||
max_length, max_distance, gap,
|
||||
params->dist.max_distance, &sr);
|
||||
FN(FindLongestMatch)(privat, params->dictionary.contextual.dict[dict_id],
|
||||
ringbuffer, ringbuffer_mask, dist_cache, position, max_length,
|
||||
max_distance, dictionary_start + gap, params->dist.max_distance, &sr);
|
||||
if (ENABLE_COMPOUND_DICTIONARY) {
|
||||
LookupCompoundDictionaryMatch(¶ms->dictionary.compound, ringbuffer,
|
||||
ringbuffer_mask, dist_cache, position, max_length,
|
||||
dictionary_start, params->dist.max_distance, &sr);
|
||||
}
|
||||
if (sr.score > kMinScore) {
|
||||
/* Found a match. Let's look for something even better ahead. */
|
||||
int delayed_backward_references_in_row = 0;
|
||||
@@ -58,9 +77,25 @@ static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
|
||||
sr2.distance = 0;
|
||||
sr2.score = kMinScore;
|
||||
max_distance = BROTLI_MIN(size_t, position + 1, max_backward_limit);
|
||||
FN(FindLongestMatch)(hasher, ¶ms->dictionary,
|
||||
dictionary_start = BROTLI_MIN(size_t,
|
||||
position + 1 + position_offset, max_backward_limit);
|
||||
if (params->dictionary.contextual.context_based) {
|
||||
p2 = p1;
|
||||
p1 = ringbuffer[position & ringbuffer_mask];
|
||||
dict_id = params->dictionary.contextual.context_map[
|
||||
BROTLI_CONTEXT(p1, p2, literal_context_lut)];
|
||||
}
|
||||
FN(FindLongestMatch)(privat,
|
||||
params->dictionary.contextual.dict[dict_id],
|
||||
ringbuffer, ringbuffer_mask, dist_cache, position + 1, max_length,
|
||||
max_distance, gap, params->dist.max_distance, &sr2);
|
||||
max_distance, dictionary_start + gap, params->dist.max_distance,
|
||||
&sr2);
|
||||
if (ENABLE_COMPOUND_DICTIONARY) {
|
||||
LookupCompoundDictionaryMatch(
|
||||
¶ms->dictionary.compound, ringbuffer,
|
||||
ringbuffer_mask, dist_cache, position + 1, max_length,
|
||||
dictionary_start, params->dist.max_distance, &sr2);
|
||||
}
|
||||
if (sr2.score >= sr.score + cost_diff_lazy) {
|
||||
/* Ok, let's just write one byte for now and start a match from the
|
||||
next byte. */
|
||||
@@ -76,18 +111,19 @@ static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
|
||||
}
|
||||
apply_random_heuristics =
|
||||
position + 2 * sr.len + random_heuristics_window_size;
|
||||
max_distance = BROTLI_MIN(size_t, position, max_backward_limit);
|
||||
dictionary_start = BROTLI_MIN(size_t,
|
||||
position + position_offset, max_backward_limit);
|
||||
{
|
||||
/* The first 16 codes are special short-codes,
|
||||
and the minimum offset is 1. */
|
||||
size_t distance_code =
|
||||
ComputeDistanceCode(sr.distance, max_distance + gap, dist_cache);
|
||||
if ((sr.distance <= (max_distance + gap)) && distance_code > 0) {
|
||||
size_t distance_code = ComputeDistanceCode(
|
||||
sr.distance, dictionary_start + gap, dist_cache);
|
||||
if ((sr.distance <= (dictionary_start + gap)) && distance_code > 0) {
|
||||
dist_cache[3] = dist_cache[2];
|
||||
dist_cache[2] = dist_cache[1];
|
||||
dist_cache[1] = dist_cache[0];
|
||||
dist_cache[0] = (int)sr.distance;
|
||||
FN(PrepareDistanceCache)(hasher, dist_cache);
|
||||
FN(PrepareDistanceCache)(privat, dist_cache);
|
||||
}
|
||||
InitCommand(commands++, ¶ms->dist, insert_length,
|
||||
sr.len, sr.len_code_delta, distance_code);
|
||||
@@ -105,7 +141,7 @@ static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
|
||||
range_start = BROTLI_MIN(size_t, range_end, BROTLI_MAX(size_t,
|
||||
range_start, position + sr.len - (sr.distance << 2)));
|
||||
}
|
||||
FN(StoreRange)(hasher, ringbuffer, ringbuffer_mask, range_start,
|
||||
FN(StoreRange)(privat, ringbuffer, ringbuffer_mask, range_start,
|
||||
range_end);
|
||||
}
|
||||
position += sr.len;
|
||||
@@ -131,7 +167,7 @@ static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
|
||||
size_t pos_jump =
|
||||
BROTLI_MIN(size_t, position + 16, pos_end - kMargin);
|
||||
for (; position < pos_jump; position += 4) {
|
||||
FN(Store)(hasher, ringbuffer, ringbuffer_mask, position);
|
||||
FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
|
||||
insert_length += 4;
|
||||
}
|
||||
} else {
|
||||
@@ -140,7 +176,7 @@ static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
|
||||
size_t pos_jump =
|
||||
BROTLI_MIN(size_t, position + 8, pos_end - kMargin);
|
||||
for (; position < pos_jump; position += 2) {
|
||||
FN(Store)(hasher, ringbuffer, ringbuffer_mask, position);
|
||||
FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
|
||||
insert_length += 2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,28 +6,53 @@
|
||||
|
||||
/* Functions to estimate the bit cost of Huffman trees. */
|
||||
|
||||
#include "./bit_cost.h"
|
||||
#include "bit_cost.h"
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./fast_log.h"
|
||||
#include "./histogram.h"
|
||||
#include "fast_log.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
double BrotliBitsEntropy(const uint32_t* population, size_t size) {
|
||||
size_t sum = 0;
|
||||
double retval = 0;
|
||||
const uint32_t* population_end = population + size;
|
||||
size_t p;
|
||||
if (size & 1) {
|
||||
goto odd_number_of_elements_left;
|
||||
}
|
||||
while (population < population_end) {
|
||||
p = *population++;
|
||||
sum += p;
|
||||
retval -= (double)p * FastLog2(p);
|
||||
odd_number_of_elements_left:
|
||||
p = *population++;
|
||||
sum += p;
|
||||
retval -= (double)p * FastLog2(p);
|
||||
}
|
||||
if (sum) retval += (double)sum * FastLog2(sum);
|
||||
|
||||
if (retval < (double)sum) {
|
||||
/* TODO(eustas): consider doing that per-symbol? */
|
||||
/* At least one bit per literal is needed. */
|
||||
retval = (double)sum;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
#define FN(X) X ## Literal
|
||||
#include "./bit_cost_inc.h" /* NOLINT(build/include) */
|
||||
#include "bit_cost_inc.h" /* NOLINT(build/include) */
|
||||
#undef FN
|
||||
|
||||
#define FN(X) X ## Command
|
||||
#include "./bit_cost_inc.h" /* NOLINT(build/include) */
|
||||
#include "bit_cost_inc.h" /* NOLINT(build/include) */
|
||||
#undef FN
|
||||
|
||||
#define FN(X) X ## Distance
|
||||
#include "./bit_cost_inc.h" /* NOLINT(build/include) */
|
||||
#include "bit_cost_inc.h" /* NOLINT(build/include) */
|
||||
#undef FN
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
|
||||
@@ -10,51 +10,20 @@
|
||||
#define BROTLI_ENC_BIT_COST_H_
|
||||
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./fast_log.h"
|
||||
#include "./histogram.h"
|
||||
#include "histogram.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static BROTLI_INLINE double ShannonEntropy(
|
||||
const uint32_t* population, size_t size, size_t* total) {
|
||||
size_t sum = 0;
|
||||
double retval = 0;
|
||||
const uint32_t* population_end = population + size;
|
||||
size_t p;
|
||||
if (size & 1) {
|
||||
goto odd_number_of_elements_left;
|
||||
}
|
||||
while (population < population_end) {
|
||||
p = *population++;
|
||||
sum += p;
|
||||
retval -= (double)p * FastLog2(p);
|
||||
odd_number_of_elements_left:
|
||||
p = *population++;
|
||||
sum += p;
|
||||
retval -= (double)p * FastLog2(p);
|
||||
}
|
||||
if (sum) retval += (double)sum * FastLog2(sum);
|
||||
*total = sum;
|
||||
return retval;
|
||||
}
|
||||
|
||||
static BROTLI_INLINE double BitsEntropy(
|
||||
const uint32_t* population, size_t size) {
|
||||
size_t sum;
|
||||
double retval = ShannonEntropy(population, size, &sum);
|
||||
if (retval < sum) {
|
||||
/* At least one bit per literal is needed. */
|
||||
retval = (double)sum;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
BROTLI_INTERNAL double BrotliPopulationCostLiteral(const HistogramLiteral*);
|
||||
BROTLI_INTERNAL double BrotliPopulationCostCommand(const HistogramCommand*);
|
||||
BROTLI_INTERNAL double BrotliPopulationCostDistance(const HistogramDistance*);
|
||||
BROTLI_INTERNAL double BrotliBitsEntropy(
|
||||
const uint32_t* population, size_t size);
|
||||
BROTLI_INTERNAL double BrotliPopulationCostLiteral(
|
||||
const HistogramLiteral* histogram);
|
||||
BROTLI_INTERNAL double BrotliPopulationCostCommand(
|
||||
const HistogramCommand* histogram);
|
||||
BROTLI_INTERNAL double BrotliPopulationCostDistance(
|
||||
const HistogramDistance* histogram);
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
|
||||
@@ -119,7 +119,7 @@ double FN(BrotliPopulationCost)(const HistogramType* histogram) {
|
||||
/* Add the estimated encoding cost of the code length code histogram. */
|
||||
bits += (double)(18 + 2 * max_depth);
|
||||
/* Add the entropy of the code length code histogram. */
|
||||
bits += BitsEntropy(depth_histo, BROTLI_CODE_LENGTH_CODES);
|
||||
bits += BrotliBitsEntropy(depth_histo, BROTLI_CODE_LENGTH_CODES);
|
||||
}
|
||||
return bits;
|
||||
}
|
||||
|
||||
@@ -6,18 +6,16 @@
|
||||
|
||||
/* Block split point selection utilities. */
|
||||
|
||||
#include "./block_splitter.h"
|
||||
|
||||
#include <string.h> /* memcpy, memset */
|
||||
#include "block_splitter.h"
|
||||
|
||||
#include "../common/platform.h"
|
||||
#include "./bit_cost.h"
|
||||
#include "./cluster.h"
|
||||
#include "./command.h"
|
||||
#include "./fast_log.h"
|
||||
#include "./histogram.h"
|
||||
#include "./memory.h"
|
||||
#include "./quality.h"
|
||||
#include "bit_cost.h"
|
||||
#include "cluster.h"
|
||||
#include "command.h"
|
||||
#include "fast_log.h"
|
||||
#include "histogram.h"
|
||||
#include "memory.h"
|
||||
#include "quality.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
@@ -30,6 +28,7 @@ static const double kCommandBlockSwitchCost = 13.5;
|
||||
static const double kDistanceBlockSwitchCost = 14.6;
|
||||
static const size_t kLiteralStrideLength = 70;
|
||||
static const size_t kCommandStrideLength = 40;
|
||||
static const size_t kDistanceStrideLength = 40;
|
||||
static const size_t kSymbolsPerLiteralHistogram = 544;
|
||||
static const size_t kSymbolsPerCommandHistogram = 530;
|
||||
static const size_t kSymbolsPerDistanceHistogram = 544;
|
||||
@@ -89,19 +88,19 @@ static BROTLI_INLINE double BitCost(size_t count) {
|
||||
#define FN(X) X ## Literal
|
||||
#define DataType uint8_t
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "./block_splitter_inc.h"
|
||||
#include "block_splitter_inc.h"
|
||||
#undef DataType
|
||||
#undef FN
|
||||
|
||||
#define FN(X) X ## Command
|
||||
#define DataType uint16_t
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "./block_splitter_inc.h"
|
||||
#include "block_splitter_inc.h"
|
||||
#undef FN
|
||||
|
||||
#define FN(X) X ## Distance
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "./block_splitter_inc.h"
|
||||
#include "block_splitter_inc.h"
|
||||
#undef DataType
|
||||
#undef FN
|
||||
|
||||
@@ -119,6 +118,8 @@ void BrotliDestroyBlockSplit(MemoryManager* m, BlockSplit* self) {
|
||||
BROTLI_FREE(m, self->lengths);
|
||||
}
|
||||
|
||||
/* Extracts literals, command distance and prefix codes, then applies
|
||||
* SplitByteVector to create partitioning. */
|
||||
void BrotliSplitBlock(MemoryManager* m,
|
||||
const Command* cmds,
|
||||
const size_t num_commands,
|
||||
@@ -132,11 +133,13 @@ void BrotliSplitBlock(MemoryManager* m,
|
||||
{
|
||||
size_t literals_count = CountLiterals(cmds, num_commands);
|
||||
uint8_t* literals = BROTLI_ALLOC(m, uint8_t, literals_count);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(literals)) return;
|
||||
/* Create a continuous array of literals. */
|
||||
CopyLiteralsToByteArray(cmds, num_commands, data, pos, mask, literals);
|
||||
/* Create the block split on the array of literals.
|
||||
Literal histograms have alphabet size 256. */
|
||||
* Literal histograms can have alphabet size up to 256.
|
||||
* Though, to accommodate context modeling, less than half of maximum size
|
||||
* is allowed. */
|
||||
SplitByteVectorLiteral(
|
||||
m, literals, literals_count,
|
||||
kSymbolsPerLiteralHistogram, kMaxLiteralHistograms,
|
||||
@@ -144,13 +147,17 @@ void BrotliSplitBlock(MemoryManager* m,
|
||||
literal_split);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
BROTLI_FREE(m, literals);
|
||||
/* NB: this might be a good place for injecting extra splitting without
|
||||
* increasing encoder complexity; however, output partition would be less
|
||||
* optimal than one produced with forced splitting inside
|
||||
* SplitByteVector (FindBlocks / ClusterBlocks). */
|
||||
}
|
||||
|
||||
{
|
||||
/* Compute prefix codes for commands. */
|
||||
uint16_t* insert_and_copy_codes = BROTLI_ALLOC(m, uint16_t, num_commands);
|
||||
size_t i;
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(insert_and_copy_codes)) return;
|
||||
for (i = 0; i < num_commands; ++i) {
|
||||
insert_and_copy_codes[i] = cmds[i].cmd_prefix_;
|
||||
}
|
||||
@@ -161,7 +168,7 @@ void BrotliSplitBlock(MemoryManager* m,
|
||||
kCommandStrideLength, kCommandBlockSwitchCost, params,
|
||||
insert_and_copy_split);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
/* TODO: reuse for distances? */
|
||||
/* TODO(eustas): reuse for distances? */
|
||||
BROTLI_FREE(m, insert_and_copy_codes);
|
||||
}
|
||||
|
||||
@@ -170,7 +177,7 @@ void BrotliSplitBlock(MemoryManager* m,
|
||||
uint16_t* distance_prefixes = BROTLI_ALLOC(m, uint16_t, num_commands);
|
||||
size_t j = 0;
|
||||
size_t i;
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(distance_prefixes)) return;
|
||||
for (i = 0; i < num_commands; ++i) {
|
||||
const Command* cmd = &cmds[i];
|
||||
if (CommandCopyLen(cmd) && cmd->cmd_prefix_ >= 128) {
|
||||
@@ -181,13 +188,26 @@ void BrotliSplitBlock(MemoryManager* m,
|
||||
SplitByteVectorDistance(
|
||||
m, distance_prefixes, j,
|
||||
kSymbolsPerDistanceHistogram, kMaxCommandHistograms,
|
||||
kCommandStrideLength, kDistanceBlockSwitchCost, params,
|
||||
kDistanceStrideLength, kDistanceBlockSwitchCost, params,
|
||||
dist_split);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
BROTLI_FREE(m, distance_prefixes);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(BROTLI_TEST)
|
||||
size_t BrotliCountLiteralsForTest(const Command*, size_t);
|
||||
size_t BrotliCountLiteralsForTest(const Command* cmds, size_t num_commands) {
|
||||
return CountLiterals(cmds, num_commands);
|
||||
}
|
||||
void BrotliCopyLiteralsToByteArrayForTest(
|
||||
const Command*, size_t, const uint8_t*, size_t, size_t, uint8_t*);
|
||||
void BrotliCopyLiteralsToByteArrayForTest(const Command* cmds,
|
||||
size_t num_commands, const uint8_t* data, size_t offset, size_t mask,
|
||||
uint8_t* literals) {
|
||||
CopyLiteralsToByteArray(cmds, num_commands, data, offset, mask, literals);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
|
||||
@@ -10,10 +10,8 @@
|
||||
#define BROTLI_ENC_BLOCK_SPLITTER_H_
|
||||
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./command.h"
|
||||
#include "./memory.h"
|
||||
#include "./quality.h"
|
||||
#include "command.h"
|
||||
#include "memory.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
|
||||
@@ -46,17 +46,17 @@ static void FN(RandomSample)(uint32_t* seed,
|
||||
static void FN(RefineEntropyCodes)(const DataType* data, size_t length,
|
||||
size_t stride,
|
||||
size_t num_histograms,
|
||||
HistogramType* histograms) {
|
||||
HistogramType* histograms,
|
||||
HistogramType* tmp) {
|
||||
size_t iters =
|
||||
kIterMulForRefining * length / stride + kMinItersForRefining;
|
||||
uint32_t seed = 7;
|
||||
size_t iter;
|
||||
iters = ((iters + num_histograms - 1) / num_histograms) * num_histograms;
|
||||
for (iter = 0; iter < iters; ++iter) {
|
||||
HistogramType sample;
|
||||
FN(HistogramClear)(&sample);
|
||||
FN(RandomSample)(&seed, data, length, stride, &sample);
|
||||
FN(HistogramAddHistogram)(&histograms[iter % num_histograms], &sample);
|
||||
FN(HistogramClear)(tmp);
|
||||
FN(RandomSample)(&seed, data, length, stride, tmp);
|
||||
FN(HistogramAddHistogram)(&histograms[iter % num_histograms], tmp);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,46 +71,58 @@ static size_t FN(FindBlocks)(const DataType* data, const size_t length,
|
||||
double* cost,
|
||||
uint8_t* switch_signal,
|
||||
uint8_t* block_id) {
|
||||
const size_t data_size = FN(HistogramDataSize)();
|
||||
const size_t bitmaplen = (num_histograms + 7) >> 3;
|
||||
const size_t alphabet_size = FN(HistogramDataSize)();
|
||||
const size_t bitmap_len = (num_histograms + 7) >> 3;
|
||||
size_t num_blocks = 1;
|
||||
size_t byte_ix;
|
||||
size_t i;
|
||||
size_t j;
|
||||
BROTLI_DCHECK(num_histograms <= 256);
|
||||
|
||||
/* Trivial case: single histogram -> single block type. */
|
||||
if (num_histograms <= 1) {
|
||||
for (i = 0; i < length; ++i) {
|
||||
block_id[i] = 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
memset(insert_cost, 0, sizeof(insert_cost[0]) * data_size * num_histograms);
|
||||
|
||||
/* Fill bitcost for each symbol of all histograms.
|
||||
* Non-existing symbol cost: 2 + log2(total_count).
|
||||
* Regular symbol cost: -log2(symbol_count / total_count). */
|
||||
memset(insert_cost, 0,
|
||||
sizeof(insert_cost[0]) * alphabet_size * num_histograms);
|
||||
for (i = 0; i < num_histograms; ++i) {
|
||||
insert_cost[i] = FastLog2((uint32_t)histograms[i].total_count_);
|
||||
}
|
||||
for (i = data_size; i != 0;) {
|
||||
for (i = alphabet_size; i != 0;) {
|
||||
/* Reverse order to use the 0-th row as a temporary storage. */
|
||||
--i;
|
||||
for (j = 0; j < num_histograms; ++j) {
|
||||
insert_cost[i * num_histograms + j] =
|
||||
insert_cost[j] - BitCost(histograms[j].data_[i]);
|
||||
}
|
||||
}
|
||||
memset(cost, 0, sizeof(cost[0]) * num_histograms);
|
||||
memset(switch_signal, 0, sizeof(switch_signal[0]) * length * bitmaplen);
|
||||
|
||||
/* After each iteration of this loop, cost[k] will contain the difference
|
||||
between the minimum cost of arriving at the current byte position using
|
||||
entropy code k, and the minimum cost of arriving at the current byte
|
||||
position. This difference is capped at the block switch cost, and if it
|
||||
reaches block switch cost, it means that when we trace back from the last
|
||||
position, we need to switch here. */
|
||||
for (i = 0; i < length; ++i) {
|
||||
const size_t byte_ix = i;
|
||||
size_t ix = byte_ix * bitmaplen;
|
||||
size_t insert_cost_ix = data[byte_ix] * num_histograms;
|
||||
memset(cost, 0, sizeof(cost[0]) * num_histograms);
|
||||
memset(switch_signal, 0, sizeof(switch_signal[0]) * length * bitmap_len);
|
||||
for (byte_ix = 0; byte_ix < length; ++byte_ix) {
|
||||
size_t ix = byte_ix * bitmap_len;
|
||||
size_t symbol = data[byte_ix];
|
||||
size_t insert_cost_ix = symbol * num_histograms;
|
||||
double min_cost = 1e99;
|
||||
double block_switch_cost = block_switch_bitcost;
|
||||
static const size_t prologue_length = 2000;
|
||||
static const double multiplier = 0.07 / 2000;
|
||||
size_t k;
|
||||
for (k = 0; k < num_histograms; ++k) {
|
||||
/* We are coding the symbol in data[byte_ix] with entropy code k. */
|
||||
/* We are coding the symbol with entropy code k. */
|
||||
cost[k] += insert_cost[insert_cost_ix + k];
|
||||
if (cost[k] < min_cost) {
|
||||
min_cost = cost[k];
|
||||
@@ -118,28 +130,29 @@ static size_t FN(FindBlocks)(const DataType* data, const size_t length,
|
||||
}
|
||||
}
|
||||
/* More blocks for the beginning. */
|
||||
if (byte_ix < 2000) {
|
||||
block_switch_cost *= 0.77 + 0.07 * (double)byte_ix / 2000;
|
||||
if (byte_ix < prologue_length) {
|
||||
block_switch_cost *= 0.77 + multiplier * (double)byte_ix;
|
||||
}
|
||||
for (k = 0; k < num_histograms; ++k) {
|
||||
cost[k] -= min_cost;
|
||||
if (cost[k] >= block_switch_cost) {
|
||||
const uint8_t mask = (uint8_t)(1u << (k & 7));
|
||||
cost[k] = block_switch_cost;
|
||||
BROTLI_DCHECK((k >> 3) < bitmaplen);
|
||||
BROTLI_DCHECK((k >> 3) < bitmap_len);
|
||||
switch_signal[ix + (k >> 3)] |= mask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
byte_ix = length - 1;
|
||||
{ /* Trace back from the last position and switch at the marked places. */
|
||||
size_t byte_ix = length - 1;
|
||||
size_t ix = byte_ix * bitmaplen;
|
||||
size_t ix = byte_ix * bitmap_len;
|
||||
uint8_t cur_id = block_id[byte_ix];
|
||||
while (byte_ix > 0) {
|
||||
const uint8_t mask = (uint8_t)(1u << (cur_id & 7));
|
||||
BROTLI_DCHECK(((size_t)cur_id >> 3) < bitmaplen);
|
||||
BROTLI_DCHECK(((size_t)cur_id >> 3) < bitmap_len);
|
||||
--byte_ix;
|
||||
ix -= bitmaplen;
|
||||
ix -= bitmap_len;
|
||||
if (switch_signal[ix + (cur_id >> 3)] & mask) {
|
||||
if (cur_id != block_id[byte_ix]) {
|
||||
cur_id = block_id[byte_ix];
|
||||
@@ -185,13 +198,16 @@ static void FN(BuildBlockHistograms)(const DataType* data, const size_t length,
|
||||
}
|
||||
}
|
||||
|
||||
/* Given the initial partitioning build partitioning with limited number
|
||||
* of histograms (and block types). */
|
||||
static void FN(ClusterBlocks)(MemoryManager* m,
|
||||
const DataType* data, const size_t length,
|
||||
const size_t num_blocks,
|
||||
uint8_t* block_ids,
|
||||
BlockSplit* split) {
|
||||
uint32_t* histogram_symbols = BROTLI_ALLOC(m, uint32_t, num_blocks);
|
||||
uint32_t* block_lengths = BROTLI_ALLOC(m, uint32_t, num_blocks);
|
||||
uint32_t* u32 =
|
||||
BROTLI_ALLOC(m, uint32_t, num_blocks + 4 * HISTOGRAMS_PER_BATCH);
|
||||
const size_t expected_num_clusters = CLUSTERS_PER_BATCH *
|
||||
(num_blocks + HISTOGRAMS_PER_BATCH - 1) / HISTOGRAMS_PER_BATCH;
|
||||
size_t all_histograms_size = 0;
|
||||
@@ -214,15 +230,29 @@ static void FN(ClusterBlocks)(MemoryManager* m,
|
||||
static const uint32_t kInvalidIndex = BROTLI_UINT32_MAX;
|
||||
uint32_t* new_index;
|
||||
size_t i;
|
||||
uint32_t sizes[HISTOGRAMS_PER_BATCH] = { 0 };
|
||||
uint32_t new_clusters[HISTOGRAMS_PER_BATCH] = { 0 };
|
||||
uint32_t symbols[HISTOGRAMS_PER_BATCH] = { 0 };
|
||||
uint32_t remap[HISTOGRAMS_PER_BATCH] = { 0 };
|
||||
uint32_t* BROTLI_RESTRICT const sizes =
|
||||
u32 ? (u32 + 0 * HISTOGRAMS_PER_BATCH) : NULL;
|
||||
uint32_t* BROTLI_RESTRICT const new_clusters =
|
||||
u32 ? (u32 + 1 * HISTOGRAMS_PER_BATCH) : NULL;
|
||||
uint32_t* BROTLI_RESTRICT const symbols =
|
||||
u32 ? (u32 + 2 * HISTOGRAMS_PER_BATCH) : NULL;
|
||||
uint32_t* BROTLI_RESTRICT const remap =
|
||||
u32 ? (u32 + 3 * HISTOGRAMS_PER_BATCH) : NULL;
|
||||
uint32_t* BROTLI_RESTRICT const block_lengths =
|
||||
u32 ? (u32 + 4 * HISTOGRAMS_PER_BATCH) : NULL;
|
||||
/* TODO(eustas): move to arena? */
|
||||
HistogramType* tmp = BROTLI_ALLOC(m, HistogramType, 2);
|
||||
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(histogram_symbols) ||
|
||||
BROTLI_IS_NULL(u32) || BROTLI_IS_NULL(all_histograms) ||
|
||||
BROTLI_IS_NULL(cluster_size) || BROTLI_IS_NULL(histograms) ||
|
||||
BROTLI_IS_NULL(pairs) || BROTLI_IS_NULL(tmp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
memset(block_lengths, 0, num_blocks * sizeof(uint32_t));
|
||||
memset(u32, 0, (num_blocks + 4 * HISTOGRAMS_PER_BATCH) * sizeof(uint32_t));
|
||||
|
||||
/* Calculate block lengths (convert repeating values -> series length). */
|
||||
{
|
||||
size_t block_idx = 0;
|
||||
for (i = 0; i < length; ++i) {
|
||||
@@ -235,6 +265,7 @@ static void FN(ClusterBlocks)(MemoryManager* m,
|
||||
BROTLI_DCHECK(block_idx == num_blocks);
|
||||
}
|
||||
|
||||
/* Pre-cluster blocks (cluster batches). */
|
||||
for (i = 0; i < num_blocks; i += HISTOGRAMS_PER_BATCH) {
|
||||
const size_t num_to_combine =
|
||||
BROTLI_MIN(size_t, num_blocks - i, HISTOGRAMS_PER_BATCH);
|
||||
@@ -242,8 +273,9 @@ static void FN(ClusterBlocks)(MemoryManager* m,
|
||||
size_t j;
|
||||
for (j = 0; j < num_to_combine; ++j) {
|
||||
size_t k;
|
||||
size_t block_length = block_lengths[i + j];
|
||||
FN(HistogramClear)(&histograms[j]);
|
||||
for (k = 0; k < block_lengths[i + j]; ++k) {
|
||||
for (k = 0; k < block_length; ++k) {
|
||||
FN(HistogramAdd)(&histograms[j], data[pos++]);
|
||||
}
|
||||
histograms[j].bit_cost_ = FN(BrotliPopulationCost)(&histograms[j]);
|
||||
@@ -252,7 +284,7 @@ static void FN(ClusterBlocks)(MemoryManager* m,
|
||||
sizes[j] = 1;
|
||||
}
|
||||
num_new_clusters = FN(BrotliHistogramCombine)(
|
||||
histograms, sizes, symbols, new_clusters, pairs, num_to_combine,
|
||||
histograms, tmp, sizes, symbols, new_clusters, pairs, num_to_combine,
|
||||
num_to_combine, HISTOGRAMS_PER_BATCH, max_num_pairs);
|
||||
BROTLI_ENSURE_CAPACITY(m, HistogramType, all_histograms,
|
||||
all_histograms_capacity, all_histograms_size + num_new_clusters);
|
||||
@@ -273,47 +305,49 @@ static void FN(ClusterBlocks)(MemoryManager* m,
|
||||
}
|
||||
BROTLI_FREE(m, histograms);
|
||||
|
||||
/* Final clustering. */
|
||||
max_num_pairs =
|
||||
BROTLI_MIN(size_t, 64 * num_clusters, (num_clusters / 2) * num_clusters);
|
||||
if (pairs_capacity < max_num_pairs + 1) {
|
||||
BROTLI_FREE(m, pairs);
|
||||
pairs = BROTLI_ALLOC(m, HistogramPair, max_num_pairs + 1);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(pairs)) return;
|
||||
}
|
||||
|
||||
clusters = BROTLI_ALLOC(m, uint32_t, num_clusters);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(clusters)) return;
|
||||
for (i = 0; i < num_clusters; ++i) {
|
||||
clusters[i] = (uint32_t)i;
|
||||
}
|
||||
num_final_clusters = FN(BrotliHistogramCombine)(
|
||||
all_histograms, cluster_size, histogram_symbols, clusters, pairs,
|
||||
all_histograms, tmp, cluster_size, histogram_symbols, clusters, pairs,
|
||||
num_clusters, num_blocks, BROTLI_MAX_NUMBER_OF_BLOCK_TYPES,
|
||||
max_num_pairs);
|
||||
BROTLI_FREE(m, pairs);
|
||||
BROTLI_FREE(m, cluster_size);
|
||||
|
||||
/* Assign blocks to final histograms. */
|
||||
new_index = BROTLI_ALLOC(m, uint32_t, num_clusters);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_index)) return;
|
||||
for (i = 0; i < num_clusters; ++i) new_index[i] = kInvalidIndex;
|
||||
pos = 0;
|
||||
{
|
||||
uint32_t next_index = 0;
|
||||
for (i = 0; i < num_blocks; ++i) {
|
||||
HistogramType histo;
|
||||
size_t j;
|
||||
uint32_t best_out;
|
||||
double best_bits;
|
||||
FN(HistogramClear)(&histo);
|
||||
FN(HistogramClear)(tmp);
|
||||
for (j = 0; j < block_lengths[i]; ++j) {
|
||||
FN(HistogramAdd)(&histo, data[pos++]);
|
||||
FN(HistogramAdd)(tmp, data[pos++]);
|
||||
}
|
||||
/* Among equally good histograms prefer last used. */
|
||||
/* TODO(eustas): should we give a block-switch discount here? */
|
||||
best_out = (i == 0) ? histogram_symbols[0] : histogram_symbols[i - 1];
|
||||
best_bits =
|
||||
FN(BrotliHistogramBitCostDistance)(&histo, &all_histograms[best_out]);
|
||||
best_bits = FN(BrotliHistogramBitCostDistance)(
|
||||
tmp, &all_histograms[best_out], tmp + 1);
|
||||
for (j = 0; j < num_final_clusters; ++j) {
|
||||
const double cur_bits = FN(BrotliHistogramBitCostDistance)(
|
||||
&histo, &all_histograms[clusters[j]]);
|
||||
tmp, &all_histograms[clusters[j]], tmp + 1);
|
||||
if (cur_bits < best_bits) {
|
||||
best_bits = cur_bits;
|
||||
best_out = clusters[j];
|
||||
@@ -325,6 +359,7 @@ static void FN(ClusterBlocks)(MemoryManager* m,
|
||||
}
|
||||
}
|
||||
}
|
||||
BROTLI_FREE(m, tmp);
|
||||
BROTLI_FREE(m, clusters);
|
||||
BROTLI_FREE(m, all_histograms);
|
||||
BROTLI_ENSURE_CAPACITY(
|
||||
@@ -332,6 +367,9 @@ static void FN(ClusterBlocks)(MemoryManager* m,
|
||||
BROTLI_ENSURE_CAPACITY(
|
||||
m, uint32_t, split->lengths, split->lengths_alloc_size, num_blocks);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
|
||||
/* Rewrite final assignment to block-split. There might be less blocks
|
||||
* than |num_blocks| due to clustering. */
|
||||
{
|
||||
uint32_t cur_length = 0;
|
||||
size_t block_idx = 0;
|
||||
@@ -352,28 +390,41 @@ static void FN(ClusterBlocks)(MemoryManager* m,
|
||||
split->num_types = (size_t)max_type + 1;
|
||||
}
|
||||
BROTLI_FREE(m, new_index);
|
||||
BROTLI_FREE(m, block_lengths);
|
||||
BROTLI_FREE(m, u32);
|
||||
BROTLI_FREE(m, histogram_symbols);
|
||||
}
|
||||
|
||||
/* Create BlockSplit (partitioning) given the limits, estimates and "effort"
|
||||
* parameters.
|
||||
*
|
||||
* NB: max_histograms is often less than number of histograms allowed by format;
|
||||
* this is done intentionally, to save some "space" for context-aware
|
||||
* clustering (here entropy is estimated for context-free symbols). */
|
||||
static void FN(SplitByteVector)(MemoryManager* m,
|
||||
const DataType* data, const size_t length,
|
||||
const size_t literals_per_histogram,
|
||||
const size_t symbols_per_histogram,
|
||||
const size_t max_histograms,
|
||||
const size_t sampling_stride_length,
|
||||
const double block_switch_cost,
|
||||
const BrotliEncoderParams* params,
|
||||
BlockSplit* split) {
|
||||
const size_t data_size = FN(HistogramDataSize)();
|
||||
size_t num_histograms = length / literals_per_histogram + 1;
|
||||
HistogramType* histograms;
|
||||
HistogramType* tmp;
|
||||
/* Calculate number of histograms; initial estimate is one histogram per
|
||||
* specified amount of symbols; however, this value is capped. */
|
||||
size_t num_histograms = length / symbols_per_histogram + 1;
|
||||
if (num_histograms > max_histograms) {
|
||||
num_histograms = max_histograms;
|
||||
}
|
||||
|
||||
/* Corner case: no input. */
|
||||
if (length == 0) {
|
||||
split->num_types = 1;
|
||||
return;
|
||||
} else if (length < kMinLengthForBlockSplitting) {
|
||||
}
|
||||
|
||||
if (length < kMinLengthForBlockSplitting) {
|
||||
BROTLI_ENSURE_CAPACITY(m, uint8_t,
|
||||
split->types, split->types_alloc_size, split->num_blocks + 1);
|
||||
BROTLI_ENSURE_CAPACITY(m, uint32_t,
|
||||
@@ -385,15 +436,16 @@ static void FN(SplitByteVector)(MemoryManager* m,
|
||||
split->num_blocks++;
|
||||
return;
|
||||
}
|
||||
histograms = BROTLI_ALLOC(m, HistogramType, num_histograms);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
histograms = BROTLI_ALLOC(m, HistogramType, num_histograms + 1);
|
||||
tmp = histograms + num_histograms;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(histograms)) return;
|
||||
/* Find good entropy codes. */
|
||||
FN(InitialEntropyCodes)(data, length,
|
||||
sampling_stride_length,
|
||||
num_histograms, histograms);
|
||||
FN(RefineEntropyCodes)(data, length,
|
||||
sampling_stride_length,
|
||||
num_histograms, histograms);
|
||||
num_histograms, histograms, tmp);
|
||||
{
|
||||
/* Find a good path through literals with the good entropy codes. */
|
||||
uint8_t* block_ids = BROTLI_ALLOC(m, uint8_t, length);
|
||||
@@ -405,7 +457,11 @@ static void FN(SplitByteVector)(MemoryManager* m,
|
||||
uint16_t* new_id = BROTLI_ALLOC(m, uint16_t, num_histograms);
|
||||
const size_t iters = params->quality < HQ_ZOPFLIFICATION_QUALITY ? 3 : 10;
|
||||
size_t i;
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(block_ids) ||
|
||||
BROTLI_IS_NULL(insert_cost) || BROTLI_IS_NULL(cost) ||
|
||||
BROTLI_IS_NULL(switch_signal) || BROTLI_IS_NULL(new_id)) {
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < iters; ++i) {
|
||||
num_blocks = FN(FindBlocks)(data, length,
|
||||
block_switch_cost,
|
||||
|
||||
@@ -8,20 +8,17 @@
|
||||
compression algorithms here, just the right ordering of bits to match the
|
||||
specs. */
|
||||
|
||||
#include "./brotli_bit_stream.h"
|
||||
|
||||
#include <string.h> /* memcpy, memset */
|
||||
#include "brotli_bit_stream.h"
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include "../common/context.h"
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./entropy_encode.h"
|
||||
#include "./entropy_encode_static.h"
|
||||
#include "./fast_log.h"
|
||||
#include "./histogram.h"
|
||||
#include "./memory.h"
|
||||
#include "./write_bits.h"
|
||||
#include "entropy_encode.h"
|
||||
#include "entropy_encode_static.h"
|
||||
#include "fast_log.h"
|
||||
#include "histogram.h"
|
||||
#include "memory.h"
|
||||
#include "write_bits.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
@@ -34,33 +31,18 @@ extern "C" {
|
||||
BROTLI_DISTANCE_ALPHABET_SIZE(0, 0, BROTLI_LARGE_MAX_DISTANCE_BITS)
|
||||
/* MAX_SIMPLE_DISTANCE_ALPHABET_SIZE == 140 */
|
||||
|
||||
/* Represents the range of values belonging to a prefix code:
|
||||
[offset, offset + 2^nbits) */
|
||||
typedef struct PrefixCodeRange {
|
||||
uint32_t offset;
|
||||
uint32_t nbits;
|
||||
} PrefixCodeRange;
|
||||
|
||||
static const PrefixCodeRange
|
||||
kBlockLengthPrefixCode[BROTLI_NUM_BLOCK_LEN_SYMBOLS] = {
|
||||
{ 1, 2}, { 5, 2}, { 9, 2}, {13, 2}, {17, 3}, { 25, 3}, { 33, 3},
|
||||
{41, 3}, {49, 4}, {65, 4}, {81, 4}, {97, 4}, {113, 5}, {145, 5},
|
||||
{177, 5}, { 209, 5}, { 241, 6}, { 305, 6}, { 369, 7}, { 497, 8},
|
||||
{753, 9}, {1265, 10}, {2289, 11}, {4337, 12}, {8433, 13}, {16625, 24}
|
||||
};
|
||||
|
||||
static BROTLI_INLINE uint32_t BlockLengthPrefixCode(uint32_t len) {
|
||||
uint32_t code = (len >= 177) ? (len >= 753 ? 20 : 14) : (len >= 41 ? 7 : 0);
|
||||
while (code < (BROTLI_NUM_BLOCK_LEN_SYMBOLS - 1) &&
|
||||
len >= kBlockLengthPrefixCode[code + 1].offset) ++code;
|
||||
len >= _kBrotliPrefixCodeRanges[code + 1].offset) ++code;
|
||||
return code;
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void GetBlockLengthPrefixCode(uint32_t len, size_t* code,
|
||||
uint32_t* n_extra, uint32_t* extra) {
|
||||
*code = BlockLengthPrefixCode(len);
|
||||
*n_extra = kBlockLengthPrefixCode[*code].nbits;
|
||||
*extra = len - kBlockLengthPrefixCode[*code].offset;
|
||||
*n_extra = _kBrotliPrefixCodeRanges[*code].nbits;
|
||||
*extra = len - _kBrotliPrefixCodeRanges[*code].offset;
|
||||
}
|
||||
|
||||
typedef struct BlockTypeCodeCalculator {
|
||||
@@ -183,7 +165,8 @@ static void BrotliStoreUncompressedMetaBlockHeader(size_t length,
|
||||
static void BrotliStoreHuffmanTreeOfHuffmanTreeToBitMask(
|
||||
const int num_codes, const uint8_t* code_length_bitdepth,
|
||||
size_t* storage_ix, uint8_t* storage) {
|
||||
static const uint8_t kStorageOrder[BROTLI_CODE_LENGTH_CODES] = {
|
||||
static const BROTLI_MODEL("small")
|
||||
uint8_t kStorageOrder[BROTLI_CODE_LENGTH_CODES] = {
|
||||
1, 2, 3, 4, 0, 5, 17, 6, 16, 7, 8, 9, 10, 11, 12, 13, 14, 15
|
||||
};
|
||||
/* The bit lengths of the Huffman code over the code length alphabet
|
||||
@@ -196,10 +179,12 @@ static void BrotliStoreHuffmanTreeOfHuffmanTreeToBitMask(
|
||||
3 01
|
||||
4 10
|
||||
5 1111 */
|
||||
static const uint8_t kHuffmanBitLengthHuffmanCodeSymbols[6] = {
|
||||
static const BROTLI_MODEL("small")
|
||||
uint8_t kHuffmanBitLengthHuffmanCodeSymbols[6] = {
|
||||
0, 7, 3, 2, 1, 15
|
||||
};
|
||||
static const uint8_t kHuffmanBitLengthHuffmanCodeBitLengths[6] = {
|
||||
static const BROTLI_MODEL("small")
|
||||
uint8_t kHuffmanBitLengthHuffmanCodeBitLengths[6] = {
|
||||
2, 4, 3, 2, 2, 4
|
||||
};
|
||||
|
||||
@@ -301,6 +286,7 @@ void BrotliStoreHuffmanTree(const uint8_t* depths, size_t num,
|
||||
/* Write the Huffman tree into the brotli-representation.
|
||||
The command alphabet is the largest, so this allocation will fit all
|
||||
alphabets. */
|
||||
/* TODO(eustas): fix me */
|
||||
uint8_t huffman_tree[BROTLI_NUM_COMMAND_SYMBOLS];
|
||||
uint8_t huffman_tree_extra_bits[BROTLI_NUM_COMMAND_SYMBOLS];
|
||||
size_t huffman_tree_size = 0;
|
||||
@@ -415,7 +401,7 @@ static BROTLI_INLINE BROTLI_BOOL SortHuffmanTree(
|
||||
return TO_BROTLI_BOOL(v0->total_count_ < v1->total_count_);
|
||||
}
|
||||
|
||||
void BrotliBuildAndStoreHuffmanTreeFast(MemoryManager* m,
|
||||
void BrotliBuildAndStoreHuffmanTreeFast(HuffmanTree* tree,
|
||||
const uint32_t* histogram,
|
||||
const size_t histogram_total,
|
||||
const size_t max_bits,
|
||||
@@ -447,10 +433,7 @@ void BrotliBuildAndStoreHuffmanTreeFast(MemoryManager* m,
|
||||
|
||||
memset(depth, 0, length * sizeof(depth[0]));
|
||||
{
|
||||
const size_t max_tree_size = 2 * length + 1;
|
||||
HuffmanTree* tree = BROTLI_ALLOC(m, HuffmanTree, max_tree_size);
|
||||
uint32_t count_limit;
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
for (count_limit = 1; ; count_limit *= 2) {
|
||||
HuffmanTree* node = tree;
|
||||
size_t l;
|
||||
@@ -515,7 +498,6 @@ void BrotliBuildAndStoreHuffmanTreeFast(MemoryManager* m,
|
||||
}
|
||||
}
|
||||
}
|
||||
BROTLI_FREE(m, tree);
|
||||
}
|
||||
BrotliConvertBitDepthsToSymbols(depth, length, bits);
|
||||
if (count <= 4) {
|
||||
@@ -692,7 +674,14 @@ static void RunLengthCodeZeros(const size_t in_size,
|
||||
|
||||
#define SYMBOL_BITS 9
|
||||
|
||||
typedef struct EncodeContextMapArena {
|
||||
uint32_t histogram[BROTLI_MAX_CONTEXT_MAP_SYMBOLS];
|
||||
uint8_t depths[BROTLI_MAX_CONTEXT_MAP_SYMBOLS];
|
||||
uint16_t bits[BROTLI_MAX_CONTEXT_MAP_SYMBOLS];
|
||||
} EncodeContextMapArena;
|
||||
|
||||
static void EncodeContextMap(MemoryManager* m,
|
||||
EncodeContextMapArena* arena,
|
||||
const uint32_t* context_map,
|
||||
size_t context_map_size,
|
||||
size_t num_clusters,
|
||||
@@ -702,10 +691,10 @@ static void EncodeContextMap(MemoryManager* m,
|
||||
uint32_t* rle_symbols;
|
||||
uint32_t max_run_length_prefix = 6;
|
||||
size_t num_rle_symbols = 0;
|
||||
uint32_t histogram[BROTLI_MAX_CONTEXT_MAP_SYMBOLS];
|
||||
uint32_t* BROTLI_RESTRICT const histogram = arena->histogram;
|
||||
static const uint32_t kSymbolMask = (1u << SYMBOL_BITS) - 1u;
|
||||
uint8_t depths[BROTLI_MAX_CONTEXT_MAP_SYMBOLS];
|
||||
uint16_t bits[BROTLI_MAX_CONTEXT_MAP_SYMBOLS];
|
||||
uint8_t* BROTLI_RESTRICT const depths = arena->depths;
|
||||
uint16_t* BROTLI_RESTRICT const bits = arena->bits;
|
||||
|
||||
StoreVarLenUint8(num_clusters - 1, storage_ix, storage);
|
||||
|
||||
@@ -714,11 +703,11 @@ static void EncodeContextMap(MemoryManager* m,
|
||||
}
|
||||
|
||||
rle_symbols = BROTLI_ALLOC(m, uint32_t, context_map_size);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(rle_symbols)) return;
|
||||
MoveToFrontTransform(context_map, context_map_size, rle_symbols);
|
||||
RunLengthCodeZeros(context_map_size, rle_symbols,
|
||||
&num_rle_symbols, &max_run_length_prefix);
|
||||
memset(histogram, 0, sizeof(histogram));
|
||||
memset(histogram, 0, sizeof(arena->histogram));
|
||||
for (i = 0; i < num_rle_symbols; ++i) {
|
||||
++histogram[rle_symbols[i] & kSymbolMask];
|
||||
}
|
||||
@@ -789,7 +778,7 @@ static void BuildAndStoreBlockSplitCode(const uint8_t* types,
|
||||
++length_histo[BlockLengthPrefixCode(lengths[i])];
|
||||
}
|
||||
StoreVarLenUint8(num_types - 1, storage_ix, storage);
|
||||
if (num_types > 1) { /* TODO: else? could StoreBlockSwitch occur? */
|
||||
if (num_types > 1) { /* TODO(eustas): else? could StoreBlockSwitch occur? */
|
||||
BuildAndStoreHuffmanTree(&type_histo[0], num_types + 2, num_types + 2, tree,
|
||||
&code->type_depths[0], &code->type_bits[0],
|
||||
storage_ix, storage);
|
||||
@@ -802,7 +791,8 @@ static void BuildAndStoreBlockSplitCode(const uint8_t* types,
|
||||
}
|
||||
|
||||
/* Stores a context map where the histogram type is always the block type. */
|
||||
static void StoreTrivialContextMap(size_t num_types,
|
||||
static void StoreTrivialContextMap(EncodeContextMapArena* arena,
|
||||
size_t num_types,
|
||||
size_t context_bits,
|
||||
HuffmanTree* tree,
|
||||
size_t* storage_ix,
|
||||
@@ -812,9 +802,9 @@ static void StoreTrivialContextMap(size_t num_types,
|
||||
size_t repeat_code = context_bits - 1u;
|
||||
size_t repeat_bits = (1u << repeat_code) - 1u;
|
||||
size_t alphabet_size = num_types + repeat_code;
|
||||
uint32_t histogram[BROTLI_MAX_CONTEXT_MAP_SYMBOLS];
|
||||
uint8_t depths[BROTLI_MAX_CONTEXT_MAP_SYMBOLS];
|
||||
uint16_t bits[BROTLI_MAX_CONTEXT_MAP_SYMBOLS];
|
||||
uint32_t* BROTLI_RESTRICT const histogram = arena->histogram;
|
||||
uint8_t* BROTLI_RESTRICT const depths = arena->depths;
|
||||
uint16_t* BROTLI_RESTRICT const bits = arena->bits;
|
||||
size_t i;
|
||||
memset(histogram, 0, alphabet_size * sizeof(histogram[0]));
|
||||
/* Write RLEMAX. */
|
||||
@@ -929,17 +919,17 @@ static void StoreSymbolWithContext(BlockEncoder* self, size_t symbol,
|
||||
|
||||
#define FN(X) X ## Literal
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "./block_encoder_inc.h"
|
||||
#include "block_encoder_inc.h"
|
||||
#undef FN
|
||||
|
||||
#define FN(X) X ## Command
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "./block_encoder_inc.h"
|
||||
#include "block_encoder_inc.h"
|
||||
#undef FN
|
||||
|
||||
#define FN(X) X ## Distance
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "./block_encoder_inc.h"
|
||||
#include "block_encoder_inc.h"
|
||||
#undef FN
|
||||
|
||||
static void JumpToByteBoundary(size_t* storage_ix, uint8_t* storage) {
|
||||
@@ -947,6 +937,13 @@ static void JumpToByteBoundary(size_t* storage_ix, uint8_t* storage) {
|
||||
storage[*storage_ix >> 3] = 0;
|
||||
}
|
||||
|
||||
typedef struct StoreMetablockArena {
|
||||
BlockEncoder literal_enc;
|
||||
BlockEncoder command_enc;
|
||||
BlockEncoder distance_enc;
|
||||
EncodeContextMapArena context_map_arena;
|
||||
} StoreMetablockArena;
|
||||
|
||||
void BrotliStoreMetaBlock(MemoryManager* m,
|
||||
const uint8_t* input, size_t start_pos, size_t length, size_t mask,
|
||||
uint8_t prev_byte, uint8_t prev_byte2, BROTLI_BOOL is_last,
|
||||
@@ -956,37 +953,39 @@ void BrotliStoreMetaBlock(MemoryManager* m,
|
||||
|
||||
size_t pos = start_pos;
|
||||
size_t i;
|
||||
uint32_t num_distance_symbols = params->dist.alphabet_size;
|
||||
uint32_t num_effective_distance_symbols = num_distance_symbols;
|
||||
uint32_t num_distance_symbols = params->dist.alphabet_size_max;
|
||||
uint32_t num_effective_distance_symbols = params->dist.alphabet_size_limit;
|
||||
HuffmanTree* tree;
|
||||
ContextLut literal_context_lut = BROTLI_CONTEXT_LUT(literal_context_mode);
|
||||
BlockEncoder literal_enc;
|
||||
BlockEncoder command_enc;
|
||||
BlockEncoder distance_enc;
|
||||
StoreMetablockArena* arena = NULL;
|
||||
BlockEncoder* literal_enc = NULL;
|
||||
BlockEncoder* command_enc = NULL;
|
||||
BlockEncoder* distance_enc = NULL;
|
||||
const BrotliDistanceParams* dist = ¶ms->dist;
|
||||
if (params->large_window &&
|
||||
num_effective_distance_symbols > BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS) {
|
||||
num_effective_distance_symbols = BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS;
|
||||
}
|
||||
BROTLI_DCHECK(
|
||||
num_effective_distance_symbols <= BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS);
|
||||
|
||||
StoreCompressedMetaBlockHeader(is_last, length, storage_ix, storage);
|
||||
|
||||
tree = BROTLI_ALLOC(m, HuffmanTree, MAX_HUFFMAN_TREE_SIZE);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
InitBlockEncoder(&literal_enc, BROTLI_NUM_LITERAL_SYMBOLS,
|
||||
arena = BROTLI_ALLOC(m, StoreMetablockArena, 1);
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(tree) || BROTLI_IS_NULL(arena)) return;
|
||||
literal_enc = &arena->literal_enc;
|
||||
command_enc = &arena->command_enc;
|
||||
distance_enc = &arena->distance_enc;
|
||||
InitBlockEncoder(literal_enc, BROTLI_NUM_LITERAL_SYMBOLS,
|
||||
mb->literal_split.num_types, mb->literal_split.types,
|
||||
mb->literal_split.lengths, mb->literal_split.num_blocks);
|
||||
InitBlockEncoder(&command_enc, BROTLI_NUM_COMMAND_SYMBOLS,
|
||||
InitBlockEncoder(command_enc, BROTLI_NUM_COMMAND_SYMBOLS,
|
||||
mb->command_split.num_types, mb->command_split.types,
|
||||
mb->command_split.lengths, mb->command_split.num_blocks);
|
||||
InitBlockEncoder(&distance_enc, num_effective_distance_symbols,
|
||||
InitBlockEncoder(distance_enc, num_effective_distance_symbols,
|
||||
mb->distance_split.num_types, mb->distance_split.types,
|
||||
mb->distance_split.lengths, mb->distance_split.num_blocks);
|
||||
|
||||
BuildAndStoreBlockSwitchEntropyCodes(&literal_enc, tree, storage_ix, storage);
|
||||
BuildAndStoreBlockSwitchEntropyCodes(&command_enc, tree, storage_ix, storage);
|
||||
BuildAndStoreBlockSwitchEntropyCodes(
|
||||
&distance_enc, tree, storage_ix, storage);
|
||||
BuildAndStoreBlockSwitchEntropyCodes(literal_enc, tree, storage_ix, storage);
|
||||
BuildAndStoreBlockSwitchEntropyCodes(command_enc, tree, storage_ix, storage);
|
||||
BuildAndStoreBlockSwitchEntropyCodes(distance_enc, tree, storage_ix, storage);
|
||||
|
||||
BrotliWriteBits(2, dist->distance_postfix_bits, storage_ix, storage);
|
||||
BrotliWriteBits(
|
||||
@@ -997,34 +996,36 @@ void BrotliStoreMetaBlock(MemoryManager* m,
|
||||
}
|
||||
|
||||
if (mb->literal_context_map_size == 0) {
|
||||
StoreTrivialContextMap(mb->literal_histograms_size,
|
||||
StoreTrivialContextMap(
|
||||
&arena->context_map_arena, mb->literal_histograms_size,
|
||||
BROTLI_LITERAL_CONTEXT_BITS, tree, storage_ix, storage);
|
||||
} else {
|
||||
EncodeContextMap(m,
|
||||
EncodeContextMap(m, &arena->context_map_arena,
|
||||
mb->literal_context_map, mb->literal_context_map_size,
|
||||
mb->literal_histograms_size, tree, storage_ix, storage);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
}
|
||||
|
||||
if (mb->distance_context_map_size == 0) {
|
||||
StoreTrivialContextMap(mb->distance_histograms_size,
|
||||
StoreTrivialContextMap(
|
||||
&arena->context_map_arena, mb->distance_histograms_size,
|
||||
BROTLI_DISTANCE_CONTEXT_BITS, tree, storage_ix, storage);
|
||||
} else {
|
||||
EncodeContextMap(m,
|
||||
EncodeContextMap(m, &arena->context_map_arena,
|
||||
mb->distance_context_map, mb->distance_context_map_size,
|
||||
mb->distance_histograms_size, tree, storage_ix, storage);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
}
|
||||
|
||||
BuildAndStoreEntropyCodesLiteral(m, &literal_enc, mb->literal_histograms,
|
||||
BuildAndStoreEntropyCodesLiteral(m, literal_enc, mb->literal_histograms,
|
||||
mb->literal_histograms_size, BROTLI_NUM_LITERAL_SYMBOLS, tree,
|
||||
storage_ix, storage);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
BuildAndStoreEntropyCodesCommand(m, &command_enc, mb->command_histograms,
|
||||
BuildAndStoreEntropyCodesCommand(m, command_enc, mb->command_histograms,
|
||||
mb->command_histograms_size, BROTLI_NUM_COMMAND_SYMBOLS, tree,
|
||||
storage_ix, storage);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
BuildAndStoreEntropyCodesDistance(m, &distance_enc, mb->distance_histograms,
|
||||
BuildAndStoreEntropyCodesDistance(m, distance_enc, mb->distance_histograms,
|
||||
mb->distance_histograms_size, num_distance_symbols, tree,
|
||||
storage_ix, storage);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
@@ -1033,12 +1034,12 @@ void BrotliStoreMetaBlock(MemoryManager* m,
|
||||
for (i = 0; i < n_commands; ++i) {
|
||||
const Command cmd = commands[i];
|
||||
size_t cmd_code = cmd.cmd_prefix_;
|
||||
StoreSymbol(&command_enc, cmd_code, storage_ix, storage);
|
||||
StoreSymbol(command_enc, cmd_code, storage_ix, storage);
|
||||
StoreCommandExtra(&cmd, storage_ix, storage);
|
||||
if (mb->literal_context_map_size == 0) {
|
||||
size_t j;
|
||||
for (j = cmd.insert_len_; j != 0; --j) {
|
||||
StoreSymbol(&literal_enc, input[pos & mask], storage_ix, storage);
|
||||
StoreSymbol(literal_enc, input[pos & mask], storage_ix, storage);
|
||||
++pos;
|
||||
}
|
||||
} else {
|
||||
@@ -1047,7 +1048,7 @@ void BrotliStoreMetaBlock(MemoryManager* m,
|
||||
size_t context =
|
||||
BROTLI_CONTEXT(prev_byte, prev_byte2, literal_context_lut);
|
||||
uint8_t literal = input[pos & mask];
|
||||
StoreSymbolWithContext(&literal_enc, literal, context,
|
||||
StoreSymbolWithContext(literal_enc, literal, context,
|
||||
mb->literal_context_map, storage_ix, storage,
|
||||
BROTLI_LITERAL_CONTEXT_BITS);
|
||||
prev_byte2 = prev_byte;
|
||||
@@ -1064,10 +1065,10 @@ void BrotliStoreMetaBlock(MemoryManager* m,
|
||||
uint32_t distnumextra = cmd.dist_prefix_ >> 10;
|
||||
uint64_t distextra = cmd.dist_extra_;
|
||||
if (mb->distance_context_map_size == 0) {
|
||||
StoreSymbol(&distance_enc, dist_code, storage_ix, storage);
|
||||
StoreSymbol(distance_enc, dist_code, storage_ix, storage);
|
||||
} else {
|
||||
size_t context = CommandDistanceContext(&cmd);
|
||||
StoreSymbolWithContext(&distance_enc, dist_code, context,
|
||||
StoreSymbolWithContext(distance_enc, dist_code, context,
|
||||
mb->distance_context_map, storage_ix, storage,
|
||||
BROTLI_DISTANCE_CONTEXT_BITS);
|
||||
}
|
||||
@@ -1075,9 +1076,10 @@ void BrotliStoreMetaBlock(MemoryManager* m,
|
||||
}
|
||||
}
|
||||
}
|
||||
CleanupBlockEncoder(m, &distance_enc);
|
||||
CleanupBlockEncoder(m, &command_enc);
|
||||
CleanupBlockEncoder(m, &literal_enc);
|
||||
CleanupBlockEncoder(m, distance_enc);
|
||||
CleanupBlockEncoder(m, command_enc);
|
||||
CleanupBlockEncoder(m, literal_enc);
|
||||
BROTLI_FREE(m, arena);
|
||||
if (is_last) {
|
||||
JumpToByteBoundary(storage_ix, storage);
|
||||
}
|
||||
@@ -1148,54 +1150,60 @@ static void StoreDataWithHuffmanCodes(const uint8_t* input,
|
||||
}
|
||||
}
|
||||
|
||||
void BrotliStoreMetaBlockTrivial(MemoryManager* m,
|
||||
const uint8_t* input, size_t start_pos, size_t length, size_t mask,
|
||||
BROTLI_BOOL is_last, const BrotliEncoderParams* params,
|
||||
const Command* commands, size_t n_commands,
|
||||
size_t* storage_ix, uint8_t* storage) {
|
||||
/* TODO(eustas): pull alloc/dealloc to caller? */
|
||||
typedef struct MetablockArena {
|
||||
HistogramLiteral lit_histo;
|
||||
HistogramCommand cmd_histo;
|
||||
HistogramDistance dist_histo;
|
||||
/* TODO(eustas): merge bits and depth? */
|
||||
uint8_t lit_depth[BROTLI_NUM_LITERAL_SYMBOLS];
|
||||
uint16_t lit_bits[BROTLI_NUM_LITERAL_SYMBOLS];
|
||||
uint8_t cmd_depth[BROTLI_NUM_COMMAND_SYMBOLS];
|
||||
uint16_t cmd_bits[BROTLI_NUM_COMMAND_SYMBOLS];
|
||||
uint8_t dist_depth[MAX_SIMPLE_DISTANCE_ALPHABET_SIZE];
|
||||
uint16_t dist_bits[MAX_SIMPLE_DISTANCE_ALPHABET_SIZE];
|
||||
HuffmanTree* tree;
|
||||
uint32_t num_distance_symbols = params->dist.alphabet_size;
|
||||
HuffmanTree tree[MAX_HUFFMAN_TREE_SIZE];
|
||||
} MetablockArena;
|
||||
|
||||
void BrotliStoreMetaBlockTrivial(MemoryManager* m,
|
||||
const uint8_t* input, size_t start_pos, size_t length, size_t mask,
|
||||
BROTLI_BOOL is_last, const BrotliEncoderParams* params,
|
||||
const Command* commands, size_t n_commands,
|
||||
size_t* storage_ix, uint8_t* storage) {
|
||||
MetablockArena* arena = BROTLI_ALLOC(m, MetablockArena, 1);
|
||||
uint32_t num_distance_symbols = params->dist.alphabet_size_max;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(arena)) return;
|
||||
|
||||
StoreCompressedMetaBlockHeader(is_last, length, storage_ix, storage);
|
||||
|
||||
HistogramClearLiteral(&lit_histo);
|
||||
HistogramClearCommand(&cmd_histo);
|
||||
HistogramClearDistance(&dist_histo);
|
||||
HistogramClearLiteral(&arena->lit_histo);
|
||||
HistogramClearCommand(&arena->cmd_histo);
|
||||
HistogramClearDistance(&arena->dist_histo);
|
||||
|
||||
BuildHistograms(input, start_pos, mask, commands, n_commands,
|
||||
&lit_histo, &cmd_histo, &dist_histo);
|
||||
&arena->lit_histo, &arena->cmd_histo, &arena->dist_histo);
|
||||
|
||||
BrotliWriteBits(13, 0, storage_ix, storage);
|
||||
|
||||
tree = BROTLI_ALLOC(m, HuffmanTree, MAX_HUFFMAN_TREE_SIZE);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
BuildAndStoreHuffmanTree(lit_histo.data_, BROTLI_NUM_LITERAL_SYMBOLS,
|
||||
BROTLI_NUM_LITERAL_SYMBOLS, tree,
|
||||
lit_depth, lit_bits,
|
||||
BuildAndStoreHuffmanTree(arena->lit_histo.data_, BROTLI_NUM_LITERAL_SYMBOLS,
|
||||
BROTLI_NUM_LITERAL_SYMBOLS, arena->tree,
|
||||
arena->lit_depth, arena->lit_bits,
|
||||
storage_ix, storage);
|
||||
BuildAndStoreHuffmanTree(cmd_histo.data_, BROTLI_NUM_COMMAND_SYMBOLS,
|
||||
BROTLI_NUM_COMMAND_SYMBOLS, tree,
|
||||
cmd_depth, cmd_bits,
|
||||
BuildAndStoreHuffmanTree(arena->cmd_histo.data_, BROTLI_NUM_COMMAND_SYMBOLS,
|
||||
BROTLI_NUM_COMMAND_SYMBOLS, arena->tree,
|
||||
arena->cmd_depth, arena->cmd_bits,
|
||||
storage_ix, storage);
|
||||
BuildAndStoreHuffmanTree(dist_histo.data_, MAX_SIMPLE_DISTANCE_ALPHABET_SIZE,
|
||||
num_distance_symbols, tree,
|
||||
dist_depth, dist_bits,
|
||||
BuildAndStoreHuffmanTree(arena->dist_histo.data_,
|
||||
MAX_SIMPLE_DISTANCE_ALPHABET_SIZE,
|
||||
num_distance_symbols, arena->tree,
|
||||
arena->dist_depth, arena->dist_bits,
|
||||
storage_ix, storage);
|
||||
BROTLI_FREE(m, tree);
|
||||
StoreDataWithHuffmanCodes(input, start_pos, mask, commands,
|
||||
n_commands, lit_depth, lit_bits,
|
||||
cmd_depth, cmd_bits,
|
||||
dist_depth, dist_bits,
|
||||
n_commands, arena->lit_depth, arena->lit_bits,
|
||||
arena->cmd_depth, arena->cmd_bits,
|
||||
arena->dist_depth, arena->dist_bits,
|
||||
storage_ix, storage);
|
||||
BROTLI_FREE(m, arena);
|
||||
if (is_last) {
|
||||
JumpToByteBoundary(storage_ix, storage);
|
||||
}
|
||||
@@ -1206,9 +1214,11 @@ void BrotliStoreMetaBlockFast(MemoryManager* m,
|
||||
BROTLI_BOOL is_last, const BrotliEncoderParams* params,
|
||||
const Command* commands, size_t n_commands,
|
||||
size_t* storage_ix, uint8_t* storage) {
|
||||
uint32_t num_distance_symbols = params->dist.alphabet_size;
|
||||
MetablockArena* arena = BROTLI_ALLOC(m, MetablockArena, 1);
|
||||
uint32_t num_distance_symbols = params->dist.alphabet_size_max;
|
||||
uint32_t distance_alphabet_bits =
|
||||
Log2FloorNonZero(num_distance_symbols - 1) + 1;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(arena)) return;
|
||||
|
||||
StoreCompressedMetaBlockHeader(is_last, length, storage_ix, storage);
|
||||
|
||||
@@ -1219,8 +1229,6 @@ void BrotliStoreMetaBlockFast(MemoryManager* m,
|
||||
size_t pos = start_pos;
|
||||
size_t num_literals = 0;
|
||||
size_t i;
|
||||
uint8_t lit_depth[BROTLI_NUM_LITERAL_SYMBOLS];
|
||||
uint16_t lit_bits[BROTLI_NUM_LITERAL_SYMBOLS];
|
||||
for (i = 0; i < n_commands; ++i) {
|
||||
const Command cmd = commands[i];
|
||||
size_t j;
|
||||
@@ -1231,61 +1239,50 @@ void BrotliStoreMetaBlockFast(MemoryManager* m,
|
||||
num_literals += cmd.insert_len_;
|
||||
pos += CommandCopyLen(&cmd);
|
||||
}
|
||||
BrotliBuildAndStoreHuffmanTreeFast(m, histogram, num_literals,
|
||||
BrotliBuildAndStoreHuffmanTreeFast(arena->tree, histogram, num_literals,
|
||||
/* max_bits = */ 8,
|
||||
lit_depth, lit_bits,
|
||||
arena->lit_depth, arena->lit_bits,
|
||||
storage_ix, storage);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
StoreStaticCommandHuffmanTree(storage_ix, storage);
|
||||
StoreStaticDistanceHuffmanTree(storage_ix, storage);
|
||||
StoreDataWithHuffmanCodes(input, start_pos, mask, commands,
|
||||
n_commands, lit_depth, lit_bits,
|
||||
n_commands, arena->lit_depth, arena->lit_bits,
|
||||
kStaticCommandCodeDepth,
|
||||
kStaticCommandCodeBits,
|
||||
kStaticDistanceCodeDepth,
|
||||
kStaticDistanceCodeBits,
|
||||
storage_ix, storage);
|
||||
} else {
|
||||
HistogramLiteral lit_histo;
|
||||
HistogramCommand cmd_histo;
|
||||
HistogramDistance dist_histo;
|
||||
uint8_t lit_depth[BROTLI_NUM_LITERAL_SYMBOLS];
|
||||
uint16_t lit_bits[BROTLI_NUM_LITERAL_SYMBOLS];
|
||||
uint8_t cmd_depth[BROTLI_NUM_COMMAND_SYMBOLS];
|
||||
uint16_t cmd_bits[BROTLI_NUM_COMMAND_SYMBOLS];
|
||||
uint8_t dist_depth[MAX_SIMPLE_DISTANCE_ALPHABET_SIZE];
|
||||
uint16_t dist_bits[MAX_SIMPLE_DISTANCE_ALPHABET_SIZE];
|
||||
HistogramClearLiteral(&lit_histo);
|
||||
HistogramClearCommand(&cmd_histo);
|
||||
HistogramClearDistance(&dist_histo);
|
||||
HistogramClearLiteral(&arena->lit_histo);
|
||||
HistogramClearCommand(&arena->cmd_histo);
|
||||
HistogramClearDistance(&arena->dist_histo);
|
||||
BuildHistograms(input, start_pos, mask, commands, n_commands,
|
||||
&lit_histo, &cmd_histo, &dist_histo);
|
||||
BrotliBuildAndStoreHuffmanTreeFast(m, lit_histo.data_,
|
||||
lit_histo.total_count_,
|
||||
&arena->lit_histo, &arena->cmd_histo, &arena->dist_histo);
|
||||
BrotliBuildAndStoreHuffmanTreeFast(arena->tree, arena->lit_histo.data_,
|
||||
arena->lit_histo.total_count_,
|
||||
/* max_bits = */ 8,
|
||||
lit_depth, lit_bits,
|
||||
arena->lit_depth, arena->lit_bits,
|
||||
storage_ix, storage);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
BrotliBuildAndStoreHuffmanTreeFast(m, cmd_histo.data_,
|
||||
cmd_histo.total_count_,
|
||||
BrotliBuildAndStoreHuffmanTreeFast(arena->tree, arena->cmd_histo.data_,
|
||||
arena->cmd_histo.total_count_,
|
||||
/* max_bits = */ 10,
|
||||
cmd_depth, cmd_bits,
|
||||
arena->cmd_depth, arena->cmd_bits,
|
||||
storage_ix, storage);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
BrotliBuildAndStoreHuffmanTreeFast(m, dist_histo.data_,
|
||||
dist_histo.total_count_,
|
||||
BrotliBuildAndStoreHuffmanTreeFast(arena->tree, arena->dist_histo.data_,
|
||||
arena->dist_histo.total_count_,
|
||||
/* max_bits = */
|
||||
distance_alphabet_bits,
|
||||
dist_depth, dist_bits,
|
||||
arena->dist_depth, arena->dist_bits,
|
||||
storage_ix, storage);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
StoreDataWithHuffmanCodes(input, start_pos, mask, commands,
|
||||
n_commands, lit_depth, lit_bits,
|
||||
cmd_depth, cmd_bits,
|
||||
dist_depth, dist_bits,
|
||||
n_commands, arena->lit_depth, arena->lit_bits,
|
||||
arena->cmd_depth, arena->cmd_bits,
|
||||
arena->dist_depth, arena->dist_bits,
|
||||
storage_ix, storage);
|
||||
}
|
||||
|
||||
BROTLI_FREE(m, arena);
|
||||
|
||||
if (is_last) {
|
||||
JumpToByteBoundary(storage_ix, storage);
|
||||
}
|
||||
@@ -1326,6 +1323,15 @@ void BrotliStoreUncompressedMetaBlock(BROTLI_BOOL is_final_block,
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(BROTLI_TEST)
|
||||
void BrotliGetBlockLengthPrefixCodeForTest(uint32_t len, size_t* code,
|
||||
uint32_t* n_extra, uint32_t* extra);
|
||||
void BrotliGetBlockLengthPrefixCodeForTest(uint32_t len, size_t* code,
|
||||
uint32_t* n_extra, uint32_t* extra) {
|
||||
GetBlockLengthPrefixCode(len, code, n_extra, extra);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
@@ -18,11 +18,10 @@
|
||||
|
||||
#include "../common/context.h"
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./command.h"
|
||||
#include "./entropy_encode.h"
|
||||
#include "./memory.h"
|
||||
#include "./metablock.h"
|
||||
#include "command.h"
|
||||
#include "entropy_encode.h"
|
||||
#include "memory.h"
|
||||
#include "metablock.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
@@ -35,7 +34,7 @@ BROTLI_INTERNAL void BrotliStoreHuffmanTree(const uint8_t* depths, size_t num,
|
||||
HuffmanTree* tree, size_t* storage_ix, uint8_t* storage);
|
||||
|
||||
BROTLI_INTERNAL void BrotliBuildAndStoreHuffmanTreeFast(
|
||||
MemoryManager* m, const uint32_t* histogram, const size_t histogram_total,
|
||||
HuffmanTree* tree, const uint32_t* histogram, const size_t histogram_total,
|
||||
const size_t max_bits, uint8_t* depth, uint16_t* bits, size_t* storage_ix,
|
||||
uint8_t* storage);
|
||||
|
||||
|
||||
@@ -6,14 +6,13 @@
|
||||
|
||||
/* Functions for clustering similar histograms together. */
|
||||
|
||||
#include "./cluster.h"
|
||||
#include "cluster.h"
|
||||
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./bit_cost.h" /* BrotliPopulationCost */
|
||||
#include "./fast_log.h"
|
||||
#include "./histogram.h"
|
||||
#include "./memory.h"
|
||||
#include "bit_cost.h" /* BrotliPopulationCost */
|
||||
#include "fast_log.h"
|
||||
#include "histogram.h"
|
||||
#include "memory.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
@@ -38,15 +37,15 @@ static BROTLI_INLINE double ClusterCostDiff(size_t size_a, size_t size_b) {
|
||||
#define CODE(X) X
|
||||
|
||||
#define FN(X) X ## Literal
|
||||
#include "./cluster_inc.h" /* NOLINT(build/include) */
|
||||
#include "cluster_inc.h" /* NOLINT(build/include) */
|
||||
#undef FN
|
||||
|
||||
#define FN(X) X ## Command
|
||||
#include "./cluster_inc.h" /* NOLINT(build/include) */
|
||||
#include "cluster_inc.h" /* NOLINT(build/include) */
|
||||
#undef FN
|
||||
|
||||
#define FN(X) X ## Distance
|
||||
#include "./cluster_inc.h" /* NOLINT(build/include) */
|
||||
#include "cluster_inc.h" /* NOLINT(build/include) */
|
||||
#undef FN
|
||||
|
||||
#undef CODE
|
||||
|
||||
@@ -10,9 +10,8 @@
|
||||
#define BROTLI_ENC_CLUSTER_H_
|
||||
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./histogram.h"
|
||||
#include "./memory.h"
|
||||
#include "histogram.h"
|
||||
#include "memory.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
@@ -28,15 +27,15 @@ typedef struct HistogramPair {
|
||||
#define CODE(X) /* Declaration */;
|
||||
|
||||
#define FN(X) X ## Literal
|
||||
#include "./cluster_inc.h" /* NOLINT(build/include) */
|
||||
#include "cluster_inc.h" /* NOLINT(build/include) */
|
||||
#undef FN
|
||||
|
||||
#define FN(X) X ## Command
|
||||
#include "./cluster_inc.h" /* NOLINT(build/include) */
|
||||
#include "cluster_inc.h" /* NOLINT(build/include) */
|
||||
#undef FN
|
||||
|
||||
#define FN(X) X ## Distance
|
||||
#include "./cluster_inc.h" /* NOLINT(build/include) */
|
||||
#include "cluster_inc.h" /* NOLINT(build/include) */
|
||||
#undef FN
|
||||
|
||||
#undef CODE
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
/* Computes the bit cost reduction by combining out[idx1] and out[idx2] and if
|
||||
it is below a threshold, stores the pair (idx1, idx2) in the *pairs queue. */
|
||||
BROTLI_INTERNAL void FN(BrotliCompareAndPushToQueue)(
|
||||
const HistogramType* out, const uint32_t* cluster_size, uint32_t idx1,
|
||||
uint32_t idx2, size_t max_num_pairs, HistogramPair* pairs,
|
||||
const HistogramType* out, HistogramType* tmp, const uint32_t* cluster_size,
|
||||
uint32_t idx1, uint32_t idx2, size_t max_num_pairs, HistogramPair* pairs,
|
||||
size_t* num_pairs) CODE({
|
||||
BROTLI_BOOL is_good_pair = BROTLI_FALSE;
|
||||
HistogramPair p;
|
||||
@@ -42,10 +42,10 @@ BROTLI_INTERNAL void FN(BrotliCompareAndPushToQueue)(
|
||||
} else {
|
||||
double threshold = *num_pairs == 0 ? 1e99 :
|
||||
BROTLI_MAX(double, 0.0, pairs[0].cost_diff);
|
||||
HistogramType combo = out[idx1];
|
||||
double cost_combo;
|
||||
FN(HistogramAddHistogram)(&combo, &out[idx2]);
|
||||
cost_combo = FN(BrotliPopulationCost)(&combo);
|
||||
*tmp = out[idx1];
|
||||
FN(HistogramAddHistogram)(tmp, &out[idx2]);
|
||||
cost_combo = FN(BrotliPopulationCost)(tmp);
|
||||
if (cost_combo < threshold - p.cost_diff) {
|
||||
p.cost_combo = cost_combo;
|
||||
is_good_pair = BROTLI_TRUE;
|
||||
@@ -68,6 +68,7 @@ BROTLI_INTERNAL void FN(BrotliCompareAndPushToQueue)(
|
||||
})
|
||||
|
||||
BROTLI_INTERNAL size_t FN(BrotliHistogramCombine)(HistogramType* out,
|
||||
HistogramType* tmp,
|
||||
uint32_t* cluster_size,
|
||||
uint32_t* symbols,
|
||||
uint32_t* clusters,
|
||||
@@ -87,7 +88,7 @@ BROTLI_INTERNAL size_t FN(BrotliHistogramCombine)(HistogramType* out,
|
||||
for (idx1 = 0; idx1 < num_clusters; ++idx1) {
|
||||
size_t idx2;
|
||||
for (idx2 = idx1 + 1; idx2 < num_clusters; ++idx2) {
|
||||
FN(BrotliCompareAndPushToQueue)(out, cluster_size, clusters[idx1],
|
||||
FN(BrotliCompareAndPushToQueue)(out, tmp, cluster_size, clusters[idx1],
|
||||
clusters[idx2], max_num_pairs, &pairs[0], &num_pairs);
|
||||
}
|
||||
}
|
||||
@@ -146,8 +147,8 @@ BROTLI_INTERNAL size_t FN(BrotliHistogramCombine)(HistogramType* out,
|
||||
|
||||
/* Push new pairs formed with the combined histogram to the heap. */
|
||||
for (i = 0; i < num_clusters; ++i) {
|
||||
FN(BrotliCompareAndPushToQueue)(out, cluster_size, best_idx1, clusters[i],
|
||||
max_num_pairs, &pairs[0], &num_pairs);
|
||||
FN(BrotliCompareAndPushToQueue)(out, tmp, cluster_size, best_idx1,
|
||||
clusters[i], max_num_pairs, &pairs[0], &num_pairs);
|
||||
}
|
||||
}
|
||||
return num_clusters;
|
||||
@@ -155,13 +156,14 @@ BROTLI_INTERNAL size_t FN(BrotliHistogramCombine)(HistogramType* out,
|
||||
|
||||
/* What is the bit cost of moving histogram from cur_symbol to candidate. */
|
||||
BROTLI_INTERNAL double FN(BrotliHistogramBitCostDistance)(
|
||||
const HistogramType* histogram, const HistogramType* candidate) CODE({
|
||||
const HistogramType* histogram, const HistogramType* candidate,
|
||||
HistogramType* tmp) CODE({
|
||||
if (histogram->total_count_ == 0) {
|
||||
return 0.0;
|
||||
} else {
|
||||
HistogramType tmp = *histogram;
|
||||
FN(HistogramAddHistogram)(&tmp, candidate);
|
||||
return FN(BrotliPopulationCost)(&tmp) - candidate->bit_cost_;
|
||||
*tmp = *histogram;
|
||||
FN(HistogramAddHistogram)(tmp, candidate);
|
||||
return FN(BrotliPopulationCost)(tmp) - candidate->bit_cost_;
|
||||
}
|
||||
})
|
||||
|
||||
@@ -171,16 +173,16 @@ BROTLI_INTERNAL double FN(BrotliHistogramBitCostDistance)(
|
||||
Note: we assume that out[]->bit_cost_ is already up-to-date. */
|
||||
BROTLI_INTERNAL void FN(BrotliHistogramRemap)(const HistogramType* in,
|
||||
size_t in_size, const uint32_t* clusters, size_t num_clusters,
|
||||
HistogramType* out, uint32_t* symbols) CODE({
|
||||
HistogramType* out, HistogramType* tmp, uint32_t* symbols) CODE({
|
||||
size_t i;
|
||||
for (i = 0; i < in_size; ++i) {
|
||||
uint32_t best_out = i == 0 ? symbols[0] : symbols[i - 1];
|
||||
double best_bits =
|
||||
FN(BrotliHistogramBitCostDistance)(&in[i], &out[best_out]);
|
||||
FN(BrotliHistogramBitCostDistance)(&in[i], &out[best_out], tmp);
|
||||
size_t j;
|
||||
for (j = 0; j < num_clusters; ++j) {
|
||||
const double cur_bits =
|
||||
FN(BrotliHistogramBitCostDistance)(&in[i], &out[clusters[j]]);
|
||||
FN(BrotliHistogramBitCostDistance)(&in[i], &out[clusters[j]], tmp);
|
||||
if (cur_bits < best_bits) {
|
||||
best_bits = cur_bits;
|
||||
best_out = clusters[j];
|
||||
@@ -215,7 +217,7 @@ BROTLI_INTERNAL size_t FN(BrotliHistogramReindex)(MemoryManager* m,
|
||||
uint32_t next_index;
|
||||
HistogramType* tmp;
|
||||
size_t i;
|
||||
if (BROTLI_IS_OOM(m)) return 0;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_index)) return 0;
|
||||
for (i = 0; i < length; ++i) {
|
||||
new_index[i] = kInvalidIndex;
|
||||
}
|
||||
@@ -226,10 +228,10 @@ BROTLI_INTERNAL size_t FN(BrotliHistogramReindex)(MemoryManager* m,
|
||||
++next_index;
|
||||
}
|
||||
}
|
||||
/* TODO: by using idea of "cycle-sort" we can avoid allocation of
|
||||
/* TODO(eustas): by using idea of "cycle-sort" we can avoid allocation of
|
||||
tmp and reduce the number of copying by the factor of 2. */
|
||||
tmp = BROTLI_ALLOC(m, HistogramType, next_index);
|
||||
if (BROTLI_IS_OOM(m)) return 0;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(tmp)) return 0;
|
||||
next_index = 0;
|
||||
for (i = 0; i < length; ++i) {
|
||||
if (new_index[symbols[i]] == next_index) {
|
||||
@@ -257,9 +259,14 @@ BROTLI_INTERNAL void FN(BrotliClusterHistograms)(
|
||||
size_t pairs_capacity = max_input_histograms * max_input_histograms / 2;
|
||||
/* For the first pass of clustering, we allow all pairs. */
|
||||
HistogramPair* pairs = BROTLI_ALLOC(m, HistogramPair, pairs_capacity + 1);
|
||||
/* TODO(eustas): move to "persistent" arena? */
|
||||
HistogramType* tmp = BROTLI_ALLOC(m, HistogramType, 1);
|
||||
size_t i;
|
||||
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(cluster_size) ||
|
||||
BROTLI_IS_NULL(clusters) || BROTLI_IS_NULL(pairs)|| BROTLI_IS_NULL(tmp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < in_size; ++i) {
|
||||
cluster_size[i] = 1;
|
||||
@@ -280,7 +287,7 @@ BROTLI_INTERNAL void FN(BrotliClusterHistograms)(
|
||||
clusters[num_clusters + j] = (uint32_t)(i + j);
|
||||
}
|
||||
num_new_clusters =
|
||||
FN(BrotliHistogramCombine)(out, cluster_size,
|
||||
FN(BrotliHistogramCombine)(out, tmp, cluster_size,
|
||||
&histogram_symbols[i],
|
||||
&clusters[num_clusters], pairs,
|
||||
num_to_combine, num_to_combine,
|
||||
@@ -298,7 +305,7 @@ BROTLI_INTERNAL void FN(BrotliClusterHistograms)(
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
|
||||
/* Collapse similar histograms. */
|
||||
num_clusters = FN(BrotliHistogramCombine)(out, cluster_size,
|
||||
num_clusters = FN(BrotliHistogramCombine)(out, tmp, cluster_size,
|
||||
histogram_symbols, clusters,
|
||||
pairs, num_clusters, in_size,
|
||||
max_histograms, max_num_pairs);
|
||||
@@ -307,7 +314,8 @@ BROTLI_INTERNAL void FN(BrotliClusterHistograms)(
|
||||
BROTLI_FREE(m, cluster_size);
|
||||
/* Find the optimal map from original histograms to the final ones. */
|
||||
FN(BrotliHistogramRemap)(in, in_size, clusters, num_clusters,
|
||||
out, histogram_symbols);
|
||||
out, tmp, histogram_symbols);
|
||||
BROTLI_FREE(m, tmp);
|
||||
BROTLI_FREE(m, clusters);
|
||||
/* Convert the context map to a canonical form. */
|
||||
*out_size = FN(BrotliHistogramReindex)(m, out, histogram_symbols, in_size);
|
||||
|
||||
28
c/enc/command.c
Normal file
28
c/enc/command.c
Normal file
@@ -0,0 +1,28 @@
|
||||
/* Copyright 2013 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "command.h"
|
||||
|
||||
#include "../common/platform.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
const uint32_t kBrotliInsBase[BROTLI_NUM_INS_COPY_CODES] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 8, 10, 14, 18, 26,
|
||||
34, 50, 66, 98, 130, 194, 322, 578, 1090, 2114, 6210, 22594};
|
||||
const uint32_t kBrotliInsExtra[BROTLI_NUM_INS_COPY_CODES] = {
|
||||
0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 8, 9, 10, 12, 14, 24};
|
||||
const uint32_t kBrotliCopyBase[BROTLI_NUM_INS_COPY_CODES] = {
|
||||
2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 18,
|
||||
22, 30, 38, 54, 70, 102, 134, 198, 326, 582, 1094, 2118};
|
||||
const uint32_t kBrotliCopyExtra[BROTLI_NUM_INS_COPY_CODES] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 8, 9, 10, 24};
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
@@ -11,23 +11,22 @@
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./fast_log.h"
|
||||
#include "./params.h"
|
||||
#include "./prefix.h"
|
||||
#include "fast_log.h"
|
||||
#include "params.h"
|
||||
#include "prefix.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static uint32_t kInsBase[] = { 0, 1, 2, 3, 4, 5, 6, 8, 10, 14, 18, 26, 34, 50,
|
||||
66, 98, 130, 194, 322, 578, 1090, 2114, 6210, 22594 };
|
||||
static uint32_t kInsExtra[] = { 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4,
|
||||
5, 5, 6, 7, 8, 9, 10, 12, 14, 24 };
|
||||
static uint32_t kCopyBase[] = { 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 18, 22, 30,
|
||||
38, 54, 70, 102, 134, 198, 326, 582, 1094, 2118 };
|
||||
static uint32_t kCopyExtra[] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3,
|
||||
4, 4, 5, 5, 6, 7, 8, 9, 10, 24 };
|
||||
BROTLI_INTERNAL extern const BROTLI_MODEL("small")
|
||||
uint32_t kBrotliInsBase[BROTLI_NUM_INS_COPY_CODES];
|
||||
BROTLI_INTERNAL extern const BROTLI_MODEL("small")
|
||||
uint32_t kBrotliInsExtra[BROTLI_NUM_INS_COPY_CODES];
|
||||
BROTLI_INTERNAL extern const BROTLI_MODEL("small")
|
||||
uint32_t kBrotliCopyBase[BROTLI_NUM_INS_COPY_CODES];
|
||||
BROTLI_INTERNAL extern const BROTLI_MODEL("small")
|
||||
uint32_t kBrotliCopyExtra[BROTLI_NUM_INS_COPY_CODES];
|
||||
|
||||
static BROTLI_INLINE uint16_t GetInsertLengthCode(size_t insertlen) {
|
||||
if (insertlen < 6) {
|
||||
@@ -89,19 +88,19 @@ static BROTLI_INLINE void GetLengthCode(size_t insertlen, size_t copylen,
|
||||
}
|
||||
|
||||
static BROTLI_INLINE uint32_t GetInsertBase(uint16_t inscode) {
|
||||
return kInsBase[inscode];
|
||||
return kBrotliInsBase[inscode];
|
||||
}
|
||||
|
||||
static BROTLI_INLINE uint32_t GetInsertExtra(uint16_t inscode) {
|
||||
return kInsExtra[inscode];
|
||||
return kBrotliInsExtra[inscode];
|
||||
}
|
||||
|
||||
static BROTLI_INLINE uint32_t GetCopyBase(uint16_t copycode) {
|
||||
return kCopyBase[copycode];
|
||||
return kBrotliCopyBase[copycode];
|
||||
}
|
||||
|
||||
static BROTLI_INLINE uint32_t GetCopyExtra(uint16_t copycode) {
|
||||
return kCopyExtra[copycode];
|
||||
return kBrotliCopyExtra[copycode];
|
||||
}
|
||||
|
||||
typedef struct Command {
|
||||
|
||||
205
c/enc/compound_dictionary.c
Normal file
205
c/enc/compound_dictionary.c
Normal file
@@ -0,0 +1,205 @@
|
||||
/* Copyright 2017 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "compound_dictionary.h"
|
||||
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/shared_dictionary.h>
|
||||
#include "memory.h"
|
||||
|
||||
static PreparedDictionary* CreatePreparedDictionaryWithParams(MemoryManager* m,
|
||||
const uint8_t* source, size_t source_size, uint32_t bucket_bits,
|
||||
uint32_t slot_bits, uint32_t hash_bits, uint16_t bucket_limit) {
|
||||
/* Step 1: create "bloated" hasher. */
|
||||
uint32_t num_slots = 1u << slot_bits;
|
||||
uint32_t num_buckets = 1u << bucket_bits;
|
||||
uint32_t hash_shift = 64u - bucket_bits;
|
||||
uint64_t hash_mask = (~((uint64_t)0U)) >> (64 - hash_bits);
|
||||
uint32_t slot_mask = num_slots - 1;
|
||||
size_t alloc_size = (sizeof(uint32_t) << slot_bits) +
|
||||
(sizeof(uint32_t) << slot_bits) +
|
||||
(sizeof(uint16_t) << bucket_bits) +
|
||||
(sizeof(uint32_t) << bucket_bits) +
|
||||
(sizeof(uint32_t) * source_size);
|
||||
uint8_t* flat = NULL;
|
||||
PreparedDictionary* result = NULL;
|
||||
uint16_t* num = NULL;
|
||||
uint32_t* bucket_heads = NULL;
|
||||
uint32_t* next_bucket = NULL;
|
||||
uint32_t* slot_offsets = NULL;
|
||||
uint16_t* heads = NULL;
|
||||
uint32_t* items = NULL;
|
||||
uint8_t** source_ref = NULL;
|
||||
uint32_t i;
|
||||
uint32_t* slot_size = NULL;
|
||||
uint32_t* slot_limit = NULL;
|
||||
uint32_t total_items = 0;
|
||||
if (slot_bits > 16) return NULL;
|
||||
if (slot_bits > bucket_bits) return NULL;
|
||||
if (bucket_bits - slot_bits >= 16) return NULL;
|
||||
|
||||
flat = BROTLI_ALLOC(m, uint8_t, alloc_size);
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(flat)) return NULL;
|
||||
|
||||
slot_size = (uint32_t*)flat;
|
||||
slot_limit = (uint32_t*)(&slot_size[num_slots]);
|
||||
num = (uint16_t*)(&slot_limit[num_slots]);
|
||||
bucket_heads = (uint32_t*)(&num[num_buckets]);
|
||||
next_bucket = (uint32_t*)(&bucket_heads[num_buckets]);
|
||||
memset(num, 0, num_buckets * sizeof(num[0]));
|
||||
|
||||
/* TODO(eustas): apply custom "store" order. */
|
||||
for (i = 0; i + 7 < source_size; ++i) {
|
||||
const uint64_t h = (BROTLI_UNALIGNED_LOAD64LE(&source[i]) & hash_mask) *
|
||||
kPreparedDictionaryHashMul64Long;
|
||||
const uint32_t key = (uint32_t)(h >> hash_shift);
|
||||
uint16_t count = num[key];
|
||||
next_bucket[i] = (count == 0) ? ((uint32_t)(-1)) : bucket_heads[key];
|
||||
bucket_heads[key] = i;
|
||||
count++;
|
||||
if (count > bucket_limit) count = bucket_limit;
|
||||
num[key] = count;
|
||||
}
|
||||
|
||||
/* Step 2: find slot limits. */
|
||||
for (i = 0; i < num_slots; ++i) {
|
||||
BROTLI_BOOL overflow = BROTLI_FALSE;
|
||||
slot_limit[i] = bucket_limit;
|
||||
while (BROTLI_TRUE) {
|
||||
uint32_t limit = slot_limit[i];
|
||||
size_t j;
|
||||
uint32_t count = 0;
|
||||
overflow = BROTLI_FALSE;
|
||||
for (j = i; j < num_buckets; j += num_slots) {
|
||||
uint32_t size = num[j];
|
||||
/* Last chain may span behind 64K limit; overflow happens only if
|
||||
we are about to use 0xFFFF+ as item offset. */
|
||||
if (count >= 0xFFFF) {
|
||||
overflow = BROTLI_TRUE;
|
||||
break;
|
||||
}
|
||||
if (size > limit) size = limit;
|
||||
count += size;
|
||||
}
|
||||
if (!overflow) {
|
||||
slot_size[i] = count;
|
||||
total_items += count;
|
||||
break;
|
||||
}
|
||||
slot_limit[i]--;
|
||||
}
|
||||
}
|
||||
|
||||
/* Step 3: transfer data to "slim" hasher. */
|
||||
alloc_size = sizeof(PreparedDictionary) + (sizeof(uint32_t) << slot_bits) +
|
||||
(sizeof(uint16_t) << bucket_bits) + (sizeof(uint32_t) * total_items) +
|
||||
sizeof(uint8_t*);
|
||||
|
||||
result = (PreparedDictionary*)BROTLI_ALLOC(m, uint8_t, alloc_size);
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(result)) {
|
||||
BROTLI_FREE(m, flat);
|
||||
return NULL;
|
||||
}
|
||||
slot_offsets = (uint32_t*)(&result[1]);
|
||||
heads = (uint16_t*)(&slot_offsets[num_slots]);
|
||||
items = (uint32_t*)(&heads[num_buckets]);
|
||||
source_ref = (uint8_t**)(&items[total_items]);
|
||||
|
||||
result->magic = kLeanPreparedDictionaryMagic;
|
||||
result->num_items = total_items;
|
||||
result->source_size = (uint32_t)source_size;
|
||||
result->hash_bits = hash_bits;
|
||||
result->bucket_bits = bucket_bits;
|
||||
result->slot_bits = slot_bits;
|
||||
BROTLI_UNALIGNED_STORE_PTR(source_ref, source);
|
||||
|
||||
total_items = 0;
|
||||
for (i = 0; i < num_slots; ++i) {
|
||||
slot_offsets[i] = total_items;
|
||||
total_items += slot_size[i];
|
||||
slot_size[i] = 0;
|
||||
}
|
||||
for (i = 0; i < num_buckets; ++i) {
|
||||
uint32_t slot = i & slot_mask;
|
||||
uint32_t count = num[i];
|
||||
uint32_t pos;
|
||||
size_t j;
|
||||
size_t cursor = slot_size[slot];
|
||||
if (count > slot_limit[slot]) count = slot_limit[slot];
|
||||
if (count == 0) {
|
||||
heads[i] = 0xFFFF;
|
||||
continue;
|
||||
}
|
||||
heads[i] = (uint16_t)cursor;
|
||||
cursor += slot_offsets[slot];
|
||||
slot_size[slot] += count;
|
||||
pos = bucket_heads[i];
|
||||
for (j = 0; j < count; j++) {
|
||||
items[cursor++] = pos;
|
||||
pos = next_bucket[pos];
|
||||
}
|
||||
items[cursor - 1] |= 0x80000000;
|
||||
}
|
||||
|
||||
BROTLI_FREE(m, flat);
|
||||
return result;
|
||||
}
|
||||
|
||||
PreparedDictionary* CreatePreparedDictionary(MemoryManager* m,
|
||||
const uint8_t* source, size_t source_size) {
|
||||
uint32_t bucket_bits = 17;
|
||||
uint32_t slot_bits = 7;
|
||||
uint32_t hash_bits = 40;
|
||||
uint16_t bucket_limit = 32;
|
||||
size_t volume = 16u << bucket_bits;
|
||||
/* Tune parameters to fit dictionary size. */
|
||||
while (volume < source_size && bucket_bits < 22) {
|
||||
bucket_bits++;
|
||||
slot_bits++;
|
||||
volume <<= 1;
|
||||
}
|
||||
return CreatePreparedDictionaryWithParams(m,
|
||||
source, source_size, bucket_bits, slot_bits, hash_bits, bucket_limit);
|
||||
}
|
||||
|
||||
void DestroyPreparedDictionary(MemoryManager* m,
|
||||
PreparedDictionary* dictionary) {
|
||||
if (!dictionary) return;
|
||||
BROTLI_FREE(m, dictionary);
|
||||
}
|
||||
|
||||
BROTLI_BOOL AttachPreparedDictionary(
|
||||
CompoundDictionary* compound, const PreparedDictionary* dictionary) {
|
||||
size_t length = 0;
|
||||
size_t index = 0;
|
||||
|
||||
if (compound->num_chunks == SHARED_BROTLI_MAX_COMPOUND_DICTS) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
|
||||
if (!dictionary) return BROTLI_FALSE;
|
||||
|
||||
length = dictionary->source_size;
|
||||
index = compound->num_chunks;
|
||||
compound->total_size += length;
|
||||
compound->chunks[index] = dictionary;
|
||||
compound->chunk_offsets[index + 1] = compound->total_size;
|
||||
{
|
||||
uint32_t* slot_offsets = (uint32_t*)(&dictionary[1]);
|
||||
uint16_t* heads = (uint16_t*)(&slot_offsets[(size_t)1u << dictionary->slot_bits]);
|
||||
uint32_t* items = (uint32_t*)(&heads[(size_t)1u << dictionary->bucket_bits]);
|
||||
const void* tail = (void*)&items[dictionary->num_items];
|
||||
if (dictionary->magic == kPreparedDictionaryMagic) {
|
||||
compound->chunk_source[index] = (const uint8_t*)tail;
|
||||
} else {
|
||||
/* dictionary->magic == kLeanPreparedDictionaryMagic */
|
||||
compound->chunk_source[index] =
|
||||
(const uint8_t*)BROTLI_UNALIGNED_LOAD_PTR((const uint8_t**)tail);
|
||||
}
|
||||
}
|
||||
compound->num_chunks++;
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
71
c/enc/compound_dictionary.h
Normal file
71
c/enc/compound_dictionary.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/* Copyright 2017 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#ifndef BROTLI_ENC_PREPARED_DICTIONARY_H_
|
||||
#define BROTLI_ENC_PREPARED_DICTIONARY_H_
|
||||
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/shared_dictionary.h>
|
||||
#include "memory.h"
|
||||
|
||||
/* "Fat" prepared dictionary, could be cooked outside of C implementation,
|
||||
* e.g. on Java side. LZ77 data is copied inside PreparedDictionary struct. */
|
||||
static const uint32_t kPreparedDictionaryMagic = 0xDEBCEDE0;
|
||||
|
||||
static const uint32_t kSharedDictionaryMagic = 0xDEBCEDE1;
|
||||
|
||||
static const uint32_t kManagedDictionaryMagic = 0xDEBCEDE2;
|
||||
|
||||
/* "Lean" prepared dictionary. LZ77 data is referenced. It is the responsibility
|
||||
* of caller of "prepare dictionary" to keep the LZ77 data while prepared
|
||||
* dictionary is in use. */
|
||||
static const uint32_t kLeanPreparedDictionaryMagic = 0xDEBCEDE3;
|
||||
|
||||
static const uint64_t kPreparedDictionaryHashMul64Long =
|
||||
BROTLI_MAKE_UINT64_T(0x1FE35A7Bu, 0xD3579BD3u);
|
||||
|
||||
typedef struct PreparedDictionary {
|
||||
uint32_t magic;
|
||||
uint32_t num_items;
|
||||
uint32_t source_size;
|
||||
uint32_t hash_bits;
|
||||
uint32_t bucket_bits;
|
||||
uint32_t slot_bits;
|
||||
|
||||
/* --- Dynamic size members --- */
|
||||
|
||||
/* uint32_t slot_offsets[1 << slot_bits]; */
|
||||
/* uint16_t heads[1 << bucket_bits]; */
|
||||
/* uint32_t items[variable]; */
|
||||
|
||||
/* [maybe] uint8_t* source_ref, depending on magic. */
|
||||
/* [maybe] uint8_t source[source_size], depending on magic. */
|
||||
} PreparedDictionary;
|
||||
|
||||
BROTLI_INTERNAL PreparedDictionary* CreatePreparedDictionary(MemoryManager* m,
|
||||
const uint8_t* source, size_t source_size);
|
||||
|
||||
BROTLI_INTERNAL void DestroyPreparedDictionary(MemoryManager* m,
|
||||
PreparedDictionary* dictionary);
|
||||
|
||||
typedef struct CompoundDictionary {
|
||||
/* LZ77 prefix, compound dictionary */
|
||||
size_t num_chunks;
|
||||
size_t total_size;
|
||||
/* Client instances. */
|
||||
const PreparedDictionary* chunks[SHARED_BROTLI_MAX_COMPOUND_DICTS + 1];
|
||||
const uint8_t* chunk_source[SHARED_BROTLI_MAX_COMPOUND_DICTS + 1];
|
||||
size_t chunk_offsets[SHARED_BROTLI_MAX_COMPOUND_DICTS + 1];
|
||||
|
||||
size_t num_prepared_instances_;
|
||||
/* Owned instances. */
|
||||
PreparedDictionary* prepared_instances_[SHARED_BROTLI_MAX_COMPOUND_DICTS + 1];
|
||||
} CompoundDictionary;
|
||||
|
||||
BROTLI_INTERNAL BROTLI_BOOL AttachPreparedDictionary(
|
||||
CompoundDictionary* compound, const PreparedDictionary* dictionary);
|
||||
|
||||
#endif /* BROTLI_ENC_PREPARED_DICTIONARY */
|
||||
@@ -12,19 +12,16 @@
|
||||
Adapted from the CompressFragment() function in
|
||||
https://github.com/google/snappy/blob/master/snappy.cc */
|
||||
|
||||
#include "./compress_fragment.h"
|
||||
|
||||
#include <string.h> /* memcmp, memcpy, memset */
|
||||
#include "compress_fragment.h"
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./brotli_bit_stream.h"
|
||||
#include "./entropy_encode.h"
|
||||
#include "./fast_log.h"
|
||||
#include "./find_match_length.h"
|
||||
#include "./memory.h"
|
||||
#include "./write_bits.h"
|
||||
#include "brotli_bit_stream.h"
|
||||
#include "entropy_encode.h"
|
||||
#include "fast_log.h"
|
||||
#include "find_match_length.h"
|
||||
#include "hash_base.h"
|
||||
#include "write_bits.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
@@ -32,14 +29,6 @@ extern "C" {
|
||||
|
||||
#define MAX_DISTANCE (long)BROTLI_MAX_BACKWARD_LIMIT(18)
|
||||
|
||||
/* kHashMul32 multiplier has these properties:
|
||||
* The multiplier must be odd. Otherwise we may lose the highest bit.
|
||||
* No long streaks of ones or zeros.
|
||||
* There is no effort to ensure that it is a prime, the oddity is enough
|
||||
for this use.
|
||||
* The number has been tuned heuristically against compression benchmarks. */
|
||||
static const uint32_t kHashMul32 = 0x1E35A7BD;
|
||||
|
||||
static BROTLI_INLINE uint32_t Hash(const uint8_t* p, size_t shift) {
|
||||
const uint64_t h = (BROTLI_UNALIGNED_LOAD64LE(p) << 24) * kHashMul32;
|
||||
return (uint32_t)(h >> shift);
|
||||
@@ -69,16 +58,18 @@ static BROTLI_INLINE BROTLI_BOOL IsMatch(const uint8_t* p1, const uint8_t* p2) {
|
||||
and thus have to assign a non-zero depth for each literal.
|
||||
Returns estimated compression ratio millibytes/char for encoding given input
|
||||
with generated code. */
|
||||
static size_t BuildAndStoreLiteralPrefixCode(MemoryManager* m,
|
||||
static size_t BuildAndStoreLiteralPrefixCode(BrotliOnePassArena* s,
|
||||
const uint8_t* input,
|
||||
const size_t input_size,
|
||||
uint8_t depths[256],
|
||||
uint16_t bits[256],
|
||||
size_t* storage_ix,
|
||||
uint8_t* storage) {
|
||||
uint32_t histogram[256] = { 0 };
|
||||
uint32_t* BROTLI_RESTRICT const histogram = s->histogram;
|
||||
size_t histogram_total;
|
||||
size_t i;
|
||||
memset(histogram, 0, sizeof(s->histogram));
|
||||
|
||||
if (input_size < (1 << 15)) {
|
||||
for (i = 0; i < input_size; ++i) {
|
||||
++histogram[input[i]];
|
||||
@@ -108,10 +99,9 @@ static size_t BuildAndStoreLiteralPrefixCode(MemoryManager* m,
|
||||
histogram_total += adjust;
|
||||
}
|
||||
}
|
||||
BrotliBuildAndStoreHuffmanTreeFast(m, histogram, histogram_total,
|
||||
BrotliBuildAndStoreHuffmanTreeFast(s->tree, histogram, histogram_total,
|
||||
/* max_bits = */ 8,
|
||||
depths, bits, storage_ix, storage);
|
||||
if (BROTLI_IS_OOM(m)) return 0;
|
||||
{
|
||||
size_t literal_ratio = 0;
|
||||
for (i = 0; i < 256; ++i) {
|
||||
@@ -124,53 +114,56 @@ static size_t BuildAndStoreLiteralPrefixCode(MemoryManager* m,
|
||||
|
||||
/* Builds a command and distance prefix code (each 64 symbols) into "depth" and
|
||||
"bits" based on "histogram" and stores it into the bit stream. */
|
||||
static void BuildAndStoreCommandPrefixCode(const uint32_t histogram[128],
|
||||
uint8_t depth[128], uint16_t bits[128], size_t* storage_ix,
|
||||
uint8_t* storage) {
|
||||
/* Tree size for building a tree over 64 symbols is 2 * 64 + 1. */
|
||||
HuffmanTree tree[129];
|
||||
uint8_t cmd_depth[BROTLI_NUM_COMMAND_SYMBOLS] = { 0 };
|
||||
uint16_t cmd_bits[64];
|
||||
static void BuildAndStoreCommandPrefixCode(BrotliOnePassArena* s,
|
||||
size_t* storage_ix, uint8_t* storage) {
|
||||
const uint32_t* const histogram = s->cmd_histo;
|
||||
uint8_t* const depth = s->cmd_depth;
|
||||
uint16_t* const bits = s->cmd_bits;
|
||||
uint8_t* BROTLI_RESTRICT const tmp_depth = s->tmp_depth;
|
||||
uint16_t* BROTLI_RESTRICT const tmp_bits = s->tmp_bits;
|
||||
/* TODO(eustas): do only once on initialization. */
|
||||
memset(tmp_depth, 0, BROTLI_NUM_COMMAND_SYMBOLS);
|
||||
|
||||
BrotliCreateHuffmanTree(histogram, 64, 15, tree, depth);
|
||||
BrotliCreateHuffmanTree(&histogram[64], 64, 14, tree, &depth[64]);
|
||||
BrotliCreateHuffmanTree(histogram, 64, 15, s->tree, depth);
|
||||
BrotliCreateHuffmanTree(&histogram[64], 64, 14, s->tree, &depth[64]);
|
||||
/* We have to jump through a few hoops here in order to compute
|
||||
the command bits because the symbols are in a different order than in
|
||||
the full alphabet. This looks complicated, but having the symbols
|
||||
in this order in the command bits saves a few branches in the Emit*
|
||||
functions. */
|
||||
memcpy(cmd_depth, depth, 24);
|
||||
memcpy(cmd_depth + 24, depth + 40, 8);
|
||||
memcpy(cmd_depth + 32, depth + 24, 8);
|
||||
memcpy(cmd_depth + 40, depth + 48, 8);
|
||||
memcpy(cmd_depth + 48, depth + 32, 8);
|
||||
memcpy(cmd_depth + 56, depth + 56, 8);
|
||||
BrotliConvertBitDepthsToSymbols(cmd_depth, 64, cmd_bits);
|
||||
memcpy(bits, cmd_bits, 48);
|
||||
memcpy(bits + 24, cmd_bits + 32, 16);
|
||||
memcpy(bits + 32, cmd_bits + 48, 16);
|
||||
memcpy(bits + 40, cmd_bits + 24, 16);
|
||||
memcpy(bits + 48, cmd_bits + 40, 16);
|
||||
memcpy(bits + 56, cmd_bits + 56, 16);
|
||||
memcpy(tmp_depth, depth, 24);
|
||||
memcpy(tmp_depth + 24, depth + 40, 8);
|
||||
memcpy(tmp_depth + 32, depth + 24, 8);
|
||||
memcpy(tmp_depth + 40, depth + 48, 8);
|
||||
memcpy(tmp_depth + 48, depth + 32, 8);
|
||||
memcpy(tmp_depth + 56, depth + 56, 8);
|
||||
BrotliConvertBitDepthsToSymbols(tmp_depth, 64, tmp_bits);
|
||||
memcpy(bits, tmp_bits, 48);
|
||||
memcpy(bits + 24, tmp_bits + 32, 16);
|
||||
memcpy(bits + 32, tmp_bits + 48, 16);
|
||||
memcpy(bits + 40, tmp_bits + 24, 16);
|
||||
memcpy(bits + 48, tmp_bits + 40, 16);
|
||||
memcpy(bits + 56, tmp_bits + 56, 16);
|
||||
BrotliConvertBitDepthsToSymbols(&depth[64], 64, &bits[64]);
|
||||
{
|
||||
/* Create the bit length array for the full command alphabet. */
|
||||
size_t i;
|
||||
memset(cmd_depth, 0, 64); /* only 64 first values were used */
|
||||
memcpy(cmd_depth, depth, 8);
|
||||
memcpy(cmd_depth + 64, depth + 8, 8);
|
||||
memcpy(cmd_depth + 128, depth + 16, 8);
|
||||
memcpy(cmd_depth + 192, depth + 24, 8);
|
||||
memcpy(cmd_depth + 384, depth + 32, 8);
|
||||
memset(tmp_depth, 0, 64); /* only 64 first values were used */
|
||||
memcpy(tmp_depth, depth, 8);
|
||||
memcpy(tmp_depth + 64, depth + 8, 8);
|
||||
memcpy(tmp_depth + 128, depth + 16, 8);
|
||||
memcpy(tmp_depth + 192, depth + 24, 8);
|
||||
memcpy(tmp_depth + 384, depth + 32, 8);
|
||||
for (i = 0; i < 8; ++i) {
|
||||
cmd_depth[128 + 8 * i] = depth[40 + i];
|
||||
cmd_depth[256 + 8 * i] = depth[48 + i];
|
||||
cmd_depth[448 + 8 * i] = depth[56 + i];
|
||||
tmp_depth[128 + 8 * i] = depth[40 + i];
|
||||
tmp_depth[256 + 8 * i] = depth[48 + i];
|
||||
tmp_depth[448 + 8 * i] = depth[56 + i];
|
||||
}
|
||||
/* TODO(eustas): could/should full-length machinery be avoided? */
|
||||
BrotliStoreHuffmanTree(
|
||||
cmd_depth, BROTLI_NUM_COMMAND_SYMBOLS, tree, storage_ix, storage);
|
||||
tmp_depth, BROTLI_NUM_COMMAND_SYMBOLS, s->tree, storage_ix, storage);
|
||||
}
|
||||
BrotliStoreHuffmanTree(&depth[64], 64, tree, storage_ix, storage);
|
||||
BrotliStoreHuffmanTree(&depth[64], 64, s->tree, storage_ix, storage);
|
||||
}
|
||||
|
||||
/* REQUIRES: insertlen < 6210 */
|
||||
@@ -369,11 +362,12 @@ static void RewindBitPosition(const size_t new_storage_ix,
|
||||
*storage_ix = new_storage_ix;
|
||||
}
|
||||
|
||||
static BROTLI_BOOL ShouldMergeBlock(
|
||||
static BROTLI_BOOL ShouldMergeBlock(BrotliOnePassArena* s,
|
||||
const uint8_t* data, size_t len, const uint8_t* depths) {
|
||||
size_t histo[256] = { 0 };
|
||||
uint32_t* BROTLI_RESTRICT const histo = s->histogram;
|
||||
static const size_t kSampleRate = 43;
|
||||
size_t i;
|
||||
memset(histo, 0, sizeof(s->histogram));
|
||||
for (i = 0; i < len; i += kSampleRate) {
|
||||
++histo[data[i]];
|
||||
}
|
||||
@@ -413,7 +407,7 @@ static void EmitUncompressedMetaBlock(const uint8_t* begin, const uint8_t* end,
|
||||
storage[*storage_ix >> 3] = 0;
|
||||
}
|
||||
|
||||
static uint32_t kCmdHistoSeed[128] = {
|
||||
static BROTLI_MODEL("small") uint32_t kCmdHistoSeed[128] = {
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
|
||||
@@ -423,11 +417,14 @@ static uint32_t kCmdHistoSeed[128] = {
|
||||
};
|
||||
|
||||
static BROTLI_INLINE void BrotliCompressFragmentFastImpl(
|
||||
MemoryManager* m, const uint8_t* input, size_t input_size,
|
||||
BROTLI_BOOL is_last, int* table, size_t table_bits, uint8_t cmd_depth[128],
|
||||
uint16_t cmd_bits[128], size_t* cmd_code_numbits, uint8_t* cmd_code,
|
||||
BrotliOnePassArena* s, const uint8_t* input, size_t input_size,
|
||||
BROTLI_BOOL is_last, int* table, size_t table_bits,
|
||||
size_t* storage_ix, uint8_t* storage) {
|
||||
uint32_t cmd_histo[128];
|
||||
uint8_t* BROTLI_RESTRICT const cmd_depth = s->cmd_depth;
|
||||
uint16_t* BROTLI_RESTRICT const cmd_bits = s->cmd_bits;
|
||||
uint32_t* BROTLI_RESTRICT const cmd_histo = s->cmd_histo;
|
||||
uint8_t* BROTLI_RESTRICT const lit_depth = s->lit_depth;
|
||||
uint16_t* BROTLI_RESTRICT const lit_bits = s->lit_bits;
|
||||
const uint8_t* ip_end;
|
||||
|
||||
/* "next_emit" is a pointer to the first byte that is not covered by a
|
||||
@@ -451,9 +448,6 @@ static BROTLI_INLINE void BrotliCompressFragmentFastImpl(
|
||||
we can update it later if we decide to extend this meta-block. */
|
||||
size_t mlen_storage_ix = *storage_ix + 3;
|
||||
|
||||
uint8_t lit_depth[256];
|
||||
uint16_t lit_bits[256];
|
||||
|
||||
size_t literal_ratio;
|
||||
|
||||
const uint8_t* ip;
|
||||
@@ -466,25 +460,24 @@ static BROTLI_INLINE void BrotliCompressFragmentFastImpl(
|
||||
BrotliWriteBits(13, 0, storage_ix, storage);
|
||||
|
||||
literal_ratio = BuildAndStoreLiteralPrefixCode(
|
||||
m, input, block_size, lit_depth, lit_bits, storage_ix, storage);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
s, input, block_size, s->lit_depth, s->lit_bits, storage_ix, storage);
|
||||
|
||||
{
|
||||
/* Store the pre-compressed command and distance prefix codes. */
|
||||
size_t i;
|
||||
for (i = 0; i + 7 < *cmd_code_numbits; i += 8) {
|
||||
BrotliWriteBits(8, cmd_code[i >> 3], storage_ix, storage);
|
||||
for (i = 0; i + 7 < s->cmd_code_numbits; i += 8) {
|
||||
BrotliWriteBits(8, s->cmd_code[i >> 3], storage_ix, storage);
|
||||
}
|
||||
}
|
||||
BrotliWriteBits(*cmd_code_numbits & 7, cmd_code[*cmd_code_numbits >> 3],
|
||||
storage_ix, storage);
|
||||
BrotliWriteBits(s->cmd_code_numbits & 7,
|
||||
s->cmd_code[s->cmd_code_numbits >> 3], storage_ix, storage);
|
||||
|
||||
emit_commands:
|
||||
/* Initialize the command and distance histograms. We will gather
|
||||
statistics of command and distance codes during the processing
|
||||
of this block and use it to update the command and distance
|
||||
prefix codes for the next block. */
|
||||
memcpy(cmd_histo, kCmdHistoSeed, sizeof(kCmdHistoSeed));
|
||||
memcpy(s->cmd_histo, kCmdHistoSeed, sizeof(kCmdHistoSeed));
|
||||
|
||||
/* "ip" is the input pointer. */
|
||||
ip = input;
|
||||
@@ -565,6 +558,8 @@ trawl:
|
||||
int distance = (int)(base - candidate); /* > 0 */
|
||||
size_t insert = (size_t)(base - next_emit);
|
||||
ip += matched;
|
||||
BROTLI_LOG(("[CompressFragment] pos = %d insert = %lu copy = %d\n",
|
||||
(int)(next_emit - base_ip), (unsigned long)insert, 2));
|
||||
BROTLI_DCHECK(0 == memcmp(base, candidate, matched));
|
||||
if (BROTLI_PREDICT_TRUE(insert < 6210)) {
|
||||
EmitInsertLen(insert, cmd_depth, cmd_bits, cmd_histo,
|
||||
@@ -593,6 +588,12 @@ trawl:
|
||||
}
|
||||
EmitCopyLenLastDistance(matched, cmd_depth, cmd_bits, cmd_histo,
|
||||
storage_ix, storage);
|
||||
BROTLI_LOG(("[CompressFragment] pos = %d distance = %d\n"
|
||||
"[CompressFragment] pos = %d insert = %d copy = %d\n"
|
||||
"[CompressFragment] pos = %d distance = %d\n",
|
||||
(int)(base - base_ip), (int)distance,
|
||||
(int)(base - base_ip) + 2, 0, (int)matched - 2,
|
||||
(int)(base - base_ip) + 2, (int)distance));
|
||||
|
||||
next_emit = ip;
|
||||
if (BROTLI_PREDICT_FALSE(ip >= ip_limit)) {
|
||||
@@ -630,6 +631,10 @@ trawl:
|
||||
storage_ix, storage);
|
||||
EmitDistance((size_t)last_distance, cmd_depth, cmd_bits,
|
||||
cmd_histo, storage_ix, storage);
|
||||
BROTLI_LOG(("[CompressFragment] pos = %d insert = %d copy = %d\n"
|
||||
"[CompressFragment] pos = %d distance = %d\n",
|
||||
(int)(base - base_ip), 0, (int)matched,
|
||||
(int)(base - base_ip), (int)last_distance));
|
||||
|
||||
next_emit = ip;
|
||||
if (BROTLI_PREDICT_FALSE(ip >= ip_limit)) {
|
||||
@@ -667,7 +672,7 @@ trawl:
|
||||
last insert-only command. */
|
||||
if (input_size > 0 &&
|
||||
total_block_size + block_size <= (1 << 20) &&
|
||||
ShouldMergeBlock(input, block_size, lit_depth)) {
|
||||
ShouldMergeBlock(s, input, block_size, lit_depth)) {
|
||||
BROTLI_DCHECK(total_block_size > (1 << 16));
|
||||
/* Update the size of the current meta-block and continue emitting commands.
|
||||
We can do this because the current size and the new size both have 5
|
||||
@@ -680,6 +685,8 @@ trawl:
|
||||
/* Emit the remaining bytes as literals. */
|
||||
if (next_emit < ip_end) {
|
||||
const size_t insert = (size_t)(ip_end - next_emit);
|
||||
BROTLI_LOG(("[CompressFragment] pos = %d insert = %lu copy = %d\n",
|
||||
(int)(next_emit - base_ip), (unsigned long)insert, 2));
|
||||
if (BROTLI_PREDICT_TRUE(insert < 6210)) {
|
||||
EmitInsertLen(insert, cmd_depth, cmd_bits, cmd_histo,
|
||||
storage_ix, storage);
|
||||
@@ -711,20 +718,17 @@ next_block:
|
||||
/* No block splits, no contexts. */
|
||||
BrotliWriteBits(13, 0, storage_ix, storage);
|
||||
literal_ratio = BuildAndStoreLiteralPrefixCode(
|
||||
m, input, block_size, lit_depth, lit_bits, storage_ix, storage);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
BuildAndStoreCommandPrefixCode(cmd_histo, cmd_depth, cmd_bits,
|
||||
storage_ix, storage);
|
||||
s, input, block_size, lit_depth, lit_bits, storage_ix, storage);
|
||||
BuildAndStoreCommandPrefixCode(s, storage_ix, storage);
|
||||
goto emit_commands;
|
||||
}
|
||||
|
||||
if (!is_last) {
|
||||
/* If this is not the last block, update the command and distance prefix
|
||||
codes for the next block and store the compressed forms. */
|
||||
cmd_code[0] = 0;
|
||||
*cmd_code_numbits = 0;
|
||||
BuildAndStoreCommandPrefixCode(cmd_histo, cmd_depth, cmd_bits,
|
||||
cmd_code_numbits, cmd_code);
|
||||
s->cmd_code[0] = 0;
|
||||
s->cmd_code_numbits = 0;
|
||||
BuildAndStoreCommandPrefixCode(s, &s->cmd_code_numbits, s->cmd_code);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -732,20 +736,17 @@ next_block:
|
||||
|
||||
#define BAKE_METHOD_PARAM_(B) \
|
||||
static BROTLI_NOINLINE void BrotliCompressFragmentFastImpl ## B( \
|
||||
MemoryManager* m, const uint8_t* input, size_t input_size, \
|
||||
BROTLI_BOOL is_last, int* table, uint8_t cmd_depth[128], \
|
||||
uint16_t cmd_bits[128], size_t* cmd_code_numbits, uint8_t* cmd_code, \
|
||||
size_t* storage_ix, uint8_t* storage) { \
|
||||
BrotliCompressFragmentFastImpl(m, input, input_size, is_last, table, B, \
|
||||
cmd_depth, cmd_bits, cmd_code_numbits, cmd_code, storage_ix, storage); \
|
||||
BrotliOnePassArena* s, const uint8_t* input, size_t input_size, \
|
||||
BROTLI_BOOL is_last, int* table, size_t* storage_ix, uint8_t* storage) { \
|
||||
BrotliCompressFragmentFastImpl(s, input, input_size, is_last, table, B, \
|
||||
storage_ix, storage); \
|
||||
}
|
||||
FOR_TABLE_BITS_(BAKE_METHOD_PARAM_)
|
||||
#undef BAKE_METHOD_PARAM_
|
||||
|
||||
void BrotliCompressFragmentFast(
|
||||
MemoryManager* m, const uint8_t* input, size_t input_size,
|
||||
BROTLI_BOOL is_last, int* table, size_t table_size, uint8_t cmd_depth[128],
|
||||
uint16_t cmd_bits[128], size_t* cmd_code_numbits, uint8_t* cmd_code,
|
||||
BrotliOnePassArena* s, const uint8_t* input, size_t input_size,
|
||||
BROTLI_BOOL is_last, int* table, size_t table_size,
|
||||
size_t* storage_ix, uint8_t* storage) {
|
||||
const size_t initial_storage_ix = *storage_ix;
|
||||
const size_t table_bits = Log2FloorNonZero(table_size);
|
||||
@@ -762,8 +763,7 @@ void BrotliCompressFragmentFast(
|
||||
#define CASE_(B) \
|
||||
case B: \
|
||||
BrotliCompressFragmentFastImpl ## B( \
|
||||
m, input, input_size, is_last, table, cmd_depth, cmd_bits, \
|
||||
cmd_code_numbits, cmd_code, storage_ix, storage); \
|
||||
s, input, input_size, is_last, table, storage_ix, storage);\
|
||||
break;
|
||||
FOR_TABLE_BITS_(CASE_)
|
||||
#undef CASE_
|
||||
|
||||
@@ -12,14 +12,41 @@
|
||||
#ifndef BROTLI_ENC_COMPRESS_FRAGMENT_H_
|
||||
#define BROTLI_ENC_COMPRESS_FRAGMENT_H_
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./memory.h"
|
||||
#include "entropy_encode.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct BrotliOnePassArena {
|
||||
uint8_t lit_depth[256];
|
||||
uint16_t lit_bits[256];
|
||||
|
||||
/* Command and distance prefix codes (each 64 symbols, stored back-to-back)
|
||||
used for the next block. The command prefix code is over a smaller alphabet
|
||||
with the following 64 symbols:
|
||||
0 - 15: insert length code 0, copy length code 0 - 15, same distance
|
||||
16 - 39: insert length code 0, copy length code 0 - 23
|
||||
40 - 63: insert length code 0 - 23, copy length code 0
|
||||
Note that symbols 16 and 40 represent the same code in the full alphabet,
|
||||
but we do not use either of them. */
|
||||
uint8_t cmd_depth[128];
|
||||
uint16_t cmd_bits[128];
|
||||
uint32_t cmd_histo[128];
|
||||
|
||||
/* The compressed form of the command and distance prefix codes for the next
|
||||
block. */
|
||||
uint8_t cmd_code[512];
|
||||
size_t cmd_code_numbits;
|
||||
|
||||
HuffmanTree tree[2 * BROTLI_NUM_LITERAL_SYMBOLS + 1];
|
||||
uint32_t histogram[256];
|
||||
uint8_t tmp_depth[BROTLI_NUM_COMMAND_SYMBOLS];
|
||||
uint16_t tmp_bits[64];
|
||||
} BrotliOnePassArena;
|
||||
|
||||
/* Compresses "input" string to the "*storage" buffer as one or more complete
|
||||
meta-blocks, and updates the "*storage_ix" bit position.
|
||||
|
||||
@@ -42,15 +69,11 @@ extern "C" {
|
||||
REQUIRES: "table_size" is an odd (9, 11, 13, 15) power of two
|
||||
OUTPUT: maximal copy distance <= |input_size|
|
||||
OUTPUT: maximal copy distance <= BROTLI_MAX_BACKWARD_LIMIT(18) */
|
||||
BROTLI_INTERNAL void BrotliCompressFragmentFast(MemoryManager* m,
|
||||
BROTLI_INTERNAL void BrotliCompressFragmentFast(BrotliOnePassArena* s,
|
||||
const uint8_t* input,
|
||||
size_t input_size,
|
||||
BROTLI_BOOL is_last,
|
||||
int* table, size_t table_size,
|
||||
uint8_t cmd_depth[128],
|
||||
uint16_t cmd_bits[128],
|
||||
size_t* cmd_code_numbits,
|
||||
uint8_t* cmd_code,
|
||||
size_t* storage_ix,
|
||||
uint8_t* storage);
|
||||
|
||||
|
||||
@@ -10,20 +10,17 @@
|
||||
second pass we emit them into the bit stream using prefix codes built based
|
||||
on the actual command and literal byte histograms. */
|
||||
|
||||
#include "./compress_fragment_two_pass.h"
|
||||
|
||||
#include <string.h> /* memcmp, memcpy, memset */
|
||||
#include "compress_fragment_two_pass.h"
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./bit_cost.h"
|
||||
#include "./brotli_bit_stream.h"
|
||||
#include "./entropy_encode.h"
|
||||
#include "./fast_log.h"
|
||||
#include "./find_match_length.h"
|
||||
#include "./memory.h"
|
||||
#include "./write_bits.h"
|
||||
#include "bit_cost.h"
|
||||
#include "brotli_bit_stream.h"
|
||||
#include "entropy_encode.h"
|
||||
#include "fast_log.h"
|
||||
#include "find_match_length.h"
|
||||
#include "hash_base.h"
|
||||
#include "write_bits.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
@@ -31,14 +28,6 @@ extern "C" {
|
||||
|
||||
#define MAX_DISTANCE (long)BROTLI_MAX_BACKWARD_LIMIT(18)
|
||||
|
||||
/* kHashMul32 multiplier has these properties:
|
||||
* The multiplier must be odd. Otherwise we may lose the highest bit.
|
||||
* No long streaks of ones or zeros.
|
||||
* There is no effort to ensure that it is a prime, the oddity is enough
|
||||
for this use.
|
||||
* The number has been tuned heuristically against compression benchmarks. */
|
||||
static const uint32_t kHashMul32 = 0x1E35A7BD;
|
||||
|
||||
static BROTLI_INLINE uint32_t Hash(const uint8_t* p,
|
||||
size_t shift, size_t length) {
|
||||
const uint64_t h =
|
||||
@@ -66,53 +55,53 @@ static BROTLI_INLINE BROTLI_BOOL IsMatch(const uint8_t* p1, const uint8_t* p2,
|
||||
|
||||
/* Builds a command and distance prefix code (each 64 symbols) into "depth" and
|
||||
"bits" based on "histogram" and stores it into the bit stream. */
|
||||
static void BuildAndStoreCommandPrefixCode(
|
||||
const uint32_t histogram[128],
|
||||
uint8_t depth[128], uint16_t bits[128],
|
||||
size_t* storage_ix, uint8_t* storage) {
|
||||
static void BuildAndStoreCommandPrefixCode(BrotliTwoPassArena* s,
|
||||
size_t* storage_ix,
|
||||
uint8_t* storage) {
|
||||
/* Tree size for building a tree over 64 symbols is 2 * 64 + 1. */
|
||||
HuffmanTree tree[129];
|
||||
uint8_t cmd_depth[BROTLI_NUM_COMMAND_SYMBOLS] = { 0 };
|
||||
uint16_t cmd_bits[64];
|
||||
BrotliCreateHuffmanTree(histogram, 64, 15, tree, depth);
|
||||
BrotliCreateHuffmanTree(&histogram[64], 64, 14, tree, &depth[64]);
|
||||
/* TODO(eustas): initialize once. */
|
||||
memset(s->tmp_depth, 0, sizeof(s->tmp_depth));
|
||||
BrotliCreateHuffmanTree(s->cmd_histo, 64, 15, s->tmp_tree, s->cmd_depth);
|
||||
BrotliCreateHuffmanTree(&s->cmd_histo[64], 64, 14, s->tmp_tree,
|
||||
&s->cmd_depth[64]);
|
||||
/* We have to jump through a few hoops here in order to compute
|
||||
the command bits because the symbols are in a different order than in
|
||||
the full alphabet. This looks complicated, but having the symbols
|
||||
in this order in the command bits saves a few branches in the Emit*
|
||||
functions. */
|
||||
memcpy(cmd_depth, depth + 24, 24);
|
||||
memcpy(cmd_depth + 24, depth, 8);
|
||||
memcpy(cmd_depth + 32, depth + 48, 8);
|
||||
memcpy(cmd_depth + 40, depth + 8, 8);
|
||||
memcpy(cmd_depth + 48, depth + 56, 8);
|
||||
memcpy(cmd_depth + 56, depth + 16, 8);
|
||||
BrotliConvertBitDepthsToSymbols(cmd_depth, 64, cmd_bits);
|
||||
memcpy(bits, cmd_bits + 24, 16);
|
||||
memcpy(bits + 8, cmd_bits + 40, 16);
|
||||
memcpy(bits + 16, cmd_bits + 56, 16);
|
||||
memcpy(bits + 24, cmd_bits, 48);
|
||||
memcpy(bits + 48, cmd_bits + 32, 16);
|
||||
memcpy(bits + 56, cmd_bits + 48, 16);
|
||||
BrotliConvertBitDepthsToSymbols(&depth[64], 64, &bits[64]);
|
||||
memcpy(s->tmp_depth, s->cmd_depth + 24, 24);
|
||||
memcpy(s->tmp_depth + 24, s->cmd_depth, 8);
|
||||
memcpy(s->tmp_depth + 32, s->cmd_depth + 48, 8);
|
||||
memcpy(s->tmp_depth + 40, s->cmd_depth + 8, 8);
|
||||
memcpy(s->tmp_depth + 48, s->cmd_depth + 56, 8);
|
||||
memcpy(s->tmp_depth + 56, s->cmd_depth + 16, 8);
|
||||
BrotliConvertBitDepthsToSymbols(s->tmp_depth, 64, s->tmp_bits);
|
||||
memcpy(s->cmd_bits, s->tmp_bits + 24, 16);
|
||||
memcpy(s->cmd_bits + 8, s->tmp_bits + 40, 16);
|
||||
memcpy(s->cmd_bits + 16, s->tmp_bits + 56, 16);
|
||||
memcpy(s->cmd_bits + 24, s->tmp_bits, 48);
|
||||
memcpy(s->cmd_bits + 48, s->tmp_bits + 32, 16);
|
||||
memcpy(s->cmd_bits + 56, s->tmp_bits + 48, 16);
|
||||
BrotliConvertBitDepthsToSymbols(&s->cmd_depth[64], 64, &s->cmd_bits[64]);
|
||||
{
|
||||
/* Create the bit length array for the full command alphabet. */
|
||||
size_t i;
|
||||
memset(cmd_depth, 0, 64); /* only 64 first values were used */
|
||||
memcpy(cmd_depth, depth + 24, 8);
|
||||
memcpy(cmd_depth + 64, depth + 32, 8);
|
||||
memcpy(cmd_depth + 128, depth + 40, 8);
|
||||
memcpy(cmd_depth + 192, depth + 48, 8);
|
||||
memcpy(cmd_depth + 384, depth + 56, 8);
|
||||
memset(s->tmp_depth, 0, 64); /* only 64 first values were used */
|
||||
memcpy(s->tmp_depth, s->cmd_depth + 24, 8);
|
||||
memcpy(s->tmp_depth + 64, s->cmd_depth + 32, 8);
|
||||
memcpy(s->tmp_depth + 128, s->cmd_depth + 40, 8);
|
||||
memcpy(s->tmp_depth + 192, s->cmd_depth + 48, 8);
|
||||
memcpy(s->tmp_depth + 384, s->cmd_depth + 56, 8);
|
||||
for (i = 0; i < 8; ++i) {
|
||||
cmd_depth[128 + 8 * i] = depth[i];
|
||||
cmd_depth[256 + 8 * i] = depth[8 + i];
|
||||
cmd_depth[448 + 8 * i] = depth[16 + i];
|
||||
s->tmp_depth[128 + 8 * i] = s->cmd_depth[i];
|
||||
s->tmp_depth[256 + 8 * i] = s->cmd_depth[8 + i];
|
||||
s->tmp_depth[448 + 8 * i] = s->cmd_depth[16 + i];
|
||||
}
|
||||
BrotliStoreHuffmanTree(
|
||||
cmd_depth, BROTLI_NUM_COMMAND_SYMBOLS, tree, storage_ix, storage);
|
||||
BrotliStoreHuffmanTree(s->tmp_depth, BROTLI_NUM_COMMAND_SYMBOLS,
|
||||
s->tmp_tree, storage_ix, storage);
|
||||
}
|
||||
BrotliStoreHuffmanTree(&depth[64], 64, tree, storage_ix, storage);
|
||||
BrotliStoreHuffmanTree(&s->cmd_depth[64], 64, s->tmp_tree, storage_ix,
|
||||
storage);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void EmitInsertLen(
|
||||
@@ -330,6 +319,8 @@ trawl:
|
||||
ip += matched;
|
||||
BROTLI_DCHECK(0 == memcmp(base, candidate, matched));
|
||||
EmitInsertLen((uint32_t)insert, commands);
|
||||
BROTLI_LOG(("[CompressFragment] pos = %d insert = %d copy = %d\n",
|
||||
(int)(next_emit - base_ip), insert, 2));
|
||||
memcpy(*literals, next_emit, (size_t)insert);
|
||||
*literals += insert;
|
||||
if (distance == last_distance) {
|
||||
@@ -340,6 +331,12 @@ trawl:
|
||||
last_distance = distance;
|
||||
}
|
||||
EmitCopyLenLastDistance(matched, commands);
|
||||
BROTLI_LOG(("[CompressFragment] pos = %d distance = %d\n"
|
||||
"[CompressFragment] pos = %d insert = %d copy = %d\n"
|
||||
"[CompressFragment] pos = %d distance = %d\n",
|
||||
(int)(base - base_ip), (int)distance,
|
||||
(int)(base - base_ip) + 2, 0, (int)matched - 2,
|
||||
(int)(base - base_ip) + 2, (int)distance));
|
||||
|
||||
next_emit = ip;
|
||||
if (BROTLI_PREDICT_FALSE(ip >= ip_limit)) {
|
||||
@@ -395,6 +392,10 @@ trawl:
|
||||
BROTLI_DCHECK(0 == memcmp(base, candidate, matched));
|
||||
EmitCopyLen(matched, commands);
|
||||
EmitDistance((uint32_t)last_distance, commands);
|
||||
BROTLI_LOG(("[CompressFragment] pos = %d insert = %d copy = %d\n"
|
||||
"[CompressFragment] pos = %d distance = %d\n",
|
||||
(int)(base - base_ip), 0, (int)matched,
|
||||
(int)(base - base_ip), (int)last_distance));
|
||||
|
||||
next_emit = ip;
|
||||
if (BROTLI_PREDICT_FALSE(ip >= ip_limit)) {
|
||||
@@ -447,70 +448,71 @@ emit_remainder:
|
||||
if (next_emit < ip_end) {
|
||||
const uint32_t insert = (uint32_t)(ip_end - next_emit);
|
||||
EmitInsertLen(insert, commands);
|
||||
BROTLI_LOG(("[CompressFragment] pos = %d insert = %d copy = %d\n",
|
||||
(int)(next_emit - base_ip), insert, 2));
|
||||
memcpy(*literals, next_emit, insert);
|
||||
*literals += insert;
|
||||
}
|
||||
}
|
||||
|
||||
static void StoreCommands(MemoryManager* m,
|
||||
static void StoreCommands(BrotliTwoPassArena* s,
|
||||
const uint8_t* literals, const size_t num_literals,
|
||||
const uint32_t* commands, const size_t num_commands,
|
||||
size_t* storage_ix, uint8_t* storage) {
|
||||
static const uint32_t kNumExtraBits[128] = {
|
||||
0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 8, 9, 10, 12, 14, 24,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 8, 9, 10, 24,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8,
|
||||
9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16,
|
||||
17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24,
|
||||
static const BROTLI_MODEL("small") uint32_t kNumExtraBits[128] = {
|
||||
0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5,
|
||||
6, 7, 8, 9, 10, 12, 14, 24, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 1, 2, 2, 3, 3, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 8, 9, 10, 24,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8,
|
||||
9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16,
|
||||
17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24,
|
||||
};
|
||||
static const uint32_t kInsertOffset[24] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 8, 10, 14, 18, 26, 34, 50, 66, 98, 130, 194, 322, 578,
|
||||
1090, 2114, 6210, 22594,
|
||||
static const BROTLI_MODEL("small") uint32_t kInsertOffset[24] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 8, 10, 14, 18, 26,
|
||||
34, 50, 66, 98, 130, 194, 322, 578, 1090, 2114, 6210, 22594,
|
||||
};
|
||||
|
||||
uint8_t lit_depths[256];
|
||||
uint16_t lit_bits[256];
|
||||
uint32_t lit_histo[256] = { 0 };
|
||||
uint8_t cmd_depths[128] = { 0 };
|
||||
uint16_t cmd_bits[128] = { 0 };
|
||||
uint32_t cmd_histo[128] = { 0 };
|
||||
size_t i;
|
||||
memset(s->lit_histo, 0, sizeof(s->lit_histo));
|
||||
/* TODO(eustas): is that necessary? */
|
||||
memset(s->cmd_depth, 0, sizeof(s->cmd_depth));
|
||||
/* TODO(eustas): is that necessary? */
|
||||
memset(s->cmd_bits, 0, sizeof(s->cmd_bits));
|
||||
memset(s->cmd_histo, 0, sizeof(s->cmd_histo));
|
||||
for (i = 0; i < num_literals; ++i) {
|
||||
++lit_histo[literals[i]];
|
||||
++s->lit_histo[literals[i]];
|
||||
}
|
||||
BrotliBuildAndStoreHuffmanTreeFast(m, lit_histo, num_literals,
|
||||
/* max_bits = */ 8,
|
||||
lit_depths, lit_bits,
|
||||
storage_ix, storage);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
BrotliBuildAndStoreHuffmanTreeFast(s->tmp_tree, s->lit_histo, num_literals,
|
||||
/* max_bits = */ 8, s->lit_depth,
|
||||
s->lit_bits, storage_ix, storage);
|
||||
|
||||
for (i = 0; i < num_commands; ++i) {
|
||||
const uint32_t code = commands[i] & 0xFF;
|
||||
BROTLI_DCHECK(code < 128);
|
||||
++cmd_histo[code];
|
||||
++s->cmd_histo[code];
|
||||
}
|
||||
cmd_histo[1] += 1;
|
||||
cmd_histo[2] += 1;
|
||||
cmd_histo[64] += 1;
|
||||
cmd_histo[84] += 1;
|
||||
BuildAndStoreCommandPrefixCode(cmd_histo, cmd_depths, cmd_bits,
|
||||
storage_ix, storage);
|
||||
s->cmd_histo[1] += 1;
|
||||
s->cmd_histo[2] += 1;
|
||||
s->cmd_histo[64] += 1;
|
||||
s->cmd_histo[84] += 1;
|
||||
BuildAndStoreCommandPrefixCode(s, storage_ix, storage);
|
||||
|
||||
for (i = 0; i < num_commands; ++i) {
|
||||
const uint32_t cmd = commands[i];
|
||||
const uint32_t code = cmd & 0xFF;
|
||||
const uint32_t extra = cmd >> 8;
|
||||
BROTLI_DCHECK(code < 128);
|
||||
BrotliWriteBits(cmd_depths[code], cmd_bits[code], storage_ix, storage);
|
||||
BrotliWriteBits(s->cmd_depth[code], s->cmd_bits[code], storage_ix, storage);
|
||||
BrotliWriteBits(kNumExtraBits[code], extra, storage_ix, storage);
|
||||
if (code < 24) {
|
||||
const uint32_t insert = kInsertOffset[code] + extra;
|
||||
uint32_t j;
|
||||
for (j = 0; j < insert; ++j) {
|
||||
const uint8_t lit = *literals;
|
||||
BrotliWriteBits(lit_depths[lit], lit_bits[lit], storage_ix, storage);
|
||||
BrotliWriteBits(s->lit_depth[lit], s->lit_bits[lit], storage_ix,
|
||||
storage);
|
||||
++literals;
|
||||
}
|
||||
}
|
||||
@@ -521,19 +523,20 @@ static void StoreCommands(MemoryManager* m,
|
||||
#define MIN_RATIO 0.98
|
||||
#define SAMPLE_RATE 43
|
||||
|
||||
static BROTLI_BOOL ShouldCompress(
|
||||
static BROTLI_BOOL ShouldCompress(BrotliTwoPassArena* s,
|
||||
const uint8_t* input, size_t input_size, size_t num_literals) {
|
||||
double corpus_size = (double)input_size;
|
||||
if (num_literals < MIN_RATIO * corpus_size) {
|
||||
if ((double)num_literals < MIN_RATIO * corpus_size) {
|
||||
return BROTLI_TRUE;
|
||||
} else {
|
||||
uint32_t literal_histo[256] = { 0 };
|
||||
const double max_total_bit_cost = corpus_size * 8 * MIN_RATIO / SAMPLE_RATE;
|
||||
size_t i;
|
||||
memset(s->lit_histo, 0, sizeof(s->lit_histo));
|
||||
for (i = 0; i < input_size; i += SAMPLE_RATE) {
|
||||
++literal_histo[input[i]];
|
||||
++s->lit_histo[input[i]];
|
||||
}
|
||||
return TO_BROTLI_BOOL(BitsEntropy(literal_histo, 256) < max_total_bit_cost);
|
||||
return TO_BROTLI_BOOL(
|
||||
BrotliBitsEntropy(s->lit_histo, 256) < max_total_bit_cost);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -555,7 +558,7 @@ static void EmitUncompressedMetaBlock(const uint8_t* input, size_t input_size,
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void BrotliCompressFragmentTwoPassImpl(
|
||||
MemoryManager* m, const uint8_t* input, size_t input_size,
|
||||
BrotliTwoPassArena* s, const uint8_t* input, size_t input_size,
|
||||
BROTLI_BOOL is_last, uint32_t* command_buf, uint8_t* literal_buf,
|
||||
int* table, size_t table_bits, size_t min_match,
|
||||
size_t* storage_ix, uint8_t* storage) {
|
||||
@@ -573,14 +576,13 @@ static BROTLI_INLINE void BrotliCompressFragmentTwoPassImpl(
|
||||
CreateCommands(input, block_size, input_size, base_ip, table,
|
||||
table_bits, min_match, &literals, &commands);
|
||||
num_literals = (size_t)(literals - literal_buf);
|
||||
if (ShouldCompress(input, block_size, num_literals)) {
|
||||
if (ShouldCompress(s, input, block_size, num_literals)) {
|
||||
const size_t num_commands = (size_t)(commands - command_buf);
|
||||
BrotliStoreMetaBlockHeader(block_size, 0, storage_ix, storage);
|
||||
/* No block splits, no contexts. */
|
||||
BrotliWriteBits(13, 0, storage_ix, storage);
|
||||
StoreCommands(m, literal_buf, num_literals, command_buf, num_commands,
|
||||
StoreCommands(s, literal_buf, num_literals, command_buf, num_commands,
|
||||
storage_ix, storage);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
} else {
|
||||
/* Since we did not find many backward references and the entropy of
|
||||
the data is close to 8 bits, we can simply emit an uncompressed block.
|
||||
@@ -597,18 +599,18 @@ static BROTLI_INLINE void BrotliCompressFragmentTwoPassImpl(
|
||||
|
||||
#define BAKE_METHOD_PARAM_(B) \
|
||||
static BROTLI_NOINLINE void BrotliCompressFragmentTwoPassImpl ## B( \
|
||||
MemoryManager* m, const uint8_t* input, size_t input_size, \
|
||||
BrotliTwoPassArena* s, const uint8_t* input, size_t input_size, \
|
||||
BROTLI_BOOL is_last, uint32_t* command_buf, uint8_t* literal_buf, \
|
||||
int* table, size_t* storage_ix, uint8_t* storage) { \
|
||||
size_t min_match = (B <= 15) ? 4 : 6; \
|
||||
BrotliCompressFragmentTwoPassImpl(m, input, input_size, is_last, command_buf,\
|
||||
BrotliCompressFragmentTwoPassImpl(s, input, input_size, is_last, command_buf,\
|
||||
literal_buf, table, B, min_match, storage_ix, storage); \
|
||||
}
|
||||
FOR_TABLE_BITS_(BAKE_METHOD_PARAM_)
|
||||
#undef BAKE_METHOD_PARAM_
|
||||
|
||||
void BrotliCompressFragmentTwoPass(
|
||||
MemoryManager* m, const uint8_t* input, size_t input_size,
|
||||
BrotliTwoPassArena* s, const uint8_t* input, size_t input_size,
|
||||
BROTLI_BOOL is_last, uint32_t* command_buf, uint8_t* literal_buf,
|
||||
int* table, size_t table_size, size_t* storage_ix, uint8_t* storage) {
|
||||
const size_t initial_storage_ix = *storage_ix;
|
||||
@@ -617,7 +619,7 @@ void BrotliCompressFragmentTwoPass(
|
||||
#define CASE_(B) \
|
||||
case B: \
|
||||
BrotliCompressFragmentTwoPassImpl ## B( \
|
||||
m, input, input_size, is_last, command_buf, \
|
||||
s, input, input_size, is_last, command_buf, \
|
||||
literal_buf, table, storage_ix, storage); \
|
||||
break;
|
||||
FOR_TABLE_BITS_(CASE_)
|
||||
|
||||
@@ -13,16 +13,32 @@
|
||||
#ifndef BROTLI_ENC_COMPRESS_FRAGMENT_TWO_PASS_H_
|
||||
#define BROTLI_ENC_COMPRESS_FRAGMENT_TWO_PASS_H_
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./memory.h"
|
||||
#include "entropy_encode.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* TODO(eustas): turn to macro. */
|
||||
static const size_t kCompressFragmentTwoPassBlockSize = 1 << 17;
|
||||
|
||||
typedef struct BrotliTwoPassArena {
|
||||
uint32_t lit_histo[256];
|
||||
uint8_t lit_depth[256];
|
||||
uint16_t lit_bits[256];
|
||||
|
||||
uint32_t cmd_histo[128];
|
||||
uint8_t cmd_depth[128];
|
||||
uint16_t cmd_bits[128];
|
||||
|
||||
/* BuildAndStoreCommandPrefixCode */
|
||||
HuffmanTree tmp_tree[2 * BROTLI_NUM_LITERAL_SYMBOLS + 1];
|
||||
uint8_t tmp_depth[BROTLI_NUM_COMMAND_SYMBOLS];
|
||||
uint16_t tmp_bits[64];
|
||||
} BrotliTwoPassArena;
|
||||
|
||||
/* Compresses "input" string to the "*storage" buffer as one or more complete
|
||||
meta-blocks, and updates the "*storage_ix" bit position.
|
||||
|
||||
@@ -36,7 +52,7 @@ static const size_t kCompressFragmentTwoPassBlockSize = 1 << 17;
|
||||
REQUIRES: "table_size" is a power of two
|
||||
OUTPUT: maximal copy distance <= |input_size|
|
||||
OUTPUT: maximal copy distance <= BROTLI_MAX_BACKWARD_LIMIT(18) */
|
||||
BROTLI_INTERNAL void BrotliCompressFragmentTwoPass(MemoryManager* m,
|
||||
BROTLI_INTERNAL void BrotliCompressFragmentTwoPass(BrotliTwoPassArena* s,
|
||||
const uint8_t* input,
|
||||
size_t input_size,
|
||||
BROTLI_BOOL is_last,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,13 +9,34 @@
|
||||
#ifndef BROTLI_ENC_DICTIONARY_HASH_H_
|
||||
#define BROTLI_ENC_DICTIONARY_HASH_H_
|
||||
|
||||
#include <brotli/types.h>
|
||||
#include "../common/platform.h"
|
||||
#include "../common/static_init.h"
|
||||
|
||||
#if (BROTLI_STATIC_INIT != BROTLI_STATIC_INIT_NONE)
|
||||
#include "../common/dictionary.h"
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern const uint16_t kStaticDictionaryHash[32768];
|
||||
/* Bucket is (Hash14 * 2 + length_lt_8); in other words we reserve 2 buckets
|
||||
for each hash - one for shorter words and one for longer words. */
|
||||
#define BROTLI_ENC_NUM_HASH_BUCKETS 32768
|
||||
|
||||
#if (BROTLI_STATIC_INIT != BROTLI_STATIC_INIT_NONE)
|
||||
BROTLI_BOOL BROTLI_INTERNAL BrotliEncoderInitDictionaryHash(
|
||||
const BrotliDictionary* dictionary, uint16_t* words, uint8_t* lengths);
|
||||
BROTLI_INTERNAL extern BROTLI_MODEL("small") uint16_t
|
||||
kStaticDictionaryHashWords[BROTLI_ENC_NUM_HASH_BUCKETS];
|
||||
BROTLI_INTERNAL extern BROTLI_MODEL("small") uint8_t
|
||||
kStaticDictionaryHashLengths[BROTLI_ENC_NUM_HASH_BUCKETS];
|
||||
#else
|
||||
BROTLI_INTERNAL extern const BROTLI_MODEL("small") uint16_t
|
||||
kStaticDictionaryHashWords[BROTLI_ENC_NUM_HASH_BUCKETS];
|
||||
BROTLI_INTERNAL extern const BROTLI_MODEL("small") uint8_t
|
||||
kStaticDictionaryHashLengths[BROTLI_ENC_NUM_HASH_BUCKETS];
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
|
||||
1829
c/enc/dictionary_hash_inc.h
Normal file
1829
c/enc/dictionary_hash_inc.h
Normal file
File diff suppressed because it is too large
Load Diff
1051
c/enc/encode.c
1051
c/enc/encode.c
File diff suppressed because it is too large
Load Diff
622
c/enc/encoder_dict.c
Executable file → Normal file
622
c/enc/encoder_dict.c
Executable file → Normal file
@@ -4,29 +4,639 @@
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "./encoder_dict.h"
|
||||
#include "encoder_dict.h"
|
||||
|
||||
#include "../common/dictionary.h"
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/shared_dictionary.h>
|
||||
#include "../common/shared_dictionary_internal.h"
|
||||
#include "../common/transform.h"
|
||||
#include "./dictionary_hash.h"
|
||||
#include "./hash.h"
|
||||
#include <brotli/encode.h>
|
||||
#include "compound_dictionary.h"
|
||||
#include "dictionary_hash.h"
|
||||
#include "hash_base.h"
|
||||
#include "hash.h"
|
||||
#include "memory.h"
|
||||
#include "quality.h"
|
||||
#include "static_dict_lut.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void BrotliInitEncoderDictionary(BrotliEncoderDictionary* dict) {
|
||||
dict->words = BrotliGetDictionary();
|
||||
#define NUM_HASH_BITS 15u
|
||||
#define NUM_HASH_BUCKETS (1u << NUM_HASH_BITS)
|
||||
|
||||
dict->hash_table = kStaticDictionaryHash;
|
||||
static void BrotliTrieInit(BrotliTrie* trie) {
|
||||
trie->pool_capacity = 0;
|
||||
trie->pool_size = 0;
|
||||
trie->pool = 0;
|
||||
|
||||
/* Set up the root node */
|
||||
trie->root.single = 0;
|
||||
trie->root.len_ = 0;
|
||||
trie->root.idx_ = 0;
|
||||
trie->root.sub = 0;
|
||||
}
|
||||
|
||||
static void BrotliTrieFree(MemoryManager* m, BrotliTrie* trie) {
|
||||
BrotliFree(m, trie->pool);
|
||||
}
|
||||
|
||||
/* Initializes to RFC 7932 static dictionary / transforms. */
|
||||
static void InitEncoderDictionary(BrotliEncoderDictionary* dict) {
|
||||
dict->words = BrotliGetDictionary();
|
||||
dict->num_transforms = (uint32_t)BrotliGetTransforms()->num_transforms;
|
||||
|
||||
dict->hash_table_words = kStaticDictionaryHashWords;
|
||||
dict->hash_table_lengths = kStaticDictionaryHashLengths;
|
||||
dict->buckets = kStaticDictionaryBuckets;
|
||||
dict->dict_words = kStaticDictionaryWords;
|
||||
|
||||
dict->cutoffTransformsCount = kCutoffTransformsCount;
|
||||
dict->cutoffTransforms = kCutoffTransforms;
|
||||
|
||||
dict->parent = 0;
|
||||
|
||||
dict->hash_table_data_words_ = 0;
|
||||
dict->hash_table_data_lengths_ = 0;
|
||||
dict->buckets_alloc_size_ = 0;
|
||||
dict->buckets_data_ = 0;
|
||||
dict->dict_words_alloc_size_ = 0;
|
||||
dict->dict_words_data_ = 0;
|
||||
dict->words_instance_ = 0;
|
||||
dict->has_words_heavy = BROTLI_FALSE;
|
||||
BrotliTrieInit(&dict->trie);
|
||||
}
|
||||
|
||||
static void BrotliDestroyEncoderDictionary(MemoryManager* m,
|
||||
BrotliEncoderDictionary* dict) {
|
||||
BrotliFree(m, dict->hash_table_data_words_);
|
||||
BrotliFree(m, dict->hash_table_data_lengths_);
|
||||
BrotliFree(m, dict->buckets_data_);
|
||||
BrotliFree(m, dict->dict_words_data_);
|
||||
BrotliFree(m, dict->words_instance_);
|
||||
BrotliTrieFree(m, &dict->trie);
|
||||
}
|
||||
|
||||
#if defined(BROTLI_EXPERIMENTAL)
|
||||
/* Word length must be at least 4 bytes */
|
||||
static uint32_t Hash(const uint8_t* data, int bits) {
|
||||
uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kHashMul32;
|
||||
/* The higher bits contain more mixture from the multiplication,
|
||||
so we take our results from there. */
|
||||
return h >> (32 - bits);
|
||||
}
|
||||
|
||||
/* Theoretical max possible word size after transform */
|
||||
#define kTransformedBufferSize \
|
||||
(256 + 256 + SHARED_BROTLI_MAX_DICTIONARY_WORD_LENGTH)
|
||||
|
||||
/* To be safe buffer must have at least kTransformedBufferSize */
|
||||
static void TransformedDictionaryWord(uint32_t word_idx, int len, int transform,
|
||||
const BrotliTransforms* transforms,
|
||||
const BrotliEncoderDictionary* dict,
|
||||
uint8_t* buffer, size_t* size) {
|
||||
const uint8_t* dict_word = &dict->words->data[
|
||||
dict->words->offsets_by_length[len] + (uint32_t)len * word_idx];
|
||||
*size = (size_t)BrotliTransformDictionaryWord(buffer, dict_word, len,
|
||||
transforms, transform);
|
||||
}
|
||||
|
||||
static DictWord MakeDictWord(uint8_t len, uint8_t transform, uint16_t idx) {
|
||||
DictWord result;
|
||||
result.len = len;
|
||||
result.transform = transform;
|
||||
result.idx = idx;
|
||||
return result;
|
||||
}
|
||||
|
||||
static uint32_t BrotliTrieAlloc(MemoryManager* m, size_t num, BrotliTrie* trie,
|
||||
BrotliTrieNode** keep) {
|
||||
uint32_t result;
|
||||
uint32_t keep_index = 0;
|
||||
if (keep && *keep != &trie->root) {
|
||||
/* Optional node to keep, since address may change after re-allocating */
|
||||
keep_index = (uint32_t)(*keep - trie->pool);
|
||||
}
|
||||
if (trie->pool_size == 0) {
|
||||
/* Have a placeholder node in the front. We do not want the result to be 0,
|
||||
it must be at least 1, 0 represents "null pointer" */
|
||||
trie->pool_size = 1;
|
||||
}
|
||||
BROTLI_ENSURE_CAPACITY(m, BrotliTrieNode, trie->pool, trie->pool_capacity,
|
||||
trie->pool_size + num);
|
||||
if (BROTLI_IS_OOM(m)) return 0;
|
||||
/* Init the new nodes to empty */
|
||||
memset(trie->pool + trie->pool_size, 0, sizeof(*trie->pool) * num);
|
||||
result = (uint32_t)trie->pool_size;
|
||||
trie->pool_size += num;
|
||||
if (keep && *keep != &trie->root) {
|
||||
*keep = trie->pool + keep_index;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* len and idx: payload for last node
|
||||
* word, size: the string
|
||||
* index: position in the string
|
||||
*/
|
||||
static BROTLI_BOOL BrotliTrieNodeAdd(MemoryManager* m, uint8_t len,
|
||||
uint32_t idx, const uint8_t* word, size_t size, int index,
|
||||
BrotliTrieNode* node, BrotliTrie* trie) {
|
||||
BrotliTrieNode* child = 0;
|
||||
uint8_t c;
|
||||
if ((size_t)index == size) {
|
||||
if (!node->len_ || idx < node->idx_) {
|
||||
node->len_ = len;
|
||||
node->idx_ = idx;
|
||||
}
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
c = word[index];
|
||||
if (node->single && c != node->c) {
|
||||
BrotliTrieNode old = trie->pool[node->sub];
|
||||
uint32_t new_nodes = BrotliTrieAlloc(m, 32, trie, &node);
|
||||
if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
|
||||
node->single = 0;
|
||||
node->sub = new_nodes;
|
||||
trie->pool[node->sub + (node->c >> 4)].sub = new_nodes + 16;
|
||||
trie->pool[trie->pool[node->sub + (node->c >> 4)].sub + (node->c & 15)] =
|
||||
old;
|
||||
}
|
||||
if (!node->sub) {
|
||||
uint32_t new_node = BrotliTrieAlloc(m, 1, trie, &node);
|
||||
if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
|
||||
node->single = 1;
|
||||
node->c = c;
|
||||
node->sub = new_node;
|
||||
}
|
||||
if (node->single) {
|
||||
child = &trie->pool[node->sub];
|
||||
} else {
|
||||
if (!trie->pool[node->sub + (c >> 4)].sub) {
|
||||
uint32_t new_nodes = BrotliTrieAlloc(m, 16, trie, &node);
|
||||
if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
|
||||
trie->pool[node->sub + (c >> 4)].sub = new_nodes;
|
||||
}
|
||||
child = &trie->pool[trie->pool[node->sub + (c >> 4)].sub + (c & 15)];
|
||||
}
|
||||
return BrotliTrieNodeAdd(m, len, idx, word, size, index + 1, child, trie);
|
||||
}
|
||||
|
||||
static BROTLI_BOOL BrotliTrieAdd(MemoryManager* m, uint8_t len, uint32_t idx,
|
||||
const uint8_t* word, size_t size, BrotliTrie* trie) {
|
||||
return BrotliTrieNodeAdd(m, len, idx, word, size, 0, &trie->root, trie);
|
||||
}
|
||||
|
||||
const BrotliTrieNode* BrotliTrieSub(const BrotliTrie* trie,
|
||||
const BrotliTrieNode* node, uint8_t c) {
|
||||
BrotliTrieNode* temp_node;
|
||||
if (node->single) {
|
||||
if (node->c == c) return &trie->pool[node->sub];
|
||||
return 0;
|
||||
}
|
||||
if (!node->sub) return 0;
|
||||
temp_node = &trie->pool[node->sub + (c >> 4)];
|
||||
if (!temp_node->sub) return 0;
|
||||
return &trie->pool[temp_node->sub + (c & 15)];
|
||||
}
|
||||
|
||||
static const BrotliTrieNode* BrotliTrieFind(const BrotliTrie* trie,
|
||||
const uint8_t* word, size_t size) {
|
||||
const BrotliTrieNode* node = &trie->root;
|
||||
size_t i;
|
||||
for (i = 0; i < size; i++) {
|
||||
node = BrotliTrieSub(trie, node, word[i]);
|
||||
if (!node) return 0;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
static BROTLI_BOOL BuildDictionaryLut(MemoryManager* m,
|
||||
const BrotliTransforms* transforms,
|
||||
BrotliEncoderDictionary* dict) {
|
||||
uint32_t i;
|
||||
DictWord* dict_words;
|
||||
uint16_t* buckets;
|
||||
DictWord** words_by_hash;
|
||||
size_t* words_by_hash_size;
|
||||
size_t* words_by_hash_capacity;
|
||||
BrotliTrie dedup;
|
||||
uint8_t word[kTransformedBufferSize];
|
||||
size_t word_size;
|
||||
size_t total = 0;
|
||||
uint8_t l;
|
||||
uint16_t idx;
|
||||
|
||||
BrotliTrieInit(&dedup);
|
||||
|
||||
words_by_hash = (DictWord**)BrotliAllocate(m,
|
||||
sizeof(*words_by_hash) * NUM_HASH_BUCKETS);
|
||||
words_by_hash_size = (size_t*)BrotliAllocate(m,
|
||||
sizeof(*words_by_hash_size) * NUM_HASH_BUCKETS);
|
||||
words_by_hash_capacity = (size_t*)BrotliAllocate(m,
|
||||
sizeof(*words_by_hash_capacity) * NUM_HASH_BUCKETS);
|
||||
if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
|
||||
memset(words_by_hash, 0, sizeof(*words_by_hash) * NUM_HASH_BUCKETS);
|
||||
memset(words_by_hash_size, 0, sizeof(*words_by_hash_size) * NUM_HASH_BUCKETS);
|
||||
memset(words_by_hash_capacity, 0,
|
||||
sizeof(*words_by_hash_capacity) * NUM_HASH_BUCKETS);
|
||||
|
||||
if (transforms->num_transforms > 0) {
|
||||
for (l = SHARED_BROTLI_MIN_DICTIONARY_WORD_LENGTH;
|
||||
l <= SHARED_BROTLI_MAX_DICTIONARY_WORD_LENGTH; ++l) {
|
||||
uint16_t n = dict->words->size_bits_by_length[l] ?
|
||||
(uint16_t)(1 << dict->words->size_bits_by_length[l]) : 0u;
|
||||
for (idx = 0; idx < n; ++idx) {
|
||||
uint32_t key;
|
||||
/* First transform (usually identity) */
|
||||
TransformedDictionaryWord(idx, l, 0, transforms, dict, word,
|
||||
&word_size);
|
||||
/* Cannot hash words smaller than 4 bytes */
|
||||
if (word_size < 4) {
|
||||
/* Break instead of continue, all next words of this length will have
|
||||
same length after transform */
|
||||
break;
|
||||
}
|
||||
if (!BrotliTrieAdd(m, 0, idx, word, word_size, &dedup)) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
key = Hash(word, NUM_HASH_BITS);
|
||||
BROTLI_ENSURE_CAPACITY_APPEND(m, DictWord, words_by_hash[key],
|
||||
words_by_hash_capacity[key], words_by_hash_size[key],
|
||||
MakeDictWord(l, 0, idx));
|
||||
++total;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* These LUT transforms only supported if no custom transforms. This is
|
||||
ok, we will use the heavy trie instead. */
|
||||
if (transforms == BrotliGetTransforms()) {
|
||||
for (l = SHARED_BROTLI_MIN_DICTIONARY_WORD_LENGTH;
|
||||
l <= SHARED_BROTLI_MAX_DICTIONARY_WORD_LENGTH; ++l) {
|
||||
uint16_t n = dict->words->size_bits_by_length[l] ?
|
||||
(uint16_t)(1 << dict->words->size_bits_by_length[l]) : 0u;
|
||||
for (idx = 0; idx < n; ++idx) {
|
||||
int k;
|
||||
BROTLI_BOOL is_ascii = BROTLI_TRUE;
|
||||
size_t offset = dict->words->offsets_by_length[l] + (size_t)l * idx;
|
||||
const uint8_t* data = &dict->words->data[offset];
|
||||
for (k = 0; k < l; ++k) {
|
||||
if (data[k] >= 128) is_ascii = BROTLI_FALSE;
|
||||
}
|
||||
if (data[0] < 128) {
|
||||
int transform = 9; /* {empty, uppercase first, empty} */
|
||||
uint32_t ix = idx + (uint32_t)transform * n;
|
||||
const BrotliTrieNode* it;
|
||||
TransformedDictionaryWord(idx, l, transform, transforms,
|
||||
dict, word, &word_size);
|
||||
it = BrotliTrieFind(&dedup, word, word_size);
|
||||
if (!it || it->idx_ > ix) {
|
||||
uint32_t key = Hash(word, NUM_HASH_BITS);
|
||||
if (!BrotliTrieAdd(m, 0, ix, word, word_size, &dedup)) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
BROTLI_ENSURE_CAPACITY_APPEND(m, DictWord, words_by_hash[key],
|
||||
words_by_hash_capacity[key], words_by_hash_size[key],
|
||||
MakeDictWord(l, BROTLI_TRANSFORM_UPPERCASE_FIRST, idx));
|
||||
++total;
|
||||
}
|
||||
}
|
||||
if (is_ascii) {
|
||||
int transform = 44; /* {empty, uppercase all, empty} */
|
||||
uint32_t ix = idx + (uint32_t)transform * n;
|
||||
const BrotliTrieNode* it;
|
||||
TransformedDictionaryWord(idx, l, transform, transforms,
|
||||
dict, word, &word_size);
|
||||
it = BrotliTrieFind(&dedup, word, word_size);
|
||||
if (!it || it->idx_ > ix) {
|
||||
uint32_t key = Hash(word, NUM_HASH_BITS);
|
||||
if (!BrotliTrieAdd(m, 0, ix, word, word_size, &dedup)) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
BROTLI_ENSURE_CAPACITY_APPEND(m, DictWord, words_by_hash[key],
|
||||
words_by_hash_capacity[key], words_by_hash_size[key],
|
||||
MakeDictWord(l, BROTLI_TRANSFORM_UPPERCASE_ALL, idx));
|
||||
++total;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dict_words = (DictWord*)BrotliAllocate(m,
|
||||
sizeof(*dict->dict_words) * (total + 1));
|
||||
buckets = (uint16_t*)BrotliAllocate(m,
|
||||
sizeof(*dict->buckets) * NUM_HASH_BUCKETS);
|
||||
if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
|
||||
dict->dict_words_alloc_size_ = total + 1;
|
||||
dict->dict_words = dict->dict_words_data_ = dict_words;
|
||||
dict->buckets_alloc_size_ = NUM_HASH_BUCKETS;
|
||||
dict->buckets = dict->buckets_data_ = buckets;
|
||||
|
||||
/* Unused; makes offsets start from 1. */
|
||||
dict_words[0] = MakeDictWord(0, 0, 0);
|
||||
total = 1;
|
||||
for (i = 0; i < NUM_HASH_BUCKETS; ++i) {
|
||||
size_t num_words = words_by_hash_size[i];
|
||||
if (num_words > 0) {
|
||||
buckets[i] = (uint16_t)(total);
|
||||
memcpy(&dict_words[total], &words_by_hash[i][0],
|
||||
sizeof(dict_words[0]) * num_words);
|
||||
total += num_words;
|
||||
dict_words[total - 1].len |= 0x80;
|
||||
} else {
|
||||
buckets[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < NUM_HASH_BUCKETS; ++i) {
|
||||
BrotliFree(m, words_by_hash[i]);
|
||||
}
|
||||
BrotliFree(m, words_by_hash);
|
||||
BrotliFree(m, words_by_hash_size);
|
||||
BrotliFree(m, words_by_hash_capacity);
|
||||
BrotliTrieFree(m, &dedup);
|
||||
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
|
||||
static void BuildDictionaryHashTable(uint16_t* hash_table_words,
|
||||
uint8_t* hash_table_lengths, const BrotliDictionary* dict) {
|
||||
int j, len;
|
||||
/* The order of the loops is such that in case of collision, words with
|
||||
shorter length are preferred, and in case of same length, words with
|
||||
smaller index. There is only a single word per bucket. */
|
||||
/* TODO(lode): consider adding optional user-supplied frequency_map to use
|
||||
for preferred words instead, this can make the encoder better for
|
||||
quality 9 and below without affecting the decoder */
|
||||
memset(hash_table_words, 0, sizeof(kStaticDictionaryHashWords));
|
||||
memset(hash_table_lengths, 0, sizeof(kStaticDictionaryHashLengths));
|
||||
for (len = SHARED_BROTLI_MAX_DICTIONARY_WORD_LENGTH;
|
||||
len >= SHARED_BROTLI_MIN_DICTIONARY_WORD_LENGTH; --len) {
|
||||
const size_t num_words = dict->size_bits_by_length[len] ?
|
||||
(1u << dict->size_bits_by_length[len]) : 0;
|
||||
for (j = (int)num_words - 1; j >= 0; --j) {
|
||||
size_t offset = dict->offsets_by_length[len] +
|
||||
(size_t)len * (size_t)j;
|
||||
const uint8_t* word = &dict->data[offset];
|
||||
const uint32_t key = Hash(word, 14);
|
||||
int idx = (int)(key << 1) + (len < 8 ? 1 : 0);
|
||||
BROTLI_DCHECK(idx < (int)NUM_HASH_BUCKETS);
|
||||
hash_table_words[idx] = (uint16_t)j;
|
||||
hash_table_lengths[idx] = (uint8_t)len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static BROTLI_BOOL GenerateWordsHeavy(MemoryManager* m,
|
||||
const BrotliTransforms* transforms,
|
||||
BrotliEncoderDictionary* dict) {
|
||||
int i, j, l;
|
||||
for (j = (int)transforms->num_transforms - 1; j >= 0 ; --j) {
|
||||
for (l = 0; l < 32; l++) {
|
||||
int num = (int)((1u << dict->words->size_bits_by_length[l]) & ~1u);
|
||||
for (i = 0; i < num; i++) {
|
||||
uint8_t transformed[kTransformedBufferSize];
|
||||
size_t size;
|
||||
TransformedDictionaryWord(
|
||||
(uint32_t)i, l, j, transforms, dict, transformed, &size);
|
||||
if (size < 4) continue;
|
||||
if (!BrotliTrieAdd(m, (uint8_t)l, (uint32_t)(i + num * j),
|
||||
transformed, size, &dict->trie)) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
|
||||
/* Computes cutoffTransformsCount (in count) and cutoffTransforms (in data) for
|
||||
the custom transforms, where possible within the limits of the
|
||||
cutoffTransforms encoding. The fast encoder uses this to do fast lookup for
|
||||
transforms that remove the N last characters (OmitLast). */
|
||||
static void ComputeCutoffTransforms(
|
||||
const BrotliTransforms* transforms,
|
||||
uint32_t* count, uint64_t* data) {
|
||||
int i;
|
||||
/* The encoding in a 64-bit integer of transform N in the data is: (N << 2) +
|
||||
((cutoffTransforms >> (N * 6)) & 0x3F), so for example the identity
|
||||
transform code must be 0-63, for N=1 the transform code must be 4-67, ...,
|
||||
for N=9 it must be 36-99.
|
||||
TODO(lode): consider a simple flexible uint8_t[10] instead of the uint64_t
|
||||
for the cutoff transforms, so that shared dictionaries can have the
|
||||
OmitLast transforms anywhere without loss. */
|
||||
*count = 0;
|
||||
*data = 0;
|
||||
for (i = 0; i < BROTLI_TRANSFORMS_MAX_CUT_OFF + 1; i++) {
|
||||
int idx = transforms->cutOffTransforms[i];
|
||||
if (idx == -1) break; /* Not found */
|
||||
if (idx < (i << 2)) break; /* Too small for the encoding */
|
||||
if (idx >= (i << 2) + 64) break; /* Too large for the encoding */
|
||||
(*count)++;
|
||||
*data |= (uint64_t)(((uint64_t)idx -
|
||||
((uint64_t)i << 2u)) << ((uint64_t)i * 6u));
|
||||
}
|
||||
}
|
||||
|
||||
static BROTLI_BOOL ComputeDictionary(MemoryManager* m, int quality,
|
||||
const BrotliTransforms* transforms,
|
||||
BrotliEncoderDictionary* current) {
|
||||
int default_words = current->words == BrotliGetDictionary();
|
||||
int default_transforms = transforms == BrotliGetTransforms();
|
||||
|
||||
if (default_words && default_transforms) {
|
||||
/* hashes are already set to Brotli defaults */
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
|
||||
current->hash_table_data_words_ = (uint16_t*)BrotliAllocate(
|
||||
m, sizeof(kStaticDictionaryHashWords));
|
||||
current->hash_table_data_lengths_ = (uint8_t*)BrotliAllocate(
|
||||
m, sizeof(kStaticDictionaryHashLengths));
|
||||
if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
|
||||
current->hash_table_words = current->hash_table_data_words_;
|
||||
current->hash_table_lengths = current->hash_table_data_lengths_;
|
||||
|
||||
BuildDictionaryHashTable(current->hash_table_data_words_,
|
||||
current->hash_table_data_lengths_, current->words);
|
||||
|
||||
ComputeCutoffTransforms(transforms,
|
||||
¤t->cutoffTransformsCount, ¤t->cutoffTransforms);
|
||||
|
||||
/* Only compute the data for slow encoder if the requested quality is high
|
||||
enough to need it */
|
||||
if (quality >= ZOPFLIFICATION_QUALITY) {
|
||||
if (!BuildDictionaryLut(m, transforms, current)) return BROTLI_FALSE;
|
||||
|
||||
/* For the built-in Brotli transforms, there is a hard-coded function to
|
||||
handle all transforms, but for custom transforms, we use the following
|
||||
large hammer instead */
|
||||
current->has_words_heavy = !default_transforms;
|
||||
if (current->has_words_heavy) {
|
||||
if (!GenerateWordsHeavy(m, transforms, current)) return BROTLI_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
#endif /* BROTLI_EXPERIMENTAL */
|
||||
|
||||
void BrotliInitSharedEncoderDictionary(SharedEncoderDictionary* dict) {
|
||||
dict->magic = kSharedDictionaryMagic;
|
||||
|
||||
dict->compound.num_chunks = 0;
|
||||
dict->compound.total_size = 0;
|
||||
dict->compound.chunk_offsets[0] = 0;
|
||||
dict->compound.num_prepared_instances_ = 0;
|
||||
|
||||
dict->contextual.context_based = 0;
|
||||
dict->contextual.num_dictionaries = 1;
|
||||
dict->contextual.instances_ = 0;
|
||||
dict->contextual.num_instances_ = 1; /* The instance_ field */
|
||||
dict->contextual.dict[0] = &dict->contextual.instance_;
|
||||
InitEncoderDictionary(&dict->contextual.instance_);
|
||||
dict->contextual.instance_.parent = &dict->contextual;
|
||||
|
||||
dict->max_quality = BROTLI_MAX_QUALITY;
|
||||
}
|
||||
|
||||
#if defined(BROTLI_EXPERIMENTAL)
|
||||
/* TODO(eustas): make sure that tooling will warn user if not all the cutoff
|
||||
transforms are available (for low-quality encoder). */
|
||||
static BROTLI_BOOL InitCustomSharedEncoderDictionary(
|
||||
MemoryManager* m, const BrotliSharedDictionary* decoded_dict,
|
||||
int quality, SharedEncoderDictionary* dict) {
|
||||
ContextualEncoderDictionary* contextual;
|
||||
CompoundDictionary* compound;
|
||||
BrotliEncoderDictionary* instances;
|
||||
int i;
|
||||
BrotliInitSharedEncoderDictionary(dict);
|
||||
|
||||
contextual = &dict->contextual;
|
||||
compound = &dict->compound;
|
||||
|
||||
for (i = 0; i < (int)decoded_dict->num_prefix; i++) {
|
||||
PreparedDictionary* prepared = CreatePreparedDictionary(m,
|
||||
decoded_dict->prefix[i], decoded_dict->prefix_size[i]);
|
||||
AttachPreparedDictionary(compound, prepared);
|
||||
/* remember for cleanup */
|
||||
compound->prepared_instances_[
|
||||
compound->num_prepared_instances_++] = prepared;
|
||||
}
|
||||
|
||||
dict->max_quality = quality;
|
||||
contextual->context_based = decoded_dict->context_based;
|
||||
if (decoded_dict->context_based) {
|
||||
memcpy(contextual->context_map, decoded_dict->context_map,
|
||||
SHARED_BROTLI_NUM_DICTIONARY_CONTEXTS);
|
||||
}
|
||||
|
||||
contextual->num_dictionaries = decoded_dict->num_dictionaries;
|
||||
contextual->num_instances_ = decoded_dict->num_dictionaries;
|
||||
if (contextual->num_instances_ == 1) {
|
||||
instances = &contextual->instance_;
|
||||
} else {
|
||||
contextual->instances_ = (BrotliEncoderDictionary*)
|
||||
BrotliAllocate(m, sizeof(*contextual->instances_) *
|
||||
contextual->num_instances_);
|
||||
if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
|
||||
instances = contextual->instances_;
|
||||
}
|
||||
for (i = 0; i < (int)contextual->num_instances_; i++) {
|
||||
BrotliEncoderDictionary* current = &instances[i];
|
||||
InitEncoderDictionary(current);
|
||||
current->parent = &dict->contextual;
|
||||
if (decoded_dict->words[i] == BrotliGetDictionary()) {
|
||||
current->words = BrotliGetDictionary();
|
||||
} else {
|
||||
current->words_instance_ = (BrotliDictionary*)BrotliAllocate(
|
||||
m, sizeof(BrotliDictionary));
|
||||
if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
|
||||
*current->words_instance_ = *decoded_dict->words[i];
|
||||
current->words = current->words_instance_;
|
||||
}
|
||||
current->num_transforms =
|
||||
(uint32_t)decoded_dict->transforms[i]->num_transforms;
|
||||
if (!ComputeDictionary(
|
||||
m, quality, decoded_dict->transforms[i], current)) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
|
||||
contextual->dict[i] = current;
|
||||
}
|
||||
|
||||
return BROTLI_TRUE; /* success */
|
||||
}
|
||||
|
||||
BROTLI_BOOL BrotliInitCustomSharedEncoderDictionary(
|
||||
MemoryManager* m, const uint8_t* encoded_dict, size_t size,
|
||||
int quality, SharedEncoderDictionary* dict) {
|
||||
BROTLI_BOOL success = BROTLI_FALSE;
|
||||
BrotliSharedDictionary* decoded_dict = BrotliSharedDictionaryCreateInstance(
|
||||
m->alloc_func, m->free_func, m->opaque);
|
||||
if (!decoded_dict) { /* OOM */
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
success = BrotliSharedDictionaryAttach(
|
||||
decoded_dict, BROTLI_SHARED_DICTIONARY_SERIALIZED, size, encoded_dict);
|
||||
if (success) {
|
||||
success = InitCustomSharedEncoderDictionary(m,
|
||||
decoded_dict, quality, dict);
|
||||
}
|
||||
BrotliSharedDictionaryDestroyInstance(decoded_dict);
|
||||
return success;
|
||||
}
|
||||
#endif /* BROTLI_EXPERIMENTAL */
|
||||
|
||||
void BrotliCleanupSharedEncoderDictionary(MemoryManager* m,
|
||||
SharedEncoderDictionary* dict) {
|
||||
size_t i;
|
||||
for (i = 0; i < dict->compound.num_prepared_instances_; i++) {
|
||||
DestroyPreparedDictionary(m,
|
||||
(PreparedDictionary*)dict->compound.prepared_instances_[i]);
|
||||
}
|
||||
if (dict->contextual.num_instances_ == 1) {
|
||||
BrotliDestroyEncoderDictionary(m, &dict->contextual.instance_);
|
||||
} else if (dict->contextual.num_instances_ > 1) {
|
||||
for (i = 0; i < dict->contextual.num_instances_; i++) {
|
||||
BrotliDestroyEncoderDictionary(m, &dict->contextual.instances_[i]);
|
||||
}
|
||||
BrotliFree(m, dict->contextual.instances_);
|
||||
}
|
||||
}
|
||||
|
||||
ManagedDictionary* BrotliCreateManagedDictionary(
|
||||
brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque) {
|
||||
ManagedDictionary* result = (ManagedDictionary*)BrotliBootstrapAlloc(
|
||||
sizeof(ManagedDictionary), alloc_func, free_func, opaque);
|
||||
if (result == NULL) return NULL;
|
||||
|
||||
result->magic = kManagedDictionaryMagic;
|
||||
BrotliInitMemoryManager(
|
||||
&result->memory_manager_, alloc_func, free_func, opaque);
|
||||
result->dictionary = NULL;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void BrotliDestroyManagedDictionary(ManagedDictionary* dictionary) {
|
||||
if (!dictionary) return;
|
||||
BrotliBootstrapFree(dictionary, &dictionary->memory_manager_);
|
||||
}
|
||||
|
||||
/* Escalate internal functions visibility; for testing purposes only. */
|
||||
#if defined(BROTLI_TEST)
|
||||
void BrotliInitEncoderDictionaryForTest(BrotliEncoderDictionary*);
|
||||
void BrotliInitEncoderDictionaryForTest(BrotliEncoderDictionary* d) {
|
||||
InitEncoderDictionary(d);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
122
c/enc/encoder_dict.h
Executable file → Normal file
122
c/enc/encoder_dict.h
Executable file → Normal file
@@ -8,31 +8,145 @@
|
||||
#define BROTLI_ENC_ENCODER_DICT_H_
|
||||
|
||||
#include "../common/dictionary.h"
|
||||
#include <brotli/shared_dictionary.h>
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./static_dict_lut.h"
|
||||
#include "compound_dictionary.h"
|
||||
#include "memory.h"
|
||||
#include "static_dict_lut.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
Dictionary hierarchy for Encoder:
|
||||
-SharedEncoderDictionary
|
||||
--CompoundDictionary
|
||||
---PreparedDictionary [up to 15x]
|
||||
= prefix dictionary with precomputed hashes
|
||||
--ContextualEncoderDictionary
|
||||
---BrotliEncoderDictionary [up to 64x]
|
||||
= for each context, precomputed static dictionary with words + transforms
|
||||
|
||||
Dictionary hierarchy from common: similar, but without precomputed hashes
|
||||
-BrotliSharedDictionary
|
||||
--BrotliDictionary [up to 64x]
|
||||
--BrotliTransforms [up to 64x]
|
||||
--const uint8_t* prefix [up to 15x]: compound dictionaries
|
||||
*/
|
||||
|
||||
typedef struct BrotliTrieNode {
|
||||
uint8_t single; /* if 1, sub is a single node for c instead of 256 */
|
||||
uint8_t c;
|
||||
uint8_t len_; /* untransformed length */
|
||||
uint32_t idx_; /* word index + num words * transform index */
|
||||
uint32_t sub; /* index of sub node(s) in the pool */
|
||||
} BrotliTrieNode;
|
||||
|
||||
typedef struct BrotliTrie {
|
||||
BrotliTrieNode* pool;
|
||||
size_t pool_capacity;
|
||||
size_t pool_size;
|
||||
BrotliTrieNode root;
|
||||
} BrotliTrie;
|
||||
|
||||
#if defined(BROTLI_EXPERIMENTAL)
|
||||
BROTLI_INTERNAL const BrotliTrieNode* BrotliTrieSub(const BrotliTrie* trie,
|
||||
const BrotliTrieNode* node, uint8_t c);
|
||||
#endif /* BROTLI_EXPERIMENTAL */
|
||||
|
||||
/* Dictionary data (words and transforms) for 1 possible context */
|
||||
typedef struct BrotliEncoderDictionary {
|
||||
const BrotliDictionary* words;
|
||||
uint32_t num_transforms;
|
||||
|
||||
/* cut off for fast encoder */
|
||||
uint32_t cutoffTransformsCount;
|
||||
uint64_t cutoffTransforms;
|
||||
|
||||
/* from dictionary_hash.h, for fast encoder */
|
||||
const uint16_t* hash_table;
|
||||
const uint16_t* hash_table_words;
|
||||
const uint8_t* hash_table_lengths;
|
||||
|
||||
/* from static_dict_lut.h, for slow encoder */
|
||||
const uint16_t* buckets;
|
||||
const DictWord* dict_words;
|
||||
/* Heavy version, for use by slow encoder when there are custom transforms.
|
||||
Contains every possible transformed dictionary word in a trie. It encodes
|
||||
about as fast as the non-heavy encoder but consumes a lot of memory and
|
||||
takes time to build. */
|
||||
BrotliTrie trie;
|
||||
BROTLI_BOOL has_words_heavy;
|
||||
|
||||
/* Reference to other dictionaries. */
|
||||
const struct ContextualEncoderDictionary* parent;
|
||||
|
||||
/* Allocated memory, used only when not using the Brotli defaults */
|
||||
uint16_t* hash_table_data_words_;
|
||||
uint8_t* hash_table_data_lengths_;
|
||||
size_t buckets_alloc_size_;
|
||||
uint16_t* buckets_data_;
|
||||
size_t dict_words_alloc_size_;
|
||||
DictWord* dict_words_data_;
|
||||
BrotliDictionary* words_instance_;
|
||||
} BrotliEncoderDictionary;
|
||||
|
||||
BROTLI_INTERNAL void BrotliInitEncoderDictionary(BrotliEncoderDictionary* dict);
|
||||
/* Dictionary data for all 64 contexts */
|
||||
typedef struct ContextualEncoderDictionary {
|
||||
BROTLI_BOOL context_based;
|
||||
uint8_t num_dictionaries;
|
||||
uint8_t context_map[SHARED_BROTLI_NUM_DICTIONARY_CONTEXTS];
|
||||
const BrotliEncoderDictionary* dict[SHARED_BROTLI_NUM_DICTIONARY_CONTEXTS];
|
||||
|
||||
/* If num_instances_ is 1, instance_ is used, else dynamic allocation with
|
||||
instances_ is used. */
|
||||
size_t num_instances_;
|
||||
BrotliEncoderDictionary instance_;
|
||||
BrotliEncoderDictionary* instances_;
|
||||
} ContextualEncoderDictionary;
|
||||
|
||||
typedef struct SharedEncoderDictionary {
|
||||
/* Magic value to distinguish this struct from PreparedDictionary for
|
||||
certain external usages. */
|
||||
uint32_t magic;
|
||||
|
||||
/* LZ77 prefix, compound dictionary */
|
||||
CompoundDictionary compound;
|
||||
|
||||
/* Custom static dictionary (optionally context-based) */
|
||||
ContextualEncoderDictionary contextual;
|
||||
|
||||
/* The maximum quality the dictionary was computed for */
|
||||
int max_quality;
|
||||
} SharedEncoderDictionary;
|
||||
|
||||
typedef struct ManagedDictionary {
|
||||
uint32_t magic;
|
||||
MemoryManager memory_manager_;
|
||||
uint32_t* dictionary;
|
||||
} ManagedDictionary;
|
||||
|
||||
/* Initializes to the brotli built-in dictionary */
|
||||
BROTLI_INTERNAL void BrotliInitSharedEncoderDictionary(
|
||||
SharedEncoderDictionary* dict);
|
||||
|
||||
#if defined(BROTLI_EXPERIMENTAL)
|
||||
/* Initializes to shared dictionary that will be parsed from
|
||||
encoded_dict. Requires that you keep the encoded_dict buffer
|
||||
around, parts of data will point to it. */
|
||||
BROTLI_INTERNAL BROTLI_BOOL BrotliInitCustomSharedEncoderDictionary(
|
||||
MemoryManager* m, const uint8_t* encoded_dict, size_t size,
|
||||
int quality, SharedEncoderDictionary* dict);
|
||||
#endif /* BROTLI_EXPERIMENTAL */
|
||||
|
||||
BROTLI_INTERNAL void BrotliCleanupSharedEncoderDictionary(
|
||||
MemoryManager* m, SharedEncoderDictionary* dict);
|
||||
|
||||
BROTLI_INTERNAL ManagedDictionary* BrotliCreateManagedDictionary(
|
||||
brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque);
|
||||
|
||||
BROTLI_INTERNAL void BrotliDestroyManagedDictionary(
|
||||
ManagedDictionary* dictionary);
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
|
||||
@@ -6,18 +6,17 @@
|
||||
|
||||
/* Entropy encoding (Huffman) utilities. */
|
||||
|
||||
#include "./entropy_encode.h"
|
||||
|
||||
#include <string.h> /* memset */
|
||||
#include "entropy_encode.h"
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
const BROTLI_MODEL("small") size_t kBrotliShellGaps[] = {132, 57, 23, 10, 4, 1};
|
||||
|
||||
BROTLI_BOOL BrotliSetDepth(
|
||||
int p0, HuffmanTree* pool, uint8_t* depth, int max_depth) {
|
||||
int stack[16];
|
||||
@@ -453,7 +452,8 @@ void BrotliWriteHuffmanTree(const uint8_t* depth,
|
||||
}
|
||||
|
||||
static uint16_t BrotliReverseBits(size_t num_bits, uint16_t bits) {
|
||||
static const size_t kLut[16] = { /* Pre-reversed 4-bit values. */
|
||||
static const size_t BROTLI_MODEL("small") kLut[16] =
|
||||
{ /* Pre-reversed 4-bit values. */
|
||||
0x00, 0x08, 0x04, 0x0C, 0x02, 0x0A, 0x06, 0x0E,
|
||||
0x01, 0x09, 0x05, 0x0D, 0x03, 0x0B, 0x07, 0x0F
|
||||
};
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#define BROTLI_ENC_ENTROPY_ENCODE_H_
|
||||
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
@@ -66,7 +65,7 @@ BROTLI_INTERNAL void BrotliOptimizeHuffmanCountsForRle(
|
||||
of a Huffman tree. The generated Huffman tree is to be compressed once
|
||||
more using a Huffman tree */
|
||||
BROTLI_INTERNAL void BrotliWriteHuffmanTree(const uint8_t* depth,
|
||||
size_t num,
|
||||
size_t length,
|
||||
size_t* tree_size,
|
||||
uint8_t* tree,
|
||||
uint8_t* extra_bits_data);
|
||||
@@ -76,12 +75,12 @@ BROTLI_INTERNAL void BrotliConvertBitDepthsToSymbols(const uint8_t* depth,
|
||||
size_t len,
|
||||
uint16_t* bits);
|
||||
|
||||
BROTLI_INTERNAL extern BROTLI_MODEL("small") const size_t kBrotliShellGaps[6];
|
||||
/* Input size optimized Shell sort. */
|
||||
typedef BROTLI_BOOL (*HuffmanTreeComparator)(
|
||||
const HuffmanTree*, const HuffmanTree*);
|
||||
static BROTLI_INLINE void SortHuffmanTreeItems(HuffmanTree* items,
|
||||
const size_t n, HuffmanTreeComparator comparator) {
|
||||
static const size_t gaps[] = {132, 57, 23, 10, 4, 1};
|
||||
if (n < 13) {
|
||||
/* Insertion sort. */
|
||||
size_t i;
|
||||
@@ -101,7 +100,7 @@ static BROTLI_INLINE void SortHuffmanTreeItems(HuffmanTree* items,
|
||||
/* Shell sort. */
|
||||
int g = n < 57 ? 2 : 0;
|
||||
for (; g < 6; ++g) {
|
||||
size_t gap = gaps[g];
|
||||
size_t gap = kBrotliShellGaps[g];
|
||||
size_t i;
|
||||
for (i = gap; i < n; ++i) {
|
||||
size_t j = i;
|
||||
|
||||
@@ -11,18 +11,18 @@
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./write_bits.h"
|
||||
#include "write_bits.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static const uint8_t kCodeLengthDepth[18] = {
|
||||
static const BROTLI_MODEL("small") uint8_t kCodeLengthDepth[18] = {
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 0, 4, 4,
|
||||
};
|
||||
|
||||
static const uint8_t kStaticCommandCodeDepth[BROTLI_NUM_COMMAND_SYMBOLS] = {
|
||||
static const BROTLI_MODEL("small")
|
||||
uint8_t kStaticCommandCodeDepth[BROTLI_NUM_COMMAND_SYMBOLS] = {
|
||||
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
||||
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
||||
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
||||
@@ -69,14 +69,17 @@ static const uint8_t kStaticCommandCodeDepth[BROTLI_NUM_COMMAND_SYMBOLS] = {
|
||||
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
|
||||
};
|
||||
|
||||
static const uint8_t kStaticDistanceCodeDepth[64] = {
|
||||
static const BROTLI_MODEL("small")
|
||||
uint8_t kStaticDistanceCodeDepth[64] = {
|
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
||||
};
|
||||
|
||||
static const uint32_t kCodeLengthBits[18] = {
|
||||
/* GENERATED CODE START */
|
||||
static const BROTLI_MODEL("small")
|
||||
uint32_t kCodeLengthBits[18] = {
|
||||
0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 15, 31, 0, 11, 7,
|
||||
};
|
||||
|
||||
@@ -86,7 +89,8 @@ static BROTLI_INLINE void StoreStaticCodeLengthCode(
|
||||
40, BROTLI_MAKE_UINT64_T(0x0000FFu, 0x55555554u), storage_ix, storage);
|
||||
}
|
||||
|
||||
static const uint64_t kZeroRepsBits[BROTLI_NUM_COMMAND_SYMBOLS] = {
|
||||
static const BROTLI_MODEL("small")
|
||||
uint64_t kZeroRepsBits[BROTLI_NUM_COMMAND_SYMBOLS] = {
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000007, 0x00000017, 0x00000027,
|
||||
0x00000037, 0x00000047, 0x00000057, 0x00000067, 0x00000077, 0x00000770,
|
||||
0x00000b87, 0x00001387, 0x00001b87, 0x00002387, 0x00002b87, 0x00003387,
|
||||
@@ -207,7 +211,8 @@ static const uint64_t kZeroRepsBits[BROTLI_NUM_COMMAND_SYMBOLS] = {
|
||||
0x06f9cb87, 0x08f9cb87,
|
||||
};
|
||||
|
||||
static const uint32_t kZeroRepsDepth[BROTLI_NUM_COMMAND_SYMBOLS] = {
|
||||
static const BROTLI_MODEL("small")
|
||||
uint32_t kZeroRepsDepth[BROTLI_NUM_COMMAND_SYMBOLS] = {
|
||||
0, 4, 8, 7, 7, 7, 7, 7, 7, 7, 7, 11, 14, 14, 14, 14,
|
||||
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
|
||||
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
|
||||
@@ -254,7 +259,8 @@ static const uint32_t kZeroRepsDepth[BROTLI_NUM_COMMAND_SYMBOLS] = {
|
||||
28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
|
||||
};
|
||||
|
||||
static const uint64_t kNonZeroRepsBits[BROTLI_NUM_COMMAND_SYMBOLS] = {
|
||||
static const BROTLI_MODEL("small")
|
||||
uint64_t kNonZeroRepsBits[BROTLI_NUM_COMMAND_SYMBOLS] = {
|
||||
0x0000000b, 0x0000001b, 0x0000002b, 0x0000003b, 0x000002cb, 0x000006cb,
|
||||
0x00000acb, 0x00000ecb, 0x000002db, 0x000006db, 0x00000adb, 0x00000edb,
|
||||
0x000002eb, 0x000006eb, 0x00000aeb, 0x00000eeb, 0x000002fb, 0x000006fb,
|
||||
@@ -375,7 +381,8 @@ static const uint64_t kNonZeroRepsBits[BROTLI_NUM_COMMAND_SYMBOLS] = {
|
||||
0x2baeb6db, 0x3baeb6db,
|
||||
};
|
||||
|
||||
static const uint32_t kNonZeroRepsDepth[BROTLI_NUM_COMMAND_SYMBOLS] = {
|
||||
static const BROTLI_MODEL("small")
|
||||
uint32_t kNonZeroRepsDepth[BROTLI_NUM_COMMAND_SYMBOLS] = {
|
||||
6, 6, 6, 6, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
|
||||
12, 12, 12, 12, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
|
||||
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
|
||||
@@ -422,7 +429,8 @@ static const uint32_t kNonZeroRepsDepth[BROTLI_NUM_COMMAND_SYMBOLS] = {
|
||||
30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
|
||||
};
|
||||
|
||||
static const uint16_t kStaticCommandCodeBits[BROTLI_NUM_COMMAND_SYMBOLS] = {
|
||||
static const BROTLI_MODEL("small")
|
||||
uint16_t kStaticCommandCodeBits[BROTLI_NUM_COMMAND_SYMBOLS] = {
|
||||
0, 256, 128, 384, 64, 320, 192, 448,
|
||||
32, 288, 160, 416, 96, 352, 224, 480,
|
||||
16, 272, 144, 400, 80, 336, 208, 464,
|
||||
@@ -520,7 +528,7 @@ static BROTLI_INLINE void StoreStaticCommandHuffmanTree(
|
||||
BrotliWriteBits(3, 0x00000000U, storage_ix, storage);
|
||||
}
|
||||
|
||||
static const uint16_t kStaticDistanceCodeBits[64] = {
|
||||
static const BROTLI_MODEL("small") uint16_t kStaticDistanceCodeBits[64] = {
|
||||
0, 32, 16, 48, 8, 40, 24, 56, 4, 36, 20, 52, 12, 44, 28, 60,
|
||||
2, 34, 18, 50, 10, 42, 26, 58, 6, 38, 22, 54, 14, 46, 30, 62,
|
||||
1, 33, 17, 49, 9, 41, 25, 57, 5, 37, 21, 53, 13, 45, 29, 61,
|
||||
@@ -531,6 +539,7 @@ static BROTLI_INLINE void StoreStaticDistanceHuffmanTree(
|
||||
size_t* storage_ix, uint8_t* storage) {
|
||||
BrotliWriteBits(28, 0x0369DC03u, storage_ix, storage);
|
||||
}
|
||||
/* GENERATED CODE END */
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
|
||||
105
c/enc/fast_log.c
Normal file
105
c/enc/fast_log.c
Normal file
@@ -0,0 +1,105 @@
|
||||
/* Copyright 2013 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "fast_log.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ", ".join(["%.16ff" % x for x in [0.0]+[log2(x) for x in range(1, 256)]]) */
|
||||
const BROTLI_MODEL("small") double kBrotliLog2Table[BROTLI_LOG2_TABLE_SIZE] = {
|
||||
0.0000000000000000f, 0.0000000000000000f, 1.0000000000000000f,
|
||||
1.5849625007211563f, 2.0000000000000000f, 2.3219280948873622f,
|
||||
2.5849625007211561f, 2.8073549220576042f, 3.0000000000000000f,
|
||||
3.1699250014423126f, 3.3219280948873626f, 3.4594316186372978f,
|
||||
3.5849625007211565f, 3.7004397181410922f, 3.8073549220576037f,
|
||||
3.9068905956085187f, 4.0000000000000000f, 4.0874628412503400f,
|
||||
4.1699250014423122f, 4.2479275134435852f, 4.3219280948873626f,
|
||||
4.3923174227787607f, 4.4594316186372973f, 4.5235619560570131f,
|
||||
4.5849625007211570f, 4.6438561897747244f, 4.7004397181410926f,
|
||||
4.7548875021634691f, 4.8073549220576037f, 4.8579809951275728f,
|
||||
4.9068905956085187f, 4.9541963103868758f, 5.0000000000000000f,
|
||||
5.0443941193584534f, 5.0874628412503400f, 5.1292830169449664f,
|
||||
5.1699250014423122f, 5.2094533656289501f, 5.2479275134435852f,
|
||||
5.2854022188622487f, 5.3219280948873626f, 5.3575520046180838f,
|
||||
5.3923174227787607f, 5.4262647547020979f, 5.4594316186372973f,
|
||||
5.4918530963296748f, 5.5235619560570131f, 5.5545888516776376f,
|
||||
5.5849625007211570f, 5.6147098441152083f, 5.6438561897747244f,
|
||||
5.6724253419714961f, 5.7004397181410926f, 5.7279204545631996f,
|
||||
5.7548875021634691f, 5.7813597135246599f, 5.8073549220576046f,
|
||||
5.8328900141647422f, 5.8579809951275719f, 5.8826430493618416f,
|
||||
5.9068905956085187f, 5.9307373375628867f, 5.9541963103868758f,
|
||||
5.9772799234999168f, 6.0000000000000000f, 6.0223678130284544f,
|
||||
6.0443941193584534f, 6.0660891904577721f, 6.0874628412503400f,
|
||||
6.1085244567781700f, 6.1292830169449672f, 6.1497471195046822f,
|
||||
6.1699250014423122f, 6.1898245588800176f, 6.2094533656289510f,
|
||||
6.2288186904958804f, 6.2479275134435861f, 6.2667865406949019f,
|
||||
6.2854022188622487f, 6.3037807481771031f, 6.3219280948873617f,
|
||||
6.3398500028846252f, 6.3575520046180847f, 6.3750394313469254f,
|
||||
6.3923174227787598f, 6.4093909361377026f, 6.4262647547020979f,
|
||||
6.4429434958487288f, 6.4594316186372982f, 6.4757334309663976f,
|
||||
6.4918530963296748f, 6.5077946401986964f, 6.5235619560570131f,
|
||||
6.5391588111080319f, 6.5545888516776376f, 6.5698556083309478f,
|
||||
6.5849625007211561f, 6.5999128421871278f, 6.6147098441152092f,
|
||||
6.6293566200796095f, 6.6438561897747253f, 6.6582114827517955f,
|
||||
6.6724253419714952f, 6.6865005271832185f, 6.7004397181410917f,
|
||||
6.7142455176661224f, 6.7279204545631988f, 6.7414669864011465f,
|
||||
6.7548875021634691f, 6.7681843247769260f, 6.7813597135246599f,
|
||||
6.7944158663501062f, 6.8073549220576037f, 6.8201789624151887f,
|
||||
6.8328900141647422f, 6.8454900509443757f, 6.8579809951275719f,
|
||||
6.8703647195834048f, 6.8826430493618416f, 6.8948177633079437f,
|
||||
6.9068905956085187f, 6.9188632372745955f, 6.9307373375628867f,
|
||||
6.9425145053392399f, 6.9541963103868758f, 6.9657842846620879f,
|
||||
6.9772799234999168f, 6.9886846867721664f, 7.0000000000000000f,
|
||||
7.0112272554232540f, 7.0223678130284544f, 7.0334230015374501f,
|
||||
7.0443941193584534f, 7.0552824355011898f, 7.0660891904577721f,
|
||||
7.0768155970508317f, 7.0874628412503400f, 7.0980320829605272f,
|
||||
7.1085244567781700f, 7.1189410727235076f, 7.1292830169449664f,
|
||||
7.1395513523987937f, 7.1497471195046822f, 7.1598713367783891f,
|
||||
7.1699250014423130f, 7.1799090900149345f, 7.1898245588800176f,
|
||||
7.1996723448363644f, 7.2094533656289492f, 7.2191685204621621f,
|
||||
7.2288186904958804f, 7.2384047393250794f, 7.2479275134435861f,
|
||||
7.2573878426926521f, 7.2667865406949019f, 7.2761244052742384f,
|
||||
7.2854022188622487f, 7.2946207488916270f, 7.3037807481771031f,
|
||||
7.3128829552843557f, 7.3219280948873617f, 7.3309168781146177f,
|
||||
7.3398500028846243f, 7.3487281542310781f, 7.3575520046180847f,
|
||||
7.3663222142458151f, 7.3750394313469254f, 7.3837042924740528f,
|
||||
7.3923174227787607f, 7.4008794362821844f, 7.4093909361377026f,
|
||||
7.4178525148858991f, 7.4262647547020979f, 7.4346282276367255f,
|
||||
7.4429434958487288f, 7.4512111118323299f, 7.4594316186372973f,
|
||||
7.4676055500829976f, 7.4757334309663976f, 7.4838157772642564f,
|
||||
7.4918530963296748f, 7.4998458870832057f, 7.5077946401986964f,
|
||||
7.5156998382840436f, 7.5235619560570131f, 7.5313814605163119f,
|
||||
7.5391588111080319f, 7.5468944598876373f, 7.5545888516776376f,
|
||||
7.5622424242210728f, 7.5698556083309478f, 7.5774288280357487f,
|
||||
7.5849625007211561f, 7.5924570372680806f, 7.5999128421871278f,
|
||||
7.6073303137496113f, 7.6147098441152075f, 7.6220518194563764f,
|
||||
7.6293566200796095f, 7.6366246205436488f, 7.6438561897747244f,
|
||||
7.6510516911789290f, 7.6582114827517955f, 7.6653359171851765f,
|
||||
7.6724253419714952f, 7.6794800995054464f, 7.6865005271832185f,
|
||||
7.6934869574993252f, 7.7004397181410926f, 7.7073591320808825f,
|
||||
7.7142455176661224f, 7.7210991887071856f, 7.7279204545631996f,
|
||||
7.7347096202258392f, 7.7414669864011465f, 7.7481928495894596f,
|
||||
7.7548875021634691f, 7.7615512324444795f, 7.7681843247769260f,
|
||||
7.7747870596011737f, 7.7813597135246608f, 7.7879025593914317f,
|
||||
7.7944158663501062f, 7.8008998999203047f, 7.8073549220576037f,
|
||||
7.8137811912170374f, 7.8201789624151887f, 7.8265484872909159f,
|
||||
7.8328900141647422f, 7.8392037880969445f, 7.8454900509443757f,
|
||||
7.8517490414160571f, 7.8579809951275719f, 7.8641861446542798f,
|
||||
7.8703647195834048f, 7.8765169465650002f, 7.8826430493618425f,
|
||||
7.8887432488982601f, 7.8948177633079446f, 7.9008668079807496f,
|
||||
7.9068905956085187f, 7.9128893362299619f, 7.9188632372745955f,
|
||||
7.9248125036057813f, 7.9307373375628867f, 7.9366379390025719f,
|
||||
7.9425145053392399f, 7.9483672315846778f, 7.9541963103868758f,
|
||||
7.9600019320680806f, 7.9657842846620870f, 7.9715435539507720f,
|
||||
7.9772799234999168f, 7.9829935746943104f, 7.9886846867721664f,
|
||||
7.9943534368588578f
|
||||
};
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
123
c/enc/fast_log.h
123
c/enc/fast_log.h
@@ -12,17 +12,14 @@
|
||||
#include <math.h>
|
||||
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static BROTLI_INLINE uint32_t Log2FloorNonZero(size_t n) {
|
||||
/* TODO: generalize and move to platform.h */
|
||||
#if BROTLI_GNUC_HAS_BUILTIN(__builtin_clz, 3, 4, 0) || \
|
||||
BROTLI_INTEL_VERSION_CHECK(16, 0, 0)
|
||||
return 31u ^ (uint32_t)__builtin_clz((uint32_t)n);
|
||||
#if defined(BROTLI_BSR32)
|
||||
return BROTLI_BSR32((uint32_t)n);
|
||||
#else
|
||||
uint32_t result = 0;
|
||||
while (n >>= 1) result++;
|
||||
@@ -30,110 +27,32 @@ static BROTLI_INLINE uint32_t Log2FloorNonZero(size_t n) {
|
||||
#endif
|
||||
}
|
||||
|
||||
/* A lookup table for small values of log2(int) to be used in entropy
|
||||
computation.
|
||||
#define BROTLI_LOG2_TABLE_SIZE 256
|
||||
|
||||
", ".join(["%.16ff" % x for x in [0.0]+[log2(x) for x in range(1, 256)]]) */
|
||||
static const float kLog2Table[] = {
|
||||
0.0000000000000000f, 0.0000000000000000f, 1.0000000000000000f,
|
||||
1.5849625007211563f, 2.0000000000000000f, 2.3219280948873622f,
|
||||
2.5849625007211561f, 2.8073549220576042f, 3.0000000000000000f,
|
||||
3.1699250014423126f, 3.3219280948873626f, 3.4594316186372978f,
|
||||
3.5849625007211565f, 3.7004397181410922f, 3.8073549220576037f,
|
||||
3.9068905956085187f, 4.0000000000000000f, 4.0874628412503400f,
|
||||
4.1699250014423122f, 4.2479275134435852f, 4.3219280948873626f,
|
||||
4.3923174227787607f, 4.4594316186372973f, 4.5235619560570131f,
|
||||
4.5849625007211570f, 4.6438561897747244f, 4.7004397181410926f,
|
||||
4.7548875021634691f, 4.8073549220576037f, 4.8579809951275728f,
|
||||
4.9068905956085187f, 4.9541963103868758f, 5.0000000000000000f,
|
||||
5.0443941193584534f, 5.0874628412503400f, 5.1292830169449664f,
|
||||
5.1699250014423122f, 5.2094533656289501f, 5.2479275134435852f,
|
||||
5.2854022188622487f, 5.3219280948873626f, 5.3575520046180838f,
|
||||
5.3923174227787607f, 5.4262647547020979f, 5.4594316186372973f,
|
||||
5.4918530963296748f, 5.5235619560570131f, 5.5545888516776376f,
|
||||
5.5849625007211570f, 5.6147098441152083f, 5.6438561897747244f,
|
||||
5.6724253419714961f, 5.7004397181410926f, 5.7279204545631996f,
|
||||
5.7548875021634691f, 5.7813597135246599f, 5.8073549220576046f,
|
||||
5.8328900141647422f, 5.8579809951275719f, 5.8826430493618416f,
|
||||
5.9068905956085187f, 5.9307373375628867f, 5.9541963103868758f,
|
||||
5.9772799234999168f, 6.0000000000000000f, 6.0223678130284544f,
|
||||
6.0443941193584534f, 6.0660891904577721f, 6.0874628412503400f,
|
||||
6.1085244567781700f, 6.1292830169449672f, 6.1497471195046822f,
|
||||
6.1699250014423122f, 6.1898245588800176f, 6.2094533656289510f,
|
||||
6.2288186904958804f, 6.2479275134435861f, 6.2667865406949019f,
|
||||
6.2854022188622487f, 6.3037807481771031f, 6.3219280948873617f,
|
||||
6.3398500028846252f, 6.3575520046180847f, 6.3750394313469254f,
|
||||
6.3923174227787598f, 6.4093909361377026f, 6.4262647547020979f,
|
||||
6.4429434958487288f, 6.4594316186372982f, 6.4757334309663976f,
|
||||
6.4918530963296748f, 6.5077946401986964f, 6.5235619560570131f,
|
||||
6.5391588111080319f, 6.5545888516776376f, 6.5698556083309478f,
|
||||
6.5849625007211561f, 6.5999128421871278f, 6.6147098441152092f,
|
||||
6.6293566200796095f, 6.6438561897747253f, 6.6582114827517955f,
|
||||
6.6724253419714952f, 6.6865005271832185f, 6.7004397181410917f,
|
||||
6.7142455176661224f, 6.7279204545631988f, 6.7414669864011465f,
|
||||
6.7548875021634691f, 6.7681843247769260f, 6.7813597135246599f,
|
||||
6.7944158663501062f, 6.8073549220576037f, 6.8201789624151887f,
|
||||
6.8328900141647422f, 6.8454900509443757f, 6.8579809951275719f,
|
||||
6.8703647195834048f, 6.8826430493618416f, 6.8948177633079437f,
|
||||
6.9068905956085187f, 6.9188632372745955f, 6.9307373375628867f,
|
||||
6.9425145053392399f, 6.9541963103868758f, 6.9657842846620879f,
|
||||
6.9772799234999168f, 6.9886846867721664f, 7.0000000000000000f,
|
||||
7.0112272554232540f, 7.0223678130284544f, 7.0334230015374501f,
|
||||
7.0443941193584534f, 7.0552824355011898f, 7.0660891904577721f,
|
||||
7.0768155970508317f, 7.0874628412503400f, 7.0980320829605272f,
|
||||
7.1085244567781700f, 7.1189410727235076f, 7.1292830169449664f,
|
||||
7.1395513523987937f, 7.1497471195046822f, 7.1598713367783891f,
|
||||
7.1699250014423130f, 7.1799090900149345f, 7.1898245588800176f,
|
||||
7.1996723448363644f, 7.2094533656289492f, 7.2191685204621621f,
|
||||
7.2288186904958804f, 7.2384047393250794f, 7.2479275134435861f,
|
||||
7.2573878426926521f, 7.2667865406949019f, 7.2761244052742384f,
|
||||
7.2854022188622487f, 7.2946207488916270f, 7.3037807481771031f,
|
||||
7.3128829552843557f, 7.3219280948873617f, 7.3309168781146177f,
|
||||
7.3398500028846243f, 7.3487281542310781f, 7.3575520046180847f,
|
||||
7.3663222142458151f, 7.3750394313469254f, 7.3837042924740528f,
|
||||
7.3923174227787607f, 7.4008794362821844f, 7.4093909361377026f,
|
||||
7.4178525148858991f, 7.4262647547020979f, 7.4346282276367255f,
|
||||
7.4429434958487288f, 7.4512111118323299f, 7.4594316186372973f,
|
||||
7.4676055500829976f, 7.4757334309663976f, 7.4838157772642564f,
|
||||
7.4918530963296748f, 7.4998458870832057f, 7.5077946401986964f,
|
||||
7.5156998382840436f, 7.5235619560570131f, 7.5313814605163119f,
|
||||
7.5391588111080319f, 7.5468944598876373f, 7.5545888516776376f,
|
||||
7.5622424242210728f, 7.5698556083309478f, 7.5774288280357487f,
|
||||
7.5849625007211561f, 7.5924570372680806f, 7.5999128421871278f,
|
||||
7.6073303137496113f, 7.6147098441152075f, 7.6220518194563764f,
|
||||
7.6293566200796095f, 7.6366246205436488f, 7.6438561897747244f,
|
||||
7.6510516911789290f, 7.6582114827517955f, 7.6653359171851765f,
|
||||
7.6724253419714952f, 7.6794800995054464f, 7.6865005271832185f,
|
||||
7.6934869574993252f, 7.7004397181410926f, 7.7073591320808825f,
|
||||
7.7142455176661224f, 7.7210991887071856f, 7.7279204545631996f,
|
||||
7.7347096202258392f, 7.7414669864011465f, 7.7481928495894596f,
|
||||
7.7548875021634691f, 7.7615512324444795f, 7.7681843247769260f,
|
||||
7.7747870596011737f, 7.7813597135246608f, 7.7879025593914317f,
|
||||
7.7944158663501062f, 7.8008998999203047f, 7.8073549220576037f,
|
||||
7.8137811912170374f, 7.8201789624151887f, 7.8265484872909159f,
|
||||
7.8328900141647422f, 7.8392037880969445f, 7.8454900509443757f,
|
||||
7.8517490414160571f, 7.8579809951275719f, 7.8641861446542798f,
|
||||
7.8703647195834048f, 7.8765169465650002f, 7.8826430493618425f,
|
||||
7.8887432488982601f, 7.8948177633079446f, 7.9008668079807496f,
|
||||
7.9068905956085187f, 7.9128893362299619f, 7.9188632372745955f,
|
||||
7.9248125036057813f, 7.9307373375628867f, 7.9366379390025719f,
|
||||
7.9425145053392399f, 7.9483672315846778f, 7.9541963103868758f,
|
||||
7.9600019320680806f, 7.9657842846620870f, 7.9715435539507720f,
|
||||
7.9772799234999168f, 7.9829935746943104f, 7.9886846867721664f,
|
||||
7.9943534368588578f
|
||||
};
|
||||
/* A lookup table for small values of log2(int) to be used in entropy
|
||||
computation. */
|
||||
BROTLI_INTERNAL extern const BROTLI_MODEL("small")
|
||||
double kBrotliLog2Table[BROTLI_LOG2_TABLE_SIZE];
|
||||
|
||||
/* Visual Studio 2012 and Android API levels < 18 do not have the log2()
|
||||
* function defined, so we use log() and a multiplication instead. */
|
||||
#if !defined(BROTLI_HAVE_LOG2)
|
||||
#if ((defined(_MSC_VER) && _MSC_VER <= 1700) || \
|
||||
(defined(__ANDROID_API__) && __ANDROID_API__ < 18))
|
||||
#define BROTLI_HAVE_LOG2 0
|
||||
#else
|
||||
#define BROTLI_HAVE_LOG2 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define LOG_2_INV 1.4426950408889634
|
||||
|
||||
/* Faster logarithm for small integers, with the property of log2(0) == 0. */
|
||||
static BROTLI_INLINE double FastLog2(size_t v) {
|
||||
if (v < sizeof(kLog2Table) / sizeof(kLog2Table[0])) {
|
||||
return kLog2Table[v];
|
||||
if (v < BROTLI_LOG2_TABLE_SIZE) {
|
||||
return kBrotliLog2Table[v];
|
||||
}
|
||||
#if (defined(_MSC_VER) && _MSC_VER <= 1700) || \
|
||||
(defined(__ANDROID_API__) && __ANDROID_API__ < 18)
|
||||
/* Visual Studio 2012 and Android API levels < 18 do not have the log2()
|
||||
* function defined, so we use log() and a multiplication instead. */
|
||||
#if !(BROTLI_HAVE_LOG2)
|
||||
return log((double)v) * LOG_2_INV;
|
||||
#else
|
||||
return log2((double)v);
|
||||
|
||||
@@ -10,43 +10,33 @@
|
||||
#define BROTLI_ENC_FIND_MATCH_LENGTH_H_
|
||||
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Separate implementation for little-endian 64-bit targets, for speed. */
|
||||
#if defined(__GNUC__) && defined(_LP64) && defined(BROTLI_LITTLE_ENDIAN)
|
||||
|
||||
#if defined(BROTLI_TZCNT64) && BROTLI_64_BITS && BROTLI_LITTLE_ENDIAN
|
||||
static BROTLI_INLINE size_t FindMatchLengthWithLimit(const uint8_t* s1,
|
||||
const uint8_t* s2,
|
||||
size_t limit) {
|
||||
size_t matched = 0;
|
||||
size_t limit2 = (limit >> 3) + 1; /* + 1 is for pre-decrement in while */
|
||||
while (BROTLI_PREDICT_TRUE(--limit2)) {
|
||||
if (BROTLI_PREDICT_FALSE(BROTLI_UNALIGNED_LOAD64LE(s2) ==
|
||||
BROTLI_UNALIGNED_LOAD64LE(s1 + matched))) {
|
||||
s2 += 8;
|
||||
matched += 8;
|
||||
} else {
|
||||
uint64_t x = BROTLI_UNALIGNED_LOAD64LE(s2) ^
|
||||
BROTLI_UNALIGNED_LOAD64LE(s1 + matched);
|
||||
size_t matching_bits = (size_t)__builtin_ctzll(x);
|
||||
matched += matching_bits >> 3;
|
||||
return matched;
|
||||
const uint8_t *s1_orig = s1;
|
||||
for (; limit >= 8; limit -= 8) {
|
||||
uint64_t x = BROTLI_UNALIGNED_LOAD64LE(s2) ^
|
||||
BROTLI_UNALIGNED_LOAD64LE(s1);
|
||||
s2 += 8;
|
||||
if (x != 0) {
|
||||
size_t matching_bits = (size_t)BROTLI_TZCNT64(x);
|
||||
return (size_t)(s1 - s1_orig) + (matching_bits >> 3);
|
||||
}
|
||||
s1 += 8;
|
||||
}
|
||||
limit = (limit & 7) + 1; /* + 1 is for pre-decrement in while */
|
||||
while (--limit) {
|
||||
if (BROTLI_PREDICT_TRUE(s1[matched] == *s2)) {
|
||||
++s2;
|
||||
++matched;
|
||||
} else {
|
||||
return matched;
|
||||
}
|
||||
while (limit && *s1 == *s2) {
|
||||
limit--;
|
||||
++s2;
|
||||
++s1;
|
||||
}
|
||||
return matched;
|
||||
return (size_t)(s1 - s1_orig);
|
||||
}
|
||||
#else
|
||||
static BROTLI_INLINE size_t FindMatchLengthWithLimit(const uint8_t* s1,
|
||||
|
||||
516
c/enc/hash.h
516
c/enc/hash.h
@@ -10,50 +10,49 @@
|
||||
#ifndef BROTLI_ENC_HASH_H_
|
||||
#define BROTLI_ENC_HASH_H_
|
||||
|
||||
#include <string.h> /* memcmp, memset */
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include "../common/dictionary.h"
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./encoder_dict.h"
|
||||
#include "./fast_log.h"
|
||||
#include "./find_match_length.h"
|
||||
#include "./memory.h"
|
||||
#include "./quality.h"
|
||||
#include "./static_dict.h"
|
||||
#include "compound_dictionary.h"
|
||||
#include "encoder_dict.h"
|
||||
#include "fast_log.h"
|
||||
#include "find_match_length.h"
|
||||
#include "hash_base.h"
|
||||
#include "matching_tag_mask.h"
|
||||
#include "memory.h"
|
||||
#include "params.h"
|
||||
#include "quality.h"
|
||||
#include "static_dict.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Pointer to hasher data.
|
||||
*
|
||||
* Excluding initialization and destruction, hasher can be passed as
|
||||
* HasherHandle by value.
|
||||
*
|
||||
* Typically hasher data consists of 3 sections:
|
||||
* * HasherCommon structure
|
||||
* * private structured hasher data, depending on hasher type
|
||||
* * private dynamic hasher data, depending on hasher type and parameters
|
||||
*
|
||||
* Using "define" instead of "typedef", because on MSVC __restrict does not work
|
||||
* on typedef pointer types. */
|
||||
#define HasherHandle uint8_t*
|
||||
|
||||
typedef struct {
|
||||
BrotliHasherParams params;
|
||||
/**
|
||||
* Dynamically allocated areas; regular hasher uses one or two allocations;
|
||||
* "composite" hasher uses up to 4 allocations.
|
||||
*/
|
||||
void* extra[4];
|
||||
|
||||
/* False if hasher needs to be "prepared" before use. */
|
||||
BROTLI_BOOL is_prepared_;
|
||||
/**
|
||||
* False before the first invocation of HasherSetup (where "extra" memory)
|
||||
* is allocated.
|
||||
*/
|
||||
BROTLI_BOOL is_setup_;
|
||||
|
||||
size_t dict_num_lookups;
|
||||
size_t dict_num_matches;
|
||||
} HasherCommon;
|
||||
|
||||
static BROTLI_INLINE HasherCommon* GetHasherCommon(HasherHandle handle) {
|
||||
return (HasherCommon*)handle;
|
||||
}
|
||||
BrotliHasherParams params;
|
||||
|
||||
/**
|
||||
* False if hasher needs to be "prepared" before use (before the first
|
||||
* invocation of HasherSetup or after HasherReset). "preparation" is hasher
|
||||
* data initialization (using input ringbuffer).
|
||||
*/
|
||||
BROTLI_BOOL is_prepared_;
|
||||
} HasherCommon;
|
||||
|
||||
#define score_t size_t
|
||||
|
||||
@@ -70,24 +69,6 @@ typedef struct HasherSearchResult {
|
||||
int len_code_delta; /* == len_code - len */
|
||||
} HasherSearchResult;
|
||||
|
||||
/* kHashMul32 multiplier has these properties:
|
||||
* The multiplier must be odd. Otherwise we may lose the highest bit.
|
||||
* No long streaks of ones or zeros.
|
||||
* There is no effort to ensure that it is a prime, the oddity is enough
|
||||
for this use.
|
||||
* The number has been tuned heuristically against compression benchmarks. */
|
||||
static const uint32_t kHashMul32 = 0x1E35A7BD;
|
||||
static const uint64_t kHashMul64 = BROTLI_MAKE_UINT64_T(0x1E35A7BD, 0x1E35A7BD);
|
||||
static const uint64_t kHashMul64Long =
|
||||
BROTLI_MAKE_UINT64_T(0x1FE35A7Bu, 0xD3579BD3u);
|
||||
|
||||
static BROTLI_INLINE uint32_t Hash14(const uint8_t* data) {
|
||||
uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kHashMul32;
|
||||
/* The higher bits contain more mixture from the multiplication,
|
||||
so we take our results from there. */
|
||||
return h >> (32 - 14);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void PrepareDistanceCache(
|
||||
int* BROTLI_RESTRICT distance_cache, const int num_distances) {
|
||||
if (num_distances > 4) {
|
||||
@@ -149,17 +130,13 @@ static BROTLI_INLINE score_t BackwardReferencePenaltyUsingLastDistance(
|
||||
}
|
||||
|
||||
static BROTLI_INLINE BROTLI_BOOL TestStaticDictionaryItem(
|
||||
const BrotliEncoderDictionary* dictionary, size_t item, const uint8_t* data,
|
||||
size_t max_length, size_t max_backward, size_t max_distance,
|
||||
HasherSearchResult* out) {
|
||||
size_t len;
|
||||
size_t word_idx;
|
||||
const BrotliEncoderDictionary* dictionary, size_t len, size_t word_idx,
|
||||
const uint8_t* data, size_t max_length, size_t max_backward,
|
||||
size_t max_distance, HasherSearchResult* out) {
|
||||
size_t offset;
|
||||
size_t matchlen;
|
||||
size_t backward;
|
||||
score_t score;
|
||||
len = item & 0x1F;
|
||||
word_idx = item >> 5;
|
||||
offset = dictionary->words->offsets_by_length[len] + len * word_idx;
|
||||
if (len > max_length) {
|
||||
return BROTLI_FALSE;
|
||||
@@ -193,24 +170,24 @@ static BROTLI_INLINE BROTLI_BOOL TestStaticDictionaryItem(
|
||||
|
||||
static BROTLI_INLINE void SearchInStaticDictionary(
|
||||
const BrotliEncoderDictionary* dictionary,
|
||||
HasherHandle handle, const uint8_t* data, size_t max_length,
|
||||
HasherCommon* common, const uint8_t* data, size_t max_length,
|
||||
size_t max_backward, size_t max_distance,
|
||||
HasherSearchResult* out, BROTLI_BOOL shallow) {
|
||||
size_t key;
|
||||
size_t i;
|
||||
HasherCommon* self = GetHasherCommon(handle);
|
||||
if (self->dict_num_matches < (self->dict_num_lookups >> 7)) {
|
||||
if (common->dict_num_matches < (common->dict_num_lookups >> 7)) {
|
||||
return;
|
||||
}
|
||||
key = Hash14(data) << 1;
|
||||
for (i = 0; i < (shallow ? 1u : 2u); ++i, ++key) {
|
||||
size_t item = dictionary->hash_table[key];
|
||||
self->dict_num_lookups++;
|
||||
if (item != 0) {
|
||||
common->dict_num_lookups++;
|
||||
if (dictionary->hash_table_lengths[key] != 0) {
|
||||
BROTLI_BOOL item_matches = TestStaticDictionaryItem(
|
||||
dictionary, item, data, max_length, max_backward, max_distance, out);
|
||||
dictionary, dictionary->hash_table_lengths[key],
|
||||
dictionary->hash_table_words[key], data,
|
||||
max_length, max_backward, max_distance, out);
|
||||
if (item_matches) {
|
||||
self->dict_num_matches++;
|
||||
common->dict_num_matches++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -251,7 +228,7 @@ static BROTLI_INLINE size_t BackwardMatchLengthCode(const BackwardMatch* self) {
|
||||
#define BUCKET_BITS 17
|
||||
#define MAX_TREE_SEARCH_DEPTH 64
|
||||
#define MAX_TREE_COMP_LENGTH 128
|
||||
#include "./hash_to_binary_tree_inc.h" /* NOLINT(build/include) */
|
||||
#include "hash_to_binary_tree_inc.h" /* NOLINT(build/include) */
|
||||
#undef MAX_TREE_SEARCH_DEPTH
|
||||
#undef MAX_TREE_COMP_LENGTH
|
||||
#undef BUCKET_BITS
|
||||
@@ -259,61 +236,71 @@ static BROTLI_INLINE size_t BackwardMatchLengthCode(const BackwardMatch* self) {
|
||||
/* MAX_NUM_MATCHES == 64 + MAX_TREE_SEARCH_DEPTH */
|
||||
#define MAX_NUM_MATCHES_H10 128
|
||||
|
||||
/* For BUCKET_SWEEP == 1, enabling the dictionary lookup makes compression
|
||||
/* For BUCKET_SWEEP_BITS == 0, enabling the dictionary lookup makes compression
|
||||
a little faster (0.5% - 1%) and it compresses 0.15% better on small text
|
||||
and HTML inputs. */
|
||||
|
||||
#define HASHER() H2
|
||||
#define BUCKET_BITS 16
|
||||
#define BUCKET_SWEEP 1
|
||||
#define BUCKET_SWEEP_BITS 0
|
||||
#define HASH_LEN 5
|
||||
#define USE_DICTIONARY 1
|
||||
#include "./hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */
|
||||
#undef BUCKET_SWEEP
|
||||
#include "hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */
|
||||
#undef BUCKET_SWEEP_BITS
|
||||
#undef USE_DICTIONARY
|
||||
#undef HASHER
|
||||
|
||||
#define HASHER() H3
|
||||
#define BUCKET_SWEEP 2
|
||||
#define BUCKET_SWEEP_BITS 1
|
||||
#define USE_DICTIONARY 0
|
||||
#include "./hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */
|
||||
#include "hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */
|
||||
#undef USE_DICTIONARY
|
||||
#undef BUCKET_SWEEP
|
||||
#undef BUCKET_SWEEP_BITS
|
||||
#undef BUCKET_BITS
|
||||
#undef HASHER
|
||||
|
||||
#define HASHER() H4
|
||||
#define BUCKET_BITS 17
|
||||
#define BUCKET_SWEEP 4
|
||||
#define BUCKET_SWEEP_BITS 2
|
||||
#define USE_DICTIONARY 1
|
||||
#include "./hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */
|
||||
#include "hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */
|
||||
#undef USE_DICTIONARY
|
||||
#undef HASH_LEN
|
||||
#undef BUCKET_SWEEP
|
||||
#undef BUCKET_SWEEP_BITS
|
||||
#undef BUCKET_BITS
|
||||
#undef HASHER
|
||||
|
||||
#define HASHER() H5
|
||||
#include "./hash_longest_match_inc.h" /* NOLINT(build/include) */
|
||||
#include "hash_longest_match_inc.h" /* NOLINT(build/include) */
|
||||
#undef HASHER
|
||||
|
||||
#define HASHER() H6
|
||||
#include "./hash_longest_match64_inc.h" /* NOLINT(build/include) */
|
||||
#include "hash_longest_match64_inc.h" /* NOLINT(build/include) */
|
||||
#undef HASHER
|
||||
|
||||
#if defined(BROTLI_MAX_SIMD_QUALITY)
|
||||
#define HASHER() H58
|
||||
#include "hash_longest_match_simd_inc.h" /* NOLINT(build/include) */
|
||||
#undef HASHER
|
||||
|
||||
#define HASHER() H68
|
||||
#include "hash_longest_match64_simd_inc.h" /* NOLINT(build/include) */
|
||||
#undef HASHER
|
||||
#endif
|
||||
|
||||
#define BUCKET_BITS 15
|
||||
|
||||
#define NUM_LAST_DISTANCES_TO_CHECK 4
|
||||
#define NUM_BANKS 1
|
||||
#define BANK_BITS 16
|
||||
#define HASHER() H40
|
||||
#include "./hash_forgetful_chain_inc.h" /* NOLINT(build/include) */
|
||||
#include "hash_forgetful_chain_inc.h" /* NOLINT(build/include) */
|
||||
#undef HASHER
|
||||
#undef NUM_LAST_DISTANCES_TO_CHECK
|
||||
|
||||
#define NUM_LAST_DISTANCES_TO_CHECK 10
|
||||
#define HASHER() H41
|
||||
#include "./hash_forgetful_chain_inc.h" /* NOLINT(build/include) */
|
||||
#include "hash_forgetful_chain_inc.h" /* NOLINT(build/include) */
|
||||
#undef HASHER
|
||||
#undef NUM_LAST_DISTANCES_TO_CHECK
|
||||
#undef NUM_BANKS
|
||||
@@ -323,7 +310,7 @@ static BROTLI_INLINE size_t BackwardMatchLengthCode(const BackwardMatch* self) {
|
||||
#define NUM_BANKS 512
|
||||
#define BANK_BITS 9
|
||||
#define HASHER() H42
|
||||
#include "./hash_forgetful_chain_inc.h" /* NOLINT(build/include) */
|
||||
#include "hash_forgetful_chain_inc.h" /* NOLINT(build/include) */
|
||||
#undef HASHER
|
||||
#undef NUM_LAST_DISTANCES_TO_CHECK
|
||||
#undef NUM_BANKS
|
||||
@@ -333,13 +320,13 @@ static BROTLI_INLINE size_t BackwardMatchLengthCode(const BackwardMatch* self) {
|
||||
|
||||
#define HASHER() H54
|
||||
#define BUCKET_BITS 20
|
||||
#define BUCKET_SWEEP 4
|
||||
#define BUCKET_SWEEP_BITS 2
|
||||
#define HASH_LEN 7
|
||||
#define USE_DICTIONARY 0
|
||||
#include "./hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */
|
||||
#include "hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */
|
||||
#undef USE_DICTIONARY
|
||||
#undef HASH_LEN
|
||||
#undef BUCKET_SWEEP
|
||||
#undef BUCKET_SWEEP_BITS
|
||||
#undef BUCKET_BITS
|
||||
#undef HASHER
|
||||
|
||||
@@ -350,14 +337,14 @@ static BROTLI_INLINE size_t BackwardMatchLengthCode(const BackwardMatch* self) {
|
||||
#define JUMP 4
|
||||
#define NUMBUCKETS 16777216
|
||||
#define MASK ((NUMBUCKETS * 64) - 1)
|
||||
#include "./hash_rolling_inc.h" /* NOLINT(build/include) */
|
||||
#include "hash_rolling_inc.h" /* NOLINT(build/include) */
|
||||
#undef JUMP
|
||||
#undef HASHER
|
||||
|
||||
|
||||
#define HASHER() HROLLING
|
||||
#define JUMP 1
|
||||
#include "./hash_rolling_inc.h" /* NOLINT(build/include) */
|
||||
#include "hash_rolling_inc.h" /* NOLINT(build/include) */
|
||||
#undef MASK
|
||||
#undef NUMBUCKETS
|
||||
#undef JUMP
|
||||
@@ -367,7 +354,7 @@ static BROTLI_INLINE size_t BackwardMatchLengthCode(const BackwardMatch* self) {
|
||||
#define HASHER() H35
|
||||
#define HASHER_A H3
|
||||
#define HASHER_B HROLLING_FAST
|
||||
#include "./hash_composite_inc.h" /* NOLINT(build/include) */
|
||||
#include "hash_composite_inc.h" /* NOLINT(build/include) */
|
||||
#undef HASHER_A
|
||||
#undef HASHER_B
|
||||
#undef HASHER
|
||||
@@ -375,7 +362,7 @@ static BROTLI_INLINE size_t BackwardMatchLengthCode(const BackwardMatch* self) {
|
||||
#define HASHER() H55
|
||||
#define HASHER_A H54
|
||||
#define HASHER_B HROLLING_FAST
|
||||
#include "./hash_composite_inc.h" /* NOLINT(build/include) */
|
||||
#include "hash_composite_inc.h" /* NOLINT(build/include) */
|
||||
#undef HASHER_A
|
||||
#undef HASHER_B
|
||||
#undef HASHER
|
||||
@@ -383,7 +370,7 @@ static BROTLI_INLINE size_t BackwardMatchLengthCode(const BackwardMatch* self) {
|
||||
#define HASHER() H65
|
||||
#define HASHER_A H6
|
||||
#define HASHER_B HROLLING
|
||||
#include "./hash_composite_inc.h" /* NOLINT(build/include) */
|
||||
#include "hash_composite_inc.h" /* NOLINT(build/include) */
|
||||
#undef HASHER_A
|
||||
#undef HASHER_B
|
||||
#undef HASHER
|
||||
@@ -392,97 +379,122 @@ static BROTLI_INLINE size_t BackwardMatchLengthCode(const BackwardMatch* self) {
|
||||
#undef CAT
|
||||
#undef EXPAND_CAT
|
||||
|
||||
#define FOR_GENERIC_HASHERS(H) H(2) H(3) H(4) H(5) H(6) H(40) H(41) H(42) H(54)\
|
||||
H(35) H(55) H(65)
|
||||
#if defined(BROTLI_MAX_SIMD_QUALITY)
|
||||
#define FOR_SIMPLE_HASHERS(H) \
|
||||
H(2) H(3) H(4) H(5) H(6) H(40) H(41) H(42) H(54) H(58) H(68)
|
||||
#else
|
||||
#define FOR_SIMPLE_HASHERS(H) \
|
||||
H(2) H(3) H(4) H(5) H(6) H(40) H(41) H(42) H(54)
|
||||
#endif
|
||||
#define FOR_COMPOSITE_HASHERS(H) H(35) H(55) H(65)
|
||||
#define FOR_GENERIC_HASHERS(H) FOR_SIMPLE_HASHERS(H) FOR_COMPOSITE_HASHERS(H)
|
||||
#define FOR_ALL_HASHERS(H) FOR_GENERIC_HASHERS(H) H(10)
|
||||
|
||||
static BROTLI_INLINE void DestroyHasher(
|
||||
MemoryManager* m, HasherHandle* handle) {
|
||||
if (*handle == NULL) return;
|
||||
BROTLI_FREE(m, *handle);
|
||||
typedef struct {
|
||||
HasherCommon common;
|
||||
|
||||
union {
|
||||
#define MEMBER_(N) \
|
||||
H ## N _H ## N;
|
||||
FOR_ALL_HASHERS(MEMBER_)
|
||||
#undef MEMBER_
|
||||
} privat;
|
||||
} Hasher;
|
||||
|
||||
/* MUST be invoked before any other method. */
|
||||
static BROTLI_INLINE void HasherInit(Hasher* hasher) {
|
||||
hasher->common.is_setup_ = BROTLI_FALSE;
|
||||
hasher->common.extra[0] = NULL;
|
||||
hasher->common.extra[1] = NULL;
|
||||
hasher->common.extra[2] = NULL;
|
||||
hasher->common.extra[3] = NULL;
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void HasherReset(HasherHandle handle) {
|
||||
if (handle == NULL) return;
|
||||
GetHasherCommon(handle)->is_prepared_ = BROTLI_FALSE;
|
||||
static BROTLI_INLINE void DestroyHasher(MemoryManager* m, Hasher* hasher) {
|
||||
if (hasher->common.extra[0] != NULL) BROTLI_FREE(m, hasher->common.extra[0]);
|
||||
if (hasher->common.extra[1] != NULL) BROTLI_FREE(m, hasher->common.extra[1]);
|
||||
if (hasher->common.extra[2] != NULL) BROTLI_FREE(m, hasher->common.extra[2]);
|
||||
if (hasher->common.extra[3] != NULL) BROTLI_FREE(m, hasher->common.extra[3]);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE size_t HasherSize(const BrotliEncoderParams* params,
|
||||
BROTLI_BOOL one_shot, const size_t input_size) {
|
||||
size_t result = sizeof(HasherCommon);
|
||||
static BROTLI_INLINE void HasherReset(Hasher* hasher) {
|
||||
hasher->common.is_prepared_ = BROTLI_FALSE;
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void HasherSize(const BrotliEncoderParams* params,
|
||||
BROTLI_BOOL one_shot, const size_t input_size, size_t* alloc_size) {
|
||||
switch (params->hasher.type) {
|
||||
#define SIZE_(N) \
|
||||
case N: \
|
||||
result += HashMemAllocInBytesH ## N(params, one_shot, input_size); \
|
||||
#define SIZE_(N) \
|
||||
case N: \
|
||||
HashMemAllocInBytesH ## N(params, one_shot, input_size, alloc_size); \
|
||||
break;
|
||||
FOR_ALL_HASHERS(SIZE_)
|
||||
#undef SIZE_
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void HasherSetup(MemoryManager* m, HasherHandle* handle,
|
||||
static BROTLI_INLINE void HasherSetup(MemoryManager* m, Hasher* hasher,
|
||||
BrotliEncoderParams* params, const uint8_t* data, size_t position,
|
||||
size_t input_size, BROTLI_BOOL is_last) {
|
||||
HasherHandle self = NULL;
|
||||
HasherCommon* common = NULL;
|
||||
BROTLI_BOOL one_shot = (position == 0 && is_last);
|
||||
if (*handle == NULL) {
|
||||
size_t alloc_size;
|
||||
if (!hasher->common.is_setup_) {
|
||||
size_t alloc_size[4] = {0};
|
||||
size_t i;
|
||||
ChooseHasher(params, ¶ms->hasher);
|
||||
alloc_size = HasherSize(params, one_shot, input_size);
|
||||
self = BROTLI_ALLOC(m, uint8_t, alloc_size);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
*handle = self;
|
||||
common = GetHasherCommon(self);
|
||||
common->params = params->hasher;
|
||||
switch (common->params.type) {
|
||||
#define INITIALIZE_(N) \
|
||||
case N: \
|
||||
InitializeH ## N(*handle, params); \
|
||||
hasher->common.params = params->hasher;
|
||||
hasher->common.dict_num_lookups = 0;
|
||||
hasher->common.dict_num_matches = 0;
|
||||
HasherSize(params, one_shot, input_size, alloc_size);
|
||||
for (i = 0; i < 4; ++i) {
|
||||
if (alloc_size[i] == 0) continue;
|
||||
hasher->common.extra[i] = BROTLI_ALLOC(m, uint8_t, alloc_size[i]);
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(hasher->common.extra[i])) return;
|
||||
}
|
||||
switch (hasher->common.params.type) {
|
||||
#define INITIALIZE_(N) \
|
||||
case N: \
|
||||
InitializeH ## N(&hasher->common, \
|
||||
&hasher->privat._H ## N, params); \
|
||||
break;
|
||||
FOR_ALL_HASHERS(INITIALIZE_);
|
||||
#undef INITIALIZE_
|
||||
default:
|
||||
break;
|
||||
}
|
||||
HasherReset(*handle);
|
||||
HasherReset(hasher);
|
||||
hasher->common.is_setup_ = BROTLI_TRUE;
|
||||
}
|
||||
|
||||
self = *handle;
|
||||
common = GetHasherCommon(self);
|
||||
if (!common->is_prepared_) {
|
||||
switch (common->params.type) {
|
||||
#define PREPARE_(N) \
|
||||
case N: \
|
||||
PrepareH ## N(self, one_shot, input_size, data); \
|
||||
if (!hasher->common.is_prepared_) {
|
||||
switch (hasher->common.params.type) {
|
||||
#define PREPARE_(N) \
|
||||
case N: \
|
||||
PrepareH ## N( \
|
||||
&hasher->privat._H ## N, \
|
||||
one_shot, input_size, data); \
|
||||
break;
|
||||
FOR_ALL_HASHERS(PREPARE_)
|
||||
#undef PREPARE_
|
||||
default: break;
|
||||
}
|
||||
if (position == 0) {
|
||||
common->dict_num_lookups = 0;
|
||||
common->dict_num_matches = 0;
|
||||
}
|
||||
common->is_prepared_ = BROTLI_TRUE;
|
||||
hasher->common.is_prepared_ = BROTLI_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void InitOrStitchToPreviousBlock(
|
||||
MemoryManager* m, HasherHandle* handle, const uint8_t* data, size_t mask,
|
||||
MemoryManager* m, Hasher* hasher, const uint8_t* data, size_t mask,
|
||||
BrotliEncoderParams* params, size_t position, size_t input_size,
|
||||
BROTLI_BOOL is_last) {
|
||||
HasherHandle self;
|
||||
HasherSetup(m, handle, params, data, position, input_size, is_last);
|
||||
HasherSetup(m, hasher, params, data, position, input_size, is_last);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
self = *handle;
|
||||
switch (GetHasherCommon(self)->params.type) {
|
||||
#define INIT_(N) \
|
||||
case N: \
|
||||
StitchToPreviousBlockH ## N(self, input_size, position, data, mask); \
|
||||
switch (hasher->common.params.type) {
|
||||
#define INIT_(N) \
|
||||
case N: \
|
||||
StitchToPreviousBlockH ## N( \
|
||||
&hasher->privat._H ## N, \
|
||||
input_size, position, data, mask); \
|
||||
break;
|
||||
FOR_ALL_HASHERS(INIT_)
|
||||
#undef INIT_
|
||||
@@ -490,6 +502,232 @@ static BROTLI_INLINE void InitOrStitchToPreviousBlock(
|
||||
}
|
||||
}
|
||||
|
||||
/* NB: when seamless dictionary-ring-buffer copies are implemented, don't forget
|
||||
to add proper guards for non-zero-BROTLI_PARAM_STREAM_OFFSET. */
|
||||
static BROTLI_INLINE void FindCompoundDictionaryMatch(
|
||||
const PreparedDictionary* self, const uint8_t* BROTLI_RESTRICT data,
|
||||
const size_t ring_buffer_mask, const int* BROTLI_RESTRICT distance_cache,
|
||||
const size_t cur_ix, const size_t max_length, const size_t distance_offset,
|
||||
const size_t max_distance, HasherSearchResult* BROTLI_RESTRICT out) {
|
||||
const uint32_t source_size = self->source_size;
|
||||
const size_t boundary = distance_offset - source_size;
|
||||
const uint32_t hash_bits = self->hash_bits;
|
||||
const uint32_t bucket_bits = self->bucket_bits;
|
||||
const uint32_t slot_bits = self->slot_bits;
|
||||
|
||||
const uint32_t hash_shift = 64u - bucket_bits;
|
||||
const uint32_t slot_mask = (~((uint32_t)0U)) >> (32 - slot_bits);
|
||||
const uint64_t hash_mask = (~((uint64_t)0U)) >> (64 - hash_bits);
|
||||
|
||||
const uint32_t* slot_offsets = (uint32_t*)(&self[1]);
|
||||
const uint16_t* heads = (uint16_t*)(&slot_offsets[(size_t)1u << slot_bits]);
|
||||
const uint32_t* items = (uint32_t*)(&heads[(size_t)1u << bucket_bits]);
|
||||
const uint8_t* source = NULL;
|
||||
|
||||
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
|
||||
score_t best_score = out->score;
|
||||
size_t best_len = out->len;
|
||||
size_t i;
|
||||
const uint64_t h =
|
||||
(BROTLI_UNALIGNED_LOAD64LE(&data[cur_ix_masked]) & hash_mask) *
|
||||
kPreparedDictionaryHashMul64Long;
|
||||
const uint32_t key = (uint32_t)(h >> hash_shift);
|
||||
const uint32_t slot = key & slot_mask;
|
||||
const uint32_t head = heads[key];
|
||||
const uint32_t* BROTLI_RESTRICT chain = &items[slot_offsets[slot] + head];
|
||||
uint32_t item = (head == 0xFFFF) ? 1 : 0;
|
||||
|
||||
const void* tail = (void*)&items[self->num_items];
|
||||
if (self->magic == kPreparedDictionaryMagic) {
|
||||
source = (const uint8_t*)tail;
|
||||
} else {
|
||||
/* kLeanPreparedDictionaryMagic */
|
||||
source = (const uint8_t*)BROTLI_UNALIGNED_LOAD_PTR((const uint8_t**)tail);
|
||||
}
|
||||
|
||||
BROTLI_DCHECK(cur_ix_masked + max_length <= ring_buffer_mask);
|
||||
|
||||
for (i = 0; i < 4; ++i) {
|
||||
const size_t distance = (size_t)distance_cache[i];
|
||||
size_t offset;
|
||||
size_t limit;
|
||||
size_t len;
|
||||
if (distance <= boundary || distance > distance_offset) continue;
|
||||
offset = distance_offset - distance;
|
||||
limit = source_size - offset;
|
||||
limit = limit > max_length ? max_length : limit;
|
||||
len = FindMatchLengthWithLimit(&source[offset], &data[cur_ix_masked],
|
||||
limit);
|
||||
if (len >= 2) {
|
||||
score_t score = BackwardReferenceScoreUsingLastDistance(len);
|
||||
if (best_score < score) {
|
||||
if (i != 0) score -= BackwardReferencePenaltyUsingLastDistance(i);
|
||||
if (best_score < score) {
|
||||
best_score = score;
|
||||
if (len > best_len) best_len = len;
|
||||
out->len = len;
|
||||
out->len_code_delta = 0;
|
||||
out->distance = distance;
|
||||
out->score = best_score;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* we require matches of len >4, so increase best_len to 3, so we can compare
|
||||
* 4 bytes all the time. */
|
||||
if (best_len < 3) {
|
||||
best_len = 3;
|
||||
}
|
||||
while (item == 0) {
|
||||
size_t offset;
|
||||
size_t distance;
|
||||
size_t limit;
|
||||
item = *chain;
|
||||
chain++;
|
||||
offset = item & 0x7FFFFFFF;
|
||||
item &= 0x80000000;
|
||||
distance = distance_offset - offset;
|
||||
limit = source_size - offset;
|
||||
limit = (limit > max_length) ? max_length : limit;
|
||||
if (distance > max_distance) continue;
|
||||
if (cur_ix_masked + best_len > ring_buffer_mask || best_len >= limit ||
|
||||
/* compare 4 bytes ending at best_len + 1 */
|
||||
BrotliUnalignedRead32(&data[cur_ix_masked + best_len - 3]) !=
|
||||
BrotliUnalignedRead32(&source[offset + best_len - 3])) {
|
||||
continue;
|
||||
}
|
||||
{
|
||||
const size_t len = FindMatchLengthWithLimit(&source[offset],
|
||||
&data[cur_ix_masked],
|
||||
limit);
|
||||
if (len >= 4) {
|
||||
score_t score = BackwardReferenceScore(len, distance);
|
||||
if (best_score < score) {
|
||||
best_score = score;
|
||||
best_len = len;
|
||||
out->len = best_len;
|
||||
out->len_code_delta = 0;
|
||||
out->distance = distance;
|
||||
out->score = best_score;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* NB: when seamless dictionary-ring-buffer copies are implemented, don't forget
|
||||
to add proper guards for non-zero-BROTLI_PARAM_STREAM_OFFSET. */
|
||||
static BROTLI_INLINE size_t FindAllCompoundDictionaryMatches(
|
||||
const PreparedDictionary* self, const uint8_t* BROTLI_RESTRICT data,
|
||||
const size_t ring_buffer_mask, const size_t cur_ix, const size_t min_length,
|
||||
const size_t max_length, const size_t distance_offset,
|
||||
const size_t max_distance, BackwardMatch* matches, size_t match_limit) {
|
||||
const uint32_t source_size = self->source_size;
|
||||
const uint32_t hash_bits = self->hash_bits;
|
||||
const uint32_t bucket_bits = self->bucket_bits;
|
||||
const uint32_t slot_bits = self->slot_bits;
|
||||
|
||||
const uint32_t hash_shift = 64u - bucket_bits;
|
||||
const uint32_t slot_mask = (~((uint32_t)0U)) >> (32 - slot_bits);
|
||||
const uint64_t hash_mask = (~((uint64_t)0U)) >> (64 - hash_bits);
|
||||
|
||||
const uint32_t* slot_offsets = (uint32_t*)(&self[1]);
|
||||
const uint16_t* heads = (uint16_t*)(&slot_offsets[(size_t)1u << slot_bits]);
|
||||
const uint32_t* items = (uint32_t*)(&heads[(size_t)1u << bucket_bits]);
|
||||
const uint8_t* source = NULL;
|
||||
|
||||
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
|
||||
size_t best_len = min_length;
|
||||
const uint64_t h =
|
||||
(BROTLI_UNALIGNED_LOAD64LE(&data[cur_ix_masked]) & hash_mask) *
|
||||
kPreparedDictionaryHashMul64Long;
|
||||
const uint32_t key = (uint32_t)(h >> hash_shift);
|
||||
const uint32_t slot = key & slot_mask;
|
||||
const uint32_t head = heads[key];
|
||||
const uint32_t* BROTLI_RESTRICT chain = &items[slot_offsets[slot] + head];
|
||||
uint32_t item = (head == 0xFFFF) ? 1 : 0;
|
||||
size_t found = 0;
|
||||
|
||||
const void* tail = (void*)&items[self->num_items];
|
||||
if (self->magic == kPreparedDictionaryMagic) {
|
||||
source = (const uint8_t*)tail;
|
||||
} else {
|
||||
/* kLeanPreparedDictionaryMagic */
|
||||
source = (const uint8_t*)BROTLI_UNALIGNED_LOAD_PTR((const uint8_t**)tail);
|
||||
}
|
||||
|
||||
BROTLI_DCHECK(cur_ix_masked + max_length <= ring_buffer_mask);
|
||||
|
||||
while (item == 0) {
|
||||
size_t offset;
|
||||
size_t distance;
|
||||
size_t limit;
|
||||
size_t len;
|
||||
item = *chain;
|
||||
chain++;
|
||||
offset = item & 0x7FFFFFFF;
|
||||
item &= 0x80000000;
|
||||
distance = distance_offset - offset;
|
||||
limit = source_size - offset;
|
||||
limit = (limit > max_length) ? max_length : limit;
|
||||
if (distance > max_distance) continue;
|
||||
if (cur_ix_masked + best_len > ring_buffer_mask ||
|
||||
best_len >= limit ||
|
||||
data[cur_ix_masked + best_len] != source[offset + best_len]) {
|
||||
continue;
|
||||
}
|
||||
len = FindMatchLengthWithLimit(
|
||||
&source[offset], &data[cur_ix_masked], limit);
|
||||
if (len > best_len) {
|
||||
best_len = len;
|
||||
InitBackwardMatch(matches++, distance, len);
|
||||
found++;
|
||||
if (found == match_limit) break;
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void LookupCompoundDictionaryMatch(
|
||||
const CompoundDictionary* addon, const uint8_t* BROTLI_RESTRICT data,
|
||||
const size_t ring_buffer_mask, const int* BROTLI_RESTRICT distance_cache,
|
||||
const size_t cur_ix, const size_t max_length,
|
||||
const size_t max_ring_buffer_distance, const size_t max_distance,
|
||||
HasherSearchResult* sr) {
|
||||
size_t base_offset = max_ring_buffer_distance + 1 + addon->total_size - 1;
|
||||
size_t d;
|
||||
for (d = 0; d < addon->num_chunks; ++d) {
|
||||
/* Only one prepared dictionary type is currently supported. */
|
||||
FindCompoundDictionaryMatch(
|
||||
(const PreparedDictionary*)addon->chunks[d], data, ring_buffer_mask,
|
||||
distance_cache, cur_ix, max_length,
|
||||
base_offset - addon->chunk_offsets[d], max_distance, sr);
|
||||
}
|
||||
}
|
||||
|
||||
static BROTLI_INLINE size_t LookupAllCompoundDictionaryMatches(
|
||||
const CompoundDictionary* addon, const uint8_t* BROTLI_RESTRICT data,
|
||||
const size_t ring_buffer_mask, const size_t cur_ix, size_t min_length,
|
||||
const size_t max_length, const size_t max_ring_buffer_distance,
|
||||
const size_t max_distance, BackwardMatch* matches,
|
||||
size_t match_limit) {
|
||||
size_t base_offset = max_ring_buffer_distance + 1 + addon->total_size - 1;
|
||||
size_t d;
|
||||
size_t total_found = 0;
|
||||
for (d = 0; d < addon->num_chunks; ++d) {
|
||||
/* Only one prepared dictionary type is currently supported. */
|
||||
total_found += FindAllCompoundDictionaryMatches(
|
||||
(const PreparedDictionary*)addon->chunks[d], data, ring_buffer_mask,
|
||||
cur_ix, min_length, max_length, base_offset - addon->chunk_offsets[d],
|
||||
max_distance, matches + total_found, match_limit - total_found);
|
||||
if (total_found == match_limit) break;
|
||||
if (total_found > 0) {
|
||||
min_length = BackwardMatchLength(&matches[total_found - 1]);
|
||||
}
|
||||
}
|
||||
return total_found;
|
||||
}
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
38
c/enc/hash_base.h
Normal file
38
c/enc/hash_base.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/* Copyright 2025 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/* Basic common hash functions / constants. */
|
||||
|
||||
#ifndef THIRD_PARTY_BROTLI_ENC_HASH_BASE_H_
|
||||
#define THIRD_PARTY_BROTLI_ENC_HASH_BASE_H_
|
||||
|
||||
#include "../common/platform.h"
|
||||
|
||||
/* kHashMul32 multiplier has these properties:
|
||||
* The multiplier must be odd. Otherwise we may lose the highest bit.
|
||||
* No long streaks of ones or zeros.
|
||||
* There is no effort to ensure that it is a prime, the oddity is enough
|
||||
for this use.
|
||||
* The number has been tuned heuristically against compression benchmarks. */
|
||||
static const uint32_t kHashMul32 = 0x1E35A7BD;
|
||||
static const uint64_t kHashMul64 =
|
||||
BROTLI_MAKE_UINT64_T(0x1FE35A7Bu, 0xD3579BD3u);
|
||||
|
||||
static BROTLI_INLINE uint32_t Hash14(const uint8_t* data) {
|
||||
uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kHashMul32;
|
||||
/* The higher bits contain more mixture from the multiplication,
|
||||
so we take our results from there. */
|
||||
return h >> (32 - 14);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE uint32_t Hash15(const uint8_t* data) {
|
||||
uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kHashMul32;
|
||||
/* The higher bits contain more mixture from the multiplication,
|
||||
so we take our results from there. */
|
||||
return h >> (32 - 15);
|
||||
}
|
||||
|
||||
#endif // THIRD_PARTY_BROTLI_ENC_HASH_BASE_H_
|
||||
141
c/enc/hash_composite_inc.h
Executable file → Normal file
141
c/enc/hash_composite_inc.h
Executable file → Normal file
@@ -28,106 +28,113 @@ static BROTLI_INLINE size_t FN(StoreLookahead)(void) {
|
||||
}
|
||||
|
||||
typedef struct HashComposite {
|
||||
HasherHandle ha;
|
||||
HasherHandle hb;
|
||||
HASHER_A ha;
|
||||
HASHER_B hb;
|
||||
HasherCommon ha_common;
|
||||
HasherCommon hb_common;
|
||||
|
||||
/* Shortcuts. */
|
||||
HasherCommon* common;
|
||||
|
||||
BROTLI_BOOL fresh;
|
||||
const BrotliEncoderParams* params;
|
||||
} HashComposite;
|
||||
|
||||
static BROTLI_INLINE HashComposite* FN(Self)(HasherHandle handle) {
|
||||
return (HashComposite*)&(GetHasherCommon(handle)[1]);
|
||||
}
|
||||
static void FN(Initialize)(HasherCommon* common,
|
||||
HashComposite* BROTLI_RESTRICT self, const BrotliEncoderParams* params) {
|
||||
self->common = common;
|
||||
|
||||
static void FN(Initialize)(
|
||||
HasherHandle handle, const BrotliEncoderParams* params) {
|
||||
HashComposite* self = FN(Self)(handle);
|
||||
self->ha = 0;
|
||||
self->hb = 0;
|
||||
self->ha_common = *self->common;
|
||||
self->hb_common = *self->common;
|
||||
self->fresh = BROTLI_TRUE;
|
||||
self->params = params;
|
||||
/* TODO: Initialize of the hashers is defered to Prepare (and params
|
||||
/* TODO(lode): Initialize of the hashers is deferred to Prepare (and params
|
||||
remembered here) because we don't get the one_shot and input_size params
|
||||
here that are needed to know the memory size of them. Instead provide
|
||||
those params to all hashers FN(Initialize) */
|
||||
}
|
||||
|
||||
static void FN(Prepare)(HasherHandle handle, BROTLI_BOOL one_shot,
|
||||
size_t input_size, const uint8_t* data) {
|
||||
HashComposite* self = FN(Self)(handle);
|
||||
if (!self->ha) {
|
||||
HasherCommon* common_a;
|
||||
HasherCommon* common_b;
|
||||
static void FN(Prepare)(
|
||||
HashComposite* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
|
||||
size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
|
||||
if (self->fresh) {
|
||||
self->fresh = BROTLI_FALSE;
|
||||
self->ha_common.extra[0] = self->common->extra[0];
|
||||
self->ha_common.extra[1] = self->common->extra[1];
|
||||
self->ha_common.extra[2] = NULL;
|
||||
self->ha_common.extra[3] = NULL;
|
||||
self->hb_common.extra[0] = self->common->extra[2];
|
||||
self->hb_common.extra[1] = self->common->extra[3];
|
||||
self->hb_common.extra[2] = NULL;
|
||||
self->hb_common.extra[3] = NULL;
|
||||
|
||||
self->ha = handle + sizeof(HasherCommon) + sizeof(HashComposite);
|
||||
common_a = (HasherCommon*)self->ha;
|
||||
common_a->params = self->params->hasher;
|
||||
common_a->is_prepared_ = BROTLI_FALSE;
|
||||
common_a->dict_num_lookups = 0;
|
||||
common_a->dict_num_matches = 0;
|
||||
FN_A(Initialize)(self->ha, self->params);
|
||||
|
||||
self->hb = self->ha + sizeof(HasherCommon) + FN_A(HashMemAllocInBytes)(
|
||||
self->params, one_shot, input_size);
|
||||
common_b = (HasherCommon*)self->hb;
|
||||
common_b->params = self->params->hasher;
|
||||
common_b->is_prepared_ = BROTLI_FALSE;
|
||||
common_b->dict_num_lookups = 0;
|
||||
common_b->dict_num_matches = 0;
|
||||
FN_B(Initialize)(self->hb, self->params);
|
||||
FN_A(Initialize)(&self->ha_common, &self->ha, self->params);
|
||||
FN_B(Initialize)(&self->hb_common, &self->hb, self->params);
|
||||
}
|
||||
FN_A(Prepare)(self->ha, one_shot, input_size, data);
|
||||
FN_B(Prepare)(self->hb, one_shot, input_size, data);
|
||||
FN_A(Prepare)(&self->ha, one_shot, input_size, data);
|
||||
FN_B(Prepare)(&self->hb, one_shot, input_size, data);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
|
||||
static BROTLI_INLINE void FN(HashMemAllocInBytes)(
|
||||
const BrotliEncoderParams* params, BROTLI_BOOL one_shot,
|
||||
size_t input_size) {
|
||||
return sizeof(HashComposite) + 2 * sizeof(HasherCommon) +
|
||||
FN_A(HashMemAllocInBytes)(params, one_shot, input_size) +
|
||||
FN_B(HashMemAllocInBytes)(params, one_shot, input_size);
|
||||
size_t input_size, size_t* alloc_size) {
|
||||
size_t alloc_size_a[4] = {0};
|
||||
size_t alloc_size_b[4] = {0};
|
||||
FN_A(HashMemAllocInBytes)(params, one_shot, input_size, alloc_size_a);
|
||||
FN_B(HashMemAllocInBytes)(params, one_shot, input_size, alloc_size_b);
|
||||
/* Should never happen. */
|
||||
if (alloc_size_a[2] != 0 || alloc_size_a[3] != 0) exit(EXIT_FAILURE);
|
||||
if (alloc_size_b[2] != 0 || alloc_size_b[3] != 0) exit(EXIT_FAILURE);
|
||||
alloc_size[0] = alloc_size_a[0];
|
||||
alloc_size[1] = alloc_size_a[1];
|
||||
alloc_size[2] = alloc_size_b[0];
|
||||
alloc_size[3] = alloc_size_b[1];
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(Store)(HasherHandle BROTLI_RESTRICT handle,
|
||||
static BROTLI_INLINE void FN(Store)(HashComposite* BROTLI_RESTRICT self,
|
||||
const uint8_t* BROTLI_RESTRICT data, const size_t mask, const size_t ix) {
|
||||
HashComposite* self = FN(Self)(handle);
|
||||
FN_A(Store)(self->ha, data, mask, ix);
|
||||
FN_B(Store)(self->hb, data, mask, ix);
|
||||
FN_A(Store)(&self->ha, data, mask, ix);
|
||||
FN_B(Store)(&self->hb, data, mask, ix);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(StoreRange)(HasherHandle handle,
|
||||
const uint8_t* data, const size_t mask, const size_t ix_start,
|
||||
static BROTLI_INLINE void FN(StoreRange)(
|
||||
HashComposite* BROTLI_RESTRICT self, const uint8_t* BROTLI_RESTRICT data,
|
||||
const size_t mask, const size_t ix_start,
|
||||
const size_t ix_end) {
|
||||
HashComposite* self = FN(Self)(handle);
|
||||
FN_A(StoreRange)(self->ha, data, mask, ix_start, ix_end);
|
||||
FN_B(StoreRange)(self->hb, data, mask, ix_start, ix_end);
|
||||
FN_A(StoreRange)(&self->ha, data, mask, ix_start, ix_end);
|
||||
FN_B(StoreRange)(&self->hb, data, mask, ix_start, ix_end);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(StitchToPreviousBlock)(HasherHandle handle,
|
||||
static BROTLI_INLINE void FN(StitchToPreviousBlock)(
|
||||
HashComposite* BROTLI_RESTRICT self,
|
||||
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
|
||||
size_t ring_buffer_mask) {
|
||||
HashComposite* self = FN(Self)(handle);
|
||||
FN_A(StitchToPreviousBlock)(self->ha, num_bytes, position, ringbuffer,
|
||||
ring_buffer_mask);
|
||||
FN_B(StitchToPreviousBlock)(self->hb, num_bytes, position, ringbuffer,
|
||||
ring_buffer_mask);
|
||||
FN_A(StitchToPreviousBlock)(&self->ha, num_bytes, position,
|
||||
ringbuffer, ring_buffer_mask);
|
||||
FN_B(StitchToPreviousBlock)(&self->hb, num_bytes, position,
|
||||
ringbuffer, ring_buffer_mask);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(PrepareDistanceCache)(
|
||||
HasherHandle handle, int* BROTLI_RESTRICT distance_cache) {
|
||||
HashComposite* self = FN(Self)(handle);
|
||||
FN_A(PrepareDistanceCache)(self->ha, distance_cache);
|
||||
FN_B(PrepareDistanceCache)(self->hb, distance_cache);
|
||||
HashComposite* BROTLI_RESTRICT self, int* BROTLI_RESTRICT distance_cache) {
|
||||
FN_A(PrepareDistanceCache)(&self->ha, distance_cache);
|
||||
FN_B(PrepareDistanceCache)(&self->hb, distance_cache);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
||||
static BROTLI_INLINE void FN(FindLongestMatch)(
|
||||
HashComposite* BROTLI_RESTRICT self,
|
||||
const BrotliEncoderDictionary* dictionary,
|
||||
const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask,
|
||||
const int* BROTLI_RESTRICT distance_cache, const size_t cur_ix,
|
||||
const size_t max_length, const size_t max_backward, const size_t gap,
|
||||
const size_t max_distance, HasherSearchResult* BROTLI_RESTRICT out) {
|
||||
HashComposite* self = FN(Self)(handle);
|
||||
FN_A(FindLongestMatch)(self->ha, dictionary, data, ring_buffer_mask,
|
||||
distance_cache, cur_ix, max_length, max_backward, gap, max_distance, out);
|
||||
FN_B(FindLongestMatch)(self->hb, dictionary, data, ring_buffer_mask,
|
||||
distance_cache, cur_ix, max_length, max_backward, gap, max_distance, out);
|
||||
const size_t max_length, const size_t max_backward,
|
||||
const size_t dictionary_distance, const size_t max_distance,
|
||||
HasherSearchResult* BROTLI_RESTRICT out) {
|
||||
FN_A(FindLongestMatch)(&self->ha, dictionary, data, ring_buffer_mask,
|
||||
distance_cache, cur_ix, max_length, max_backward, dictionary_distance,
|
||||
max_distance, out);
|
||||
FN_B(FindLongestMatch)(&self->hb, dictionary, data, ring_buffer_mask,
|
||||
distance_cache, cur_ix, max_length, max_backward, dictionary_distance,
|
||||
max_distance, out);
|
||||
}
|
||||
|
||||
#undef HashComposite
|
||||
|
||||
@@ -28,7 +28,7 @@ static BROTLI_INLINE size_t FN(HashTypeLength)(void) { return 4; }
|
||||
static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 4; }
|
||||
|
||||
/* HashBytes is the function that chooses the bucket to place the address in.*/
|
||||
static BROTLI_INLINE size_t FN(HashBytes)(const uint8_t* data) {
|
||||
static BROTLI_INLINE size_t FN(HashBytes)(const uint8_t* BROTLI_RESTRICT data) {
|
||||
const uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kHashMul32;
|
||||
/* The higher bits contain more mixture from the multiplication,
|
||||
so we take our results from there. */
|
||||
@@ -45,28 +45,57 @@ typedef struct FN(Bank) {
|
||||
} FN(Bank);
|
||||
|
||||
typedef struct HashForgetfulChain {
|
||||
uint32_t addr[BUCKET_SIZE];
|
||||
uint16_t head[BUCKET_SIZE];
|
||||
/* Truncated hash used for quick rejection of "distance cache" candidates. */
|
||||
uint8_t tiny_hash[65536];
|
||||
FN(Bank) banks[NUM_BANKS];
|
||||
uint16_t free_slot_idx[NUM_BANKS];
|
||||
uint16_t free_slot_idx[NUM_BANKS]; /* Up to 1KiB. Move to dynamic? */
|
||||
size_t max_hops;
|
||||
|
||||
/* Shortcuts. */
|
||||
void* extra[2];
|
||||
HasherCommon* common;
|
||||
|
||||
/* --- Dynamic size members --- */
|
||||
|
||||
/* uint32_t addr[BUCKET_SIZE]; */
|
||||
|
||||
/* uint16_t head[BUCKET_SIZE]; */
|
||||
|
||||
/* Truncated hash used for quick rejection of "distance cache" candidates. */
|
||||
/* uint8_t tiny_hash[65536];*/
|
||||
|
||||
/* FN(Bank) banks[NUM_BANKS]; */
|
||||
} HashForgetfulChain;
|
||||
|
||||
static BROTLI_INLINE HashForgetfulChain* FN(Self)(HasherHandle handle) {
|
||||
return (HashForgetfulChain*)&(GetHasherCommon(handle)[1]);
|
||||
static uint32_t* FN(Addr)(void* extra) {
|
||||
return (uint32_t*)extra;
|
||||
}
|
||||
|
||||
static uint16_t* FN(Head)(void* extra) {
|
||||
return (uint16_t*)(&FN(Addr)(extra)[BUCKET_SIZE]);
|
||||
}
|
||||
|
||||
static uint8_t* FN(TinyHash)(void* extra) {
|
||||
return (uint8_t*)(&FN(Head)(extra)[BUCKET_SIZE]);
|
||||
}
|
||||
|
||||
static FN(Bank)* FN(Banks)(void* extra) {
|
||||
return (FN(Bank)*)(extra);
|
||||
}
|
||||
|
||||
static void FN(Initialize)(
|
||||
HasherHandle handle, const BrotliEncoderParams* params) {
|
||||
FN(Self)(handle)->max_hops =
|
||||
(params->quality > 6 ? 7u : 8u) << (params->quality - 4);
|
||||
HasherCommon* common, HashForgetfulChain* BROTLI_RESTRICT self,
|
||||
const BrotliEncoderParams* params) {
|
||||
self->common = common;
|
||||
self->extra[0] = common->extra[0];
|
||||
self->extra[1] = common->extra[1];
|
||||
|
||||
self->max_hops = (params->quality > 6 ? 7u : 8u) << (params->quality - 4);
|
||||
}
|
||||
|
||||
static void FN(Prepare)(HasherHandle handle, BROTLI_BOOL one_shot,
|
||||
size_t input_size, const uint8_t* data) {
|
||||
HashForgetfulChain* self = FN(Self)(handle);
|
||||
static void FN(Prepare)(
|
||||
HashForgetfulChain* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
|
||||
size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
|
||||
uint32_t* BROTLI_RESTRICT addr = FN(Addr)(self->extra[0]);
|
||||
uint16_t* BROTLI_RESTRICT head = FN(Head)(self->extra[0]);
|
||||
uint8_t* BROTLI_RESTRICT tiny_hash = FN(TinyHash)(self->extra[0]);
|
||||
/* Partial preparation is 100 times slower (per socket). */
|
||||
size_t partial_prepare_threshold = BUCKET_SIZE >> 6;
|
||||
if (one_shot && input_size <= partial_prepare_threshold) {
|
||||
@@ -74,71 +103,79 @@ static void FN(Prepare)(HasherHandle handle, BROTLI_BOOL one_shot,
|
||||
for (i = 0; i < input_size; ++i) {
|
||||
size_t bucket = FN(HashBytes)(&data[i]);
|
||||
/* See InitEmpty comment. */
|
||||
self->addr[bucket] = 0xCCCCCCCC;
|
||||
self->head[bucket] = 0xCCCC;
|
||||
addr[bucket] = 0xCCCCCCCC;
|
||||
head[bucket] = 0xCCCC;
|
||||
}
|
||||
} else {
|
||||
/* Fill |addr| array with 0xCCCCCCCC value. Because of wrapping, position
|
||||
processed by hasher never reaches 3GB + 64M; this makes all new chains
|
||||
to be terminated after the first node. */
|
||||
memset(self->addr, 0xCC, sizeof(self->addr));
|
||||
memset(self->head, 0, sizeof(self->head));
|
||||
memset(addr, 0xCC, sizeof(uint32_t) * BUCKET_SIZE);
|
||||
memset(head, 0, sizeof(uint16_t) * BUCKET_SIZE);
|
||||
}
|
||||
memset(self->tiny_hash, 0, sizeof(self->tiny_hash));
|
||||
memset(tiny_hash, 0, sizeof(uint8_t) * 65536);
|
||||
memset(self->free_slot_idx, 0, sizeof(self->free_slot_idx));
|
||||
}
|
||||
|
||||
static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
|
||||
static BROTLI_INLINE void FN(HashMemAllocInBytes)(
|
||||
const BrotliEncoderParams* params, BROTLI_BOOL one_shot,
|
||||
size_t input_size) {
|
||||
size_t input_size, size_t* alloc_size) {
|
||||
BROTLI_UNUSED(params);
|
||||
BROTLI_UNUSED(one_shot);
|
||||
BROTLI_UNUSED(input_size);
|
||||
return sizeof(HashForgetfulChain);
|
||||
alloc_size[0] = sizeof(uint32_t) * BUCKET_SIZE +
|
||||
sizeof(uint16_t) * BUCKET_SIZE + sizeof(uint8_t) * 65536;
|
||||
alloc_size[1] = sizeof(FN(Bank)) * NUM_BANKS;
|
||||
}
|
||||
|
||||
/* Look at 4 bytes at &data[ix & mask]. Compute a hash from these, and prepend
|
||||
node to corresponding chain; also update tiny_hash for current position. */
|
||||
static BROTLI_INLINE void FN(Store)(HasherHandle BROTLI_RESTRICT handle,
|
||||
static BROTLI_INLINE void FN(Store)(HashForgetfulChain* BROTLI_RESTRICT self,
|
||||
const uint8_t* BROTLI_RESTRICT data, const size_t mask, const size_t ix) {
|
||||
HashForgetfulChain* self = FN(Self)(handle);
|
||||
uint32_t* BROTLI_RESTRICT addr = FN(Addr)(self->extra[0]);
|
||||
uint16_t* BROTLI_RESTRICT head = FN(Head)(self->extra[0]);
|
||||
uint8_t* BROTLI_RESTRICT tiny_hash = FN(TinyHash)(self->extra[0]);
|
||||
FN(Bank)* BROTLI_RESTRICT banks = FN(Banks)(self->extra[1]);
|
||||
const size_t key = FN(HashBytes)(&data[ix & mask]);
|
||||
const size_t bank = key & (NUM_BANKS - 1);
|
||||
const size_t idx = self->free_slot_idx[bank]++ & (BANK_SIZE - 1);
|
||||
size_t delta = ix - self->addr[key];
|
||||
self->tiny_hash[(uint16_t)ix] = (uint8_t)key;
|
||||
size_t delta = ix - addr[key];
|
||||
tiny_hash[(uint16_t)ix] = (uint8_t)key;
|
||||
if (delta > 0xFFFF) delta = CAPPED_CHAINS ? 0 : 0xFFFF;
|
||||
self->banks[bank].slots[idx].delta = (uint16_t)delta;
|
||||
self->banks[bank].slots[idx].next = self->head[key];
|
||||
self->addr[key] = (uint32_t)ix;
|
||||
self->head[key] = (uint16_t)idx;
|
||||
banks[bank].slots[idx].delta = (uint16_t)delta;
|
||||
banks[bank].slots[idx].next = head[key];
|
||||
addr[key] = (uint32_t)ix;
|
||||
head[key] = (uint16_t)idx;
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(StoreRange)(HasherHandle handle,
|
||||
const uint8_t* data, const size_t mask, const size_t ix_start,
|
||||
const size_t ix_end) {
|
||||
static BROTLI_INLINE void FN(StoreRange)(
|
||||
HashForgetfulChain* BROTLI_RESTRICT self,
|
||||
const uint8_t* BROTLI_RESTRICT data, const size_t mask,
|
||||
const size_t ix_start, const size_t ix_end) {
|
||||
size_t i;
|
||||
for (i = ix_start; i < ix_end; ++i) {
|
||||
FN(Store)(handle, data, mask, i);
|
||||
FN(Store)(self, data, mask, i);
|
||||
}
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(StitchToPreviousBlock)(HasherHandle handle,
|
||||
static BROTLI_INLINE void FN(StitchToPreviousBlock)(
|
||||
HashForgetfulChain* BROTLI_RESTRICT self,
|
||||
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
|
||||
size_t ring_buffer_mask) {
|
||||
if (num_bytes >= FN(HashTypeLength)() - 1 && position >= 3) {
|
||||
/* Prepare the hashes for three last bytes of the last write.
|
||||
These could not be calculated before, since they require knowledge
|
||||
of both the previous and the current block. */
|
||||
FN(Store)(handle, ringbuffer, ring_buffer_mask, position - 3);
|
||||
FN(Store)(handle, ringbuffer, ring_buffer_mask, position - 2);
|
||||
FN(Store)(handle, ringbuffer, ring_buffer_mask, position - 1);
|
||||
FN(Store)(self, ringbuffer, ring_buffer_mask, position - 3);
|
||||
FN(Store)(self, ringbuffer, ring_buffer_mask, position - 2);
|
||||
FN(Store)(self, ringbuffer, ring_buffer_mask, position - 1);
|
||||
}
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(PrepareDistanceCache)(
|
||||
HasherHandle handle, int* BROTLI_RESTRICT distance_cache) {
|
||||
BROTLI_UNUSED(handle);
|
||||
HashForgetfulChain* BROTLI_RESTRICT self,
|
||||
int* BROTLI_RESTRICT distance_cache) {
|
||||
BROTLI_UNUSED(self);
|
||||
PrepareDistanceCache(distance_cache, NUM_LAST_DISTANCES_TO_CHECK);
|
||||
}
|
||||
|
||||
@@ -153,14 +190,18 @@ static BROTLI_INLINE void FN(PrepareDistanceCache)(
|
||||
Does not look for matches further away than max_backward.
|
||||
Writes the best match into |out|.
|
||||
|out|->score is updated only if a better match is found. */
|
||||
static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
||||
static BROTLI_INLINE void FN(FindLongestMatch)(
|
||||
HashForgetfulChain* BROTLI_RESTRICT self,
|
||||
const BrotliEncoderDictionary* dictionary,
|
||||
const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask,
|
||||
const int* BROTLI_RESTRICT distance_cache,
|
||||
const size_t cur_ix, const size_t max_length, const size_t max_backward,
|
||||
const size_t gap, const size_t max_distance,
|
||||
const size_t dictionary_distance, const size_t max_distance,
|
||||
HasherSearchResult* BROTLI_RESTRICT out) {
|
||||
HashForgetfulChain* self = FN(Self)(handle);
|
||||
uint32_t* BROTLI_RESTRICT addr = FN(Addr)(self->extra[0]);
|
||||
uint16_t* BROTLI_RESTRICT head = FN(Head)(self->extra[0]);
|
||||
uint8_t* BROTLI_RESTRICT tiny_hashes = FN(TinyHash)(self->extra[0]);
|
||||
FN(Bank)* BROTLI_RESTRICT banks = FN(Banks)(self->extra[1]);
|
||||
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
|
||||
/* Don't accept a short copy from far away. */
|
||||
score_t min_score = out->score;
|
||||
@@ -171,12 +212,15 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
||||
const uint8_t tiny_hash = (uint8_t)(key);
|
||||
out->len = 0;
|
||||
out->len_code_delta = 0;
|
||||
|
||||
BROTLI_DCHECK(cur_ix_masked + max_length <= ring_buffer_mask);
|
||||
|
||||
/* Try last distance first. */
|
||||
for (i = 0; i < NUM_LAST_DISTANCES_TO_CHECK; ++i) {
|
||||
const size_t backward = (size_t)distance_cache[i];
|
||||
size_t prev_ix = (cur_ix - backward);
|
||||
/* For distance code 0 we want to consider 2-byte matches. */
|
||||
if (i > 0 && self->tiny_hash[(uint16_t)prev_ix] != tiny_hash) continue;
|
||||
if (i > 0 && tiny_hashes[(uint16_t)prev_ix] != tiny_hash) continue;
|
||||
if (prev_ix >= cur_ix || backward > max_backward) {
|
||||
continue;
|
||||
}
|
||||
@@ -200,23 +244,30 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
||||
}
|
||||
}
|
||||
}
|
||||
/* we require matches of len >4, so increase best_len to 3, so we can compare
|
||||
* 4 bytes all the time. */
|
||||
if (best_len < 3) {
|
||||
best_len = 3;
|
||||
}
|
||||
{
|
||||
const size_t bank = key & (NUM_BANKS - 1);
|
||||
size_t backward = 0;
|
||||
size_t hops = self->max_hops;
|
||||
size_t delta = cur_ix - self->addr[key];
|
||||
size_t slot = self->head[key];
|
||||
size_t delta = cur_ix - addr[key];
|
||||
size_t slot = head[key];
|
||||
while (hops--) {
|
||||
size_t prev_ix;
|
||||
size_t last = slot;
|
||||
backward += delta;
|
||||
if (backward > max_backward || (CAPPED_CHAINS && !delta)) break;
|
||||
prev_ix = (cur_ix - backward) & ring_buffer_mask;
|
||||
slot = self->banks[bank].slots[last].next;
|
||||
delta = self->banks[bank].slots[last].delta;
|
||||
slot = banks[bank].slots[last].next;
|
||||
delta = banks[bank].slots[last].delta;
|
||||
if (cur_ix_masked + best_len > ring_buffer_mask ||
|
||||
prev_ix + best_len > ring_buffer_mask ||
|
||||
data[cur_ix_masked + best_len] != data[prev_ix + best_len]) {
|
||||
/* compare 4 bytes ending at best_len + 1 */
|
||||
BrotliUnalignedRead32(&data[cur_ix_masked + best_len - 3]) !=
|
||||
BrotliUnalignedRead32(&data[prev_ix + best_len - 3])) {
|
||||
continue;
|
||||
}
|
||||
{
|
||||
@@ -238,11 +289,11 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
||||
}
|
||||
}
|
||||
}
|
||||
FN(Store)(handle, data, ring_buffer_mask, cur_ix);
|
||||
FN(Store)(self, data, ring_buffer_mask, cur_ix);
|
||||
}
|
||||
if (out->score == min_score) {
|
||||
SearchInStaticDictionary(dictionary,
|
||||
handle, &data[cur_ix_masked], max_length, max_backward + gap,
|
||||
self->common, &data[cur_ix_masked], max_length, dictionary_distance,
|
||||
max_distance, out, BROTLI_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,13 +20,12 @@ static BROTLI_INLINE size_t FN(HashTypeLength)(void) { return 8; }
|
||||
static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 8; }
|
||||
|
||||
/* HashBytes is the function that chooses the bucket to place the address in. */
|
||||
static BROTLI_INLINE uint32_t FN(HashBytes)(const uint8_t* data,
|
||||
const uint64_t mask,
|
||||
const int shift) {
|
||||
const uint64_t h = (BROTLI_UNALIGNED_LOAD64LE(data) & mask) * kHashMul64Long;
|
||||
static BROTLI_INLINE size_t FN(HashBytes)(const uint8_t* BROTLI_RESTRICT data,
|
||||
uint64_t hash_mul) {
|
||||
const uint64_t h = BROTLI_UNALIGNED_LOAD64LE(data) * hash_mul;
|
||||
/* The higher bits contain more mixture from the multiplication,
|
||||
so we take our results from there. */
|
||||
return (uint32_t)(h >> shift);
|
||||
return (size_t)(h >> (64 - 15));
|
||||
}
|
||||
|
||||
typedef struct HashLongestMatch {
|
||||
@@ -35,57 +34,54 @@ typedef struct HashLongestMatch {
|
||||
/* Only block_size_ newest backward references are kept,
|
||||
and the older are forgotten. */
|
||||
size_t block_size_;
|
||||
/* Left-shift for computing hash bucket index from hash value. */
|
||||
int hash_shift_;
|
||||
/* Mask for selecting the next 4-8 bytes of input */
|
||||
uint64_t hash_mask_;
|
||||
/* Hash multiplier tuned to match length. */
|
||||
uint64_t hash_mul_;
|
||||
/* Mask for accessing entries in a block (in a ring-buffer manner). */
|
||||
uint32_t block_mask_;
|
||||
|
||||
int block_bits_;
|
||||
int num_last_distances_to_check_;
|
||||
|
||||
/* Shortcuts. */
|
||||
HasherCommon* common_;
|
||||
|
||||
/* --- Dynamic size members --- */
|
||||
|
||||
/* Number of entries in a particular bucket. */
|
||||
/* uint16_t num[bucket_size]; */
|
||||
uint16_t* num_; /* uint16_t[bucket_size]; */
|
||||
|
||||
/* Buckets containing block_size_ of backward references. */
|
||||
/* uint32_t* buckets[bucket_size * block_size]; */
|
||||
uint32_t* buckets_; /* uint32_t[bucket_size * block_size]; */
|
||||
} HashLongestMatch;
|
||||
|
||||
static BROTLI_INLINE HashLongestMatch* FN(Self)(HasherHandle handle) {
|
||||
return (HashLongestMatch*)&(GetHasherCommon(handle)[1]);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE uint16_t* FN(Num)(HashLongestMatch* self) {
|
||||
return (uint16_t*)(&self[1]);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE uint32_t* FN(Buckets)(HashLongestMatch* self) {
|
||||
return (uint32_t*)(&FN(Num)(self)[self->bucket_size_]);
|
||||
}
|
||||
|
||||
static void FN(Initialize)(
|
||||
HasherHandle handle, const BrotliEncoderParams* params) {
|
||||
HasherCommon* common = GetHasherCommon(handle);
|
||||
HashLongestMatch* self = FN(Self)(handle);
|
||||
HasherCommon* common, HashLongestMatch* BROTLI_RESTRICT self,
|
||||
const BrotliEncoderParams* params) {
|
||||
self->common_ = common;
|
||||
|
||||
BROTLI_UNUSED(params);
|
||||
self->hash_shift_ = 64 - common->params.bucket_bits;
|
||||
self->hash_mask_ = (~((uint64_t)0U)) >> (64 - 8 * common->params.hash_len);
|
||||
self->hash_mul_ = kHashMul64 << (64 - 5 * 8);
|
||||
BROTLI_DCHECK(common->params.bucket_bits == 15);
|
||||
self->bucket_size_ = (size_t)1 << common->params.bucket_bits;
|
||||
self->block_bits_ = common->params.block_bits;
|
||||
self->block_size_ = (size_t)1 << common->params.block_bits;
|
||||
self->block_mask_ = (uint32_t)(self->block_size_ - 1);
|
||||
self->num_last_distances_to_check_ =
|
||||
common->params.num_last_distances_to_check;
|
||||
self->num_ = (uint16_t*)common->extra[0];
|
||||
self->buckets_ = (uint32_t*)common->extra[1];
|
||||
}
|
||||
|
||||
static void FN(Prepare)(HasherHandle handle, BROTLI_BOOL one_shot,
|
||||
size_t input_size, const uint8_t* data) {
|
||||
HashLongestMatch* self = FN(Self)(handle);
|
||||
uint16_t* num = FN(Num)(self);
|
||||
static void FN(Prepare)(
|
||||
HashLongestMatch* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
|
||||
size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
|
||||
uint16_t* BROTLI_RESTRICT num = self->num_;
|
||||
/* Partial preparation is 100 times slower (per socket). */
|
||||
size_t partial_prepare_threshold = self->bucket_size_ >> 6;
|
||||
if (one_shot && input_size <= partial_prepare_threshold) {
|
||||
size_t i;
|
||||
for (i = 0; i < input_size; ++i) {
|
||||
const uint32_t key = FN(HashBytes)(&data[i], self->hash_mask_,
|
||||
self->hash_shift_);
|
||||
const size_t key = FN(HashBytes)(&data[i], self->hash_mul_);
|
||||
num[key] = 0;
|
||||
}
|
||||
} else {
|
||||
@@ -93,57 +89,58 @@ static void FN(Prepare)(HasherHandle handle, BROTLI_BOOL one_shot,
|
||||
}
|
||||
}
|
||||
|
||||
static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
|
||||
static BROTLI_INLINE void FN(HashMemAllocInBytes)(
|
||||
const BrotliEncoderParams* params, BROTLI_BOOL one_shot,
|
||||
size_t input_size) {
|
||||
size_t input_size, size_t* alloc_size) {
|
||||
size_t bucket_size = (size_t)1 << params->hasher.bucket_bits;
|
||||
size_t block_size = (size_t)1 << params->hasher.block_bits;
|
||||
BROTLI_UNUSED(one_shot);
|
||||
BROTLI_UNUSED(input_size);
|
||||
return sizeof(HashLongestMatch) + bucket_size * (2 + 4 * block_size);
|
||||
alloc_size[0] = sizeof(uint16_t) * bucket_size;
|
||||
alloc_size[1] = sizeof(uint32_t) * bucket_size * block_size;
|
||||
}
|
||||
|
||||
/* Look at 4 bytes at &data[ix & mask].
|
||||
Compute a hash from these, and store the value of ix at that position. */
|
||||
static BROTLI_INLINE void FN(Store)(HasherHandle handle, const uint8_t* data,
|
||||
static BROTLI_INLINE void FN(Store)(
|
||||
HashLongestMatch* BROTLI_RESTRICT self, const uint8_t* BROTLI_RESTRICT data,
|
||||
const size_t mask, const size_t ix) {
|
||||
HashLongestMatch* self = FN(Self)(handle);
|
||||
uint16_t* num = FN(Num)(self);
|
||||
const uint32_t key = FN(HashBytes)(&data[ix & mask], self->hash_mask_,
|
||||
self->hash_shift_);
|
||||
uint16_t* BROTLI_RESTRICT num = self->num_;
|
||||
uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
|
||||
const size_t key = FN(HashBytes)(&data[ix & mask], self->hash_mul_);
|
||||
const size_t minor_ix = num[key] & self->block_mask_;
|
||||
const size_t offset =
|
||||
minor_ix + (key << GetHasherCommon(handle)->params.block_bits);
|
||||
FN(Buckets)(self)[offset] = (uint32_t)ix;
|
||||
const size_t offset = minor_ix + (key << self->block_bits_);
|
||||
++num[key];
|
||||
buckets[offset] = (uint32_t)ix;
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(StoreRange)(HasherHandle handle,
|
||||
const uint8_t* data, const size_t mask, const size_t ix_start,
|
||||
const size_t ix_end) {
|
||||
static BROTLI_INLINE void FN(StoreRange)(HashLongestMatch* BROTLI_RESTRICT self,
|
||||
const uint8_t* BROTLI_RESTRICT data, const size_t mask,
|
||||
const size_t ix_start, const size_t ix_end) {
|
||||
size_t i;
|
||||
for (i = ix_start; i < ix_end; ++i) {
|
||||
FN(Store)(handle, data, mask, i);
|
||||
FN(Store)(self, data, mask, i);
|
||||
}
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(StitchToPreviousBlock)(HasherHandle handle,
|
||||
static BROTLI_INLINE void FN(StitchToPreviousBlock)(
|
||||
HashLongestMatch* BROTLI_RESTRICT self,
|
||||
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
|
||||
size_t ringbuffer_mask) {
|
||||
if (num_bytes >= FN(HashTypeLength)() - 1 && position >= 3) {
|
||||
/* Prepare the hashes for three last bytes of the last write.
|
||||
These could not be calculated before, since they require knowledge
|
||||
of both the previous and the current block. */
|
||||
FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 3);
|
||||
FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 2);
|
||||
FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 1);
|
||||
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 3);
|
||||
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 2);
|
||||
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 1);
|
||||
}
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(PrepareDistanceCache)(
|
||||
HasherHandle handle, int* BROTLI_RESTRICT distance_cache) {
|
||||
PrepareDistanceCache(distance_cache,
|
||||
GetHasherCommon(handle)->params.num_last_distances_to_check);
|
||||
HashLongestMatch* BROTLI_RESTRICT self,
|
||||
int* BROTLI_RESTRICT distance_cache) {
|
||||
PrepareDistanceCache(distance_cache, self->num_last_distances_to_check_);
|
||||
}
|
||||
|
||||
/* Find a longest backward match of &data[cur_ix] up to the length of
|
||||
@@ -157,26 +154,34 @@ static BROTLI_INLINE void FN(PrepareDistanceCache)(
|
||||
Does not look for matches further away than max_backward.
|
||||
Writes the best match into |out|.
|
||||
|out|->score is updated only if a better match is found. */
|
||||
static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
||||
static BROTLI_INLINE void FN(FindLongestMatch)(
|
||||
HashLongestMatch* BROTLI_RESTRICT self,
|
||||
const BrotliEncoderDictionary* dictionary,
|
||||
const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask,
|
||||
const int* BROTLI_RESTRICT distance_cache, const size_t cur_ix,
|
||||
const size_t max_length, const size_t max_backward, const size_t gap,
|
||||
const size_t max_distance, HasherSearchResult* BROTLI_RESTRICT out) {
|
||||
HasherCommon* common = GetHasherCommon(handle);
|
||||
HashLongestMatch* self = FN(Self)(handle);
|
||||
uint16_t* num = FN(Num)(self);
|
||||
uint32_t* buckets = FN(Buckets)(self);
|
||||
const size_t max_length, const size_t max_backward,
|
||||
const size_t dictionary_distance, const size_t max_distance,
|
||||
HasherSearchResult* BROTLI_RESTRICT out) {
|
||||
uint16_t* BROTLI_RESTRICT num = self->num_;
|
||||
uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
|
||||
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
|
||||
/* Don't accept a short copy from far away. */
|
||||
score_t min_score = out->score;
|
||||
score_t best_score = out->score;
|
||||
size_t best_len = out->len;
|
||||
size_t i;
|
||||
/* Precalculate the hash key and prefetch the bucket. */
|
||||
const size_t key = FN(HashBytes)(&data[cur_ix_masked], self->hash_mul_);
|
||||
uint32_t* BROTLI_RESTRICT bucket = &buckets[key << self->block_bits_];
|
||||
PREFETCH_L1(bucket);
|
||||
if (self->block_bits_ > 4) PREFETCH_L1(bucket + 16);
|
||||
out->len = 0;
|
||||
out->len_code_delta = 0;
|
||||
|
||||
BROTLI_DCHECK(cur_ix_masked + max_length <= ring_buffer_mask);
|
||||
|
||||
/* Try last distance first. */
|
||||
for (i = 0; i < (size_t)common->params.num_last_distances_to_check; ++i) {
|
||||
for (i = 0; i < (size_t)self->num_last_distances_to_check_; ++i) {
|
||||
const size_t backward = (size_t)distance_cache[i];
|
||||
size_t prev_ix = (size_t)(cur_ix - backward);
|
||||
if (prev_ix >= cur_ix) {
|
||||
@@ -187,8 +192,10 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
||||
}
|
||||
prev_ix &= ring_buffer_mask;
|
||||
|
||||
if (cur_ix_masked + best_len > ring_buffer_mask ||
|
||||
prev_ix + best_len > ring_buffer_mask ||
|
||||
if (cur_ix_masked + best_len > ring_buffer_mask) {
|
||||
break;
|
||||
}
|
||||
if (prev_ix + best_len > ring_buffer_mask ||
|
||||
data[cur_ix_masked + best_len] != data[prev_ix + best_len]) {
|
||||
continue;
|
||||
}
|
||||
@@ -214,42 +221,48 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
||||
}
|
||||
}
|
||||
}
|
||||
/* we require matches of len >4, so increase best_len to 3, so we can compare
|
||||
* 4 bytes all the time. */
|
||||
if (best_len < 3) {
|
||||
best_len = 3;
|
||||
}
|
||||
{
|
||||
const uint32_t key = FN(HashBytes)(
|
||||
&data[cur_ix_masked], self->hash_mask_, self->hash_shift_);
|
||||
uint32_t* BROTLI_RESTRICT bucket =
|
||||
&buckets[key << common->params.block_bits];
|
||||
const size_t down =
|
||||
(num[key] > self->block_size_) ?
|
||||
(num[key] - self->block_size_) : 0u;
|
||||
for (i = num[key]; i > down;) {
|
||||
const uint32_t first4 = BrotliUnalignedRead32(data + cur_ix_masked);
|
||||
const size_t max_length_m4 = max_length - 4;
|
||||
i = num[key];
|
||||
for (; i > down;) {
|
||||
size_t prev_ix = bucket[--i & self->block_mask_];
|
||||
uint32_t current4;
|
||||
const size_t backward = cur_ix - prev_ix;
|
||||
if (BROTLI_PREDICT_FALSE(backward > max_backward)) {
|
||||
break;
|
||||
}
|
||||
prev_ix &= ring_buffer_mask;
|
||||
if (cur_ix_masked + best_len > ring_buffer_mask ||
|
||||
prev_ix + best_len > ring_buffer_mask ||
|
||||
data[cur_ix_masked + best_len] != data[prev_ix + best_len]) {
|
||||
if (cur_ix_masked + best_len > ring_buffer_mask) {
|
||||
break;
|
||||
}
|
||||
if (prev_ix + best_len > ring_buffer_mask ||
|
||||
/* compare 4 bytes ending at best_len + 1 */
|
||||
BrotliUnalignedRead32(&data[cur_ix_masked + best_len - 3]) !=
|
||||
BrotliUnalignedRead32(&data[prev_ix + best_len - 3])) {
|
||||
continue;
|
||||
}
|
||||
current4 = BrotliUnalignedRead32(data + prev_ix);
|
||||
if (first4 != current4) continue;
|
||||
{
|
||||
const size_t len = FindMatchLengthWithLimit(&data[prev_ix],
|
||||
&data[cur_ix_masked],
|
||||
max_length);
|
||||
if (len >= 4) {
|
||||
/* Comparing for >= 3 does not change the semantics, but just saves
|
||||
for a few unnecessary binary logarithms in backward reference
|
||||
score, since we are not interested in such short matches. */
|
||||
score_t score = BackwardReferenceScore(len, backward);
|
||||
if (best_score < score) {
|
||||
best_score = score;
|
||||
best_len = len;
|
||||
out->len = best_len;
|
||||
out->distance = backward;
|
||||
out->score = best_score;
|
||||
}
|
||||
const size_t len = FindMatchLengthWithLimit(&data[prev_ix + 4],
|
||||
&data[cur_ix_masked + 4],
|
||||
max_length_m4) + 4;
|
||||
const score_t score = BackwardReferenceScore(len, backward);
|
||||
if (best_score < score) {
|
||||
best_score = score;
|
||||
best_len = len;
|
||||
out->len = best_len;
|
||||
out->distance = backward;
|
||||
out->score = best_score;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -258,7 +271,7 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
||||
}
|
||||
if (min_score == out->score) {
|
||||
SearchInStaticDictionary(dictionary,
|
||||
handle, &data[cur_ix_masked], max_length, max_backward + gap,
|
||||
self->common_, &data[cur_ix_masked], max_length, dictionary_distance,
|
||||
max_distance, out, BROTLI_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
304
c/enc/hash_longest_match64_simd_inc.h
Normal file
304
c/enc/hash_longest_match64_simd_inc.h
Normal file
@@ -0,0 +1,304 @@
|
||||
/* NOLINT(build/header_guard) */
|
||||
/* Copyright 2010 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/* template parameters: FN */
|
||||
|
||||
/* A (forgetful) hash table to the data seen by the compressor, to
|
||||
help create backward references to previous data.
|
||||
|
||||
This is a hash map of fixed size (bucket_size_) to a ring buffer of
|
||||
fixed size (block_size_). The ring buffer contains the last block_size_
|
||||
index positions of the given hash key in the compressed data. */
|
||||
|
||||
#define HashLongestMatch HASHER()
|
||||
|
||||
#define TAG_HASH_BITS 8
|
||||
#define TAG_HASH_MASK ((1 << TAG_HASH_BITS) - 1)
|
||||
|
||||
static BROTLI_INLINE size_t FN(HashTypeLength)(void) { return 8; }
|
||||
static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 8; }
|
||||
|
||||
/* HashBytes is the function that chooses the bucket to place the address in. */
|
||||
static BROTLI_INLINE size_t FN(HashBytes)(const uint8_t* BROTLI_RESTRICT data,
|
||||
uint64_t hash_mul) {
|
||||
const uint64_t h = BROTLI_UNALIGNED_LOAD64LE(data) * hash_mul;
|
||||
/* The higher bits contain more mixture from the multiplication,
|
||||
so we take our results from there. */
|
||||
return (size_t)(h >> (64 - 15 - TAG_HASH_BITS));
|
||||
}
|
||||
|
||||
typedef struct HashLongestMatch {
|
||||
/* Number of hash buckets. */
|
||||
size_t bucket_size_;
|
||||
/* Only block_size_ newest backward references are kept,
|
||||
and the older are forgotten. */
|
||||
size_t block_size_;
|
||||
/* Hash multiplier tuned to match length. */
|
||||
uint64_t hash_mul_;
|
||||
/* Mask for accessing entries in a block (in a ring-buffer manner). */
|
||||
uint32_t block_mask_;
|
||||
|
||||
int block_bits_;
|
||||
int num_last_distances_to_check_;
|
||||
|
||||
/* Shortcuts. */
|
||||
HasherCommon* common_;
|
||||
|
||||
/* --- Dynamic size members --- */
|
||||
|
||||
/* Number of entries in a particular bucket. */
|
||||
uint16_t* num_; /* uint16_t[bucket_size]; */
|
||||
|
||||
uint8_t* tags_;
|
||||
|
||||
/* Buckets containing block_size_ of backward references. */
|
||||
uint32_t* buckets_; /* uint32_t[bucket_size * block_size]; */
|
||||
} HashLongestMatch;
|
||||
|
||||
static void FN(Initialize)(
|
||||
HasherCommon* common, HashLongestMatch* BROTLI_RESTRICT self,
|
||||
const BrotliEncoderParams* params) {
|
||||
self->common_ = common;
|
||||
|
||||
BROTLI_UNUSED(params);
|
||||
self->hash_mul_ = kHashMul64 << (64 - 5 * 8);
|
||||
BROTLI_DCHECK(common->params.bucket_bits == 15);
|
||||
self->bucket_size_ = (size_t)1 << common->params.bucket_bits;
|
||||
self->block_bits_ = common->params.block_bits;
|
||||
self->block_size_ = (size_t)1 << common->params.block_bits;
|
||||
self->block_mask_ = (uint32_t)(self->block_size_ - 1);
|
||||
self->num_last_distances_to_check_ =
|
||||
common->params.num_last_distances_to_check;
|
||||
self->num_ = (uint16_t*)common->extra[0];
|
||||
self->tags_ = (uint8_t*)common->extra[1];
|
||||
self->buckets_ = (uint32_t*)common->extra[2];
|
||||
}
|
||||
|
||||
static void FN(Prepare)(
|
||||
HashLongestMatch* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
|
||||
size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
|
||||
uint16_t* BROTLI_RESTRICT num = self->num_;
|
||||
/* Partial preparation is 100 times slower (per socket). */
|
||||
size_t partial_prepare_threshold = self->bucket_size_ >> 6;
|
||||
if (one_shot && input_size <= partial_prepare_threshold) {
|
||||
size_t i;
|
||||
for (i = 0; i < input_size; ++i) {
|
||||
const size_t hash = FN(HashBytes)(&data[i], self->hash_mul_);
|
||||
const size_t key = hash >> TAG_HASH_BITS;
|
||||
num[key] = 65535;
|
||||
}
|
||||
} else {
|
||||
/* Set all the bytes of num to 255, which makes each uint16_t 65535. */
|
||||
memset(num, 255, self->bucket_size_ * sizeof(num[0]));
|
||||
}
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(HashMemAllocInBytes)(
|
||||
const BrotliEncoderParams* params, BROTLI_BOOL one_shot,
|
||||
size_t input_size, size_t* alloc_size) {
|
||||
size_t bucket_size = (size_t)1 << params->hasher.bucket_bits;
|
||||
size_t block_size = (size_t)1 << params->hasher.block_bits;
|
||||
BROTLI_UNUSED(one_shot);
|
||||
BROTLI_UNUSED(input_size);
|
||||
alloc_size[0] = sizeof(uint16_t) * bucket_size;
|
||||
alloc_size[1] = sizeof(uint8_t) * bucket_size * block_size;
|
||||
alloc_size[2] = sizeof(uint32_t) * bucket_size * block_size;
|
||||
}
|
||||
|
||||
/* Look at 4 bytes at &data[ix & mask].
|
||||
Compute a hash from these, and store the value of ix at that position. */
|
||||
static BROTLI_INLINE void FN(Store)(
|
||||
HashLongestMatch* BROTLI_RESTRICT self, const uint8_t* BROTLI_RESTRICT data,
|
||||
const size_t mask, const size_t ix) {
|
||||
uint16_t* BROTLI_RESTRICT num = self->num_;
|
||||
uint8_t* BROTLI_RESTRICT tags = self->tags_;
|
||||
uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
|
||||
const size_t hash = FN(HashBytes)(&data[ix & mask], self->hash_mul_);
|
||||
const size_t key = hash >> TAG_HASH_BITS;
|
||||
const uint8_t tag = hash & TAG_HASH_MASK;
|
||||
const size_t minor_ix = num[key] & self->block_mask_;
|
||||
const size_t offset = minor_ix + (key << self->block_bits_);
|
||||
--num[key];
|
||||
buckets[offset] = (uint32_t)ix;
|
||||
tags[offset] = tag;
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(StoreRange)(HashLongestMatch* BROTLI_RESTRICT self,
|
||||
const uint8_t* BROTLI_RESTRICT data, const size_t mask,
|
||||
const size_t ix_start, const size_t ix_end) {
|
||||
size_t i;
|
||||
for (i = ix_start; i < ix_end; ++i) {
|
||||
FN(Store)(self, data, mask, i);
|
||||
}
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(StitchToPreviousBlock)(
|
||||
HashLongestMatch* BROTLI_RESTRICT self,
|
||||
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
|
||||
size_t ringbuffer_mask) {
|
||||
if (num_bytes >= FN(HashTypeLength)() - 1 && position >= 3) {
|
||||
/* Prepare the hashes for three last bytes of the last write.
|
||||
These could not be calculated before, since they require knowledge
|
||||
of both the previous and the current block. */
|
||||
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 3);
|
||||
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 2);
|
||||
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 1);
|
||||
}
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(PrepareDistanceCache)(
|
||||
HashLongestMatch* BROTLI_RESTRICT self,
|
||||
int* BROTLI_RESTRICT distance_cache) {
|
||||
PrepareDistanceCache(distance_cache, self->num_last_distances_to_check_);
|
||||
}
|
||||
|
||||
/* Find a longest backward match of &data[cur_ix] up to the length of
|
||||
max_length and stores the position cur_ix in the hash table.
|
||||
|
||||
REQUIRES: FN(PrepareDistanceCache) must be invoked for current distance cache
|
||||
values; if this method is invoked repeatedly with the same distance
|
||||
cache values, it is enough to invoke FN(PrepareDistanceCache) once.
|
||||
|
||||
Does not look for matches longer than max_length.
|
||||
Does not look for matches further away than max_backward.
|
||||
Writes the best match into |out|.
|
||||
|out|->score is updated only if a better match is found. */
|
||||
static BROTLI_INLINE void FN(FindLongestMatch)(
|
||||
HashLongestMatch* BROTLI_RESTRICT self,
|
||||
const BrotliEncoderDictionary* dictionary,
|
||||
const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask,
|
||||
const int* BROTLI_RESTRICT distance_cache, const size_t cur_ix,
|
||||
const size_t max_length, const size_t max_backward,
|
||||
const size_t dictionary_distance, const size_t max_distance,
|
||||
HasherSearchResult* BROTLI_RESTRICT out) {
|
||||
uint16_t* BROTLI_RESTRICT num = self->num_;
|
||||
uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
|
||||
uint8_t* BROTLI_RESTRICT tags = self->tags_;
|
||||
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
|
||||
/* Don't accept a short copy from far away. */
|
||||
score_t min_score = out->score;
|
||||
score_t best_score = out->score;
|
||||
size_t best_len = out->len;
|
||||
size_t i;
|
||||
/* Precalculate the hash key and prefetch the bucket. */
|
||||
const size_t hash = FN(HashBytes)(&data[cur_ix_masked], self->hash_mul_);
|
||||
const size_t key = hash >> TAG_HASH_BITS;
|
||||
uint32_t* BROTLI_RESTRICT bucket = &buckets[key << self->block_bits_];
|
||||
uint8_t* BROTLI_RESTRICT tag_bucket = &tags[key << self->block_bits_];
|
||||
PREFETCH_L1(bucket);
|
||||
PREFETCH_L1(tag_bucket);
|
||||
if (self->block_bits_ > 4) PREFETCH_L1(bucket + 16);
|
||||
out->len = 0;
|
||||
out->len_code_delta = 0;
|
||||
|
||||
BROTLI_DCHECK(cur_ix_masked + max_length <= ring_buffer_mask);
|
||||
|
||||
/* Try last distance first. */
|
||||
for (i = 0; i < (size_t)self->num_last_distances_to_check_; ++i) {
|
||||
const size_t backward = (size_t)distance_cache[i];
|
||||
size_t prev_ix = (size_t)(cur_ix - backward);
|
||||
if (prev_ix >= cur_ix) {
|
||||
continue;
|
||||
}
|
||||
if (BROTLI_PREDICT_FALSE(backward > max_backward)) {
|
||||
continue;
|
||||
}
|
||||
prev_ix &= ring_buffer_mask;
|
||||
|
||||
if (cur_ix_masked + best_len > ring_buffer_mask) {
|
||||
break;
|
||||
}
|
||||
if (prev_ix + best_len > ring_buffer_mask ||
|
||||
data[cur_ix_masked + best_len] != data[prev_ix + best_len]) {
|
||||
continue;
|
||||
}
|
||||
{
|
||||
const size_t len = FindMatchLengthWithLimit(&data[prev_ix],
|
||||
&data[cur_ix_masked],
|
||||
max_length);
|
||||
if (len >= 3 || (len == 2 && i < 2)) {
|
||||
/* Comparing for >= 2 does not change the semantics, but just saves for
|
||||
a few unnecessary binary logarithms in backward reference score,
|
||||
since we are not interested in such short matches. */
|
||||
score_t score = BackwardReferenceScoreUsingLastDistance(len);
|
||||
if (best_score < score) {
|
||||
if (i != 0) score -= BackwardReferencePenaltyUsingLastDistance(i);
|
||||
if (best_score < score) {
|
||||
best_score = score;
|
||||
best_len = len;
|
||||
out->len = best_len;
|
||||
out->distance = backward;
|
||||
out->score = best_score;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* we require matches of len >4, so increase best_len to 3, so we can compare
|
||||
* 4 bytes all the time. */
|
||||
if (best_len < 3) {
|
||||
best_len = 3;
|
||||
}
|
||||
{
|
||||
const uint8_t tag = hash & TAG_HASH_MASK;
|
||||
const uint32_t first4 = BrotliUnalignedRead32(data + cur_ix_masked);
|
||||
const size_t max_length_m4 = max_length - 4;
|
||||
const size_t head = (num[key] + 1) & self->block_mask_;
|
||||
uint64_t matches =
|
||||
GetMatchingTagMask(self->block_size_ / 16, tag, tag_bucket, head);
|
||||
/* Mask off any matches from uninitialized tags. */
|
||||
uint16_t n = 65535 - num[key];
|
||||
uint64_t block_has_unused_slots = self->block_size_ > n;
|
||||
uint64_t mask = (block_has_unused_slots << (n & (64 - 1))) - 1;
|
||||
matches &= mask;
|
||||
for (; matches > 0; matches &= (matches - 1)) {
|
||||
const size_t rb_index =
|
||||
(head + (size_t)BROTLI_TZCNT64(matches)) & self->block_mask_;
|
||||
size_t prev_ix = bucket[rb_index];
|
||||
uint32_t current4;
|
||||
const size_t backward = cur_ix - prev_ix;
|
||||
if (BROTLI_PREDICT_FALSE(backward > max_backward)) {
|
||||
break;
|
||||
}
|
||||
prev_ix &= ring_buffer_mask;
|
||||
if (cur_ix_masked + best_len > ring_buffer_mask) {
|
||||
break;
|
||||
}
|
||||
if (prev_ix + best_len > ring_buffer_mask ||
|
||||
/* compare 4 bytes ending at best_len + 1 */
|
||||
BrotliUnalignedRead32(&data[cur_ix_masked + best_len - 3]) !=
|
||||
BrotliUnalignedRead32(&data[prev_ix + best_len - 3])) {
|
||||
continue;
|
||||
}
|
||||
current4 = BrotliUnalignedRead32(data + prev_ix);
|
||||
if (first4 != current4) continue;
|
||||
{
|
||||
const size_t len = FindMatchLengthWithLimit(&data[prev_ix + 4],
|
||||
&data[cur_ix_masked + 4],
|
||||
max_length_m4) + 4;
|
||||
const score_t score = BackwardReferenceScore(len, backward);
|
||||
if (best_score < score) {
|
||||
best_score = score;
|
||||
best_len = len;
|
||||
out->len = best_len;
|
||||
out->distance = backward;
|
||||
out->score = best_score;
|
||||
}
|
||||
}
|
||||
}
|
||||
bucket[num[key] & self->block_mask_] = (uint32_t)cur_ix;
|
||||
tag_bucket[num[key] & self->block_mask_] = tag;
|
||||
--num[key];
|
||||
}
|
||||
if (min_score == out->score) {
|
||||
SearchInStaticDictionary(dictionary,
|
||||
self->common_, &data[cur_ix_masked], max_length, dictionary_distance,
|
||||
max_distance, out, BROTLI_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
#undef HashLongestMatch
|
||||
@@ -20,7 +20,8 @@ static BROTLI_INLINE size_t FN(HashTypeLength)(void) { return 4; }
|
||||
static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 4; }
|
||||
|
||||
/* HashBytes is the function that chooses the bucket to place the address in. */
|
||||
static uint32_t FN(HashBytes)(const uint8_t* data, const int shift) {
|
||||
static uint32_t FN(HashBytes)(
|
||||
const uint8_t* BROTLI_RESTRICT data, const int shift) {
|
||||
uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kHashMul32;
|
||||
/* The higher bits contain more mixture from the multiplication,
|
||||
so we take our results from there. */
|
||||
@@ -38,42 +39,42 @@ typedef struct HashLongestMatch {
|
||||
/* Mask for accessing entries in a block (in a ring-buffer manner). */
|
||||
uint32_t block_mask_;
|
||||
|
||||
int block_bits_;
|
||||
int num_last_distances_to_check_;
|
||||
|
||||
/* Shortcuts. */
|
||||
HasherCommon* common_;
|
||||
|
||||
/* --- Dynamic size members --- */
|
||||
|
||||
/* Number of entries in a particular bucket. */
|
||||
/* uint16_t num[bucket_size]; */
|
||||
uint16_t* num_; /* uint16_t[bucket_size]; */
|
||||
|
||||
/* Buckets containing block_size_ of backward references. */
|
||||
/* uint32_t* buckets[bucket_size * block_size]; */
|
||||
uint32_t* buckets_; /* uint32_t[bucket_size * block_size]; */
|
||||
} HashLongestMatch;
|
||||
|
||||
static BROTLI_INLINE HashLongestMatch* FN(Self)(HasherHandle handle) {
|
||||
return (HashLongestMatch*)&(GetHasherCommon(handle)[1]);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE uint16_t* FN(Num)(HashLongestMatch* self) {
|
||||
return (uint16_t*)(&self[1]);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE uint32_t* FN(Buckets)(HashLongestMatch* self) {
|
||||
return (uint32_t*)(&FN(Num)(self)[self->bucket_size_]);
|
||||
}
|
||||
|
||||
static void FN(Initialize)(
|
||||
HasherHandle handle, const BrotliEncoderParams* params) {
|
||||
HasherCommon* common = GetHasherCommon(handle);
|
||||
HashLongestMatch* self = FN(Self)(handle);
|
||||
HasherCommon* common, HashLongestMatch* BROTLI_RESTRICT self,
|
||||
const BrotliEncoderParams* params) {
|
||||
self->common_ = common;
|
||||
|
||||
BROTLI_UNUSED(params);
|
||||
self->hash_shift_ = 32 - common->params.bucket_bits;
|
||||
self->bucket_size_ = (size_t)1 << common->params.bucket_bits;
|
||||
self->block_size_ = (size_t)1 << common->params.block_bits;
|
||||
self->block_mask_ = (uint32_t)(self->block_size_ - 1);
|
||||
self->num_ = (uint16_t*)common->extra[0];
|
||||
self->buckets_ = (uint32_t*)common->extra[1];
|
||||
self->block_bits_ = common->params.block_bits;
|
||||
self->num_last_distances_to_check_ =
|
||||
common->params.num_last_distances_to_check;
|
||||
}
|
||||
|
||||
static void FN(Prepare)(HasherHandle handle, BROTLI_BOOL one_shot,
|
||||
size_t input_size, const uint8_t* data) {
|
||||
HashLongestMatch* self = FN(Self)(handle);
|
||||
uint16_t* num = FN(Num)(self);
|
||||
static void FN(Prepare)(
|
||||
HashLongestMatch* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
|
||||
size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
|
||||
uint16_t* BROTLI_RESTRICT num = self->num_;
|
||||
/* Partial preparation is 100 times slower (per socket). */
|
||||
size_t partial_prepare_threshold = self->bucket_size_ >> 6;
|
||||
if (one_shot && input_size <= partial_prepare_threshold) {
|
||||
@@ -87,56 +88,58 @@ static void FN(Prepare)(HasherHandle handle, BROTLI_BOOL one_shot,
|
||||
}
|
||||
}
|
||||
|
||||
static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
|
||||
static BROTLI_INLINE void FN(HashMemAllocInBytes)(
|
||||
const BrotliEncoderParams* params, BROTLI_BOOL one_shot,
|
||||
size_t input_size) {
|
||||
size_t input_size, size_t* alloc_size) {
|
||||
size_t bucket_size = (size_t)1 << params->hasher.bucket_bits;
|
||||
size_t block_size = (size_t)1 << params->hasher.block_bits;
|
||||
BROTLI_UNUSED(one_shot);
|
||||
BROTLI_UNUSED(input_size);
|
||||
return sizeof(HashLongestMatch) + bucket_size * (2 + 4 * block_size);
|
||||
alloc_size[0] = sizeof(uint16_t) * bucket_size;
|
||||
alloc_size[1] = sizeof(uint32_t) * bucket_size * block_size;
|
||||
}
|
||||
|
||||
/* Look at 4 bytes at &data[ix & mask].
|
||||
Compute a hash from these, and store the value of ix at that position. */
|
||||
static BROTLI_INLINE void FN(Store)(HasherHandle handle, const uint8_t* data,
|
||||
static BROTLI_INLINE void FN(Store)(
|
||||
HashLongestMatch* BROTLI_RESTRICT self, const uint8_t* BROTLI_RESTRICT data,
|
||||
const size_t mask, const size_t ix) {
|
||||
HashLongestMatch* self = FN(Self)(handle);
|
||||
uint16_t* num = FN(Num)(self);
|
||||
uint16_t* BROTLI_RESTRICT num = self->num_;
|
||||
uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
|
||||
const uint32_t key = FN(HashBytes)(&data[ix & mask], self->hash_shift_);
|
||||
const size_t minor_ix = num[key] & self->block_mask_;
|
||||
const size_t offset =
|
||||
minor_ix + (key << GetHasherCommon(handle)->params.block_bits);
|
||||
FN(Buckets)(self)[offset] = (uint32_t)ix;
|
||||
const size_t offset = minor_ix + (key << self->block_bits_);
|
||||
++num[key];
|
||||
buckets[offset] = (uint32_t)ix;
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(StoreRange)(HasherHandle handle,
|
||||
const uint8_t* data, const size_t mask, const size_t ix_start,
|
||||
const size_t ix_end) {
|
||||
static BROTLI_INLINE void FN(StoreRange)(HashLongestMatch* BROTLI_RESTRICT self,
|
||||
const uint8_t* BROTLI_RESTRICT data, const size_t mask,
|
||||
const size_t ix_start, const size_t ix_end) {
|
||||
size_t i;
|
||||
for (i = ix_start; i < ix_end; ++i) {
|
||||
FN(Store)(handle, data, mask, i);
|
||||
FN(Store)(self, data, mask, i);
|
||||
}
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(StitchToPreviousBlock)(HasherHandle handle,
|
||||
static BROTLI_INLINE void FN(StitchToPreviousBlock)(
|
||||
HashLongestMatch* BROTLI_RESTRICT self,
|
||||
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
|
||||
size_t ringbuffer_mask) {
|
||||
if (num_bytes >= FN(HashTypeLength)() - 1 && position >= 3) {
|
||||
/* Prepare the hashes for three last bytes of the last write.
|
||||
These could not be calculated before, since they require knowledge
|
||||
of both the previous and the current block. */
|
||||
FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 3);
|
||||
FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 2);
|
||||
FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 1);
|
||||
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 3);
|
||||
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 2);
|
||||
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 1);
|
||||
}
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(PrepareDistanceCache)(
|
||||
HasherHandle handle, int* BROTLI_RESTRICT distance_cache) {
|
||||
PrepareDistanceCache(distance_cache,
|
||||
GetHasherCommon(handle)->params.num_last_distances_to_check);
|
||||
HashLongestMatch* BROTLI_RESTRICT self,
|
||||
int* BROTLI_RESTRICT distance_cache) {
|
||||
PrepareDistanceCache(distance_cache, self->num_last_distances_to_check_);
|
||||
}
|
||||
|
||||
/* Find a longest backward match of &data[cur_ix] up to the length of
|
||||
@@ -150,26 +153,35 @@ static BROTLI_INLINE void FN(PrepareDistanceCache)(
|
||||
Does not look for matches further away than max_backward.
|
||||
Writes the best match into |out|.
|
||||
|out|->score is updated only if a better match is found. */
|
||||
static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
||||
static BROTLI_INLINE void FN(FindLongestMatch)(
|
||||
HashLongestMatch* BROTLI_RESTRICT self,
|
||||
const BrotliEncoderDictionary* dictionary,
|
||||
const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask,
|
||||
const int* BROTLI_RESTRICT distance_cache, const size_t cur_ix,
|
||||
const size_t max_length, const size_t max_backward, const size_t gap,
|
||||
const size_t max_distance, HasherSearchResult* BROTLI_RESTRICT out) {
|
||||
HasherCommon* common = GetHasherCommon(handle);
|
||||
HashLongestMatch* self = FN(Self)(handle);
|
||||
uint16_t* num = FN(Num)(self);
|
||||
uint32_t* buckets = FN(Buckets)(self);
|
||||
const size_t max_length, const size_t max_backward,
|
||||
const size_t dictionary_distance, const size_t max_distance,
|
||||
HasherSearchResult* BROTLI_RESTRICT out) {
|
||||
uint16_t* BROTLI_RESTRICT num = self->num_;
|
||||
uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
|
||||
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
|
||||
/* Don't accept a short copy from far away. */
|
||||
score_t min_score = out->score;
|
||||
score_t best_score = out->score;
|
||||
size_t best_len = out->len;
|
||||
size_t i;
|
||||
/* Precalculate the hash key and prefetch the bucket. */
|
||||
const uint32_t key =
|
||||
FN(HashBytes)(&data[cur_ix_masked], self->hash_shift_);
|
||||
uint32_t* BROTLI_RESTRICT bucket = &buckets[key << self->block_bits_];
|
||||
PREFETCH_L1(bucket);
|
||||
if (self->block_bits_ > 4) PREFETCH_L1(bucket + 16);
|
||||
out->len = 0;
|
||||
out->len_code_delta = 0;
|
||||
|
||||
BROTLI_DCHECK(cur_ix_masked + max_length <= ring_buffer_mask);
|
||||
|
||||
/* Try last distance first. */
|
||||
for (i = 0; i < (size_t)common->params.num_last_distances_to_check; ++i) {
|
||||
for (i = 0; i < (size_t)self->num_last_distances_to_check_; ++i) {
|
||||
const size_t backward = (size_t)distance_cache[i];
|
||||
size_t prev_ix = (size_t)(cur_ix - backward);
|
||||
if (prev_ix >= cur_ix) {
|
||||
@@ -180,8 +192,10 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
||||
}
|
||||
prev_ix &= ring_buffer_mask;
|
||||
|
||||
if (cur_ix_masked + best_len > ring_buffer_mask ||
|
||||
prev_ix + best_len > ring_buffer_mask ||
|
||||
if (cur_ix_masked + best_len > ring_buffer_mask) {
|
||||
break;
|
||||
}
|
||||
if (prev_ix + best_len > ring_buffer_mask ||
|
||||
data[cur_ix_masked + best_len] != data[prev_ix + best_len]) {
|
||||
continue;
|
||||
}
|
||||
@@ -207,11 +221,12 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
||||
}
|
||||
}
|
||||
}
|
||||
/* we require matches of len >4, so increase best_len to 3, so we can compare
|
||||
* 4 bytes all the time. */
|
||||
if (best_len < 3) {
|
||||
best_len = 3;
|
||||
}
|
||||
{
|
||||
const uint32_t key =
|
||||
FN(HashBytes)(&data[cur_ix_masked], self->hash_shift_);
|
||||
uint32_t* BROTLI_RESTRICT bucket =
|
||||
&buckets[key << common->params.block_bits];
|
||||
const size_t down =
|
||||
(num[key] > self->block_size_) ? (num[key] - self->block_size_) : 0u;
|
||||
for (i = num[key]; i > down;) {
|
||||
@@ -221,9 +236,13 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
||||
break;
|
||||
}
|
||||
prev_ix &= ring_buffer_mask;
|
||||
if (cur_ix_masked + best_len > ring_buffer_mask ||
|
||||
prev_ix + best_len > ring_buffer_mask ||
|
||||
data[cur_ix_masked + best_len] != data[prev_ix + best_len]) {
|
||||
if (cur_ix_masked + best_len > ring_buffer_mask) {
|
||||
break;
|
||||
}
|
||||
if (prev_ix + best_len > ring_buffer_mask ||
|
||||
/* compare 4 bytes ending at best_len + 1 */
|
||||
BrotliUnalignedRead32(&data[cur_ix_masked + best_len - 3]) !=
|
||||
BrotliUnalignedRead32(&data[prev_ix + best_len - 3])) {
|
||||
continue;
|
||||
}
|
||||
{
|
||||
@@ -250,7 +269,7 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
||||
}
|
||||
if (min_score == out->score) {
|
||||
SearchInStaticDictionary(dictionary,
|
||||
handle, &data[cur_ix_masked], max_length, max_backward + gap,
|
||||
self->common_, &data[cur_ix_masked], max_length, dictionary_distance,
|
||||
max_distance, out, BROTLI_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,15 +5,16 @@
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/* template parameters: FN, BUCKET_BITS, BUCKET_SWEEP, HASH_LEN,
|
||||
/* template parameters: FN, BUCKET_BITS, BUCKET_SWEEP_BITS, HASH_LEN,
|
||||
USE_DICTIONARY
|
||||
*/
|
||||
|
||||
#define HashLongestMatchQuickly HASHER()
|
||||
|
||||
#define BUCKET_SIZE (1 << BUCKET_BITS)
|
||||
|
||||
#define HASH_MAP_SIZE (4 << BUCKET_BITS)
|
||||
#define BUCKET_MASK (BUCKET_SIZE - 1)
|
||||
#define BUCKET_SWEEP (1 << BUCKET_SWEEP_BITS)
|
||||
#define BUCKET_SWEEP_MASK ((BUCKET_SWEEP - 1) << 3)
|
||||
|
||||
static BROTLI_INLINE size_t FN(HashTypeLength)(void) { return 8; }
|
||||
static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 8; }
|
||||
@@ -32,87 +33,106 @@ static uint32_t FN(HashBytes)(const uint8_t* data) {
|
||||
/* A (forgetful) hash table to the data seen by the compressor, to
|
||||
help create backward references to previous data.
|
||||
|
||||
This is a hash map of fixed size (BUCKET_SIZE). Starting from the
|
||||
given index, BUCKET_SWEEP buckets are used to store values of a key. */
|
||||
This is a hash map of fixed size (BUCKET_SIZE). */
|
||||
typedef struct HashLongestMatchQuickly {
|
||||
uint32_t buckets_[BUCKET_SIZE + BUCKET_SWEEP];
|
||||
/* Shortcuts. */
|
||||
HasherCommon* common;
|
||||
|
||||
/* --- Dynamic size members --- */
|
||||
|
||||
uint32_t* buckets_; /* uint32_t[BUCKET_SIZE]; */
|
||||
} HashLongestMatchQuickly;
|
||||
|
||||
static BROTLI_INLINE HashLongestMatchQuickly* FN(Self)(HasherHandle handle) {
|
||||
return (HashLongestMatchQuickly*)&(GetHasherCommon(handle)[1]);
|
||||
}
|
||||
|
||||
static void FN(Initialize)(
|
||||
HasherHandle handle, const BrotliEncoderParams* params) {
|
||||
BROTLI_UNUSED(handle);
|
||||
HasherCommon* common, HashLongestMatchQuickly* BROTLI_RESTRICT self,
|
||||
const BrotliEncoderParams* params) {
|
||||
self->common = common;
|
||||
|
||||
BROTLI_UNUSED(params);
|
||||
self->buckets_ = (uint32_t*)common->extra[0];
|
||||
}
|
||||
|
||||
static void FN(Prepare)(HasherHandle handle, BROTLI_BOOL one_shot,
|
||||
size_t input_size, const uint8_t* data) {
|
||||
HashLongestMatchQuickly* self = FN(Self)(handle);
|
||||
static void FN(Prepare)(
|
||||
HashLongestMatchQuickly* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
|
||||
size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
|
||||
uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
|
||||
/* Partial preparation is 100 times slower (per socket). */
|
||||
size_t partial_prepare_threshold = HASH_MAP_SIZE >> 7;
|
||||
size_t partial_prepare_threshold = BUCKET_SIZE >> 5;
|
||||
if (one_shot && input_size <= partial_prepare_threshold) {
|
||||
size_t i;
|
||||
for (i = 0; i < input_size; ++i) {
|
||||
const uint32_t key = FN(HashBytes)(&data[i]);
|
||||
memset(&self->buckets_[key], 0, BUCKET_SWEEP * sizeof(self->buckets_[0]));
|
||||
if (BUCKET_SWEEP == 1) {
|
||||
buckets[key] = 0;
|
||||
} else {
|
||||
uint32_t j;
|
||||
for (j = 0; j < BUCKET_SWEEP; ++j) {
|
||||
buckets[(key + (j << 3)) & BUCKET_MASK] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* It is not strictly necessary to fill this buffer here, but
|
||||
not filling will make the results of the compression stochastic
|
||||
(but correct). This is because random data would cause the
|
||||
system to find accidentally good backward references here and there. */
|
||||
memset(&self->buckets_[0], 0, sizeof(self->buckets_));
|
||||
memset(buckets, 0, sizeof(uint32_t) * BUCKET_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
|
||||
static BROTLI_INLINE void FN(HashMemAllocInBytes)(
|
||||
const BrotliEncoderParams* params, BROTLI_BOOL one_shot,
|
||||
size_t input_size) {
|
||||
size_t input_size, size_t* alloc_size) {
|
||||
BROTLI_UNUSED(params);
|
||||
BROTLI_UNUSED(one_shot);
|
||||
BROTLI_UNUSED(input_size);
|
||||
return sizeof(HashLongestMatchQuickly);
|
||||
alloc_size[0] = sizeof(uint32_t) * BUCKET_SIZE;
|
||||
}
|
||||
|
||||
/* Look at 5 bytes at &data[ix & mask].
|
||||
Compute a hash from these, and store the value somewhere within
|
||||
[ix .. ix+3]. */
|
||||
static BROTLI_INLINE void FN(Store)(HasherHandle handle,
|
||||
const uint8_t* data, const size_t mask, const size_t ix) {
|
||||
static BROTLI_INLINE void FN(Store)(
|
||||
HashLongestMatchQuickly* BROTLI_RESTRICT self,
|
||||
const uint8_t* BROTLI_RESTRICT data, const size_t mask, const size_t ix) {
|
||||
const uint32_t key = FN(HashBytes)(&data[ix & mask]);
|
||||
/* Wiggle the value with the bucket sweep range. */
|
||||
const uint32_t off = (ix >> 3) % BUCKET_SWEEP;
|
||||
FN(Self)(handle)->buckets_[key + off] = (uint32_t)ix;
|
||||
if (BUCKET_SWEEP == 1) {
|
||||
self->buckets_[key] = (uint32_t)ix;
|
||||
} else {
|
||||
/* Wiggle the value with the bucket sweep range. */
|
||||
const uint32_t off = ix & BUCKET_SWEEP_MASK;
|
||||
self->buckets_[(key + off) & BUCKET_MASK] = (uint32_t)ix;
|
||||
}
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(StoreRange)(HasherHandle handle,
|
||||
const uint8_t* data, const size_t mask, const size_t ix_start,
|
||||
const size_t ix_end) {
|
||||
static BROTLI_INLINE void FN(StoreRange)(
|
||||
HashLongestMatchQuickly* BROTLI_RESTRICT self,
|
||||
const uint8_t* BROTLI_RESTRICT data, const size_t mask,
|
||||
const size_t ix_start, const size_t ix_end) {
|
||||
size_t i;
|
||||
for (i = ix_start; i < ix_end; ++i) {
|
||||
FN(Store)(handle, data, mask, i);
|
||||
FN(Store)(self, data, mask, i);
|
||||
}
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(StitchToPreviousBlock)(
|
||||
HasherHandle handle, size_t num_bytes, size_t position,
|
||||
HashLongestMatchQuickly* BROTLI_RESTRICT self,
|
||||
size_t num_bytes, size_t position,
|
||||
const uint8_t* ringbuffer, size_t ringbuffer_mask) {
|
||||
if (num_bytes >= FN(HashTypeLength)() - 1 && position >= 3) {
|
||||
/* Prepare the hashes for three last bytes of the last write.
|
||||
These could not be calculated before, since they require knowledge
|
||||
of both the previous and the current block. */
|
||||
FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 3);
|
||||
FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 2);
|
||||
FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 1);
|
||||
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 3);
|
||||
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 2);
|
||||
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 1);
|
||||
}
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(PrepareDistanceCache)(
|
||||
HasherHandle handle, int* BROTLI_RESTRICT distance_cache) {
|
||||
BROTLI_UNUSED(handle);
|
||||
HashLongestMatchQuickly* BROTLI_RESTRICT self,
|
||||
int* BROTLI_RESTRICT distance_cache) {
|
||||
BROTLI_UNUSED(self);
|
||||
BROTLI_UNUSED(distance_cache);
|
||||
}
|
||||
|
||||
@@ -125,41 +145,47 @@ static BROTLI_INLINE void FN(PrepareDistanceCache)(
|
||||
Writes the best match into |out|.
|
||||
|out|->score is updated only if a better match is found. */
|
||||
static BROTLI_INLINE void FN(FindLongestMatch)(
|
||||
HasherHandle handle, const BrotliEncoderDictionary* dictionary,
|
||||
HashLongestMatchQuickly* BROTLI_RESTRICT self,
|
||||
const BrotliEncoderDictionary* dictionary,
|
||||
const uint8_t* BROTLI_RESTRICT data,
|
||||
const size_t ring_buffer_mask, const int* BROTLI_RESTRICT distance_cache,
|
||||
const size_t cur_ix, const size_t max_length, const size_t max_backward,
|
||||
const size_t gap, const size_t max_distance,
|
||||
const size_t dictionary_distance, const size_t max_distance,
|
||||
HasherSearchResult* BROTLI_RESTRICT out) {
|
||||
HashLongestMatchQuickly* self = FN(Self)(handle);
|
||||
uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
|
||||
const size_t best_len_in = out->len;
|
||||
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
|
||||
const uint32_t key = FN(HashBytes)(&data[cur_ix_masked]);
|
||||
/* TODO: compare 4 bytes at once (and set the minimum best len to 4) */
|
||||
int compare_char = data[cur_ix_masked + best_len_in];
|
||||
size_t key = FN(HashBytes)(&data[cur_ix_masked]);
|
||||
size_t key_out;
|
||||
score_t min_score = out->score;
|
||||
score_t best_score = out->score;
|
||||
size_t best_len = best_len_in;
|
||||
size_t cached_backward = (size_t)distance_cache[0];
|
||||
size_t prev_ix = cur_ix - cached_backward;
|
||||
|
||||
BROTLI_DCHECK(cur_ix_masked + max_length <= ring_buffer_mask);
|
||||
|
||||
out->len_code_delta = 0;
|
||||
if (prev_ix < cur_ix) {
|
||||
prev_ix &= (uint32_t)ring_buffer_mask;
|
||||
if (compare_char == data[prev_ix + best_len]) {
|
||||
size_t len = FindMatchLengthWithLimit(&data[prev_ix],
|
||||
&data[cur_ix_masked],
|
||||
max_length);
|
||||
const size_t len = FindMatchLengthWithLimit(
|
||||
&data[prev_ix], &data[cur_ix_masked], max_length);
|
||||
if (len >= 4) {
|
||||
const score_t score = BackwardReferenceScoreUsingLastDistance(len);
|
||||
if (best_score < score) {
|
||||
best_score = score;
|
||||
best_len = len;
|
||||
out->len = len;
|
||||
out->distance = cached_backward;
|
||||
out->score = best_score;
|
||||
compare_char = data[cur_ix_masked + best_len];
|
||||
out->score = score;
|
||||
if (BUCKET_SWEEP == 1) {
|
||||
self->buckets_[key] = (uint32_t)cur_ix;
|
||||
buckets[key] = (uint32_t)cur_ix;
|
||||
return;
|
||||
} else {
|
||||
best_len = len;
|
||||
best_score = score;
|
||||
compare_char = data[cur_ix_masked + len];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -169,8 +195,8 @@ static BROTLI_INLINE void FN(FindLongestMatch)(
|
||||
size_t backward;
|
||||
size_t len;
|
||||
/* Only one to look for, don't bother to prepare for a loop. */
|
||||
prev_ix = self->buckets_[key];
|
||||
self->buckets_[key] = (uint32_t)cur_ix;
|
||||
prev_ix = buckets[key];
|
||||
buckets[key] = (uint32_t)cur_ix;
|
||||
backward = cur_ix - prev_ix;
|
||||
prev_ix &= (uint32_t)ring_buffer_mask;
|
||||
if (compare_char != data[prev_ix + best_len_in]) {
|
||||
@@ -192,12 +218,17 @@ static BROTLI_INLINE void FN(FindLongestMatch)(
|
||||
}
|
||||
}
|
||||
} else {
|
||||
uint32_t* bucket = self->buckets_ + key;
|
||||
int i;
|
||||
prev_ix = *bucket++;
|
||||
for (i = 0; i < BUCKET_SWEEP; ++i, prev_ix = *bucket++) {
|
||||
const size_t backward = cur_ix - prev_ix;
|
||||
size_t keys[BUCKET_SWEEP];
|
||||
size_t i;
|
||||
for (i = 0; i < BUCKET_SWEEP; ++i) {
|
||||
keys[i] = (key + (i << 3)) & BUCKET_MASK;
|
||||
}
|
||||
key_out = keys[(cur_ix & BUCKET_SWEEP_MASK) >> 3];
|
||||
for (i = 0; i < BUCKET_SWEEP; ++i) {
|
||||
size_t len;
|
||||
size_t backward;
|
||||
prev_ix = buckets[keys[i]];
|
||||
backward = cur_ix - prev_ix;
|
||||
prev_ix &= (uint32_t)ring_buffer_mask;
|
||||
if (compare_char != data[prev_ix + best_len]) {
|
||||
continue;
|
||||
@@ -211,25 +242,29 @@ static BROTLI_INLINE void FN(FindLongestMatch)(
|
||||
if (len >= 4) {
|
||||
const score_t score = BackwardReferenceScore(len, backward);
|
||||
if (best_score < score) {
|
||||
best_score = score;
|
||||
best_len = len;
|
||||
out->len = best_len;
|
||||
out->distance = backward;
|
||||
out->len = len;
|
||||
compare_char = data[cur_ix_masked + len];
|
||||
best_score = score;
|
||||
out->score = score;
|
||||
compare_char = data[cur_ix_masked + best_len];
|
||||
out->distance = backward;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (USE_DICTIONARY && min_score == out->score) {
|
||||
SearchInStaticDictionary(dictionary,
|
||||
handle, &data[cur_ix_masked], max_length, max_backward + gap,
|
||||
self->common, &data[cur_ix_masked], max_length, dictionary_distance,
|
||||
max_distance, out, BROTLI_TRUE);
|
||||
}
|
||||
self->buckets_[key + ((cur_ix >> 3) % BUCKET_SWEEP)] = (uint32_t)cur_ix;
|
||||
if (BUCKET_SWEEP != 1) {
|
||||
buckets[key_out] = (uint32_t)cur_ix;
|
||||
}
|
||||
}
|
||||
|
||||
#undef HASH_MAP_SIZE
|
||||
#undef BUCKET_SWEEP_MASK
|
||||
#undef BUCKET_SWEEP
|
||||
#undef BUCKET_MASK
|
||||
#undef BUCKET_SIZE
|
||||
|
||||
#undef HashLongestMatchQuickly
|
||||
|
||||
278
c/enc/hash_longest_match_simd_inc.h
Normal file
278
c/enc/hash_longest_match_simd_inc.h
Normal file
@@ -0,0 +1,278 @@
|
||||
/* NOLINT(build/header_guard) */
|
||||
/* Copyright 2010 Google Inc. All Rights Reserved.
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
/* template parameters: FN */
|
||||
/* A (forgetful) hash table to the data seen by the compressor, to
|
||||
help create backward references to previous data.
|
||||
This is a hash map of fixed size (bucket_size_) to a ring buffer of
|
||||
fixed size (block_size_). The ring buffer contains the last block_size_
|
||||
index positions of the given hash key in the compressed data. */
|
||||
#define HashLongestMatch HASHER()
|
||||
#define TAG_HASH_BITS 8
|
||||
#define TAG_HASH_MASK ((1 << TAG_HASH_BITS) - 1)
|
||||
static BROTLI_INLINE size_t FN(HashTypeLength)(void) { return 4; }
|
||||
static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 4; }
|
||||
/* HashBytes is the function that chooses the bucket to place the address in. */
|
||||
static uint32_t FN(HashBytes)(
|
||||
const uint8_t* BROTLI_RESTRICT data, const int shift) {
|
||||
uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kHashMul32;
|
||||
/* The higher bits contain more mixture from the multiplication,
|
||||
so we take our results from there. */
|
||||
return (uint32_t)(h >> shift);
|
||||
}
|
||||
typedef struct HashLongestMatch {
|
||||
/* Number of hash buckets. */
|
||||
size_t bucket_size_;
|
||||
/* Only block_size_ newest backward references are kept,
|
||||
and the older are forgotten. */
|
||||
size_t block_size_;
|
||||
/* Left-shift for computing hash bucket index from hash value. */
|
||||
int hash_shift_;
|
||||
/* Mask for accessing entries in a block (in a ring-buffer manner). */
|
||||
uint32_t block_mask_;
|
||||
int block_bits_;
|
||||
int num_last_distances_to_check_;
|
||||
/* Shortcuts. */
|
||||
HasherCommon* common_;
|
||||
/* --- Dynamic size members --- */
|
||||
/* Number of entries in a particular bucket. */
|
||||
uint16_t* num_; /* uint16_t[bucket_size]; */
|
||||
uint8_t* tags_;
|
||||
/* Buckets containing block_size_ of backward references. */
|
||||
uint32_t* buckets_; /* uint32_t[bucket_size * block_size]; */
|
||||
} HashLongestMatch;
|
||||
static void FN(Initialize)(
|
||||
HasherCommon* common, HashLongestMatch* BROTLI_RESTRICT self,
|
||||
const BrotliEncoderParams* params) {
|
||||
self->common_ = common;
|
||||
BROTLI_UNUSED(params);
|
||||
self->hash_shift_ = 32 - common->params.bucket_bits - TAG_HASH_BITS;
|
||||
self->bucket_size_ = (size_t)1 << common->params.bucket_bits;
|
||||
self->block_size_ = (size_t)1 << common->params.block_bits;
|
||||
self->block_mask_ = (uint32_t)(self->block_size_ - 1);
|
||||
self->num_ = (uint16_t*)common->extra[0];
|
||||
self->tags_ = (uint8_t*)common->extra[1];
|
||||
self->buckets_ = (uint32_t*)common->extra[2];
|
||||
self->block_bits_ = common->params.block_bits;
|
||||
self->num_last_distances_to_check_ =
|
||||
common->params.num_last_distances_to_check;
|
||||
}
|
||||
static void FN(Prepare)(
|
||||
HashLongestMatch* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
|
||||
size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
|
||||
uint16_t* BROTLI_RESTRICT num = self->num_;
|
||||
/* Partial preparation is 100 times slower (per socket). */
|
||||
size_t partial_prepare_threshold = self->bucket_size_ >> 6;
|
||||
if (one_shot && input_size <= partial_prepare_threshold) {
|
||||
size_t i;
|
||||
for (i = 0; i < input_size; ++i) {
|
||||
const uint32_t hash = FN(HashBytes)(&data[i], self->hash_shift_);
|
||||
const uint32_t key = hash >> TAG_HASH_BITS;
|
||||
num[key] = 65535;
|
||||
}
|
||||
} else {
|
||||
/* Set all the bytes of num to 255, which makes each uint16_t 65535. */
|
||||
memset(num, 255, self->bucket_size_ * sizeof(num[0]));
|
||||
}
|
||||
}
|
||||
static BROTLI_INLINE void FN(HashMemAllocInBytes)(
|
||||
const BrotliEncoderParams* params, BROTLI_BOOL one_shot,
|
||||
size_t input_size, size_t* alloc_size) {
|
||||
size_t bucket_size = (size_t)1 << params->hasher.bucket_bits;
|
||||
size_t block_size = (size_t)1 << params->hasher.block_bits;
|
||||
BROTLI_UNUSED(one_shot);
|
||||
BROTLI_UNUSED(input_size);
|
||||
alloc_size[0] = sizeof(uint16_t) * bucket_size;
|
||||
alloc_size[1] = sizeof(uint8_t) * bucket_size * block_size;
|
||||
alloc_size[2] = sizeof(uint32_t) * bucket_size * block_size;
|
||||
}
|
||||
/* Look at 4 bytes at &data[ix & mask].
|
||||
Compute a hash from these, and store the value of ix at that position. */
|
||||
static BROTLI_INLINE void FN(Store)(
|
||||
HashLongestMatch* BROTLI_RESTRICT self, const uint8_t* BROTLI_RESTRICT data,
|
||||
const size_t mask, const size_t ix) {
|
||||
uint16_t* BROTLI_RESTRICT num = self->num_;
|
||||
uint8_t* BROTLI_RESTRICT tags = self->tags_;
|
||||
uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
|
||||
const size_t hash = FN(HashBytes)(&data[ix & mask], self->hash_shift_);
|
||||
const size_t key = hash >> TAG_HASH_BITS;
|
||||
const uint8_t tag = hash & TAG_HASH_MASK;
|
||||
const size_t minor_ix = num[key] & self->block_mask_;
|
||||
const size_t offset = minor_ix + (key << self->block_bits_);
|
||||
--num[key];
|
||||
buckets[offset] = (uint32_t)ix;
|
||||
tags[offset] = tag;
|
||||
}
|
||||
static BROTLI_INLINE void FN(StoreRange)(HashLongestMatch* BROTLI_RESTRICT self,
|
||||
const uint8_t* BROTLI_RESTRICT data, const size_t mask,
|
||||
const size_t ix_start, const size_t ix_end) {
|
||||
size_t i;
|
||||
for (i = ix_start; i < ix_end; ++i) {
|
||||
FN(Store)(self, data, mask, i);
|
||||
}
|
||||
}
|
||||
static BROTLI_INLINE void FN(StitchToPreviousBlock)(
|
||||
HashLongestMatch* BROTLI_RESTRICT self,
|
||||
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
|
||||
size_t ringbuffer_mask) {
|
||||
if (num_bytes >= FN(HashTypeLength)() - 1 && position >= 3) {
|
||||
/* Prepare the hashes for three last bytes of the last write.
|
||||
These could not be calculated before, since they require knowledge
|
||||
of both the previous and the current block. */
|
||||
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 3);
|
||||
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 2);
|
||||
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 1);
|
||||
}
|
||||
}
|
||||
static BROTLI_INLINE void FN(PrepareDistanceCache)(
|
||||
HashLongestMatch* BROTLI_RESTRICT self,
|
||||
int* BROTLI_RESTRICT distance_cache) {
|
||||
PrepareDistanceCache(distance_cache, self->num_last_distances_to_check_);
|
||||
}
|
||||
|
||||
/* Find a longest backward match of &data[cur_ix] up to the length of
|
||||
max_length and stores the position cur_ix in the hash table.
|
||||
REQUIRES: FN(PrepareDistanceCache) must be invoked for current distance cache
|
||||
values; if this method is invoked repeatedly with the same distance
|
||||
cache values, it is enough to invoke FN(PrepareDistanceCache) once.
|
||||
Does not look for matches longer than max_length.
|
||||
Does not look for matches further away than max_backward.
|
||||
Writes the best match into |out|.
|
||||
|out|->score is updated only if a better match is found. */
|
||||
static BROTLI_INLINE void FN(FindLongestMatch)(
|
||||
HashLongestMatch* BROTLI_RESTRICT self,
|
||||
const BrotliEncoderDictionary* dictionary,
|
||||
const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask,
|
||||
const int* BROTLI_RESTRICT distance_cache, const size_t cur_ix,
|
||||
const size_t max_length, const size_t max_backward,
|
||||
const size_t dictionary_distance, const size_t max_distance,
|
||||
HasherSearchResult* BROTLI_RESTRICT out) {
|
||||
uint16_t* BROTLI_RESTRICT num = self->num_;
|
||||
uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
|
||||
uint8_t* BROTLI_RESTRICT tags = self->tags_;
|
||||
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
|
||||
/* Don't accept a short copy from far away. */
|
||||
score_t min_score = out->score;
|
||||
score_t best_score = out->score;
|
||||
size_t best_len = out->len;
|
||||
size_t i;
|
||||
/* Precalculate the hash key and prefetch the bucket. */
|
||||
const uint32_t hash =
|
||||
FN(HashBytes)(&data[cur_ix_masked], self->hash_shift_);
|
||||
const uint32_t key = hash >> TAG_HASH_BITS;
|
||||
uint32_t* BROTLI_RESTRICT bucket = &buckets[key << self->block_bits_];
|
||||
uint8_t* BROTLI_RESTRICT tag_bucket = &tags[key << self->block_bits_];
|
||||
PREFETCH_L1(bucket);
|
||||
PREFETCH_L1(tag_bucket);
|
||||
if (self->block_bits_ > 4) PREFETCH_L1(bucket + 16);
|
||||
out->len = 0;
|
||||
out->len_code_delta = 0;
|
||||
|
||||
BROTLI_DCHECK(cur_ix_masked + max_length <= ring_buffer_mask);
|
||||
|
||||
/* Try last distance first. */
|
||||
for (i = 0; i < (size_t)self->num_last_distances_to_check_; ++i) {
|
||||
const size_t backward = (size_t)distance_cache[i];
|
||||
size_t prev_ix = (size_t)(cur_ix - backward);
|
||||
if (prev_ix >= cur_ix) {
|
||||
continue;
|
||||
}
|
||||
if (BROTLI_PREDICT_FALSE(backward > max_backward)) {
|
||||
continue;
|
||||
}
|
||||
prev_ix &= ring_buffer_mask;
|
||||
|
||||
if (cur_ix_masked + best_len > ring_buffer_mask) {
|
||||
break;
|
||||
}
|
||||
if (prev_ix + best_len > ring_buffer_mask ||
|
||||
data[cur_ix_masked + best_len] != data[prev_ix + best_len]) {
|
||||
continue;
|
||||
}
|
||||
{
|
||||
const size_t len = FindMatchLengthWithLimit(&data[prev_ix],
|
||||
&data[cur_ix_masked],
|
||||
max_length);
|
||||
if (len >= 3 || (len == 2 && i < 2)) {
|
||||
/* Comparing for >= 2 does not change the semantics, but just saves for
|
||||
a few unnecessary binary logarithms in backward reference score,
|
||||
since we are not interested in such short matches. */
|
||||
score_t score = BackwardReferenceScoreUsingLastDistance(len);
|
||||
if (best_score < score) {
|
||||
if (i != 0) score -= BackwardReferencePenaltyUsingLastDistance(i);
|
||||
if (best_score < score) {
|
||||
best_score = score;
|
||||
best_len = len;
|
||||
out->len = best_len;
|
||||
out->distance = backward;
|
||||
out->score = best_score;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* we require matches of len >4, so increase best_len to 3, so we can compare
|
||||
* 4 bytes all the time. */
|
||||
if (best_len < 3) {
|
||||
best_len = 3;
|
||||
}
|
||||
{
|
||||
const uint8_t tag = hash & TAG_HASH_MASK;
|
||||
const size_t head = (num[key] + 1) & self->block_mask_;
|
||||
uint64_t matches =
|
||||
GetMatchingTagMask(self->block_size_ / 16, tag, tag_bucket, head);
|
||||
/* Mask off any matches from uninitialized tags. */
|
||||
uint16_t n = 65535 - num[key];
|
||||
uint64_t block_has_unused_slots = self->block_size_ > n;
|
||||
uint64_t mask = (block_has_unused_slots << (n & (64 - 1))) - 1;
|
||||
matches &= mask;
|
||||
for (; matches > 0; matches &= (matches - 1)) {
|
||||
const size_t rb_index =
|
||||
(head + (size_t)BROTLI_TZCNT64(matches)) & self->block_mask_;
|
||||
size_t prev_ix = bucket[rb_index];
|
||||
const size_t backward = cur_ix - prev_ix;
|
||||
if (BROTLI_PREDICT_FALSE(backward > max_backward)) {
|
||||
break;
|
||||
}
|
||||
prev_ix &= ring_buffer_mask;
|
||||
if (cur_ix_masked + best_len > ring_buffer_mask) {
|
||||
break;
|
||||
}
|
||||
if (prev_ix + best_len > ring_buffer_mask ||
|
||||
/* compare 4 bytes ending at best_len + 1 */
|
||||
BrotliUnalignedRead32(&data[cur_ix_masked + best_len - 3]) !=
|
||||
BrotliUnalignedRead32(&data[prev_ix + best_len - 3])) {
|
||||
continue;
|
||||
}
|
||||
{
|
||||
const size_t len = FindMatchLengthWithLimit(&data[prev_ix],
|
||||
&data[cur_ix_masked],
|
||||
max_length);
|
||||
if (len >= 4) {
|
||||
/* Comparing for >= 3 does not change the semantics, but just saves
|
||||
for a few unnecessary binary logarithms in backward reference
|
||||
score, since we are not interested in such short matches. */
|
||||
score_t score = BackwardReferenceScore(len, backward);
|
||||
if (best_score < score) {
|
||||
best_score = score;
|
||||
best_len = len;
|
||||
out->len = best_len;
|
||||
out->distance = backward;
|
||||
out->score = best_score;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
bucket[num[key] & self->block_mask_] = (uint32_t)cur_ix;
|
||||
tag_bucket[num[key] & self->block_mask_] = tag;
|
||||
--num[key];
|
||||
}
|
||||
if (min_score == out->score) {
|
||||
SearchInStaticDictionary(dictionary,
|
||||
self->common_, &data[cur_ix_masked], max_length, dictionary_distance,
|
||||
max_distance, out, BROTLI_FALSE);
|
||||
}
|
||||
}
|
||||
#undef HashLongestMatch
|
||||
57
c/enc/hash_rolling_inc.h
Executable file → Normal file
57
c/enc/hash_rolling_inc.h
Executable file → Normal file
@@ -51,13 +51,9 @@ typedef struct HashRolling {
|
||||
uint32_t factor_remove;
|
||||
} HashRolling;
|
||||
|
||||
static BROTLI_INLINE HashRolling* FN(Self)(HasherHandle handle) {
|
||||
return (HashRolling*)&(GetHasherCommon(handle)[1]);
|
||||
}
|
||||
|
||||
static void FN(Initialize)(
|
||||
HasherHandle handle, const BrotliEncoderParams* params) {
|
||||
HashRolling* self = FN(Self)(handle);
|
||||
HasherCommon* common, HashRolling* BROTLI_RESTRICT self,
|
||||
const BrotliEncoderParams* params) {
|
||||
size_t i;
|
||||
self->state = 0;
|
||||
self->next_ix = 0;
|
||||
@@ -71,7 +67,7 @@ static void FN(Initialize)(
|
||||
self->factor_remove *= self->factor;
|
||||
}
|
||||
|
||||
self->table = (uint32_t*)((HasherHandle)self + sizeof(HashRolling));
|
||||
self->table = (uint32_t*)common->extra[0];
|
||||
for (i = 0; i < NUMBUCKETS; i++) {
|
||||
self->table[i] = FN(kInvalidPos);
|
||||
}
|
||||
@@ -79,9 +75,8 @@ static void FN(Initialize)(
|
||||
BROTLI_UNUSED(params);
|
||||
}
|
||||
|
||||
static void FN(Prepare)(HasherHandle handle, BROTLI_BOOL one_shot,
|
||||
size_t input_size, const uint8_t* data) {
|
||||
HashRolling* self = FN(Self)(handle);
|
||||
static void FN(Prepare)(HashRolling* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
|
||||
size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
|
||||
size_t i;
|
||||
/* Too small size, cannot use this hasher. */
|
||||
if (input_size < CHUNKLEN) return;
|
||||
@@ -93,39 +88,39 @@ static void FN(Prepare)(HasherHandle handle, BROTLI_BOOL one_shot,
|
||||
BROTLI_UNUSED(one_shot);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
|
||||
static BROTLI_INLINE void FN(HashMemAllocInBytes)(
|
||||
const BrotliEncoderParams* params, BROTLI_BOOL one_shot,
|
||||
size_t input_size) {
|
||||
return sizeof(HashRolling) + NUMBUCKETS * sizeof(uint32_t);
|
||||
size_t input_size, size_t* alloc_size) {
|
||||
BROTLI_UNUSED(params);
|
||||
BROTLI_UNUSED(one_shot);
|
||||
BROTLI_UNUSED(input_size);
|
||||
alloc_size[0] = NUMBUCKETS * sizeof(uint32_t);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(Store)(HasherHandle BROTLI_RESTRICT handle,
|
||||
static BROTLI_INLINE void FN(Store)(HashRolling* BROTLI_RESTRICT self,
|
||||
const uint8_t* BROTLI_RESTRICT data, const size_t mask, const size_t ix) {
|
||||
BROTLI_UNUSED(handle);
|
||||
BROTLI_UNUSED(self);
|
||||
BROTLI_UNUSED(data);
|
||||
BROTLI_UNUSED(mask);
|
||||
BROTLI_UNUSED(ix);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(StoreRange)(HasherHandle handle,
|
||||
const uint8_t* data, const size_t mask, const size_t ix_start,
|
||||
const size_t ix_end) {
|
||||
BROTLI_UNUSED(handle);
|
||||
static BROTLI_INLINE void FN(StoreRange)(HashRolling* BROTLI_RESTRICT self,
|
||||
const uint8_t* BROTLI_RESTRICT data, const size_t mask,
|
||||
const size_t ix_start, const size_t ix_end) {
|
||||
BROTLI_UNUSED(self);
|
||||
BROTLI_UNUSED(data);
|
||||
BROTLI_UNUSED(mask);
|
||||
BROTLI_UNUSED(ix_start);
|
||||
BROTLI_UNUSED(ix_end);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(StitchToPreviousBlock)(HasherHandle handle,
|
||||
static BROTLI_INLINE void FN(StitchToPreviousBlock)(
|
||||
HashRolling* BROTLI_RESTRICT self,
|
||||
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
|
||||
size_t ring_buffer_mask) {
|
||||
/* In this case we must re-initialize the hasher from scratch from the
|
||||
current position. */
|
||||
HashRolling* self = FN(Self)(handle);
|
||||
size_t position_masked;
|
||||
size_t available = num_bytes;
|
||||
if ((position & (JUMP - 1)) != 0) {
|
||||
@@ -139,27 +134,29 @@ static BROTLI_INLINE void FN(StitchToPreviousBlock)(HasherHandle handle,
|
||||
available = ring_buffer_mask - position_masked;
|
||||
}
|
||||
|
||||
FN(Prepare)(handle, BROTLI_FALSE, available,
|
||||
FN(Prepare)(self, BROTLI_FALSE, available,
|
||||
ringbuffer + (position & ring_buffer_mask));
|
||||
self->next_ix = position;
|
||||
BROTLI_UNUSED(num_bytes);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(PrepareDistanceCache)(
|
||||
HasherHandle handle, int* BROTLI_RESTRICT distance_cache) {
|
||||
BROTLI_UNUSED(handle);
|
||||
HashRolling* BROTLI_RESTRICT self,
|
||||
int* BROTLI_RESTRICT distance_cache) {
|
||||
BROTLI_UNUSED(self);
|
||||
BROTLI_UNUSED(distance_cache);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
||||
static BROTLI_INLINE void FN(FindLongestMatch)(
|
||||
HashRolling* BROTLI_RESTRICT self,
|
||||
const BrotliEncoderDictionary* dictionary,
|
||||
const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask,
|
||||
const int* BROTLI_RESTRICT distance_cache, const size_t cur_ix,
|
||||
const size_t max_length, const size_t max_backward, const size_t gap,
|
||||
const size_t max_distance, HasherSearchResult* BROTLI_RESTRICT out) {
|
||||
HashRolling* self = FN(Self)(handle);
|
||||
const size_t max_length, const size_t max_backward,
|
||||
const size_t dictionary_distance, const size_t max_distance,
|
||||
HasherSearchResult* BROTLI_RESTRICT out) {
|
||||
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
|
||||
size_t pos = self->next_ix;
|
||||
size_t pos;
|
||||
|
||||
if ((cur_ix & (JUMP - 1)) != 0) return;
|
||||
|
||||
@@ -208,7 +205,7 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
||||
backup-hasher, the main hasher already searches in it. */
|
||||
BROTLI_UNUSED(dictionary);
|
||||
BROTLI_UNUSED(distance_cache);
|
||||
BROTLI_UNUSED(gap);
|
||||
BROTLI_UNUSED(dictionary_distance);
|
||||
BROTLI_UNUSED(max_distance);
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user