mirror of
https://github.com/google/brotli.git
synced 2026-02-06 13:44:45 +00:00
Compare commits
539 Commits
custom-dic
...
dependabot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1de7df3db1 | ||
|
|
5fa73e23be | ||
|
|
5db7aca571 | ||
|
|
486ed5bc56 | ||
|
|
688d661f40 | ||
|
|
5151a220d5 | ||
|
|
e1979c07fe | ||
|
|
7ff6d1d286 | ||
|
|
61af0e5b94 | ||
|
|
a0d2679607 | ||
|
|
52ad34cea4 | ||
|
|
7c77ca0b18 | ||
|
|
f81d6bc7f0 | ||
|
|
fa925d0c15 | ||
|
|
8e4d912826 | ||
|
|
2138ac6153 | ||
|
|
ea5b5c10dd | ||
|
|
8a9ab54e2e | ||
|
|
c83197f8eb | ||
|
|
48152367b3 | ||
|
|
fa141a189a | ||
|
|
464fe15603 | ||
|
|
e4bc10a000 | ||
|
|
cedd986cf2 | ||
|
|
7f0d259e54 | ||
|
|
0e8a06c0bd | ||
|
|
595a634fd7 | ||
|
|
808e2b99e6 | ||
|
|
b54d27c0f1 | ||
|
|
d00c29a783 | ||
|
|
781c2698ba | ||
|
|
1ed8c49aca | ||
|
|
e230f474b8 | ||
|
|
028fb5a236 | ||
|
|
390de5b472 | ||
|
|
3499acbb7a | ||
|
|
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 | ||
|
|
6eba239a5b | ||
|
|
2216a0dd63 | ||
|
|
d4cd6cdf1c | ||
|
|
8a073bd9e2 | ||
|
|
6d027d1648 | ||
|
|
fc4d345968 | ||
|
|
b601fe817b | ||
|
|
ee2a5e1540 | ||
|
|
eb12ec04eb | ||
|
|
7505290ef9 | ||
|
|
ff05c35166 | ||
|
|
09cd3e877f | ||
|
|
8544ae858d | ||
|
|
1e7ea1d8e6 | ||
|
|
29dc2cce90 | ||
|
|
f9b8c02673 | ||
|
|
48a25b3fa4 | ||
|
|
a4581c158e | ||
|
|
f5ed35d065 | ||
|
|
f94cd51b5c | ||
|
|
6000396155 | ||
|
|
68db5c0272 | ||
|
|
c6333e1e79 | ||
|
|
0f3c84e745 | ||
|
|
515fc62313 | ||
|
|
2c03482569 | ||
|
|
a238f5bac9 | ||
|
|
631fe194a1 | ||
|
|
533843e354 | ||
|
|
35e69fc7cf | ||
|
|
3af18990f5 | ||
|
|
b5033d0e1e | ||
|
|
da254cffdb | ||
|
|
63e15bb3a6 | ||
|
|
62194f204d | ||
|
|
2d6b298e11 | ||
|
|
c8c8389ed3 | ||
|
|
1ca15159d6 | ||
|
|
0ad94eed00 | ||
|
|
273de5a22f | ||
|
|
a755ba3bd0 | ||
|
|
bdda95ee55 | ||
|
|
3e58ea5f90 | ||
|
|
39ef4bbdcf | ||
|
|
9c75a2a26a | ||
|
|
a0c7dafe28 | ||
|
|
42d78807bb | ||
|
|
4f8cd4c0f4 | ||
|
|
5b4769990d | ||
|
|
bf6a6cda56 | ||
|
|
7748a1dc69 | ||
|
|
c60563591a | ||
|
|
b6a017492e | ||
|
|
37fb83ec0d | ||
|
|
61a5015938 | ||
|
|
4760f7db47 | ||
|
|
248bddd0d7 | ||
|
|
52f0483332 | ||
|
|
87b43eb61b | ||
|
|
6b1d0ab53d | ||
|
|
26a34a435c | ||
|
|
d7bce1e092 | ||
|
|
fe09a5030c | ||
|
|
a629289e32 | ||
|
|
6535435413 | ||
|
|
4f455cac32 | ||
|
|
019091f994 | ||
|
|
3917011ddb | ||
|
|
d63e8f75f5 | ||
|
|
0608253110 | ||
|
|
bc541f74e1 |
6
.bazelignore
Normal file
6
.bazelignore
Normal file
@@ -0,0 +1,6 @@
|
||||
# Exclude Bazel roots (workspaces)
|
||||
c/fuzz
|
||||
go
|
||||
java
|
||||
js
|
||||
research
|
||||
40
.editorconfig
Normal file
40
.editorconfig
Normal file
@@ -0,0 +1,40 @@
|
||||
# http://editorconfig.org
|
||||
# Consistent coding style across different editors.
|
||||
|
||||
# Top-most file
|
||||
root = true
|
||||
|
||||
# Global styles:
|
||||
# - indent 2 spaces
|
||||
# - add final new line
|
||||
# - trim trailing whitespace
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
# BUILD:
|
||||
# - indent 4 spaces
|
||||
[BUILD]
|
||||
indent_size = 4
|
||||
|
||||
# Makefile:
|
||||
# - indent 1 tab
|
||||
[Makefile]
|
||||
indent_size = tab
|
||||
indent_style = tab
|
||||
|
||||
# Markdown:
|
||||
# - indent 4 spaces
|
||||
# - trailing whitespace is significant
|
||||
[*.md]
|
||||
indent_size = 4
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
# Python
|
||||
# - indent 4 spaces
|
||||
[*.py]
|
||||
indent_size = 4
|
||||
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"
|
||||
355
.github/workflows/build_test.yml
vendored
Normal file
355
.github/workflows/build_test.yml
vendored
Normal file
@@ -0,0 +1,355 @@
|
||||
# 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-ios:clang
|
||||
build_system: cmake
|
||||
c_compiler: clang
|
||||
cxx_compiler: clang++
|
||||
os: macos-latest
|
||||
skip_tests: true # TODO(eustas): run tests in a simulator
|
||||
cmake_args: >-
|
||||
-DCMAKE_SYSTEM_NAME=iOS
|
||||
-DCMAKE_OSX_ARCHITECTURES=arm64
|
||||
|
||||
- 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
|
||||
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@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2
|
||||
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@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.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
|
||||
[ ! -z '${{ matrix.skip_tests || '' }}' ] || 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@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.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 pytest
|
||||
python setup.py build_ext --inplace
|
||||
pytest ./python/tests
|
||||
|
||||
build_test_dotnet:
|
||||
name: Build and test with .NET
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
- name: Checkout the source
|
||||
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||
with:
|
||||
submodules: false
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Build / Test
|
||||
run: |
|
||||
cd csharp
|
||||
dotnet build brotlidec.csproj --configuration Release
|
||||
dotnet test brotlidec.Tests.csproj
|
||||
|
||||
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@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||
with:
|
||||
submodules: true
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Install node
|
||||
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.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@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@e12f0178983d466f2f6028f5cc7a6d786fd97f4b # 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@e12f0178983d466f2f6028f5cc7a6d786fd97f4b # 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@e12f0178983d466f2f6028f5cc7a6d786fd97f4b # 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@e12f0178983d466f2f6028f5cc7a6d786fd97f4b # 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@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2
|
||||
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
|
||||
55
.github/workflows/lint.yml
vendored
Normal file
55
.github/workflows/lint.yml
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
# 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@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||
|
||||
- name: Install tools
|
||||
run: |
|
||||
eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
|
||||
brew install buildifier ruff typos-cli
|
||||
|
||||
- name: Check typos
|
||||
run: |
|
||||
eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
|
||||
./scripts/check_typos.sh
|
||||
|
||||
- name: Lint Python code
|
||||
run: |
|
||||
eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
|
||||
ruff check --extend-select=C4,C90,PERF,RET,SIM,W
|
||||
|
||||
# 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@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout the source
|
||||
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.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@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout the source
|
||||
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.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@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||
with:
|
||||
submodules: false
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Download all artifacts
|
||||
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.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@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout the source
|
||||
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.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@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: "Checkout code"
|
||||
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.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@e12f0178983d466f2f6028f5cc7a6d786fd97f4b # v2.23.3
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,9 +1,12 @@
|
||||
# C
|
||||
*.d
|
||||
*.o
|
||||
*.obj
|
||||
bin/
|
||||
buildfiles/
|
||||
**/obj/
|
||||
dist/
|
||||
**/bazel-*
|
||||
|
||||
# Python
|
||||
__pycache__/
|
||||
|
||||
6
.gitmodules
vendored
6
.gitmodules
vendored
@@ -1,6 +0,0 @@
|
||||
[submodule "terryfy"]
|
||||
path = scripts/terryfy
|
||||
url = https://github.com/MacPython/terryfy.git
|
||||
[submodule "research/esaxx"]
|
||||
path = research/esaxx
|
||||
url = https://github.com/hillbig/esaxx
|
||||
285
.travis.yml
285
.travis.yml
@@ -1,285 +0,0 @@
|
||||
language: c
|
||||
sudo: false
|
||||
matrix:
|
||||
include:
|
||||
###
|
||||
## Linux builds using various versions of GCC.
|
||||
###
|
||||
- os: linux
|
||||
env: BUILD_SYSTEM=cmake C_COMPILER=gcc-6 CXX_COMPILER=g++-6
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- gcc-6
|
||||
- g++-6
|
||||
- os: linux
|
||||
env: BUILD_SYSTEM=cmake C_COMPILER=gcc-5 CXX_COMPILER=g++-5
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- gcc-5
|
||||
- g++-5
|
||||
- os: linux
|
||||
env: BUILD_SYSTEM=cmake C_COMPILER=gcc-4.9 CXX_COMPILER=g++-4.9
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- gcc-4.9
|
||||
- g++-4.9
|
||||
- os: linux
|
||||
env: BUILD_SYSTEM=cmake C_COMPILER=gcc-4.8 CXX_COMPILER=g++-4.8
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- gcc-4.8
|
||||
- g++-4.8
|
||||
- os: linux
|
||||
env: BUILD_SYSTEM=cmake C_COMPILER=gcc-4.7 CXX_COMPILER=g++-4.7
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- gcc-4.7
|
||||
- g++-4.7
|
||||
- os: linux
|
||||
env: BUILD_SYSTEM=cmake C_COMPILER=gcc-4.6 CXX_COMPILER=g++-4.6
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- gcc-4.6
|
||||
- g++-4.6
|
||||
# - os: linux
|
||||
# env: BUILD_SYSTEM=cmake C_COMPILER=gcc-4.5 CXX_COMPILER=g++-4.5
|
||||
# addons:
|
||||
# apt:
|
||||
# sources:
|
||||
# - ubuntu-toolchain-r-test
|
||||
# packages:
|
||||
# - gcc-4.5
|
||||
# - g++-4.5
|
||||
- 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
|
||||
|
||||
###
|
||||
## clang on Linux
|
||||
###
|
||||
- os: linux
|
||||
env: BUILD_SYSTEM=cmake C_COMPILER=clang-3.8 CXX_COMPILER=clang++-3.8
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- llvm-toolchain-precise-3.8
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- clang-3.8
|
||||
- os: linux
|
||||
env: BUILD_SYSTEM=cmake C_COMPILER=clang-3.7 CXX_COMPILER=clang++-3.7
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- llvm-toolchain-precise-3.7
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- clang-3.7
|
||||
- os: linux
|
||||
env: BUILD_SYSTEM=cmake C_COMPILER=clang-3.6 CXX_COMPILER=clang++-3.6
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- llvm-toolchain-precise-3.6
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- clang-3.6
|
||||
- os: linux
|
||||
env: BUILD_SYSTEM=cmake C_COMPILER=clang-3.5 CXX_COMPILER=clang++-3.5
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- llvm-toolchain-precise-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 build on Linux
|
||||
###
|
||||
- os: linux
|
||||
env: BUILD_SYSTEM=python C_COMPILER=gcc-6 CXX_COMPILER=g++-6
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- gcc-6
|
||||
- g++-6
|
||||
|
||||
###
|
||||
## 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-6 CXX_COMPILER=g++-6
|
||||
- os: osx
|
||||
env: BUILD_SYSTEM=cmake C_COMPILER=gcc-5 CXX_COMPILER=g++-5
|
||||
# - os: osx
|
||||
# env: BUILD_SYSTEM=cmake C_COMPILER=gcc-4.9 CXX_COMPILER=g++-4.9
|
||||
# - os: osx
|
||||
# env: BUILD_SYSTEM=cmake C_COMPILER=gcc-4.8 CXX_COMPILER=g++-4.8
|
||||
# - os: osx
|
||||
# env: BUILD_SYSTEM=cmake C_COMPILER=gcc-4.7 CXX_COMPILER=g++-4.7
|
||||
# - os: osx
|
||||
# env: BUILD_SYSTEM=cmake C_COMPILER=gcc-4.6 CXX_COMPILER=g++-4.6
|
||||
# - os: osx
|
||||
# env: BUILD_SYSTEM=cmake C_COMPILER=gcc-4.5 CXX_COMPILER=g++-4.5
|
||||
- os: osx
|
||||
osx_image: beta-xcode6.2
|
||||
env: BUILD_SYSTEM=cmake C_COMPILER=gcc-4.4 CXX_COMPILER=g++-4.4
|
||||
|
||||
###
|
||||
## Python OS X builds
|
||||
###
|
||||
- os: osx
|
||||
env: BUILD_SYSTEM=python INSTALL_TYPE=macpython PYTHON_VERSION=2.7.12 C_COMPILER=gcc CXX_COMPILER=g++
|
||||
- os: osx
|
||||
env: BUILD_SYSTEM=python INSTALL_TYPE=macpython PYTHON_VERSION=3.4.4 C_COMPILER=gcc CXX_COMPILER=g++
|
||||
- os: osx
|
||||
env: BUILD_SYSTEM=python INSTALL_TYPE=macpython PYTHON_VERSION=3.5.2 C_COMPILER=gcc CXX_COMPILER=g++
|
||||
|
||||
###
|
||||
## Sanitizers
|
||||
###
|
||||
- os: linux
|
||||
env: BUILD_SYSTEM=cmake C_COMPILER=clang-3.8 CXX_COMPILER=clang++-3.8 SANITIZER=address
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-precise-3.8
|
||||
packages:
|
||||
- clang-3.8
|
||||
- os: linux
|
||||
env: BUILD_SYSTEM=cmake C_COMPILER=clang-3.8 CXX_COMPILER=clang++-3.8 SANITIZER=thread
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-precise-3.8
|
||||
packages:
|
||||
- clang-3.8
|
||||
- os: linux
|
||||
env: BUILD_SYSTEM=cmake C_COMPILER=clang-3.8 CXX_COMPILER=clang++-3.8 SANITIZER=undefined CFLAGS="-fno-sanitize-recover=undefined,integer"
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-precise-3.8
|
||||
packages:
|
||||
- clang-3.8
|
||||
|
||||
###
|
||||
## mingw
|
||||
###
|
||||
- os: linux
|
||||
env: BUILD_SYSTEM=cmake C_COMPILER=x86_64-w64-mingw32-gcc CXX_COMPILER=x86_64-w64-mingw32-g++ RC_COMPILER=x86_64-w64-mingw32-windres CROSS_COMPILE=yes
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- george-edison55-precise-backports
|
||||
packages:
|
||||
- binutils-mingw-w64-x86-64
|
||||
- g++-mingw-w64-x86-64
|
||||
- gcc-mingw-w64-x86-64
|
||||
- binutils-mingw-w64-x86-64
|
||||
- wine
|
||||
# Because 2.8.6 passes -rdynamic to the linker, which breaks the build.
|
||||
- cmake
|
||||
- cmake-data
|
||||
|
||||
- os: linux
|
||||
env: BUILD_SYSTEM=maven
|
||||
language: java
|
||||
|
||||
- os: linux
|
||||
dist: trusty
|
||||
sudo: required
|
||||
language: java
|
||||
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:
|
||||
- oracle-java8-installer
|
||||
- bazel
|
||||
|
||||
- os: osx
|
||||
env: BUILD_SYSTEM=bazel
|
||||
|
||||
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:
|
||||
- if [ "${BUILD_SYSTEM}" = "python" ] && [ "${TRAVIS_OS_NAME}" = "osx" ]; then export WHEELS=$(ls ./dist/*.whl); fi
|
||||
- scripts/.travis.sh before_deploy
|
||||
|
||||
deploy:
|
||||
- provider: releases
|
||||
api_key:
|
||||
secure: YcCBi6W/w4dtKCa59Wfm8L5lGWvK7KxaFNDr3yh1Hz5aStXXf758pEMHGewnlbfbwuj5a3SjBb1nLp1M69OQJfxm442uXBaBKo52PM9PPbD7NjvbNIso73pqcSODXQXKuZxDFpEhfuDTVq3hUkUqiwhChWhrFucJsSL51i7qSss=
|
||||
file: "${WHEELS}"
|
||||
skip_cleanup: true
|
||||
on:
|
||||
repo: "google/brotli"
|
||||
tags: true
|
||||
condition: "${BUILD_SYSTEM} = python && ${TRAVIS_OS_NAME} = osx"
|
||||
- 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
|
||||
207
BUILD
207
BUILD
@@ -1,207 +0,0 @@
|
||||
# Description:
|
||||
# Brotli is a generic-purpose lossless compression algorithm.
|
||||
|
||||
package(
|
||||
default_visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
licenses(["notice"]) # MIT
|
||||
|
||||
exports_files(["LICENSE"])
|
||||
|
||||
# >>> JNI headers
|
||||
|
||||
config_setting(
|
||||
name = "darwin",
|
||||
values = {"cpu": "darwin"},
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "darwin_x86_64",
|
||||
values = {"cpu": "darwin_x86_64"},
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
genrule(
|
||||
name = "copy_link_jni_header",
|
||||
srcs = ["@openjdk_linux//:jni_h"],
|
||||
outs = ["jni/jni.h"],
|
||||
cmd = "cp -f $< $@",
|
||||
)
|
||||
|
||||
genrule(
|
||||
name = "copy_link_jni_md_header",
|
||||
srcs = select({
|
||||
":darwin": ["@openjdk_macos//:jni_md_h"],
|
||||
":darwin_x86_64": ["@openjdk_macos//:jni_md_h"],
|
||||
"//conditions:default": ["@openjdk_linux//:jni_md_h"],
|
||||
}),
|
||||
outs = ["jni/jni_md.h"],
|
||||
cmd = "cp -f $< $@",
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "jni_inc",
|
||||
hdrs = [
|
||||
":jni/jni.h",
|
||||
":jni/jni_md.h",
|
||||
],
|
||||
includes = ["jni"],
|
||||
)
|
||||
|
||||
# <<< JNI headers
|
||||
|
||||
STRICT_C_OPTIONS = [
|
||||
"--pedantic-errors",
|
||||
"-Wall",
|
||||
"-Wconversion",
|
||||
"-Werror",
|
||||
"-Wextra",
|
||||
"-Wlong-long",
|
||||
"-Wmissing-declarations",
|
||||
"-Wmissing-prototypes",
|
||||
"-Wno-strict-aliasing",
|
||||
"-Wshadow",
|
||||
"-Wsign-compare",
|
||||
]
|
||||
|
||||
filegroup(
|
||||
name = "public_headers",
|
||||
srcs = glob(["c/include/brotli/*.h"]),
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "common_headers",
|
||||
srcs = glob(["c/common/*.h"]),
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "common_sources",
|
||||
srcs = glob(["c/common/*.c"]),
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "dec_headers",
|
||||
srcs = glob(["c/dec/*.h"]),
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "dec_sources",
|
||||
srcs = glob(["c/dec/*.c"]),
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "enc_headers",
|
||||
srcs = glob(["c/enc/*.h"]),
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "enc_sources",
|
||||
srcs = glob(["c/enc/*.c"]),
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "brotli_inc",
|
||||
hdrs = [":public_headers"],
|
||||
copts = STRICT_C_OPTIONS,
|
||||
includes = ["c/include"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "brotlicommon",
|
||||
srcs = [":common_sources"],
|
||||
hdrs = [":common_headers"],
|
||||
copts = STRICT_C_OPTIONS,
|
||||
deps = [":brotli_inc"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "brotlidec",
|
||||
srcs = [":dec_sources"],
|
||||
hdrs = [":dec_headers"],
|
||||
copts = STRICT_C_OPTIONS,
|
||||
deps = [":brotlicommon"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "brotlienc",
|
||||
srcs = [":enc_sources"],
|
||||
hdrs = [":enc_headers"],
|
||||
copts = STRICT_C_OPTIONS,
|
||||
linkopts = ["-lm"],
|
||||
deps = [":brotlicommon"],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "brotli",
|
||||
srcs = ["c/tools/brotli.c"],
|
||||
copts = STRICT_C_OPTIONS,
|
||||
linkstatic = 1,
|
||||
deps = [
|
||||
":brotlidec",
|
||||
":brotlienc",
|
||||
],
|
||||
)
|
||||
|
||||
########################################################
|
||||
# WARNING: do not (transitively) depend on this target!
|
||||
########################################################
|
||||
cc_library(
|
||||
name = "jni",
|
||||
srcs = [
|
||||
":common_sources",
|
||||
":dec_sources",
|
||||
":enc_sources",
|
||||
"//java/org/brotli/wrapper/common:jni_src",
|
||||
"//java/org/brotli/wrapper/dec:jni_src",
|
||||
"//java/org/brotli/wrapper/enc:jni_src",
|
||||
],
|
||||
hdrs = [
|
||||
":common_headers",
|
||||
":dec_headers",
|
||||
":enc_headers",
|
||||
],
|
||||
deps = [
|
||||
":brotli_inc",
|
||||
":jni_inc",
|
||||
],
|
||||
alwayslink = 1,
|
||||
)
|
||||
|
||||
########################################################
|
||||
# WARNING: do not (transitively) depend on this target!
|
||||
########################################################
|
||||
cc_library(
|
||||
name = "jni_no_dictionary_data",
|
||||
srcs = [
|
||||
":common_sources",
|
||||
":dec_sources",
|
||||
":enc_sources",
|
||||
"//java/org/brotli/wrapper/common:jni_src",
|
||||
"//java/org/brotli/wrapper/dec:jni_src",
|
||||
"//java/org/brotli/wrapper/enc:jni_src",
|
||||
],
|
||||
hdrs = [
|
||||
":common_headers",
|
||||
":dec_headers",
|
||||
":enc_headers",
|
||||
],
|
||||
defines = [
|
||||
"BROTLI_EXTERNAL_DICTIONARY_DATA=",
|
||||
],
|
||||
deps = [
|
||||
":brotli_inc",
|
||||
":jni_inc",
|
||||
],
|
||||
alwayslink = 1,
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "dictionary",
|
||||
srcs = ["c/common/dictionary.bin"],
|
||||
)
|
||||
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_prefix")
|
||||
|
||||
go_prefix("github.com/google/brotli")
|
||||
141
BUILD.bazel
Normal file
141
BUILD.bazel
Normal file
@@ -0,0 +1,141 @@
|
||||
# Description:
|
||||
# Brotli is a generic-purpose lossless compression algorithm.
|
||||
|
||||
package(
|
||||
default_visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
licenses(["notice"]) # MIT
|
||||
|
||||
exports_files(["LICENSE"])
|
||||
|
||||
config_setting(
|
||||
name = "clang-cl",
|
||||
flag_values = {
|
||||
"@bazel_tools//tools/cpp:compiler": "clang-cl",
|
||||
},
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "msvc",
|
||||
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",
|
||||
"-Wconversion",
|
||||
"-Werror",
|
||||
"-Wextra",
|
||||
"-Wlong-long",
|
||||
"-Wmissing-declarations",
|
||||
"-Wmissing-prototypes",
|
||||
"-Wno-strict-aliasing",
|
||||
"-Wshadow",
|
||||
"-Wsign-compare",
|
||||
],
|
||||
})
|
||||
|
||||
filegroup(
|
||||
name = "public_headers",
|
||||
srcs = glob(["c/include/brotli/*.h"]),
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "common_headers",
|
||||
srcs = glob(["c/common/*.h"]),
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "common_sources",
|
||||
srcs = glob(["c/common/*.c"]),
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "dec_headers",
|
||||
srcs = glob(["c/dec/*.h"]),
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "dec_sources",
|
||||
srcs = glob(["c/dec/*.c"]),
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "enc_headers",
|
||||
srcs = glob(["c/enc/*.h"]),
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "enc_sources",
|
||||
srcs = glob(["c/enc/*.c"]),
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "brotli_inc",
|
||||
hdrs = [":public_headers"],
|
||||
copts = STRICT_C_OPTIONS,
|
||||
strip_include_prefix = "c/include",
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "brotlicommon",
|
||||
srcs = [":common_sources"],
|
||||
hdrs = [":common_headers"],
|
||||
copts = STRICT_C_OPTIONS,
|
||||
deps = [":brotli_inc"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "brotlidec",
|
||||
srcs = [":dec_sources"],
|
||||
hdrs = [":dec_headers"],
|
||||
copts = STRICT_C_OPTIONS,
|
||||
deps = [":brotlicommon"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "brotlienc",
|
||||
srcs = [":enc_sources"],
|
||||
hdrs = [":enc_headers"],
|
||||
copts = STRICT_C_OPTIONS,
|
||||
linkopts = select({
|
||||
":clang-cl": [],
|
||||
":msvc": [],
|
||||
"//conditions:default": ["-lm"],
|
||||
}),
|
||||
deps = [":brotlicommon"],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "brotli",
|
||||
srcs = ["c/tools/brotli.c"],
|
||||
copts = STRICT_C_OPTIONS,
|
||||
linkstatic = 1,
|
||||
deps = [
|
||||
":brotlidec",
|
||||
":brotlienc",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "dictionary",
|
||||
srcs = ["c/common/dictionary.bin"],
|
||||
)
|
||||
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-27
|
||||
|
||||
### 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.
|
||||
500
CMakeLists.txt
500
CMakeLists.txt
@@ -1,171 +1,166 @@
|
||||
# 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)
|
||||
|
||||
project(brotli)
|
||||
# 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(BROTLI_BUNDLED_MODE STREQUAL "")
|
||||
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)
|
||||
set(BROTLI_BUNDLED_MODE OFF)
|
||||
else()
|
||||
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(CMakeDependentOption)
|
||||
CMAKE_DEPENDENT_OPTION(BUILD_SHARED_LIBS "Build shared libraries" ON "NOT BROTLI_BUNDLED_MODE" OFF)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
# When building shared libraries it is important to set the correct rpath.
|
||||
# See https://cmake.org/Wiki/CMake_RPATH_handling#Always_full_RPATH
|
||||
if (BUILD_SHARED_LIBS)
|
||||
add_definitions(-DBROTLI_SHARED_COMPILATION)
|
||||
set(CMAKE_SKIP_BUILD_RPATH FALSE)
|
||||
set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
|
||||
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
|
||||
list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_LIBDIR}" isSystemDir)
|
||||
if ("${isSystemDir}" STREQUAL "-1")
|
||||
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_LIBDIR}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# 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_REVISION "${_brotli_version} & 4095")
|
||||
mark_as_advanced(BROTLI_VERSION_MAJOR BROTLI_VERSION_MINOR BROTLI_VERSION_REVISION)
|
||||
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
|
||||
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)
|
||||
|
||||
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")
|
||||
set(BROTLI_LIBRARIES_CORE brotlienc brotlidec brotlicommon)
|
||||
set(BROTLI_LIBRARIES ${BROTLI_LIBRARIES_CORE} ${LIBM_LIBRARY})
|
||||
mark_as_advanced(BROTLI_INCLUDE_DIRS BROTLI_LIBRARIES)
|
||||
mark_as_advanced(BROTLI_INCLUDE_DIRS)
|
||||
|
||||
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)
|
||||
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)
|
||||
|
||||
if (MSVC)
|
||||
message(STATUS "Defining _CRT_SECURE_NO_WARNINGS to avoid warnings about security")
|
||||
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
endif()
|
||||
|
||||
add_library(brotlicommon
|
||||
c/common/dictionary.c)
|
||||
add_library(brotlidec
|
||||
c/dec/bit_reader.c
|
||||
c/dec/decode.c
|
||||
c/dec/huffman.c
|
||||
c/dec/state.c)
|
||||
add_library(brotlienc
|
||||
c/enc/backward_references.c
|
||||
c/enc/backward_references_hq.c
|
||||
c/enc/bit_cost.c
|
||||
c/enc/block_splitter.c
|
||||
c/enc/brotli_bit_stream.c
|
||||
c/enc/cluster.c
|
||||
c/enc/compress_fragment.c
|
||||
c/enc/compress_fragment_two_pass.c
|
||||
c/enc/dictionary_hash.c
|
||||
c/enc/encode.c
|
||||
c/enc/entropy_encode.c
|
||||
c/enc/histogram.c
|
||||
c/enc/literal_cost.c
|
||||
c/enc/memory.c
|
||||
c/enc/metablock.c
|
||||
c/enc/static_dict.c
|
||||
c/enc/utf8_util.c)
|
||||
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)
|
||||
|
||||
add_library(brotlicommon ${BROTLI_COMMON_SOURCES})
|
||||
add_library(brotlidec ${BROTLI_DEC_SOURCES})
|
||||
add_library(brotlienc ${BROTLI_ENC_SOURCES})
|
||||
|
||||
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)
|
||||
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 ${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
|
||||
SOVERSION "${BROTLI_VERSION_MAJOR}.${BROTLI_VERSION_MINOR}.${BROTLI_VERSION_REVISION}"
|
||||
VERSION "${BROTLI_VERSION_MAJOR}.${BROTLI_VERSION_MINOR}.${BROTLI_VERSION_REVISION}"
|
||||
POSITION_INDEPENDENT_CODE TRUE)
|
||||
string(TOUPPER "${lib}" LIB)
|
||||
set_target_properties (${lib} PROPERTIES DEFINE_SYMBOL "${LIB}_SHARED_COMPILATION" )
|
||||
|
||||
set_property(TARGET ${lib} APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${BROTLI_INCLUDE_DIRS}")
|
||||
endforeach()
|
||||
VERSION "${BROTLI_ABI_COMPATIBILITY}.${BROTLI_ABI_AGE}.${BROTLI_ABI_REVISION}"
|
||||
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)
|
||||
@@ -176,24 +171,30 @@ target_link_libraries(brotlienc brotlicommon)
|
||||
#
|
||||
# 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 c/tools/brotli.c)
|
||||
target_link_libraries(brotli ${BROTLI_LIBRARIES})
|
||||
if (BROTLI_BUILD_TOOLS)
|
||||
add_executable(brotli c/tools/brotli.c)
|
||||
target_link_libraries(brotli ${BROTLI_LIBRARIES})
|
||||
# brotli is a CLI tool
|
||||
set_target_properties(brotli PROPERTIES MACOSX_BUNDLE OFF)
|
||||
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}
|
||||
TARGETS ${BROTLI_SHARED_LIBRARIES} ${BROTLI_STATIC_LIBRARIES}
|
||||
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
||||
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
||||
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
|
||||
@@ -203,24 +204,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()
|
||||
|
||||
@@ -239,16 +269,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
|
||||
@@ -257,18 +292,20 @@ 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 file
|
||||
|
||||
include(CMakeParseArguments)
|
||||
# Generate a pkg-config files
|
||||
|
||||
function(generate_pkg_config_path outvar path)
|
||||
string(LENGTH "${path}" path_length)
|
||||
@@ -286,19 +323,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()
|
||||
@@ -313,113 +350,48 @@ function(generate_pkg_config_path outvar path)
|
||||
set("${outvar}" "${${outvar}}" PARENT_SCOPE)
|
||||
endfunction(generate_pkg_config_path)
|
||||
|
||||
function(generate_pkg_config output_file)
|
||||
set (options)
|
||||
set (oneValueArgs NAME DESCRIPTION URL VERSION PREFIX LIBDIR INCLUDEDIR)
|
||||
set (multiValueArgs DEPENDS_PRIVATE CFLAGS LIBRARIES)
|
||||
cmake_parse_arguments(GEN_PKG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||
unset (options)
|
||||
unset (oneValueArgs)
|
||||
unset (multiValueArgs)
|
||||
function(transform_pc_file INPUT_FILE OUTPUT_FILE VERSION)
|
||||
file(READ ${INPUT_FILE} TEXT)
|
||||
|
||||
if(NOT GEN_PKG_PREFIX)
|
||||
set(GEN_PKG_PREFIX "${CMAKE_INSTALL_PREFIX}")
|
||||
endif()
|
||||
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})
|
||||
|
||||
if(NOT GEN_PKG_LIBDIR)
|
||||
set(GEN_PKG_LIBDIR "${CMAKE_INSTALL_FULL_LIBDIR}")
|
||||
endif()
|
||||
generate_pkg_config_path(GEN_PKG_LIBDIR "${GEN_PKG_LIBDIR}"
|
||||
prefix "${GEN_PKG_PREFIX}")
|
||||
generate_pkg_config_path(LIBDIR "${CMAKE_INSTALL_FULL_LIBDIR}" prefix "${PREFIX}")
|
||||
string(REGEX REPLACE "@libdir@" "${LIBDIR}" TEXT ${TEXT})
|
||||
|
||||
if(NOT GEN_PKG_INCLUDEDIR)
|
||||
set(GEN_PKG_INCLUDEDIR "${CMAKE_INSTALL_FULL_INCLUDEDIR}")
|
||||
endif()
|
||||
generate_pkg_config_path(GEN_PKG_INCLUDEDIR "${GEN_PKG_INCLUDEDIR}"
|
||||
prefix "${GEN_PKG_PREFIX}")
|
||||
generate_pkg_config_path(INCLUDEDIR "${CMAKE_INSTALL_FULL_INCLUDEDIR}" prefix "${PREFIX}")
|
||||
string(REGEX REPLACE "@includedir@" "${INCLUDEDIR}" TEXT ${TEXT})
|
||||
|
||||
file(WRITE "${output_file}" "prefix=${GEN_PKG_PREFIX}\n")
|
||||
file(APPEND "${output_file}" "libdir=${GEN_PKG_LIBDIR}\n")
|
||||
file(APPEND "${output_file}" "includedir=${GEN_PKG_INCLUDEDIR}\n")
|
||||
file(APPEND "${output_file}" "\n")
|
||||
string(REGEX REPLACE "@PACKAGE_VERSION@" "${VERSION}" TEXT ${TEXT})
|
||||
|
||||
if(GEN_PKG_NAME)
|
||||
file(APPEND "${output_file}" "Name: ${GEN_PKG_NAME}\n")
|
||||
else()
|
||||
file(APPEND "${output_file}" "Name: ${CMAKE_PROJECT_NAME}\n")
|
||||
endif()
|
||||
file(WRITE ${OUTPUT_FILE} ${TEXT})
|
||||
endfunction()
|
||||
|
||||
if(GEN_PKG_DESCRIPTION)
|
||||
file(APPEND "${output_file}" "Description: ${GEN_PKG_DESCRIPTION}\n")
|
||||
endif()
|
||||
transform_pc_file("scripts/libbrotlicommon.pc.in" "${CMAKE_CURRENT_BINARY_DIR}/libbrotlicommon.pc" "${BROTLI_VERSION}")
|
||||
|
||||
if(GEN_PKG_URL)
|
||||
file(APPEND "${output_file}" "URL: ${GEN_PKG_URL}\n")
|
||||
endif()
|
||||
transform_pc_file("scripts/libbrotlidec.pc.in" "${CMAKE_CURRENT_BINARY_DIR}/libbrotlidec.pc" "${BROTLI_VERSION}")
|
||||
|
||||
if(GEN_PKG_VERSION)
|
||||
file(APPEND "${output_file}" "Version: ${GEN_PKG_VERSION}\n")
|
||||
endif()
|
||||
transform_pc_file("scripts/libbrotlienc.pc.in" "${CMAKE_CURRENT_BINARY_DIR}/libbrotlienc.pc" "${BROTLI_VERSION}")
|
||||
|
||||
if(GEN_PKG_DEPENDS_PRIVATE)
|
||||
file(APPEND "${output_file}" "Requires.private:")
|
||||
foreach(lib ${GEN_PKG_DEPENDS_PRIVATE})
|
||||
file(APPEND "${output_file}" " ${lib}")
|
||||
endforeach()
|
||||
file(APPEND "${output_file}" "\n")
|
||||
endif()
|
||||
|
||||
if(GEN_PKG_LIBRARIES)
|
||||
set(libs)
|
||||
|
||||
file(APPEND "${output_file}" "Libs: -L\${libdir}")
|
||||
foreach(lib ${GEN_PKG_LIBRARIES})
|
||||
file(APPEND "${output_file}" " -l${lib}")
|
||||
endforeach()
|
||||
file(APPEND "${output_file}" "\n")
|
||||
endif()
|
||||
|
||||
file(APPEND "${output_file}" "Cflags: -I\${includedir}")
|
||||
if(GEN_PKG_CFLAGS)
|
||||
foreach(cflag ${GEN_PKG_CFLAGS})
|
||||
file(APPEND "${output_file}" " ${cflag}")
|
||||
endforeach()
|
||||
endif()
|
||||
file(APPEND "${output_file}" "\n")
|
||||
endfunction(generate_pkg_config)
|
||||
|
||||
generate_pkg_config ("${CMAKE_CURRENT_BINARY_DIR}/libbrotlicommon.pc"
|
||||
NAME libbrotlicommon
|
||||
DESCRIPTION "Shared data used by libbrotlienc and libbrotlidec libraries"
|
||||
URL "https://github.com/google/brotli"
|
||||
VERSION "${BROTLI_VERSION_MAJOR}.${BROTLI_VERSION_MINOR}.${BROTLI_VERSION_REVISION}"
|
||||
LIBRARIES brotlicommon)
|
||||
|
||||
generate_pkg_config ("${CMAKE_CURRENT_BINARY_DIR}/libbrotlidec.pc"
|
||||
NAME libbrotlidec
|
||||
DESCRIPTION "Brotli decoder library"
|
||||
VERSION "${BROTLI_VERSION_MAJOR}.${BROTLI_VERSION_MINOR}.${BROTLI_VERSION_REVISION}"
|
||||
URL "https://github.com/google/brotli"
|
||||
DEPENDS_PRIVATE libbrotlicommon
|
||||
LIBRARIES brotlidec)
|
||||
|
||||
generate_pkg_config ("${CMAKE_CURRENT_BINARY_DIR}/libbrotlienc.pc"
|
||||
NAME libbrotlienc
|
||||
DESCRIPTION "Brotli encoder library"
|
||||
VERSION "${BROTLI_VERSION_MAJOR}.${BROTLI_VERSION_MINOR}.${BROTLI_VERSION_REVISION}"
|
||||
URL "https://github.com/google/brotli"
|
||||
DEPENDS_PRIVATE libbrotlicommon
|
||||
LIBRARIES brotlienc)
|
||||
|
||||
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_MANDIR}/man1")
|
||||
endif()
|
||||
|
||||
install(FILES docs/constants.h.3 docs/decode.h.3 docs/encode.h.3 docs/types.h.3
|
||||
DESTINATION "${CMAKE_INSTALL_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]
|
||||
|
||||
@@ -8,9 +8,11 @@ include c/enc/*.h
|
||||
include c/include/brotli/*.h
|
||||
include LICENSE
|
||||
include MANIFEST.in
|
||||
include python/bro.py
|
||||
include python/brotlimodule.cc
|
||||
include python/_brotli.cc
|
||||
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 $@
|
||||
15
README
Normal file
15
README
Normal file
@@ -0,0 +1,15 @@
|
||||
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
|
||||
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://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/g/brotli
|
||||
116
README.md
116
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,79 +12,103 @@ 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.
|
||||
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
|
||||
|
||||
To build static libraries use `--disable-shared-libs` argument:
|
||||
|
||||
$ mkdir out-static && cd out-static
|
||||
$ ../configure-cmake --disable-shared-libs
|
||||
$ make install
|
||||
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
|
||||
|
||||
The basic commands to build, test and install brotli are:
|
||||
The basic commands to build and install brotli are:
|
||||
|
||||
$ mkdir out && cd out
|
||||
$ cmake ..
|
||||
$ make
|
||||
$ make test
|
||||
$ make install
|
||||
$ cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=./installed ..
|
||||
$ cmake --build . --config Release --target install
|
||||
|
||||
You can use other [CMake](https://cmake.org/) configuration. For example, to
|
||||
build static libraries:
|
||||
|
||||
$ mkdir out-static && cd out-static
|
||||
$ cmake .. -DBUILD_SHARED_LIBS=OFF
|
||||
$ make
|
||||
|
||||
#### Premake5
|
||||
|
||||
See [Premake5](https://premake.github.io/)
|
||||
You can use other [CMake](https://cmake.org/) configuration.
|
||||
|
||||
#### Python
|
||||
|
||||
To install the Python module from source, run the following:
|
||||
To install the latest release of the Python module, run the following:
|
||||
|
||||
$ python setup.py install
|
||||
$ pip install brotli
|
||||
|
||||
See the [Python readme](python/README.md) for more details on testing
|
||||
and development.
|
||||
To install the tip-of-the-tree version, run:
|
||||
|
||||
$ pip install --upgrade git+https://github.com/google/brotli
|
||||
|
||||
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
|
||||
Independent [decoder](https://github.com/madler/brotli) implementation by Mark Adler, based entirely on format specification.
|
||||
> **Disclaimer:** Brotli authors take no responsibility for the third party projects mentioned in this section.
|
||||
|
||||
JavaScript port of brotli [decoder](https://github.com/devongovett/brotli.js). Could be used directly via `npm install brotli`
|
||||
Independent [decoder](https://github.com/madler/brotli) implementation
|
||||
by Mark Adler, based entirely on format specification.
|
||||
|
||||
Hand ported [decoder / encoder](https://github.com/dominikhlbg/BrotliHaxe) in haxe by Dominik Homberger. Output source code: JavaScript, PHP, Python, Java and C#
|
||||
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#
|
||||
|
||||
7Zip [plugin](https://github.com/mcmilk/7-Zip-Zstd)
|
||||
|
||||
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.
|
||||
50
WORKSPACE
50
WORKSPACE
@@ -1,50 +0,0 @@
|
||||
# Description:
|
||||
# Bazel workspace file for Brotli.
|
||||
|
||||
workspace(name = "org_brotli")
|
||||
|
||||
maven_jar(
|
||||
name = "junit_junit",
|
||||
artifact = "junit:junit:4.12",
|
||||
)
|
||||
|
||||
git_repository(
|
||||
name = "io_bazel_rules_go",
|
||||
remote = "https://github.com/bazelbuild/rules_go.git",
|
||||
tag = "0.4.4",
|
||||
)
|
||||
|
||||
new_http_archive(
|
||||
name = "openjdk_linux",
|
||||
url = "https://bazel-mirror.storage.googleapis.com/openjdk/azul-zulu-8.20.0.5-jdk8.0.121/zulu8.20.0.5-jdk8.0.121-linux_x64.tar.gz",
|
||||
sha256 = "7fdfb17d890406470b2303d749d3138e7f353749e67a0a22f542e1ab3e482745",
|
||||
build_file_content = """
|
||||
package(
|
||||
default_visibility = ["//visibility:public"],
|
||||
)
|
||||
filegroup(
|
||||
name = "jni_h",
|
||||
srcs = ["zulu8.20.0.5-jdk8.0.121-linux_x64/include/jni.h"],
|
||||
)
|
||||
filegroup(
|
||||
name = "jni_md_h",
|
||||
srcs = ["zulu8.20.0.5-jdk8.0.121-linux_x64/include/linux/jni_md.h"],
|
||||
)""",
|
||||
)
|
||||
|
||||
new_http_archive(
|
||||
name = "openjdk_macos",
|
||||
url = "https://bazel-mirror.storage.googleapis.com/openjdk/azul-zulu-8.20.0.5-jdk8.0.121/zulu8.20.0.5-jdk8.0.121-macosx_x64.zip",
|
||||
sha256 = "2a58bd1d9b0cbf0b3d8d1bcdd117c407e3d5a0ec01e2f53565c9bec5cf9ea78b",
|
||||
build_file_content = """
|
||||
package(
|
||||
default_visibility = ["//visibility:public"],
|
||||
)
|
||||
filegroup(
|
||||
name = "jni_md_h",
|
||||
srcs = ["zulu8.20.0.5-jdk8.0.121-macosx_x64/include/darwin/jni_md.h"],
|
||||
)""",
|
||||
)
|
||||
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_repositories")
|
||||
go_repositories()
|
||||
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
|
||||
|
||||
@@ -28,16 +35,57 @@
|
||||
/* "code length of 8 is repeated" */
|
||||
#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
|
||||
/* BROTLI_NUM_DISTANCE_SYMBOLS == 520 */
|
||||
#define BROTLI_NUM_DISTANCE_SYMBOLS (BROTLI_NUM_DISTANCE_SHORT_CODES + \
|
||||
BROTLI_MAX_NDIRECT + \
|
||||
(BROTLI_MAX_DISTANCE_BITS << \
|
||||
(BROTLI_MAX_NPOSTFIX + 1)))
|
||||
#define BROTLI_DISTANCE_ALPHABET_SIZE(NPOSTFIX, NDIRECT, MAXNBITS) ( \
|
||||
BROTLI_NUM_DISTANCE_SHORT_CODES + (NDIRECT) + \
|
||||
((MAXNBITS) << ((NPOSTFIX) + 1)))
|
||||
/* BROTLI_NUM_DISTANCE_SYMBOLS == 1128 */
|
||||
#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" */
|
||||
@@ -52,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_ */
|
||||
|
||||
@@ -1,115 +1,81 @@
|
||||
/* Copyright 2013 Google Inc. All Rights Reserved.
|
||||
#include "context.h"
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/* Lookup table to map the previous two bytes to a context id.
|
||||
|
||||
There are four different context modeling modes defined here:
|
||||
CONTEXT_LSB6: context id is the least significant 6 bits of the last byte,
|
||||
CONTEXT_MSB6: context id is the most significant 6 bits of the last byte,
|
||||
CONTEXT_UTF8: second-order context model tuned for UTF8-encoded text,
|
||||
CONTEXT_SIGNED: second-order context model tuned for signed integers.
|
||||
|
||||
The context id for the UTF8 context model is calculated as follows. If p1
|
||||
and p2 are the previous two bytes, we calculate the context as
|
||||
|
||||
context = kContextLookup[p1] | kContextLookup[p2 + 256].
|
||||
|
||||
If the previous two bytes are ASCII characters (i.e. < 128), this will be
|
||||
equivalent to
|
||||
|
||||
context = 4 * context1(p1) + context2(p2),
|
||||
|
||||
where context1 is based on the previous byte in the following way:
|
||||
|
||||
0 : non-ASCII control
|
||||
1 : \t, \n, \r
|
||||
2 : space
|
||||
3 : other punctuation
|
||||
4 : " '
|
||||
5 : %
|
||||
6 : ( < [ {
|
||||
7 : ) > ] }
|
||||
8 : , ; :
|
||||
9 : .
|
||||
10 : =
|
||||
11 : number
|
||||
12 : upper-case vowel
|
||||
13 : upper-case consonant
|
||||
14 : lower-case vowel
|
||||
15 : lower-case consonant
|
||||
|
||||
and context2 is based on the second last byte:
|
||||
|
||||
0 : control, space
|
||||
1 : punctuation
|
||||
2 : upper-case letter, number
|
||||
3 : lower-case letter
|
||||
|
||||
If the last byte is ASCII, and the second last byte is not (in a valid UTF8
|
||||
stream it will be a continuation byte, value between 128 and 191), the
|
||||
context is the same as if the second last byte was an ASCII control or space.
|
||||
|
||||
If the last byte is a UTF8 lead byte (value >= 192), then the next byte will
|
||||
be a continuation byte and the context id is 2 or 3 depending on the LSB of
|
||||
the last byte and to a lesser extent on the second last byte if it is ASCII.
|
||||
|
||||
If the last byte is a UTF8 continuation byte, the second last byte can be:
|
||||
- continuation byte: the next byte is probably ASCII or lead byte (assuming
|
||||
4-byte UTF8 characters are rare) and the context id is 0 or 1.
|
||||
- lead byte (192 - 207): next byte is ASCII or lead byte, context is 0 or 1
|
||||
- lead byte (208 - 255): next byte is continuation byte, context is 2 or 3
|
||||
|
||||
The possible value combinations of the previous two bytes, the range of
|
||||
context ids and the type of the next byte is summarized in the table below:
|
||||
|
||||
|--------\-----------------------------------------------------------------|
|
||||
| \ Last byte |
|
||||
| Second \---------------------------------------------------------------|
|
||||
| last byte \ ASCII | cont. byte | lead byte |
|
||||
| \ (0-127) | (128-191) | (192-) |
|
||||
|=============|===================|=====================|==================|
|
||||
| ASCII | next: ASCII/lead | not valid | next: cont. |
|
||||
| (0-127) | context: 4 - 63 | | context: 2 - 3 |
|
||||
|-------------|-------------------|---------------------|------------------|
|
||||
| cont. byte | next: ASCII/lead | next: ASCII/lead | next: cont. |
|
||||
| (128-191) | context: 4 - 63 | context: 0 - 1 | context: 2 - 3 |
|
||||
|-------------|-------------------|---------------------|------------------|
|
||||
| lead byte | not valid | next: ASCII/lead | not valid |
|
||||
| (192-207) | | context: 0 - 1 | |
|
||||
|-------------|-------------------|---------------------|------------------|
|
||||
| lead byte | not valid | next: cont. | not valid |
|
||||
| (208-) | | context: 2 - 3 | |
|
||||
|-------------|-------------------|---------------------|------------------|
|
||||
|
||||
The context id for the signed context mode is calculated as:
|
||||
|
||||
context = (kContextLookup[512 + p1] << 3) | kContextLookup[512 + p2].
|
||||
|
||||
For any context modeling modes, the context ids can be calculated by |-ing
|
||||
together two lookups from one table using context model dependent offsets:
|
||||
|
||||
context = kContextLookup[offset1 + p1] | kContextLookup[offset2 + p2].
|
||||
|
||||
where offset1 and offset2 are dependent on the context mode.
|
||||
*/
|
||||
|
||||
#ifndef BROTLI_DEC_CONTEXT_H_
|
||||
#define BROTLI_DEC_CONTEXT_H_
|
||||
|
||||
#include <brotli/types.h>
|
||||
|
||||
enum ContextType {
|
||||
CONTEXT_LSB6 = 0,
|
||||
CONTEXT_MSB6 = 1,
|
||||
CONTEXT_UTF8 = 2,
|
||||
CONTEXT_SIGNED = 3
|
||||
};
|
||||
#include "platform.h"
|
||||
|
||||
/* Common context lookup table for all context modes. */
|
||||
static const uint8_t kContextLookup[1792] = {
|
||||
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,
|
||||
@@ -130,6 +96,7 @@ static const uint8_t kContextLookup[1792] = {
|
||||
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,
|
||||
@@ -150,23 +117,7 @@ static const uint8_t kContextLookup[1792] = {
|
||||
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, 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,
|
||||
|
||||
/* 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,
|
||||
@@ -184,68 +135,22 @@ static const uint8_t kContextLookup[1792] = {
|
||||
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_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_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_{M,L}SB6, 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,
|
||||
};
|
||||
|
||||
static const int kContextLookupOffsets[8] = {
|
||||
/* CONTEXT_LSB6 */
|
||||
1024, 1536,
|
||||
/* CONTEXT_MSB6 */
|
||||
1280, 1536,
|
||||
/* CONTEXT_UTF8 */
|
||||
0, 256,
|
||||
/* CONTEXT_SIGNED */
|
||||
768, 512,
|
||||
/* 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,
|
||||
};
|
||||
|
||||
#endif /* BROTLI_DEC_CONTEXT_H_ */
|
||||
112
c/common/context.h
Normal file
112
c/common/context.h
Normal file
@@ -0,0 +1,112 @@
|
||||
/* Copyright 2013 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/* Lookup table to map the previous two bytes to a context id.
|
||||
|
||||
There are four different context modeling modes defined here:
|
||||
CONTEXT_LSB6: context id is the least significant 6 bits of the last byte,
|
||||
CONTEXT_MSB6: context id is the most significant 6 bits of the last byte,
|
||||
CONTEXT_UTF8: second-order context model tuned for UTF8-encoded text,
|
||||
CONTEXT_SIGNED: second-order context model tuned for signed integers.
|
||||
|
||||
If |p1| and |p2| are the previous two bytes, and |mode| is current context
|
||||
mode, we calculate the context as:
|
||||
|
||||
context = ContextLut(mode)[p1] | ContextLut(mode)[p2 + 256].
|
||||
|
||||
For CONTEXT_UTF8 mode, if the previous two bytes are ASCII characters
|
||||
(i.e. < 128), this will be equivalent to
|
||||
|
||||
context = 4 * context1(p1) + context2(p2),
|
||||
|
||||
where context1 is based on the previous byte in the following way:
|
||||
|
||||
0 : non-ASCII control
|
||||
1 : \t, \n, \r
|
||||
2 : space
|
||||
3 : other punctuation
|
||||
4 : " '
|
||||
5 : %
|
||||
6 : ( < [ {
|
||||
7 : ) > ] }
|
||||
8 : , ; :
|
||||
9 : .
|
||||
10 : =
|
||||
11 : number
|
||||
12 : upper-case vowel
|
||||
13 : upper-case consonant
|
||||
14 : lower-case vowel
|
||||
15 : lower-case consonant
|
||||
|
||||
and context2 is based on the second last byte:
|
||||
|
||||
0 : control, space
|
||||
1 : punctuation
|
||||
2 : upper-case letter, number
|
||||
3 : lower-case letter
|
||||
|
||||
If the last byte is ASCII, and the second last byte is not (in a valid UTF8
|
||||
stream it will be a continuation byte, value between 128 and 191), the
|
||||
context is the same as if the second last byte was an ASCII control or space.
|
||||
|
||||
If the last byte is a UTF8 lead byte (value >= 192), then the next byte will
|
||||
be a continuation byte and the context id is 2 or 3 depending on the LSB of
|
||||
the last byte and to a lesser extent on the second last byte if it is ASCII.
|
||||
|
||||
If the last byte is a UTF8 continuation byte, the second last byte can be:
|
||||
- continuation byte: the next byte is probably ASCII or lead byte (assuming
|
||||
4-byte UTF8 characters are rare) and the context id is 0 or 1.
|
||||
- lead byte (192 - 207): next byte is ASCII or lead byte, context is 0 or 1
|
||||
- lead byte (208 - 255): next byte is continuation byte, context is 2 or 3
|
||||
|
||||
The possible value combinations of the previous two bytes, the range of
|
||||
context ids and the type of the next byte is summarized in the table below:
|
||||
|
||||
|--------\-----------------------------------------------------------------|
|
||||
| \ Last byte |
|
||||
| Second \---------------------------------------------------------------|
|
||||
| last byte \ ASCII | cont. byte | lead byte |
|
||||
| \ (0-127) | (128-191) | (192-) |
|
||||
|=============|===================|=====================|==================|
|
||||
| ASCII | next: ASCII/lead | not valid | next: cont. |
|
||||
| (0-127) | context: 4 - 63 | | context: 2 - 3 |
|
||||
|-------------|-------------------|---------------------|------------------|
|
||||
| cont. byte | next: ASCII/lead | next: ASCII/lead | next: cont. |
|
||||
| (128-191) | context: 4 - 63 | context: 0 - 1 | context: 2 - 3 |
|
||||
|-------------|-------------------|---------------------|------------------|
|
||||
| lead byte | not valid | next: ASCII/lead | not valid |
|
||||
| (192-207) | | context: 0 - 1 | |
|
||||
|-------------|-------------------|---------------------|------------------|
|
||||
| lead byte | not valid | next: cont. | not valid |
|
||||
| (208-) | | context: 2 - 3 | |
|
||||
|-------------|-------------------|---------------------|------------------|
|
||||
*/
|
||||
|
||||
#ifndef BROTLI_COMMON_CONTEXT_H_
|
||||
#define BROTLI_COMMON_CONTEXT_H_
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
typedef enum ContextType {
|
||||
CONTEXT_LSB6 = 0,
|
||||
CONTEXT_MSB6 = 1,
|
||||
CONTEXT_UTF8 = 2,
|
||||
CONTEXT_SIGNED = 3
|
||||
} ContextType;
|
||||
|
||||
/* "Soft-private", it is exported, but not "advertised" as API. */
|
||||
/* Common context lookup table for all context modes. */
|
||||
BROTLI_COMMON_API extern const uint8_t _kBrotliContextLookupTable[2048];
|
||||
|
||||
typedef const uint8_t* ContextLut;
|
||||
|
||||
/* typeof(MODE) == ContextType; returns ContextLut */
|
||||
#define BROTLI_CONTEXT_LUT(MODE) (&_kBrotliContextLookupTable[(MODE) << 9])
|
||||
|
||||
/* typeof(LUT) == ContextLut */
|
||||
#define BROTLI_CONTEXT(P1, P2, LUT) ((LUT)[P1] | ((LUT) + 256)[P2])
|
||||
|
||||
#endif /* BROTLI_COMMON_CONTEXT_H_ */
|
||||
0
c/common/dictionary.bin
Executable file → Normal file
0
c/common/dictionary.bin
Executable file → Normal file
BIN
c/common/dictionary.bin.br
Normal file
BIN
c/common/dictionary.bin.br
Normal file
Binary file not shown.
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" {
|
||||
@@ -27,13 +26,13 @@ typedef struct BrotliDictionary {
|
||||
* Dictionary consists of words with length of [4..24] bytes.
|
||||
* Values at [0..3] and [25..31] indices should not be addressed.
|
||||
*/
|
||||
const uint8_t size_bits_by_length[32];
|
||||
uint8_t size_bits_by_length[32];
|
||||
|
||||
/* assert(offset[i + 1] == offset[i] + (bits[i] ? (i << bits[i]) : 0)) */
|
||||
const uint32_t offsets_by_length[32];
|
||||
uint32_t offsets_by_length[32];
|
||||
|
||||
/* assert(data_size == offsets_by_length[31]) */
|
||||
const size_t data_size;
|
||||
size_t data_size;
|
||||
|
||||
/* Data array is not bound, and should obey to size_bits_by_length values.
|
||||
Specified size matches default (RFC 7932) dictionary. Its size is
|
||||
@@ -41,7 +40,7 @@ typedef struct BrotliDictionary {
|
||||
const uint8_t* data;
|
||||
} BrotliDictionary;
|
||||
|
||||
BROTLI_COMMON_API extern const BrotliDictionary* BrotliGetDictionary(void);
|
||||
BROTLI_COMMON_API const BrotliDictionary* BrotliGetDictionary(void);
|
||||
|
||||
/**
|
||||
* Sets dictionary data.
|
||||
|
||||
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);
|
||||
}
|
||||
685
c/common/platform.h
Normal file
685
c/common/platform.h
Normal file
@@ -0,0 +1,685 @@
|
||||
/* Copyright 2016 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/* Macros for compiler / platform specific features and build options.
|
||||
|
||||
Build options are:
|
||||
* BROTLI_BUILD_32_BIT disables 64-bit optimizations
|
||||
* BROTLI_BUILD_64_BIT forces to use 64-bit optimizations
|
||||
* 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_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> /* 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> /* IWYU pragma: export */
|
||||
#include <brotli/types.h> /* IWYU pragma: export */
|
||||
|
||||
#if BROTLI_MSVC_VERSION_CHECK(18, 0, 0)
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
#if defined(BROTLI_ENABLE_LOG) || defined(BROTLI_DEBUG)
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
/* The following macros were borrowed from https://github.com/nemequ/hedley
|
||||
* with permission of original author - Evan Nemerson <evan@nemerson.com> */
|
||||
|
||||
/* >>> >>> >>> hedley macros */
|
||||
|
||||
/* Define "BROTLI_PREDICT_TRUE" and "BROTLI_PREDICT_FALSE" macros for capable
|
||||
compilers.
|
||||
|
||||
To apply compiler hint, enclose the branching condition into macros, like this:
|
||||
|
||||
if (BROTLI_PREDICT_TRUE(zero == 0)) {
|
||||
// main execution path
|
||||
} else {
|
||||
// compiler should place this code outside of main execution path
|
||||
}
|
||||
|
||||
OR:
|
||||
|
||||
if (BROTLI_PREDICT_FALSE(something_rare_or_unexpected_happens)) {
|
||||
// compiler should place this code outside of main execution path
|
||||
}
|
||||
|
||||
*/
|
||||
#if BROTLI_GNUC_HAS_BUILTIN(__builtin_expect, 3, 0, 0) || \
|
||||
BROTLI_INTEL_VERSION_CHECK(16, 0, 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) || \
|
||||
BROTLI_TINYC_VERSION_CHECK(0, 9, 27)
|
||||
#define BROTLI_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1))
|
||||
#define BROTLI_PREDICT_FALSE(x) (__builtin_expect(x, 0))
|
||||
#else
|
||||
#define BROTLI_PREDICT_FALSE(x) (x)
|
||||
#define BROTLI_PREDICT_TRUE(x) (x)
|
||||
#endif
|
||||
|
||||
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \
|
||||
!defined(__cplusplus)
|
||||
#define BROTLI_RESTRICT restrict
|
||||
#elif BROTLI_GNUC_VERSION_CHECK(3, 1, 0) || \
|
||||
BROTLI_MSVC_VERSION_CHECK(14, 0, 0) || \
|
||||
BROTLI_INTEL_VERSION_CHECK(16, 0, 0) || \
|
||||
BROTLI_ARM_VERSION_CHECK(4, 1, 0) || \
|
||||
BROTLI_IBM_VERSION_CHECK(10, 1, 0) || \
|
||||
BROTLI_PGI_VERSION_CHECK(17, 10, 0) || \
|
||||
BROTLI_TI_VERSION_CHECK(8, 0, 0) || \
|
||||
BROTLI_IAR_VERSION_CHECK(8, 0, 0) || \
|
||||
(BROTLI_SUNPRO_VERSION_CHECK(5, 14, 0) && defined(__cplusplus))
|
||||
#define BROTLI_RESTRICT __restrict
|
||||
#elif BROTLI_SUNPRO_VERSION_CHECK(5, 3, 0) && !defined(__cplusplus)
|
||||
#define BROTLI_RESTRICT _Restrict
|
||||
#else
|
||||
#define BROTLI_RESTRICT
|
||||
#endif
|
||||
|
||||
#if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \
|
||||
(defined(__cplusplus) && (__cplusplus >= 199711L))
|
||||
#define BROTLI_MAYBE_INLINE inline
|
||||
#elif defined(__GNUC_STDC_INLINE__) || defined(__GNUC_GNU_INLINE__) || \
|
||||
BROTLI_ARM_VERSION_CHECK(6, 2, 0)
|
||||
#define BROTLI_MAYBE_INLINE __inline__
|
||||
#elif BROTLI_MSVC_VERSION_CHECK(12, 0, 0) || \
|
||||
BROTLI_ARM_VERSION_CHECK(4, 1, 0) || BROTLI_TI_VERSION_CHECK(8, 0, 0)
|
||||
#define BROTLI_MAYBE_INLINE __inline
|
||||
#else
|
||||
#define BROTLI_MAYBE_INLINE
|
||||
#endif
|
||||
|
||||
#if BROTLI_GNUC_HAS_ATTRIBUTE(always_inline, 4, 0, 0) || \
|
||||
BROTLI_INTEL_VERSION_CHECK(16, 0, 0) || \
|
||||
BROTLI_SUNPRO_VERSION_CHECK(5, 11, 0) || \
|
||||
BROTLI_ARM_VERSION_CHECK(4, 1, 0) || \
|
||||
BROTLI_IBM_VERSION_CHECK(10, 1, 0) || \
|
||||
BROTLI_TI_VERSION_CHECK(8, 0, 0) || \
|
||||
(BROTLI_TI_VERSION_CHECK(7, 3, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__))
|
||||
#define BROTLI_INLINE BROTLI_MAYBE_INLINE __attribute__((__always_inline__))
|
||||
#elif BROTLI_MSVC_VERSION_CHECK(12, 0, 0)
|
||||
#define BROTLI_INLINE BROTLI_MAYBE_INLINE __forceinline
|
||||
#elif BROTLI_TI_VERSION_CHECK(7, 0, 0) && defined(__cplusplus)
|
||||
#define BROTLI_INLINE BROTLI_MAYBE_INLINE _Pragma("FUNC_ALWAYS_INLINE;")
|
||||
#elif BROTLI_IAR_VERSION_CHECK(8, 0, 0)
|
||||
#define BROTLI_INLINE BROTLI_MAYBE_INLINE _Pragma("inline=forced")
|
||||
#else
|
||||
#define BROTLI_INLINE BROTLI_MAYBE_INLINE
|
||||
#endif
|
||||
|
||||
#if BROTLI_GNUC_HAS_ATTRIBUTE(noinline, 4, 0, 0) || \
|
||||
BROTLI_INTEL_VERSION_CHECK(16, 0, 0) || \
|
||||
BROTLI_SUNPRO_VERSION_CHECK(5, 11, 0) || \
|
||||
BROTLI_ARM_VERSION_CHECK(4, 1, 0) || \
|
||||
BROTLI_IBM_VERSION_CHECK(10, 1, 0) || \
|
||||
BROTLI_TI_VERSION_CHECK(8, 0, 0) || \
|
||||
(BROTLI_TI_VERSION_CHECK(7, 3, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__))
|
||||
#define BROTLI_NOINLINE __attribute__((__noinline__))
|
||||
#elif BROTLI_MSVC_VERSION_CHECK(13, 10, 0)
|
||||
#define BROTLI_NOINLINE __declspec(noinline)
|
||||
#elif BROTLI_PGI_VERSION_CHECK(10, 2, 0)
|
||||
#define BROTLI_NOINLINE _Pragma("noinline")
|
||||
#elif BROTLI_TI_VERSION_CHECK(6, 0, 0) && defined(__cplusplus)
|
||||
#define BROTLI_NOINLINE _Pragma("FUNC_CANNOT_INLINE;")
|
||||
#elif BROTLI_IAR_VERSION_CHECK(8, 0, 0)
|
||||
#define BROTLI_NOINLINE _Pragma("inline=never")
|
||||
#else
|
||||
#define BROTLI_NOINLINE
|
||||
#endif
|
||||
|
||||
/* <<< <<< <<< end of hedley macros. */
|
||||
|
||||
#if BROTLI_GNUC_HAS_ATTRIBUTE(unused, 2, 7, 0) || \
|
||||
BROTLI_INTEL_VERSION_CHECK(16, 0, 0)
|
||||
#define BROTLI_UNUSED_FUNCTION static BROTLI_INLINE __attribute__ ((unused))
|
||||
#else
|
||||
#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
|
||||
#endif /* ARMv7 */
|
||||
|
||||
#if (defined(__ARM_ARCH) && (__ARM_ARCH == 8)) || \
|
||||
defined(__aarch64__) || defined(__ARM64_ARCH_8__)
|
||||
#define BROTLI_TARGET_ARMV8_ANY
|
||||
|
||||
#if defined(__ARM_32BIT_STATE)
|
||||
#define BROTLI_TARGET_ARMV8_32
|
||||
#elif defined(__ARM_64BIT_STATE)
|
||||
#define BROTLI_TARGET_ARMV8_64
|
||||
#endif
|
||||
|
||||
#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
|
||||
|
||||
#if defined(__x86_64__) || defined(_M_X64)
|
||||
#define BROTLI_TARGET_X64
|
||||
#endif
|
||||
|
||||
#if defined(__PPC64__)
|
||||
#define BROTLI_TARGET_POWERPC64
|
||||
#endif
|
||||
|
||||
#if defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 64
|
||||
#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(__ia64__) || defined(_M_IA64)
|
||||
#define BROTLI_TARGET_IA64
|
||||
#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
|
||||
#else
|
||||
#define BROTLI_64_BITS BROTLI_TARGET_64_BITS
|
||||
#endif
|
||||
|
||||
#if (BROTLI_64_BITS)
|
||||
#define brotli_reg_t uint64_t
|
||||
#else
|
||||
#define brotli_reg_t uint32_t
|
||||
#endif
|
||||
|
||||
#if defined(BROTLI_BUILD_BIG_ENDIAN)
|
||||
#define BROTLI_BIG_ENDIAN 1
|
||||
#elif defined(BROTLI_BUILD_LITTLE_ENDIAN)
|
||||
#define BROTLI_LITTLE_ENDIAN 1
|
||||
#elif defined(BROTLI_BUILD_ENDIAN_NEUTRAL)
|
||||
/* Just break elif chain. */
|
||||
#elif defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
|
||||
#define BROTLI_LITTLE_ENDIAN 1
|
||||
#elif defined(_WIN32) || defined(BROTLI_TARGET_X64)
|
||||
/* Win32 & x64 can currently always be assumed to be little endian */
|
||||
#define BROTLI_LITTLE_ENDIAN 1
|
||||
#elif defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
|
||||
#define BROTLI_BIG_ENDIAN 1
|
||||
/* Likely target platform is iOS / OSX. */
|
||||
#elif defined(BYTE_ORDER) && (BYTE_ORDER == LITTLE_ENDIAN)
|
||||
#define BROTLI_LITTLE_ENDIAN 1
|
||||
#elif defined(BYTE_ORDER) && (BYTE_ORDER == BIG_ENDIAN)
|
||||
#define BROTLI_BIG_ENDIAN 1
|
||||
#endif
|
||||
|
||||
#if !defined(BROTLI_LITTLE_ENDIAN)
|
||||
#define BROTLI_LITTLE_ENDIAN 0
|
||||
#endif
|
||||
|
||||
#if !defined(BROTLI_BIG_ENDIAN)
|
||||
#define BROTLI_BIG_ENDIAN 0
|
||||
#endif
|
||||
|
||||
#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) || 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_UNALIGNED_READ_FAST (!!0)
|
||||
#endif
|
||||
|
||||
/* 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);
|
||||
return t;
|
||||
}
|
||||
static BROTLI_INLINE uint32_t BrotliUnalignedRead32(const void* p) {
|
||||
uint32_t t;
|
||||
memcpy(&t, p, sizeof t);
|
||||
return t;
|
||||
}
|
||||
static BROTLI_INLINE uint64_t BrotliUnalignedRead64(const void* p) {
|
||||
uint64_t t;
|
||||
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);
|
||||
}
|
||||
|
||||
#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
|
||||
#define BROTLI_BSWAP16(V) ((uint16_t)( \
|
||||
(((V) & 0xFFU) << 8) | \
|
||||
(((V) >> 8) & 0xFFU)))
|
||||
#endif
|
||||
|
||||
#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
|
||||
|
||||
#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. */
|
||||
#define BROTLI_UNALIGNED_LOAD16LE BrotliUnalignedRead16
|
||||
#define BROTLI_UNALIGNED_LOAD32LE BrotliUnalignedRead32
|
||||
#define BROTLI_UNALIGNED_LOAD64LE BrotliUnalignedRead64
|
||||
#define BROTLI_UNALIGNED_STORE64LE BrotliUnalignedWrite64
|
||||
#elif BROTLI_BIG_ENDIAN /* BROTLI_LITTLE_ENDIAN */
|
||||
static BROTLI_INLINE uint16_t BROTLI_UNALIGNED_LOAD16LE(const void* p) {
|
||||
uint16_t value = BrotliUnalignedRead16(p);
|
||||
return BROTLI_BSWAP16(value);
|
||||
}
|
||||
static BROTLI_INLINE uint32_t BROTLI_UNALIGNED_LOAD32LE(const void* p) {
|
||||
uint32_t value = BrotliUnalignedRead32(p);
|
||||
return BROTLI_BSWAP32(value);
|
||||
}
|
||||
static BROTLI_INLINE uint64_t BROTLI_UNALIGNED_LOAD64LE(const void* p) {
|
||||
uint64_t value = BrotliUnalignedRead64(p);
|
||||
return BROTLI_BSWAP64(value);
|
||||
}
|
||||
static BROTLI_INLINE void BROTLI_UNALIGNED_STORE64LE(void* p, uint64_t v) {
|
||||
uint64_t value = BROTLI_BSWAP64(v);
|
||||
BrotliUnalignedWrite64(p, value);
|
||||
}
|
||||
#else /* BROTLI_LITTLE_ENDIAN */
|
||||
/* Read / store values byte-wise; hopefully compiler will understand. */
|
||||
static BROTLI_INLINE uint16_t BROTLI_UNALIGNED_LOAD16LE(const void* p) {
|
||||
const uint8_t* in = (const uint8_t*)p;
|
||||
return (uint16_t)(in[0] | (in[1] << 8));
|
||||
}
|
||||
static BROTLI_INLINE uint32_t BROTLI_UNALIGNED_LOAD32LE(const void* p) {
|
||||
const uint8_t* in = (const uint8_t*)p;
|
||||
uint32_t value = (uint32_t)(in[0]);
|
||||
value |= (uint32_t)(in[1]) << 8;
|
||||
value |= (uint32_t)(in[2]) << 16;
|
||||
value |= (uint32_t)(in[3]) << 24;
|
||||
return value;
|
||||
}
|
||||
static BROTLI_INLINE uint64_t BROTLI_UNALIGNED_LOAD64LE(const void* p) {
|
||||
const uint8_t* in = (const uint8_t*)p;
|
||||
uint64_t value = (uint64_t)(in[0]);
|
||||
value |= (uint64_t)(in[1]) << 8;
|
||||
value |= (uint64_t)(in[2]) << 16;
|
||||
value |= (uint64_t)(in[3]) << 24;
|
||||
value |= (uint64_t)(in[4]) << 32;
|
||||
value |= (uint64_t)(in[5]) << 40;
|
||||
value |= (uint64_t)(in[6]) << 48;
|
||||
value |= (uint64_t)(in[7]) << 56;
|
||||
return value;
|
||||
}
|
||||
static BROTLI_INLINE void BROTLI_UNALIGNED_STORE64LE(void* p, uint64_t v) {
|
||||
uint8_t* out = (uint8_t*)p;
|
||||
out[0] = (uint8_t)v;
|
||||
out[1] = (uint8_t)(v >> 8);
|
||||
out[2] = (uint8_t)(v >> 16);
|
||||
out[3] = (uint8_t)(v >> 24);
|
||||
out[4] = (uint8_t)(v >> 32);
|
||||
out[5] = (uint8_t)(v >> 40);
|
||||
out[6] = (uint8_t)(v >> 48);
|
||||
out[7] = (uint8_t)(v >> 56);
|
||||
}
|
||||
#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)
|
||||
#define BROTLI_IS_CONSTANT(x) (!!__builtin_constant_p(x))
|
||||
#else
|
||||
#define BROTLI_IS_CONSTANT(x) (!!0)
|
||||
#endif
|
||||
|
||||
#if defined(BROTLI_TARGET_ARMV7) || defined(BROTLI_TARGET_ARMV8_ANY)
|
||||
#define BROTLI_HAS_UBFX (!!1)
|
||||
#else
|
||||
#define BROTLI_HAS_UBFX (!!0)
|
||||
#endif
|
||||
|
||||
#if defined(BROTLI_ENABLE_LOG)
|
||||
#define BROTLI_LOG(x) printf x
|
||||
#else
|
||||
#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);
|
||||
}
|
||||
#define BROTLI_DUMP() BrotliDump(__FILE__, __LINE__, __FUNCTION__)
|
||||
#else
|
||||
#define BROTLI_DUMP() (void)(0)
|
||||
#endif
|
||||
|
||||
/* 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(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));
|
||||
return output;
|
||||
}
|
||||
#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_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)
|
||||
|
||||
#define BROTLI_MIN_MAX(T) \
|
||||
static BROTLI_INLINE T brotli_min_ ## T (T a, T b) { return a < b ? a : b; } \
|
||||
static BROTLI_INLINE T brotli_max_ ## T (T a, T b) { return a > b ? a : b; }
|
||||
BROTLI_MIN_MAX(double) BROTLI_MIN_MAX(float) BROTLI_MIN_MAX(int)
|
||||
BROTLI_MIN_MAX(size_t) BROTLI_MIN_MAX(uint32_t) BROTLI_MIN_MAX(uint8_t)
|
||||
#undef BROTLI_MIN_MAX
|
||||
#define BROTLI_MIN(T, A, B) (brotli_min_ ## T((A), (B)))
|
||||
#define BROTLI_MAX(T, A, B) (brotli_max_ ## T((A), (B)))
|
||||
|
||||
#define BROTLI_SWAP(T, A, I, J) { \
|
||||
T __brotli_swap_tmp = (A)[(I)]; \
|
||||
(A)[(I)] = (A)[(J)]; \
|
||||
(A)[(J)] = __brotli_swap_tmp; \
|
||||
}
|
||||
|
||||
#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 */
|
||||
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) {
|
||||
BROTLI_UNUSED(&BrotliSuppressUnusedFunctions);
|
||||
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);
|
||||
BROTLI_UNUSED(&brotli_min_float);
|
||||
BROTLI_UNUSED(&brotli_max_float);
|
||||
BROTLI_UNUSED(&brotli_min_int);
|
||||
BROTLI_UNUSED(&brotli_max_int);
|
||||
BROTLI_UNUSED(&brotli_min_size_t);
|
||||
BROTLI_UNUSED(&brotli_max_size_t);
|
||||
BROTLI_UNUSED(&brotli_min_uint32_t);
|
||||
BROTLI_UNUSED(&brotli_max_uint32_t);
|
||||
BROTLI_UNUSED(&brotli_min_uint8_t);
|
||||
BROTLI_UNUSED(&brotli_max_uint8_t);
|
||||
BROTLI_UNUSED(&BrotliDefaultAllocFunc);
|
||||
BROTLI_UNUSED(&BrotliDefaultFreeFunc);
|
||||
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 !defined(BROTLI_MODEL) && BROTLI_GNUC_HAS_ATTRIBUTE(model, 3, 0, 3) && \
|
||||
!defined(BROTLI_TARGET_IA64) && !defined(BROTLI_TARGET_LOONGARCH64)
|
||||
#define BROTLI_MODEL(M) __attribute__((model(M)))
|
||||
#else
|
||||
#define BROTLI_MODEL(M) /* M */
|
||||
#endif
|
||||
|
||||
#if !defined(BROTLI_COLD) && 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_
|
||||
293
c/common/transform.c
Normal file
293
c/common/transform.c
Normal file
@@ -0,0 +1,293 @@
|
||||
/* 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 "platform.h"
|
||||
#include "transform.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* RFC 7932 transforms string data */
|
||||
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 "
|
||||
/* 2x _3_ _5 _A_ _D_ _F _2 _4 _A _E */
|
||||
"that \1\'\6 with \6 from \4 by \1(\6. T"
|
||||
/* 4x _5_ _7 _E _5 _A _C */
|
||||
"he \4 on \4 as \4 is \4ing \2\n\t\1:\3ed "
|
||||
/* 6x _3 _8 _D _2 _7_ _ _A _C */
|
||||
"\2=\"\4 at \3ly \1,\2=\'\5.com/\7. This \5"
|
||||
/* 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 - implicit trailing zero. */
|
||||
/* Cx _2 _7___ ___ _A _F _5 _8 */
|
||||
|
||||
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,
|
||||
0x80, 0x83, 0x88, 0x8C, 0x8E, 0x91, 0x97, 0x9F, 0xA5, 0xA9,
|
||||
0xAD, 0xB2, 0xB7, 0xBD, 0xC2, 0xC7, 0xCA, 0xCF, 0xD5, 0xD8
|
||||
};
|
||||
|
||||
/* RFC 7932 transforms */
|
||||
static const BROTLI_MODEL("small") uint8_t kTransformsData[] = {
|
||||
49, BROTLI_TRANSFORM_IDENTITY, 49,
|
||||
49, BROTLI_TRANSFORM_IDENTITY, 0,
|
||||
0, BROTLI_TRANSFORM_IDENTITY, 0,
|
||||
49, BROTLI_TRANSFORM_OMIT_FIRST_1, 49,
|
||||
49, BROTLI_TRANSFORM_UPPERCASE_FIRST, 0,
|
||||
49, BROTLI_TRANSFORM_IDENTITY, 47,
|
||||
0, BROTLI_TRANSFORM_IDENTITY, 49,
|
||||
4, BROTLI_TRANSFORM_IDENTITY, 0,
|
||||
49, BROTLI_TRANSFORM_IDENTITY, 3,
|
||||
49, BROTLI_TRANSFORM_UPPERCASE_FIRST, 49,
|
||||
49, BROTLI_TRANSFORM_IDENTITY, 6,
|
||||
49, BROTLI_TRANSFORM_OMIT_FIRST_2, 49,
|
||||
49, BROTLI_TRANSFORM_OMIT_LAST_1, 49,
|
||||
1, BROTLI_TRANSFORM_IDENTITY, 0,
|
||||
49, BROTLI_TRANSFORM_IDENTITY, 1,
|
||||
0, BROTLI_TRANSFORM_UPPERCASE_FIRST, 0,
|
||||
49, BROTLI_TRANSFORM_IDENTITY, 7,
|
||||
49, BROTLI_TRANSFORM_IDENTITY, 9,
|
||||
48, BROTLI_TRANSFORM_IDENTITY, 0,
|
||||
49, BROTLI_TRANSFORM_IDENTITY, 8,
|
||||
49, BROTLI_TRANSFORM_IDENTITY, 5,
|
||||
49, BROTLI_TRANSFORM_IDENTITY, 10,
|
||||
49, BROTLI_TRANSFORM_IDENTITY, 11,
|
||||
49, BROTLI_TRANSFORM_OMIT_LAST_3, 49,
|
||||
49, BROTLI_TRANSFORM_IDENTITY, 13,
|
||||
49, BROTLI_TRANSFORM_IDENTITY, 14,
|
||||
49, BROTLI_TRANSFORM_OMIT_FIRST_3, 49,
|
||||
49, BROTLI_TRANSFORM_OMIT_LAST_2, 49,
|
||||
49, BROTLI_TRANSFORM_IDENTITY, 15,
|
||||
49, BROTLI_TRANSFORM_IDENTITY, 16,
|
||||
0, BROTLI_TRANSFORM_UPPERCASE_FIRST, 49,
|
||||
49, BROTLI_TRANSFORM_IDENTITY, 12,
|
||||
5, BROTLI_TRANSFORM_IDENTITY, 49,
|
||||
0, BROTLI_TRANSFORM_IDENTITY, 1,
|
||||
49, BROTLI_TRANSFORM_OMIT_FIRST_4, 49,
|
||||
49, BROTLI_TRANSFORM_IDENTITY, 18,
|
||||
49, BROTLI_TRANSFORM_IDENTITY, 17,
|
||||
49, BROTLI_TRANSFORM_IDENTITY, 19,
|
||||
49, BROTLI_TRANSFORM_IDENTITY, 20,
|
||||
49, BROTLI_TRANSFORM_OMIT_FIRST_5, 49,
|
||||
49, BROTLI_TRANSFORM_OMIT_FIRST_6, 49,
|
||||
47, BROTLI_TRANSFORM_IDENTITY, 49,
|
||||
49, BROTLI_TRANSFORM_OMIT_LAST_4, 49,
|
||||
49, BROTLI_TRANSFORM_IDENTITY, 22,
|
||||
49, BROTLI_TRANSFORM_UPPERCASE_ALL, 49,
|
||||
49, BROTLI_TRANSFORM_IDENTITY, 23,
|
||||
49, BROTLI_TRANSFORM_IDENTITY, 24,
|
||||
49, BROTLI_TRANSFORM_IDENTITY, 25,
|
||||
49, BROTLI_TRANSFORM_OMIT_LAST_7, 49,
|
||||
49, BROTLI_TRANSFORM_OMIT_LAST_1, 26,
|
||||
49, BROTLI_TRANSFORM_IDENTITY, 27,
|
||||
49, BROTLI_TRANSFORM_IDENTITY, 28,
|
||||
0, BROTLI_TRANSFORM_IDENTITY, 12,
|
||||
49, BROTLI_TRANSFORM_IDENTITY, 29,
|
||||
49, BROTLI_TRANSFORM_OMIT_FIRST_9, 49,
|
||||
49, BROTLI_TRANSFORM_OMIT_FIRST_7, 49,
|
||||
49, BROTLI_TRANSFORM_OMIT_LAST_6, 49,
|
||||
49, BROTLI_TRANSFORM_IDENTITY, 21,
|
||||
49, BROTLI_TRANSFORM_UPPERCASE_FIRST, 1,
|
||||
49, BROTLI_TRANSFORM_OMIT_LAST_8, 49,
|
||||
49, BROTLI_TRANSFORM_IDENTITY, 31,
|
||||
49, BROTLI_TRANSFORM_IDENTITY, 32,
|
||||
47, BROTLI_TRANSFORM_IDENTITY, 3,
|
||||
49, BROTLI_TRANSFORM_OMIT_LAST_5, 49,
|
||||
49, BROTLI_TRANSFORM_OMIT_LAST_9, 49,
|
||||
0, BROTLI_TRANSFORM_UPPERCASE_FIRST, 1,
|
||||
49, BROTLI_TRANSFORM_UPPERCASE_FIRST, 8,
|
||||
5, BROTLI_TRANSFORM_IDENTITY, 21,
|
||||
49, BROTLI_TRANSFORM_UPPERCASE_ALL, 0,
|
||||
49, BROTLI_TRANSFORM_UPPERCASE_FIRST, 10,
|
||||
49, BROTLI_TRANSFORM_IDENTITY, 30,
|
||||
0, BROTLI_TRANSFORM_IDENTITY, 5,
|
||||
35, BROTLI_TRANSFORM_IDENTITY, 49,
|
||||
47, BROTLI_TRANSFORM_IDENTITY, 2,
|
||||
49, BROTLI_TRANSFORM_UPPERCASE_FIRST, 17,
|
||||
49, BROTLI_TRANSFORM_IDENTITY, 36,
|
||||
49, BROTLI_TRANSFORM_IDENTITY, 33,
|
||||
5, BROTLI_TRANSFORM_IDENTITY, 0,
|
||||
49, BROTLI_TRANSFORM_UPPERCASE_FIRST, 21,
|
||||
49, BROTLI_TRANSFORM_UPPERCASE_FIRST, 5,
|
||||
49, BROTLI_TRANSFORM_IDENTITY, 37,
|
||||
0, BROTLI_TRANSFORM_IDENTITY, 30,
|
||||
49, BROTLI_TRANSFORM_IDENTITY, 38,
|
||||
0, BROTLI_TRANSFORM_UPPERCASE_ALL, 0,
|
||||
49, BROTLI_TRANSFORM_IDENTITY, 39,
|
||||
0, BROTLI_TRANSFORM_UPPERCASE_ALL, 49,
|
||||
49, BROTLI_TRANSFORM_IDENTITY, 34,
|
||||
49, BROTLI_TRANSFORM_UPPERCASE_ALL, 8,
|
||||
49, BROTLI_TRANSFORM_UPPERCASE_FIRST, 12,
|
||||
0, BROTLI_TRANSFORM_IDENTITY, 21,
|
||||
49, BROTLI_TRANSFORM_IDENTITY, 40,
|
||||
0, BROTLI_TRANSFORM_UPPERCASE_FIRST, 12,
|
||||
49, BROTLI_TRANSFORM_IDENTITY, 41,
|
||||
49, BROTLI_TRANSFORM_IDENTITY, 42,
|
||||
49, BROTLI_TRANSFORM_UPPERCASE_ALL, 17,
|
||||
49, BROTLI_TRANSFORM_IDENTITY, 43,
|
||||
0, BROTLI_TRANSFORM_UPPERCASE_FIRST, 5,
|
||||
49, BROTLI_TRANSFORM_UPPERCASE_ALL, 10,
|
||||
0, BROTLI_TRANSFORM_IDENTITY, 34,
|
||||
49, BROTLI_TRANSFORM_UPPERCASE_FIRST, 33,
|
||||
49, BROTLI_TRANSFORM_IDENTITY, 44,
|
||||
49, BROTLI_TRANSFORM_UPPERCASE_ALL, 5,
|
||||
45, BROTLI_TRANSFORM_IDENTITY, 49,
|
||||
0, BROTLI_TRANSFORM_IDENTITY, 33,
|
||||
49, BROTLI_TRANSFORM_UPPERCASE_FIRST, 30,
|
||||
49, BROTLI_TRANSFORM_UPPERCASE_ALL, 30,
|
||||
49, BROTLI_TRANSFORM_IDENTITY, 46,
|
||||
49, BROTLI_TRANSFORM_UPPERCASE_ALL, 1,
|
||||
49, BROTLI_TRANSFORM_UPPERCASE_FIRST, 34,
|
||||
0, BROTLI_TRANSFORM_UPPERCASE_FIRST, 33,
|
||||
0, BROTLI_TRANSFORM_UPPERCASE_ALL, 30,
|
||||
0, BROTLI_TRANSFORM_UPPERCASE_ALL, 1,
|
||||
49, BROTLI_TRANSFORM_UPPERCASE_ALL, 33,
|
||||
49, BROTLI_TRANSFORM_UPPERCASE_ALL, 21,
|
||||
49, BROTLI_TRANSFORM_UPPERCASE_ALL, 12,
|
||||
0, BROTLI_TRANSFORM_UPPERCASE_ALL, 5,
|
||||
49, BROTLI_TRANSFORM_UPPERCASE_ALL, 34,
|
||||
0, BROTLI_TRANSFORM_UPPERCASE_ALL, 12,
|
||||
0, BROTLI_TRANSFORM_UPPERCASE_FIRST, 30,
|
||||
0, BROTLI_TRANSFORM_UPPERCASE_ALL, 34,
|
||||
0, BROTLI_TRANSFORM_UPPERCASE_FIRST, 34,
|
||||
};
|
||||
|
||||
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}
|
||||
};
|
||||
|
||||
const BrotliTransforms* BrotliGetTransforms(void) {
|
||||
return &kBrotliTransforms;
|
||||
}
|
||||
|
||||
static int ToUpperCase(uint8_t* p) {
|
||||
if (p[0] < 0xC0) {
|
||||
if (p[0] >= 'a' && p[0] <= 'z') {
|
||||
p[0] ^= 32;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
/* An overly simplified uppercasing model for UTF-8. */
|
||||
if (p[0] < 0xE0) {
|
||||
p[1] ^= 32;
|
||||
return 2;
|
||||
}
|
||||
/* An arbitrary transform for three byte characters. */
|
||||
p[2] ^= 5;
|
||||
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 transform_idx) {
|
||||
int idx = 0;
|
||||
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++; }
|
||||
}
|
||||
{
|
||||
const int t = type;
|
||||
int i = 0;
|
||||
if (t <= BROTLI_TRANSFORM_OMIT_LAST_9) {
|
||||
len -= t;
|
||||
} else if (t >= BROTLI_TRANSFORM_OMIT_FIRST_1
|
||||
&& t <= BROTLI_TRANSFORM_OMIT_FIRST_9) {
|
||||
int skip = t - (BROTLI_TRANSFORM_OMIT_FIRST_1 - 1);
|
||||
word += skip;
|
||||
len -= skip;
|
||||
}
|
||||
while (i < len) { dst[idx++] = word[i++]; }
|
||||
if (t == BROTLI_TRANSFORM_UPPERCASE_FIRST) {
|
||||
ToUpperCase(&dst[idx - len]);
|
||||
} else if (t == BROTLI_TRANSFORM_UPPERCASE_ALL) {
|
||||
uint8_t* uppercase = &dst[idx - len];
|
||||
while (len > 0) {
|
||||
int step = ToUpperCase(uppercase);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
int suffix_len = *suffix++;
|
||||
while (suffix_len--) { dst[idx++] = *suffix++; }
|
||||
return idx;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
84
c/common/transform.h
Normal file
84
c/common/transform.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/* transforms is a part of ABI, but not API.
|
||||
|
||||
It means that there are some functions that are supposed to be in "common"
|
||||
library, but header itself is not placed into include/brotli. This way,
|
||||
aforementioned functions will be available only to brotli internals.
|
||||
*/
|
||||
|
||||
#ifndef BROTLI_COMMON_TRANSFORM_H_
|
||||
#define BROTLI_COMMON_TRANSFORM_H_
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum BrotliWordTransformType {
|
||||
BROTLI_TRANSFORM_IDENTITY = 0,
|
||||
BROTLI_TRANSFORM_OMIT_LAST_1 = 1,
|
||||
BROTLI_TRANSFORM_OMIT_LAST_2 = 2,
|
||||
BROTLI_TRANSFORM_OMIT_LAST_3 = 3,
|
||||
BROTLI_TRANSFORM_OMIT_LAST_4 = 4,
|
||||
BROTLI_TRANSFORM_OMIT_LAST_5 = 5,
|
||||
BROTLI_TRANSFORM_OMIT_LAST_6 = 6,
|
||||
BROTLI_TRANSFORM_OMIT_LAST_7 = 7,
|
||||
BROTLI_TRANSFORM_OMIT_LAST_8 = 8,
|
||||
BROTLI_TRANSFORM_OMIT_LAST_9 = 9,
|
||||
BROTLI_TRANSFORM_UPPERCASE_FIRST = 10,
|
||||
BROTLI_TRANSFORM_UPPERCASE_ALL = 11,
|
||||
BROTLI_TRANSFORM_OMIT_FIRST_1 = 12,
|
||||
BROTLI_TRANSFORM_OMIT_FIRST_2 = 13,
|
||||
BROTLI_TRANSFORM_OMIT_FIRST_3 = 14,
|
||||
BROTLI_TRANSFORM_OMIT_FIRST_4 = 15,
|
||||
BROTLI_TRANSFORM_OMIT_FIRST_5 = 16,
|
||||
BROTLI_TRANSFORM_OMIT_FIRST_6 = 17,
|
||||
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. */
|
||||
};
|
||||
|
||||
#define BROTLI_TRANSFORMS_MAX_CUT_OFF BROTLI_TRANSFORM_OMIT_LAST_9
|
||||
|
||||
typedef struct BrotliTransforms {
|
||||
uint16_t prefix_suffix_size;
|
||||
/* Last character must be null, so prefix_suffix_size must be at least 1. */
|
||||
const uint8_t* prefix_suffix;
|
||||
const uint16_t* prefix_suffix_map;
|
||||
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. */
|
||||
int16_t cutOffTransforms[BROTLI_TRANSFORMS_MAX_CUT_OFF + 1];
|
||||
} BrotliTransforms;
|
||||
|
||||
/* T is BrotliTransforms*; result is uint8_t. */
|
||||
#define BROTLI_TRANSFORM_PREFIX_ID(T, I) ((T)->transforms[((I) * 3) + 0])
|
||||
#define BROTLI_TRANSFORM_TYPE(T, I) ((T)->transforms[((I) * 3) + 1])
|
||||
#define BROTLI_TRANSFORM_SUFFIX_ID(T, I) ((T)->transforms[((I) * 3) + 2])
|
||||
|
||||
/* T is BrotliTransforms*; result is const uint8_t*. */
|
||||
#define BROTLI_TRANSFORM_PREFIX(T, I) (&(T)->prefix_suffix[ \
|
||||
(T)->prefix_suffix_map[BROTLI_TRANSFORM_PREFIX_ID(T, I)]])
|
||||
#define BROTLI_TRANSFORM_SUFFIX(T, I) (&(T)->prefix_suffix[ \
|
||||
(T)->prefix_suffix_map[BROTLI_TRANSFORM_SUFFIX_ID(T, I)]])
|
||||
|
||||
BROTLI_COMMON_API const BrotliTransforms* BrotliGetTransforms(void);
|
||||
|
||||
BROTLI_COMMON_API int BrotliTransformDictionaryWord(
|
||||
uint8_t* dst, const uint8_t* word, int len,
|
||||
const BrotliTransforms* transforms, int transform_idx);
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* BROTLI_COMMON_TRANSFORM_H_ */
|
||||
40
c/common/version.h
Executable file → Normal file
40
c/common/version.h
Executable file → Normal file
@@ -9,11 +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 0x1000000
|
||||
#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
|
||||
*/
|
||||
|
||||
#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 <brotli/types.h>
|
||||
#include "./port.h"
|
||||
#include "../common/platform.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,67 +9,83 @@
|
||||
#ifndef BROTLI_DEC_BIT_READER_H_
|
||||
#define BROTLI_DEC_BIT_READER_H_
|
||||
|
||||
#include <string.h> /* memcpy */
|
||||
|
||||
#include <brotli/types.h>
|
||||
#include "./port.h"
|
||||
#include "../common/constants.h"
|
||||
#include "../common/platform.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define BROTLI_SHORT_FILL_BIT_WINDOW_READ (sizeof(reg_t) >> 1)
|
||||
#define BROTLI_SHORT_FILL_BIT_WINDOW_READ (sizeof(brotli_reg_t) >> 1)
|
||||
|
||||
static const uint32_t kBitMask[33] = { 0x0000,
|
||||
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) {
|
||||
if (IS_CONSTANT(n) || BROTLI_HAS_UBFX) {
|
||||
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 {
|
||||
reg_t val_; /* pre-fetched bits */
|
||||
uint32_t bit_pos_; /* current bit-reading position in val_ */
|
||||
brotli_reg_t val_; /* pre-fetched bits */
|
||||
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 {
|
||||
reg_t val_;
|
||||
uint32_t bit_pos_;
|
||||
brotli_reg_t val_;
|
||||
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 one byte of input.
|
||||
Returns 0 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);
|
||||
/* 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_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(
|
||||
@@ -77,130 +93,92 @@ 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);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE uint16_t BrotliLoad16LE(const uint8_t* in) {
|
||||
if (BROTLI_LITTLE_ENDIAN) {
|
||||
return *((const uint16_t*)in);
|
||||
} else if (BROTLI_BIG_ENDIAN) {
|
||||
uint16_t value = *((const uint16_t*)in);
|
||||
return (uint16_t)(((value & 0xFFU) << 8) | ((value & 0xFF00U) >> 8));
|
||||
} else {
|
||||
return (uint16_t)(in[0] | (in[1] << 8));
|
||||
}
|
||||
/* 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);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE uint32_t BrotliLoad32LE(const uint8_t* in) {
|
||||
if (BROTLI_LITTLE_ENDIAN) {
|
||||
return *((const uint32_t*)in);
|
||||
} else if (BROTLI_BIG_ENDIAN) {
|
||||
uint32_t value = *((const uint32_t*)in);
|
||||
return ((value & 0xFFU) << 24) | ((value & 0xFF00U) << 8) |
|
||||
((value & 0xFF0000U) >> 8) | ((value & 0xFF000000U) >> 24);
|
||||
} else {
|
||||
uint32_t value = (uint32_t)(*(in++));
|
||||
value |= (uint32_t)(*(in++)) << 8;
|
||||
value |= (uint32_t)(*(in++)) << 16;
|
||||
value |= (uint32_t)(*(in++)) << 24;
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
#if (BROTLI_64_BITS)
|
||||
static BROTLI_INLINE uint64_t BrotliLoad64LE(const uint8_t* in) {
|
||||
if (BROTLI_LITTLE_ENDIAN) {
|
||||
return *((const uint64_t*)in);
|
||||
} else if (BROTLI_BIG_ENDIAN) {
|
||||
uint64_t value = *((const uint64_t*)in);
|
||||
return
|
||||
((value & 0xFFU) << 56) |
|
||||
((value & 0xFF00U) << 40) |
|
||||
((value & 0xFF0000U) << 24) |
|
||||
((value & 0xFF000000U) << 8) |
|
||||
((value & 0xFF00000000U) >> 8) |
|
||||
((value & 0xFF0000000000U) >> 24) |
|
||||
((value & 0xFF000000000000U) >> 40) |
|
||||
((value & 0xFF00000000000000U) >> 56);
|
||||
} else {
|
||||
uint64_t value = (uint64_t)(*(in++));
|
||||
value |= (uint64_t)(*(in++)) << 8;
|
||||
value |= (uint64_t)(*(in++)) << 16;
|
||||
value |= (uint64_t)(*(in++)) << 24;
|
||||
value |= (uint64_t)(*(in++)) << 32;
|
||||
value |= (uint64_t)(*(in++)) << 40;
|
||||
value |= (uint64_t)(*(in++)) << 48;
|
||||
value |= (uint64_t)(*(in++)) << 56;
|
||||
return value;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Guarantees that there are at least n_bits + 1 bits in accumulator.
|
||||
/* Guarantees that there are at least |n_bits| + 1 bits in accumulator.
|
||||
Precondition: accumulator contains at least 1 bit.
|
||||
n_bits should be in the range [1..24] for regular build. For portable
|
||||
|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 && 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_ |= BrotliLoad64LE(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 && 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_ |= BrotliLoad64LE(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)BrotliLoad32LE(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 && 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_ |= BrotliLoad32LE(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)BrotliLoad16LE(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;
|
||||
}
|
||||
}
|
||||
@@ -213,98 +191,107 @@ static BROTLI_INLINE void BrotliFillBitWindow16(BrotliBitReader* const br) {
|
||||
BrotliFillBitWindow(br, 17);
|
||||
}
|
||||
|
||||
/* Pulls one byte of input to accumulator. */
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* Returns currently available bits.
|
||||
The number of valid bits could be calculated by BrotliGetAvailableBits. */
|
||||
static BROTLI_INLINE reg_t BrotliGetBitsUnmasked(BrotliBitReader* const br) {
|
||||
return br->val_ >> br->bit_pos_;
|
||||
static BROTLI_INLINE brotli_reg_t BrotliGetBitsUnmasked(
|
||||
BrotliBitReader* const br) {
|
||||
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 pos. */
|
||||
static BROTLI_INLINE uint32_t BrotliGetBits(
|
||||
BrotliBitReader* const br, uint32_t n_bits) {
|
||||
/* Returns the specified number of bits from |br| without advancing bit
|
||||
position. */
|
||||
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 0, if there is not
|
||||
enough input. */
|
||||
/* 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. */
|
||||
/* 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_, n_bits, (int)*val));
|
||||
Precondition: accumulator MUST contain at least |n_bits|. */
|
||||
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);
|
||||
@@ -313,10 +300,32 @@ static BROTLI_INLINE uint32_t BrotliReadBits(
|
||||
}
|
||||
}
|
||||
|
||||
/* Tries to read the specified amount of bits. Returns 0, if there is not
|
||||
enough input. n_bits MUST be positive. */
|
||||
/* 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.
|
||||
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;
|
||||
@@ -326,19 +335,44 @@ 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
|
||||
|num| may not be larger than BrotliGetRemainingBytes. The bit reader must be
|
||||
warmed up again after this. */
|
||||
static BROTLI_INLINE void BrotliCopyBytes(uint8_t* dest,
|
||||
BrotliBitReader* br, size_t num) {
|
||||
@@ -348,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)
|
||||
|
||||
1813
c/dec/decode.c
1813
c/dec/decode.c
File diff suppressed because it is too large
Load Diff
163
c/dec/huffman.c
163
c/dec/huffman.c
@@ -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 <brotli/types.h>
|
||||
#include "./port.h"
|
||||
#include "../common/platform.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
@@ -20,12 +17,13 @@ extern "C" {
|
||||
|
||||
#define BROTLI_REVERSE_BITS_MAX 8
|
||||
|
||||
#ifdef BROTLI_RBIT
|
||||
#if defined(BROTLI_RBIT)
|
||||
#define BROTLI_REVERSE_BITS_BASE \
|
||||
((sizeof(reg_t) << 3) - BROTLI_REVERSE_BITS_MAX)
|
||||
((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,
|
||||
@@ -62,13 +60,13 @@ static uint8_t kReverseBits[1 << BROTLI_REVERSE_BITS_MAX] = {
|
||||
#endif /* BROTLI_RBIT */
|
||||
|
||||
#define BROTLI_REVERSE_BITS_LOWEST \
|
||||
((reg_t)1 << (BROTLI_REVERSE_BITS_MAX - 1 + BROTLI_REVERSE_BITS_BASE))
|
||||
((brotli_reg_t)1 << (BROTLI_REVERSE_BITS_MAX - 1 + BROTLI_REVERSE_BITS_BASE))
|
||||
|
||||
/* Returns reverse(num >> BROTLI_REVERSE_BITS_BASE, BROTLI_REVERSE_BITS_MAX),
|
||||
where reverse(value, len) is the bit-wise reversal of the len least
|
||||
significant bits of value. */
|
||||
static BROTLI_INLINE reg_t BrotliReverseBits(reg_t num) {
|
||||
#ifdef BROTLI_RBIT
|
||||
static BROTLI_INLINE brotli_reg_t BrotliReverseBits(brotli_reg_t num) {
|
||||
#if defined(BROTLI_RBIT)
|
||||
return BROTLI_RBIT(num);
|
||||
#else
|
||||
return kReverseBits[num];
|
||||
@@ -86,9 +84,9 @@ static BROTLI_INLINE void ReplicateValue(HuffmanCode* table,
|
||||
} while (end > 0);
|
||||
}
|
||||
|
||||
/* Returns the table width of the next 2nd level table. count is the histogram
|
||||
of bit lengths for the remaining symbols, len is the code length of the next
|
||||
processed symbol */
|
||||
/* Returns the table width of the next 2nd level table. |count| is the histogram
|
||||
of bit lengths for the remaining symbols, |len| is the code length of the
|
||||
next processed symbol. */
|
||||
static BROTLI_INLINE int NextTableBitSize(const uint16_t* const count,
|
||||
int len, int root_bits) {
|
||||
int left = 1 << (len - root_bits);
|
||||
@@ -104,12 +102,12 @@ static BROTLI_INLINE int NextTableBitSize(const uint16_t* const count,
|
||||
void BrotliBuildCodeLengthsHuffmanTable(HuffmanCode* table,
|
||||
const uint8_t* const code_lengths,
|
||||
uint16_t* count) {
|
||||
HuffmanCode code; /* current table entry */
|
||||
int symbol; /* symbol index in original or sorted table */
|
||||
reg_t key; /* prefix code */
|
||||
reg_t key_step; /* prefix code addend */
|
||||
int step; /* step size to replicate values in current table */
|
||||
int table_size; /* size of current table */
|
||||
HuffmanCode code; /* current table entry */
|
||||
int symbol; /* symbol index in original or sorted table */
|
||||
brotli_reg_t key; /* prefix code */
|
||||
brotli_reg_t key_step; /* prefix code addend */
|
||||
int step; /* step size to replicate values in current table */
|
||||
int table_size; /* size of current table */
|
||||
int sorted[BROTLI_CODE_LENGTH_CODES]; /* symbols sorted by code length */
|
||||
/* offsets in sorted table for each length */
|
||||
int offset[BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH + 1];
|
||||
@@ -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 */
|
||||
/* 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++;
|
||||
@@ -129,10 +129,10 @@ void BrotliBuildCodeLengthsHuffmanTable(HuffmanCode* table,
|
||||
/* Symbols with code length 0 are placed after all other symbols. */
|
||||
offset[0] = BROTLI_CODE_LENGTH_CODES - 1;
|
||||
|
||||
/* sort symbols by length, by symbol order within each length */
|
||||
/* 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,24 +142,22 @@ 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];
|
||||
for (key = 0; key < (reg_t)table_size; ++key) {
|
||||
code = ConstructHuffmanCode(0, (uint16_t)sorted[0]);
|
||||
for (key = 0; key < (brotli_reg_t)table_size; ++key) {
|
||||
table[key] = code;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* fill in table */
|
||||
/* Fill in table. */
|
||||
key = 0;
|
||||
key_step = BROTLI_REVERSE_BITS_LOWEST;
|
||||
symbol = 0;
|
||||
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;
|
||||
}
|
||||
@@ -172,18 +170,18 @@ uint32_t BrotliBuildHuffmanTable(HuffmanCode* root_table,
|
||||
int root_bits,
|
||||
const uint16_t* const symbol_lists,
|
||||
uint16_t* count) {
|
||||
HuffmanCode code; /* current table entry */
|
||||
HuffmanCode* table; /* next available space in table */
|
||||
int len; /* current code length */
|
||||
int symbol; /* symbol index in original or sorted table */
|
||||
reg_t key; /* prefix code */
|
||||
reg_t key_step; /* prefix code addend */
|
||||
reg_t sub_key; /* 2nd level table prefix code */
|
||||
reg_t sub_key_step; /* 2nd level table prefix code addend */
|
||||
int step; /* step size to replicate values in current table */
|
||||
int table_bits; /* key length of current table */
|
||||
int table_size; /* size of current table */
|
||||
int total_size; /* sum of root table size and 2nd level table sizes */
|
||||
HuffmanCode code; /* current table entry */
|
||||
HuffmanCode* table; /* next available space in table */
|
||||
int len; /* current code length */
|
||||
int symbol; /* symbol index in original or sorted table */
|
||||
brotli_reg_t key; /* prefix code */
|
||||
brotli_reg_t key_step; /* prefix code addend */
|
||||
brotli_reg_t sub_key; /* 2nd level table prefix code */
|
||||
brotli_reg_t sub_key_step; /* 2nd level table prefix code addend */
|
||||
int step; /* step size to replicate values in current table */
|
||||
int table_bits; /* key length of current table */
|
||||
int table_size; /* size of current table */
|
||||
int total_size; /* sum of root table size and 2nd level table sizes */
|
||||
int max_length = -1;
|
||||
int bits;
|
||||
int bits_count;
|
||||
@@ -200,9 +198,8 @@ uint32_t BrotliBuildHuffmanTable(HuffmanCode* root_table,
|
||||
table_size = 1 << table_bits;
|
||||
total_size = table_size;
|
||||
|
||||
/* fill in root table */
|
||||
/* let's reduce the table size to a smaller size if possible, and */
|
||||
/* create the repetitions by memcpy if possible in the coming loop */
|
||||
/* Fill in the root table. Reduce the table size to if possible,
|
||||
and create the repetitions by memcpy. */
|
||||
if (table_bits > max_length) {
|
||||
table_bits = max_length;
|
||||
table_size = 1 << table_bits;
|
||||
@@ -212,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;
|
||||
}
|
||||
@@ -224,15 +220,14 @@ uint32_t BrotliBuildHuffmanTable(HuffmanCode* root_table,
|
||||
key_step >>= 1;
|
||||
} while (++bits <= table_bits);
|
||||
|
||||
/* if root_bits != table_bits we only created one fraction of the */
|
||||
/* table, and we need to replicate it now. */
|
||||
/* If root_bits != table_bits then replicate to fill the remaining slots. */
|
||||
while (total_size != table_size) {
|
||||
memcpy(&table[table_size], &table[0],
|
||||
(size_t)table_size * sizeof(table[0]));
|
||||
table_size <<= 1;
|
||||
}
|
||||
|
||||
/* fill in 2nd level tables and add pointers to root table */
|
||||
/* Fill in 2nd level tables and add pointers to root table. */
|
||||
key_step = BROTLI_REVERSE_BITS_LOWEST >> (root_bits - 1);
|
||||
sub_key = (BROTLI_REVERSE_BITS_LOWEST << 1);
|
||||
sub_key_step = BROTLI_REVERSE_BITS_LOWEST;
|
||||
@@ -246,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;
|
||||
@@ -272,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: {
|
||||
@@ -314,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;
|
||||
}
|
||||
|
||||
@@ -9,8 +9,7 @@
|
||||
#ifndef BROTLI_DEC_HUFFMAN_H_
|
||||
#define BROTLI_DEC_HUFFMAN_H_
|
||||
|
||||
#include <brotli/types.h>
|
||||
#include "./port.h"
|
||||
#include "../common/platform.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
@@ -18,11 +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};
|
||||
/* BROTLI_NUM_BLOCK_LEN_SYMBOLS == 26 */
|
||||
#define BROTLI_HUFFMAN_MAX_SIZE_26 396
|
||||
/* BROTLI_MAX_BLOCK_TYPE_SYMBOLS == 258 */
|
||||
@@ -32,32 +26,90 @@ 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);
|
||||
|
||||
/* Builds Huffman lookup table assuming code lengths are in symbol order. */
|
||||
/* Returns size of resulting 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, 2 means 3 */
|
||||
/* symbols, 3 means 4 symbols with lengths 2,2,2,2, 4 means 4 symbols with */
|
||||
/* lengths 1,2,3,3. */
|
||||
/* Builds a simple Huffman table. The |num_symbols| parameter is to be
|
||||
interpreted as follows: 0 means 1 symbol, 1 means 2 symbols,
|
||||
2 means 3 symbols, 3 means 4 symbols with lengths [2, 2, 2, 2],
|
||||
4 means 4 symbols with lengths [1, 2, 3, 3]. */
|
||||
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. */
|
||||
/* 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 alphabet_size_max;
|
||||
uint16_t alphabet_size_limit;
|
||||
uint16_t num_htrees;
|
||||
} HuffmanTreeGroup;
|
||||
|
||||
|
||||
168
c/dec/port.h
168
c/dec/port.h
@@ -1,168 +0,0 @@
|
||||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/* Macros for compiler / platform specific features and build options.
|
||||
|
||||
Build options are:
|
||||
* BROTLI_BUILD_32_BIT disables 64-bit optimizations
|
||||
* BROTLI_BUILD_64_BIT forces to use 64-bit optimizations
|
||||
* 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_MODERN_COMPILER forces to use modern compilers built-ins,
|
||||
features and attributes
|
||||
* 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_DEBUG dumps file name and line number when decoder detects stream
|
||||
or memory error
|
||||
* BROTLI_ENABLE_LOG enables asserts and dumps various state information
|
||||
*/
|
||||
|
||||
#ifndef BROTLI_DEC_PORT_H_
|
||||
#define BROTLI_DEC_PORT_H_
|
||||
|
||||
#if defined(BROTLI_ENABLE_LOG) || defined(BROTLI_DEBUG)
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#include <brotli/port.h>
|
||||
|
||||
#if defined(__arm__) || defined(__thumb__) || \
|
||||
defined(_M_ARM) || defined(_M_ARMT) || defined(__ARM64_ARCH_8__)
|
||||
#define BROTLI_TARGET_ARM
|
||||
#if (defined(__ARM_ARCH) && (__ARM_ARCH == 7)) || \
|
||||
(defined(M_ARM) && (M_ARM == 7))
|
||||
#define BROTLI_TARGET_ARMV7
|
||||
#endif /* ARMv7 */
|
||||
#if defined(__aarch64__) || defined(__ARM64_ARCH_8__)
|
||||
#define BROTLI_TARGET_ARMV8
|
||||
#endif /* ARMv8 */
|
||||
#endif /* ARM */
|
||||
|
||||
#if defined(__i386) || defined(_M_IX86)
|
||||
#define BROTLI_TARGET_X86
|
||||
#endif
|
||||
|
||||
#if defined(__x86_64__) || defined(_M_X64)
|
||||
#define BROTLI_TARGET_X64
|
||||
#endif
|
||||
|
||||
#if defined(__PPC64__)
|
||||
#define BROTLI_TARGET_POWERPC64
|
||||
#endif
|
||||
|
||||
#ifdef BROTLI_BUILD_PORTABLE
|
||||
#define BROTLI_ALIGNED_READ (!!1)
|
||||
#elif defined(BROTLI_TARGET_X86) || defined(BROTLI_TARGET_X64) || \
|
||||
defined(BROTLI_TARGET_ARMV7) || defined(BROTLI_TARGET_ARMV8)
|
||||
/* Allow unaligned read only for white-listed CPUs. */
|
||||
#define BROTLI_ALIGNED_READ (!!0)
|
||||
#else
|
||||
#define BROTLI_ALIGNED_READ (!!1)
|
||||
#endif
|
||||
|
||||
/* IS_CONSTANT macros returns true for compile-time constant expressions. */
|
||||
#if BROTLI_MODERN_COMPILER || __has_builtin(__builtin_constant_p)
|
||||
#define IS_CONSTANT(x) (!!__builtin_constant_p(x))
|
||||
#else
|
||||
#define IS_CONSTANT(x) (!!0)
|
||||
#endif
|
||||
|
||||
#ifdef 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)
|
||||
static BROTLI_INLINE void BrotliDump(const char* f, int l, const char* fn) {
|
||||
fprintf(stderr, "%s:%d (%s)\n", f, l, fn);
|
||||
fflush(stderr);
|
||||
}
|
||||
#define BROTLI_DUMP() BrotliDump(__FILE__, __LINE__, __FUNCTION__)
|
||||
#else
|
||||
#define BROTLI_DUMP() (void)(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) || \
|
||||
defined(BROTLI_TARGET_POWERPC64)
|
||||
#define BROTLI_64_BITS 1
|
||||
#else
|
||||
#define BROTLI_64_BITS 0
|
||||
#endif
|
||||
|
||||
#if (BROTLI_64_BITS)
|
||||
#define reg_t uint64_t
|
||||
#else
|
||||
#define reg_t uint32_t
|
||||
#endif
|
||||
|
||||
#if defined(BROTLI_BUILD_BIG_ENDIAN)
|
||||
#define BROTLI_LITTLE_ENDIAN 0
|
||||
#define BROTLI_BIG_ENDIAN 1
|
||||
#elif defined(BROTLI_BUILD_LITTLE_ENDIAN)
|
||||
#define BROTLI_LITTLE_ENDIAN 1
|
||||
#define BROTLI_BIG_ENDIAN 0
|
||||
#elif defined(BROTLI_BUILD_ENDIAN_NEUTRAL)
|
||||
#define BROTLI_LITTLE_ENDIAN 0
|
||||
#define BROTLI_BIG_ENDIAN 0
|
||||
#elif defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
|
||||
#define BROTLI_LITTLE_ENDIAN 1
|
||||
#define BROTLI_BIG_ENDIAN 0
|
||||
#elif defined(_WIN32)
|
||||
/* Win32 can currently always be assumed to be little endian */
|
||||
#define BROTLI_LITTLE_ENDIAN 1
|
||||
#define BROTLI_BIG_ENDIAN 0
|
||||
#else
|
||||
#if (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
|
||||
#define BROTLI_BIG_ENDIAN 1
|
||||
#else
|
||||
#define BROTLI_BIG_ENDIAN 0
|
||||
#endif
|
||||
#define BROTLI_LITTLE_ENDIAN 0
|
||||
#endif
|
||||
|
||||
#define BROTLI_REPEAT(N, X) { \
|
||||
if ((N & 1) != 0) {X;} \
|
||||
if ((N & 2) != 0) {X; X;} \
|
||||
if ((N & 4) != 0) {X; X; X; X;} \
|
||||
}
|
||||
|
||||
#if (BROTLI_MODERN_COMPILER || defined(__llvm__)) && \
|
||||
!defined(BROTLI_BUILD_NO_RBIT)
|
||||
#if defined(BROTLI_TARGET_ARMV7) || defined(BROTLI_TARGET_ARMV8)
|
||||
/* TODO: detect ARMv6T2 and enable this code for it. */
|
||||
static BROTLI_INLINE reg_t BrotliRBit(reg_t input) {
|
||||
reg_t output;
|
||||
__asm__("rbit %0, %1\n" : "=r"(output) : "r"(input));
|
||||
return output;
|
||||
}
|
||||
#define BROTLI_RBIT(x) BrotliRBit(x)
|
||||
#endif /* armv7 */
|
||||
#endif /* gcc || clang */
|
||||
|
||||
#if defined(BROTLI_TARGET_ARM)
|
||||
#define BROTLI_HAS_UBFX (!!1)
|
||||
#else
|
||||
#define BROTLI_HAS_UBFX (!!0)
|
||||
#endif
|
||||
|
||||
#define BROTLI_ALLOC(S, L) S->alloc_func(S->memory_manager_opaque, L)
|
||||
|
||||
#define BROTLI_FREE(S, X) { \
|
||||
S->free_func(S->memory_manager_opaque, X); \
|
||||
X = NULL; \
|
||||
}
|
||||
|
||||
#endif /* BROTLI_DEC_PORT_H_ */
|
||||
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
|
||||
744
c/dec/prefix.h
744
c/dec/prefix.h
@@ -5,32 +5,18 @@
|
||||
*/
|
||||
|
||||
/* Lookup tables to map prefix codes to value ranges. This is used during
|
||||
decoding of the block lengths, literal insertion lengths and copy lengths.
|
||||
*/
|
||||
decoding of the block lengths, literal insertion lengths and copy lengths. */
|
||||
|
||||
#ifndef BROTLI_DEC_PREFIX_H_
|
||||
#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;
|
||||
@@ -41,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 },
|
||||
};
|
||||
117
c/dec/state.c
117
c/dec/state.c
@@ -4,36 +4,37 @@
|
||||
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
|
||||
|
||||
static void* DefaultAllocFunc(void* opaque, size_t size) {
|
||||
BROTLI_UNUSED(opaque);
|
||||
return malloc(size);
|
||||
}
|
||||
#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
|
||||
|
||||
static void DefaultFreeFunc(void* opaque, void* address) {
|
||||
BROTLI_UNUSED(opaque);
|
||||
free(address);
|
||||
}
|
||||
|
||||
void BrotliDecoderStateInit(BrotliDecoderState* s) {
|
||||
BrotliDecoderStateInitWithCustomAllocators(s, 0, 0, 0);
|
||||
}
|
||||
|
||||
void BrotliDecoderStateInitWithCustomAllocators(BrotliDecoderState* s,
|
||||
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 = DefaultAllocFunc;
|
||||
s->free_func = DefaultFreeFunc;
|
||||
s->alloc_func = BrotliDefaultAllocFunc;
|
||||
s->free_func = BrotliDefaultFreeFunc;
|
||||
s->memory_manager_opaque = 0;
|
||||
} else {
|
||||
s->alloc_func = alloc_func;
|
||||
@@ -45,21 +46,18 @@ void BrotliDecoderStateInitWithCustomAllocators(BrotliDecoderState* s,
|
||||
|
||||
BrotliInitBitReader(&s->br);
|
||||
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;
|
||||
|
||||
s->dictionary = BrotliGetDictionary();
|
||||
|
||||
s->buffer_length = 0;
|
||||
s->loop_counter = 0;
|
||||
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;
|
||||
@@ -74,8 +72,6 @@ void BrotliDecoderStateInitWithCustomAllocators(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;
|
||||
@@ -83,9 +79,6 @@ void BrotliDecoderStateInitWithCustomAllocators(BrotliDecoderState* s,
|
||||
s->distance_hgroup.codes = NULL;
|
||||
s->distance_hgroup.htrees = NULL;
|
||||
|
||||
s->custom_dict = NULL;
|
||||
s->custom_dict_size = 0;
|
||||
|
||||
s->is_last_metablock = 0;
|
||||
s->is_uncompressed = 0;
|
||||
s->is_metadata = 0;
|
||||
@@ -102,17 +95,25 @@ void BrotliDecoderStateInitWithCustomAllocators(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->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 << 28;
|
||||
s->block_length[1] = 1U << 28;
|
||||
s->block_length[2] = 1U << 28;
|
||||
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;
|
||||
@@ -129,8 +130,7 @@ void BrotliDecoderStateMetablockBegin(BrotliDecoderState* s) {
|
||||
s->literal_htree = NULL;
|
||||
s->dist_context_map_slice = NULL;
|
||||
s->dist_htree_index = 0;
|
||||
s->context_lookup1 = NULL;
|
||||
s->context_lookup2 = NULL;
|
||||
s->context_lookup = NULL;
|
||||
s->literal_hgroup.codes = NULL;
|
||||
s->literal_hgroup.htrees = NULL;
|
||||
s->insert_copy_hgroup.codes = NULL;
|
||||
@@ -140,33 +140,44 @@ void BrotliDecoderStateMetablockBegin(BrotliDecoderState* s) {
|
||||
}
|
||||
|
||||
void BrotliDecoderStateCleanupAfterMetablock(BrotliDecoderState* s) {
|
||||
BROTLI_FREE(s, s->context_modes);
|
||||
BROTLI_FREE(s, s->context_map);
|
||||
BROTLI_FREE(s, s->dist_context_map);
|
||||
BROTLI_FREE(s, s->literal_hgroup.htrees);
|
||||
BROTLI_FREE(s, s->insert_copy_hgroup.htrees);
|
||||
BROTLI_FREE(s, s->distance_hgroup.htrees);
|
||||
BROTLI_DECODER_FREE(s, s->context_modes);
|
||||
BROTLI_DECODER_FREE(s, s->context_map);
|
||||
BROTLI_DECODER_FREE(s, s->dist_context_map);
|
||||
BROTLI_DECODER_FREE(s, s->literal_hgroup.htrees);
|
||||
BROTLI_DECODER_FREE(s, s->insert_copy_hgroup.htrees);
|
||||
BROTLI_DECODER_FREE(s, s->distance_hgroup.htrees);
|
||||
}
|
||||
|
||||
void BrotliDecoderStateCleanup(BrotliDecoderState* s) {
|
||||
BrotliDecoderStateCleanupAfterMetablock(s);
|
||||
|
||||
BROTLI_FREE(s, s->ringbuffer);
|
||||
BROTLI_FREE(s, s->block_type_trees);
|
||||
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 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_ALLOC(s, code_size + htree_size);
|
||||
group->alphabet_size = (uint16_t)alphabet_size;
|
||||
HuffmanCode** p = (HuffmanCode**)BROTLI_DECODER_ALLOC(s,
|
||||
code_size + htree_size);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
301
c/dec/state.h
301
c/dec/state.h
@@ -10,18 +10,109 @@
|
||||
#define BROTLI_DEC_STATE_H_
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include "../common/dictionary.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./bit_reader.h"
|
||||
#include "./huffman.h"
|
||||
#include "./port.h"
|
||||
#include "../common/platform.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,
|
||||
BROTLI_STATE_INITIALIZE,
|
||||
BROTLI_STATE_METABLOCK_BEGIN,
|
||||
BROTLI_STATE_METABLOCK_HEADER,
|
||||
BROTLI_STATE_METABLOCK_HEADER_2,
|
||||
@@ -36,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,
|
||||
@@ -43,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;
|
||||
|
||||
@@ -95,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;
|
||||
|
||||
@@ -107,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;
|
||||
@@ -122,127 +275,119 @@ 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;
|
||||
const uint8_t* context_lookup1;
|
||||
const uint8_t* context_lookup2;
|
||||
const uint8_t* context_lookup;
|
||||
uint8_t* context_map_slice;
|
||||
uint8_t* dist_context_map_slice;
|
||||
|
||||
/* This ring buffer holds a few past copy distances that will be used by */
|
||||
/* some special distance codes. */
|
||||
/* This ring buffer holds a few past copy distances that will be used by
|
||||
some special distance codes. */
|
||||
HuffmanTreeGroup literal_hgroup;
|
||||
HuffmanTreeGroup insert_copy_hgroup;
|
||||
HuffmanTreeGroup distance_hgroup;
|
||||
HuffmanCode* block_type_trees;
|
||||
HuffmanCode* block_len_trees;
|
||||
/* This is true if the literal context map histogram type always matches the
|
||||
block type. It is then not needed to keep the context (faster decoding). */
|
||||
block type. It is then not needed to keep the context (faster decoding). */
|
||||
int trivial_literal_context;
|
||||
/* Distance context is actual after command is decoded and before distance
|
||||
is computed. After distance computation it is used as a temporary variable. */
|
||||
/* 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;
|
||||
|
||||
/* 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 InverseMoveToFrontTransform. */
|
||||
brotli_reg_t mtf_upper_bound;
|
||||
uint32_t mtf[64 + 1];
|
||||
|
||||
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 */
|
||||
uint8_t dist_htree_index;
|
||||
/* TODO(eustas): +3 bytes padding */
|
||||
|
||||
/* For ReadHuffmanCode */
|
||||
uint32_t symbol;
|
||||
uint32_t repeat;
|
||||
uint32_t space;
|
||||
/* Less used attributes are at the end of this struct. */
|
||||
|
||||
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];
|
||||
brotli_decoder_metadata_start_func metadata_start_func;
|
||||
brotli_decoder_metadata_chunk_func metadata_chunk_func;
|
||||
void* metadata_callback_opaque;
|
||||
|
||||
/* For HuffmanTreeGroupDecode */
|
||||
int htree_index;
|
||||
HuffmanCode* next;
|
||||
/* For reporting. */
|
||||
uint64_t used_input; /* how many bytes of input are consumed */
|
||||
|
||||
/* 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;
|
||||
uint32_t mtf[64 + 1];
|
||||
|
||||
/* For custom dictionaries */
|
||||
const uint8_t* custom_dict;
|
||||
int custom_dict_size;
|
||||
|
||||
/* less used attributes are in the end of this struct */
|
||||
/* States inside function calls */
|
||||
/* 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;
|
||||
|
||||
BrotliSharedDictionary* dictionary;
|
||||
BrotliDecoderCompoundDictionary* compound_dictionary;
|
||||
|
||||
uint32_t trivial_literal_contexts[8]; /* 256 bits */
|
||||
|
||||
union {
|
||||
BrotliMetablockHeaderArena header;
|
||||
BrotliMetablockBodyArena body;
|
||||
} arena;
|
||||
};
|
||||
|
||||
typedef struct BrotliDecoderStateStruct BrotliDecoderStateInternal;
|
||||
#define BrotliDecoderState BrotliDecoderStateInternal
|
||||
|
||||
BROTLI_INTERNAL void BrotliDecoderStateInit(BrotliDecoderState* s);
|
||||
BROTLI_INTERNAL void BrotliDecoderStateInitWithCustomAllocators(
|
||||
BrotliDecoderState* s, brotli_alloc_func alloc_func,
|
||||
brotli_free_func free_func, void* opaque);
|
||||
BROTLI_INTERNAL BROTLI_BOOL BrotliDecoderStateInit(BrotliDecoderState* s,
|
||||
brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque);
|
||||
BROTLI_INTERNAL void BrotliDecoderStateCleanup(BrotliDecoderState* s);
|
||||
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 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)
|
||||
|
||||
#define BROTLI_DECODER_FREE(S, X) { \
|
||||
S->free_func(S->memory_manager_opaque, X); \
|
||||
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" */
|
||||
|
||||
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_
|
||||
@@ -1,300 +0,0 @@
|
||||
/* Copyright 2013 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/* Transformations on dictionary words. */
|
||||
|
||||
#ifndef BROTLI_DEC_TRANSFORM_H_
|
||||
#define BROTLI_DEC_TRANSFORM_H_
|
||||
|
||||
#include <brotli/types.h>
|
||||
#include "./port.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum WordTransformType {
|
||||
kIdentity = 0,
|
||||
kOmitLast1 = 1,
|
||||
kOmitLast2 = 2,
|
||||
kOmitLast3 = 3,
|
||||
kOmitLast4 = 4,
|
||||
kOmitLast5 = 5,
|
||||
kOmitLast6 = 6,
|
||||
kOmitLast7 = 7,
|
||||
kOmitLast8 = 8,
|
||||
kOmitLast9 = 9,
|
||||
kUppercaseFirst = 10,
|
||||
kUppercaseAll = 11,
|
||||
kOmitFirst1 = 12,
|
||||
kOmitFirst2 = 13,
|
||||
kOmitFirst3 = 14,
|
||||
kOmitFirst4 = 15,
|
||||
kOmitFirst5 = 16,
|
||||
kOmitFirst6 = 17,
|
||||
kOmitFirst7 = 18,
|
||||
kOmitFirst8 = 19,
|
||||
kOmitFirst9 = 20
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
const uint8_t prefix_id;
|
||||
const uint8_t transform;
|
||||
const uint8_t suffix_id;
|
||||
} Transform;
|
||||
|
||||
static const char kPrefixSuffix[208] =
|
||||
"\0 \0, \0 of the \0 of \0s \0.\0 and \0 in \0\"\0 to \0\">\0\n\0. \0]\0"
|
||||
" for \0 a \0 that \0\'\0 with \0 from \0 by \0(\0. The \0 on \0 as \0"
|
||||
" is \0ing \0\n\t\0:\0ed \0=\"\0 at \0ly \0,\0=\'\0.com/\0. This \0"
|
||||
" not \0er \0al \0ful \0ive \0less \0est \0ize \0\xc2\xa0\0ous ";
|
||||
|
||||
enum {
|
||||
/* EMPTY = ""
|
||||
SP = " "
|
||||
DQUOT = "\""
|
||||
SQUOT = "'"
|
||||
CLOSEBR = "]"
|
||||
OPEN = "("
|
||||
SLASH = "/"
|
||||
NBSP = non-breaking space "\0xc2\xa0"
|
||||
*/
|
||||
kPFix_EMPTY = 0,
|
||||
kPFix_SP = 1,
|
||||
kPFix_COMMASP = 3,
|
||||
kPFix_SPofSPtheSP = 6,
|
||||
kPFix_SPtheSP = 9,
|
||||
kPFix_eSP = 12,
|
||||
kPFix_SPofSP = 15,
|
||||
kPFix_sSP = 20,
|
||||
kPFix_DOT = 23,
|
||||
kPFix_SPandSP = 25,
|
||||
kPFix_SPinSP = 31,
|
||||
kPFix_DQUOT = 36,
|
||||
kPFix_SPtoSP = 38,
|
||||
kPFix_DQUOTGT = 43,
|
||||
kPFix_NEWLINE = 46,
|
||||
kPFix_DOTSP = 48,
|
||||
kPFix_CLOSEBR = 51,
|
||||
kPFix_SPforSP = 53,
|
||||
kPFix_SPaSP = 59,
|
||||
kPFix_SPthatSP = 63,
|
||||
kPFix_SQUOT = 70,
|
||||
kPFix_SPwithSP = 72,
|
||||
kPFix_SPfromSP = 79,
|
||||
kPFix_SPbySP = 86,
|
||||
kPFix_OPEN = 91,
|
||||
kPFix_DOTSPTheSP = 93,
|
||||
kPFix_SPonSP = 100,
|
||||
kPFix_SPasSP = 105,
|
||||
kPFix_SPisSP = 110,
|
||||
kPFix_ingSP = 115,
|
||||
kPFix_NEWLINETAB = 120,
|
||||
kPFix_COLON = 123,
|
||||
kPFix_edSP = 125,
|
||||
kPFix_EQDQUOT = 129,
|
||||
kPFix_SPatSP = 132,
|
||||
kPFix_lySP = 137,
|
||||
kPFix_COMMA = 141,
|
||||
kPFix_EQSQUOT = 143,
|
||||
kPFix_DOTcomSLASH = 146,
|
||||
kPFix_DOTSPThisSP = 152,
|
||||
kPFix_SPnotSP = 160,
|
||||
kPFix_erSP = 166,
|
||||
kPFix_alSP = 170,
|
||||
kPFix_fulSP = 174,
|
||||
kPFix_iveSP = 179,
|
||||
kPFix_lessSP = 184,
|
||||
kPFix_estSP = 190,
|
||||
kPFix_izeSP = 195,
|
||||
kPFix_NBSP = 200,
|
||||
kPFix_ousSP = 203
|
||||
};
|
||||
|
||||
static const Transform kTransforms[] = {
|
||||
{ kPFix_EMPTY, kIdentity, kPFix_EMPTY },
|
||||
{ kPFix_EMPTY, kIdentity, kPFix_SP },
|
||||
{ kPFix_SP, kIdentity, kPFix_SP },
|
||||
{ kPFix_EMPTY, kOmitFirst1, kPFix_EMPTY },
|
||||
{ kPFix_EMPTY, kUppercaseFirst, kPFix_SP },
|
||||
{ kPFix_EMPTY, kIdentity, kPFix_SPtheSP },
|
||||
{ kPFix_SP, kIdentity, kPFix_EMPTY },
|
||||
{ kPFix_sSP, kIdentity, kPFix_SP },
|
||||
{ kPFix_EMPTY, kIdentity, kPFix_SPofSP },
|
||||
{ kPFix_EMPTY, kUppercaseFirst, kPFix_EMPTY },
|
||||
{ kPFix_EMPTY, kIdentity, kPFix_SPandSP },
|
||||
{ kPFix_EMPTY, kOmitFirst2, kPFix_EMPTY },
|
||||
{ kPFix_EMPTY, kOmitLast1, kPFix_EMPTY },
|
||||
{ kPFix_COMMASP, kIdentity, kPFix_SP },
|
||||
{ kPFix_EMPTY, kIdentity, kPFix_COMMASP },
|
||||
{ kPFix_SP, kUppercaseFirst, kPFix_SP },
|
||||
{ kPFix_EMPTY, kIdentity, kPFix_SPinSP },
|
||||
{ kPFix_EMPTY, kIdentity, kPFix_SPtoSP },
|
||||
{ kPFix_eSP, kIdentity, kPFix_SP },
|
||||
{ kPFix_EMPTY, kIdentity, kPFix_DQUOT },
|
||||
{ kPFix_EMPTY, kIdentity, kPFix_DOT },
|
||||
{ kPFix_EMPTY, kIdentity, kPFix_DQUOTGT },
|
||||
{ kPFix_EMPTY, kIdentity, kPFix_NEWLINE },
|
||||
{ kPFix_EMPTY, kOmitLast3, kPFix_EMPTY },
|
||||
{ kPFix_EMPTY, kIdentity, kPFix_CLOSEBR },
|
||||
{ kPFix_EMPTY, kIdentity, kPFix_SPforSP },
|
||||
{ kPFix_EMPTY, kOmitFirst3, kPFix_EMPTY },
|
||||
{ kPFix_EMPTY, kOmitLast2, kPFix_EMPTY },
|
||||
{ kPFix_EMPTY, kIdentity, kPFix_SPaSP },
|
||||
{ kPFix_EMPTY, kIdentity, kPFix_SPthatSP },
|
||||
{ kPFix_SP, kUppercaseFirst, kPFix_EMPTY },
|
||||
{ kPFix_EMPTY, kIdentity, kPFix_DOTSP },
|
||||
{ kPFix_DOT, kIdentity, kPFix_EMPTY },
|
||||
{ kPFix_SP, kIdentity, kPFix_COMMASP },
|
||||
{ kPFix_EMPTY, kOmitFirst4, kPFix_EMPTY },
|
||||
{ kPFix_EMPTY, kIdentity, kPFix_SPwithSP },
|
||||
{ kPFix_EMPTY, kIdentity, kPFix_SQUOT },
|
||||
{ kPFix_EMPTY, kIdentity, kPFix_SPfromSP },
|
||||
{ kPFix_EMPTY, kIdentity, kPFix_SPbySP },
|
||||
{ kPFix_EMPTY, kOmitFirst5, kPFix_EMPTY },
|
||||
{ kPFix_EMPTY, kOmitFirst6, kPFix_EMPTY },
|
||||
{ kPFix_SPtheSP, kIdentity, kPFix_EMPTY },
|
||||
{ kPFix_EMPTY, kOmitLast4, kPFix_EMPTY },
|
||||
{ kPFix_EMPTY, kIdentity, kPFix_DOTSPTheSP },
|
||||
{ kPFix_EMPTY, kUppercaseAll, kPFix_EMPTY },
|
||||
{ kPFix_EMPTY, kIdentity, kPFix_SPonSP },
|
||||
{ kPFix_EMPTY, kIdentity, kPFix_SPasSP },
|
||||
{ kPFix_EMPTY, kIdentity, kPFix_SPisSP },
|
||||
{ kPFix_EMPTY, kOmitLast7, kPFix_EMPTY },
|
||||
{ kPFix_EMPTY, kOmitLast1, kPFix_ingSP },
|
||||
{ kPFix_EMPTY, kIdentity, kPFix_NEWLINETAB },
|
||||
{ kPFix_EMPTY, kIdentity, kPFix_COLON },
|
||||
{ kPFix_SP, kIdentity, kPFix_DOTSP },
|
||||
{ kPFix_EMPTY, kIdentity, kPFix_edSP },
|
||||
{ kPFix_EMPTY, kOmitFirst9, kPFix_EMPTY },
|
||||
{ kPFix_EMPTY, kOmitFirst7, kPFix_EMPTY },
|
||||
{ kPFix_EMPTY, kOmitLast6, kPFix_EMPTY },
|
||||
{ kPFix_EMPTY, kIdentity, kPFix_OPEN },
|
||||
{ kPFix_EMPTY, kUppercaseFirst, kPFix_COMMASP },
|
||||
{ kPFix_EMPTY, kOmitLast8, kPFix_EMPTY },
|
||||
{ kPFix_EMPTY, kIdentity, kPFix_SPatSP },
|
||||
{ kPFix_EMPTY, kIdentity, kPFix_lySP },
|
||||
{ kPFix_SPtheSP, kIdentity, kPFix_SPofSP },
|
||||
{ kPFix_EMPTY, kOmitLast5, kPFix_EMPTY },
|
||||
{ kPFix_EMPTY, kOmitLast9, kPFix_EMPTY },
|
||||
{ kPFix_SP, kUppercaseFirst, kPFix_COMMASP },
|
||||
{ kPFix_EMPTY, kUppercaseFirst, kPFix_DQUOT },
|
||||
{ kPFix_DOT, kIdentity, kPFix_OPEN },
|
||||
{ kPFix_EMPTY, kUppercaseAll, kPFix_SP },
|
||||
{ kPFix_EMPTY, kUppercaseFirst, kPFix_DQUOTGT },
|
||||
{ kPFix_EMPTY, kIdentity, kPFix_EQDQUOT },
|
||||
{ kPFix_SP, kIdentity, kPFix_DOT },
|
||||
{ kPFix_DOTcomSLASH, kIdentity, kPFix_EMPTY },
|
||||
{ kPFix_SPtheSP, kIdentity, kPFix_SPofSPtheSP },
|
||||
{ kPFix_EMPTY, kUppercaseFirst, kPFix_SQUOT },
|
||||
{ kPFix_EMPTY, kIdentity, kPFix_DOTSPThisSP },
|
||||
{ kPFix_EMPTY, kIdentity, kPFix_COMMA },
|
||||
{ kPFix_DOT, kIdentity, kPFix_SP },
|
||||
{ kPFix_EMPTY, kUppercaseFirst, kPFix_OPEN },
|
||||
{ kPFix_EMPTY, kUppercaseFirst, kPFix_DOT },
|
||||
{ kPFix_EMPTY, kIdentity, kPFix_SPnotSP },
|
||||
{ kPFix_SP, kIdentity, kPFix_EQDQUOT },
|
||||
{ kPFix_EMPTY, kIdentity, kPFix_erSP },
|
||||
{ kPFix_SP, kUppercaseAll, kPFix_SP },
|
||||
{ kPFix_EMPTY, kIdentity, kPFix_alSP },
|
||||
{ kPFix_SP, kUppercaseAll, kPFix_EMPTY },
|
||||
{ kPFix_EMPTY, kIdentity, kPFix_EQSQUOT },
|
||||
{ kPFix_EMPTY, kUppercaseAll, kPFix_DQUOT },
|
||||
{ kPFix_EMPTY, kUppercaseFirst, kPFix_DOTSP },
|
||||
{ kPFix_SP, kIdentity, kPFix_OPEN },
|
||||
{ kPFix_EMPTY, kIdentity, kPFix_fulSP },
|
||||
{ kPFix_SP, kUppercaseFirst, kPFix_DOTSP },
|
||||
{ kPFix_EMPTY, kIdentity, kPFix_iveSP },
|
||||
{ kPFix_EMPTY, kIdentity, kPFix_lessSP },
|
||||
{ kPFix_EMPTY, kUppercaseAll, kPFix_SQUOT },
|
||||
{ kPFix_EMPTY, kIdentity, kPFix_estSP },
|
||||
{ kPFix_SP, kUppercaseFirst, kPFix_DOT },
|
||||
{ kPFix_EMPTY, kUppercaseAll, kPFix_DQUOTGT },
|
||||
{ kPFix_SP, kIdentity, kPFix_EQSQUOT },
|
||||
{ kPFix_EMPTY, kUppercaseFirst, kPFix_COMMA },
|
||||
{ kPFix_EMPTY, kIdentity, kPFix_izeSP },
|
||||
{ kPFix_EMPTY, kUppercaseAll, kPFix_DOT },
|
||||
{ kPFix_NBSP, kIdentity, kPFix_EMPTY },
|
||||
{ kPFix_SP, kIdentity, kPFix_COMMA },
|
||||
{ kPFix_EMPTY, kUppercaseFirst, kPFix_EQDQUOT },
|
||||
{ kPFix_EMPTY, kUppercaseAll, kPFix_EQDQUOT },
|
||||
{ kPFix_EMPTY, kIdentity, kPFix_ousSP },
|
||||
{ kPFix_EMPTY, kUppercaseAll, kPFix_COMMASP },
|
||||
{ kPFix_EMPTY, kUppercaseFirst, kPFix_EQSQUOT },
|
||||
{ kPFix_SP, kUppercaseFirst, kPFix_COMMA },
|
||||
{ kPFix_SP, kUppercaseAll, kPFix_EQDQUOT },
|
||||
{ kPFix_SP, kUppercaseAll, kPFix_COMMASP },
|
||||
{ kPFix_EMPTY, kUppercaseAll, kPFix_COMMA },
|
||||
{ kPFix_EMPTY, kUppercaseAll, kPFix_OPEN },
|
||||
{ kPFix_EMPTY, kUppercaseAll, kPFix_DOTSP },
|
||||
{ kPFix_SP, kUppercaseAll, kPFix_DOT },
|
||||
{ kPFix_EMPTY, kUppercaseAll, kPFix_EQSQUOT },
|
||||
{ kPFix_SP, kUppercaseAll, kPFix_DOTSP },
|
||||
{ kPFix_SP, kUppercaseFirst, kPFix_EQDQUOT },
|
||||
{ kPFix_SP, kUppercaseAll, kPFix_EQSQUOT },
|
||||
{ kPFix_SP, kUppercaseFirst, kPFix_EQSQUOT },
|
||||
};
|
||||
|
||||
static const int kNumTransforms = sizeof(kTransforms) / sizeof(kTransforms[0]);
|
||||
|
||||
static int ToUpperCase(uint8_t* p) {
|
||||
if (p[0] < 0xc0) {
|
||||
if (p[0] >= 'a' && p[0] <= 'z') {
|
||||
p[0] ^= 32;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
/* An overly simplified uppercasing model for UTF-8. */
|
||||
if (p[0] < 0xe0) {
|
||||
p[1] ^= 32;
|
||||
return 2;
|
||||
}
|
||||
/* An arbitrary transform for three byte characters. */
|
||||
p[2] ^= 5;
|
||||
return 3;
|
||||
}
|
||||
|
||||
static BROTLI_NOINLINE int TransformDictionaryWord(
|
||||
uint8_t* dst, const uint8_t* word, int len, int transform) {
|
||||
int idx = 0;
|
||||
{
|
||||
const char* prefix = &kPrefixSuffix[kTransforms[transform].prefix_id];
|
||||
while (*prefix) { dst[idx++] = (uint8_t)*prefix++; }
|
||||
}
|
||||
{
|
||||
const int t = kTransforms[transform].transform;
|
||||
int i = 0;
|
||||
int skip = t - (kOmitFirst1 - 1);
|
||||
if (skip > 0) {
|
||||
word += skip;
|
||||
len -= skip;
|
||||
} else if (t <= kOmitLast9) {
|
||||
len -= t;
|
||||
}
|
||||
while (i < len) { dst[idx++] = word[i++]; }
|
||||
if (t == kUppercaseFirst) {
|
||||
ToUpperCase(&dst[idx - len]);
|
||||
} else if (t == kUppercaseAll) {
|
||||
uint8_t* uppercase = &dst[idx - len];
|
||||
while (len > 0) {
|
||||
int step = ToUpperCase(uppercase);
|
||||
uppercase += step;
|
||||
len -= step;
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
const char* suffix = &kPrefixSuffix[kTransforms[transform].suffix_id];
|
||||
while (*suffix) { dst[idx++] = (uint8_t)*suffix++; }
|
||||
return idx;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* BROTLI_DEC_TRANSFORM_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 <brotli/types.h>
|
||||
#include "./command.h"
|
||||
#include "./dictionary_hash.h"
|
||||
#include "./memory.h"
|
||||
#include "./port.h"
|
||||
#include "./quality.h"
|
||||
#include "../common/context.h"
|
||||
#include "../common/platform.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" {
|
||||
@@ -48,79 +49,179 @@ static BROTLI_INLINE size_t ComputeDistanceCode(size_t distance,
|
||||
#define EXPAND_CAT(a, b) CAT(a, b)
|
||||
#define CAT(a, b) a ## b
|
||||
#define FN(X) EXPAND_CAT(X, HASHER())
|
||||
#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"
|
||||
#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
|
||||
#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
|
||||
#undef FN
|
||||
#undef CAT
|
||||
#undef EXPAND_CAT
|
||||
|
||||
void BrotliCreateBackwardReferences(const BrotliDictionary* dictionary,
|
||||
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) {
|
||||
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: \
|
||||
CreateBackwardReferencesH ## N(dictionary, \
|
||||
kStaticDictionaryHash, 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); \
|
||||
break;
|
||||
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 <brotli/types.h>
|
||||
#include "./command.h"
|
||||
#include "./hash.h"
|
||||
#include "./port.h"
|
||||
#include "./quality.h"
|
||||
#include "../common/context.h"
|
||||
#include "../common/platform.h"
|
||||
#include "command.h"
|
||||
#include "hash.h"
|
||||
#include "params.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
@@ -25,12 +23,11 @@ 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(
|
||||
const BrotliDictionary* dictionary, 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);
|
||||
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)
|
||||
} /* extern "C" */
|
||||
|
||||
485
c/enc/backward_references_hq.c
Executable file → Normal file
485
c/enc/backward_references_hq.c
Executable file → Normal file
@@ -6,31 +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 <brotli/types.h>
|
||||
#include "./command.h"
|
||||
#include "./fast_log.h"
|
||||
#include "./find_match_length.h"
|
||||
#include "./literal_cost.h"
|
||||
#include "./memory.h"
|
||||
#include "./port.h"
|
||||
#include "./prefix.h"
|
||||
#include "./quality.h"
|
||||
#include "../common/context.h"
|
||||
#include "../common/platform.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
|
||||
};
|
||||
|
||||
@@ -39,69 +44,97 @@ void BrotliInitZopfliNodes(ZopfliNode* array, size_t length) {
|
||||
size_t i;
|
||||
stub.length = 1;
|
||||
stub.distance = 0;
|
||||
stub.insert_length = 0;
|
||||
stub.dcode_insert_length = 0;
|
||||
stub.u.cost = kInfinity;
|
||||
for (i = 0; i < length; ++i) array[i] = stub;
|
||||
}
|
||||
|
||||
static BROTLI_INLINE uint32_t ZopfliNodeCopyLength(const ZopfliNode* self) {
|
||||
return self->length & 0xffffff;
|
||||
return self->length & 0x1FFFFFF;
|
||||
}
|
||||
|
||||
static BROTLI_INLINE uint32_t ZopfliNodeLengthCode(const ZopfliNode* self) {
|
||||
const uint32_t modifier = self->length >> 24;
|
||||
const uint32_t modifier = self->length >> 25;
|
||||
return ZopfliNodeCopyLength(self) + 9u - modifier;
|
||||
}
|
||||
|
||||
static BROTLI_INLINE uint32_t ZopfliNodeCopyDistance(const ZopfliNode* self) {
|
||||
return self->distance & 0x1ffffff;
|
||||
return self->distance;
|
||||
}
|
||||
|
||||
static BROTLI_INLINE uint32_t ZopfliNodeDistanceCode(const ZopfliNode* self) {
|
||||
const uint32_t short_code = self->distance >> 25;
|
||||
const uint32_t short_code = self->dcode_insert_length >> 27;
|
||||
return short_code == 0 ?
|
||||
ZopfliNodeCopyDistance(self) + BROTLI_NUM_DISTANCE_SHORT_CODES - 1 :
|
||||
short_code - 1;
|
||||
}
|
||||
|
||||
static BROTLI_INLINE uint32_t ZopfliNodeCommandLength(const ZopfliNode* self) {
|
||||
return ZopfliNodeCopyLength(self) + self->insert_length;
|
||||
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. */
|
||||
float cost_cmd_[BROTLI_NUM_COMMAND_SYMBOLS];
|
||||
float cost_dist_[BROTLI_NUM_DISTANCE_SYMBOLS];
|
||||
float* cost_dist_;
|
||||
uint32_t distance_histogram_size;
|
||||
/* Cumulative costs of literals per position in the stream. */
|
||||
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, size_t num_bytes) {
|
||||
MemoryManager* m, ZopfliCostModel* self, const BrotliDistanceParams* dist,
|
||||
size_t num_bytes) {
|
||||
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_limit);
|
||||
self->distance_histogram_size = dist->alphabet_size_limit;
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
}
|
||||
|
||||
static void CleanupZopfliCostModel(MemoryManager* m, ZopfliCostModel* self) {
|
||||
BROTLI_FREE(m, self->literal_costs_);
|
||||
BROTLI_FREE(m, self->cost_dist_);
|
||||
}
|
||||
|
||||
static void SetCost(const uint32_t* histogram, size_t histogram_size,
|
||||
float* cost) {
|
||||
BROTLI_BOOL literal_histogram, float* cost) {
|
||||
size_t sum = 0;
|
||||
size_t missing_symbol_sum;
|
||||
float log2sum;
|
||||
float missing_symbol_cost;
|
||||
size_t i;
|
||||
for (i = 0; i < histogram_size; i++) {
|
||||
sum += histogram[i];
|
||||
}
|
||||
log2sum = (float)FastLog2(sum);
|
||||
missing_symbol_sum = sum;
|
||||
if (!literal_histogram) {
|
||||
for (i = 0; i < histogram_size; i++) {
|
||||
if (histogram[i] == 0) missing_symbol_sum++;
|
||||
}
|
||||
}
|
||||
missing_symbol_cost = (float)FastLog2(missing_symbol_sum) + 2;
|
||||
for (i = 0; i < histogram_size; i++) {
|
||||
if (histogram[i] == 0) {
|
||||
cost[i] = log2sum + 2;
|
||||
cost[i] = missing_symbol_cost;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -120,39 +153,39 @@ 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_NUM_DISTANCE_SYMBOLS];
|
||||
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_;
|
||||
size_t copylength = CommandCopyLen(&commands[i]);
|
||||
size_t distcode = commands[i].dist_prefix_;
|
||||
size_t distcode = commands[i].dist_prefix_ & 0x3FF;
|
||||
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, cost_literal);
|
||||
SetCost(histogram_cmd, BROTLI_NUM_COMMAND_SYMBOLS, cost_cmd);
|
||||
SetCost(histogram_dist, BROTLI_NUM_DISTANCE_SYMBOLS, self->cost_dist_);
|
||||
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(arena->histogram_dist, self->distance_histogram_size, BROTLI_FALSE,
|
||||
self->cost_dist_);
|
||||
|
||||
for (i = 0; i < BROTLI_NUM_COMMAND_SYMBOLS; ++i) {
|
||||
min_cost_cmd = BROTLI_MIN(float, min_cost_cmd, cost_cmd[i]);
|
||||
@@ -161,11 +194,14 @@ static void ZopfliCostModelSetFromCommands(ZopfliCostModel* self,
|
||||
|
||||
{
|
||||
float* literal_costs = self->literal_costs_;
|
||||
float literal_carry = 0.0;
|
||||
size_t num_bytes = self->num_bytes_;
|
||||
literal_costs[0] = 0.0;
|
||||
for (i = 0; i < num_bytes; ++i) {
|
||||
literal_costs[i + 1] = literal_costs[i] +
|
||||
cost_literal[ringbuffer[(position + i) & ringbuffer_mask]];
|
||||
literal_carry +=
|
||||
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];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -175,20 +211,24 @@ static void ZopfliCostModelSetFromLiteralCosts(ZopfliCostModel* self,
|
||||
const uint8_t* ringbuffer,
|
||||
size_t ringbuffer_mask) {
|
||||
float* literal_costs = self->literal_costs_;
|
||||
float literal_carry = 0.0;
|
||||
float* cost_dist = self->cost_dist_;
|
||||
float* cost_cmd = self->cost_cmd_;
|
||||
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_costs[i + 1] += literal_costs[i];
|
||||
literal_carry += literal_costs[i + 1];
|
||||
literal_costs[i + 1] = literal_costs[i] + literal_carry;
|
||||
literal_carry -= literal_costs[i + 1] - literal_costs[i];
|
||||
}
|
||||
for (i = 0; i < BROTLI_NUM_COMMAND_SYMBOLS; ++i) {
|
||||
cost_cmd[i] = (float)FastLog2(11 + (uint32_t)i);
|
||||
}
|
||||
for (i = 0; i < BROTLI_NUM_DISTANCE_SYMBOLS; ++i) {
|
||||
for (i = 0; i < self->distance_histogram_size; ++i) {
|
||||
cost_dist[i] = (float)FastLog2(20 + (uint32_t)i);
|
||||
}
|
||||
self->min_cost_cmd_ = (float)FastLog2(11);
|
||||
@@ -221,9 +261,10 @@ static BROTLI_INLINE void UpdateZopfliNode(ZopfliNode* nodes, size_t pos,
|
||||
size_t start_pos, size_t len, size_t len_code, size_t dist,
|
||||
size_t short_code, float cost) {
|
||||
ZopfliNode* next = &nodes[pos + len];
|
||||
next->length = (uint32_t)(len | ((len + 9u - len_code) << 24));
|
||||
next->distance = (uint32_t)(dist | (short_code << 25));
|
||||
next->insert_length = (uint32_t)(pos - start_pos);
|
||||
next->length = (uint32_t)(len | ((len + 9u - len_code) << 25));
|
||||
next->distance = (uint32_t)dist;
|
||||
next->dcode_insert_length = (uint32_t)(
|
||||
(short_code << 27) | (pos - start_pos));
|
||||
next->u.cost = cost;
|
||||
}
|
||||
|
||||
@@ -299,24 +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].insert_length;
|
||||
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 &&
|
||||
dist <= max_backward &&
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -334,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].insert_length;
|
||||
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++;
|
||||
@@ -350,12 +392,12 @@ static void ComputeDistanceCache(const size_t pos,
|
||||
is eligible. */
|
||||
static void EvaluateNode(
|
||||
const size_t block_start, const size_t pos, const size_t max_backward_limit,
|
||||
const int* starting_dist_cache, const ZopfliCostModel* model,
|
||||
StartPosQueue* queue, ZopfliNode* nodes) {
|
||||
const size_t gap, const int* starting_dist_cache,
|
||||
const ZopfliCostModel* model, StartPosQueue* queue, ZopfliNode* nodes) {
|
||||
/* Save cost, because ComputeDistanceCache invalidates it. */
|
||||
float node_cost = nodes[pos].u.cost;
|
||||
nodes[pos].u.shortcut = ComputeDistanceShortcut(
|
||||
block_start, pos, max_backward_limit, nodes);
|
||||
block_start, pos, max_backward_limit, gap, nodes);
|
||||
if (node_cost <= ZopfliCostModelGetLiteralCosts(model, 0, pos)) {
|
||||
PosData posdata;
|
||||
posdata.pos = pos;
|
||||
@@ -376,18 +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;
|
||||
const CompoundDictionary* addon = ¶ms->dictionary.compound;
|
||||
size_t gap = addon->total_size;
|
||||
|
||||
EvaluateNode(block_start, pos, max_backward_limit, starting_dist_cache, model,
|
||||
queue, nodes);
|
||||
BROTLI_DCHECK(cur_ix_masked + max_len <= ringbuffer_mask + 1);
|
||||
|
||||
EvaluateNode(block_start + stream_offset, pos, max_backward_limit, gap,
|
||||
starting_dist_cache, model, queue, nodes);
|
||||
|
||||
{
|
||||
const PosData* posdata = StartPosQueueAt(queue, 0);
|
||||
@@ -415,25 +464,53 @@ static size_t UpdateNodes(
|
||||
const size_t backward =
|
||||
(size_t)(posdata->distance_cache[idx] + kDistanceCacheOffset[j]);
|
||||
size_t prev_ix = cur_ix - backward;
|
||||
if (prev_ix >= cur_ix) {
|
||||
size_t len = 0;
|
||||
uint8_t continuation = ringbuffer[cur_ix_masked + best_len];
|
||||
if (cur_ix_masked + best_len > ringbuffer_mask) {
|
||||
break;
|
||||
}
|
||||
if (BROTLI_PREDICT_FALSE(backward > dictionary_start + gap)) {
|
||||
/* Word dictionary -> ignore. */
|
||||
continue;
|
||||
}
|
||||
if (BROTLI_PREDICT_FALSE(backward > max_distance)) {
|
||||
continue;
|
||||
}
|
||||
prev_ix &= ringbuffer_mask;
|
||||
if (backward <= max_distance) {
|
||||
/* Regular backward reference. */
|
||||
if (prev_ix >= cur_ix) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cur_ix_masked + best_len > ringbuffer_mask ||
|
||||
prev_ix + best_len > ringbuffer_mask ||
|
||||
ringbuffer[cur_ix_masked + best_len] !=
|
||||
ringbuffer[prev_ix + best_len]) {
|
||||
prev_ix &= ringbuffer_mask;
|
||||
if (prev_ix + best_len > ringbuffer_mask ||
|
||||
continuation != ringbuffer[prev_ix + best_len]) {
|
||||
continue;
|
||||
}
|
||||
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;
|
||||
}
|
||||
{
|
||||
const size_t len =
|
||||
FindMatchLengthWithLimit(&ringbuffer[prev_ix],
|
||||
&ringbuffer[cur_ix_masked],
|
||||
max_len);
|
||||
const float dist_cost = base_cost +
|
||||
ZopfliCostModelGetDistanceCost(model, j);
|
||||
size_t l;
|
||||
@@ -464,7 +541,8 @@ static size_t UpdateNodes(
|
||||
for (j = 0; j < num_matches; ++j) {
|
||||
BackwardMatch match = matches[j];
|
||||
size_t dist = match.distance;
|
||||
BROTLI_BOOL is_dictionary_match = TO_BROTLI_BOOL(dist > max_distance);
|
||||
BROTLI_BOOL is_dictionary_match =
|
||||
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;
|
||||
@@ -473,10 +551,12 @@ static size_t UpdateNodes(
|
||||
uint32_t distnumextra;
|
||||
float dist_cost;
|
||||
size_t max_match_len;
|
||||
PrefixEncodeCopyDistance(dist_code, 0, 0, &dist_symbol, &distextra);
|
||||
distnumextra = distextra >> 24;
|
||||
PrefixEncodeCopyDistance(
|
||||
dist_code, params->dist.num_direct_distance_codes,
|
||||
params->dist.distance_postfix_bits, &dist_symbol, &distextra);
|
||||
distnumextra = dist_symbol >> 10;
|
||||
dist_cost = base_cost + (float)distnumextra +
|
||||
ZopfliCostModelGetDistanceCost(model, dist_symbol);
|
||||
ZopfliCostModelGetDistanceCost(model, dist_symbol & 0x3FF);
|
||||
|
||||
/* Try all copy lengths up until the maximum copy length corresponding
|
||||
to this distance. If the distance refers to the static dictionary, or
|
||||
@@ -508,7 +588,8 @@ static size_t ComputeShortestPathFromNodes(size_t num_bytes,
|
||||
ZopfliNode* nodes) {
|
||||
size_t index = num_bytes;
|
||||
size_t num_commands = 0;
|
||||
while (nodes[index].insert_length == 0 && nodes[index].length == 1) --index;
|
||||
while ((nodes[index].dcode_insert_length & 0x7FFFFFF) == 0 &&
|
||||
nodes[index].length == 1) --index;
|
||||
nodes[index].u.next = BROTLI_UINT32_MAX;
|
||||
while (index != 0) {
|
||||
size_t len = ZopfliNodeCommandLength(&nodes[index]);
|
||||
@@ -521,20 +602,19 @@ 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,
|
||||
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 = 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);
|
||||
size_t insert_length = next->insert_length;
|
||||
size_t insert_length = next->dcode_insert_length & 0x7FFFFFF;
|
||||
pos += insert_length;
|
||||
offset = next->u.next;
|
||||
if (i == 0) {
|
||||
@@ -544,12 +624,12 @@ 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);
|
||||
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], insert_length,
|
||||
InitCommand(&commands[i], ¶ms->dist, insert_length,
|
||||
copy_length, (int)len_code - (int)copy_length, dist_code);
|
||||
|
||||
if (!is_dictionary && dist_code > 0) {
|
||||
@@ -566,17 +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 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;
|
||||
@@ -600,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, 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--;
|
||||
}
|
||||
@@ -610,45 +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,
|
||||
const BrotliDictionary* dictionary,
|
||||
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[MAX_NUM_MATCHES_H10];
|
||||
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;
|
||||
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, 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);
|
||||
size_t num_matches = FindAllMatchesH10(hasher, dictionary, ringbuffer,
|
||||
ringbuffer_mask, pos, num_bytes - i, max_distance, params, matches);
|
||||
const size_t dictionary_start = BROTLI_MIN(size_t,
|
||||
pos + stream_offset, max_backward_limit);
|
||||
size_t skip;
|
||||
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) {
|
||||
@@ -656,48 +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, 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, const BrotliDictionary* dictionary, size_t num_bytes,
|
||||
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, 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;
|
||||
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) {
|
||||
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, dictionary, num_bytes,
|
||||
position, ringbuffer, ringbuffer_mask, params, max_backward_limit,
|
||||
*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, 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, const BrotliDictionary* dictionary, size_t num_bytes,
|
||||
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, 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) {
|
||||
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;
|
||||
@@ -709,30 +828,58 @@ void BrotliCreateHqZopfliBackwardReferences(
|
||||
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);
|
||||
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);
|
||||
cur_match_pos + MAX_NUM_MATCHES_H10 + shadow_matches);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
num_found_matches = FindAllMatchesH10(hasher, dictionary, ringbuffer,
|
||||
ringbuffer_mask, pos, max_length, max_distance, params,
|
||||
&matches[cur_match_pos]);
|
||||
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) {
|
||||
assert(BackwardMatchLength(&matches[j]) <
|
||||
BROTLI_DCHECK(BackwardMatchLength(&matches[j]) <=
|
||||
BackwardMatchLength(&matches[j + 1]));
|
||||
assert(matches[j].distance > max_distance ||
|
||||
matches[j].distance <= matches[j + 1].distance);
|
||||
}
|
||||
num_matches[i] = (uint32_t)num_found_matches;
|
||||
if (num_found_matches > 0) {
|
||||
@@ -742,7 +889,8 @@ void BrotliCreateHqZopfliBackwardReferences(
|
||||
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;
|
||||
@@ -756,16 +904,16 @@ void BrotliCreateHqZopfliBackwardReferences(
|
||||
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, 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);
|
||||
}
|
||||
@@ -774,12 +922,13 @@ void BrotliCreateHqZopfliBackwardReferences(
|
||||
*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, dist_cache,
|
||||
&model, num_matches, matches, nodes);
|
||||
BrotliZopfliCreateCommands(num_bytes, position, max_backward_limit,
|
||||
nodes, dist_cache, last_insert_len, 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);
|
||||
|
||||
65
c/enc/backward_references_hq.h
Executable file → Normal file
65
c/enc/backward_references_hq.h
Executable file → Normal file
@@ -9,43 +9,40 @@
|
||||
#ifndef BROTLI_ENC_BACKWARD_REFERENCES_HQ_H_
|
||||
#define BROTLI_ENC_BACKWARD_REFERENCES_HQ_H_
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include "../common/dictionary.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./command.h"
|
||||
#include "./hash.h"
|
||||
#include "./memory.h"
|
||||
#include "./port.h"
|
||||
#include "./quality.h"
|
||||
#include "../common/context.h"
|
||||
#include "../common/platform.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, const BrotliDictionary* dictionary, size_t num_bytes,
|
||||
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, 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);
|
||||
|
||||
BROTLI_INTERNAL void BrotliCreateHqZopfliBackwardReferences(
|
||||
MemoryManager* m, const BrotliDictionary* dictionary, size_t num_bytes,
|
||||
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, 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);
|
||||
|
||||
typedef struct ZopfliNode {
|
||||
/* best length to get up to this byte (not including this byte itself)
|
||||
highest 8 bit is used to reconstruct the length code */
|
||||
/* Best length to get up to this byte (not including this byte itself)
|
||||
highest 7 bit is used to reconstruct the length code. */
|
||||
uint32_t length;
|
||||
/* distance associated with the length
|
||||
highest 7 bit contains distance short code + 1 (or zero if no short code)
|
||||
*/
|
||||
/* Distance associated with the length. */
|
||||
uint32_t distance;
|
||||
/* number of literal inserts before this copy */
|
||||
uint32_t insert_length;
|
||||
/* Number of literal inserts before this copy; highest 5 bits contain
|
||||
distance short code + 1 (or zero if no short code). */
|
||||
uint32_t dcode_insert_length;
|
||||
|
||||
/* This union holds information used by dynamic-programming. During forward
|
||||
pass |cost| it used to store the goal function. When node is processed its
|
||||
@@ -78,19 +75,15 @@ BROTLI_INTERNAL void BrotliInitZopfliNodes(ZopfliNode* array, size_t length);
|
||||
(2) nodes[i].command_length() <= i and
|
||||
(3) nodes[i - nodes[i].command_length()].cost < kInfinity */
|
||||
BROTLI_INTERNAL size_t BrotliZopfliComputeShortestPath(
|
||||
MemoryManager* m, const BrotliDictionary* dictionary, size_t num_bytes,
|
||||
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);
|
||||
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,
|
||||
int* dist_cache,
|
||||
size_t* last_insert_len,
|
||||
Command* commands,
|
||||
size_t* num_literals);
|
||||
BROTLI_INTERNAL void BrotliZopfliCreateCommands(
|
||||
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);
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
|
||||
@@ -5,17 +5,18 @@
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/* template parameters: FN */
|
||||
/* template parameters: EXPORT_FN, FN */
|
||||
|
||||
static BROTLI_NOINLINE void FN(CreateBackwardReferences)(
|
||||
const BrotliDictionary* dictionary, const uint16_t* dictionary_hash,
|
||||
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;
|
||||
@@ -27,23 +28,42 @@ static BROTLI_NOINLINE void 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 = 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, dictionary, dictionary_hash, ringbuffer,
|
||||
ringbuffer_mask, dist_cache, position,
|
||||
max_length, 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;
|
||||
@@ -57,9 +77,25 @@ static BROTLI_NOINLINE void FN(CreateBackwardReferences)(
|
||||
sr2.distance = 0;
|
||||
sr2.score = kMinScore;
|
||||
max_distance = BROTLI_MIN(size_t, position + 1, max_backward_limit);
|
||||
FN(FindLongestMatch)(hasher, dictionary, dictionary_hash, ringbuffer,
|
||||
ringbuffer_mask, dist_cache, position + 1,
|
||||
max_length, max_distance, &sr2);
|
||||
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, 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. */
|
||||
@@ -75,29 +111,39 @@ static BROTLI_NOINLINE void 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, dist_cache);
|
||||
if (sr.distance <= max_distance && 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++, insert_length, sr.len, sr.len_code_delta,
|
||||
distance_code);
|
||||
InitCommand(commands++, ¶ms->dist, insert_length,
|
||||
sr.len, sr.len_code_delta, distance_code);
|
||||
}
|
||||
*num_literals += insert_length;
|
||||
insert_length = 0;
|
||||
/* Put the hash keys into the table, if there are enough bytes left.
|
||||
Depending on the hasher implementation, it can push all positions
|
||||
in the given range or only a subset of them. */
|
||||
FN(StoreRange)(hasher, ringbuffer, ringbuffer_mask, position + 2,
|
||||
BROTLI_MIN(size_t, position + sr.len, store_end));
|
||||
in the given range or only a subset of them.
|
||||
Avoid hash poisoning with RLE data. */
|
||||
{
|
||||
size_t range_start = position + 2;
|
||||
size_t range_end = BROTLI_MIN(size_t, position + sr.len, store_end);
|
||||
if (sr.distance < (sr.len >> 2)) {
|
||||
range_start = BROTLI_MIN(size_t, range_end, BROTLI_MAX(size_t,
|
||||
range_start, position + sr.len - (sr.distance << 2)));
|
||||
}
|
||||
FN(StoreRange)(privat, ringbuffer, ringbuffer_mask, range_start,
|
||||
range_end);
|
||||
}
|
||||
position += sr.len;
|
||||
} else {
|
||||
++insert_length;
|
||||
@@ -121,7 +167,7 @@ static BROTLI_NOINLINE void 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 {
|
||||
@@ -130,7 +176,7 @@ static BROTLI_NOINLINE void 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 <brotli/types.h>
|
||||
#include "./fast_log.h"
|
||||
#include "./histogram.h"
|
||||
#include "./port.h"
|
||||
#include "../common/platform.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)
|
||||
|
||||
@@ -9,52 +9,21 @@
|
||||
#ifndef BROTLI_ENC_BIT_COST_H_
|
||||
#define BROTLI_ENC_BIT_COST_H_
|
||||
|
||||
#include <brotli/types.h>
|
||||
#include "./fast_log.h"
|
||||
#include "./histogram.h"
|
||||
#include "./port.h"
|
||||
#include "../common/platform.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;
|
||||
}
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
stream. */
|
||||
static void FN(BuildAndStoreEntropyCodes)(MemoryManager* m, BlockEncoder* self,
|
||||
const HistogramType* histograms, const size_t histograms_size,
|
||||
HuffmanTree* tree, size_t* storage_ix, uint8_t* storage) {
|
||||
const size_t alphabet_size = self->alphabet_size_;
|
||||
const size_t table_size = histograms_size * alphabet_size;
|
||||
const size_t alphabet_size, HuffmanTree* tree,
|
||||
size_t* storage_ix, uint8_t* storage) {
|
||||
const size_t table_size = histograms_size * self->histogram_length_;
|
||||
self->depths_ = BROTLI_ALLOC(m, uint8_t, table_size);
|
||||
self->bits_ = BROTLI_ALLOC(m, uint16_t, table_size);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
@@ -23,9 +23,10 @@ static void FN(BuildAndStoreEntropyCodes)(MemoryManager* m, BlockEncoder* self,
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < histograms_size; ++i) {
|
||||
size_t ix = i * alphabet_size;
|
||||
BuildAndStoreHuffmanTree(&histograms[i].data_[0], alphabet_size, tree,
|
||||
&self->depths_[ix], &self->bits_[ix], storage_ix, storage);
|
||||
size_t ix = i * self->histogram_length_;
|
||||
BuildAndStoreHuffmanTree(&histograms[i].data_[0], self->histogram_length_,
|
||||
alphabet_size, tree, &self->depths_[ix], &self->bits_[ix],
|
||||
storage_ix, storage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,19 +6,16 @@
|
||||
|
||||
/* Block split point selection utilities. */
|
||||
|
||||
#include "./block_splitter.h"
|
||||
#include "block_splitter.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h> /* memcpy, memset */
|
||||
|
||||
#include "./bit_cost.h"
|
||||
#include "./cluster.h"
|
||||
#include "./command.h"
|
||||
#include "./fast_log.h"
|
||||
#include "./histogram.h"
|
||||
#include "./memory.h"
|
||||
#include "./port.h"
|
||||
#include "./quality.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"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
@@ -31,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;
|
||||
@@ -74,11 +72,9 @@ static void CopyLiteralsToByteArray(const Command* cmds,
|
||||
}
|
||||
}
|
||||
|
||||
static BROTLI_INLINE unsigned int MyRand(unsigned int* seed) {
|
||||
static BROTLI_INLINE uint32_t MyRand(uint32_t* seed) {
|
||||
/* Initial seed should be 7. In this case, loop length is (1 << 29). */
|
||||
*seed *= 16807U;
|
||||
if (*seed == 0) {
|
||||
*seed = 1;
|
||||
}
|
||||
return *seed;
|
||||
}
|
||||
|
||||
@@ -92,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
|
||||
|
||||
@@ -122,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,
|
||||
@@ -135,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,
|
||||
@@ -147,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_;
|
||||
}
|
||||
@@ -164,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);
|
||||
}
|
||||
|
||||
@@ -173,24 +177,37 @@ 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) {
|
||||
distance_prefixes[j++] = cmd->dist_prefix_;
|
||||
distance_prefixes[j++] = cmd->dist_prefix_ & 0x3FF;
|
||||
}
|
||||
}
|
||||
/* Create the block split on the array of distance prefixes. */
|
||||
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" */
|
||||
|
||||
@@ -9,11 +9,9 @@
|
||||
#ifndef BROTLI_ENC_BLOCK_SPLITTER_H_
|
||||
#define BROTLI_ENC_BLOCK_SPLITTER_H_
|
||||
|
||||
#include <brotli/types.h>
|
||||
#include "./command.h"
|
||||
#include "./memory.h"
|
||||
#include "./port.h"
|
||||
#include "./quality.h"
|
||||
#include "../common/platform.h"
|
||||
#include "command.h"
|
||||
#include "memory.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
|
||||
@@ -13,7 +13,7 @@ static void FN(InitialEntropyCodes)(const DataType* data, size_t length,
|
||||
size_t stride,
|
||||
size_t num_histograms,
|
||||
HistogramType* histograms) {
|
||||
unsigned int seed = 7;
|
||||
uint32_t seed = 7;
|
||||
size_t block_length = length / num_histograms;
|
||||
size_t i;
|
||||
FN(ClearHistograms)(histograms, num_histograms);
|
||||
@@ -29,14 +29,13 @@ static void FN(InitialEntropyCodes)(const DataType* data, size_t length,
|
||||
}
|
||||
}
|
||||
|
||||
static void FN(RandomSample)(unsigned int* seed,
|
||||
static void FN(RandomSample)(uint32_t* seed,
|
||||
const DataType* data,
|
||||
size_t length,
|
||||
size_t stride,
|
||||
HistogramType* sample) {
|
||||
size_t pos = 0;
|
||||
if (stride >= length) {
|
||||
pos = 0;
|
||||
stride = length;
|
||||
} else {
|
||||
pos = MyRand(seed) % (length - stride + 1);
|
||||
@@ -47,17 +46,17 @@ static void FN(RandomSample)(unsigned int* 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;
|
||||
unsigned int seed = 7;
|
||||
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,47 +70,59 @@ static size_t FN(FindBlocks)(const DataType* data, const size_t length,
|
||||
double* insert_cost,
|
||||
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;
|
||||
uint8_t* block_id) {
|
||||
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;
|
||||
assert(num_histograms <= 256);
|
||||
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];
|
||||
@@ -119,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;
|
||||
assert((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));
|
||||
assert(((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];
|
||||
@@ -162,16 +174,16 @@ static size_t FN(RemapBlockIds)(uint8_t* block_ids, const size_t length,
|
||||
new_id[i] = kInvalidId;
|
||||
}
|
||||
for (i = 0; i < length; ++i) {
|
||||
assert(block_ids[i] < num_histograms);
|
||||
BROTLI_DCHECK(block_ids[i] < num_histograms);
|
||||
if (new_id[block_ids[i]] == kInvalidId) {
|
||||
new_id[block_ids[i]] = next_id++;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < length; ++i) {
|
||||
block_ids[i] = (uint8_t)new_id[block_ids[i]];
|
||||
assert(block_ids[i] < num_histograms);
|
||||
BROTLI_DCHECK(block_ids[i] < num_histograms);
|
||||
}
|
||||
assert(next_id <= num_histograms);
|
||||
BROTLI_DCHECK(next_id <= num_histograms);
|
||||
return next_id;
|
||||
}
|
||||
|
||||
@@ -186,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;
|
||||
@@ -215,27 +230,42 @@ 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) {
|
||||
assert(block_idx < num_blocks);
|
||||
BROTLI_DCHECK(block_idx < num_blocks);
|
||||
++block_lengths[block_idx];
|
||||
if (i + 1 == length || block_ids[i] != block_ids[i + 1]) {
|
||||
++block_idx;
|
||||
}
|
||||
}
|
||||
assert(block_idx == num_blocks);
|
||||
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);
|
||||
@@ -243,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]);
|
||||
@@ -253,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);
|
||||
@@ -269,52 +300,54 @@ static void FN(ClusterBlocks)(MemoryManager* m,
|
||||
histogram_symbols[i + j] = (uint32_t)num_clusters + remap[symbols[j]];
|
||||
}
|
||||
num_clusters += num_new_clusters;
|
||||
assert(num_clusters == cluster_size_size);
|
||||
assert(num_clusters == all_histograms_size);
|
||||
BROTLI_DCHECK(num_clusters == cluster_size_size);
|
||||
BROTLI_DCHECK(num_clusters == all_histograms_size);
|
||||
}
|
||||
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];
|
||||
@@ -326,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(
|
||||
@@ -333,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;
|
||||
@@ -353,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,
|
||||
@@ -386,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);
|
||||
@@ -406,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,59 +8,41 @@
|
||||
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 <brotli/types.h>
|
||||
#include "./context.h"
|
||||
#include "./entropy_encode.h"
|
||||
#include "./entropy_encode_static.h"
|
||||
#include "./fast_log.h"
|
||||
#include "./memory.h"
|
||||
#include "./port.h"
|
||||
#include "./write_bits.h"
|
||||
#include "../common/context.h"
|
||||
#include "../common/platform.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" {
|
||||
#endif
|
||||
|
||||
#define MAX_HUFFMAN_TREE_SIZE (2 * BROTLI_NUM_COMMAND_SYMBOLS + 1)
|
||||
/* The size of Huffman dictionary for distances assuming that NPOSTFIX = 0 and
|
||||
NDIRECT = 0. */
|
||||
#define SIMPLE_DISTANCE_ALPHABET_SIZE (BROTLI_NUM_DISTANCE_SHORT_CODES + \
|
||||
(2 * BROTLI_MAX_DISTANCE_BITS))
|
||||
/* SIMPLE_DISTANCE_ALPHABET_SIZE == 64 */
|
||||
#define SIMPLE_DISTANCE_ALPHABET_BITS 6
|
||||
|
||||
/* 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}
|
||||
};
|
||||
/* The maximum size of Huffman dictionary for distances assuming that
|
||||
NPOSTFIX = 0 and NDIRECT = 0. */
|
||||
#define MAX_SIMPLE_DISTANCE_ALPHABET_SIZE \
|
||||
BROTLI_DISTANCE_ALPHABET_SIZE(0, 0, BROTLI_LARGE_MAX_DISTANCE_BITS)
|
||||
/* MAX_SIMPLE_DISTANCE_ALPHABET_SIZE == 140 */
|
||||
|
||||
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 {
|
||||
@@ -89,9 +71,9 @@ static void BrotliEncodeMlen(size_t length, uint64_t* bits,
|
||||
size_t* numbits, uint64_t* nibblesbits) {
|
||||
size_t lg = (length == 1) ? 1 : Log2FloorNonZero((uint32_t)(length - 1)) + 1;
|
||||
size_t mnibbles = (lg < 16 ? 16 : (lg + 3)) / 4;
|
||||
assert(length > 0);
|
||||
assert(length <= (1 << 24));
|
||||
assert(lg <= 24);
|
||||
BROTLI_DCHECK(length > 0);
|
||||
BROTLI_DCHECK(length <= (1 << 24));
|
||||
BROTLI_DCHECK(lg <= 24);
|
||||
*nibblesbits = mnibbles - 4;
|
||||
*numbits = mnibbles * 4;
|
||||
*bits = length - 1;
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -258,7 +243,7 @@ static void StoreSimpleHuffmanTree(const uint8_t* depths,
|
||||
size_t symbols[4],
|
||||
size_t num_symbols,
|
||||
size_t max_bits,
|
||||
size_t *storage_ix, uint8_t *storage) {
|
||||
size_t* storage_ix, uint8_t* storage) {
|
||||
/* value of 1 indicates a simple Huffman code */
|
||||
BrotliWriteBits(2, 1, storage_ix, storage);
|
||||
BrotliWriteBits(2, num_symbols - 1, storage_ix, storage); /* NSYM - 1 */
|
||||
@@ -297,10 +282,11 @@ static void StoreSimpleHuffmanTree(const uint8_t* depths,
|
||||
depths = symbol depths */
|
||||
void BrotliStoreHuffmanTree(const uint8_t* depths, size_t num,
|
||||
HuffmanTree* tree,
|
||||
size_t *storage_ix, uint8_t *storage) {
|
||||
size_t* storage_ix, uint8_t* storage) {
|
||||
/* 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;
|
||||
@@ -311,7 +297,7 @@ void BrotliStoreHuffmanTree(const uint8_t* depths, size_t num,
|
||||
int num_codes = 0;
|
||||
size_t code = 0;
|
||||
|
||||
assert(num <= BROTLI_NUM_COMMAND_SYMBOLS);
|
||||
BROTLI_DCHECK(num <= BROTLI_NUM_COMMAND_SYMBOLS);
|
||||
|
||||
BrotliWriteHuffmanTree(depths, num, &huffman_tree_size, huffman_tree,
|
||||
huffman_tree_extra_bits);
|
||||
@@ -360,8 +346,9 @@ void BrotliStoreHuffmanTree(const uint8_t* depths, size_t num,
|
||||
|
||||
/* Builds a Huffman tree from histogram[0:length] into depth[0:length] and
|
||||
bits[0:length] and stores the encoded tree to the bit stream. */
|
||||
static void BuildAndStoreHuffmanTree(const uint32_t *histogram,
|
||||
const size_t length,
|
||||
static void BuildAndStoreHuffmanTree(const uint32_t* histogram,
|
||||
const size_t histogram_length,
|
||||
const size_t alphabet_size,
|
||||
HuffmanTree* tree,
|
||||
uint8_t* depth,
|
||||
uint16_t* bits,
|
||||
@@ -371,7 +358,7 @@ static void BuildAndStoreHuffmanTree(const uint32_t *histogram,
|
||||
size_t s4[4] = { 0 };
|
||||
size_t i;
|
||||
size_t max_bits = 0;
|
||||
for (i = 0; i < length; i++) {
|
||||
for (i = 0; i < histogram_length; i++) {
|
||||
if (histogram[i]) {
|
||||
if (count < 4) {
|
||||
s4[count] = i;
|
||||
@@ -383,7 +370,7 @@ static void BuildAndStoreHuffmanTree(const uint32_t *histogram,
|
||||
}
|
||||
|
||||
{
|
||||
size_t max_bits_counter = length - 1;
|
||||
size_t max_bits_counter = alphabet_size - 1;
|
||||
while (max_bits_counter) {
|
||||
max_bits_counter >>= 1;
|
||||
++max_bits;
|
||||
@@ -398,14 +385,14 @@ static void BuildAndStoreHuffmanTree(const uint32_t *histogram,
|
||||
return;
|
||||
}
|
||||
|
||||
memset(depth, 0, length * sizeof(depth[0]));
|
||||
BrotliCreateHuffmanTree(histogram, length, 15, tree, depth);
|
||||
BrotliConvertBitDepthsToSymbols(depth, length, bits);
|
||||
memset(depth, 0, histogram_length * sizeof(depth[0]));
|
||||
BrotliCreateHuffmanTree(histogram, histogram_length, 15, tree, depth);
|
||||
BrotliConvertBitDepthsToSymbols(depth, histogram_length, bits);
|
||||
|
||||
if (count <= 4) {
|
||||
StoreSimpleHuffmanTree(depth, s4, count, max_bits, storage_ix, storage);
|
||||
} else {
|
||||
BrotliStoreHuffmanTree(depth, length, tree, storage_ix, storage);
|
||||
BrotliStoreHuffmanTree(depth, histogram_length, tree, storage_ix, storage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -414,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,
|
||||
@@ -446,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;
|
||||
@@ -514,7 +498,6 @@ void BrotliBuildAndStoreHuffmanTreeFast(MemoryManager* m,
|
||||
}
|
||||
}
|
||||
}
|
||||
BROTLI_FREE(m, tree);
|
||||
}
|
||||
BrotliConvertBitDepthsToSymbols(depth, length, bits);
|
||||
if (count <= 4) {
|
||||
@@ -619,7 +602,7 @@ static void MoveToFrontTransform(const uint32_t* BROTLI_RESTRICT v_in,
|
||||
for (i = 1; i < v_size; ++i) {
|
||||
if (v_in[i] > max_value) max_value = v_in[i];
|
||||
}
|
||||
assert(max_value < 256u);
|
||||
BROTLI_DCHECK(max_value < 256u);
|
||||
for (i = 0; i <= max_value; ++i) {
|
||||
mtf[i] = (uint8_t)i;
|
||||
}
|
||||
@@ -627,7 +610,7 @@ static void MoveToFrontTransform(const uint32_t* BROTLI_RESTRICT v_in,
|
||||
size_t mtf_size = max_value + 1;
|
||||
for (i = 0; i < v_size; ++i) {
|
||||
size_t index = IndexOf(mtf, mtf_size, (uint8_t)v_in[i]);
|
||||
assert(index < mtf_size);
|
||||
BROTLI_DCHECK(index < mtf_size);
|
||||
v_out[i] = (uint32_t)index;
|
||||
MoveToFront(mtf, index);
|
||||
}
|
||||
@@ -659,7 +642,7 @@ static void RunLengthCodeZeros(const size_t in_size,
|
||||
*max_run_length_prefix = max_prefix;
|
||||
*out_size = 0;
|
||||
for (i = 0; i < in_size;) {
|
||||
assert(*out_size <= i);
|
||||
BROTLI_DCHECK(*out_size <= i);
|
||||
if (v[i] != 0) {
|
||||
v[*out_size] = v[i] + *max_run_length_prefix;
|
||||
++i;
|
||||
@@ -691,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,
|
||||
@@ -701,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);
|
||||
|
||||
@@ -713,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];
|
||||
}
|
||||
@@ -729,6 +719,7 @@ static void EncodeContextMap(MemoryManager* m,
|
||||
}
|
||||
}
|
||||
BuildAndStoreHuffmanTree(histogram, num_clusters + max_run_length_prefix,
|
||||
num_clusters + max_run_length_prefix,
|
||||
tree, depths, bits, storage_ix, storage);
|
||||
for (i = 0; i < num_rle_symbols; ++i) {
|
||||
const uint32_t rle_symbol = rle_symbols[i] & kSymbolMask;
|
||||
@@ -787,11 +778,12 @@ 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? */
|
||||
BuildAndStoreHuffmanTree(&type_histo[0], num_types + 2, tree,
|
||||
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);
|
||||
BuildAndStoreHuffmanTree(&length_histo[0], BROTLI_NUM_BLOCK_LEN_SYMBOLS,
|
||||
BROTLI_NUM_BLOCK_LEN_SYMBOLS,
|
||||
tree, &code->length_depths[0],
|
||||
&code->length_bits[0], storage_ix, storage);
|
||||
StoreBlockSwitch(code, lengths[0], types[0], 1, storage_ix, storage);
|
||||
@@ -799,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,
|
||||
@@ -809,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. */
|
||||
@@ -822,8 +815,8 @@ static void StoreTrivialContextMap(size_t num_types,
|
||||
for (i = context_bits; i < alphabet_size; ++i) {
|
||||
histogram[i] = 1;
|
||||
}
|
||||
BuildAndStoreHuffmanTree(histogram, alphabet_size, tree,
|
||||
depths, bits, storage_ix, storage);
|
||||
BuildAndStoreHuffmanTree(histogram, alphabet_size, alphabet_size,
|
||||
tree, depths, bits, storage_ix, storage);
|
||||
for (i = 0; i < num_types; ++i) {
|
||||
size_t code = (i == 0 ? 0 : i + context_bits - 1);
|
||||
BrotliWriteBits(depths[code], bits[code], storage_ix, storage);
|
||||
@@ -838,7 +831,7 @@ static void StoreTrivialContextMap(size_t num_types,
|
||||
|
||||
/* Manages the encoding of one block category (literal, command or distance). */
|
||||
typedef struct BlockEncoder {
|
||||
size_t alphabet_size_;
|
||||
size_t histogram_length_;
|
||||
size_t num_block_types_;
|
||||
const uint8_t* block_types_; /* Not owned. */
|
||||
const uint32_t* block_lengths_; /* Not owned. */
|
||||
@@ -851,10 +844,10 @@ typedef struct BlockEncoder {
|
||||
uint16_t* bits_;
|
||||
} BlockEncoder;
|
||||
|
||||
static void InitBlockEncoder(BlockEncoder* self, size_t alphabet_size,
|
||||
static void InitBlockEncoder(BlockEncoder* self, size_t histogram_length,
|
||||
size_t num_block_types, const uint8_t* block_types,
|
||||
const uint32_t* block_lengths, const size_t num_blocks) {
|
||||
self->alphabet_size_ = alphabet_size;
|
||||
self->histogram_length_ = histogram_length;
|
||||
self->num_block_types_ = num_block_types;
|
||||
self->block_types_ = block_types;
|
||||
self->block_lengths_ = block_lengths;
|
||||
@@ -890,7 +883,7 @@ static void StoreSymbol(BlockEncoder* self, size_t symbol, size_t* storage_ix,
|
||||
uint32_t block_len = self->block_lengths_[block_ix];
|
||||
uint8_t block_type = self->block_types_[block_ix];
|
||||
self->block_len_ = block_len;
|
||||
self->entropy_ix_ = block_type * self->alphabet_size_;
|
||||
self->entropy_ix_ = block_type * self->histogram_length_;
|
||||
StoreBlockSwitch(&self->block_split_code_, block_len, block_type, 0,
|
||||
storage_ix, storage);
|
||||
}
|
||||
@@ -919,24 +912,24 @@ static void StoreSymbolWithContext(BlockEncoder* self, size_t symbol,
|
||||
--self->block_len_;
|
||||
{
|
||||
size_t histo_ix = context_map[self->entropy_ix_ + context];
|
||||
size_t ix = histo_ix * self->alphabet_size_ + symbol;
|
||||
size_t ix = histo_ix * self->histogram_length_ + symbol;
|
||||
BrotliWriteBits(self->depths_[ix], self->bits_[ix], storage_ix, storage);
|
||||
}
|
||||
}
|
||||
|
||||
#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) {
|
||||
@@ -944,106 +937,118 @@ static void JumpToByteBoundary(size_t* storage_ix, uint8_t* storage) {
|
||||
storage[*storage_ix >> 3] = 0;
|
||||
}
|
||||
|
||||
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,
|
||||
uint32_t num_direct_distance_codes,
|
||||
uint32_t distance_postfix_bits,
|
||||
ContextType literal_context_mode,
|
||||
const Command *commands,
|
||||
size_t n_commands,
|
||||
const MetaBlockSplit* mb,
|
||||
size_t *storage_ix,
|
||||
uint8_t *storage) {
|
||||
size_t pos = start_pos;
|
||||
size_t i;
|
||||
size_t num_distance_codes =
|
||||
BROTLI_NUM_DISTANCE_SHORT_CODES + num_direct_distance_codes +
|
||||
(48u << distance_postfix_bits);
|
||||
HuffmanTree* tree;
|
||||
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,
|
||||
const BrotliEncoderParams* params, ContextType literal_context_mode,
|
||||
const Command* commands, size_t n_commands, const MetaBlockSplit* mb,
|
||||
size_t* storage_ix, uint8_t* storage) {
|
||||
|
||||
size_t pos = start_pos;
|
||||
size_t i;
|
||||
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);
|
||||
StoreMetablockArena* arena = NULL;
|
||||
BlockEncoder* literal_enc = NULL;
|
||||
BlockEncoder* command_enc = NULL;
|
||||
BlockEncoder* distance_enc = NULL;
|
||||
const BrotliDistanceParams* dist = ¶ms->dist;
|
||||
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, 256, 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,
|
||||
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,
|
||||
mb->command_split.num_types, mb->command_split.types,
|
||||
mb->command_split.lengths, mb->command_split.num_blocks);
|
||||
InitBlockEncoder(&distance_enc, num_distance_codes,
|
||||
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, distance_postfix_bits, storage_ix, storage);
|
||||
BrotliWriteBits(4, num_direct_distance_codes >> distance_postfix_bits,
|
||||
storage_ix, storage);
|
||||
BrotliWriteBits(2, dist->distance_postfix_bits, storage_ix, storage);
|
||||
BrotliWriteBits(
|
||||
4, dist->num_direct_distance_codes >> dist->distance_postfix_bits,
|
||||
storage_ix, storage);
|
||||
for (i = 0; i < mb->literal_split.num_types; ++i) {
|
||||
BrotliWriteBits(2, literal_context_mode, storage_ix, storage);
|
||||
}
|
||||
|
||||
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,
|
||||
mb->literal_histograms_size, tree, storage_ix, storage);
|
||||
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,
|
||||
mb->command_histograms_size, tree, storage_ix, storage);
|
||||
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,
|
||||
mb->distance_histograms_size, tree, storage_ix, storage);
|
||||
BuildAndStoreEntropyCodesDistance(m, distance_enc, mb->distance_histograms,
|
||||
mb->distance_histograms_size, num_distance_symbols, tree,
|
||||
storage_ix, storage);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
BROTLI_FREE(m, tree);
|
||||
|
||||
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 {
|
||||
size_t j;
|
||||
for (j = cmd.insert_len_; j != 0; --j) {
|
||||
size_t context = Context(prev_byte, prev_byte2, literal_context_mode);
|
||||
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;
|
||||
@@ -1056,14 +1061,14 @@ void BrotliStoreMetaBlock(MemoryManager* m,
|
||||
prev_byte2 = input[(pos - 2) & mask];
|
||||
prev_byte = input[(pos - 1) & mask];
|
||||
if (cmd.cmd_prefix_ >= 128) {
|
||||
size_t dist_code = cmd.dist_prefix_;
|
||||
uint32_t distnumextra = cmd.dist_extra_ >> 24;
|
||||
uint64_t distextra = cmd.dist_extra_ & 0xffffff;
|
||||
size_t dist_code = cmd.dist_prefix_ & 0x3FF;
|
||||
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);
|
||||
}
|
||||
@@ -1071,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);
|
||||
}
|
||||
@@ -1082,7 +1088,7 @@ void BrotliStoreMetaBlock(MemoryManager* m,
|
||||
static void BuildHistograms(const uint8_t* input,
|
||||
size_t start_pos,
|
||||
size_t mask,
|
||||
const Command *commands,
|
||||
const Command* commands,
|
||||
size_t n_commands,
|
||||
HistogramLiteral* lit_histo,
|
||||
HistogramCommand* cmd_histo,
|
||||
@@ -1099,7 +1105,7 @@ static void BuildHistograms(const uint8_t* input,
|
||||
}
|
||||
pos += CommandCopyLen(&cmd);
|
||||
if (CommandCopyLen(&cmd) && cmd.cmd_prefix_ >= 128) {
|
||||
HistogramAddDistance(dist_histo, cmd.dist_prefix_);
|
||||
HistogramAddDistance(dist_histo, cmd.dist_prefix_ & 0x3FF);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1107,7 +1113,7 @@ static void BuildHistograms(const uint8_t* input,
|
||||
static void StoreDataWithHuffmanCodes(const uint8_t* input,
|
||||
size_t start_pos,
|
||||
size_t mask,
|
||||
const Command *commands,
|
||||
const Command* commands,
|
||||
size_t n_commands,
|
||||
const uint8_t* lit_depth,
|
||||
const uint16_t* lit_bits,
|
||||
@@ -1134,9 +1140,9 @@ static void StoreDataWithHuffmanCodes(const uint8_t* input,
|
||||
}
|
||||
pos += CommandCopyLen(&cmd);
|
||||
if (CommandCopyLen(&cmd) && cmd.cmd_prefix_ >= 128) {
|
||||
const size_t dist_code = cmd.dist_prefix_;
|
||||
const uint32_t distnumextra = cmd.dist_extra_ >> 24;
|
||||
const uint32_t distextra = cmd.dist_extra_ & 0xffffff;
|
||||
const size_t dist_code = cmd.dist_prefix_ & 0x3FF;
|
||||
const uint32_t distnumextra = cmd.dist_prefix_ >> 10;
|
||||
const uint32_t distextra = cmd.dist_extra_;
|
||||
BrotliWriteBits(dist_depth[dist_code], dist_bits[dist_code],
|
||||
storage_ix, storage);
|
||||
BrotliWriteBits(distnumextra, distextra, storage_ix, storage);
|
||||
@@ -1144,71 +1150,76 @@ 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 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[SIMPLE_DISTANCE_ALPHABET_SIZE];
|
||||
uint16_t dist_bits[SIMPLE_DISTANCE_ALPHABET_SIZE];
|
||||
HuffmanTree* tree;
|
||||
uint8_t dist_depth[MAX_SIMPLE_DISTANCE_ALPHABET_SIZE];
|
||||
uint16_t dist_bits[MAX_SIMPLE_DISTANCE_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, 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, 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_, SIMPLE_DISTANCE_ALPHABET_SIZE,
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void BrotliStoreMetaBlockFast(MemoryManager* m,
|
||||
const uint8_t* input,
|
||||
size_t start_pos,
|
||||
size_t length,
|
||||
size_t mask,
|
||||
BROTLI_BOOL is_last,
|
||||
const Command *commands,
|
||||
size_t n_commands,
|
||||
size_t *storage_ix,
|
||||
uint8_t *storage) {
|
||||
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;
|
||||
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);
|
||||
|
||||
BrotliWriteBits(13, 0, storage_ix, storage);
|
||||
@@ -1218,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;
|
||||
@@ -1230,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[SIMPLE_DISTANCE_ALPHABET_SIZE];
|
||||
uint16_t dist_bits[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 = */
|
||||
SIMPLE_DISTANCE_ALPHABET_BITS,
|
||||
dist_depth, dist_bits,
|
||||
distance_alphabet_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);
|
||||
}
|
||||
@@ -1293,11 +1291,11 @@ void BrotliStoreMetaBlockFast(MemoryManager* m,
|
||||
/* This is for storing uncompressed blocks (simple raw storage of
|
||||
bytes-as-bytes). */
|
||||
void BrotliStoreUncompressedMetaBlock(BROTLI_BOOL is_final_block,
|
||||
const uint8_t * BROTLI_RESTRICT input,
|
||||
const uint8_t* BROTLI_RESTRICT input,
|
||||
size_t position, size_t mask,
|
||||
size_t len,
|
||||
size_t * BROTLI_RESTRICT storage_ix,
|
||||
uint8_t * BROTLI_RESTRICT storage) {
|
||||
size_t* BROTLI_RESTRICT storage_ix,
|
||||
uint8_t* BROTLI_RESTRICT storage) {
|
||||
size_t masked_pos = position & mask;
|
||||
BrotliStoreUncompressedMetaBlockHeader(len, storage_ix, storage);
|
||||
JumpToByteBoundary(storage_ix, storage);
|
||||
@@ -1325,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
|
||||
|
||||
@@ -16,13 +16,12 @@
|
||||
#ifndef BROTLI_ENC_BROTLI_BIT_STREAM_H_
|
||||
#define BROTLI_ENC_BROTLI_BIT_STREAM_H_
|
||||
|
||||
#include <brotli/types.h>
|
||||
#include "./command.h"
|
||||
#include "./context.h"
|
||||
#include "./entropy_encode.h"
|
||||
#include "./memory.h"
|
||||
#include "./metablock.h"
|
||||
#include "./port.h"
|
||||
#include "../common/context.h"
|
||||
#include "../common/platform.h"
|
||||
#include "command.h"
|
||||
#include "entropy_encode.h"
|
||||
#include "memory.h"
|
||||
#include "metablock.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
@@ -32,69 +31,50 @@ extern "C" {
|
||||
position for the current storage. */
|
||||
|
||||
BROTLI_INTERNAL void BrotliStoreHuffmanTree(const uint8_t* depths, size_t num,
|
||||
HuffmanTree* tree, size_t *storage_ix, uint8_t *storage);
|
||||
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);
|
||||
|
||||
/* REQUIRES: length > 0 */
|
||||
/* REQUIRES: length <= (1 << 24) */
|
||||
BROTLI_INTERNAL 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_final_block,
|
||||
uint32_t num_direct_distance_codes,
|
||||
uint32_t distance_postfix_bits,
|
||||
ContextType literal_context_mode,
|
||||
const Command* commands,
|
||||
size_t n_commands,
|
||||
const MetaBlockSplit* mb,
|
||||
size_t* storage_ix,
|
||||
uint8_t* storage);
|
||||
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,
|
||||
const BrotliEncoderParams* params, ContextType literal_context_mode,
|
||||
const Command* commands, size_t n_commands, const MetaBlockSplit* mb,
|
||||
size_t* storage_ix, uint8_t* storage);
|
||||
|
||||
/* Stores the meta-block without doing any block splitting, just collects
|
||||
one histogram per block category and uses that for entropy coding.
|
||||
REQUIRES: length > 0
|
||||
REQUIRES: length <= (1 << 24) */
|
||||
BROTLI_INTERNAL void BrotliStoreMetaBlockTrivial(MemoryManager* m,
|
||||
const uint8_t* input,
|
||||
size_t start_pos,
|
||||
size_t length,
|
||||
size_t mask,
|
||||
BROTLI_BOOL is_last,
|
||||
const Command *commands,
|
||||
size_t n_commands,
|
||||
size_t* storage_ix,
|
||||
uint8_t* storage);
|
||||
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);
|
||||
|
||||
/* Same as above, but uses static prefix codes for histograms with a only a few
|
||||
symbols, and uses static code length prefix codes for all other histograms.
|
||||
REQUIRES: length > 0
|
||||
REQUIRES: length <= (1 << 24) */
|
||||
BROTLI_INTERNAL void BrotliStoreMetaBlockFast(MemoryManager* m,
|
||||
const uint8_t* input,
|
||||
size_t start_pos,
|
||||
size_t length,
|
||||
size_t mask,
|
||||
BROTLI_BOOL is_last,
|
||||
const Command *commands,
|
||||
size_t n_commands,
|
||||
size_t* storage_ix,
|
||||
uint8_t* storage);
|
||||
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);
|
||||
|
||||
/* This is for storing uncompressed blocks (simple raw storage of
|
||||
bytes-as-bytes).
|
||||
REQUIRES: length > 0
|
||||
REQUIRES: length <= (1 << 24) */
|
||||
BROTLI_INTERNAL void BrotliStoreUncompressedMetaBlock(
|
||||
BROTLI_BOOL is_final_block, const uint8_t* input, size_t position,
|
||||
size_t mask, size_t len, size_t* storage_ix, uint8_t* storage);
|
||||
BROTLI_BOOL is_final_block, const uint8_t* BROTLI_RESTRICT input,
|
||||
size_t position, size_t mask, size_t len,
|
||||
size_t* BROTLI_RESTRICT storage_ix, uint8_t* BROTLI_RESTRICT storage);
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
|
||||
@@ -6,14 +6,13 @@
|
||||
|
||||
/* Functions for clustering similar histograms together. */
|
||||
|
||||
#include "./cluster.h"
|
||||
#include "cluster.h"
|
||||
|
||||
#include <brotli/types.h>
|
||||
#include "./bit_cost.h" /* BrotliPopulationCost */
|
||||
#include "./fast_log.h"
|
||||
#include "./histogram.h"
|
||||
#include "./memory.h"
|
||||
#include "./port.h"
|
||||
#include "../common/platform.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
|
||||
|
||||
@@ -9,10 +9,9 @@
|
||||
#ifndef BROTLI_ENC_CLUSTER_H_
|
||||
#define BROTLI_ENC_CLUSTER_H_
|
||||
|
||||
#include <brotli/types.h>
|
||||
#include "./histogram.h"
|
||||
#include "./memory.h"
|
||||
#include "./port.h"
|
||||
#include "../common/platform.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
|
||||
@@ -10,23 +10,23 @@
|
||||
#define BROTLI_ENC_COMMAND_H_
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include <brotli/port.h>
|
||||
#include <brotli/types.h>
|
||||
#include "./fast_log.h"
|
||||
#include "./prefix.h"
|
||||
#include "../common/platform.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) {
|
||||
@@ -61,21 +61,21 @@ static BROTLI_INLINE uint16_t GetCopyLengthCode(size_t copylen) {
|
||||
static BROTLI_INLINE uint16_t CombineLengthCodes(
|
||||
uint16_t inscode, uint16_t copycode, BROTLI_BOOL use_last_distance) {
|
||||
uint16_t bits64 =
|
||||
(uint16_t)((copycode & 0x7u) | ((inscode & 0x7u) << 3));
|
||||
if (use_last_distance && inscode < 8 && copycode < 16) {
|
||||
return (copycode < 8) ? bits64 : (bits64 | 64);
|
||||
(uint16_t)((copycode & 0x7u) | ((inscode & 0x7u) << 3u));
|
||||
if (use_last_distance && inscode < 8u && copycode < 16u) {
|
||||
return (copycode < 8u) ? bits64 : (bits64 | 64u);
|
||||
} else {
|
||||
/* Specification: 5 Encoding of ... (last table) */
|
||||
/* offset = 2 * index, where index is in range [0..8] */
|
||||
int offset = 2 * ((copycode >> 3) + 3 * (inscode >> 3));
|
||||
uint32_t offset = 2u * ((copycode >> 3u) + 3u * (inscode >> 3u));
|
||||
/* All values in specification are K * 64,
|
||||
where K = [2, 3, 6, 4, 5, 8, 7, 9, 10],
|
||||
i + 1 = [1, 2, 3, 4, 5, 6, 7, 8, 9],
|
||||
K - i - 1 = [1, 1, 3, 0, 0, 2, 0, 1, 2] = D.
|
||||
All values in D require only 2 bits to encode.
|
||||
Magic constant is shifted 6 bits left, to avoid final multiplication. */
|
||||
offset = (offset << 5) + 0x40 + ((0x520D40 >> offset) & 0xC0);
|
||||
return (uint16_t)offset | bits64;
|
||||
offset = (offset << 5u) + 0x40u + ((0x520D40u >> offset) & 0xC0u);
|
||||
return (uint16_t)(offset | bits64);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,70 +88,78 @@ 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 {
|
||||
uint32_t insert_len_;
|
||||
/* Stores copy_len in low 24 bits and copy_len XOR copy_code in high 8 bit. */
|
||||
/* Stores copy_len in low 25 bits and copy_code - copy_len in high 7 bit. */
|
||||
uint32_t copy_len_;
|
||||
/* Stores distance extra bits. */
|
||||
uint32_t dist_extra_;
|
||||
uint16_t cmd_prefix_;
|
||||
/* Stores distance code in low 10 bits
|
||||
and number of extra bits in high 6 bits. */
|
||||
uint16_t dist_prefix_;
|
||||
} Command;
|
||||
|
||||
/* distance_code is e.g. 0 for same-as-last short code, or 16 for offset 1. */
|
||||
static BROTLI_INLINE void InitCommand(Command* self, size_t insertlen,
|
||||
static BROTLI_INLINE void InitCommand(Command* self,
|
||||
const BrotliDistanceParams* dist, size_t insertlen,
|
||||
size_t copylen, int copylen_code_delta, size_t distance_code) {
|
||||
/* Don't rely on signed int representation, use honest casts. */
|
||||
uint32_t delta = (uint8_t)((int8_t)copylen_code_delta);
|
||||
self->insert_len_ = (uint32_t)insertlen;
|
||||
self->copy_len_ = (uint32_t)(copylen | (delta << 24));
|
||||
self->copy_len_ = (uint32_t)(copylen | (delta << 25));
|
||||
/* The distance prefix and extra bits are stored in this Command as if
|
||||
npostfix and ndirect were 0, they are only recomputed later after the
|
||||
clustering if needed. */
|
||||
PrefixEncodeCopyDistance(
|
||||
distance_code, 0, 0, &self->dist_prefix_, &self->dist_extra_);
|
||||
distance_code, dist->num_direct_distance_codes,
|
||||
dist->distance_postfix_bits, &self->dist_prefix_, &self->dist_extra_);
|
||||
GetLengthCode(
|
||||
insertlen, (size_t)((int)copylen + copylen_code_delta),
|
||||
TO_BROTLI_BOOL(self->dist_prefix_ == 0), &self->cmd_prefix_);
|
||||
TO_BROTLI_BOOL((self->dist_prefix_ & 0x3FF) == 0), &self->cmd_prefix_);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void InitInsertCommand(Command* self, size_t insertlen) {
|
||||
self->insert_len_ = (uint32_t)insertlen;
|
||||
self->copy_len_ = 4 << 24;
|
||||
self->copy_len_ = 4 << 25;
|
||||
self->dist_extra_ = 0;
|
||||
self->dist_prefix_ = BROTLI_NUM_DISTANCE_SHORT_CODES;
|
||||
GetLengthCode(insertlen, 4, BROTLI_FALSE, &self->cmd_prefix_);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE uint32_t CommandRestoreDistanceCode(const Command* self) {
|
||||
if (self->dist_prefix_ < BROTLI_NUM_DISTANCE_SHORT_CODES) {
|
||||
return self->dist_prefix_;
|
||||
static BROTLI_INLINE uint32_t CommandRestoreDistanceCode(
|
||||
const Command* self, const BrotliDistanceParams* dist) {
|
||||
if ((self->dist_prefix_ & 0x3FFu) <
|
||||
BROTLI_NUM_DISTANCE_SHORT_CODES + dist->num_direct_distance_codes) {
|
||||
return self->dist_prefix_ & 0x3FFu;
|
||||
} else {
|
||||
uint32_t nbits = self->dist_extra_ >> 24;
|
||||
uint32_t extra = self->dist_extra_ & 0xffffff;
|
||||
/* It is assumed that the distance was first encoded with NPOSTFIX = 0 and
|
||||
NDIRECT = 0, so the code itself is of this form:
|
||||
BROTLI_NUM_DISTANCE_SHORT_CODES + 2 * (nbits - 1) + prefix_bit
|
||||
Therefore, the following expression results in (2 + prefix_bit). */
|
||||
uint32_t prefix =
|
||||
self->dist_prefix_ + 4u - BROTLI_NUM_DISTANCE_SHORT_CODES - 2u * nbits;
|
||||
/* Subtract 4 for offset (Chapter 4.) and
|
||||
increase by BROTLI_NUM_DISTANCE_SHORT_CODES - 1 */
|
||||
return (prefix << nbits) + extra + BROTLI_NUM_DISTANCE_SHORT_CODES - 4u;
|
||||
uint32_t dcode = self->dist_prefix_ & 0x3FFu;
|
||||
uint32_t nbits = self->dist_prefix_ >> 10;
|
||||
uint32_t extra = self->dist_extra_;
|
||||
uint32_t postfix_mask = (1U << dist->distance_postfix_bits) - 1U;
|
||||
uint32_t hcode = (dcode - dist->num_direct_distance_codes -
|
||||
BROTLI_NUM_DISTANCE_SHORT_CODES) >>
|
||||
dist->distance_postfix_bits;
|
||||
uint32_t lcode = (dcode - dist->num_direct_distance_codes -
|
||||
BROTLI_NUM_DISTANCE_SHORT_CODES) & postfix_mask;
|
||||
uint32_t offset = ((2U + (hcode & 1U)) << nbits) - 4U;
|
||||
return ((offset + extra) << dist->distance_postfix_bits) + lcode +
|
||||
dist->num_direct_distance_codes + BROTLI_NUM_DISTANCE_SHORT_CODES;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,12 +173,13 @@ static BROTLI_INLINE uint32_t CommandDistanceContext(const Command* self) {
|
||||
}
|
||||
|
||||
static BROTLI_INLINE uint32_t CommandCopyLen(const Command* self) {
|
||||
return self->copy_len_ & 0xFFFFFF;
|
||||
return self->copy_len_ & 0x1FFFFFF;
|
||||
}
|
||||
|
||||
static BROTLI_INLINE uint32_t CommandCopyLenCode(const Command* self) {
|
||||
int32_t delta = (int8_t)((uint8_t)(self->copy_len_ >> 24));
|
||||
return (uint32_t)((int32_t)(self->copy_len_ & 0xFFFFFF) + delta);
|
||||
uint32_t modifier = self->copy_len_ >> 25;
|
||||
int32_t delta = (int8_t)((uint8_t)(modifier | ((modifier & 0x40) << 1)));
|
||||
return (uint32_t)((int32_t)(self->copy_len_ & 0x1FFFFFF) + delta);
|
||||
}
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
|
||||
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,20 +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 <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 "./port.h"
|
||||
#include "./write_bits.h"
|
||||
|
||||
#include "../common/platform.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" {
|
||||
@@ -33,23 +29,15 @@ 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_LOAD64(p) << 24) * kHashMul32;
|
||||
const uint64_t h = (BROTLI_UNALIGNED_LOAD64LE(p) << 24) * kHashMul32;
|
||||
return (uint32_t)(h >> shift);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE uint32_t HashBytesAtOffset(
|
||||
uint64_t v, int offset, size_t shift) {
|
||||
assert(offset >= 0);
|
||||
assert(offset <= 3);
|
||||
BROTLI_DCHECK(offset >= 0);
|
||||
BROTLI_DCHECK(offset <= 3);
|
||||
{
|
||||
const uint64_t h = ((v >> (8 * offset)) << 24) * kHashMul32;
|
||||
return (uint32_t)(h >> shift);
|
||||
@@ -58,7 +46,7 @@ static BROTLI_INLINE uint32_t HashBytesAtOffset(
|
||||
|
||||
static BROTLI_INLINE BROTLI_BOOL IsMatch(const uint8_t* p1, const uint8_t* p2) {
|
||||
return TO_BROTLI_BOOL(
|
||||
BROTLI_UNALIGNED_LOAD32(p1) == BROTLI_UNALIGNED_LOAD32(p2) &&
|
||||
BrotliUnalignedRead32(p1) == BrotliUnalignedRead32(p2) &&
|
||||
p1[4] == p2[4]);
|
||||
}
|
||||
|
||||
@@ -70,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]];
|
||||
@@ -109,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) {
|
||||
@@ -125,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 */
|
||||
@@ -203,7 +195,7 @@ static BROTLI_INLINE void EmitInsertLen(size_t insertlen,
|
||||
} else {
|
||||
BrotliWriteBits(depth[61], bits[61], storage_ix, storage);
|
||||
BrotliWriteBits(12, insertlen - 2114, storage_ix, storage);
|
||||
++histo[21];
|
||||
++histo[61];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,11 +208,11 @@ static BROTLI_INLINE void EmitLongInsertLen(size_t insertlen,
|
||||
if (insertlen < 22594) {
|
||||
BrotliWriteBits(depth[62], bits[62], storage_ix, storage);
|
||||
BrotliWriteBits(14, insertlen - 6210, storage_ix, storage);
|
||||
++histo[22];
|
||||
++histo[62];
|
||||
} else {
|
||||
BrotliWriteBits(depth[63], bits[63], storage_ix, storage);
|
||||
BrotliWriteBits(24, insertlen - 22594, storage_ix, storage);
|
||||
++histo[23];
|
||||
++histo[63];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -252,7 +244,7 @@ static BROTLI_INLINE void EmitCopyLen(size_t copylen,
|
||||
} else {
|
||||
BrotliWriteBits(depth[39], bits[39], storage_ix, storage);
|
||||
BrotliWriteBits(24, copylen - 2118, storage_ix, storage);
|
||||
++histo[47];
|
||||
++histo[39];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -294,7 +286,7 @@ static BROTLI_INLINE void EmitCopyLenLastDistance(size_t copylen,
|
||||
BrotliWriteBits(depth[39], bits[39], storage_ix, storage);
|
||||
BrotliWriteBits(24, copylen - 2120, storage_ix, storage);
|
||||
BrotliWriteBits(depth[64], bits[64], storage_ix, storage);
|
||||
++histo[47];
|
||||
++histo[39];
|
||||
++histo[64];
|
||||
}
|
||||
}
|
||||
@@ -344,7 +336,7 @@ static void BrotliStoreMetaBlockHeader(
|
||||
}
|
||||
|
||||
static void UpdateBits(size_t n_bits, uint32_t bits, size_t pos,
|
||||
uint8_t *array) {
|
||||
uint8_t* array) {
|
||||
while (n_bits > 0) {
|
||||
size_t byte_pos = pos >> 3;
|
||||
size_t n_unchanged_bits = pos & 7;
|
||||
@@ -370,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]];
|
||||
}
|
||||
@@ -414,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,
|
||||
@@ -424,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
|
||||
@@ -452,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;
|
||||
@@ -467,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;
|
||||
@@ -522,12 +514,12 @@ static BROTLI_INLINE void BrotliCompressFragmentFastImpl(
|
||||
|
||||
const uint8_t* next_ip = ip;
|
||||
const uint8_t* candidate;
|
||||
assert(next_emit < ip);
|
||||
BROTLI_DCHECK(next_emit < ip);
|
||||
trawl:
|
||||
do {
|
||||
uint32_t hash = next_hash;
|
||||
uint32_t bytes_between_hash_lookups = skip++ >> 5;
|
||||
assert(hash == Hash(next_ip, shift));
|
||||
BROTLI_DCHECK(hash == Hash(next_ip, shift));
|
||||
ip = next_ip;
|
||||
next_ip = ip + bytes_between_hash_lookups;
|
||||
if (BROTLI_PREDICT_FALSE(next_ip > ip_limit)) {
|
||||
@@ -542,8 +534,8 @@ trawl:
|
||||
}
|
||||
}
|
||||
candidate = base_ip + table[hash];
|
||||
assert(candidate >= base_ip);
|
||||
assert(candidate < ip);
|
||||
BROTLI_DCHECK(candidate >= base_ip);
|
||||
BROTLI_DCHECK(candidate < ip);
|
||||
|
||||
table[hash] = (int)(ip - base_ip);
|
||||
} while (BROTLI_PREDICT_TRUE(!IsMatch(ip, candidate)));
|
||||
@@ -566,7 +558,9 @@ trawl:
|
||||
int distance = (int)(base - candidate); /* > 0 */
|
||||
size_t insert = (size_t)(base - next_emit);
|
||||
ip += matched;
|
||||
assert(0 == memcmp(base, candidate, 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,
|
||||
storage_ix, storage);
|
||||
@@ -594,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)) {
|
||||
@@ -603,7 +603,7 @@ trawl:
|
||||
compression we first update "table" with the hashes of some positions
|
||||
within the last copy. */
|
||||
{
|
||||
uint64_t input_bytes = BROTLI_UNALIGNED_LOAD64(ip - 3);
|
||||
uint64_t input_bytes = BROTLI_UNALIGNED_LOAD64LE(ip - 3);
|
||||
uint32_t prev_hash = HashBytesAtOffset(input_bytes, 0, shift);
|
||||
uint32_t cur_hash = HashBytesAtOffset(input_bytes, 3, shift);
|
||||
table[prev_hash] = (int)(ip - base_ip - 3);
|
||||
@@ -626,11 +626,15 @@ trawl:
|
||||
if (ip - candidate > MAX_DISTANCE) break;
|
||||
ip += matched;
|
||||
last_distance = (int)(base - candidate); /* > 0 */
|
||||
assert(0 == memcmp(base, candidate, matched));
|
||||
BROTLI_DCHECK(0 == memcmp(base, candidate, matched));
|
||||
EmitCopyLen(matched, cmd_depth, cmd_bits, cmd_histo,
|
||||
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)) {
|
||||
@@ -640,7 +644,7 @@ trawl:
|
||||
compression we first update "table" with the hashes of some positions
|
||||
within the last copy. */
|
||||
{
|
||||
uint64_t input_bytes = BROTLI_UNALIGNED_LOAD64(ip - 3);
|
||||
uint64_t input_bytes = BROTLI_UNALIGNED_LOAD64LE(ip - 3);
|
||||
uint32_t prev_hash = HashBytesAtOffset(input_bytes, 0, shift);
|
||||
uint32_t cur_hash = HashBytesAtOffset(input_bytes, 3, shift);
|
||||
table[prev_hash] = (int)(ip - base_ip - 3);
|
||||
@@ -659,7 +663,7 @@ trawl:
|
||||
}
|
||||
|
||||
emit_remainder:
|
||||
assert(next_emit <= ip_end);
|
||||
BROTLI_DCHECK(next_emit <= ip_end);
|
||||
input += block_size;
|
||||
input_size -= block_size;
|
||||
block_size = BROTLI_MIN(size_t, input_size, kMergeBlockSize);
|
||||
@@ -668,8 +672,8 @@ trawl:
|
||||
last insert-only command. */
|
||||
if (input_size > 0 &&
|
||||
total_block_size + block_size <= (1 << 20) &&
|
||||
ShouldMergeBlock(input, block_size, lit_depth)) {
|
||||
assert(total_block_size > (1 << 16));
|
||||
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
|
||||
nibbles. */
|
||||
@@ -681,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);
|
||||
@@ -712,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -733,26 +736,23 @@ 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);
|
||||
|
||||
if (input_size == 0) {
|
||||
assert(is_last);
|
||||
BROTLI_DCHECK(is_last);
|
||||
BrotliWriteBits(1, 1, storage_ix, storage); /* islast */
|
||||
BrotliWriteBits(1, 1, storage_ix, storage); /* isempty */
|
||||
*storage_ix = (*storage_ix + 7u) & ~7u;
|
||||
@@ -763,12 +763,11 @@ 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_
|
||||
default: assert(0); break;
|
||||
default: BROTLI_DCHECK(0); break;
|
||||
}
|
||||
|
||||
/* If output is larger than single uncompressed block, rewrite it. */
|
||||
|
||||
@@ -12,14 +12,41 @@
|
||||
#ifndef BROTLI_ENC_COMPRESS_FRAGMENT_H_
|
||||
#define BROTLI_ENC_COMPRESS_FRAGMENT_H_
|
||||
|
||||
#include <brotli/types.h>
|
||||
#include "./memory.h"
|
||||
#include "./port.h"
|
||||
#include "../common/constants.h"
|
||||
#include "../common/platform.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,21 +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 <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 "./port.h"
|
||||
#include "./write_bits.h"
|
||||
|
||||
#include "../common/platform.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" {
|
||||
@@ -32,85 +28,80 @@ 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_LOAD64(p) << 16) * kHashMul32;
|
||||
static BROTLI_INLINE uint32_t Hash(const uint8_t* p,
|
||||
size_t shift, size_t length) {
|
||||
const uint64_t h =
|
||||
(BROTLI_UNALIGNED_LOAD64LE(p) << ((8 - length) * 8)) * kHashMul32;
|
||||
return (uint32_t)(h >> shift);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE uint32_t HashBytesAtOffset(
|
||||
uint64_t v, int offset, size_t shift) {
|
||||
assert(offset >= 0);
|
||||
assert(offset <= 2);
|
||||
static BROTLI_INLINE uint32_t HashBytesAtOffset(uint64_t v, size_t offset,
|
||||
size_t shift, size_t length) {
|
||||
BROTLI_DCHECK(offset <= 8 - length);
|
||||
{
|
||||
const uint64_t h = ((v >> (8 * offset)) << 16) * kHashMul32;
|
||||
const uint64_t h = ((v >> (8 * offset)) << ((8 - length) * 8)) * kHashMul32;
|
||||
return (uint32_t)(h >> shift);
|
||||
}
|
||||
}
|
||||
|
||||
static BROTLI_INLINE BROTLI_BOOL IsMatch(const uint8_t* p1, const uint8_t* p2) {
|
||||
return TO_BROTLI_BOOL(
|
||||
BROTLI_UNALIGNED_LOAD32(p1) == BROTLI_UNALIGNED_LOAD32(p2) &&
|
||||
p1[4] == p2[4] &&
|
||||
p1[5] == p2[5]);
|
||||
static BROTLI_INLINE BROTLI_BOOL IsMatch(const uint8_t* p1, const uint8_t* p2,
|
||||
size_t length) {
|
||||
if (BrotliUnalignedRead32(p1) == BrotliUnalignedRead32(p2)) {
|
||||
if (length == 4) return BROTLI_TRUE;
|
||||
return TO_BROTLI_BOOL(p1[4] == p2[4] && p1[5] == p2[5]);
|
||||
}
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
|
||||
/* 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(
|
||||
@@ -236,7 +227,8 @@ static void BrotliStoreMetaBlockHeader(
|
||||
|
||||
static BROTLI_INLINE void CreateCommands(const uint8_t* input,
|
||||
size_t block_size, size_t input_size, const uint8_t* base_ip, int* table,
|
||||
size_t table_bits, uint8_t** literals, uint32_t** commands) {
|
||||
size_t table_bits, size_t min_match,
|
||||
uint8_t** literals, uint32_t** commands) {
|
||||
/* "ip" is the input pointer. */
|
||||
const uint8_t* ip = input;
|
||||
const size_t shift = 64u - table_bits;
|
||||
@@ -248,19 +240,18 @@ static BROTLI_INLINE void CreateCommands(const uint8_t* input,
|
||||
|
||||
int last_distance = -1;
|
||||
const size_t kInputMarginBytes = BROTLI_WINDOW_GAP;
|
||||
const size_t kMinMatchLen = 6;
|
||||
|
||||
if (BROTLI_PREDICT_TRUE(block_size >= kInputMarginBytes)) {
|
||||
/* For the last block, we need to keep a 16 bytes margin so that we can be
|
||||
sure that all distances are at most window size - 16.
|
||||
For all other blocks, we only need to keep a margin of 5 bytes so that
|
||||
we don't go over the block size with a copy. */
|
||||
const size_t len_limit = BROTLI_MIN(size_t, block_size - kMinMatchLen,
|
||||
const size_t len_limit = BROTLI_MIN(size_t, block_size - min_match,
|
||||
input_size - kInputMarginBytes);
|
||||
const uint8_t* ip_limit = input + len_limit;
|
||||
|
||||
uint32_t next_hash;
|
||||
for (next_hash = Hash(++ip, shift); ; ) {
|
||||
for (next_hash = Hash(++ip, shift, min_match); ; ) {
|
||||
/* Step 1: Scan forward in the input looking for a 6-byte-long match.
|
||||
If we get close to exhausting the input then goto emit_remainder.
|
||||
|
||||
@@ -281,31 +272,31 @@ static BROTLI_INLINE void CreateCommands(const uint8_t* input,
|
||||
const uint8_t* next_ip = ip;
|
||||
const uint8_t* candidate;
|
||||
|
||||
assert(next_emit < ip);
|
||||
BROTLI_DCHECK(next_emit < ip);
|
||||
trawl:
|
||||
do {
|
||||
uint32_t hash = next_hash;
|
||||
uint32_t bytes_between_hash_lookups = skip++ >> 5;
|
||||
ip = next_ip;
|
||||
assert(hash == Hash(ip, shift));
|
||||
BROTLI_DCHECK(hash == Hash(ip, shift, min_match));
|
||||
next_ip = ip + bytes_between_hash_lookups;
|
||||
if (BROTLI_PREDICT_FALSE(next_ip > ip_limit)) {
|
||||
goto emit_remainder;
|
||||
}
|
||||
next_hash = Hash(next_ip, shift);
|
||||
next_hash = Hash(next_ip, shift, min_match);
|
||||
candidate = ip - last_distance;
|
||||
if (IsMatch(ip, candidate)) {
|
||||
if (IsMatch(ip, candidate, min_match)) {
|
||||
if (BROTLI_PREDICT_TRUE(candidate < ip)) {
|
||||
table[hash] = (int)(ip - base_ip);
|
||||
break;
|
||||
}
|
||||
}
|
||||
candidate = base_ip + table[hash];
|
||||
assert(candidate >= base_ip);
|
||||
assert(candidate < ip);
|
||||
BROTLI_DCHECK(candidate >= base_ip);
|
||||
BROTLI_DCHECK(candidate < ip);
|
||||
|
||||
table[hash] = (int)(ip - base_ip);
|
||||
} while (BROTLI_PREDICT_TRUE(!IsMatch(ip, candidate)));
|
||||
} while (BROTLI_PREDICT_TRUE(!IsMatch(ip, candidate, min_match)));
|
||||
|
||||
/* Check copy distance. If candidate is not feasible, continue search.
|
||||
Checking is done outside of hot loop to reduce overhead. */
|
||||
@@ -320,13 +311,16 @@ trawl:
|
||||
/* We have a 6-byte match at ip, and we need to emit bytes in
|
||||
[next_emit, ip). */
|
||||
const uint8_t* base = ip;
|
||||
size_t matched = 6 + FindMatchLengthWithLimit(
|
||||
candidate + 6, ip + 6, (size_t)(ip_end - ip) - 6);
|
||||
size_t matched = min_match + FindMatchLengthWithLimit(
|
||||
candidate + min_match, ip + min_match,
|
||||
(size_t)(ip_end - ip) - min_match);
|
||||
int distance = (int)(base - candidate); /* > 0 */
|
||||
int insert = (int)(base - next_emit);
|
||||
ip += matched;
|
||||
assert(0 == memcmp(base, candidate, 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) {
|
||||
@@ -337,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)) {
|
||||
@@ -346,37 +346,56 @@ trawl:
|
||||
/* We could immediately start working at ip now, but to improve
|
||||
compression we first update "table" with the hashes of some
|
||||
positions within the last copy. */
|
||||
uint64_t input_bytes = BROTLI_UNALIGNED_LOAD64(ip - 5);
|
||||
uint32_t prev_hash = HashBytesAtOffset(input_bytes, 0, shift);
|
||||
uint64_t input_bytes;
|
||||
uint32_t cur_hash;
|
||||
table[prev_hash] = (int)(ip - base_ip - 5);
|
||||
prev_hash = HashBytesAtOffset(input_bytes, 1, shift);
|
||||
table[prev_hash] = (int)(ip - base_ip - 4);
|
||||
prev_hash = HashBytesAtOffset(input_bytes, 2, shift);
|
||||
table[prev_hash] = (int)(ip - base_ip - 3);
|
||||
input_bytes = BROTLI_UNALIGNED_LOAD64(ip - 2);
|
||||
cur_hash = HashBytesAtOffset(input_bytes, 2, shift);
|
||||
prev_hash = HashBytesAtOffset(input_bytes, 0, shift);
|
||||
table[prev_hash] = (int)(ip - base_ip - 2);
|
||||
prev_hash = HashBytesAtOffset(input_bytes, 1, shift);
|
||||
table[prev_hash] = (int)(ip - base_ip - 1);
|
||||
uint32_t prev_hash;
|
||||
if (min_match == 4) {
|
||||
input_bytes = BROTLI_UNALIGNED_LOAD64LE(ip - 3);
|
||||
cur_hash = HashBytesAtOffset(input_bytes, 3, shift, min_match);
|
||||
prev_hash = HashBytesAtOffset(input_bytes, 0, shift, min_match);
|
||||
table[prev_hash] = (int)(ip - base_ip - 3);
|
||||
prev_hash = HashBytesAtOffset(input_bytes, 1, shift, min_match);
|
||||
table[prev_hash] = (int)(ip - base_ip - 2);
|
||||
prev_hash = HashBytesAtOffset(input_bytes, 0, shift, min_match);
|
||||
table[prev_hash] = (int)(ip - base_ip - 1);
|
||||
} else {
|
||||
input_bytes = BROTLI_UNALIGNED_LOAD64LE(ip - 5);
|
||||
prev_hash = HashBytesAtOffset(input_bytes, 0, shift, min_match);
|
||||
table[prev_hash] = (int)(ip - base_ip - 5);
|
||||
prev_hash = HashBytesAtOffset(input_bytes, 1, shift, min_match);
|
||||
table[prev_hash] = (int)(ip - base_ip - 4);
|
||||
prev_hash = HashBytesAtOffset(input_bytes, 2, shift, min_match);
|
||||
table[prev_hash] = (int)(ip - base_ip - 3);
|
||||
input_bytes = BROTLI_UNALIGNED_LOAD64LE(ip - 2);
|
||||
cur_hash = HashBytesAtOffset(input_bytes, 2, shift, min_match);
|
||||
prev_hash = HashBytesAtOffset(input_bytes, 0, shift, min_match);
|
||||
table[prev_hash] = (int)(ip - base_ip - 2);
|
||||
prev_hash = HashBytesAtOffset(input_bytes, 1, shift, min_match);
|
||||
table[prev_hash] = (int)(ip - base_ip - 1);
|
||||
}
|
||||
|
||||
candidate = base_ip + table[cur_hash];
|
||||
table[cur_hash] = (int)(ip - base_ip);
|
||||
}
|
||||
}
|
||||
|
||||
while (ip - candidate <= MAX_DISTANCE && IsMatch(ip, candidate)) {
|
||||
while (ip - candidate <= MAX_DISTANCE &&
|
||||
IsMatch(ip, candidate, min_match)) {
|
||||
/* We have a 6-byte match at ip, and no need to emit any
|
||||
literal bytes prior to ip. */
|
||||
const uint8_t* base = ip;
|
||||
size_t matched = 6 + FindMatchLengthWithLimit(
|
||||
candidate + 6, ip + 6, (size_t)(ip_end - ip) - 6);
|
||||
size_t matched = min_match + FindMatchLengthWithLimit(
|
||||
candidate + min_match, ip + min_match,
|
||||
(size_t)(ip_end - ip) - min_match);
|
||||
ip += matched;
|
||||
last_distance = (int)(base - candidate); /* > 0 */
|
||||
assert(0 == memcmp(base, candidate, matched));
|
||||
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)) {
|
||||
@@ -386,100 +405,114 @@ trawl:
|
||||
/* We could immediately start working at ip now, but to improve
|
||||
compression we first update "table" with the hashes of some
|
||||
positions within the last copy. */
|
||||
uint64_t input_bytes = BROTLI_UNALIGNED_LOAD64(ip - 5);
|
||||
uint32_t prev_hash = HashBytesAtOffset(input_bytes, 0, shift);
|
||||
uint64_t input_bytes;
|
||||
uint32_t cur_hash;
|
||||
table[prev_hash] = (int)(ip - base_ip - 5);
|
||||
prev_hash = HashBytesAtOffset(input_bytes, 1, shift);
|
||||
table[prev_hash] = (int)(ip - base_ip - 4);
|
||||
prev_hash = HashBytesAtOffset(input_bytes, 2, shift);
|
||||
table[prev_hash] = (int)(ip - base_ip - 3);
|
||||
input_bytes = BROTLI_UNALIGNED_LOAD64(ip - 2);
|
||||
cur_hash = HashBytesAtOffset(input_bytes, 2, shift);
|
||||
prev_hash = HashBytesAtOffset(input_bytes, 0, shift);
|
||||
table[prev_hash] = (int)(ip - base_ip - 2);
|
||||
prev_hash = HashBytesAtOffset(input_bytes, 1, shift);
|
||||
table[prev_hash] = (int)(ip - base_ip - 1);
|
||||
uint32_t prev_hash;
|
||||
if (min_match == 4) {
|
||||
input_bytes = BROTLI_UNALIGNED_LOAD64LE(ip - 3);
|
||||
cur_hash = HashBytesAtOffset(input_bytes, 3, shift, min_match);
|
||||
prev_hash = HashBytesAtOffset(input_bytes, 0, shift, min_match);
|
||||
table[prev_hash] = (int)(ip - base_ip - 3);
|
||||
prev_hash = HashBytesAtOffset(input_bytes, 1, shift, min_match);
|
||||
table[prev_hash] = (int)(ip - base_ip - 2);
|
||||
prev_hash = HashBytesAtOffset(input_bytes, 2, shift, min_match);
|
||||
table[prev_hash] = (int)(ip - base_ip - 1);
|
||||
} else {
|
||||
input_bytes = BROTLI_UNALIGNED_LOAD64LE(ip - 5);
|
||||
prev_hash = HashBytesAtOffset(input_bytes, 0, shift, min_match);
|
||||
table[prev_hash] = (int)(ip - base_ip - 5);
|
||||
prev_hash = HashBytesAtOffset(input_bytes, 1, shift, min_match);
|
||||
table[prev_hash] = (int)(ip - base_ip - 4);
|
||||
prev_hash = HashBytesAtOffset(input_bytes, 2, shift, min_match);
|
||||
table[prev_hash] = (int)(ip - base_ip - 3);
|
||||
input_bytes = BROTLI_UNALIGNED_LOAD64LE(ip - 2);
|
||||
cur_hash = HashBytesAtOffset(input_bytes, 2, shift, min_match);
|
||||
prev_hash = HashBytesAtOffset(input_bytes, 0, shift, min_match);
|
||||
table[prev_hash] = (int)(ip - base_ip - 2);
|
||||
prev_hash = HashBytesAtOffset(input_bytes, 1, shift, min_match);
|
||||
table[prev_hash] = (int)(ip - base_ip - 1);
|
||||
}
|
||||
|
||||
candidate = base_ip + table[cur_hash];
|
||||
table[cur_hash] = (int)(ip - base_ip);
|
||||
}
|
||||
}
|
||||
|
||||
next_hash = Hash(++ip, shift);
|
||||
next_hash = Hash(++ip, shift, min_match);
|
||||
}
|
||||
}
|
||||
|
||||
emit_remainder:
|
||||
assert(next_emit <= ip_end);
|
||||
BROTLI_DCHECK(next_emit <= ip_end);
|
||||
/* Emit the remaining bytes as literals. */
|
||||
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;
|
||||
assert(code < 128);
|
||||
++cmd_histo[code];
|
||||
BROTLI_DCHECK(code < 128);
|
||||
++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;
|
||||
assert(code < 128);
|
||||
BrotliWriteBits(cmd_depths[code], cmd_bits[code], storage_ix, storage);
|
||||
BROTLI_DCHECK(code < 128);
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -490,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -524,9 +558,10 @@ 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* storage_ix, uint8_t* storage) {
|
||||
int* table, size_t table_bits, size_t min_match,
|
||||
size_t* storage_ix, uint8_t* storage) {
|
||||
/* Save the start of the first block for position and distance computations.
|
||||
*/
|
||||
const uint8_t* base_ip = input;
|
||||
@@ -538,17 +573,16 @@ static BROTLI_INLINE void BrotliCompressFragmentTwoPassImpl(
|
||||
uint32_t* commands = command_buf;
|
||||
uint8_t* literals = literal_buf;
|
||||
size_t num_literals;
|
||||
CreateCommands(input, block_size, input_size, base_ip, table, table_bits,
|
||||
&literals, &commands);
|
||||
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.
|
||||
@@ -565,17 +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) { \
|
||||
BrotliCompressFragmentTwoPassImpl(m, input, input_size, is_last, command_buf,\
|
||||
literal_buf, table, B, storage_ix, storage); \
|
||||
size_t min_match = (B <= 15) ? 4 : 6; \
|
||||
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;
|
||||
@@ -584,12 +619,12 @@ 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_)
|
||||
#undef CASE_
|
||||
default: assert(0); break;
|
||||
default: BROTLI_DCHECK(0); break;
|
||||
}
|
||||
|
||||
/* If output is larger than single uncompressed block, rewrite it. */
|
||||
|
||||
@@ -13,16 +13,32 @@
|
||||
#ifndef BROTLI_ENC_COMPRESS_FRAGMENT_TWO_PASS_H_
|
||||
#define BROTLI_ENC_COMPRESS_FRAGMENT_TWO_PASS_H_
|
||||
|
||||
#include <brotli/types.h>
|
||||
#include "./memory.h"
|
||||
#include "./port.h"
|
||||
#include "../common/constants.h"
|
||||
#include "../common/platform.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,
|
||||
|
||||
184
c/enc/context.h
184
c/enc/context.h
@@ -1,184 +0,0 @@
|
||||
/* Copyright 2013 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/* Functions to map previous bytes into a context id. */
|
||||
|
||||
#ifndef BROTLI_ENC_CONTEXT_H_
|
||||
#define BROTLI_ENC_CONTEXT_H_
|
||||
|
||||
#include <brotli/port.h>
|
||||
#include <brotli/types.h>
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Second-order context lookup table for UTF8 byte streams.
|
||||
|
||||
If p1 and p2 are the previous two bytes, we calculate the context as
|
||||
|
||||
context = kUTF8ContextLookup[p1] | kUTF8ContextLookup[p2 + 256].
|
||||
|
||||
If the previous two bytes are ASCII characters (i.e. < 128), this will be
|
||||
equivalent to
|
||||
|
||||
context = 4 * context1(p1) + context2(p2),
|
||||
|
||||
where context1 is based on the previous byte in the following way:
|
||||
|
||||
0 : non-ASCII control
|
||||
1 : \t, \n, \r
|
||||
2 : space
|
||||
3 : other punctuation
|
||||
4 : " '
|
||||
5 : %
|
||||
6 : ( < [ {
|
||||
7 : ) > ] }
|
||||
8 : , ; :
|
||||
9 : .
|
||||
10 : =
|
||||
11 : number
|
||||
12 : upper-case vowel
|
||||
13 : upper-case consonant
|
||||
14 : lower-case vowel
|
||||
15 : lower-case consonant
|
||||
|
||||
and context2 is based on the second last byte:
|
||||
|
||||
0 : control, space
|
||||
1 : punctuation
|
||||
2 : upper-case letter, number
|
||||
3 : lower-case letter
|
||||
|
||||
If the last byte is ASCII, and the second last byte is not (in a valid UTF8
|
||||
stream it will be a continuation byte, value between 128 and 191), the
|
||||
context is the same as if the second last byte was an ASCII control or space.
|
||||
|
||||
If the last byte is a UTF8 lead byte (value >= 192), then the next byte will
|
||||
be a continuation byte and the context id is 2 or 3 depending on the LSB of
|
||||
the last byte and to a lesser extent on the second last byte if it is ASCII.
|
||||
|
||||
If the last byte is a UTF8 continuation byte, the second last byte can be:
|
||||
- continuation byte: the next byte is probably ASCII or lead byte (assuming
|
||||
4-byte UTF8 characters are rare) and the context id is 0 or 1.
|
||||
- lead byte (192 - 207): next byte is ASCII or lead byte, context is 0 or 1
|
||||
- lead byte (208 - 255): next byte is continuation byte, context is 2 or 3
|
||||
|
||||
The possible value combinations of the previous two bytes, the range of
|
||||
context ids and the type of the next byte is summarized in the table below:
|
||||
|
||||
|--------\-----------------------------------------------------------------|
|
||||
| \ Last byte |
|
||||
| Second \---------------------------------------------------------------|
|
||||
| last byte \ ASCII | cont. byte | lead byte |
|
||||
| \ (0-127) | (128-191) | (192-) |
|
||||
|=============|===================|=====================|==================|
|
||||
| ASCII | next: ASCII/lead | not valid | next: cont. |
|
||||
| (0-127) | context: 4 - 63 | | context: 2 - 3 |
|
||||
|-------------|-------------------|---------------------|------------------|
|
||||
| cont. byte | next: ASCII/lead | next: ASCII/lead | next: cont. |
|
||||
| (128-191) | context: 4 - 63 | context: 0 - 1 | context: 2 - 3 |
|
||||
|-------------|-------------------|---------------------|------------------|
|
||||
| lead byte | not valid | next: ASCII/lead | not valid |
|
||||
| (192-207) | | context: 0 - 1 | |
|
||||
|-------------|-------------------|---------------------|------------------|
|
||||
| lead byte | not valid | next: cont. | not valid |
|
||||
| (208-) | | context: 2 - 3 | |
|
||||
|-------------|-------------------|---------------------|------------------|
|
||||
*/
|
||||
static const uint8_t kUTF8ContextLookup[512] = {
|
||||
/* 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,
|
||||
/* 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,
|
||||
/* UTF8 lead 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,
|
||||
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 lookup table for small signed integers. */
|
||||
static const uint8_t kSigned3BitContextLookup[] = {
|
||||
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,
|
||||
};
|
||||
|
||||
typedef enum ContextType {
|
||||
CONTEXT_LSB6 = 0,
|
||||
CONTEXT_MSB6 = 1,
|
||||
CONTEXT_UTF8 = 2,
|
||||
CONTEXT_SIGNED = 3
|
||||
} ContextType;
|
||||
|
||||
static BROTLI_INLINE uint8_t Context(uint8_t p1, uint8_t p2, ContextType mode) {
|
||||
switch (mode) {
|
||||
case CONTEXT_LSB6:
|
||||
return p1 & 0x3f;
|
||||
case CONTEXT_MSB6:
|
||||
return (uint8_t)(p1 >> 2);
|
||||
case CONTEXT_UTF8:
|
||||
return kUTF8ContextLookup[p1] | kUTF8ContextLookup[p2 + 256];
|
||||
case CONTEXT_SIGNED:
|
||||
return (uint8_t)((kSigned3BitContextLookup[p1] << 3) +
|
||||
kSigned3BitContextLookup[p2]);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* BROTLI_ENC_CONTEXT_H_ */
|
||||
1231
c/enc/dictionary_hash.c
Executable file → Normal file
1231
c/enc/dictionary_hash.c
Executable file → Normal file
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
1382
c/enc/encode.c
1382
c/enc/encode.c
File diff suppressed because it is too large
Load Diff
642
c/enc/encoder_dict.c
Normal file
642
c/enc/encoder_dict.c
Normal file
@@ -0,0 +1,642 @@
|
||||
/* 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 "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 <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
|
||||
|
||||
#define NUM_HASH_BITS 15u
|
||||
#define NUM_HASH_BUCKETS (1u << NUM_HASH_BITS)
|
||||
|
||||
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
|
||||
155
c/enc/encoder_dict.h
Normal file
155
c/enc/encoder_dict.h
Normal file
@@ -0,0 +1,155 @@
|
||||
/* 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_ENCODER_DICT_H_
|
||||
#define BROTLI_ENC_ENCODER_DICT_H_
|
||||
|
||||
#include "../common/dictionary.h"
|
||||
#include <brotli/shared_dictionary.h>
|
||||
#include "../common/platform.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_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;
|
||||
|
||||
/* 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" */
|
||||
#endif
|
||||
|
||||
#endif /* BROTLI_ENC_ENCODER_DICT_H_ */
|
||||
@@ -6,24 +6,23 @@
|
||||
|
||||
/* Entropy encoding (Huffman) utilities. */
|
||||
|
||||
#include "./entropy_encode.h"
|
||||
|
||||
#include <string.h> /* memset */
|
||||
#include "entropy_encode.h"
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./port.h"
|
||||
#include "../common/platform.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];
|
||||
int level = 0;
|
||||
int p = p0;
|
||||
assert(max_depth <= 15);
|
||||
BROTLI_DCHECK(max_depth <= 15);
|
||||
stack[0] = -1;
|
||||
while (BROTLI_TRUE) {
|
||||
if (pool[p].index_left_ >= 0) {
|
||||
@@ -66,11 +65,11 @@ static BROTLI_INLINE BROTLI_BOOL SortHuffmanTree(
|
||||
we are not planning to use this with extremely long blocks.
|
||||
|
||||
See http://en.wikipedia.org/wiki/Huffman_coding */
|
||||
void BrotliCreateHuffmanTree(const uint32_t *data,
|
||||
void BrotliCreateHuffmanTree(const uint32_t* data,
|
||||
const size_t length,
|
||||
const int tree_limit,
|
||||
HuffmanTree* tree,
|
||||
uint8_t *depth) {
|
||||
uint8_t* depth) {
|
||||
uint32_t count_limit;
|
||||
HuffmanTree sentinel;
|
||||
InitHuffmanTree(&sentinel, BROTLI_UINT32_MAX, -1, -1);
|
||||
@@ -165,7 +164,7 @@ static void BrotliWriteHuffmanTreeRepetitions(
|
||||
size_t* tree_size,
|
||||
uint8_t* tree,
|
||||
uint8_t* extra_bits_data) {
|
||||
assert(repetitions > 0);
|
||||
BROTLI_DCHECK(repetitions > 0);
|
||||
if (previous_value != value) {
|
||||
tree[*tree_size] = value;
|
||||
extra_bits_data[*tree_size] = 0;
|
||||
@@ -371,8 +370,8 @@ void BrotliOptimizeHuffmanCountsForRle(size_t length, uint32_t* counts,
|
||||
}
|
||||
|
||||
static void DecideOverRleUse(const uint8_t* depth, const size_t length,
|
||||
BROTLI_BOOL *use_rle_for_non_zero,
|
||||
BROTLI_BOOL *use_rle_for_zero) {
|
||||
BROTLI_BOOL* use_rle_for_non_zero,
|
||||
BROTLI_BOOL* use_rle_for_zero) {
|
||||
size_t total_reps_zero = 0;
|
||||
size_t total_reps_non_zero = 0;
|
||||
size_t count_reps_zero = 1;
|
||||
@@ -453,27 +452,28 @@ 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. */
|
||||
0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe,
|
||||
0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf
|
||||
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
|
||||
};
|
||||
size_t retval = kLut[bits & 0xf];
|
||||
size_t retval = kLut[bits & 0x0F];
|
||||
size_t i;
|
||||
for (i = 4; i < num_bits; i += 4) {
|
||||
retval <<= 4;
|
||||
bits = (uint16_t)(bits >> 4);
|
||||
retval |= kLut[bits & 0xf];
|
||||
retval |= kLut[bits & 0x0F];
|
||||
}
|
||||
retval >>= ((0 - num_bits) & 0x3);
|
||||
retval >>= ((0 - num_bits) & 0x03);
|
||||
return (uint16_t)retval;
|
||||
}
|
||||
|
||||
/* 0..15 are values for bits */
|
||||
#define MAX_HUFFMAN_BITS 16
|
||||
|
||||
void BrotliConvertBitDepthsToSymbols(const uint8_t *depth,
|
||||
void BrotliConvertBitDepthsToSymbols(const uint8_t* depth,
|
||||
size_t len,
|
||||
uint16_t *bits) {
|
||||
uint16_t* bits) {
|
||||
/* In Brotli, all bit depths are [1..15]
|
||||
0 bit depth means that the symbol does not exist. */
|
||||
uint16_t bl_count[MAX_HUFFMAN_BITS] = { 0 };
|
||||
|
||||
@@ -9,8 +9,7 @@
|
||||
#ifndef BROTLI_ENC_ENTROPY_ENCODE_H_
|
||||
#define BROTLI_ENC_ENTROPY_ENCODE_H_
|
||||
|
||||
#include <brotli/types.h>
|
||||
#include "./port.h"
|
||||
#include "../common/platform.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
@@ -46,11 +45,11 @@ BROTLI_INTERNAL BROTLI_BOOL BrotliSetDepth(
|
||||
be at least 2 * length + 1 long.
|
||||
|
||||
See http://en.wikipedia.org/wiki/Huffman_coding */
|
||||
BROTLI_INTERNAL void BrotliCreateHuffmanTree(const uint32_t *data,
|
||||
BROTLI_INTERNAL void BrotliCreateHuffmanTree(const uint32_t* data,
|
||||
const size_t length,
|
||||
const int tree_limit,
|
||||
HuffmanTree* tree,
|
||||
uint8_t *depth);
|
||||
uint8_t* depth);
|
||||
|
||||
/* Change the population counts in a way that the consequent
|
||||
Huffman tree compression, especially its RLE-part will be more
|
||||
@@ -66,22 +65,22 @@ 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);
|
||||
|
||||
/* Get the actual bit values for a tree of bit depths. */
|
||||
BROTLI_INTERNAL void BrotliConvertBitDepthsToSymbols(const uint8_t *depth,
|
||||
BROTLI_INTERNAL void BrotliConvertBitDepthsToSymbols(const uint8_t* depth,
|
||||
size_t len,
|
||||
uint16_t *bits);
|
||||
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;
|
||||
|
||||
@@ -10,19 +10,19 @@
|
||||
#define BROTLI_ENC_ENTROPY_ENCODE_STATIC_H_
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include <brotli/port.h>
|
||||
#include <brotli/types.h>
|
||||
#include "./write_bits.h"
|
||||
#include "../common/platform.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,24 +69,28 @@ 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,
|
||||
};
|
||||
|
||||
static BROTLI_INLINE void StoreStaticCodeLengthCode(
|
||||
size_t* storage_ix, uint8_t* storage) {
|
||||
BrotliWriteBits(
|
||||
40, BROTLI_MAKE_UINT64_T(0x0000ffU, 0x55555554U), storage_ix, storage);
|
||||
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,
|
||||
@@ -529,8 +537,9 @@ static const uint16_t kStaticDistanceCodeBits[64] = {
|
||||
|
||||
static BROTLI_INLINE void StoreStaticDistanceHuffmanTree(
|
||||
size_t* storage_ix, uint8_t* storage) {
|
||||
BrotliWriteBits(28, 0x0369dc03U, storage_ix, 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
@@ -11,16 +11,15 @@
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include <brotli/types.h>
|
||||
#include <brotli/port.h>
|
||||
#include "../common/platform.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static BROTLI_INLINE uint32_t Log2FloorNonZero(size_t n) {
|
||||
#if BROTLI_MODERN_COMPILER || __has_builtin(__builtin_clz)
|
||||
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++;
|
||||
@@ -28,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);
|
||||
|
||||
@@ -9,44 +9,34 @@
|
||||
#ifndef BROTLI_ENC_FIND_MATCH_LENGTH_H_
|
||||
#define BROTLI_ENC_FIND_MATCH_LENGTH_H_
|
||||
|
||||
#include <brotli/types.h>
|
||||
#include "./port.h"
|
||||
#include "../common/platform.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(IS_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_LOAD64(s2) ==
|
||||
BROTLI_UNALIGNED_LOAD64(s1 + matched))) {
|
||||
s2 += 8;
|
||||
matched += 8;
|
||||
} else {
|
||||
uint64_t x =
|
||||
BROTLI_UNALIGNED_LOAD64(s2) ^ BROTLI_UNALIGNED_LOAD64(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,
|
||||
@@ -60,8 +50,8 @@ static BROTLI_INLINE size_t FindMatchLengthWithLimit(const uint8_t* s1,
|
||||
the first non-matching bit and use that to calculate the total
|
||||
length of the match. */
|
||||
while (s2_ptr <= s2_limit - 4 &&
|
||||
BROTLI_UNALIGNED_LOAD32(s2_ptr) ==
|
||||
BROTLI_UNALIGNED_LOAD32(s1 + matched)) {
|
||||
BrotliUnalignedRead32(s2_ptr) ==
|
||||
BrotliUnalignedRead32(s1 + matched)) {
|
||||
s2_ptr += 4;
|
||||
matched += 4;
|
||||
}
|
||||
|
||||
594
c/enc/hash.h
594
c/enc/hash.h
@@ -10,47 +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 <brotli/types.h>
|
||||
#include "./fast_log.h"
|
||||
#include "./find_match_length.h"
|
||||
#include "./memory.h"
|
||||
#include "./port.h"
|
||||
#include "./quality.h"
|
||||
#include "./static_dict.h"
|
||||
#include "../common/platform.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
|
||||
*/
|
||||
typedef uint8_t* HasherHandle;
|
||||
|
||||
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
|
||||
|
||||
@@ -67,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_LOAD32(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) {
|
||||
@@ -146,32 +130,32 @@ static BROTLI_INLINE score_t BackwardReferencePenaltyUsingLastDistance(
|
||||
}
|
||||
|
||||
static BROTLI_INLINE BROTLI_BOOL TestStaticDictionaryItem(
|
||||
const BrotliDictionary* dictionary, size_t item, const uint8_t* data,
|
||||
size_t max_length, size_t max_backward, HasherSearchResult* out) {
|
||||
size_t len;
|
||||
size_t dist;
|
||||
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;
|
||||
dist = item >> 5;
|
||||
offset = dictionary->offsets_by_length[len] + len * dist;
|
||||
offset = dictionary->words->offsets_by_length[len] + len * word_idx;
|
||||
if (len > max_length) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
|
||||
matchlen =
|
||||
FindMatchLengthWithLimit(data, &dictionary->data[offset], len);
|
||||
if (matchlen + kCutoffTransformsCount <= len || matchlen == 0) {
|
||||
FindMatchLengthWithLimit(data, &dictionary->words->data[offset], len);
|
||||
if (matchlen + dictionary->cutoffTransformsCount <= len || matchlen == 0) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
{
|
||||
size_t cut = len - matchlen;
|
||||
size_t transform_id =
|
||||
(cut << 2) + (size_t)((kCutoffTransforms >> (cut * 6)) & 0x3F);
|
||||
backward = max_backward + dist + 1 +
|
||||
(transform_id << dictionary->size_bits_by_length[len]);
|
||||
size_t transform_id = (cut << 2) +
|
||||
(size_t)((dictionary->cutoffTransforms >> (cut * 6)) & 0x3F);
|
||||
backward = max_backward + 1 + word_idx +
|
||||
(transform_id << dictionary->words->size_bits_by_length[len]);
|
||||
}
|
||||
if (backward > max_distance) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
score = BackwardReferenceScore(matchlen, backward);
|
||||
if (score < out->score) {
|
||||
@@ -185,24 +169,25 @@ static BROTLI_INLINE BROTLI_BOOL TestStaticDictionaryItem(
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void SearchInStaticDictionary(
|
||||
const BrotliDictionary* dictionary, const uint16_t* dictionary_hash,
|
||||
HasherHandle handle, const uint8_t* data, size_t max_length,
|
||||
size_t max_backward, HasherSearchResult* out, BROTLI_BOOL shallow) {
|
||||
const BrotliEncoderDictionary* dictionary,
|
||||
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[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, 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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -243,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
|
||||
@@ -251,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
|
||||
@@ -315,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
|
||||
@@ -325,134 +320,181 @@ 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
|
||||
|
||||
/* fast large window hashers */
|
||||
|
||||
#define HASHER() HROLLING_FAST
|
||||
#define CHUNKLEN 32
|
||||
#define JUMP 4
|
||||
#define NUMBUCKETS 16777216
|
||||
#define MASK ((NUMBUCKETS * 64) - 1)
|
||||
#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) */
|
||||
#undef MASK
|
||||
#undef NUMBUCKETS
|
||||
#undef JUMP
|
||||
#undef CHUNKLEN
|
||||
#undef HASHER
|
||||
|
||||
#define HASHER() H35
|
||||
#define HASHER_A H3
|
||||
#define HASHER_B HROLLING_FAST
|
||||
#include "hash_composite_inc.h" /* NOLINT(build/include) */
|
||||
#undef HASHER_A
|
||||
#undef HASHER_B
|
||||
#undef HASHER
|
||||
|
||||
#define HASHER() H55
|
||||
#define HASHER_A H54
|
||||
#define HASHER_B HROLLING_FAST
|
||||
#include "hash_composite_inc.h" /* NOLINT(build/include) */
|
||||
#undef HASHER_A
|
||||
#undef HASHER_B
|
||||
#undef HASHER
|
||||
|
||||
#define HASHER() H65
|
||||
#define HASHER_A H6
|
||||
#define HASHER_B HROLLING
|
||||
#include "hash_composite_inc.h" /* NOLINT(build/include) */
|
||||
#undef HASHER_A
|
||||
#undef HASHER_B
|
||||
#undef HASHER
|
||||
|
||||
#undef FN
|
||||
#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)
|
||||
#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;
|
||||
}
|
||||
}
|
||||
|
||||
/* Custom LZ77 window. */
|
||||
static BROTLI_INLINE void HasherPrependCustomDictionary(
|
||||
MemoryManager* m, HasherHandle* handle, BrotliEncoderParams* params,
|
||||
const size_t size, const uint8_t* dict) {
|
||||
size_t overlap;
|
||||
size_t i;
|
||||
HasherHandle self;
|
||||
HasherSetup(m, handle, params, dict, 0, size, BROTLI_FALSE);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
self = *handle;
|
||||
switch (GetHasherCommon(self)->params.type) {
|
||||
#define PREPEND_(N) \
|
||||
case N: \
|
||||
overlap = (StoreLookaheadH ## N()) - 1; \
|
||||
for (i = 0; i + overlap < size; i++) { \
|
||||
StoreH ## N(self, dict, ~(size_t)0, i); \
|
||||
} \
|
||||
break;
|
||||
FOR_ALL_HASHERS(PREPEND_)
|
||||
#undef PREPEND_
|
||||
default: break;
|
||||
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_
|
||||
@@ -460,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 + 1);
|
||||
|
||||
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 + 1);
|
||||
|
||||
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_
|
||||
140
c/enc/hash_composite_inc.h
Normal file
140
c/enc/hash_composite_inc.h
Normal file
@@ -0,0 +1,140 @@
|
||||
/* NOLINT(build/header_guard) */
|
||||
/* Copyright 2018 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, HASHER_A, HASHER_B */
|
||||
|
||||
/* Composite hasher: This hasher allows to combine two other hashers, HASHER_A
|
||||
and HASHER_B. */
|
||||
|
||||
#define HashComposite HASHER()
|
||||
|
||||
#define FN_A(X) EXPAND_CAT(X, HASHER_A)
|
||||
#define FN_B(X) EXPAND_CAT(X, HASHER_B)
|
||||
|
||||
static BROTLI_INLINE size_t FN(HashTypeLength)(void) {
|
||||
size_t a = FN_A(HashTypeLength)();
|
||||
size_t b = FN_B(HashTypeLength)();
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
static BROTLI_INLINE size_t FN(StoreLookahead)(void) {
|
||||
size_t a = FN_A(StoreLookahead)();
|
||||
size_t b = FN_B(StoreLookahead)();
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
typedef struct HashComposite {
|
||||
HASHER_A ha;
|
||||
HASHER_B hb;
|
||||
HasherCommon ha_common;
|
||||
HasherCommon hb_common;
|
||||
|
||||
/* Shortcuts. */
|
||||
HasherCommon* common;
|
||||
|
||||
BROTLI_BOOL fresh;
|
||||
const BrotliEncoderParams* params;
|
||||
} HashComposite;
|
||||
|
||||
static void FN(Initialize)(HasherCommon* common,
|
||||
HashComposite* BROTLI_RESTRICT self, const BrotliEncoderParams* params) {
|
||||
self->common = common;
|
||||
|
||||
self->ha_common = *self->common;
|
||||
self->hb_common = *self->common;
|
||||
self->fresh = BROTLI_TRUE;
|
||||
self->params = 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)(
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(HashMemAllocInBytes)(
|
||||
const BrotliEncoderParams* params, BROTLI_BOOL one_shot,
|
||||
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)(HashComposite* BROTLI_RESTRICT self,
|
||||
const uint8_t* BROTLI_RESTRICT data, const size_t mask, const size_t ix) {
|
||||
FN_A(Store)(&self->ha, data, mask, ix);
|
||||
FN_B(Store)(&self->hb, data, mask, ix);
|
||||
}
|
||||
|
||||
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) {
|
||||
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)(
|
||||
HashComposite* BROTLI_RESTRICT self,
|
||||
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
|
||||
size_t 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)(
|
||||
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)(
|
||||
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 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
|
||||
162
c/enc/hash_forgetful_chain_inc.h
Executable file → Normal file
162
c/enc/hash_forgetful_chain_inc.h
Executable file → Normal file
@@ -28,8 +28,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 BROTLI_INLINE size_t FN(HashBytes)(const uint8_t *data) {
|
||||
const uint32_t h = BROTLI_UNALIGNED_LOAD32(data) * kHashMul32;
|
||||
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. */
|
||||
return h >> (32 - BUCKET_BITS);
|
||||
@@ -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,13 +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,
|
||||
const BrotliDictionary* dictionary, const uint16_t* dictionary_hash,
|
||||
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 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;
|
||||
@@ -170,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 + 1);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
@@ -199,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;
|
||||
}
|
||||
{
|
||||
@@ -237,12 +289,12 @@ 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, dictionary_hash,
|
||||
handle, &data[cur_ix_masked], max_length, max_backward, out,
|
||||
BROTLI_FALSE);
|
||||
SearchInStaticDictionary(dictionary,
|
||||
self->common, &data[cur_ix_masked], max_length, dictionary_distance,
|
||||
max_distance, out, BROTLI_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
195
c/enc/hash_longest_match64_inc.h
Executable file → Normal file
195
c/enc/hash_longest_match64_inc.h
Executable file → Normal file
@@ -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_LOAD64(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,
|
||||
const BrotliDictionary* dictionary, const uint16_t* dictionary_hash,
|
||||
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) {
|
||||
HasherCommon* common = GetHasherCommon(handle);
|
||||
HashLongestMatch* self = FN(Self)(handle);
|
||||
uint16_t* num = FN(Num)(self);
|
||||
uint32_t* buckets = FN(Buckets)(self);
|
||||
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 + 1);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -257,9 +270,9 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
||||
++num[key];
|
||||
}
|
||||
if (min_score == out->score) {
|
||||
SearchInStaticDictionary(dictionary, dictionary_hash,
|
||||
handle, &data[cur_ix_masked], max_length, max_backward, out,
|
||||
BROTLI_FALSE);
|
||||
SearchInStaticDictionary(dictionary,
|
||||
self->common_, &data[cur_ix_masked], max_length, dictionary_distance,
|
||||
max_distance, out, BROTLI_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user