Compare commits
755 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2b671100d9 | ||
|
|
ed6ab27a67 | ||
|
|
e7fb4376c0 | ||
|
|
684d28d328 | ||
|
|
a5b0db3219 | ||
|
|
cf0a5fb607 | ||
|
|
e0374ee623 | ||
|
|
655494f37b | ||
|
|
353a56dbbf | ||
|
|
1c8fd0ccc4 | ||
|
|
1c3d3ad9be | ||
|
|
e66b8a47d4 | ||
|
|
e57692e4f5 | ||
|
|
437fc0d8c2 | ||
|
|
3d98b33076 | ||
|
|
a444b5eccb | ||
|
|
6c64428be9 | ||
|
|
d034bcb1ac | ||
|
|
325f8df709 | ||
|
|
996a821bf8 | ||
|
|
ac4eef7eb3 | ||
|
|
b48b53fce9 | ||
|
|
acf3fef03d | ||
|
|
48ed574b4f | ||
|
|
8fc96c5bd7 | ||
|
|
208490f4e1 | ||
|
|
d392aba64d | ||
|
|
597710dd53 | ||
|
|
d630b3d8a7 | ||
|
|
aebfab3777 | ||
|
|
91f699b571 | ||
|
|
b46d1d8d21 | ||
|
|
bf60321466 | ||
|
|
38daac868a | ||
|
|
0b27f2cbe0 | ||
|
|
eb96830aa0 | ||
|
|
334bb36745 | ||
|
|
60f9bcf51c | ||
|
|
65fadf4ed3 | ||
|
|
8951581815 | ||
|
|
4dc1e733a7 | ||
|
|
283eba9667 | ||
|
|
c651312a88 | ||
|
|
5b1fdc34eb | ||
|
|
a158fa108b | ||
|
|
60cb0fa650 | ||
|
|
67314bf2fb | ||
|
|
d4cc5aa698 | ||
|
|
235b8dc2e4 | ||
|
|
4f6faddbab | ||
|
|
416d52bdac | ||
|
|
2d18e0be81 | ||
|
|
9225bd772d | ||
|
|
9e55951d5a | ||
|
|
d9663aa135 | ||
|
|
9d86448585 | ||
|
|
2c4ffba0f3 | ||
|
|
f9e38d3311 | ||
|
|
1317a7c4ac | ||
|
|
8f19d7aa8b | ||
|
|
18b595a7e7 | ||
|
|
676c426e87 | ||
|
|
0198b7fa5a | ||
|
|
8413d298df | ||
|
|
77d637cc47 | ||
|
|
9faeb3e2ce | ||
|
|
1bffe89b5d | ||
|
|
bdfa57039c | ||
|
|
f51c2f08a5 | ||
|
|
ecee7086a8 | ||
|
|
76999d1a67 | ||
|
|
20375ee77a | ||
|
|
cd67184432 | ||
|
|
b3197e4498 | ||
|
|
90d2b8330a | ||
|
|
02c6f024d1 | ||
|
|
32905bbf5d | ||
|
|
bddc552433 | ||
|
|
1f1f1f60ac | ||
|
|
6adf4f5171 | ||
|
|
b76e94059d | ||
|
|
ad039c703c | ||
|
|
efc1509d87 | ||
|
|
7071452e6e | ||
|
|
b4bba99678 | ||
|
|
d3b5e86f30 | ||
|
|
16e3b8e0fd | ||
|
|
20e9549afe | ||
|
|
aae1c81840 | ||
|
|
23779da2dc | ||
|
|
d51c342cbd | ||
|
|
e0c7eefc84 | ||
|
|
5a62bbdd33 | ||
|
|
94a612c4df | ||
|
|
b0d29e7348 | ||
|
|
0965155935 | ||
|
|
5548b1aa21 | ||
|
|
775b7c4758 | ||
|
|
f4fe015261 | ||
|
|
0c6fa47789 | ||
|
|
274a9d7759 | ||
|
|
7796c15248 | ||
|
|
ce035361e8 | ||
|
|
d260c0a679 | ||
|
|
c72963dfc5 | ||
|
|
4fe65f75bc | ||
|
|
a61a48d876 | ||
|
|
9ac4e6b64e | ||
|
|
a695b4ebe1 | ||
|
|
700b57bc18 | ||
|
|
c9f8596357 | ||
|
|
4b282211de | ||
|
|
506be129e1 | ||
|
|
d38c986c82 | ||
|
|
399a9d65d2 | ||
|
|
8335a5212e | ||
|
|
e5a7554c30 | ||
|
|
5d5f3ff1b5 | ||
|
|
aca13a619a | ||
|
|
dd879c413a | ||
|
|
f8dda12024 | ||
|
|
d2c21ee297 | ||
|
|
351e96ca75 | ||
|
|
610390ed69 | ||
|
|
a40a36d191 | ||
|
|
073f78badb | ||
|
|
0c5e8be49a | ||
|
|
3363de8549 | ||
|
|
2009a20561 | ||
|
|
bb45062ef6 | ||
|
|
ede332fecf | ||
|
|
304c68ba6f | ||
|
|
f7a7765ba2 | ||
|
|
adf5917325 | ||
|
|
08378de48c | ||
|
|
f5314cb862 | ||
|
|
cbd7aa565b | ||
|
|
6398dd5b75 | ||
|
|
2edd332759 | ||
|
|
8bd9dbcee8 | ||
|
|
9149f6e34c | ||
|
|
c5fc65b56a | ||
|
|
83fcd472bb | ||
|
|
006a047276 | ||
|
|
db3a49fc4b | ||
|
|
cd5099d6f7 | ||
|
|
1ae607f924 | ||
|
|
4d93801d5f | ||
|
|
efcacd0885 | ||
|
|
7ade6f97e9 | ||
|
|
a58187943d | ||
|
|
06316eee26 | ||
|
|
7cebb37c93 | ||
|
|
396def91e5 | ||
|
|
ebee3f1c02 | ||
|
|
c9701a9b05 | ||
|
|
cc76732058 | ||
|
|
3adf05244d | ||
|
|
0dd2c3ea27 | ||
|
|
d56fbb88e5 | ||
|
|
46db1f7b76 | ||
|
|
85a980ea3e | ||
|
|
e9689ea50d | ||
|
|
3fa5125f24 | ||
|
|
4f049302c8 | ||
|
|
5f7e53bfde | ||
|
|
de1dee6c3b | ||
|
|
411ae71ca9 | ||
|
|
0b6943fb5a | ||
|
|
333ea519ed | ||
|
|
56978189e0 | ||
|
|
fe5ccc144b | ||
|
|
0641ec2d89 | ||
|
|
707e69a794 | ||
|
|
5b4ea0052c | ||
|
|
a0aba4da4a | ||
|
|
af82938427 | ||
|
|
42994bac37 | ||
|
|
4878b7cfd3 | ||
|
|
98d32e50e0 | ||
|
|
12e9db4ccc | ||
|
|
ebb1063e33 | ||
|
|
716bcb6d12 | ||
|
|
2f151e773c | ||
|
|
1c9f9a74e8 | ||
|
|
9df7460fe1 | ||
|
|
55feef8663 | ||
|
|
22c59fe19f | ||
|
|
3b74fcb88c | ||
|
|
e818f01ff2 | ||
|
|
e11081ac09 | ||
|
|
0eae7ba21d | ||
|
|
0be9b888fa | ||
|
|
adda3249f5 | ||
|
|
cc11ed5c2c | ||
|
|
83468535dd | ||
|
|
55115058d2 | ||
|
|
776bfa3d7e | ||
|
|
6979f1c5eb | ||
|
|
5d0c25f5ea | ||
|
|
eb42ad3a2b | ||
|
|
2b6edbccbc | ||
|
|
7e12cc57c6 | ||
|
|
1f149861f9 | ||
|
|
11882aef2d | ||
|
|
3c4db20d2d | ||
|
|
924b87a16a | ||
|
|
198b69e275 | ||
|
|
ad64472950 | ||
|
|
d9f33b19bc | ||
|
|
a5fea33757 | ||
|
|
8cc360e344 | ||
|
|
a285d09459 | ||
|
|
e646596c5b | ||
|
|
f3d9ad3244 | ||
|
|
752fcb6424 | ||
|
|
0042288e92 | ||
|
|
7ea0af6f6d | ||
|
|
69c0eaaf74 | ||
|
|
a0424bf1bd | ||
|
|
481eccfe3c | ||
|
|
c5c3f98595 | ||
|
|
3c19b6f734 | ||
|
|
2d8deb86bb | ||
|
|
5e0185d3eb | ||
|
|
aee84c32e5 | ||
|
|
19a9594143 | ||
|
|
32f0da2e77 | ||
|
|
d329cb3fff | ||
|
|
3bb9e36fc8 | ||
|
|
76ae5f5b9b | ||
|
|
393169f79d | ||
|
|
f5570c38dd | ||
|
|
0153c9bb85 | ||
|
|
1712a317d5 | ||
|
|
10cff577d6 | ||
|
|
86c59016c6 | ||
|
|
7821ae39ab | ||
|
|
039d144c84 | ||
|
|
af0d570725 | ||
|
|
288fa0128b | ||
|
|
77125798a4 | ||
|
|
c26954c69e | ||
|
|
9667da307c | ||
|
|
baa3ec0a62 | ||
|
|
478fc766b6 | ||
|
|
6c49066cde | ||
|
|
a839af04dc | ||
|
|
3950632517 | ||
|
|
297ac9c3fe | ||
|
|
60d4ed3a1c | ||
|
|
a1b40cc8f5 | ||
|
|
5a9cf82564 | ||
|
|
04f8cb6d30 | ||
|
|
5264f3b5aa | ||
|
|
5105c2f3ea | ||
|
|
eb46107575 | ||
|
|
d75b8c63ef | ||
|
|
7d787e6c22 | ||
|
|
36c79f3d50 | ||
|
|
88b7595929 | ||
|
|
fccf8db099 | ||
|
|
d33afd4e96 | ||
|
|
76a4840a0f | ||
|
|
65923b1aba | ||
|
|
47fea26b62 | ||
|
|
9ea0dde469 | ||
|
|
6c31256aa1 | ||
|
|
210c417d96 | ||
|
|
c1af14c22a | ||
|
|
a3d8be5e2f | ||
|
|
d08a44ea4c | ||
|
|
63d974135b | ||
|
|
7b34c0603f | ||
|
|
c3c99113c7 | ||
|
|
9352576d1e | ||
|
|
dc82a06e9e | ||
|
|
bb98b81f82 | ||
|
|
1687c74913 | ||
|
|
bfe4256bf2 | ||
|
|
66c3e1c1ff | ||
|
|
c6acfa2cd4 | ||
|
|
8fa592d849 | ||
|
|
89108e856f | ||
|
|
0a0420bfd0 | ||
|
|
2cc08cc5fd | ||
|
|
f3344e1da0 | ||
|
|
9eb82c600d | ||
|
|
17fe6b3373 | ||
|
|
c3869dc479 | ||
|
|
473bff1aae | ||
|
|
99ceb2476e | ||
|
|
05881db492 | ||
|
|
1086757dc0 | ||
|
|
d4c302bea3 | ||
|
|
b8774327b6 | ||
|
|
e9c4e73103 | ||
|
|
d19a2fb606 | ||
|
|
99af9739b2 | ||
|
|
9ce366fa7b | ||
|
|
daeaf65d7e | ||
|
|
c5a10d19a4 | ||
|
|
a5f3142514 | ||
|
|
cf49fcc4e9 | ||
|
|
06dd84d6da | ||
|
|
dd3d4f8451 | ||
|
|
c08523a1ad | ||
|
|
559be309ea | ||
|
|
299c39a214 | ||
|
|
4575608a97 | ||
|
|
1a9a7a59ac | ||
|
|
e7d6101bd4 | ||
|
|
76381f5cdd | ||
|
|
40a4429e58 | ||
|
|
bd1aed43ec | ||
|
|
7727cd45cf | ||
|
|
4ee5b94584 | ||
|
|
1d5c7d662e | ||
|
|
f4f06222d4 | ||
|
|
4caf8a6b14 | ||
|
|
c19488f3be | ||
|
|
ad3ab877f8 | ||
|
|
88f3c8c5ee | ||
|
|
91013a4e05 | ||
|
|
de92470f0d | ||
|
|
1c62b0f1ec | ||
|
|
b52af64ffe | ||
|
|
1db7ac5f6b | ||
|
|
e77a970ca1 | ||
|
|
ac984d05f2 | ||
|
|
f16c2a0d67 | ||
|
|
29a574a4bc | ||
|
|
a7c06b38e6 | ||
|
|
16d36c46fe | ||
|
|
720618bc37 | ||
|
|
2f727e6561 | ||
|
|
b65a5f78fd | ||
|
|
0a1eb038a5 | ||
|
|
e541c0534d | ||
|
|
eb1e3b33b4 | ||
|
|
41ec46d5bb | ||
|
|
b021e9b648 | ||
|
|
ede4d7fbca | ||
|
|
d0797a025b | ||
|
|
1acd223f45 | ||
|
|
8639a2ac40 | ||
|
|
f48e4ffd5e | ||
|
|
c01b959723 | ||
|
|
36773c09d3 | ||
|
|
687340003d | ||
|
|
7467307200 | ||
|
|
bbdb0b15f3 | ||
|
|
b5edd9ad57 | ||
|
|
a32e1aafa6 | ||
|
|
f9fd6ffd46 | ||
|
|
31a5fcf297 | ||
|
|
493fc900e9 | ||
|
|
3abdc54e4b | ||
|
|
618aeec709 | ||
|
|
4585361161 | ||
|
|
f64739c29b | ||
|
|
f3830aa854 | ||
|
|
f1fe0bf40a | ||
|
|
561712090d | ||
|
|
d5f34c401d | ||
|
|
d9190ea675 | ||
|
|
57f4ea4d4a | ||
|
|
9b0ae8d403 | ||
|
|
aed0611fb8 | ||
|
|
920b8a2496 | ||
|
|
5a5e31c38b | ||
|
|
db2e0e816d | ||
|
|
a298781b85 | ||
|
|
d5cd9ef2ca | ||
|
|
55c909c656 | ||
|
|
da31db3212 | ||
|
|
601c4ad4df | ||
|
|
2549b4328f | ||
|
|
68d800d4fa | ||
|
|
9fc3db1dd1 | ||
|
|
d4c4805f96 | ||
|
|
161eae78b6 | ||
|
|
6cdc7ac91d | ||
|
|
0bccada9d1 | ||
|
|
9cb9373274 | ||
|
|
d987ffe49a | ||
|
|
77cfd44f24 | ||
|
|
59be7213cf | ||
|
|
d60dacbd09 | ||
|
|
82b7b4fcce | ||
|
|
fa9a2b1e2e | ||
|
|
4e6138d785 | ||
|
|
86a55e2c0a | ||
|
|
de8c1e0206 | ||
|
|
131716da00 | ||
|
|
4d35fc2928 | ||
|
|
3b65c1a58a | ||
|
|
9bca415af2 | ||
|
|
60bc8e6c25 | ||
|
|
8aa1b112b8 | ||
|
|
0bd47d8457 | ||
|
|
fcbda63023 | ||
|
|
1d59bfade3 | ||
|
|
fd7d0f8787 | ||
|
|
fa11858a72 | ||
|
|
1293ee60e0 | ||
|
|
66341aa28e | ||
|
|
73342411bc | ||
|
|
8dd6f9b07c | ||
|
|
7e77a196e6 | ||
|
|
465616223c | ||
|
|
9d4193f4ea | ||
|
|
dafb876d75 | ||
|
|
4b846e0106 | ||
|
|
76c6630084 | ||
|
|
23a4012aeb | ||
|
|
eee14ae148 | ||
|
|
b0ccaa09be | ||
|
|
bbaccfdaae | ||
|
|
cb5a2cce53 | ||
|
|
4fec11af05 | ||
|
|
5a9304e1b8 | ||
|
|
2b9c646c5b | ||
|
|
6b6f3e0ece | ||
|
|
b560fe34c9 | ||
|
|
e5b27d066c | ||
|
|
8762a939c0 | ||
|
|
06da31019c | ||
|
|
d0621cb82a | ||
|
|
9935b5ddb2 | ||
|
|
49d664bb0d | ||
|
|
c6c0d0ed60 | ||
|
|
6f74d1b0c1 | ||
|
|
5eb852532f | ||
|
|
43e0281ab5 | ||
|
|
99d1eec021 | ||
|
|
0a158f3577 | ||
|
|
89c431a624 | ||
|
|
b48b70aedf | ||
|
|
f105bc5f4e | ||
|
|
d5fae07ab7 | ||
|
|
58dbcf0840 | ||
|
|
0340c3c8f7 | ||
|
|
d8a53fbafd | ||
|
|
b237e1b99f | ||
|
|
43f64f71e4 | ||
|
|
ceac074dad | ||
|
|
903dd26a08 | ||
|
|
f0efb1cb19 | ||
|
|
4eb49b3320 | ||
|
|
0fcb055246 | ||
|
|
61a89a14b6 | ||
|
|
4fbb70d89e | ||
|
|
5c3e54dede | ||
|
|
5721b1315e | ||
|
|
85fcac2a61 | ||
|
|
8d01a42db1 | ||
|
|
0e4c49a0d6 | ||
|
|
a9111f9a40 | ||
|
|
616fcfd201 | ||
|
|
b3ca5d51fb | ||
|
|
e783eccc97 | ||
|
|
c98b9403ac | ||
|
|
7e6459a5e4 | ||
|
|
67d22b0ec6 | ||
|
|
79f99bb3ad | ||
|
|
fa3579656b | ||
|
|
8a10fcaf5a | ||
|
|
4c8b8caead | ||
|
|
4238fedee7 | ||
|
|
b0dcdf74bd | ||
|
|
a63d62fb4e | ||
|
|
8dbb0cff6f | ||
|
|
07bba337f5 | ||
|
|
b28fbf6817 | ||
|
|
daa169b8ed | ||
|
|
a5251bedc9 | ||
|
|
e9820eb207 | ||
|
|
645b2811e2 | ||
|
|
9804021de4 | ||
|
|
ea5858e10b | ||
|
|
4589a62738 | ||
|
|
1275c9275b | ||
|
|
d95f7ac159 | ||
|
|
8e2d448c5c | ||
|
|
37c05e3212 | ||
|
|
99e67f0859 | ||
|
|
2cb87861c0 | ||
|
|
c1793d8781 | ||
|
|
fce896c480 | ||
|
|
f45cd87488 | ||
|
|
7b963a2372 | ||
|
|
d863cbd7c0 | ||
|
|
e50447c840 | ||
|
|
ab919f6fa1 | ||
|
|
f596351bc1 | ||
|
|
7c5e011fe6 | ||
|
|
b444b2ee36 | ||
|
|
aeb60edf55 | ||
|
|
6c2ef90033 | ||
|
|
182b0aac98 | ||
|
|
d9d6bd7ffb | ||
|
|
21bba05805 | ||
|
|
b146e9c457 | ||
|
|
1f835b27c4 | ||
|
|
89debca4af | ||
|
|
a33b747de5 | ||
|
|
532cc44e66 | ||
|
|
391a43d967 | ||
|
|
be37a283d5 | ||
|
|
7e424e1848 | ||
|
|
96bcb1d33b | ||
|
|
7f60c649f4 | ||
|
|
e52bcb5b93 | ||
|
|
d93283c547 | ||
|
|
aef0b9f50f | ||
|
|
74391d7c50 | ||
|
|
8975d1a9f4 | ||
|
|
48bf8c6105 | ||
|
|
0ed1c6f840 | ||
|
|
72e73f2f81 | ||
|
|
95eac2e510 | ||
|
|
bc499000a5 | ||
|
|
e2be8c2d37 | ||
|
|
fd4c8e1e2d | ||
|
|
ba18c5a669 | ||
|
|
293ad34535 | ||
|
|
45e10394a0 | ||
|
|
0531b4bc79 | ||
|
|
0f6d11351b | ||
|
|
1b11c3e923 | ||
|
|
c79baa56e4 | ||
|
|
c6f4c93d0a | ||
|
|
8742fb8cce | ||
|
|
0bd67620c6 | ||
|
|
0f60ac2dd7 | ||
|
|
0cd761808a | ||
|
|
43fb09dc39 | ||
|
|
c2d81d67c2 | ||
|
|
272e944a13 | ||
|
|
a9f5519d11 | ||
|
|
a055aaf035 | ||
|
|
718f4b328f | ||
|
|
b41cf52ce4 | ||
|
|
e08e15a676 | ||
|
|
c5f0b03a62 | ||
|
|
794bd85371 | ||
|
|
73d657a21a | ||
|
|
103f5f3956 | ||
|
|
ef7d92a117 | ||
|
|
33102d8c4e | ||
|
|
56dcbca238 | ||
|
|
cc6dc96c90 | ||
|
|
2dffad1d8e | ||
|
|
93430cd5f4 | ||
|
|
3d0a90e63d | ||
|
|
9eb91984dd | ||
|
|
071c8200a6 | ||
|
|
ad7175a24d | ||
|
|
24232ba277 | ||
|
|
0f6e5fe57e | ||
|
|
ef8e8313ab | ||
|
|
17cb65e981 | ||
|
|
f2153f060d | ||
|
|
48c0b30671 | ||
|
|
e8f67281cf | ||
|
|
49a54b086f | ||
|
|
4790959938 | ||
|
|
33249c872f | ||
|
|
71bf099041 | ||
|
|
307acb3f64 | ||
|
|
e5675e9537 | ||
|
|
9cf425006f | ||
|
|
c052831291 | ||
|
|
fe2cd543ba | ||
|
|
1925d5ea65 | ||
|
|
aacdffd539 | ||
|
|
a0e1eb4985 | ||
|
|
e4c48a5f17 | ||
|
|
021dd168e5 | ||
|
|
b032313c45 | ||
|
|
19a41b4d9a | ||
|
|
25e7a2882d | ||
|
|
a75fb6509e | ||
|
|
23c42cb555 | ||
|
|
1f8feea454 | ||
|
|
f0afdc51af | ||
|
|
ac6afcb0a8 | ||
|
|
ad7f671a7b | ||
|
|
4f67b8b433 | ||
|
|
e3d6aa2c60 | ||
|
|
89d416806b | ||
|
|
859b0cc585 | ||
|
|
8b4209cb97 | ||
|
|
8dca5a6b9a | ||
|
|
200e5bf6e3 | ||
|
|
f4819175b0 | ||
|
|
5921ca1139 | ||
|
|
dbc4b98742 | ||
|
|
822c9cb1d6 | ||
|
|
529de9c91d | ||
|
|
7914523a16 | ||
|
|
d39c71f927 | ||
|
|
934f2ede0b | ||
|
|
8dbea2a046 | ||
|
|
38c8100a76 | ||
|
|
a560d86d0f | ||
|
|
47a493c090 | ||
|
|
35da87994b | ||
|
|
f49f2a1b82 | ||
|
|
91c3492455 | ||
|
|
75872a1097 | ||
|
|
4c267bdc24 | ||
|
|
409ca6bfab | ||
|
|
56abcbf910 | ||
|
|
f140b74f17 | ||
|
|
8360a4ec53 | ||
|
|
ccf124218b | ||
|
|
737d7bf8f2 | ||
|
|
3f41b22011 | ||
|
|
43451b1287 | ||
|
|
2914c2eb95 | ||
|
|
fc1775753a | ||
|
|
65aca5b140 | ||
|
|
e7c466797c | ||
|
|
c66c0b8edc | ||
|
|
a6da0ac6ca | ||
|
|
5c9aa6a21a | ||
|
|
50935b6c93 | ||
|
|
0a6d83901d | ||
|
|
8bff6f1995 | ||
|
|
8f1b30a25b | ||
|
|
9f337e93fc | ||
|
|
08d99967dc | ||
|
|
72635c55c5 | ||
|
|
2b3b8bae23 | ||
|
|
f96182cc11 | ||
|
|
93784903b2 | ||
|
|
afcffc03b1 | ||
|
|
34164dc341 | ||
|
|
6205fb32fd | ||
|
|
23bb2e1b67 | ||
|
|
c81ac668da | ||
|
|
f42b49e597 | ||
|
|
a4ca143fc5 | ||
|
|
969bd05fc5 | ||
|
|
8a83014f51 | ||
|
|
dcde461c02 | ||
|
|
6c0e938d5a | ||
|
|
76158f39ba | ||
|
|
a4193a1b02 | ||
|
|
5ab1e647bf | ||
|
|
9ecf79fa84 | ||
|
|
44c96a208e | ||
|
|
065866895c | ||
|
|
52025ff030 | ||
|
|
5168e0b576 | ||
|
|
e4bb00d942 | ||
|
|
5f809bf249 | ||
|
|
b083ad9038 | ||
|
|
ce2e1b0813 | ||
|
|
be92cc87a4 | ||
|
|
b2391553f9 | ||
|
|
d35f391725 | ||
|
|
b9ebb23bb9 | ||
|
|
c4ef6b87aa | ||
|
|
031f9d8c26 | ||
|
|
8c25c55f01 | ||
|
|
cdce26e519 | ||
|
|
925043d645 | ||
|
|
f63a4cf90c | ||
|
|
e6d881e89b | ||
|
|
325e6acd7e | ||
|
|
10cfc66737 | ||
|
|
5dbfee9e9c | ||
|
|
edd2bc85ae | ||
|
|
e918b3fb1e | ||
|
|
c915d1bf58 | ||
|
|
cd2c7b3bbd | ||
|
|
63b8893c50 | ||
|
|
946d28ae37 | ||
|
|
97e2d41233 | ||
|
|
54548931b5 | ||
|
|
ac7b6870a8 | ||
|
|
576a269648 | ||
|
|
4bcf69a47e | ||
|
|
5a418a8cd6 | ||
|
|
585ac148a6 | ||
|
|
af84161528 | ||
|
|
7c14e0d666 | ||
|
|
62347d7e97 | ||
|
|
777fd5350b | ||
|
|
442ca012fd | ||
|
|
065b17ddbd | ||
|
|
bc3c9ce2fa | ||
|
|
9bea8bb5bc | ||
|
|
fef8c536d8 | ||
|
|
8cc2cad4d9 | ||
|
|
5f8e5b0a29 | ||
|
|
4ede3a8a82 | ||
|
|
934217baf1 | ||
|
|
d0f3b34517 | ||
|
|
cd8f0c1374 | ||
|
|
9b8ee54034 | ||
|
|
d730c189db | ||
|
|
3fc1e6911a | ||
|
|
e8d9ca4465 | ||
|
|
8c12086beb | ||
|
|
5a2ee2f9a3 | ||
|
|
cafd5a7471 | ||
|
|
4c46d2bc95 | ||
|
|
c95fc3689b | ||
|
|
8c50632a10 | ||
|
|
ae1bf69a3d | ||
|
|
08d88af2fb | ||
|
|
4dfbcb539f | ||
|
|
cc0d6621a4 | ||
|
|
d6e55f72c0 | ||
|
|
cd30de3727 | ||
|
|
cec427777c | ||
|
|
30e3ad83bc | ||
|
|
9ef6801f4c | ||
|
|
7f1c371b6e | ||
|
|
2f7b0d1d94 | ||
|
|
90e1ba7781 | ||
|
|
0dfe89a817 | ||
|
|
c76f75a154 | ||
|
|
f51520eb79 | ||
|
|
828f4f312a | ||
|
|
a9c7a85d9a | ||
|
|
38393b50c1 | ||
|
|
7b6c532ac2 | ||
|
|
b3e74de390 | ||
|
|
1aa4d7d24b | ||
|
|
a3e324d623 | ||
|
|
d6116f7426 | ||
|
|
ab9631f045 | ||
|
|
ec0a449c63 | ||
|
|
01ffbfdb42 | ||
|
|
f5621bd56c | ||
|
|
708750173e | ||
|
|
20e43a3e7d | ||
|
|
ff4ee95eba | ||
|
|
2707c44f0f | ||
|
|
e7e401c8dd | ||
|
|
b0ab5bd5eb | ||
|
|
d75395794d | ||
|
|
c7d894d499 | ||
|
|
30905db75f | ||
|
|
89c3b4f9e2 | ||
|
|
0bd50abd77 | ||
|
|
7038292d11 | ||
|
|
b33f8416db | ||
|
|
99b3d0727d | ||
|
|
9503725a32 |
6
.gitattributes
vendored
@@ -16,11 +16,17 @@ kittens/diff/options/types.py linguist-generated=true
|
||||
kittens/diff/options/parse.py linguist-generated=true
|
||||
glfw/*.c linguist-vendored=true
|
||||
glfw/*.h linguist-vendored=true
|
||||
3rdparty/** linguist-vendored=true
|
||||
kittens/unicode_input/names.h linguist-generated=true
|
||||
tools/wcswidth/std.go linguist-generated=true
|
||||
tools/unicode_names/names.txt linguist-generated=true
|
||||
terminfo/kitty.term* linguist-generated=true
|
||||
terminfo/x/* linguist-generated=true
|
||||
*_generated.h linguist-generated=true
|
||||
*_generated.go linguist-generated=true
|
||||
*_generated_test.go linguist-generated=true
|
||||
*_generated_test.s linguist-generated=true
|
||||
*_generated.s linguist-generated=true
|
||||
|
||||
*.py text diff=python
|
||||
*.m text diff=objc
|
||||
|
||||
49
.github/workflows/ci.py
vendored
@@ -2,6 +2,7 @@
|
||||
# vim:fileencoding=utf-8
|
||||
# License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
import glob
|
||||
import io
|
||||
import os
|
||||
import shlex
|
||||
@@ -9,6 +10,7 @@ import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tarfile
|
||||
import time
|
||||
from urllib.request import urlopen
|
||||
|
||||
BUNDLE_URL = 'https://download.calibre-ebook.com/ci/kitty/{}-64.tar.xz'
|
||||
@@ -17,14 +19,44 @@ is_macos = 'darwin' in sys.platform.lower()
|
||||
SW = None
|
||||
|
||||
|
||||
def run(*a):
|
||||
def do_print_crash_reports():
|
||||
print('Printing available crash reports...')
|
||||
if is_macos:
|
||||
end_time = time.monotonic() + 90
|
||||
while time.monotonic() < end_time:
|
||||
time.sleep(1)
|
||||
items = glob.glob(os.path.join(os.path.expanduser('~/Library/Logs/DiagnosticReports'), 'kitty-*.ips'))
|
||||
if items:
|
||||
break
|
||||
if items:
|
||||
time.sleep(1)
|
||||
print(os.path.basename(items[0]))
|
||||
sdir = os.path.dirname(os.path.abspath(__file__))
|
||||
subprocess.check_call([sys.executable, os.path.join(sdir, 'macos_crash_report.py'), items[0]])
|
||||
else:
|
||||
run('sh -c "echo bt | coredumpctl debug"')
|
||||
print(flush=True)
|
||||
|
||||
|
||||
def run(*a, print_crash_reports=False):
|
||||
if len(a) == 1:
|
||||
a = shlex.split(a[0])
|
||||
print(' '.join(map(shlex.quote, a)))
|
||||
cmd = ' '.join(map(shlex.quote, a))
|
||||
print(cmd)
|
||||
sys.stdout.flush()
|
||||
ret = subprocess.Popen(a).wait()
|
||||
if ret != 0:
|
||||
raise SystemExit(ret)
|
||||
if ret < 0:
|
||||
import signal
|
||||
try:
|
||||
sig = signal.Signals(-ret)
|
||||
except ValueError:
|
||||
pass
|
||||
else:
|
||||
if print_crash_reports:
|
||||
do_print_crash_reports()
|
||||
raise SystemExit(f'The following process was killed by signal: {sig.name}:\n{cmd}')
|
||||
raise SystemExit(f'The following process failed with exit code: {ret}:\n{cmd}')
|
||||
|
||||
|
||||
def install_deps():
|
||||
@@ -37,13 +69,13 @@ def install_deps():
|
||||
import ssl
|
||||
if ssl.OPENSSL_VERSION_INFO[0] == 1:
|
||||
openssl += '@1.1'
|
||||
run('brew', 'install', 'fish', openssl, *items)
|
||||
run('brew', 'install', 'fish', 'simde', openssl, *items)
|
||||
else:
|
||||
run('sudo apt-get update')
|
||||
run('sudo apt-get install -y libgl1-mesa-dev libxi-dev libxrandr-dev libxinerama-dev ca-certificates'
|
||||
' libxcursor-dev libxcb-xkb-dev libdbus-1-dev libxkbcommon-dev libharfbuzz-dev libx11-xcb-dev zsh'
|
||||
' libpng-dev liblcms2-dev libfontconfig-dev libxkbcommon-x11-dev libcanberra-dev libxxhash-dev uuid-dev'
|
||||
' zsh bash dash')
|
||||
' libsimde-dev zsh bash dash systemd-coredump gdb')
|
||||
# for some reason these directories are world writable which causes zsh
|
||||
# compinit to break
|
||||
run('sudo chmod -R og-w /usr/share/zsh')
|
||||
@@ -59,13 +91,18 @@ def install_deps():
|
||||
def build_kitty():
|
||||
python = shutil.which('python3') if is_bundle else sys.executable
|
||||
cmd = f'{python} setup.py build --verbose'
|
||||
if is_macos:
|
||||
cmd += ' --debug' # for better crash report to debug SIGILL issue
|
||||
if os.environ.get('KITTY_SANITIZE') == '1':
|
||||
cmd += ' --debug --sanitize'
|
||||
run(cmd)
|
||||
|
||||
|
||||
def test_kitty():
|
||||
run('./test.py')
|
||||
if is_macos:
|
||||
run('ulimit -c unlimited')
|
||||
run('sudo chmod -R 777 /cores')
|
||||
run('./test.py', print_crash_reports=True)
|
||||
|
||||
|
||||
def package_kitty():
|
||||
|
||||
2
.github/workflows/ci.yml
vendored
@@ -2,7 +2,7 @@ name: CI
|
||||
on: [push, pull_request]
|
||||
env:
|
||||
CI: 'true'
|
||||
ASAN_OPTIONS: leak_check_at_exit=0
|
||||
ASAN_OPTIONS: detect_leaks=0
|
||||
LC_ALL: en_US.UTF-8
|
||||
LANG: en_US.UTF-8
|
||||
|
||||
|
||||
450
.github/workflows/macos_crash_report.py
vendored
Executable file
@@ -0,0 +1,450 @@
|
||||
#!/usr/bin/env python
|
||||
# License: GPLv3 Copyright: 2024, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
import json
|
||||
import posixpath
|
||||
import sys
|
||||
from collections import namedtuple
|
||||
from datetime import datetime
|
||||
from enum import Enum
|
||||
from functools import cached_property
|
||||
from typing import IO, List, Mapping, Optional
|
||||
|
||||
Frame = namedtuple('Frame', 'image_name image_base image_offset symbol symbol_offset')
|
||||
Register = namedtuple('Register', 'name value')
|
||||
|
||||
|
||||
def surround(x: str, start: int, end: int) -> str:
|
||||
if sys.stdout.isatty():
|
||||
x = f'\033[{start}m{x}\033[{end}m'
|
||||
return x
|
||||
|
||||
|
||||
def cyan(x: str) -> str:
|
||||
return surround(x, 96, 39)
|
||||
|
||||
|
||||
def bold(x: str) -> str:
|
||||
return surround(x, 1, 22)
|
||||
|
||||
|
||||
class BugType(Enum):
|
||||
WatchdogTimeout = '28'
|
||||
BasebandStats = '195'
|
||||
GPUEvent = '284'
|
||||
Sandbox = '187'
|
||||
TerminatingStackshot = '509'
|
||||
ServiceWatchdogTimeout = '29'
|
||||
Session = '179'
|
||||
LegacyStackshot = '188'
|
||||
MACorrelation = '197'
|
||||
iMessages = '189'
|
||||
log_power = '278'
|
||||
PowerLog = 'powerlog'
|
||||
DuetKnowledgeCollector2 = '58'
|
||||
BridgeRestore = '83'
|
||||
LegacyJetsam = '198'
|
||||
ExcResource_385 = '385'
|
||||
Modem = '199'
|
||||
Stackshot = '288'
|
||||
SystemInformation = 'system_profile'
|
||||
Jetsam_298 = '298'
|
||||
MemoryResource = '30'
|
||||
Bridge = '31'
|
||||
DifferentialPrivacy = 'diff_privacy'
|
||||
FirmwareIntegrity = '32'
|
||||
CoreAnalytics_33 = '33'
|
||||
AutoBugCapture = '34'
|
||||
EfiFirmwareIntegrity = '35'
|
||||
SystemStats = '36'
|
||||
AnonSystemStats = '37'
|
||||
Crash_9 = '9'
|
||||
Jetsam_98 = '98'
|
||||
LDCM = '100'
|
||||
Panic_10 = '10'
|
||||
Spin = '11'
|
||||
CLTM = '101'
|
||||
Hang = '12'
|
||||
Panic_110 = '110'
|
||||
ConnectionFailure = '13'
|
||||
MessageTracer = '14'
|
||||
LowBattery = '120'
|
||||
Siri = '201'
|
||||
ShutdownStall = '17'
|
||||
Panic_210 = '210'
|
||||
SymptomsCPUUsage = '202'
|
||||
AssumptionViolation = '18'
|
||||
CoreHandwriting = 'chw'
|
||||
IOMicroStackShot = '44'
|
||||
CoreAnalytics_211 = '211'
|
||||
SiriAppPrediction = '203'
|
||||
spin_45 = '45'
|
||||
PowerMicroStackshots = '220'
|
||||
BTMetadata = '212'
|
||||
SystemMemoryReset = '301'
|
||||
ResetCount = '115'
|
||||
AutoBugCapture_204 = '204'
|
||||
WifiCrashBinary = '221'
|
||||
MicroRunloopHang = '310'
|
||||
Rosetta = '213'
|
||||
glitchyspin = '302'
|
||||
System = '116'
|
||||
IOPowerSources = '141'
|
||||
PanicStats = '205'
|
||||
PowerLog_230 = '230'
|
||||
LongRunloopHang = '222'
|
||||
HomeProductsAnalytics = '311'
|
||||
DifferentialPrivacy_150 = '150'
|
||||
Rhodes = '214'
|
||||
ProactiveEventTrackerTransparency = '303'
|
||||
WiFi = '117'
|
||||
SymptomsCPUWakes = '142'
|
||||
SymptomsCPUUsageFatal = '206'
|
||||
Crash_109 = '109'
|
||||
ShortRunloopHang = '223'
|
||||
CoreHandwriting_231 = '231'
|
||||
ForceReset = '151'
|
||||
SiriAppSelection = '215'
|
||||
PrivateFederatedLearning = '304'
|
||||
Bluetooth = '118'
|
||||
SCPMotion = '143'
|
||||
HangSpin = '207'
|
||||
StepCount = '160'
|
||||
RTCTransparency = '224'
|
||||
DiagnosticRequest = '312'
|
||||
MemorySnapshot = '152'
|
||||
Rosetta_B = '216'
|
||||
AudioAccessory = '305'
|
||||
General = '119'
|
||||
HotSpotIOMicroSS = '144'
|
||||
GeoServicesTransparency = '233'
|
||||
MotionState = '161'
|
||||
AppStoreTransparency = '225'
|
||||
SiriSearchFeedback = '313'
|
||||
BearTrapReserved = '153'
|
||||
Portrait = '217'
|
||||
AWDMetricLog = 'metriclog'
|
||||
SymptomsIO = '145'
|
||||
SubmissionReserved = '170'
|
||||
WifiCrash = '209'
|
||||
Natalies = '162'
|
||||
SecurityTransparency = '226'
|
||||
BiomeMapReduce = '234'
|
||||
MemoryGraph = '154'
|
||||
MultichannelAudio = '218'
|
||||
honeybee_payload = '146'
|
||||
MesaReserved = '171'
|
||||
WifiSensing = '235'
|
||||
SiriMiss = '163'
|
||||
ExcResourceThreads_227 = '227'
|
||||
TestA = 'T01'
|
||||
NetworkUsage = '155'
|
||||
WifiReserved = '180'
|
||||
SiriActionPrediction = '219'
|
||||
honeybee_heartbeat = '147'
|
||||
ECCEvent = '172'
|
||||
KeyTransparency = '236'
|
||||
SubDiagHeartBeat = '164'
|
||||
ThirdPartyHang = '228'
|
||||
OSFault = '308'
|
||||
CoreTime = '156'
|
||||
WifiDriverReserved = '181'
|
||||
Crash_309 = '309'
|
||||
honeybee_issue = '148'
|
||||
CellularPerfReserved = '173'
|
||||
TestB = 'T02'
|
||||
StorageStatus = '165'
|
||||
SiriNotificationTransparency = '229'
|
||||
TestC = 'T03'
|
||||
CPUMicroSS = '157'
|
||||
AccessoryUpdate = '182'
|
||||
xprotect = '20'
|
||||
MultitouchFirmware = '149'
|
||||
MicroStackshot = '174'
|
||||
AppLaunchDiagnostics = '238'
|
||||
KeyboardAccuracy = '166'
|
||||
GPURestart = '21'
|
||||
FaceTime = '191'
|
||||
DuetKnowledgeCollector = '158'
|
||||
OTASUpdate = '183'
|
||||
ExcResourceThreads_327 = '327'
|
||||
ExcResource_22 = '22'
|
||||
DuetDB = '175'
|
||||
ThirdPartyHangDeveloper = '328'
|
||||
PrivacySettings = '167'
|
||||
GasGauge = '192'
|
||||
MicroStackShots = '23'
|
||||
BasebandCrash = '159'
|
||||
GPURestart_184 = '184'
|
||||
SystemWatchdogCrash = '409'
|
||||
FlashStatus = '176'
|
||||
SleepWakeFailure = '24'
|
||||
CarouselEvent = '168'
|
||||
AggregateD = '193'
|
||||
WakeupsMonitorViolation = '25'
|
||||
DifferentialPrivacy_50 = '50'
|
||||
ExcResource_185 = '185'
|
||||
UIAutomation = '177'
|
||||
ping = '26'
|
||||
SiriTransaction = '169'
|
||||
SURestore = '194'
|
||||
KtraceStackshot = '186'
|
||||
WirelessDiagnostics = '27'
|
||||
PowerLogLite = '178'
|
||||
SKAdNetworkAnalytics = '237'
|
||||
HangWorkflowResponsiveness = '239'
|
||||
CompositorClientHang = '243'
|
||||
|
||||
|
||||
class CrashReportBase:
|
||||
def __init__(self, metadata: Mapping, data: str, filename: str = None):
|
||||
self.filename = filename
|
||||
self._metadata = metadata
|
||||
self._data = data
|
||||
self._parse()
|
||||
|
||||
def _parse(self):
|
||||
self._is_json = False
|
||||
try:
|
||||
modified_data = self._data
|
||||
if '\n \n' in modified_data:
|
||||
modified_data, rest = modified_data.split('\n \n', 1)
|
||||
rest = '",' + rest.split('",', 1)[1]
|
||||
modified_data += rest
|
||||
self._data = json.loads(modified_data)
|
||||
self._is_json = True
|
||||
except json.decoder.JSONDecodeError:
|
||||
pass
|
||||
|
||||
@cached_property
|
||||
def bug_type(self) -> BugType:
|
||||
return BugType(self.bug_type_str)
|
||||
|
||||
@cached_property
|
||||
def bug_type_str(self) -> str:
|
||||
return self._metadata['bug_type']
|
||||
|
||||
@cached_property
|
||||
def incident_id(self):
|
||||
return self._metadata.get('incident_id')
|
||||
|
||||
@cached_property
|
||||
def timestamp(self) -> datetime:
|
||||
timestamp = self._metadata.get('timestamp')
|
||||
timestamp_without_timezone = timestamp.rsplit(' ', 1)[0]
|
||||
return datetime.strptime(timestamp_without_timezone, '%Y-%m-%d %H:%M:%S.%f')
|
||||
|
||||
@cached_property
|
||||
def name(self) -> str:
|
||||
return self._metadata.get('name')
|
||||
|
||||
def __repr__(self) -> str:
|
||||
filename = ''
|
||||
if self.filename:
|
||||
filename = f'FILENAME:{posixpath.basename(self.filename)} '
|
||||
return f'<{self.__class__} {filename}TIMESTAMP:{self.timestamp}>'
|
||||
|
||||
def __str__(self) -> str:
|
||||
filename = ''
|
||||
if self.filename:
|
||||
filename = self.filename
|
||||
|
||||
return cyan(f'{self.incident_id} {self.timestamp}\n{filename}\n\n')
|
||||
|
||||
|
||||
class UserModeCrashReport(CrashReportBase):
|
||||
def _parse_field(self, name: str) -> str:
|
||||
name += ':'
|
||||
for line in self._data.split('\n'):
|
||||
if line.startswith(name):
|
||||
field = line.split(name, 1)[1]
|
||||
field = field.strip()
|
||||
return field
|
||||
|
||||
@cached_property
|
||||
def faulting_thread(self) -> int:
|
||||
if self._is_json:
|
||||
return self._data['faultingThread']
|
||||
else:
|
||||
return int(self._parse_field('Triggered by Thread'))
|
||||
|
||||
@cached_property
|
||||
def frames(self) -> List[Frame]:
|
||||
result = []
|
||||
if self._is_json:
|
||||
thread_index = self.faulting_thread
|
||||
images = self._data['usedImages']
|
||||
for frame in self._data['threads'][thread_index]['frames']:
|
||||
image = images[frame['imageIndex']]
|
||||
result.append(
|
||||
Frame(image_name=image.get('path'), image_base=image.get('base'), symbol=frame.get('symbol'),
|
||||
image_offset=frame.get('imageOffset'), symbol_offset=frame.get('symbolLocation')))
|
||||
else:
|
||||
in_frames = False
|
||||
for line in self._data.split('\n'):
|
||||
if in_frames:
|
||||
splitted = line.split()
|
||||
|
||||
if len(splitted) == 0:
|
||||
break
|
||||
|
||||
assert splitted[-2] == '+'
|
||||
image_base = splitted[-3]
|
||||
if image_base.startswith('0x'):
|
||||
result.append(Frame(image_name=splitted[1], image_base=int(image_base, 16), symbol=None,
|
||||
image_offset=int(splitted[-1]), symbol_offset=None))
|
||||
else:
|
||||
# symbolicated
|
||||
result.append(Frame(image_name=splitted[1], image_base=None, symbol=image_base,
|
||||
image_offset=None, symbol_offset=int(splitted[-1])))
|
||||
|
||||
if line.startswith(f'Thread {self.faulting_thread} Crashed:'):
|
||||
in_frames = True
|
||||
|
||||
return result
|
||||
|
||||
@cached_property
|
||||
def registers(self) -> List[Register]:
|
||||
result = []
|
||||
if self._is_json:
|
||||
thread_index = self._data['faultingThread']
|
||||
thread_state = self._data['threads'][thread_index]['threadState']
|
||||
|
||||
if 'x' in thread_state:
|
||||
for i, reg_x in enumerate(thread_state['x']):
|
||||
result.append(Register(name=f'x{i}', value=reg_x['value']))
|
||||
|
||||
for i, (name, value) in enumerate(thread_state.items()):
|
||||
if name == 'x':
|
||||
for j, reg_x in enumerate(value):
|
||||
result.append(Register(name=f'x{j}', value=reg_x['value']))
|
||||
else:
|
||||
if isinstance(value, dict):
|
||||
result.append(Register(name=name, value=value['value']))
|
||||
else:
|
||||
in_frames = False
|
||||
for line in self._data.split('\n'):
|
||||
if in_frames:
|
||||
splitted = line.split()
|
||||
|
||||
if len(splitted) == 0:
|
||||
break
|
||||
|
||||
for i in range(0, len(splitted), 2):
|
||||
register_name = splitted[i]
|
||||
if not register_name.endswith(':'):
|
||||
break
|
||||
|
||||
register_name = register_name[:-1]
|
||||
register_value = int(splitted[i + 1], 16)
|
||||
|
||||
result.append(Register(name=register_name, value=register_value))
|
||||
|
||||
if line.startswith(f'Thread {self.faulting_thread} crashed with ARM Thread State'):
|
||||
in_frames = True
|
||||
|
||||
return result
|
||||
|
||||
@cached_property
|
||||
def exception_type(self):
|
||||
if self._is_json:
|
||||
return self._data['exception'].get('type')
|
||||
else:
|
||||
return self._parse_field('Exception Type')
|
||||
|
||||
@cached_property
|
||||
def exception_subtype(self) -> Optional[str]:
|
||||
if self._is_json:
|
||||
return self._data['exception'].get('subtype')
|
||||
else:
|
||||
return self._parse_field('Exception Subtype')
|
||||
|
||||
@cached_property
|
||||
def application_specific_information(self) -> Optional[str]:
|
||||
result = ''
|
||||
if self._is_json:
|
||||
asi = self._data.get('asi')
|
||||
if asi is None:
|
||||
return None
|
||||
return asi
|
||||
else:
|
||||
in_frames = False
|
||||
for line in self._data.split('\n'):
|
||||
if in_frames:
|
||||
line = line.strip()
|
||||
if len(line) == 0:
|
||||
break
|
||||
|
||||
result += line + '\n'
|
||||
|
||||
if line.startswith('Application Specific Information:'):
|
||||
in_frames = True
|
||||
|
||||
result = result.strip()
|
||||
if not result:
|
||||
return None
|
||||
return result
|
||||
|
||||
def __str__(self) -> str:
|
||||
result = super().__str__()
|
||||
result += bold(f'Exception: {self.exception_type}\n')
|
||||
|
||||
if self.exception_subtype:
|
||||
result += bold('Exception Subtype: ')
|
||||
result += f'{self.exception_subtype}\n'
|
||||
|
||||
if self.application_specific_information:
|
||||
result += bold('Application Specific Information: ')
|
||||
result += str(self.application_specific_information)
|
||||
|
||||
result += '\n'
|
||||
|
||||
result += bold('Registers:')
|
||||
for i, register in enumerate(self.registers):
|
||||
if i % 4 == 0:
|
||||
result += '\n'
|
||||
|
||||
result += f'{register.name} = 0x{register.value:016x} '.rjust(30)
|
||||
|
||||
result += '\n\n'
|
||||
|
||||
result += bold('Frames:\n')
|
||||
for frame in self.frames:
|
||||
image_base = '_HEADER'
|
||||
if frame.image_base is not None:
|
||||
image_base = f'0x{frame.image_base:x}'
|
||||
result += f'\t[{frame.image_name}] {image_base}'
|
||||
if frame.image_offset:
|
||||
result += f' + 0x{frame.image_offset:x}'
|
||||
if frame.symbol is not None:
|
||||
result += f' ({frame.symbol} + 0x{frame.symbol_offset:x})'
|
||||
result += '\n'
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def get_crash_report_from_file(crash_report_file: IO) -> CrashReportBase:
|
||||
metadata = json.loads(crash_report_file.readline())
|
||||
|
||||
try:
|
||||
bug_type = BugType(metadata['bug_type'])
|
||||
except ValueError:
|
||||
return CrashReportBase(metadata, crash_report_file.read(), crash_report_file.name)
|
||||
|
||||
bug_type_parsers = {
|
||||
BugType.Crash_109: UserModeCrashReport,
|
||||
BugType.Crash_309: UserModeCrashReport,
|
||||
BugType.ExcResourceThreads_327: UserModeCrashReport,
|
||||
BugType.ExcResource_385: UserModeCrashReport,
|
||||
}
|
||||
|
||||
parser = bug_type_parsers.get(bug_type)
|
||||
if parser is None:
|
||||
return CrashReportBase(metadata, crash_report_file.read(), crash_report_file.name)
|
||||
|
||||
return parser(metadata, crash_report_file.read(), crash_report_file.name)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
with open(sys.argv[-1]) as f:
|
||||
print(get_crash_report_from_file(f))
|
||||
4
.gitignore
vendored
@@ -4,6 +4,9 @@
|
||||
*.bin
|
||||
*_stub.pyi
|
||||
*_generated.go
|
||||
*_generated.s
|
||||
*_generated_test.go
|
||||
*_generated_test.s
|
||||
*_generated.h
|
||||
/.dmypy.json
|
||||
/dependencies
|
||||
@@ -18,6 +21,7 @@ __pycache__/
|
||||
/glfw/wayland-*-client-protocol.[ch]
|
||||
/docs/_build/
|
||||
/docs/generated/
|
||||
/tools/simdstring/simdstring.test
|
||||
/.mypy_cache
|
||||
/.ruff_cache
|
||||
.DS_Store
|
||||
|
||||
28
3rdparty/base64/LICENSE
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
Copyright (c) 2005-2007, Nick Galbreath
|
||||
Copyright (c) 2015-2018, Wojciech Muła
|
||||
Copyright (c) 2016-2017, Matthieu Darbois
|
||||
Copyright (c) 2013-2022, Alfred Klomp
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
491
3rdparty/base64/README.md
vendored
Normal file
@@ -0,0 +1,491 @@
|
||||
# Fast Base64 stream encoder/decoder
|
||||
|
||||
[](https://github.com/aklomp/base64/actions/workflows/test.yml)
|
||||
|
||||
This is an implementation of a base64 stream encoding/decoding library in C99
|
||||
with SIMD (AVX2, AVX512, NEON, AArch64/NEON, SSSE3, SSE4.1, SSE4.2, AVX) and
|
||||
[OpenMP](http://www.openmp.org) acceleration. It also contains wrapper functions
|
||||
to encode/decode simple length-delimited strings. This library aims to be:
|
||||
|
||||
- FAST;
|
||||
- easy to use;
|
||||
- elegant.
|
||||
|
||||
On x86, the library does runtime feature detection. The first time it's called,
|
||||
the library will determine the appropriate encoding/decoding routines for the
|
||||
machine. It then remembers them for the lifetime of the program. If your
|
||||
processor supports AVX2, SSSE3, SSE4.1, SSE4.2 or AVX instructions, the library
|
||||
will pick an optimized codec that lets it encode/decode 12 or 24 bytes at a
|
||||
time, which gives a speedup of four or more times compared to the "plain"
|
||||
bytewise codec.
|
||||
|
||||
AVX512 support is only for encoding at present, utilizing the AVX512 VL and VBMI
|
||||
instructions. Decoding part reused AVX2 implementations. For CPUs later than
|
||||
Cannonlake (manufactured in 2018) supports these instructions.
|
||||
|
||||
NEON support is hardcoded to on or off at compile time, because portable
|
||||
runtime feature detection is unavailable on ARM.
|
||||
|
||||
Even if your processor does not support SIMD instructions, this is a very fast
|
||||
library. The fallback routine can process 32 or 64 bits of input in one round,
|
||||
depending on your processor's word width, which still makes it significantly
|
||||
faster than naive bytewise implementations. On some 64-bit machines, the 64-bit
|
||||
routines even outperform the SSSE3 ones.
|
||||
|
||||
To the author's knowledge, at the time of original release, this was the only
|
||||
Base64 library to offer SIMD acceleration. The author wrote
|
||||
[an article](http://www.alfredklomp.com/programming/sse-base64) explaining one
|
||||
possible SIMD approach to encoding/decoding Base64. The article can help figure
|
||||
out what the code is doing, and why.
|
||||
|
||||
Notable features:
|
||||
|
||||
- Really fast on x86 and ARM systems by using SIMD vector processing;
|
||||
- Can use [OpenMP](http://www.openmp.org) for even more parallel speedups;
|
||||
- Really fast on other 32 or 64-bit platforms through optimized routines;
|
||||
- Reads/writes blocks of streaming data;
|
||||
- Does not dynamically allocate memory;
|
||||
- Valid C99 that compiles with pedantic options on;
|
||||
- Re-entrant and threadsafe;
|
||||
- Unit tested;
|
||||
- Uses Duff's Device.
|
||||
|
||||
## Acknowledgements
|
||||
|
||||
The original AVX2, NEON and Aarch64/NEON codecs were generously contributed by
|
||||
[Inkymail](https://github.com/inkymail/base64), who, in their fork, also
|
||||
implemented some additional features. Their work is slowly being backported
|
||||
into this project.
|
||||
|
||||
The SSSE3 and AVX2 codecs were substantially improved by using some very clever
|
||||
optimizations described by Wojciech Muła in a
|
||||
[series](http://0x80.pl/notesen/2016-01-12-sse-base64-encoding.html) of
|
||||
[articles](http://0x80.pl/notesen/2016-01-17-sse-base64-decoding.html).
|
||||
His own code is [here](https://github.com/WojciechMula/toys/tree/master/base64).
|
||||
|
||||
The AVX512 encoder is based on code from Wojciech Muła's
|
||||
[base64simd](https://github.com/WojciechMula/base64simd) library.
|
||||
|
||||
The OpenMP implementation was added by Ferry Toth (@htot) from [Exalon Delft](http://www.exalondelft.nl).
|
||||
|
||||
## Building
|
||||
|
||||
The `lib` directory contains the code for the actual library.
|
||||
Typing `make` in the toplevel directory will build `lib/libbase64.o` and `bin/base64`.
|
||||
The first is a single, self-contained object file that you can link into your own project.
|
||||
The second is a standalone test binary that works similarly to the `base64` system utility.
|
||||
|
||||
The matching header file needed to use this library is in `include/libbase64.h`.
|
||||
|
||||
To compile just the "plain" library without SIMD codecs, type:
|
||||
|
||||
```sh
|
||||
make lib/libbase64.o
|
||||
```
|
||||
|
||||
Optional SIMD codecs can be included by specifying the `AVX2_CFLAGS`, `AVX512_CFLAGS`,
|
||||
`NEON32_CFLAGS`, `NEON64_CFLAGS`, `SSSE3_CFLAGS`, `SSE41_CFLAGS`, `SSE42_CFLAGS` and/or `AVX_CFLAGS` environment variables.
|
||||
A typical build invocation on x86 looks like this:
|
||||
|
||||
```sh
|
||||
AVX2_CFLAGS=-mavx2 SSSE3_CFLAGS=-mssse3 SSE41_CFLAGS=-msse4.1 SSE42_CFLAGS=-msse4.2 AVX_CFLAGS=-mavx make lib/libbase64.o
|
||||
```
|
||||
|
||||
### AVX2
|
||||
|
||||
To build and include the AVX2 codec, set the `AVX2_CFLAGS` environment variable to a value that will turn on AVX2 support in your compiler, typically `-mavx2`.
|
||||
Example:
|
||||
|
||||
```sh
|
||||
AVX2_CFLAGS=-mavx2 make
|
||||
```
|
||||
|
||||
### AVX512
|
||||
|
||||
To build and include the AVX512 codec, set the `AVX512_CFLAGS` environment variable to a value that will turn on AVX512 support in your compiler, typically `-mavx512vl -mavx512vbmi`.
|
||||
Example:
|
||||
|
||||
```sh
|
||||
AVX512_CFLAGS="-mavx512vl -mavx512vbmi" make
|
||||
```
|
||||
|
||||
The codec will only be used if runtime feature detection shows that the target machine supports AVX2.
|
||||
|
||||
### SSSE3
|
||||
|
||||
To build and include the SSSE3 codec, set the `SSSE3_CFLAGS` environment variable to a value that will turn on SSSE3 support in your compiler, typically `-mssse3`.
|
||||
Example:
|
||||
|
||||
```sh
|
||||
SSSE3_CFLAGS=-mssse3 make
|
||||
```
|
||||
|
||||
The codec will only be used if runtime feature detection shows that the target machine supports SSSE3.
|
||||
|
||||
### NEON
|
||||
|
||||
This library includes two NEON codecs: one for regular 32-bit ARM and one for the 64-bit AArch64 with NEON, which has double the amount of SIMD registers and can do full 64-byte table lookups.
|
||||
These codecs encode in 48-byte chunks and decode in massive 64-byte chunks, so they had to be augmented with an uint32/64 codec to stay fast on smaller inputs!
|
||||
|
||||
Use LLVM/Clang for compiling the NEON codecs.
|
||||
The code generation of at least GCC 4.6 (the version shipped with Raspbian and used for testing) contains a bug when compiling `vstq4_u8()`, and the generated assembly code is of low quality.
|
||||
NEON intrinsics are a known weak area of GCC.
|
||||
Clang does a better job.
|
||||
|
||||
NEON support can unfortunately not be portably detected at runtime from userland (the `mrc` instruction is privileged), so the default value for using the NEON codec is determined at compile-time.
|
||||
But you can do your own runtime detection.
|
||||
You can include the NEON codec and make it the default, then do a runtime check if the CPU has NEON support, and if not, force a downgrade to non-NEON with `BASE64_FORCE_PLAIN`.
|
||||
|
||||
These are your options:
|
||||
|
||||
1. Don't include NEON support;
|
||||
2. build NEON support and make it the default, but build all other code without NEON flags so that you can override the default at runtime with `BASE64_FORCE_PLAIN`;
|
||||
3. build everything with NEON support and make it the default;
|
||||
4. build everything with NEON support, but don't make it the default (which makes no sense).
|
||||
|
||||
For option 1, simply don't specify any NEON-specific compiler flags at all, like so:
|
||||
|
||||
```sh
|
||||
CC=clang CFLAGS="-march=armv6" make
|
||||
```
|
||||
|
||||
For option 2, keep your `CFLAGS` plain, but set the `NEON32_CFLAGS` environment variable to a value that will build NEON support.
|
||||
The line below, for instance, will build all the code at ARMv6 level, except for the NEON codec, which is built at ARMv7.
|
||||
It will also make the NEON codec the default.
|
||||
For ARMv6 platforms, override that default at runtime with the `BASE64_FORCE_PLAIN` flag.
|
||||
No ARMv7/NEON code will then be touched.
|
||||
|
||||
```sh
|
||||
CC=clang CFLAGS="-march=armv6" NEON32_CFLAGS="-march=armv7 -mfpu=neon" make
|
||||
```
|
||||
|
||||
For option 3, put everything in your `CFLAGS` and use a stub, but non-empty, `NEON32_CFLAGS`.
|
||||
This example works for the Raspberry Pi 2B V1.1, which has NEON support:
|
||||
|
||||
```sh
|
||||
CC=clang CFLAGS="-march=armv7 -mtune=cortex-a7" NEON32_CFLAGS="-mfpu=neon" make
|
||||
```
|
||||
|
||||
To build and include the NEON64 codec, use `CFLAGS` as usual to define the platform and set `NEON64_CFLAGS` to a nonempty stub.
|
||||
(The AArch64 target has mandatory NEON64 support.)
|
||||
Example:
|
||||
|
||||
```sh
|
||||
CC=clang CFLAGS="--target=aarch64-linux-gnu -march=armv8-a" NEON64_CFLAGS=" " make
|
||||
```
|
||||
|
||||
### OpenMP
|
||||
|
||||
To enable OpenMP on GCC you need to build with `-fopenmp`. This can be by setting the `OPENMP` environment variable to `1`.
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
OPENMP=1 make
|
||||
```
|
||||
|
||||
This will let the compiler define `_OPENMP`, which in turn will include the OpenMP optimized `lib_openmp.c` into `lib.c`.
|
||||
|
||||
By default the number of parallel threads will be equal to the number of cores of the processor.
|
||||
On a quad core with hyperthreading eight cores will be detected, but hyperthreading will not increase the performance.
|
||||
|
||||
To get verbose information about OpenMP start the program with `OMP_DISPLAY_ENV=VERBOSE`, for instance
|
||||
|
||||
```sh
|
||||
OMP_DISPLAY_ENV=VERBOSE test/benchmark
|
||||
```
|
||||
|
||||
To put a limit on the number of threads, start the program with `OMP_THREAD_LIMIT=n`, for instance
|
||||
|
||||
```sh
|
||||
OMP_THREAD_LIMIT=2 test/benchmark
|
||||
```
|
||||
|
||||
An example of running a benchmark with OpenMP, SSSE3 and AVX2 enabled:
|
||||
|
||||
```sh
|
||||
make clean && OPENMP=1 SSSE3_CFLAGS=-mssse3 AVX2_CFLAGS=-mavx2 make && OPENMP=1 make -C test
|
||||
```
|
||||
|
||||
## API reference
|
||||
|
||||
Strings are represented as a pointer and a length; they are not
|
||||
zero-terminated. This was a conscious design decision. In the decoding step,
|
||||
relying on zero-termination would make no sense since the output could contain
|
||||
legitimate zero bytes. In the encoding step, returning the length saves the
|
||||
overhead of calling `strlen()` on the output. If you insist on the trailing
|
||||
zero, you can easily add it yourself at the given offset.
|
||||
|
||||
### Flags
|
||||
|
||||
Some API calls take a `flags` argument.
|
||||
That argument can be used to force the use of a specific codec, even if that codec is a no-op in the current build.
|
||||
Mainly there for testing purposes, this is also useful on ARM where the only way to do runtime NEON detection is to ask the OS if it's available.
|
||||
The following constants can be used:
|
||||
|
||||
- `BASE64_FORCE_AVX2`
|
||||
- `BASE64_FORCE_AVX512`
|
||||
- `BASE64_FORCE_NEON32`
|
||||
- `BASE64_FORCE_NEON64`
|
||||
- `BASE64_FORCE_PLAIN`
|
||||
- `BASE64_FORCE_SSSE3`
|
||||
- `BASE64_FORCE_SSE41`
|
||||
- `BASE64_FORCE_SSE42`
|
||||
- `BASE64_FORCE_AVX`
|
||||
|
||||
Set `flags` to `0` for the default behavior, which is runtime feature detection on x86, a compile-time fixed codec on ARM, and the plain codec on other platforms.
|
||||
|
||||
### Encoding
|
||||
|
||||
#### base64_encode
|
||||
|
||||
```c
|
||||
void base64_encode
|
||||
( const char *src
|
||||
, size_t srclen
|
||||
, char *out
|
||||
, size_t *outlen
|
||||
, int flags
|
||||
) ;
|
||||
```
|
||||
|
||||
Wrapper function to encode a plain string of given length.
|
||||
Output is written to `out` without trailing zero.
|
||||
Output length in bytes is written to `outlen`.
|
||||
The buffer in `out` has been allocated by the caller and is at least 4/3 the size of the input.
|
||||
|
||||
#### base64_stream_encode_init
|
||||
|
||||
```c
|
||||
void base64_stream_encode_init
|
||||
( struct base64_state *state
|
||||
, int flags
|
||||
) ;
|
||||
```
|
||||
|
||||
Call this before calling `base64_stream_encode()` to init the state.
|
||||
|
||||
#### base64_stream_encode
|
||||
|
||||
```c
|
||||
void base64_stream_encode
|
||||
( struct base64_state *state
|
||||
, const char *src
|
||||
, size_t srclen
|
||||
, char *out
|
||||
, size_t *outlen
|
||||
) ;
|
||||
```
|
||||
|
||||
Encodes the block of data of given length at `src`, into the buffer at `out`.
|
||||
Caller is responsible for allocating a large enough out-buffer; it must be at least 4/3 the size of the in-buffer, but take some margin.
|
||||
Places the number of new bytes written into `outlen` (which is set to zero when the function starts).
|
||||
Does not zero-terminate or finalize the output.
|
||||
|
||||
#### base64_stream_encode_final
|
||||
|
||||
```c
|
||||
void base64_stream_encode_final
|
||||
( struct base64_state *state
|
||||
, char *out
|
||||
, size_t *outlen
|
||||
) ;
|
||||
```
|
||||
|
||||
Finalizes the output begun by previous calls to `base64_stream_encode()`.
|
||||
Adds the required end-of-stream markers if appropriate.
|
||||
`outlen` is modified and will contain the number of new bytes written at `out` (which will quite often be zero).
|
||||
|
||||
### Decoding
|
||||
|
||||
#### base64_decode
|
||||
|
||||
```c
|
||||
int base64_decode
|
||||
( const char *src
|
||||
, size_t srclen
|
||||
, char *out
|
||||
, size_t *outlen
|
||||
, int flags
|
||||
) ;
|
||||
```
|
||||
|
||||
Wrapper function to decode a plain string of given length.
|
||||
Output is written to `out` without trailing zero. Output length in bytes is written to `outlen`.
|
||||
The buffer in `out` has been allocated by the caller and is at least 3/4 the size of the input.
|
||||
Returns `1` for success, and `0` when a decode error has occured due to invalid input.
|
||||
Returns `-1` if the chosen codec is not included in the current build.
|
||||
|
||||
#### base64_stream_decode_init
|
||||
|
||||
```c
|
||||
void base64_stream_decode_init
|
||||
( struct base64_state *state
|
||||
, int flags
|
||||
) ;
|
||||
```
|
||||
|
||||
Call this before calling `base64_stream_decode()` to init the state.
|
||||
|
||||
#### base64_stream_decode
|
||||
|
||||
```c
|
||||
int base64_stream_decode
|
||||
( struct base64_state *state
|
||||
, const char *src
|
||||
, size_t srclen
|
||||
, char *out
|
||||
, size_t *outlen
|
||||
) ;
|
||||
```
|
||||
|
||||
Decodes the block of data of given length at `src`, into the buffer at `out`.
|
||||
Caller is responsible for allocating a large enough out-buffer; it must be at least 3/4 the size of the in-buffer, but take some margin.
|
||||
Places the number of new bytes written into `outlen` (which is set to zero when the function starts).
|
||||
Does not zero-terminate the output.
|
||||
Returns 1 if all is well, and 0 if a decoding error was found, such as an invalid character.
|
||||
Returns -1 if the chosen codec is not included in the current build.
|
||||
Used by the test harness to check whether a codec is available for testing.
|
||||
|
||||
## Examples
|
||||
|
||||
A simple example of encoding a static string to base64 and printing the output
|
||||
to stdout:
|
||||
|
||||
```c
|
||||
#include <stdio.h> /* fwrite */
|
||||
#include "libbase64.h"
|
||||
|
||||
int main ()
|
||||
{
|
||||
char src[] = "hello world";
|
||||
char out[20];
|
||||
size_t srclen = sizeof(src) - 1;
|
||||
size_t outlen;
|
||||
|
||||
base64_encode(src, srclen, out, &outlen, 0);
|
||||
|
||||
fwrite(out, outlen, 1, stdout);
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
A simple example (no error checking, etc) of stream encoding standard input to
|
||||
standard output:
|
||||
|
||||
```c
|
||||
#include <stdio.h>
|
||||
#include "libbase64.h"
|
||||
|
||||
int main ()
|
||||
{
|
||||
size_t nread, nout;
|
||||
char buf[12000], out[16000];
|
||||
struct base64_state state;
|
||||
|
||||
// Initialize stream encoder:
|
||||
base64_stream_encode_init(&state, 0);
|
||||
|
||||
// Read contents of stdin into buffer:
|
||||
while ((nread = fread(buf, 1, sizeof(buf), stdin)) > 0) {
|
||||
|
||||
// Encode buffer:
|
||||
base64_stream_encode(&state, buf, nread, out, &nout);
|
||||
|
||||
// If there's output, print it to stdout:
|
||||
if (nout) {
|
||||
fwrite(out, nout, 1, stdout);
|
||||
}
|
||||
|
||||
// If an error occurred, exit the loop:
|
||||
if (feof(stdin)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Finalize encoding:
|
||||
base64_stream_encode_final(&state, out, &nout);
|
||||
|
||||
// If the finalizing resulted in extra output bytes, print them:
|
||||
if (nout) {
|
||||
fwrite(out, nout, 1, stdout);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
Also see `bin/base64.c` for a simple re-implementation of the `base64` utility.
|
||||
A file or standard input is fed through the encoder/decoder, and the output is
|
||||
written to standard output.
|
||||
|
||||
## Tests
|
||||
|
||||
See `tests/` for a small test suite. Testing is automated with
|
||||
[GitHub Actions](https://github.com/aklomp/base64/actions), which builds and
|
||||
tests the code across various architectures.
|
||||
|
||||
## Benchmarks
|
||||
|
||||
Benchmarks can be run with the built-in benchmark program as follows:
|
||||
|
||||
```sh
|
||||
make -C test benchmark <buildflags> && test/benchmark
|
||||
```
|
||||
|
||||
It will run an encoding and decoding benchmark for all of the compiled-in codecs.
|
||||
|
||||
The tables below contain some results on random machines. All numbers measured with a 10MB buffer in MB/sec, rounded to the nearest integer.
|
||||
|
||||
\*: Update needed
|
||||
|
||||
x86 processors
|
||||
|
||||
| Processor | Plain enc | Plain dec | SSSE3 enc | SSSE3 dec | AVX enc | AVX dec | AVX2 enc | AVX2 dec |
|
||||
|-------------------------------------------|----------:|----------:|----------:|----------:|--------:|--------:|---------:|---------:|
|
||||
| i7-4771 @ 3.5 GHz | 833\* | 1111\* | 3333\* | 4444\* | TBD | TBD | 4999\* | 6666\* |
|
||||
| i7-4770 @ 3.4 GHz DDR1600 | 1790\* | 3038\* | 4899\* | 4043\* | 4796\* | 5709\* | 4681\* | 6386\* |
|
||||
| i7-4770 @ 3.4 GHz DDR1600 OPENMP 1 thread | 1784\* | 3041\* | 4945\* | 4035\* | 4776\* | 5719\* | 4661\* | 6294\* |
|
||||
| i7-4770 @ 3.4 GHz DDR1600 OPENMP 2 thread | 3401\* | 5729\* | 5489\* | 7444\* | 5003\* | 8624\* | 5105\* | 8558\* |
|
||||
| i7-4770 @ 3.4 GHz DDR1600 OPENMP 4 thread | 4884\* | 7099\* | 4917\* | 7057\* | 4799\* | 7143\* | 4902\* | 7219\* |
|
||||
| i7-4770 @ 3.4 GHz DDR1600 OPENMP 8 thread | 5212\* | 8849\* | 5284\* | 9099\* | 5289\* | 9220\* | 4849\* | 9200\* |
|
||||
| i7-4870HQ @ 2.5 GHz | 1471\* | 3066\* | 6721\* | 6962\* | 7015\* | 8267\* | 8328\* | 11576\* |
|
||||
| i5-4590S @ 3.0 GHz | 3356 | 3197 | 4363 | 6104 | 4243\* | 6233 | 4160\* | 6344 |
|
||||
| Xeon X5570 @ 2.93 GHz | 2161 | 1508 | 3160 | 3915 | - | - | - | - |
|
||||
| Pentium4 @ 3.4 GHz | 896 | 740 | - | - | - | - | - | - |
|
||||
| Atom N270 | 243 | 266 | 508 | 387 | - | - | - | - |
|
||||
| AMD E-450 | 645 | 564 | 625 | 634 | - | - | - | - |
|
||||
| Intel Edison @ 500 MHz | 79\* | 92\* | 152\* | 172\* | - | - | - | - |
|
||||
| Intel Edison @ 500 MHz OPENMP 2 thread | 158\* | 184\* | 300\* | 343\* | - | - | - | - |
|
||||
| Intel Edison @ 500 MHz (x86-64) | 162 | 119 | 209 | 164 | - | - | - | - |
|
||||
| Intel Edison @ 500 MHz (x86-64) 2 thread | 319 | 237 | 412 | 329 | - | - | - | - |
|
||||
|
||||
ARM processors
|
||||
|
||||
| Processor | Plain enc | Plain dec | NEON32 enc | NEON32 dec | NEON64 enc | NEON64 dec |
|
||||
|-------------------------------------------|----------:|----------:|-----------:|-----------:|-----------:|-----------:|
|
||||
| Raspberry PI B+ V1.2 | 46\* | 40\* | - | - | - | - |
|
||||
| Raspberry PI 2 B V1.1 | 85 | 141 | 300 | 225 | - | - |
|
||||
| Apple iPhone SE armv7 | 1056\* | 895\* | 2943\* | 2618\* | - | - |
|
||||
| Apple iPhone SE arm64 | 1061\* | 1239\* | - | - | 4098\* | 3983\* |
|
||||
|
||||
PowerPC processors
|
||||
|
||||
| Processor | Plain enc | Plain dec |
|
||||
|-------------------------------------------|----------:|----------:|
|
||||
| PowerPC E6500 @ 1.8GHz | 270\* | 265\* |
|
||||
|
||||
|
||||
Benchmarks on i7-4770 @ 3.4 GHz DDR1600 with varrying buffer sizes:
|
||||

|
||||
|
||||
Note: optimal buffer size to take advantage of the cache is in the range of 100 kB to 1 MB, leading to 12x faster AVX encoding/decoding compared to Plain, or a throughput of 24/27GB/sec.
|
||||
Also note the performance degradation when the buffer size is less than 10 kB due to thread creation overhead.
|
||||
To prevent this from happening `lib_openmp.c` defines `OMP_THRESHOLD 20000`, requiring at least a 20000 byte buffer to enable multithreading.
|
||||
|
||||
## License
|
||||
|
||||
This repository is licensed under the
|
||||
[BSD 2-clause License](http://opensource.org/licenses/BSD-2-Clause). See the
|
||||
LICENSE file.
|
||||
0
3rdparty/base64/config.h
vendored
Normal file
146
3rdparty/base64/include/libbase64.h
vendored
Normal file
@@ -0,0 +1,146 @@
|
||||
#ifndef LIBBASE64_H
|
||||
#define LIBBASE64_H
|
||||
|
||||
#include <stddef.h> /* size_t */
|
||||
|
||||
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
#define BASE64_SYMBOL_IMPORT __declspec(dllimport)
|
||||
#define BASE64_SYMBOL_EXPORT __declspec(dllexport)
|
||||
#define BASE64_SYMBOL_PRIVATE
|
||||
|
||||
#elif __GNUC__ >= 4
|
||||
#define BASE64_SYMBOL_IMPORT __attribute__ ((visibility ("default")))
|
||||
#define BASE64_SYMBOL_EXPORT __attribute__ ((visibility ("default")))
|
||||
#define BASE64_SYMBOL_PRIVATE __attribute__ ((visibility ("hidden")))
|
||||
|
||||
#else
|
||||
#define BASE64_SYMBOL_IMPORT
|
||||
#define BASE64_SYMBOL_EXPORT
|
||||
#define BASE64_SYMBOL_PRIVATE
|
||||
#endif
|
||||
|
||||
#if defined(BASE64_STATIC_DEFINE)
|
||||
#define BASE64_EXPORT
|
||||
#define BASE64_NO_EXPORT
|
||||
|
||||
#else
|
||||
#if defined(BASE64_EXPORTS) // defined if we are building the shared library
|
||||
#define BASE64_EXPORT BASE64_SYMBOL_EXPORT
|
||||
|
||||
#else
|
||||
#define BASE64_EXPORT BASE64_SYMBOL_IMPORT
|
||||
#endif
|
||||
|
||||
#define BASE64_NO_EXPORT BASE64_SYMBOL_PRIVATE
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* These are the flags that can be passed in the `flags` argument. The values
|
||||
* below force the use of a given codec, even if that codec is a no-op in the
|
||||
* current build. Used in testing. Set to 0 for the default behavior, which is
|
||||
* runtime feature detection on x86, a compile-time fixed codec on ARM, and
|
||||
* the plain codec on other platforms: */
|
||||
#define BASE64_FORCE_AVX2 (1 << 0)
|
||||
#define BASE64_FORCE_NEON32 (1 << 1)
|
||||
#define BASE64_FORCE_NEON64 (1 << 2)
|
||||
#define BASE64_FORCE_PLAIN (1 << 3)
|
||||
#define BASE64_FORCE_SSSE3 (1 << 4)
|
||||
#define BASE64_FORCE_SSE41 (1 << 5)
|
||||
#define BASE64_FORCE_SSE42 (1 << 6)
|
||||
#define BASE64_FORCE_AVX (1 << 7)
|
||||
#define BASE64_FORCE_AVX512 (1 << 8)
|
||||
|
||||
struct base64_state {
|
||||
int eof;
|
||||
int bytes;
|
||||
int flags;
|
||||
unsigned char carry;
|
||||
};
|
||||
|
||||
/* Wrapper function to encode a plain string of given length. Output is written
|
||||
* to *out without trailing zero. Output length in bytes is written to *outlen.
|
||||
* The buffer in `out` has been allocated by the caller and is at least 4/3 the
|
||||
* size of the input. See above for `flags`; set to 0 for default operation: */
|
||||
void BASE64_EXPORT base64_encode
|
||||
( const char *src
|
||||
, size_t srclen
|
||||
, char *out
|
||||
, size_t *outlen
|
||||
, int flags
|
||||
) ;
|
||||
|
||||
/* Call this before calling base64_stream_encode() to init the state. See above
|
||||
* for `flags`; set to 0 for default operation: */
|
||||
void BASE64_EXPORT base64_stream_encode_init
|
||||
( struct base64_state *state
|
||||
, int flags
|
||||
) ;
|
||||
|
||||
/* Encodes the block of data of given length at `src`, into the buffer at
|
||||
* `out`. Caller is responsible for allocating a large enough out-buffer; it
|
||||
* must be at least 4/3 the size of the in-buffer, but take some margin. Places
|
||||
* the number of new bytes written into `outlen` (which is set to zero when the
|
||||
* function starts). Does not zero-terminate or finalize the output. */
|
||||
void BASE64_EXPORT base64_stream_encode
|
||||
( struct base64_state *state
|
||||
, const char *src
|
||||
, size_t srclen
|
||||
, char *out
|
||||
, size_t *outlen
|
||||
) ;
|
||||
|
||||
/* Finalizes the output begun by previous calls to `base64_stream_encode()`.
|
||||
* Adds the required end-of-stream markers if appropriate. `outlen` is modified
|
||||
* and will contain the number of new bytes written at `out` (which will quite
|
||||
* often be zero). */
|
||||
void BASE64_EXPORT base64_stream_encode_final
|
||||
( struct base64_state *state
|
||||
, char *out
|
||||
, size_t *outlen
|
||||
) ;
|
||||
|
||||
/* Wrapper function to decode a plain string of given length. Output is written
|
||||
* to *out without trailing zero. Output length in bytes is written to *outlen.
|
||||
* The buffer in `out` has been allocated by the caller and is at least 3/4 the
|
||||
* size of the input. See above for `flags`, set to 0 for default operation: */
|
||||
int BASE64_EXPORT base64_decode
|
||||
( const char *src
|
||||
, size_t srclen
|
||||
, char *out
|
||||
, size_t *outlen
|
||||
, int flags
|
||||
) ;
|
||||
|
||||
/* Call this before calling base64_stream_decode() to init the state. See above
|
||||
* for `flags`; set to 0 for default operation: */
|
||||
void BASE64_EXPORT base64_stream_decode_init
|
||||
( struct base64_state *state
|
||||
, int flags
|
||||
) ;
|
||||
|
||||
/* Decodes the block of data of given length at `src`, into the buffer at
|
||||
* `out`. Caller is responsible for allocating a large enough out-buffer; it
|
||||
* must be at least 3/4 the size of the in-buffer, but take some margin. Places
|
||||
* the number of new bytes written into `outlen` (which is set to zero when the
|
||||
* function starts). Does not zero-terminate the output. Returns 1 if all is
|
||||
* well, and 0 if a decoding error was found, such as an invalid character.
|
||||
* Returns -1 if the chosen codec is not included in the current build. Used by
|
||||
* the test harness to check whether a codec is available for testing. */
|
||||
int BASE64_EXPORT base64_stream_decode
|
||||
( struct base64_state *state
|
||||
, const char *src
|
||||
, size_t srclen
|
||||
, char *out
|
||||
, size_t *outlen
|
||||
) ;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* LIBBASE64_H */
|
||||
66
3rdparty/base64/lib/arch/avx/codec.c
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../../../include/libbase64.h"
|
||||
#include "../../tables/tables.h"
|
||||
#include "../../codecs.h"
|
||||
#include "config.h"
|
||||
#include "../../env.h"
|
||||
|
||||
#if HAVE_AVX
|
||||
#include <immintrin.h>
|
||||
|
||||
// Only enable inline assembly on supported compilers and on 64-bit CPUs.
|
||||
#ifndef BASE64_AVX_USE_ASM
|
||||
# if (defined(__GNUC__) || defined(__clang__)) && BASE64_WORDSIZE == 64
|
||||
# define BASE64_AVX_USE_ASM 1
|
||||
# else
|
||||
# define BASE64_AVX_USE_ASM 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "../ssse3/dec_reshuffle.c"
|
||||
#include "../ssse3/dec_loop.c"
|
||||
|
||||
#if BASE64_AVX_USE_ASM
|
||||
# include "enc_loop_asm.c"
|
||||
#else
|
||||
# include "../ssse3/enc_translate.c"
|
||||
# include "../ssse3/enc_reshuffle.c"
|
||||
# include "../ssse3/enc_loop.c"
|
||||
#endif
|
||||
|
||||
#endif // HAVE_AVX
|
||||
|
||||
BASE64_ENC_FUNCTION(avx)
|
||||
{
|
||||
#if HAVE_AVX
|
||||
#include "../generic/enc_head.c"
|
||||
|
||||
// For supported compilers, use a hand-optimized inline assembly
|
||||
// encoder. Otherwise fall back on the SSSE3 encoder, but compiled with
|
||||
// AVX flags to generate better optimized AVX code.
|
||||
|
||||
#if BASE64_AVX_USE_ASM
|
||||
enc_loop_avx(&s, &slen, &o, &olen);
|
||||
#else
|
||||
enc_loop_ssse3(&s, &slen, &o, &olen);
|
||||
#endif
|
||||
|
||||
#include "../generic/enc_tail.c"
|
||||
#else
|
||||
BASE64_ENC_STUB
|
||||
#endif
|
||||
}
|
||||
|
||||
BASE64_DEC_FUNCTION(avx)
|
||||
{
|
||||
#if HAVE_AVX
|
||||
#include "../generic/dec_head.c"
|
||||
dec_loop_ssse3(&s, &slen, &o, &olen);
|
||||
#include "../generic/dec_tail.c"
|
||||
#else
|
||||
BASE64_DEC_STUB
|
||||
#endif
|
||||
}
|
||||
264
3rdparty/base64/lib/arch/avx/enc_loop_asm.c
vendored
Normal file
@@ -0,0 +1,264 @@
|
||||
// Apologies in advance for combining the preprocessor with inline assembly,
|
||||
// two notoriously gnarly parts of C, but it was necessary to avoid a lot of
|
||||
// code repetition. The preprocessor is used to template large sections of
|
||||
// inline assembly that differ only in the registers used. If the code was
|
||||
// written out by hand, it would become very large and hard to audit.
|
||||
|
||||
// Generate a block of inline assembly that loads register R0 from memory. The
|
||||
// offset at which the register is loaded is set by the given round.
|
||||
#define LOAD(R0, ROUND) \
|
||||
"vlddqu ("#ROUND" * 12)(%[src]), %["R0"] \n\t"
|
||||
|
||||
// Generate a block of inline assembly that deinterleaves and shuffles register
|
||||
// R0 using preloaded constants. Outputs in R0 and R1.
|
||||
#define SHUF(R0, R1, R2) \
|
||||
"vpshufb %[lut0], %["R0"], %["R1"] \n\t" \
|
||||
"vpand %["R1"], %[msk0], %["R2"] \n\t" \
|
||||
"vpand %["R1"], %[msk2], %["R1"] \n\t" \
|
||||
"vpmulhuw %["R2"], %[msk1], %["R2"] \n\t" \
|
||||
"vpmullw %["R1"], %[msk3], %["R1"] \n\t" \
|
||||
"vpor %["R1"], %["R2"], %["R1"] \n\t"
|
||||
|
||||
// Generate a block of inline assembly that takes R0 and R1 and translates
|
||||
// their contents to the base64 alphabet, using preloaded constants.
|
||||
#define TRAN(R0, R1, R2) \
|
||||
"vpsubusb %[n51], %["R1"], %["R0"] \n\t" \
|
||||
"vpcmpgtb %[n25], %["R1"], %["R2"] \n\t" \
|
||||
"vpsubb %["R2"], %["R0"], %["R0"] \n\t" \
|
||||
"vpshufb %["R0"], %[lut1], %["R2"] \n\t" \
|
||||
"vpaddb %["R1"], %["R2"], %["R0"] \n\t"
|
||||
|
||||
// Generate a block of inline assembly that stores the given register R0 at an
|
||||
// offset set by the given round.
|
||||
#define STOR(R0, ROUND) \
|
||||
"vmovdqu %["R0"], ("#ROUND" * 16)(%[dst]) \n\t"
|
||||
|
||||
// Generate a block of inline assembly that generates a single self-contained
|
||||
// encoder round: fetch the data, process it, and store the result. Then update
|
||||
// the source and destination pointers.
|
||||
#define ROUND() \
|
||||
LOAD("a", 0) \
|
||||
SHUF("a", "b", "c") \
|
||||
TRAN("a", "b", "c") \
|
||||
STOR("a", 0) \
|
||||
"add $12, %[src] \n\t" \
|
||||
"add $16, %[dst] \n\t"
|
||||
|
||||
// Define a macro that initiates a three-way interleaved encoding round by
|
||||
// preloading registers a, b and c from memory.
|
||||
// The register graph shows which registers are in use during each step, and
|
||||
// is a visual aid for choosing registers for that step. Symbol index:
|
||||
//
|
||||
// + indicates that a register is loaded by that step.
|
||||
// | indicates that a register is in use and must not be touched.
|
||||
// - indicates that a register is decommissioned by that step.
|
||||
// x indicates that a register is used as a temporary by that step.
|
||||
// V indicates that a register is an input or output to the macro.
|
||||
//
|
||||
#define ROUND_3_INIT() /* a b c d e f */ \
|
||||
LOAD("a", 0) /* + */ \
|
||||
SHUF("a", "d", "e") /* | + x */ \
|
||||
LOAD("b", 1) /* | + | */ \
|
||||
TRAN("a", "d", "e") /* | | - x */ \
|
||||
LOAD("c", 2) /* V V V */
|
||||
|
||||
// Define a macro that translates, shuffles and stores the input registers A, B
|
||||
// and C, and preloads registers D, E and F for the next round.
|
||||
// This macro can be arbitrarily daisy-chained by feeding output registers D, E
|
||||
// and F back into the next round as input registers A, B and C. The macro
|
||||
// carefully interleaves memory operations with data operations for optimal
|
||||
// pipelined performance.
|
||||
|
||||
#define ROUND_3(ROUND, A,B,C,D,E,F) /* A B C D E F */ \
|
||||
LOAD(D, (ROUND + 3)) /* V V V + */ \
|
||||
SHUF(B, E, F) /* | | | | + x */ \
|
||||
STOR(A, (ROUND + 0)) /* - | | | | */ \
|
||||
TRAN(B, E, F) /* | | | - x */ \
|
||||
LOAD(E, (ROUND + 4)) /* | | | + */ \
|
||||
SHUF(C, A, F) /* + | | | | x */ \
|
||||
STOR(B, (ROUND + 1)) /* | - | | | */ \
|
||||
TRAN(C, A, F) /* - | | | x */ \
|
||||
LOAD(F, (ROUND + 5)) /* | | | + */ \
|
||||
SHUF(D, A, B) /* + x | | | | */ \
|
||||
STOR(C, (ROUND + 2)) /* | - | | | */ \
|
||||
TRAN(D, A, B) /* - x V V V */
|
||||
|
||||
// Define a macro that terminates a ROUND_3 macro by taking pre-loaded
|
||||
// registers D, E and F, and translating, shuffling and storing them.
|
||||
#define ROUND_3_END(ROUND, A,B,C,D,E,F) /* A B C D E F */ \
|
||||
SHUF(E, A, B) /* + x V V V */ \
|
||||
STOR(D, (ROUND + 3)) /* | - | | */ \
|
||||
TRAN(E, A, B) /* - x | | */ \
|
||||
SHUF(F, C, D) /* + x | | */ \
|
||||
STOR(E, (ROUND + 4)) /* | - | */ \
|
||||
TRAN(F, C, D) /* - x | */ \
|
||||
STOR(F, (ROUND + 5)) /* - */
|
||||
|
||||
// Define a type A round. Inputs are a, b, and c, outputs are d, e, and f.
|
||||
#define ROUND_3_A(ROUND) \
|
||||
ROUND_3(ROUND, "a", "b", "c", "d", "e", "f")
|
||||
|
||||
// Define a type B round. Inputs and outputs are swapped with regard to type A.
|
||||
#define ROUND_3_B(ROUND) \
|
||||
ROUND_3(ROUND, "d", "e", "f", "a", "b", "c")
|
||||
|
||||
// Terminating macro for a type A round.
|
||||
#define ROUND_3_A_LAST(ROUND) \
|
||||
ROUND_3_A(ROUND) \
|
||||
ROUND_3_END(ROUND, "a", "b", "c", "d", "e", "f")
|
||||
|
||||
// Terminating macro for a type B round.
|
||||
#define ROUND_3_B_LAST(ROUND) \
|
||||
ROUND_3_B(ROUND) \
|
||||
ROUND_3_END(ROUND, "d", "e", "f", "a", "b", "c")
|
||||
|
||||
// Suppress clang's warning that the literal string in the asm statement is
|
||||
// overlong (longer than the ISO-mandated minimum size of 4095 bytes for C99
|
||||
// compilers). It may be true, but the goal here is not C99 portability.
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Woverlength-strings"
|
||||
|
||||
static inline void
|
||||
enc_loop_avx (const uint8_t **s, size_t *slen, uint8_t **o, size_t *olen)
|
||||
{
|
||||
// For a clearer explanation of the algorithm used by this function,
|
||||
// please refer to the plain (not inline assembly) implementation. This
|
||||
// function follows the same basic logic.
|
||||
|
||||
if (*slen < 16) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Process blocks of 12 bytes at a time. Input is read in blocks of 16
|
||||
// bytes, so "reserve" four bytes from the input buffer to ensure that
|
||||
// we never read beyond the end of the input buffer.
|
||||
size_t rounds = (*slen - 4) / 12;
|
||||
|
||||
*slen -= rounds * 12; // 12 bytes consumed per round
|
||||
*olen += rounds * 16; // 16 bytes produced per round
|
||||
|
||||
// Number of times to go through the 36x loop.
|
||||
size_t loops = rounds / 36;
|
||||
|
||||
// Number of rounds remaining after the 36x loop.
|
||||
rounds %= 36;
|
||||
|
||||
// Lookup tables.
|
||||
const __m128i lut0 = _mm_set_epi8(
|
||||
10, 11, 9, 10, 7, 8, 6, 7, 4, 5, 3, 4, 1, 2, 0, 1);
|
||||
|
||||
const __m128i lut1 = _mm_setr_epi8(
|
||||
65, 71, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -19, -16, 0, 0);
|
||||
|
||||
// Temporary registers.
|
||||
__m128i a, b, c, d, e, f;
|
||||
|
||||
__asm__ volatile (
|
||||
|
||||
// If there are 36 rounds or more, enter a 36x unrolled loop of
|
||||
// interleaved encoding rounds. The rounds interleave memory
|
||||
// operations (load/store) with data operations (table lookups,
|
||||
// etc) to maximize pipeline throughput.
|
||||
" test %[loops], %[loops] \n\t"
|
||||
" jz 18f \n\t"
|
||||
" jmp 36f \n\t"
|
||||
" \n\t"
|
||||
".balign 64 \n\t"
|
||||
"36: " ROUND_3_INIT()
|
||||
" " ROUND_3_A( 0)
|
||||
" " ROUND_3_B( 3)
|
||||
" " ROUND_3_A( 6)
|
||||
" " ROUND_3_B( 9)
|
||||
" " ROUND_3_A(12)
|
||||
" " ROUND_3_B(15)
|
||||
" " ROUND_3_A(18)
|
||||
" " ROUND_3_B(21)
|
||||
" " ROUND_3_A(24)
|
||||
" " ROUND_3_B(27)
|
||||
" " ROUND_3_A_LAST(30)
|
||||
" add $(12 * 36), %[src] \n\t"
|
||||
" add $(16 * 36), %[dst] \n\t"
|
||||
" dec %[loops] \n\t"
|
||||
" jnz 36b \n\t"
|
||||
|
||||
// Enter an 18x unrolled loop for rounds of 18 or more.
|
||||
"18: cmp $18, %[rounds] \n\t"
|
||||
" jl 9f \n\t"
|
||||
" " ROUND_3_INIT()
|
||||
" " ROUND_3_A(0)
|
||||
" " ROUND_3_B(3)
|
||||
" " ROUND_3_A(6)
|
||||
" " ROUND_3_B(9)
|
||||
" " ROUND_3_A_LAST(12)
|
||||
" sub $18, %[rounds] \n\t"
|
||||
" add $(12 * 18), %[src] \n\t"
|
||||
" add $(16 * 18), %[dst] \n\t"
|
||||
|
||||
// Enter a 9x unrolled loop for rounds of 9 or more.
|
||||
"9: cmp $9, %[rounds] \n\t"
|
||||
" jl 6f \n\t"
|
||||
" " ROUND_3_INIT()
|
||||
" " ROUND_3_A(0)
|
||||
" " ROUND_3_B_LAST(3)
|
||||
" sub $9, %[rounds] \n\t"
|
||||
" add $(12 * 9), %[src] \n\t"
|
||||
" add $(16 * 9), %[dst] \n\t"
|
||||
|
||||
// Enter a 6x unrolled loop for rounds of 6 or more.
|
||||
"6: cmp $6, %[rounds] \n\t"
|
||||
" jl 55f \n\t"
|
||||
" " ROUND_3_INIT()
|
||||
" " ROUND_3_A_LAST(0)
|
||||
" sub $6, %[rounds] \n\t"
|
||||
" add $(12 * 6), %[src] \n\t"
|
||||
" add $(16 * 6), %[dst] \n\t"
|
||||
|
||||
// Dispatch the remaining rounds 0..5.
|
||||
"55: cmp $3, %[rounds] \n\t"
|
||||
" jg 45f \n\t"
|
||||
" je 3f \n\t"
|
||||
" cmp $1, %[rounds] \n\t"
|
||||
" jg 2f \n\t"
|
||||
" je 1f \n\t"
|
||||
" jmp 0f \n\t"
|
||||
|
||||
"45: cmp $4, %[rounds] \n\t"
|
||||
" je 4f \n\t"
|
||||
|
||||
// Block of non-interlaced encoding rounds, which can each
|
||||
// individually be jumped to. Rounds fall through to the next.
|
||||
"5: " ROUND()
|
||||
"4: " ROUND()
|
||||
"3: " ROUND()
|
||||
"2: " ROUND()
|
||||
"1: " ROUND()
|
||||
"0: \n\t"
|
||||
|
||||
// Outputs (modified).
|
||||
: [rounds] "+r" (rounds),
|
||||
[loops] "+r" (loops),
|
||||
[src] "+r" (*s),
|
||||
[dst] "+r" (*o),
|
||||
[a] "=&x" (a),
|
||||
[b] "=&x" (b),
|
||||
[c] "=&x" (c),
|
||||
[d] "=&x" (d),
|
||||
[e] "=&x" (e),
|
||||
[f] "=&x" (f)
|
||||
|
||||
// Inputs (not modified).
|
||||
: [lut0] "x" (lut0),
|
||||
[lut1] "x" (lut1),
|
||||
[msk0] "x" (_mm_set1_epi32(0x0FC0FC00)),
|
||||
[msk1] "x" (_mm_set1_epi32(0x04000040)),
|
||||
[msk2] "x" (_mm_set1_epi32(0x003F03F0)),
|
||||
[msk3] "x" (_mm_set1_epi32(0x01000010)),
|
||||
[n51] "x" (_mm_set1_epi8(51)),
|
||||
[n25] "x" (_mm_set1_epi8(25))
|
||||
|
||||
// Clobbers.
|
||||
: "cc", "memory"
|
||||
);
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
56
3rdparty/base64/lib/arch/avx2/codec.c
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../../../include/libbase64.h"
|
||||
#include "../../tables/tables.h"
|
||||
#include "../../codecs.h"
|
||||
#include "config.h"
|
||||
#include "../../env.h"
|
||||
|
||||
#if HAVE_AVX2
|
||||
#include <immintrin.h>
|
||||
|
||||
// Only enable inline assembly on supported compilers and on 64-bit CPUs.
|
||||
#ifndef BASE64_AVX2_USE_ASM
|
||||
# if (defined(__GNUC__) || defined(__clang__)) && BASE64_WORDSIZE == 64
|
||||
# define BASE64_AVX2_USE_ASM 1
|
||||
# else
|
||||
# define BASE64_AVX2_USE_ASM 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "dec_reshuffle.c"
|
||||
#include "dec_loop.c"
|
||||
|
||||
#if BASE64_AVX2_USE_ASM
|
||||
# include "enc_loop_asm.c"
|
||||
#else
|
||||
# include "enc_translate.c"
|
||||
# include "enc_reshuffle.c"
|
||||
# include "enc_loop.c"
|
||||
#endif
|
||||
|
||||
#endif // HAVE_AVX2
|
||||
|
||||
BASE64_ENC_FUNCTION(avx2)
|
||||
{
|
||||
#if HAVE_AVX2
|
||||
#include "../generic/enc_head.c"
|
||||
enc_loop_avx2(&s, &slen, &o, &olen);
|
||||
#include "../generic/enc_tail.c"
|
||||
#else
|
||||
BASE64_ENC_STUB
|
||||
#endif
|
||||
}
|
||||
|
||||
BASE64_DEC_FUNCTION(avx2)
|
||||
{
|
||||
#if HAVE_AVX2
|
||||
#include "../generic/dec_head.c"
|
||||
dec_loop_avx2(&s, &slen, &o, &olen);
|
||||
#include "../generic/dec_tail.c"
|
||||
#else
|
||||
BASE64_DEC_STUB
|
||||
#endif
|
||||
}
|
||||
110
3rdparty/base64/lib/arch/avx2/dec_loop.c
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
static inline int
|
||||
dec_loop_avx2_inner (const uint8_t **s, uint8_t **o, size_t *rounds)
|
||||
{
|
||||
const __m256i lut_lo = _mm256_setr_epi8(
|
||||
0x15, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
|
||||
0x11, 0x11, 0x13, 0x1A, 0x1B, 0x1B, 0x1B, 0x1A,
|
||||
0x15, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
|
||||
0x11, 0x11, 0x13, 0x1A, 0x1B, 0x1B, 0x1B, 0x1A);
|
||||
|
||||
const __m256i lut_hi = _mm256_setr_epi8(
|
||||
0x10, 0x10, 0x01, 0x02, 0x04, 0x08, 0x04, 0x08,
|
||||
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
|
||||
0x10, 0x10, 0x01, 0x02, 0x04, 0x08, 0x04, 0x08,
|
||||
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10);
|
||||
|
||||
const __m256i lut_roll = _mm256_setr_epi8(
|
||||
0, 16, 19, 4, -65, -65, -71, -71,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 16, 19, 4, -65, -65, -71, -71,
|
||||
0, 0, 0, 0, 0, 0, 0, 0);
|
||||
|
||||
const __m256i mask_2F = _mm256_set1_epi8(0x2F);
|
||||
|
||||
// Load input:
|
||||
__m256i str = _mm256_loadu_si256((__m256i *) *s);
|
||||
|
||||
// See the SSSE3 decoder for an explanation of the algorithm.
|
||||
const __m256i hi_nibbles = _mm256_and_si256(_mm256_srli_epi32(str, 4), mask_2F);
|
||||
const __m256i lo_nibbles = _mm256_and_si256(str, mask_2F);
|
||||
const __m256i hi = _mm256_shuffle_epi8(lut_hi, hi_nibbles);
|
||||
const __m256i lo = _mm256_shuffle_epi8(lut_lo, lo_nibbles);
|
||||
|
||||
if (!_mm256_testz_si256(lo, hi)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const __m256i eq_2F = _mm256_cmpeq_epi8(str, mask_2F);
|
||||
const __m256i roll = _mm256_shuffle_epi8(lut_roll, _mm256_add_epi8(eq_2F, hi_nibbles));
|
||||
|
||||
// Now simply add the delta values to the input:
|
||||
str = _mm256_add_epi8(str, roll);
|
||||
|
||||
// Reshuffle the input to packed 12-byte output format:
|
||||
str = dec_reshuffle(str);
|
||||
|
||||
// Store the output:
|
||||
_mm256_storeu_si256((__m256i *) *o, str);
|
||||
|
||||
*s += 32;
|
||||
*o += 24;
|
||||
*rounds -= 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline void
|
||||
dec_loop_avx2 (const uint8_t **s, size_t *slen, uint8_t **o, size_t *olen)
|
||||
{
|
||||
if (*slen < 45) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Process blocks of 32 bytes per round. Because 8 extra zero bytes are
|
||||
// written after the output, ensure that there will be at least 13
|
||||
// bytes of input data left to cover the gap. (11 data bytes and up to
|
||||
// two end-of-string markers.)
|
||||
size_t rounds = (*slen - 13) / 32;
|
||||
|
||||
*slen -= rounds * 32; // 32 bytes consumed per round
|
||||
*olen += rounds * 24; // 24 bytes produced per round
|
||||
|
||||
do {
|
||||
if (rounds >= 8) {
|
||||
if (dec_loop_avx2_inner(s, o, &rounds) &&
|
||||
dec_loop_avx2_inner(s, o, &rounds) &&
|
||||
dec_loop_avx2_inner(s, o, &rounds) &&
|
||||
dec_loop_avx2_inner(s, o, &rounds) &&
|
||||
dec_loop_avx2_inner(s, o, &rounds) &&
|
||||
dec_loop_avx2_inner(s, o, &rounds) &&
|
||||
dec_loop_avx2_inner(s, o, &rounds) &&
|
||||
dec_loop_avx2_inner(s, o, &rounds)) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (rounds >= 4) {
|
||||
if (dec_loop_avx2_inner(s, o, &rounds) &&
|
||||
dec_loop_avx2_inner(s, o, &rounds) &&
|
||||
dec_loop_avx2_inner(s, o, &rounds) &&
|
||||
dec_loop_avx2_inner(s, o, &rounds)) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (rounds >= 2) {
|
||||
if (dec_loop_avx2_inner(s, o, &rounds) &&
|
||||
dec_loop_avx2_inner(s, o, &rounds)) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
dec_loop_avx2_inner(s, o, &rounds);
|
||||
break;
|
||||
|
||||
} while (rounds > 0);
|
||||
|
||||
// Adjust for any rounds that were skipped:
|
||||
*slen += rounds * 32;
|
||||
*olen -= rounds * 24;
|
||||
}
|
||||
34
3rdparty/base64/lib/arch/avx2/dec_reshuffle.c
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
static inline __m256i
|
||||
dec_reshuffle (const __m256i in)
|
||||
{
|
||||
// in, lower lane, bits, upper case are most significant bits, lower
|
||||
// case are least significant bits:
|
||||
// 00llllll 00kkkkLL 00jjKKKK 00JJJJJJ
|
||||
// 00iiiiii 00hhhhII 00ggHHHH 00GGGGGG
|
||||
// 00ffffff 00eeeeFF 00ddEEEE 00DDDDDD
|
||||
// 00cccccc 00bbbbCC 00aaBBBB 00AAAAAA
|
||||
|
||||
const __m256i merge_ab_and_bc = _mm256_maddubs_epi16(in, _mm256_set1_epi32(0x01400140));
|
||||
// 0000kkkk LLllllll 0000JJJJ JJjjKKKK
|
||||
// 0000hhhh IIiiiiii 0000GGGG GGggHHHH
|
||||
// 0000eeee FFffffff 0000DDDD DDddEEEE
|
||||
// 0000bbbb CCcccccc 0000AAAA AAaaBBBB
|
||||
|
||||
__m256i out = _mm256_madd_epi16(merge_ab_and_bc, _mm256_set1_epi32(0x00011000));
|
||||
// 00000000 JJJJJJjj KKKKkkkk LLllllll
|
||||
// 00000000 GGGGGGgg HHHHhhhh IIiiiiii
|
||||
// 00000000 DDDDDDdd EEEEeeee FFffffff
|
||||
// 00000000 AAAAAAaa BBBBbbbb CCcccccc
|
||||
|
||||
// Pack bytes together in each lane:
|
||||
out = _mm256_shuffle_epi8(out, _mm256_setr_epi8(
|
||||
2, 1, 0, 6, 5, 4, 10, 9, 8, 14, 13, 12, -1, -1, -1, -1,
|
||||
2, 1, 0, 6, 5, 4, 10, 9, 8, 14, 13, 12, -1, -1, -1, -1));
|
||||
// 00000000 00000000 00000000 00000000
|
||||
// LLllllll KKKKkkkk JJJJJJjj IIiiiiii
|
||||
// HHHHhhhh GGGGGGgg FFffffff EEEEeeee
|
||||
// DDDDDDdd CCcccccc BBBBbbbb AAAAAAaa
|
||||
|
||||
// Pack lanes:
|
||||
return _mm256_permutevar8x32_epi32(out, _mm256_setr_epi32(0, 1, 2, 4, 5, 6, -1, -1));
|
||||
}
|
||||
89
3rdparty/base64/lib/arch/avx2/enc_loop.c
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
static inline void
|
||||
enc_loop_avx2_inner_first (const uint8_t **s, uint8_t **o)
|
||||
{
|
||||
// First load is done at s - 0 to not get a segfault:
|
||||
__m256i src = _mm256_loadu_si256((__m256i *) *s);
|
||||
|
||||
// Shift by 4 bytes, as required by enc_reshuffle:
|
||||
src = _mm256_permutevar8x32_epi32(src, _mm256_setr_epi32(0, 0, 1, 2, 3, 4, 5, 6));
|
||||
|
||||
// Reshuffle, translate, store:
|
||||
src = enc_reshuffle(src);
|
||||
src = enc_translate(src);
|
||||
_mm256_storeu_si256((__m256i *) *o, src);
|
||||
|
||||
// Subsequent loads will be done at s - 4, set pointer for next round:
|
||||
*s += 20;
|
||||
*o += 32;
|
||||
}
|
||||
|
||||
static inline void
|
||||
enc_loop_avx2_inner (const uint8_t **s, uint8_t **o)
|
||||
{
|
||||
// Load input:
|
||||
__m256i src = _mm256_loadu_si256((__m256i *) *s);
|
||||
|
||||
// Reshuffle, translate, store:
|
||||
src = enc_reshuffle(src);
|
||||
src = enc_translate(src);
|
||||
_mm256_storeu_si256((__m256i *) *o, src);
|
||||
|
||||
*s += 24;
|
||||
*o += 32;
|
||||
}
|
||||
|
||||
static inline void
|
||||
enc_loop_avx2 (const uint8_t **s, size_t *slen, uint8_t **o, size_t *olen)
|
||||
{
|
||||
if (*slen < 32) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Process blocks of 24 bytes at a time. Because blocks are loaded 32
|
||||
// bytes at a time an offset of -4, ensure that there will be at least
|
||||
// 4 remaining bytes after the last round, so that the final read will
|
||||
// not pass beyond the bounds of the input buffer:
|
||||
size_t rounds = (*slen - 4) / 24;
|
||||
|
||||
*slen -= rounds * 24; // 24 bytes consumed per round
|
||||
*olen += rounds * 32; // 32 bytes produced per round
|
||||
|
||||
// The first loop iteration requires special handling to ensure that
|
||||
// the read, which is done at an offset, does not underflow the buffer:
|
||||
enc_loop_avx2_inner_first(s, o);
|
||||
rounds--;
|
||||
|
||||
while (rounds > 0) {
|
||||
if (rounds >= 8) {
|
||||
enc_loop_avx2_inner(s, o);
|
||||
enc_loop_avx2_inner(s, o);
|
||||
enc_loop_avx2_inner(s, o);
|
||||
enc_loop_avx2_inner(s, o);
|
||||
enc_loop_avx2_inner(s, o);
|
||||
enc_loop_avx2_inner(s, o);
|
||||
enc_loop_avx2_inner(s, o);
|
||||
enc_loop_avx2_inner(s, o);
|
||||
rounds -= 8;
|
||||
continue;
|
||||
}
|
||||
if (rounds >= 4) {
|
||||
enc_loop_avx2_inner(s, o);
|
||||
enc_loop_avx2_inner(s, o);
|
||||
enc_loop_avx2_inner(s, o);
|
||||
enc_loop_avx2_inner(s, o);
|
||||
rounds -= 4;
|
||||
continue;
|
||||
}
|
||||
if (rounds >= 2) {
|
||||
enc_loop_avx2_inner(s, o);
|
||||
enc_loop_avx2_inner(s, o);
|
||||
rounds -= 2;
|
||||
continue;
|
||||
}
|
||||
enc_loop_avx2_inner(s, o);
|
||||
break;
|
||||
}
|
||||
|
||||
// Add the offset back:
|
||||
*s += 4;
|
||||
}
|
||||
291
3rdparty/base64/lib/arch/avx2/enc_loop_asm.c
vendored
Normal file
@@ -0,0 +1,291 @@
|
||||
// Apologies in advance for combining the preprocessor with inline assembly,
|
||||
// two notoriously gnarly parts of C, but it was necessary to avoid a lot of
|
||||
// code repetition. The preprocessor is used to template large sections of
|
||||
// inline assembly that differ only in the registers used. If the code was
|
||||
// written out by hand, it would become very large and hard to audit.
|
||||
|
||||
// Generate a block of inline assembly that loads register R0 from memory. The
|
||||
// offset at which the register is loaded is set by the given round and a
|
||||
// constant offset.
|
||||
#define LOAD(R0, ROUND, OFFSET) \
|
||||
"vlddqu ("#ROUND" * 24 + "#OFFSET")(%[src]), %["R0"] \n\t"
|
||||
|
||||
// Generate a block of inline assembly that deinterleaves and shuffles register
|
||||
// R0 using preloaded constants. Outputs in R0 and R1.
|
||||
#define SHUF(R0, R1, R2) \
|
||||
"vpshufb %[lut0], %["R0"], %["R1"] \n\t" \
|
||||
"vpand %["R1"], %[msk0], %["R2"] \n\t" \
|
||||
"vpand %["R1"], %[msk2], %["R1"] \n\t" \
|
||||
"vpmulhuw %["R2"], %[msk1], %["R2"] \n\t" \
|
||||
"vpmullw %["R1"], %[msk3], %["R1"] \n\t" \
|
||||
"vpor %["R1"], %["R2"], %["R1"] \n\t"
|
||||
|
||||
// Generate a block of inline assembly that takes R0 and R1 and translates
|
||||
// their contents to the base64 alphabet, using preloaded constants.
|
||||
#define TRAN(R0, R1, R2) \
|
||||
"vpsubusb %[n51], %["R1"], %["R0"] \n\t" \
|
||||
"vpcmpgtb %[n25], %["R1"], %["R2"] \n\t" \
|
||||
"vpsubb %["R2"], %["R0"], %["R0"] \n\t" \
|
||||
"vpshufb %["R0"], %[lut1], %["R2"] \n\t" \
|
||||
"vpaddb %["R1"], %["R2"], %["R0"] \n\t"
|
||||
|
||||
// Generate a block of inline assembly that stores the given register R0 at an
|
||||
// offset set by the given round.
|
||||
#define STOR(R0, ROUND) \
|
||||
"vmovdqu %["R0"], ("#ROUND" * 32)(%[dst]) \n\t"
|
||||
|
||||
// Generate a block of inline assembly that generates a single self-contained
|
||||
// encoder round: fetch the data, process it, and store the result. Then update
|
||||
// the source and destination pointers.
|
||||
#define ROUND() \
|
||||
LOAD("a", 0, -4) \
|
||||
SHUF("a", "b", "c") \
|
||||
TRAN("a", "b", "c") \
|
||||
STOR("a", 0) \
|
||||
"add $24, %[src] \n\t" \
|
||||
"add $32, %[dst] \n\t"
|
||||
|
||||
// Define a macro that initiates a three-way interleaved encoding round by
|
||||
// preloading registers a, b and c from memory.
|
||||
// The register graph shows which registers are in use during each step, and
|
||||
// is a visual aid for choosing registers for that step. Symbol index:
|
||||
//
|
||||
// + indicates that a register is loaded by that step.
|
||||
// | indicates that a register is in use and must not be touched.
|
||||
// - indicates that a register is decommissioned by that step.
|
||||
// x indicates that a register is used as a temporary by that step.
|
||||
// V indicates that a register is an input or output to the macro.
|
||||
//
|
||||
#define ROUND_3_INIT() /* a b c d e f */ \
|
||||
LOAD("a", 0, -4) /* + */ \
|
||||
SHUF("a", "d", "e") /* | + x */ \
|
||||
LOAD("b", 1, -4) /* | + | */ \
|
||||
TRAN("a", "d", "e") /* | | - x */ \
|
||||
LOAD("c", 2, -4) /* V V V */
|
||||
|
||||
// Define a macro that translates, shuffles and stores the input registers A, B
|
||||
// and C, and preloads registers D, E and F for the next round.
|
||||
// This macro can be arbitrarily daisy-chained by feeding output registers D, E
|
||||
// and F back into the next round as input registers A, B and C. The macro
|
||||
// carefully interleaves memory operations with data operations for optimal
|
||||
// pipelined performance.
|
||||
|
||||
#define ROUND_3(ROUND, A,B,C,D,E,F) /* A B C D E F */ \
|
||||
LOAD(D, (ROUND + 3), -4) /* V V V + */ \
|
||||
SHUF(B, E, F) /* | | | | + x */ \
|
||||
STOR(A, (ROUND + 0)) /* - | | | | */ \
|
||||
TRAN(B, E, F) /* | | | - x */ \
|
||||
LOAD(E, (ROUND + 4), -4) /* | | | + */ \
|
||||
SHUF(C, A, F) /* + | | | | x */ \
|
||||
STOR(B, (ROUND + 1)) /* | - | | | */ \
|
||||
TRAN(C, A, F) /* - | | | x */ \
|
||||
LOAD(F, (ROUND + 5), -4) /* | | | + */ \
|
||||
SHUF(D, A, B) /* + x | | | | */ \
|
||||
STOR(C, (ROUND + 2)) /* | - | | | */ \
|
||||
TRAN(D, A, B) /* - x V V V */
|
||||
|
||||
// Define a macro that terminates a ROUND_3 macro by taking pre-loaded
|
||||
// registers D, E and F, and translating, shuffling and storing them.
|
||||
#define ROUND_3_END(ROUND, A,B,C,D,E,F) /* A B C D E F */ \
|
||||
SHUF(E, A, B) /* + x V V V */ \
|
||||
STOR(D, (ROUND + 3)) /* | - | | */ \
|
||||
TRAN(E, A, B) /* - x | | */ \
|
||||
SHUF(F, C, D) /* + x | | */ \
|
||||
STOR(E, (ROUND + 4)) /* | - | */ \
|
||||
TRAN(F, C, D) /* - x | */ \
|
||||
STOR(F, (ROUND + 5)) /* - */
|
||||
|
||||
// Define a type A round. Inputs are a, b, and c, outputs are d, e, and f.
|
||||
#define ROUND_3_A(ROUND) \
|
||||
ROUND_3(ROUND, "a", "b", "c", "d", "e", "f")
|
||||
|
||||
// Define a type B round. Inputs and outputs are swapped with regard to type A.
|
||||
#define ROUND_3_B(ROUND) \
|
||||
ROUND_3(ROUND, "d", "e", "f", "a", "b", "c")
|
||||
|
||||
// Terminating macro for a type A round.
|
||||
#define ROUND_3_A_LAST(ROUND) \
|
||||
ROUND_3_A(ROUND) \
|
||||
ROUND_3_END(ROUND, "a", "b", "c", "d", "e", "f")
|
||||
|
||||
// Terminating macro for a type B round.
|
||||
#define ROUND_3_B_LAST(ROUND) \
|
||||
ROUND_3_B(ROUND) \
|
||||
ROUND_3_END(ROUND, "d", "e", "f", "a", "b", "c")
|
||||
|
||||
// Suppress clang's warning that the literal string in the asm statement is
|
||||
// overlong (longer than the ISO-mandated minimum size of 4095 bytes for C99
|
||||
// compilers). It may be true, but the goal here is not C99 portability.
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Woverlength-strings"
|
||||
|
||||
static inline void
|
||||
enc_loop_avx2 (const uint8_t **s, size_t *slen, uint8_t **o, size_t *olen)
|
||||
{
|
||||
// For a clearer explanation of the algorithm used by this function,
|
||||
// please refer to the plain (not inline assembly) implementation. This
|
||||
// function follows the same basic logic.
|
||||
|
||||
if (*slen < 32) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Process blocks of 24 bytes at a time. Because blocks are loaded 32
|
||||
// bytes at a time an offset of -4, ensure that there will be at least
|
||||
// 4 remaining bytes after the last round, so that the final read will
|
||||
// not pass beyond the bounds of the input buffer.
|
||||
size_t rounds = (*slen - 4) / 24;
|
||||
|
||||
*slen -= rounds * 24; // 24 bytes consumed per round
|
||||
*olen += rounds * 32; // 32 bytes produced per round
|
||||
|
||||
// Pre-decrement the number of rounds to get the number of rounds
|
||||
// *after* the first round, which is handled as a special case.
|
||||
rounds--;
|
||||
|
||||
// Number of times to go through the 36x loop.
|
||||
size_t loops = rounds / 36;
|
||||
|
||||
// Number of rounds remaining after the 36x loop.
|
||||
rounds %= 36;
|
||||
|
||||
// Lookup tables.
|
||||
const __m256i lut0 = _mm256_set_epi8(
|
||||
10, 11, 9, 10, 7, 8, 6, 7, 4, 5, 3, 4, 1, 2, 0, 1,
|
||||
14, 15, 13, 14, 11, 12, 10, 11, 8, 9, 7, 8, 5, 6, 4, 5);
|
||||
|
||||
const __m256i lut1 = _mm256_setr_epi8(
|
||||
65, 71, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -19, -16, 0, 0,
|
||||
65, 71, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -19, -16, 0, 0);
|
||||
|
||||
// Temporary registers.
|
||||
__m256i a, b, c, d, e;
|
||||
|
||||
// Temporary register f doubles as the shift mask for the first round.
|
||||
__m256i f = _mm256_setr_epi32(0, 0, 1, 2, 3, 4, 5, 6);
|
||||
|
||||
__asm__ volatile (
|
||||
|
||||
// The first loop iteration requires special handling to ensure
|
||||
// that the read, which is normally done at an offset of -4,
|
||||
// does not underflow the buffer. Load the buffer at an offset
|
||||
// of 0 and permute the input to achieve the same effect.
|
||||
LOAD("a", 0, 0)
|
||||
"vpermd %[a], %[f], %[a] \n\t"
|
||||
|
||||
// Perform the standard shuffling and translation steps.
|
||||
SHUF("a", "b", "c")
|
||||
TRAN("a", "b", "c")
|
||||
|
||||
// Store the result and increment the source and dest pointers.
|
||||
"vmovdqu %[a], (%[dst]) \n\t"
|
||||
"add $24, %[src] \n\t"
|
||||
"add $32, %[dst] \n\t"
|
||||
|
||||
// If there are 36 rounds or more, enter a 36x unrolled loop of
|
||||
// interleaved encoding rounds. The rounds interleave memory
|
||||
// operations (load/store) with data operations (table lookups,
|
||||
// etc) to maximize pipeline throughput.
|
||||
" test %[loops], %[loops] \n\t"
|
||||
" jz 18f \n\t"
|
||||
" jmp 36f \n\t"
|
||||
" \n\t"
|
||||
".balign 64 \n\t"
|
||||
"36: " ROUND_3_INIT()
|
||||
" " ROUND_3_A( 0)
|
||||
" " ROUND_3_B( 3)
|
||||
" " ROUND_3_A( 6)
|
||||
" " ROUND_3_B( 9)
|
||||
" " ROUND_3_A(12)
|
||||
" " ROUND_3_B(15)
|
||||
" " ROUND_3_A(18)
|
||||
" " ROUND_3_B(21)
|
||||
" " ROUND_3_A(24)
|
||||
" " ROUND_3_B(27)
|
||||
" " ROUND_3_A_LAST(30)
|
||||
" add $(24 * 36), %[src] \n\t"
|
||||
" add $(32 * 36), %[dst] \n\t"
|
||||
" dec %[loops] \n\t"
|
||||
" jnz 36b \n\t"
|
||||
|
||||
// Enter an 18x unrolled loop for rounds of 18 or more.
|
||||
"18: cmp $18, %[rounds] \n\t"
|
||||
" jl 9f \n\t"
|
||||
" " ROUND_3_INIT()
|
||||
" " ROUND_3_A(0)
|
||||
" " ROUND_3_B(3)
|
||||
" " ROUND_3_A(6)
|
||||
" " ROUND_3_B(9)
|
||||
" " ROUND_3_A_LAST(12)
|
||||
" sub $18, %[rounds] \n\t"
|
||||
" add $(24 * 18), %[src] \n\t"
|
||||
" add $(32 * 18), %[dst] \n\t"
|
||||
|
||||
// Enter a 9x unrolled loop for rounds of 9 or more.
|
||||
"9: cmp $9, %[rounds] \n\t"
|
||||
" jl 6f \n\t"
|
||||
" " ROUND_3_INIT()
|
||||
" " ROUND_3_A(0)
|
||||
" " ROUND_3_B_LAST(3)
|
||||
" sub $9, %[rounds] \n\t"
|
||||
" add $(24 * 9), %[src] \n\t"
|
||||
" add $(32 * 9), %[dst] \n\t"
|
||||
|
||||
// Enter a 6x unrolled loop for rounds of 6 or more.
|
||||
"6: cmp $6, %[rounds] \n\t"
|
||||
" jl 55f \n\t"
|
||||
" " ROUND_3_INIT()
|
||||
" " ROUND_3_A_LAST(0)
|
||||
" sub $6, %[rounds] \n\t"
|
||||
" add $(24 * 6), %[src] \n\t"
|
||||
" add $(32 * 6), %[dst] \n\t"
|
||||
|
||||
// Dispatch the remaining rounds 0..5.
|
||||
"55: cmp $3, %[rounds] \n\t"
|
||||
" jg 45f \n\t"
|
||||
" je 3f \n\t"
|
||||
" cmp $1, %[rounds] \n\t"
|
||||
" jg 2f \n\t"
|
||||
" je 1f \n\t"
|
||||
" jmp 0f \n\t"
|
||||
|
||||
"45: cmp $4, %[rounds] \n\t"
|
||||
" je 4f \n\t"
|
||||
|
||||
// Block of non-interlaced encoding rounds, which can each
|
||||
// individually be jumped to. Rounds fall through to the next.
|
||||
"5: " ROUND()
|
||||
"4: " ROUND()
|
||||
"3: " ROUND()
|
||||
"2: " ROUND()
|
||||
"1: " ROUND()
|
||||
"0: \n\t"
|
||||
|
||||
// Outputs (modified).
|
||||
: [rounds] "+r" (rounds),
|
||||
[loops] "+r" (loops),
|
||||
[src] "+r" (*s),
|
||||
[dst] "+r" (*o),
|
||||
[a] "=&x" (a),
|
||||
[b] "=&x" (b),
|
||||
[c] "=&x" (c),
|
||||
[d] "=&x" (d),
|
||||
[e] "=&x" (e),
|
||||
[f] "+x" (f)
|
||||
|
||||
// Inputs (not modified).
|
||||
: [lut0] "x" (lut0),
|
||||
[lut1] "x" (lut1),
|
||||
[msk0] "x" (_mm256_set1_epi32(0x0FC0FC00)),
|
||||
[msk1] "x" (_mm256_set1_epi32(0x04000040)),
|
||||
[msk2] "x" (_mm256_set1_epi32(0x003F03F0)),
|
||||
[msk3] "x" (_mm256_set1_epi32(0x01000010)),
|
||||
[n51] "x" (_mm256_set1_epi8(51)),
|
||||
[n25] "x" (_mm256_set1_epi8(25))
|
||||
|
||||
// Clobbers.
|
||||
: "cc", "memory"
|
||||
);
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
83
3rdparty/base64/lib/arch/avx2/enc_reshuffle.c
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
static inline __m256i
|
||||
enc_reshuffle (const __m256i input)
|
||||
{
|
||||
// Translation of the SSSE3 reshuffling algorithm to AVX2. This one
|
||||
// works with shifted (4 bytes) input in order to be able to work
|
||||
// efficiently in the two 128-bit lanes.
|
||||
|
||||
// Input, bytes MSB to LSB:
|
||||
// 0 0 0 0 x w v u t s r q p o n m
|
||||
// l k j i h g f e d c b a 0 0 0 0
|
||||
|
||||
const __m256i in = _mm256_shuffle_epi8(input, _mm256_set_epi8(
|
||||
10, 11, 9, 10,
|
||||
7, 8, 6, 7,
|
||||
4, 5, 3, 4,
|
||||
1, 2, 0, 1,
|
||||
|
||||
14, 15, 13, 14,
|
||||
11, 12, 10, 11,
|
||||
8, 9, 7, 8,
|
||||
5, 6, 4, 5));
|
||||
// in, bytes MSB to LSB:
|
||||
// w x v w
|
||||
// t u s t
|
||||
// q r p q
|
||||
// n o m n
|
||||
// k l j k
|
||||
// h i g h
|
||||
// e f d e
|
||||
// b c a b
|
||||
|
||||
const __m256i t0 = _mm256_and_si256(in, _mm256_set1_epi32(0x0FC0FC00));
|
||||
// bits, upper case are most significant bits, lower case are least
|
||||
// significant bits.
|
||||
// 0000wwww XX000000 VVVVVV00 00000000
|
||||
// 0000tttt UU000000 SSSSSS00 00000000
|
||||
// 0000qqqq RR000000 PPPPPP00 00000000
|
||||
// 0000nnnn OO000000 MMMMMM00 00000000
|
||||
// 0000kkkk LL000000 JJJJJJ00 00000000
|
||||
// 0000hhhh II000000 GGGGGG00 00000000
|
||||
// 0000eeee FF000000 DDDDDD00 00000000
|
||||
// 0000bbbb CC000000 AAAAAA00 00000000
|
||||
|
||||
const __m256i t1 = _mm256_mulhi_epu16(t0, _mm256_set1_epi32(0x04000040));
|
||||
// 00000000 00wwwwXX 00000000 00VVVVVV
|
||||
// 00000000 00ttttUU 00000000 00SSSSSS
|
||||
// 00000000 00qqqqRR 00000000 00PPPPPP
|
||||
// 00000000 00nnnnOO 00000000 00MMMMMM
|
||||
// 00000000 00kkkkLL 00000000 00JJJJJJ
|
||||
// 00000000 00hhhhII 00000000 00GGGGGG
|
||||
// 00000000 00eeeeFF 00000000 00DDDDDD
|
||||
// 00000000 00bbbbCC 00000000 00AAAAAA
|
||||
|
||||
const __m256i t2 = _mm256_and_si256(in, _mm256_set1_epi32(0x003F03F0));
|
||||
// 00000000 00xxxxxx 000000vv WWWW0000
|
||||
// 00000000 00uuuuuu 000000ss TTTT0000
|
||||
// 00000000 00rrrrrr 000000pp QQQQ0000
|
||||
// 00000000 00oooooo 000000mm NNNN0000
|
||||
// 00000000 00llllll 000000jj KKKK0000
|
||||
// 00000000 00iiiiii 000000gg HHHH0000
|
||||
// 00000000 00ffffff 000000dd EEEE0000
|
||||
// 00000000 00cccccc 000000aa BBBB0000
|
||||
|
||||
const __m256i t3 = _mm256_mullo_epi16(t2, _mm256_set1_epi32(0x01000010));
|
||||
// 00xxxxxx 00000000 00vvWWWW 00000000
|
||||
// 00uuuuuu 00000000 00ssTTTT 00000000
|
||||
// 00rrrrrr 00000000 00ppQQQQ 00000000
|
||||
// 00oooooo 00000000 00mmNNNN 00000000
|
||||
// 00llllll 00000000 00jjKKKK 00000000
|
||||
// 00iiiiii 00000000 00ggHHHH 00000000
|
||||
// 00ffffff 00000000 00ddEEEE 00000000
|
||||
// 00cccccc 00000000 00aaBBBB 00000000
|
||||
|
||||
return _mm256_or_si256(t1, t3);
|
||||
// 00xxxxxx 00wwwwXX 00vvWWWW 00VVVVVV
|
||||
// 00uuuuuu 00ttttUU 00ssTTTT 00SSSSSS
|
||||
// 00rrrrrr 00qqqqRR 00ppQQQQ 00PPPPPP
|
||||
// 00oooooo 00nnnnOO 00mmNNNN 00MMMMMM
|
||||
// 00llllll 00kkkkLL 00jjKKKK 00JJJJJJ
|
||||
// 00iiiiii 00hhhhII 00ggHHHH 00GGGGGG
|
||||
// 00ffffff 00eeeeFF 00ddEEEE 00DDDDDD
|
||||
// 00cccccc 00bbbbCC 00aaBBBB 00AAAAAA
|
||||
}
|
||||
30
3rdparty/base64/lib/arch/avx2/enc_translate.c
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
static inline __m256i
|
||||
enc_translate (const __m256i in)
|
||||
{
|
||||
// A lookup table containing the absolute offsets for all ranges:
|
||||
const __m256i lut = _mm256_setr_epi8(
|
||||
65, 71, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -19, -16, 0, 0,
|
||||
65, 71, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -19, -16, 0, 0);
|
||||
|
||||
// Translate values 0..63 to the Base64 alphabet. There are five sets:
|
||||
// # From To Abs Index Characters
|
||||
// 0 [0..25] [65..90] +65 0 ABCDEFGHIJKLMNOPQRSTUVWXYZ
|
||||
// 1 [26..51] [97..122] +71 1 abcdefghijklmnopqrstuvwxyz
|
||||
// 2 [52..61] [48..57] -4 [2..11] 0123456789
|
||||
// 3 [62] [43] -19 12 +
|
||||
// 4 [63] [47] -16 13 /
|
||||
|
||||
// Create LUT indices from the input. The index for range #0 is right,
|
||||
// others are 1 less than expected:
|
||||
__m256i indices = _mm256_subs_epu8(in, _mm256_set1_epi8(51));
|
||||
|
||||
// mask is 0xFF (-1) for range #[1..4] and 0x00 for range #0:
|
||||
const __m256i mask = _mm256_cmpgt_epi8(in, _mm256_set1_epi8(25));
|
||||
|
||||
// Subtract -1, so add 1 to indices for range #[1..4]. All indices are
|
||||
// now correct:
|
||||
indices = _mm256_sub_epi8(indices, mask);
|
||||
|
||||
// Add offsets to input values:
|
||||
return _mm256_add_epi8(in, _mm256_shuffle_epi8(lut, indices));
|
||||
}
|
||||
42
3rdparty/base64/lib/arch/avx512/codec.c
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../../../include/libbase64.h"
|
||||
#include "../../tables/tables.h"
|
||||
#include "../../codecs.h"
|
||||
#include "config.h"
|
||||
#include "../../env.h"
|
||||
|
||||
#if HAVE_AVX512
|
||||
#include <immintrin.h>
|
||||
|
||||
#include "../avx2/dec_reshuffle.c"
|
||||
#include "../avx2/dec_loop.c"
|
||||
#include "enc_reshuffle_translate.c"
|
||||
#include "enc_loop.c"
|
||||
|
||||
#endif // HAVE_AVX512
|
||||
|
||||
BASE64_ENC_FUNCTION(avx512)
|
||||
{
|
||||
#if HAVE_AVX512
|
||||
#include "../generic/enc_head.c"
|
||||
enc_loop_avx512(&s, &slen, &o, &olen);
|
||||
#include "../generic/enc_tail.c"
|
||||
#else
|
||||
BASE64_ENC_STUB
|
||||
#endif
|
||||
}
|
||||
|
||||
// Reuse AVX2 decoding. Not supporting AVX512 at present
|
||||
BASE64_DEC_FUNCTION(avx512)
|
||||
{
|
||||
#if HAVE_AVX512
|
||||
#include "../generic/dec_head.c"
|
||||
dec_loop_avx2(&s, &slen, &o, &olen);
|
||||
#include "../generic/dec_tail.c"
|
||||
#else
|
||||
BASE64_DEC_STUB
|
||||
#endif
|
||||
}
|
||||
61
3rdparty/base64/lib/arch/avx512/enc_loop.c
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
static inline void
|
||||
enc_loop_avx512_inner (const uint8_t **s, uint8_t **o)
|
||||
{
|
||||
// Load input.
|
||||
__m512i src = _mm512_loadu_si512((__m512i *) *s);
|
||||
|
||||
// Reshuffle, translate, store.
|
||||
src = enc_reshuffle_translate(src);
|
||||
_mm512_storeu_si512((__m512i *) *o, src);
|
||||
|
||||
*s += 48;
|
||||
*o += 64;
|
||||
}
|
||||
|
||||
static inline void
|
||||
enc_loop_avx512 (const uint8_t **s, size_t *slen, uint8_t **o, size_t *olen)
|
||||
{
|
||||
if (*slen < 64) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Process blocks of 48 bytes at a time. Because blocks are loaded 64
|
||||
// bytes at a time, ensure that there will be at least 24 remaining
|
||||
// bytes after the last round, so that the final read will not pass
|
||||
// beyond the bounds of the input buffer.
|
||||
size_t rounds = (*slen - 24) / 48;
|
||||
|
||||
*slen -= rounds * 48; // 48 bytes consumed per round
|
||||
*olen += rounds * 64; // 64 bytes produced per round
|
||||
|
||||
while (rounds > 0) {
|
||||
if (rounds >= 8) {
|
||||
enc_loop_avx512_inner(s, o);
|
||||
enc_loop_avx512_inner(s, o);
|
||||
enc_loop_avx512_inner(s, o);
|
||||
enc_loop_avx512_inner(s, o);
|
||||
enc_loop_avx512_inner(s, o);
|
||||
enc_loop_avx512_inner(s, o);
|
||||
enc_loop_avx512_inner(s, o);
|
||||
enc_loop_avx512_inner(s, o);
|
||||
rounds -= 8;
|
||||
continue;
|
||||
}
|
||||
if (rounds >= 4) {
|
||||
enc_loop_avx512_inner(s, o);
|
||||
enc_loop_avx512_inner(s, o);
|
||||
enc_loop_avx512_inner(s, o);
|
||||
enc_loop_avx512_inner(s, o);
|
||||
rounds -= 4;
|
||||
continue;
|
||||
}
|
||||
if (rounds >= 2) {
|
||||
enc_loop_avx512_inner(s, o);
|
||||
enc_loop_avx512_inner(s, o);
|
||||
rounds -= 2;
|
||||
continue;
|
||||
}
|
||||
enc_loop_avx512_inner(s, o);
|
||||
break;
|
||||
}
|
||||
}
|
||||
50
3rdparty/base64/lib/arch/avx512/enc_reshuffle_translate.c
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
// AVX512 algorithm is based on permutevar and multishift. The code is based on
|
||||
// https://github.com/WojciechMula/base64simd which is under BSD-2 license.
|
||||
|
||||
static inline __m512i
|
||||
enc_reshuffle_translate (const __m512i input)
|
||||
{
|
||||
// 32-bit input
|
||||
// [ 0 0 0 0 0 0 0 0|c1 c0 d5 d4 d3 d2 d1 d0|
|
||||
// b3 b2 b1 b0 c5 c4 c3 c2|a5 a4 a3 a2 a1 a0 b5 b4]
|
||||
// output order [1, 2, 0, 1]
|
||||
// [b3 b2 b1 b0 c5 c4 c3 c2|c1 c0 d5 d4 d3 d2 d1 d0|
|
||||
// a5 a4 a3 a2 a1 a0 b5 b4|b3 b2 b1 b0 c3 c2 c1 c0]
|
||||
|
||||
const __m512i shuffle_input = _mm512_setr_epi32(0x01020001,
|
||||
0x04050304,
|
||||
0x07080607,
|
||||
0x0a0b090a,
|
||||
0x0d0e0c0d,
|
||||
0x10110f10,
|
||||
0x13141213,
|
||||
0x16171516,
|
||||
0x191a1819,
|
||||
0x1c1d1b1c,
|
||||
0x1f201e1f,
|
||||
0x22232122,
|
||||
0x25262425,
|
||||
0x28292728,
|
||||
0x2b2c2a2b,
|
||||
0x2e2f2d2e);
|
||||
|
||||
// Reorder bytes
|
||||
// [b3 b2 b1 b0 c5 c4 c3 c2|c1 c0 d5 d4 d3 d2 d1 d0|
|
||||
// a5 a4 a3 a2 a1 a0 b5 b4|b3 b2 b1 b0 c3 c2 c1 c0]
|
||||
const __m512i in = _mm512_permutexvar_epi8(shuffle_input, input);
|
||||
|
||||
// After multishift a single 32-bit lane has following layout
|
||||
// [c1 c0 d5 d4 d3 d2 d1 d0|b1 b0 c5 c4 c3 c2 c1 c0|
|
||||
// a1 a0 b5 b4 b3 b2 b1 b0|d1 d0 a5 a4 a3 a2 a1 a0]
|
||||
// (a = [10:17], b = [4:11], c = [22:27], d = [16:21])
|
||||
|
||||
// 48, 54, 36, 42, 16, 22, 4, 10
|
||||
const __m512i shifts = _mm512_set1_epi64(0x3036242a1016040alu);
|
||||
__m512i shuffled_in = _mm512_multishift_epi64_epi8(shifts, in);
|
||||
|
||||
// Translate immediatedly after reshuffled.
|
||||
const __m512i lookup = _mm512_loadu_si512(base64_table_enc_6bit);
|
||||
|
||||
// Translation 6-bit values to ASCII.
|
||||
return _mm512_permutexvar_epi8(shuffled_in, lookup);
|
||||
}
|
||||
86
3rdparty/base64/lib/arch/generic/32/dec_loop.c
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
static inline int
|
||||
dec_loop_generic_32_inner (const uint8_t **s, uint8_t **o, size_t *rounds)
|
||||
{
|
||||
const uint32_t str
|
||||
= base64_table_dec_32bit_d0[(*s)[0]]
|
||||
| base64_table_dec_32bit_d1[(*s)[1]]
|
||||
| base64_table_dec_32bit_d2[(*s)[2]]
|
||||
| base64_table_dec_32bit_d3[(*s)[3]];
|
||||
|
||||
#if BASE64_LITTLE_ENDIAN
|
||||
|
||||
// LUTs for little-endian set MSB in case of invalid character:
|
||||
if (str & UINT32_C(0x80000000)) {
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
// LUTs for big-endian set LSB in case of invalid character:
|
||||
if (str & UINT32_C(1)) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
// Store the output:
|
||||
memcpy(*o, &str, sizeof (str));
|
||||
|
||||
*s += 4;
|
||||
*o += 3;
|
||||
*rounds -= 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline void
|
||||
dec_loop_generic_32 (const uint8_t **s, size_t *slen, uint8_t **o, size_t *olen)
|
||||
{
|
||||
if (*slen < 8) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Process blocks of 4 bytes per round. Because one extra zero byte is
|
||||
// written after the output, ensure that there will be at least 4 bytes
|
||||
// of input data left to cover the gap. (Two data bytes and up to two
|
||||
// end-of-string markers.)
|
||||
size_t rounds = (*slen - 4) / 4;
|
||||
|
||||
*slen -= rounds * 4; // 4 bytes consumed per round
|
||||
*olen += rounds * 3; // 3 bytes produced per round
|
||||
|
||||
do {
|
||||
if (rounds >= 8) {
|
||||
if (dec_loop_generic_32_inner(s, o, &rounds) &&
|
||||
dec_loop_generic_32_inner(s, o, &rounds) &&
|
||||
dec_loop_generic_32_inner(s, o, &rounds) &&
|
||||
dec_loop_generic_32_inner(s, o, &rounds) &&
|
||||
dec_loop_generic_32_inner(s, o, &rounds) &&
|
||||
dec_loop_generic_32_inner(s, o, &rounds) &&
|
||||
dec_loop_generic_32_inner(s, o, &rounds) &&
|
||||
dec_loop_generic_32_inner(s, o, &rounds)) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (rounds >= 4) {
|
||||
if (dec_loop_generic_32_inner(s, o, &rounds) &&
|
||||
dec_loop_generic_32_inner(s, o, &rounds) &&
|
||||
dec_loop_generic_32_inner(s, o, &rounds) &&
|
||||
dec_loop_generic_32_inner(s, o, &rounds)) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (rounds >= 2) {
|
||||
if (dec_loop_generic_32_inner(s, o, &rounds) &&
|
||||
dec_loop_generic_32_inner(s, o, &rounds)) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
dec_loop_generic_32_inner(s, o, &rounds);
|
||||
break;
|
||||
|
||||
} while (rounds > 0);
|
||||
|
||||
// Adjust for any rounds that were skipped:
|
||||
*slen += rounds * 4;
|
||||
*olen -= rounds * 3;
|
||||
}
|
||||
73
3rdparty/base64/lib/arch/generic/32/enc_loop.c
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
static inline void
|
||||
enc_loop_generic_32_inner (const uint8_t **s, uint8_t **o)
|
||||
{
|
||||
uint32_t src;
|
||||
|
||||
// Load input:
|
||||
memcpy(&src, *s, sizeof (src));
|
||||
|
||||
// Reorder to 32-bit big-endian, if not already in that format. The
|
||||
// workset must be in big-endian, otherwise the shifted bits do not
|
||||
// carry over properly among adjacent bytes:
|
||||
src = BASE64_HTOBE32(src);
|
||||
|
||||
// Two indices for the 12-bit lookup table:
|
||||
const size_t index0 = (src >> 20) & 0xFFFU;
|
||||
const size_t index1 = (src >> 8) & 0xFFFU;
|
||||
|
||||
// Table lookup and store:
|
||||
memcpy(*o + 0, base64_table_enc_12bit + index0, 2);
|
||||
memcpy(*o + 2, base64_table_enc_12bit + index1, 2);
|
||||
|
||||
*s += 3;
|
||||
*o += 4;
|
||||
}
|
||||
|
||||
static inline void
|
||||
enc_loop_generic_32 (const uint8_t **s, size_t *slen, uint8_t **o, size_t *olen)
|
||||
{
|
||||
if (*slen < 4) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Process blocks of 3 bytes at a time. Because blocks are loaded 4
|
||||
// bytes at a time, ensure that there will be at least one remaining
|
||||
// byte after the last round, so that the final read will not pass
|
||||
// beyond the bounds of the input buffer:
|
||||
size_t rounds = (*slen - 1) / 3;
|
||||
|
||||
*slen -= rounds * 3; // 3 bytes consumed per round
|
||||
*olen += rounds * 4; // 4 bytes produced per round
|
||||
|
||||
do {
|
||||
if (rounds >= 8) {
|
||||
enc_loop_generic_32_inner(s, o);
|
||||
enc_loop_generic_32_inner(s, o);
|
||||
enc_loop_generic_32_inner(s, o);
|
||||
enc_loop_generic_32_inner(s, o);
|
||||
enc_loop_generic_32_inner(s, o);
|
||||
enc_loop_generic_32_inner(s, o);
|
||||
enc_loop_generic_32_inner(s, o);
|
||||
enc_loop_generic_32_inner(s, o);
|
||||
rounds -= 8;
|
||||
continue;
|
||||
}
|
||||
if (rounds >= 4) {
|
||||
enc_loop_generic_32_inner(s, o);
|
||||
enc_loop_generic_32_inner(s, o);
|
||||
enc_loop_generic_32_inner(s, o);
|
||||
enc_loop_generic_32_inner(s, o);
|
||||
rounds -= 4;
|
||||
continue;
|
||||
}
|
||||
if (rounds >= 2) {
|
||||
enc_loop_generic_32_inner(s, o);
|
||||
enc_loop_generic_32_inner(s, o);
|
||||
rounds -= 2;
|
||||
continue;
|
||||
}
|
||||
enc_loop_generic_32_inner(s, o);
|
||||
break;
|
||||
|
||||
} while (rounds > 0);
|
||||
}
|
||||
77
3rdparty/base64/lib/arch/generic/64/enc_loop.c
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
static inline void
|
||||
enc_loop_generic_64_inner (const uint8_t **s, uint8_t **o)
|
||||
{
|
||||
uint64_t src;
|
||||
|
||||
// Load input:
|
||||
memcpy(&src, *s, sizeof (src));
|
||||
|
||||
// Reorder to 64-bit big-endian, if not already in that format. The
|
||||
// workset must be in big-endian, otherwise the shifted bits do not
|
||||
// carry over properly among adjacent bytes:
|
||||
src = BASE64_HTOBE64(src);
|
||||
|
||||
// Four indices for the 12-bit lookup table:
|
||||
const size_t index0 = (src >> 52) & 0xFFFU;
|
||||
const size_t index1 = (src >> 40) & 0xFFFU;
|
||||
const size_t index2 = (src >> 28) & 0xFFFU;
|
||||
const size_t index3 = (src >> 16) & 0xFFFU;
|
||||
|
||||
// Table lookup and store:
|
||||
memcpy(*o + 0, base64_table_enc_12bit + index0, 2);
|
||||
memcpy(*o + 2, base64_table_enc_12bit + index1, 2);
|
||||
memcpy(*o + 4, base64_table_enc_12bit + index2, 2);
|
||||
memcpy(*o + 6, base64_table_enc_12bit + index3, 2);
|
||||
|
||||
*s += 6;
|
||||
*o += 8;
|
||||
}
|
||||
|
||||
static inline void
|
||||
enc_loop_generic_64 (const uint8_t **s, size_t *slen, uint8_t **o, size_t *olen)
|
||||
{
|
||||
if (*slen < 8) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Process blocks of 6 bytes at a time. Because blocks are loaded 8
|
||||
// bytes at a time, ensure that there will be at least 2 remaining
|
||||
// bytes after the last round, so that the final read will not pass
|
||||
// beyond the bounds of the input buffer:
|
||||
size_t rounds = (*slen - 2) / 6;
|
||||
|
||||
*slen -= rounds * 6; // 6 bytes consumed per round
|
||||
*olen += rounds * 8; // 8 bytes produced per round
|
||||
|
||||
do {
|
||||
if (rounds >= 8) {
|
||||
enc_loop_generic_64_inner(s, o);
|
||||
enc_loop_generic_64_inner(s, o);
|
||||
enc_loop_generic_64_inner(s, o);
|
||||
enc_loop_generic_64_inner(s, o);
|
||||
enc_loop_generic_64_inner(s, o);
|
||||
enc_loop_generic_64_inner(s, o);
|
||||
enc_loop_generic_64_inner(s, o);
|
||||
enc_loop_generic_64_inner(s, o);
|
||||
rounds -= 8;
|
||||
continue;
|
||||
}
|
||||
if (rounds >= 4) {
|
||||
enc_loop_generic_64_inner(s, o);
|
||||
enc_loop_generic_64_inner(s, o);
|
||||
enc_loop_generic_64_inner(s, o);
|
||||
enc_loop_generic_64_inner(s, o);
|
||||
rounds -= 4;
|
||||
continue;
|
||||
}
|
||||
if (rounds >= 2) {
|
||||
enc_loop_generic_64_inner(s, o);
|
||||
enc_loop_generic_64_inner(s, o);
|
||||
rounds -= 2;
|
||||
continue;
|
||||
}
|
||||
enc_loop_generic_64_inner(s, o);
|
||||
break;
|
||||
|
||||
} while (rounds > 0);
|
||||
}
|
||||
39
3rdparty/base64/lib/arch/generic/codec.c
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../../../include/libbase64.h"
|
||||
#include "../../tables/tables.h"
|
||||
#include "../../codecs.h"
|
||||
#include "config.h"
|
||||
#include "../../env.h"
|
||||
|
||||
#if BASE64_WORDSIZE == 32
|
||||
# include "32/enc_loop.c"
|
||||
#elif BASE64_WORDSIZE == 64
|
||||
# include "64/enc_loop.c"
|
||||
#endif
|
||||
|
||||
#if BASE64_WORDSIZE >= 32
|
||||
# include "32/dec_loop.c"
|
||||
#endif
|
||||
|
||||
BASE64_ENC_FUNCTION(plain)
|
||||
{
|
||||
#include "enc_head.c"
|
||||
#if BASE64_WORDSIZE == 32
|
||||
enc_loop_generic_32(&s, &slen, &o, &olen);
|
||||
#elif BASE64_WORDSIZE == 64
|
||||
enc_loop_generic_64(&s, &slen, &o, &olen);
|
||||
#endif
|
||||
#include "enc_tail.c"
|
||||
}
|
||||
|
||||
BASE64_DEC_FUNCTION(plain)
|
||||
{
|
||||
#include "dec_head.c"
|
||||
#if BASE64_WORDSIZE >= 32
|
||||
dec_loop_generic_32(&s, &slen, &o, &olen);
|
||||
#endif
|
||||
#include "dec_tail.c"
|
||||
}
|
||||
37
3rdparty/base64/lib/arch/generic/dec_head.c
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
int ret = 0;
|
||||
const uint8_t *s = (const uint8_t *) src;
|
||||
uint8_t *o = (uint8_t *) out;
|
||||
uint8_t q;
|
||||
|
||||
// Use local temporaries to avoid cache thrashing:
|
||||
size_t olen = 0;
|
||||
size_t slen = srclen;
|
||||
struct base64_state st;
|
||||
st.eof = state->eof;
|
||||
st.bytes = state->bytes;
|
||||
st.carry = state->carry;
|
||||
|
||||
// If we previously saw an EOF or an invalid character, bail out:
|
||||
if (st.eof) {
|
||||
*outlen = 0;
|
||||
ret = 0;
|
||||
// If there was a trailing '=' to check, check it:
|
||||
if (slen && (st.eof == BASE64_AEOF)) {
|
||||
state->bytes = 0;
|
||||
state->eof = BASE64_EOF;
|
||||
ret = ((base64_table_dec_8bit[*s++] == 254) && (slen == 1)) ? 1 : 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Turn four 6-bit numbers into three bytes:
|
||||
// out[0] = 11111122
|
||||
// out[1] = 22223333
|
||||
// out[2] = 33444444
|
||||
|
||||
// Duff's device again:
|
||||
switch (st.bytes)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
case 0:
|
||||
91
3rdparty/base64/lib/arch/generic/dec_tail.c
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
if (slen-- == 0) {
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
if ((q = base64_table_dec_8bit[*s++]) >= 254) {
|
||||
st.eof = BASE64_EOF;
|
||||
// Treat character '=' as invalid for byte 0:
|
||||
break;
|
||||
}
|
||||
st.carry = q << 2;
|
||||
st.bytes++;
|
||||
|
||||
// Deliberate fallthrough:
|
||||
BASE64_FALLTHROUGH
|
||||
|
||||
case 1: if (slen-- == 0) {
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
if ((q = base64_table_dec_8bit[*s++]) >= 254) {
|
||||
st.eof = BASE64_EOF;
|
||||
// Treat character '=' as invalid for byte 1:
|
||||
break;
|
||||
}
|
||||
*o++ = st.carry | (q >> 4);
|
||||
st.carry = q << 4;
|
||||
st.bytes++;
|
||||
olen++;
|
||||
|
||||
// Deliberate fallthrough:
|
||||
BASE64_FALLTHROUGH
|
||||
|
||||
case 2: if (slen-- == 0) {
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
if ((q = base64_table_dec_8bit[*s++]) >= 254) {
|
||||
st.bytes++;
|
||||
// When q == 254, the input char is '='.
|
||||
// Check if next byte is also '=':
|
||||
if (q == 254) {
|
||||
if (slen-- != 0) {
|
||||
st.bytes = 0;
|
||||
// EOF:
|
||||
st.eof = BASE64_EOF;
|
||||
q = base64_table_dec_8bit[*s++];
|
||||
ret = ((q == 254) && (slen == 0)) ? 1 : 0;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
// Almost EOF
|
||||
st.eof = BASE64_AEOF;
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// If we get here, there was an error:
|
||||
break;
|
||||
}
|
||||
*o++ = st.carry | (q >> 2);
|
||||
st.carry = q << 6;
|
||||
st.bytes++;
|
||||
olen++;
|
||||
|
||||
// Deliberate fallthrough:
|
||||
BASE64_FALLTHROUGH
|
||||
|
||||
case 3: if (slen-- == 0) {
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
if ((q = base64_table_dec_8bit[*s++]) >= 254) {
|
||||
st.bytes = 0;
|
||||
st.eof = BASE64_EOF;
|
||||
// When q == 254, the input char is '='. Return 1 and EOF.
|
||||
// When q == 255, the input char is invalid. Return 0 and EOF.
|
||||
ret = ((q == 254) && (slen == 0)) ? 1 : 0;
|
||||
break;
|
||||
}
|
||||
*o++ = st.carry | q;
|
||||
st.carry = 0;
|
||||
st.bytes = 0;
|
||||
olen++;
|
||||
}
|
||||
}
|
||||
|
||||
state->eof = st.eof;
|
||||
state->bytes = st.bytes;
|
||||
state->carry = st.carry;
|
||||
*outlen = olen;
|
||||
return ret;
|
||||
24
3rdparty/base64/lib/arch/generic/enc_head.c
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
// Assume that *out is large enough to contain the output.
|
||||
// Theoretically it should be 4/3 the length of src.
|
||||
const uint8_t *s = (const uint8_t *) src;
|
||||
uint8_t *o = (uint8_t *) out;
|
||||
|
||||
// Use local temporaries to avoid cache thrashing:
|
||||
size_t olen = 0;
|
||||
size_t slen = srclen;
|
||||
struct base64_state st;
|
||||
st.bytes = state->bytes;
|
||||
st.carry = state->carry;
|
||||
|
||||
// Turn three bytes into four 6-bit numbers:
|
||||
// in[0] = 00111111
|
||||
// in[1] = 00112222
|
||||
// in[2] = 00222233
|
||||
// in[3] = 00333333
|
||||
|
||||
// Duff's device, a for() loop inside a switch() statement. Legal!
|
||||
switch (st.bytes)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
case 0:
|
||||
34
3rdparty/base64/lib/arch/generic/enc_tail.c
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
if (slen-- == 0) {
|
||||
break;
|
||||
}
|
||||
*o++ = base64_table_enc_6bit[*s >> 2];
|
||||
st.carry = (*s++ << 4) & 0x30;
|
||||
st.bytes++;
|
||||
olen += 1;
|
||||
|
||||
// Deliberate fallthrough:
|
||||
BASE64_FALLTHROUGH
|
||||
|
||||
case 1: if (slen-- == 0) {
|
||||
break;
|
||||
}
|
||||
*o++ = base64_table_enc_6bit[st.carry | (*s >> 4)];
|
||||
st.carry = (*s++ << 2) & 0x3C;
|
||||
st.bytes++;
|
||||
olen += 1;
|
||||
|
||||
// Deliberate fallthrough:
|
||||
BASE64_FALLTHROUGH
|
||||
|
||||
case 2: if (slen-- == 0) {
|
||||
break;
|
||||
}
|
||||
*o++ = base64_table_enc_6bit[st.carry | (*s >> 6)];
|
||||
*o++ = base64_table_enc_6bit[*s++ & 0x3F];
|
||||
st.bytes = 0;
|
||||
olen += 2;
|
||||
}
|
||||
}
|
||||
state->bytes = st.bytes;
|
||||
state->carry = st.carry;
|
||||
*outlen = olen;
|
||||
77
3rdparty/base64/lib/arch/neon32/codec.c
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../../../include/libbase64.h"
|
||||
#include "../../tables/tables.h"
|
||||
#include "../../codecs.h"
|
||||
#include "config.h"
|
||||
#include "../../env.h"
|
||||
|
||||
#ifdef __arm__
|
||||
# if (defined(__ARM_NEON__) || defined(__ARM_NEON)) && HAVE_NEON32
|
||||
# define BASE64_USE_NEON32
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef BASE64_USE_NEON32
|
||||
#include <arm_neon.h>
|
||||
|
||||
// Only enable inline assembly on supported compilers.
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#define BASE64_NEON32_USE_ASM
|
||||
#endif
|
||||
|
||||
static inline uint8x16_t
|
||||
vqtbl1q_u8 (const uint8x16_t lut, const uint8x16_t indices)
|
||||
{
|
||||
// NEON32 only supports 64-bit wide lookups in 128-bit tables. Emulate
|
||||
// the NEON64 `vqtbl1q_u8` intrinsic to do 128-bit wide lookups.
|
||||
uint8x8x2_t lut2;
|
||||
uint8x8x2_t result;
|
||||
|
||||
lut2.val[0] = vget_low_u8(lut);
|
||||
lut2.val[1] = vget_high_u8(lut);
|
||||
|
||||
result.val[0] = vtbl2_u8(lut2, vget_low_u8(indices));
|
||||
result.val[1] = vtbl2_u8(lut2, vget_high_u8(indices));
|
||||
|
||||
return vcombine_u8(result.val[0], result.val[1]);
|
||||
}
|
||||
|
||||
#include "../generic/32/dec_loop.c"
|
||||
#include "../generic/32/enc_loop.c"
|
||||
#include "dec_loop.c"
|
||||
#include "enc_reshuffle.c"
|
||||
#include "enc_translate.c"
|
||||
#include "enc_loop.c"
|
||||
|
||||
#endif // BASE64_USE_NEON32
|
||||
|
||||
// Stride size is so large on these NEON 32-bit functions
|
||||
// (48 bytes encode, 32 bytes decode) that we inline the
|
||||
// uint32 codec to stay performant on smaller inputs.
|
||||
|
||||
BASE64_ENC_FUNCTION(neon32)
|
||||
{
|
||||
#ifdef BASE64_USE_NEON32
|
||||
#include "../generic/enc_head.c"
|
||||
enc_loop_neon32(&s, &slen, &o, &olen);
|
||||
enc_loop_generic_32(&s, &slen, &o, &olen);
|
||||
#include "../generic/enc_tail.c"
|
||||
#else
|
||||
BASE64_ENC_STUB
|
||||
#endif
|
||||
}
|
||||
|
||||
BASE64_DEC_FUNCTION(neon32)
|
||||
{
|
||||
#ifdef BASE64_USE_NEON32
|
||||
#include "../generic/dec_head.c"
|
||||
dec_loop_neon32(&s, &slen, &o, &olen);
|
||||
dec_loop_generic_32(&s, &slen, &o, &olen);
|
||||
#include "../generic/dec_tail.c"
|
||||
#else
|
||||
BASE64_DEC_STUB
|
||||
#endif
|
||||
}
|
||||
106
3rdparty/base64/lib/arch/neon32/dec_loop.c
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
static inline int
|
||||
is_nonzero (const uint8x16_t v)
|
||||
{
|
||||
uint64_t u64;
|
||||
const uint64x2_t v64 = vreinterpretq_u64_u8(v);
|
||||
const uint32x2_t v32 = vqmovn_u64(v64);
|
||||
|
||||
vst1_u64(&u64, vreinterpret_u64_u32(v32));
|
||||
return u64 != 0;
|
||||
}
|
||||
|
||||
static inline uint8x16_t
|
||||
delta_lookup (const uint8x16_t v)
|
||||
{
|
||||
const uint8x8_t lut = {
|
||||
0, 16, 19, 4, (uint8_t) -65, (uint8_t) -65, (uint8_t) -71, (uint8_t) -71,
|
||||
};
|
||||
|
||||
return vcombine_u8(
|
||||
vtbl1_u8(lut, vget_low_u8(v)),
|
||||
vtbl1_u8(lut, vget_high_u8(v)));
|
||||
}
|
||||
|
||||
static inline uint8x16_t
|
||||
dec_loop_neon32_lane (uint8x16_t *lane)
|
||||
{
|
||||
// See the SSSE3 decoder for an explanation of the algorithm.
|
||||
const uint8x16_t lut_lo = {
|
||||
0x15, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
|
||||
0x11, 0x11, 0x13, 0x1A, 0x1B, 0x1B, 0x1B, 0x1A
|
||||
};
|
||||
|
||||
const uint8x16_t lut_hi = {
|
||||
0x10, 0x10, 0x01, 0x02, 0x04, 0x08, 0x04, 0x08,
|
||||
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10
|
||||
};
|
||||
|
||||
const uint8x16_t mask_0F = vdupq_n_u8(0x0F);
|
||||
const uint8x16_t mask_2F = vdupq_n_u8(0x2F);
|
||||
|
||||
const uint8x16_t hi_nibbles = vshrq_n_u8(*lane, 4);
|
||||
const uint8x16_t lo_nibbles = vandq_u8(*lane, mask_0F);
|
||||
const uint8x16_t eq_2F = vceqq_u8(*lane, mask_2F);
|
||||
|
||||
const uint8x16_t hi = vqtbl1q_u8(lut_hi, hi_nibbles);
|
||||
const uint8x16_t lo = vqtbl1q_u8(lut_lo, lo_nibbles);
|
||||
|
||||
// Now simply add the delta values to the input:
|
||||
*lane = vaddq_u8(*lane, delta_lookup(vaddq_u8(eq_2F, hi_nibbles)));
|
||||
|
||||
// Return the validity mask:
|
||||
return vandq_u8(lo, hi);
|
||||
}
|
||||
|
||||
static inline void
|
||||
dec_loop_neon32 (const uint8_t **s, size_t *slen, uint8_t **o, size_t *olen)
|
||||
{
|
||||
if (*slen < 64) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Process blocks of 64 bytes per round. Unlike the SSE codecs, no
|
||||
// extra trailing zero bytes are written, so it is not necessary to
|
||||
// reserve extra input bytes:
|
||||
size_t rounds = *slen / 64;
|
||||
|
||||
*slen -= rounds * 64; // 64 bytes consumed per round
|
||||
*olen += rounds * 48; // 48 bytes produced per round
|
||||
|
||||
do {
|
||||
uint8x16x3_t dec;
|
||||
|
||||
// Load 64 bytes and deinterleave:
|
||||
uint8x16x4_t str = vld4q_u8(*s);
|
||||
|
||||
// Decode each lane, collect a mask of invalid inputs:
|
||||
const uint8x16_t classified
|
||||
= dec_loop_neon32_lane(&str.val[0])
|
||||
| dec_loop_neon32_lane(&str.val[1])
|
||||
| dec_loop_neon32_lane(&str.val[2])
|
||||
| dec_loop_neon32_lane(&str.val[3]);
|
||||
|
||||
// Check for invalid input: if any of the delta values are
|
||||
// zero, fall back on bytewise code to do error checking and
|
||||
// reporting:
|
||||
if (is_nonzero(classified)) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Compress four bytes into three:
|
||||
dec.val[0] = vorrq_u8(vshlq_n_u8(str.val[0], 2), vshrq_n_u8(str.val[1], 4));
|
||||
dec.val[1] = vorrq_u8(vshlq_n_u8(str.val[1], 4), vshrq_n_u8(str.val[2], 2));
|
||||
dec.val[2] = vorrq_u8(vshlq_n_u8(str.val[2], 6), str.val[3]);
|
||||
|
||||
// Interleave and store decoded result:
|
||||
vst3q_u8(*o, dec);
|
||||
|
||||
*s += 64;
|
||||
*o += 48;
|
||||
|
||||
} while (--rounds > 0);
|
||||
|
||||
// Adjust for any rounds that were skipped:
|
||||
*slen += rounds * 64;
|
||||
*olen -= rounds * 48;
|
||||
}
|
||||
170
3rdparty/base64/lib/arch/neon32/enc_loop.c
vendored
Normal file
@@ -0,0 +1,170 @@
|
||||
#ifdef BASE64_NEON32_USE_ASM
|
||||
static inline void
|
||||
enc_loop_neon32_inner_asm (const uint8_t **s, uint8_t **o)
|
||||
{
|
||||
// This function duplicates the functionality of enc_loop_neon32_inner,
|
||||
// but entirely with inline assembly. This gives a significant speedup
|
||||
// over using NEON intrinsics, which do not always generate very good
|
||||
// code. The logic of the assembly is directly lifted from the
|
||||
// intrinsics version, so it can be used as a guide to this code.
|
||||
|
||||
// Temporary registers, used as scratch space.
|
||||
uint8x16_t tmp0, tmp1, tmp2, tmp3;
|
||||
uint8x16_t mask0, mask1, mask2, mask3;
|
||||
|
||||
// A lookup table containing the absolute offsets for all ranges.
|
||||
const uint8x16_t lut = {
|
||||
65U, 71U, 252U, 252U,
|
||||
252U, 252U, 252U, 252U,
|
||||
252U, 252U, 252U, 252U,
|
||||
237U, 240U, 0U, 0U
|
||||
};
|
||||
|
||||
// Numeric constants.
|
||||
const uint8x16_t n51 = vdupq_n_u8(51);
|
||||
const uint8x16_t n25 = vdupq_n_u8(25);
|
||||
const uint8x16_t n63 = vdupq_n_u8(63);
|
||||
|
||||
__asm__ (
|
||||
|
||||
// Load 48 bytes and deinterleave. The bytes are loaded to
|
||||
// hard-coded registers q12, q13 and q14, to ensure that they
|
||||
// are contiguous. Increment the source pointer.
|
||||
"vld3.8 {d24, d26, d28}, [%[src]]! \n\t"
|
||||
"vld3.8 {d25, d27, d29}, [%[src]]! \n\t"
|
||||
|
||||
// Reshuffle the bytes using temporaries.
|
||||
"vshr.u8 %q[t0], q12, #2 \n\t"
|
||||
"vshr.u8 %q[t1], q13, #4 \n\t"
|
||||
"vshr.u8 %q[t2], q14, #6 \n\t"
|
||||
"vsli.8 %q[t1], q12, #4 \n\t"
|
||||
"vsli.8 %q[t2], q13, #2 \n\t"
|
||||
"vand.u8 %q[t1], %q[t1], %q[n63] \n\t"
|
||||
"vand.u8 %q[t2], %q[t2], %q[n63] \n\t"
|
||||
"vand.u8 %q[t3], q14, %q[n63] \n\t"
|
||||
|
||||
// t0..t3 are the reshuffled inputs. Create LUT indices.
|
||||
"vqsub.u8 q12, %q[t0], %q[n51] \n\t"
|
||||
"vqsub.u8 q13, %q[t1], %q[n51] \n\t"
|
||||
"vqsub.u8 q14, %q[t2], %q[n51] \n\t"
|
||||
"vqsub.u8 q15, %q[t3], %q[n51] \n\t"
|
||||
|
||||
// Create the mask for range #0.
|
||||
"vcgt.u8 %q[m0], %q[t0], %q[n25] \n\t"
|
||||
"vcgt.u8 %q[m1], %q[t1], %q[n25] \n\t"
|
||||
"vcgt.u8 %q[m2], %q[t2], %q[n25] \n\t"
|
||||
"vcgt.u8 %q[m3], %q[t3], %q[n25] \n\t"
|
||||
|
||||
// Subtract -1 to correct the LUT indices.
|
||||
"vsub.u8 q12, %q[m0] \n\t"
|
||||
"vsub.u8 q13, %q[m1] \n\t"
|
||||
"vsub.u8 q14, %q[m2] \n\t"
|
||||
"vsub.u8 q15, %q[m3] \n\t"
|
||||
|
||||
// Lookup the delta values.
|
||||
"vtbl.u8 d24, {%q[lut]}, d24 \n\t"
|
||||
"vtbl.u8 d25, {%q[lut]}, d25 \n\t"
|
||||
"vtbl.u8 d26, {%q[lut]}, d26 \n\t"
|
||||
"vtbl.u8 d27, {%q[lut]}, d27 \n\t"
|
||||
"vtbl.u8 d28, {%q[lut]}, d28 \n\t"
|
||||
"vtbl.u8 d29, {%q[lut]}, d29 \n\t"
|
||||
"vtbl.u8 d30, {%q[lut]}, d30 \n\t"
|
||||
"vtbl.u8 d31, {%q[lut]}, d31 \n\t"
|
||||
|
||||
// Add the delta values.
|
||||
"vadd.u8 q12, %q[t0] \n\t"
|
||||
"vadd.u8 q13, %q[t1] \n\t"
|
||||
"vadd.u8 q14, %q[t2] \n\t"
|
||||
"vadd.u8 q15, %q[t3] \n\t"
|
||||
|
||||
// Store 64 bytes and interleave. Increment the dest pointer.
|
||||
"vst4.8 {d24, d26, d28, d30}, [%[dst]]! \n\t"
|
||||
"vst4.8 {d25, d27, d29, d31}, [%[dst]]! \n\t"
|
||||
|
||||
// Outputs (modified).
|
||||
: [src] "+r" (*s),
|
||||
[dst] "+r" (*o),
|
||||
[t0] "=&w" (tmp0),
|
||||
[t1] "=&w" (tmp1),
|
||||
[t2] "=&w" (tmp2),
|
||||
[t3] "=&w" (tmp3),
|
||||
[m0] "=&w" (mask0),
|
||||
[m1] "=&w" (mask1),
|
||||
[m2] "=&w" (mask2),
|
||||
[m3] "=&w" (mask3)
|
||||
|
||||
// Inputs (not modified).
|
||||
: [lut] "w" (lut),
|
||||
[n25] "w" (n25),
|
||||
[n51] "w" (n51),
|
||||
[n63] "w" (n63)
|
||||
|
||||
// Clobbers.
|
||||
: "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31",
|
||||
"cc", "memory"
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void
|
||||
enc_loop_neon32_inner (const uint8_t **s, uint8_t **o)
|
||||
{
|
||||
#ifdef BASE64_NEON32_USE_ASM
|
||||
enc_loop_neon32_inner_asm(s, o);
|
||||
#else
|
||||
// Load 48 bytes and deinterleave:
|
||||
uint8x16x3_t src = vld3q_u8(*s);
|
||||
|
||||
// Reshuffle:
|
||||
uint8x16x4_t out = enc_reshuffle(src);
|
||||
|
||||
// Translate reshuffled bytes to the Base64 alphabet:
|
||||
out = enc_translate(out);
|
||||
|
||||
// Interleave and store output:
|
||||
vst4q_u8(*o, out);
|
||||
|
||||
*s += 48;
|
||||
*o += 64;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void
|
||||
enc_loop_neon32 (const uint8_t **s, size_t *slen, uint8_t **o, size_t *olen)
|
||||
{
|
||||
size_t rounds = *slen / 48;
|
||||
|
||||
*slen -= rounds * 48; // 48 bytes consumed per round
|
||||
*olen += rounds * 64; // 64 bytes produced per round
|
||||
|
||||
while (rounds > 0) {
|
||||
if (rounds >= 8) {
|
||||
enc_loop_neon32_inner(s, o);
|
||||
enc_loop_neon32_inner(s, o);
|
||||
enc_loop_neon32_inner(s, o);
|
||||
enc_loop_neon32_inner(s, o);
|
||||
enc_loop_neon32_inner(s, o);
|
||||
enc_loop_neon32_inner(s, o);
|
||||
enc_loop_neon32_inner(s, o);
|
||||
enc_loop_neon32_inner(s, o);
|
||||
rounds -= 8;
|
||||
continue;
|
||||
}
|
||||
if (rounds >= 4) {
|
||||
enc_loop_neon32_inner(s, o);
|
||||
enc_loop_neon32_inner(s, o);
|
||||
enc_loop_neon32_inner(s, o);
|
||||
enc_loop_neon32_inner(s, o);
|
||||
rounds -= 4;
|
||||
continue;
|
||||
}
|
||||
if (rounds >= 2) {
|
||||
enc_loop_neon32_inner(s, o);
|
||||
enc_loop_neon32_inner(s, o);
|
||||
rounds -= 2;
|
||||
continue;
|
||||
}
|
||||
enc_loop_neon32_inner(s, o);
|
||||
break;
|
||||
}
|
||||
}
|
||||
31
3rdparty/base64/lib/arch/neon32/enc_reshuffle.c
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
static inline uint8x16x4_t
|
||||
enc_reshuffle (uint8x16x3_t in)
|
||||
{
|
||||
uint8x16x4_t out;
|
||||
|
||||
// Input:
|
||||
// in[0] = a7 a6 a5 a4 a3 a2 a1 a0
|
||||
// in[1] = b7 b6 b5 b4 b3 b2 b1 b0
|
||||
// in[2] = c7 c6 c5 c4 c3 c2 c1 c0
|
||||
|
||||
// Output:
|
||||
// out[0] = 00 00 a7 a6 a5 a4 a3 a2
|
||||
// out[1] = 00 00 a1 a0 b7 b6 b5 b4
|
||||
// out[2] = 00 00 b3 b2 b1 b0 c7 c6
|
||||
// out[3] = 00 00 c5 c4 c3 c2 c1 c0
|
||||
|
||||
// Move the input bits to where they need to be in the outputs. Except
|
||||
// for the first output, the high two bits are not cleared.
|
||||
out.val[0] = vshrq_n_u8(in.val[0], 2);
|
||||
out.val[1] = vshrq_n_u8(in.val[1], 4);
|
||||
out.val[2] = vshrq_n_u8(in.val[2], 6);
|
||||
out.val[1] = vsliq_n_u8(out.val[1], in.val[0], 4);
|
||||
out.val[2] = vsliq_n_u8(out.val[2], in.val[1], 2);
|
||||
|
||||
// Clear the high two bits in the second, third and fourth output.
|
||||
out.val[1] = vandq_u8(out.val[1], vdupq_n_u8(0x3F));
|
||||
out.val[2] = vandq_u8(out.val[2], vdupq_n_u8(0x3F));
|
||||
out.val[3] = vandq_u8(in.val[2], vdupq_n_u8(0x3F));
|
||||
|
||||
return out;
|
||||
}
|
||||
57
3rdparty/base64/lib/arch/neon32/enc_translate.c
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
static inline uint8x16x4_t
|
||||
enc_translate (const uint8x16x4_t in)
|
||||
{
|
||||
// A lookup table containing the absolute offsets for all ranges:
|
||||
const uint8x16_t lut = {
|
||||
65U, 71U, 252U, 252U,
|
||||
252U, 252U, 252U, 252U,
|
||||
252U, 252U, 252U, 252U,
|
||||
237U, 240U, 0U, 0U
|
||||
};
|
||||
|
||||
const uint8x16_t offset = vdupq_n_u8(51);
|
||||
|
||||
uint8x16x4_t indices, mask, delta, out;
|
||||
|
||||
// Translate values 0..63 to the Base64 alphabet. There are five sets:
|
||||
// # From To Abs Index Characters
|
||||
// 0 [0..25] [65..90] +65 0 ABCDEFGHIJKLMNOPQRSTUVWXYZ
|
||||
// 1 [26..51] [97..122] +71 1 abcdefghijklmnopqrstuvwxyz
|
||||
// 2 [52..61] [48..57] -4 [2..11] 0123456789
|
||||
// 3 [62] [43] -19 12 +
|
||||
// 4 [63] [47] -16 13 /
|
||||
|
||||
// Create LUT indices from input:
|
||||
// the index for range #0 is right, others are 1 less than expected:
|
||||
indices.val[0] = vqsubq_u8(in.val[0], offset);
|
||||
indices.val[1] = vqsubq_u8(in.val[1], offset);
|
||||
indices.val[2] = vqsubq_u8(in.val[2], offset);
|
||||
indices.val[3] = vqsubq_u8(in.val[3], offset);
|
||||
|
||||
// mask is 0xFF (-1) for range #[1..4] and 0x00 for range #0:
|
||||
mask.val[0] = vcgtq_u8(in.val[0], vdupq_n_u8(25));
|
||||
mask.val[1] = vcgtq_u8(in.val[1], vdupq_n_u8(25));
|
||||
mask.val[2] = vcgtq_u8(in.val[2], vdupq_n_u8(25));
|
||||
mask.val[3] = vcgtq_u8(in.val[3], vdupq_n_u8(25));
|
||||
|
||||
// Subtract -1, so add 1 to indices for range #[1..4], All indices are
|
||||
// now correct:
|
||||
indices.val[0] = vsubq_u8(indices.val[0], mask.val[0]);
|
||||
indices.val[1] = vsubq_u8(indices.val[1], mask.val[1]);
|
||||
indices.val[2] = vsubq_u8(indices.val[2], mask.val[2]);
|
||||
indices.val[3] = vsubq_u8(indices.val[3], mask.val[3]);
|
||||
|
||||
// Lookup delta values:
|
||||
delta.val[0] = vqtbl1q_u8(lut, indices.val[0]);
|
||||
delta.val[1] = vqtbl1q_u8(lut, indices.val[1]);
|
||||
delta.val[2] = vqtbl1q_u8(lut, indices.val[2]);
|
||||
delta.val[3] = vqtbl1q_u8(lut, indices.val[3]);
|
||||
|
||||
// Add delta values:
|
||||
out.val[0] = vaddq_u8(in.val[0], delta.val[0]);
|
||||
out.val[1] = vaddq_u8(in.val[1], delta.val[1]);
|
||||
out.val[2] = vaddq_u8(in.val[2], delta.val[2]);
|
||||
out.val[3] = vaddq_u8(in.val[3], delta.val[3]);
|
||||
|
||||
return out;
|
||||
}
|
||||
97
3rdparty/base64/lib/arch/neon64/codec.c
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../../../include/libbase64.h"
|
||||
#include "../../tables/tables.h"
|
||||
#include "../../codecs.h"
|
||||
#include "config.h"
|
||||
#include "../../env.h"
|
||||
|
||||
#ifdef __aarch64__
|
||||
# if (defined(__ARM_NEON__) || defined(__ARM_NEON)) && HAVE_NEON64
|
||||
# define BASE64_USE_NEON64
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef BASE64_USE_NEON64
|
||||
#include <arm_neon.h>
|
||||
|
||||
// Only enable inline assembly on supported compilers.
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#define BASE64_NEON64_USE_ASM
|
||||
#endif
|
||||
|
||||
static inline uint8x16x4_t
|
||||
load_64byte_table (const uint8_t *p)
|
||||
{
|
||||
#ifdef BASE64_NEON64_USE_ASM
|
||||
|
||||
// Force the table to be loaded into contiguous registers. GCC will not
|
||||
// normally allocate contiguous registers for a `uint8x16x4_t'. These
|
||||
// registers are chosen to not conflict with the ones in the enc loop.
|
||||
register uint8x16_t t0 __asm__ ("v8");
|
||||
register uint8x16_t t1 __asm__ ("v9");
|
||||
register uint8x16_t t2 __asm__ ("v10");
|
||||
register uint8x16_t t3 __asm__ ("v11");
|
||||
|
||||
__asm__ (
|
||||
"ld1 {%[t0].16b, %[t1].16b, %[t2].16b, %[t3].16b}, [%[src]], #64 \n\t"
|
||||
: [src] "+r" (p),
|
||||
[t0] "=w" (t0),
|
||||
[t1] "=w" (t1),
|
||||
[t2] "=w" (t2),
|
||||
[t3] "=w" (t3)
|
||||
);
|
||||
|
||||
return (uint8x16x4_t) {
|
||||
.val[0] = t0,
|
||||
.val[1] = t1,
|
||||
.val[2] = t2,
|
||||
.val[3] = t3,
|
||||
};
|
||||
#else
|
||||
return vld1q_u8_x4(p);
|
||||
#endif
|
||||
}
|
||||
|
||||
#include "../generic/32/dec_loop.c"
|
||||
#include "../generic/64/enc_loop.c"
|
||||
#include "dec_loop.c"
|
||||
|
||||
#ifdef BASE64_NEON64_USE_ASM
|
||||
# include "enc_loop_asm.c"
|
||||
#else
|
||||
# include "enc_reshuffle.c"
|
||||
# include "enc_loop.c"
|
||||
#endif
|
||||
|
||||
#endif // BASE64_USE_NEON64
|
||||
|
||||
// Stride size is so large on these NEON 64-bit functions
|
||||
// (48 bytes encode, 64 bytes decode) that we inline the
|
||||
// uint64 codec to stay performant on smaller inputs.
|
||||
|
||||
BASE64_ENC_FUNCTION(neon64)
|
||||
{
|
||||
#ifdef BASE64_USE_NEON64
|
||||
#include "../generic/enc_head.c"
|
||||
enc_loop_neon64(&s, &slen, &o, &olen);
|
||||
enc_loop_generic_64(&s, &slen, &o, &olen);
|
||||
#include "../generic/enc_tail.c"
|
||||
#else
|
||||
BASE64_ENC_STUB
|
||||
#endif
|
||||
}
|
||||
|
||||
BASE64_DEC_FUNCTION(neon64)
|
||||
{
|
||||
#ifdef BASE64_USE_NEON64
|
||||
#include "../generic/dec_head.c"
|
||||
dec_loop_neon64(&s, &slen, &o, &olen);
|
||||
dec_loop_generic_32(&s, &slen, &o, &olen);
|
||||
#include "../generic/dec_tail.c"
|
||||
#else
|
||||
BASE64_DEC_STUB
|
||||
#endif
|
||||
}
|
||||
129
3rdparty/base64/lib/arch/neon64/dec_loop.c
vendored
Normal file
@@ -0,0 +1,129 @@
|
||||
// The input consists of five valid character sets in the Base64 alphabet,
|
||||
// which we need to map back to the 6-bit values they represent.
|
||||
// There are three ranges, two singles, and then there's the rest.
|
||||
//
|
||||
// # From To LUT Characters
|
||||
// 1 [0..42] [255] #1 invalid input
|
||||
// 2 [43] [62] #1 +
|
||||
// 3 [44..46] [255] #1 invalid input
|
||||
// 4 [47] [63] #1 /
|
||||
// 5 [48..57] [52..61] #1 0..9
|
||||
// 6 [58..63] [255] #1 invalid input
|
||||
// 7 [64] [255] #2 invalid input
|
||||
// 8 [65..90] [0..25] #2 A..Z
|
||||
// 9 [91..96] [255] #2 invalid input
|
||||
// 10 [97..122] [26..51] #2 a..z
|
||||
// 11 [123..126] [255] #2 invalid input
|
||||
// (12) Everything else => invalid input
|
||||
|
||||
// The first LUT will use the VTBL instruction (out of range indices are set to
|
||||
// 0 in destination).
|
||||
static const uint8_t dec_lut1[] = {
|
||||
255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U,
|
||||
255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U,
|
||||
255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 62U, 255U, 255U, 255U, 63U,
|
||||
52U, 53U, 54U, 55U, 56U, 57U, 58U, 59U, 60U, 61U, 255U, 255U, 255U, 255U, 255U, 255U,
|
||||
};
|
||||
|
||||
// The second LUT will use the VTBX instruction (out of range indices will be
|
||||
// unchanged in destination). Input [64..126] will be mapped to index [1..63]
|
||||
// in this LUT. Index 0 means that value comes from LUT #1.
|
||||
static const uint8_t dec_lut2[] = {
|
||||
0U, 255U, 0U, 1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 11U, 12U, 13U,
|
||||
14U, 15U, 16U, 17U, 18U, 19U, 20U, 21U, 22U, 23U, 24U, 25U, 255U, 255U, 255U, 255U,
|
||||
255U, 255U, 26U, 27U, 28U, 29U, 30U, 31U, 32U, 33U, 34U, 35U, 36U, 37U, 38U, 39U,
|
||||
40U, 41U, 42U, 43U, 44U, 45U, 46U, 47U, 48U, 49U, 50U, 51U, 255U, 255U, 255U, 255U,
|
||||
};
|
||||
|
||||
// All input values in range for the first look-up will be 0U in the second
|
||||
// look-up result. All input values out of range for the first look-up will be
|
||||
// 0U in the first look-up result. Thus, the two results can be ORed without
|
||||
// conflicts.
|
||||
//
|
||||
// Invalid characters that are in the valid range for either look-up will be
|
||||
// set to 255U in the combined result. Other invalid characters will just be
|
||||
// passed through with the second look-up result (using the VTBX instruction).
|
||||
// Since the second LUT is 64 bytes, those passed-through values are guaranteed
|
||||
// to have a value greater than 63U. Therefore, valid characters will be mapped
|
||||
// to the valid [0..63] range and all invalid characters will be mapped to
|
||||
// values greater than 63.
|
||||
|
||||
static inline void
|
||||
dec_loop_neon64 (const uint8_t **s, size_t *slen, uint8_t **o, size_t *olen)
|
||||
{
|
||||
if (*slen < 64) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Process blocks of 64 bytes per round. Unlike the SSE codecs, no
|
||||
// extra trailing zero bytes are written, so it is not necessary to
|
||||
// reserve extra input bytes:
|
||||
size_t rounds = *slen / 64;
|
||||
|
||||
*slen -= rounds * 64; // 64 bytes consumed per round
|
||||
*olen += rounds * 48; // 48 bytes produced per round
|
||||
|
||||
const uint8x16x4_t tbl_dec1 = load_64byte_table(dec_lut1);
|
||||
const uint8x16x4_t tbl_dec2 = load_64byte_table(dec_lut2);
|
||||
|
||||
do {
|
||||
const uint8x16_t offset = vdupq_n_u8(63U);
|
||||
uint8x16x4_t dec1, dec2;
|
||||
uint8x16x3_t dec;
|
||||
|
||||
// Load 64 bytes and deinterleave:
|
||||
uint8x16x4_t str = vld4q_u8((uint8_t *) *s);
|
||||
|
||||
// Get indices for second LUT:
|
||||
dec2.val[0] = vqsubq_u8(str.val[0], offset);
|
||||
dec2.val[1] = vqsubq_u8(str.val[1], offset);
|
||||
dec2.val[2] = vqsubq_u8(str.val[2], offset);
|
||||
dec2.val[3] = vqsubq_u8(str.val[3], offset);
|
||||
|
||||
// Get values from first LUT:
|
||||
dec1.val[0] = vqtbl4q_u8(tbl_dec1, str.val[0]);
|
||||
dec1.val[1] = vqtbl4q_u8(tbl_dec1, str.val[1]);
|
||||
dec1.val[2] = vqtbl4q_u8(tbl_dec1, str.val[2]);
|
||||
dec1.val[3] = vqtbl4q_u8(tbl_dec1, str.val[3]);
|
||||
|
||||
// Get values from second LUT:
|
||||
dec2.val[0] = vqtbx4q_u8(dec2.val[0], tbl_dec2, dec2.val[0]);
|
||||
dec2.val[1] = vqtbx4q_u8(dec2.val[1], tbl_dec2, dec2.val[1]);
|
||||
dec2.val[2] = vqtbx4q_u8(dec2.val[2], tbl_dec2, dec2.val[2]);
|
||||
dec2.val[3] = vqtbx4q_u8(dec2.val[3], tbl_dec2, dec2.val[3]);
|
||||
|
||||
// Get final values:
|
||||
str.val[0] = vorrq_u8(dec1.val[0], dec2.val[0]);
|
||||
str.val[1] = vorrq_u8(dec1.val[1], dec2.val[1]);
|
||||
str.val[2] = vorrq_u8(dec1.val[2], dec2.val[2]);
|
||||
str.val[3] = vorrq_u8(dec1.val[3], dec2.val[3]);
|
||||
|
||||
// Check for invalid input, any value larger than 63:
|
||||
const uint8x16_t classified
|
||||
= vcgtq_u8(str.val[0], vdupq_n_u8(63))
|
||||
| vcgtq_u8(str.val[1], vdupq_n_u8(63))
|
||||
| vcgtq_u8(str.val[2], vdupq_n_u8(63))
|
||||
| vcgtq_u8(str.val[3], vdupq_n_u8(63));
|
||||
|
||||
// Check that all bits are zero:
|
||||
if (vmaxvq_u8(classified) != 0U) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Compress four bytes into three:
|
||||
dec.val[0] = vshlq_n_u8(str.val[0], 2) | vshrq_n_u8(str.val[1], 4);
|
||||
dec.val[1] = vshlq_n_u8(str.val[1], 4) | vshrq_n_u8(str.val[2], 2);
|
||||
dec.val[2] = vshlq_n_u8(str.val[2], 6) | str.val[3];
|
||||
|
||||
// Interleave and store decoded result:
|
||||
vst3q_u8((uint8_t *) *o, dec);
|
||||
|
||||
*s += 64;
|
||||
*o += 48;
|
||||
|
||||
} while (--rounds > 0);
|
||||
|
||||
// Adjust for any rounds that were skipped:
|
||||
*slen += rounds * 64;
|
||||
*olen -= rounds * 48;
|
||||
}
|
||||
66
3rdparty/base64/lib/arch/neon64/enc_loop.c
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
static inline void
|
||||
enc_loop_neon64_inner (const uint8_t **s, uint8_t **o, const uint8x16x4_t tbl_enc)
|
||||
{
|
||||
// Load 48 bytes and deinterleave:
|
||||
uint8x16x3_t src = vld3q_u8(*s);
|
||||
|
||||
// Divide bits of three input bytes over four output bytes:
|
||||
uint8x16x4_t out = enc_reshuffle(src);
|
||||
|
||||
// The bits have now been shifted to the right locations;
|
||||
// translate their values 0..63 to the Base64 alphabet.
|
||||
// Use a 64-byte table lookup:
|
||||
out.val[0] = vqtbl4q_u8(tbl_enc, out.val[0]);
|
||||
out.val[1] = vqtbl4q_u8(tbl_enc, out.val[1]);
|
||||
out.val[2] = vqtbl4q_u8(tbl_enc, out.val[2]);
|
||||
out.val[3] = vqtbl4q_u8(tbl_enc, out.val[3]);
|
||||
|
||||
// Interleave and store output:
|
||||
vst4q_u8(*o, out);
|
||||
|
||||
*s += 48;
|
||||
*o += 64;
|
||||
}
|
||||
|
||||
static inline void
|
||||
enc_loop_neon64 (const uint8_t **s, size_t *slen, uint8_t **o, size_t *olen)
|
||||
{
|
||||
size_t rounds = *slen / 48;
|
||||
|
||||
*slen -= rounds * 48; // 48 bytes consumed per round
|
||||
*olen += rounds * 64; // 64 bytes produced per round
|
||||
|
||||
// Load the encoding table:
|
||||
const uint8x16x4_t tbl_enc = load_64byte_table(base64_table_enc_6bit);
|
||||
|
||||
while (rounds > 0) {
|
||||
if (rounds >= 8) {
|
||||
enc_loop_neon64_inner(s, o, tbl_enc);
|
||||
enc_loop_neon64_inner(s, o, tbl_enc);
|
||||
enc_loop_neon64_inner(s, o, tbl_enc);
|
||||
enc_loop_neon64_inner(s, o, tbl_enc);
|
||||
enc_loop_neon64_inner(s, o, tbl_enc);
|
||||
enc_loop_neon64_inner(s, o, tbl_enc);
|
||||
enc_loop_neon64_inner(s, o, tbl_enc);
|
||||
enc_loop_neon64_inner(s, o, tbl_enc);
|
||||
rounds -= 8;
|
||||
continue;
|
||||
}
|
||||
if (rounds >= 4) {
|
||||
enc_loop_neon64_inner(s, o, tbl_enc);
|
||||
enc_loop_neon64_inner(s, o, tbl_enc);
|
||||
enc_loop_neon64_inner(s, o, tbl_enc);
|
||||
enc_loop_neon64_inner(s, o, tbl_enc);
|
||||
rounds -= 4;
|
||||
continue;
|
||||
}
|
||||
if (rounds >= 2) {
|
||||
enc_loop_neon64_inner(s, o, tbl_enc);
|
||||
enc_loop_neon64_inner(s, o, tbl_enc);
|
||||
rounds -= 2;
|
||||
continue;
|
||||
}
|
||||
enc_loop_neon64_inner(s, o, tbl_enc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
168
3rdparty/base64/lib/arch/neon64/enc_loop_asm.c
vendored
Normal file
@@ -0,0 +1,168 @@
|
||||
// Apologies in advance for combining the preprocessor with inline assembly,
|
||||
// two notoriously gnarly parts of C, but it was necessary to avoid a lot of
|
||||
// code repetition. The preprocessor is used to template large sections of
|
||||
// inline assembly that differ only in the registers used. If the code was
|
||||
// written out by hand, it would become very large and hard to audit.
|
||||
|
||||
// Generate a block of inline assembly that loads three user-defined registers
|
||||
// A, B, C from memory and deinterleaves them, post-incrementing the src
|
||||
// pointer. The register set should be sequential.
|
||||
#define LOAD(A, B, C) \
|
||||
"ld3 {"A".16b, "B".16b, "C".16b}, [%[src]], #48 \n\t"
|
||||
|
||||
// Generate a block of inline assembly that takes three deinterleaved registers
|
||||
// and shuffles the bytes. The output is in temporary registers t0..t3.
|
||||
#define SHUF(A, B, C) \
|
||||
"ushr %[t0].16b, "A".16b, #2 \n\t" \
|
||||
"ushr %[t1].16b, "B".16b, #4 \n\t" \
|
||||
"ushr %[t2].16b, "C".16b, #6 \n\t" \
|
||||
"sli %[t1].16b, "A".16b, #4 \n\t" \
|
||||
"sli %[t2].16b, "B".16b, #2 \n\t" \
|
||||
"and %[t1].16b, %[t1].16b, %[n63].16b \n\t" \
|
||||
"and %[t2].16b, %[t2].16b, %[n63].16b \n\t" \
|
||||
"and %[t3].16b, "C".16b, %[n63].16b \n\t"
|
||||
|
||||
// Generate a block of inline assembly that takes temporary registers t0..t3
|
||||
// and translates them to the base64 alphabet, using a table loaded into
|
||||
// v8..v11. The output is in user-defined registers A..D.
|
||||
#define TRAN(A, B, C, D) \
|
||||
"tbl "A".16b, {v8.16b-v11.16b}, %[t0].16b \n\t" \
|
||||
"tbl "B".16b, {v8.16b-v11.16b}, %[t1].16b \n\t" \
|
||||
"tbl "C".16b, {v8.16b-v11.16b}, %[t2].16b \n\t" \
|
||||
"tbl "D".16b, {v8.16b-v11.16b}, %[t3].16b \n\t"
|
||||
|
||||
// Generate a block of inline assembly that interleaves four registers and
|
||||
// stores them, post-incrementing the destination pointer.
|
||||
#define STOR(A, B, C, D) \
|
||||
"st4 {"A".16b, "B".16b, "C".16b, "D".16b}, [%[dst]], #64 \n\t"
|
||||
|
||||
// Generate a block of inline assembly that generates a single self-contained
|
||||
// encoder round: fetch the data, process it, and store the result.
|
||||
#define ROUND() \
|
||||
LOAD("v12", "v13", "v14") \
|
||||
SHUF("v12", "v13", "v14") \
|
||||
TRAN("v12", "v13", "v14", "v15") \
|
||||
STOR("v12", "v13", "v14", "v15")
|
||||
|
||||
// Generate a block of assembly that generates a type A interleaved encoder
|
||||
// round. It uses registers that were loaded by the previous type B round, and
|
||||
// in turn loads registers for the next type B round.
|
||||
#define ROUND_A() \
|
||||
SHUF("v2", "v3", "v4") \
|
||||
LOAD("v12", "v13", "v14") \
|
||||
TRAN("v2", "v3", "v4", "v5") \
|
||||
STOR("v2", "v3", "v4", "v5")
|
||||
|
||||
// Type B interleaved encoder round. Same as type A, but register sets swapped.
|
||||
#define ROUND_B() \
|
||||
SHUF("v12", "v13", "v14") \
|
||||
LOAD("v2", "v3", "v4") \
|
||||
TRAN("v12", "v13", "v14", "v15") \
|
||||
STOR("v12", "v13", "v14", "v15")
|
||||
|
||||
// The first type A round needs to load its own registers.
|
||||
#define ROUND_A_FIRST() \
|
||||
LOAD("v2", "v3", "v4") \
|
||||
ROUND_A()
|
||||
|
||||
// The last type B round omits the load for the next step.
|
||||
#define ROUND_B_LAST() \
|
||||
SHUF("v12", "v13", "v14") \
|
||||
TRAN("v12", "v13", "v14", "v15") \
|
||||
STOR("v12", "v13", "v14", "v15")
|
||||
|
||||
// Suppress clang's warning that the literal string in the asm statement is
|
||||
// overlong (longer than the ISO-mandated minimum size of 4095 bytes for C99
|
||||
// compilers). It may be true, but the goal here is not C99 portability.
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Woverlength-strings"
|
||||
|
||||
static inline void
|
||||
enc_loop_neon64 (const uint8_t **s, size_t *slen, uint8_t **o, size_t *olen)
|
||||
{
|
||||
size_t rounds = *slen / 48;
|
||||
|
||||
if (rounds == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
*slen -= rounds * 48; // 48 bytes consumed per round.
|
||||
*olen += rounds * 64; // 64 bytes produced per round.
|
||||
|
||||
// Number of times to go through the 8x loop.
|
||||
size_t loops = rounds / 8;
|
||||
|
||||
// Number of rounds remaining after the 8x loop.
|
||||
rounds %= 8;
|
||||
|
||||
// Temporary registers, used as scratch space.
|
||||
uint8x16_t tmp0, tmp1, tmp2, tmp3;
|
||||
|
||||
__asm__ volatile (
|
||||
|
||||
// Load the encoding table into v8..v11.
|
||||
" ld1 {v8.16b-v11.16b}, [%[tbl]] \n\t"
|
||||
|
||||
// If there are eight rounds or more, enter an 8x unrolled loop
|
||||
// of interleaved encoding rounds. The rounds interleave memory
|
||||
// operations (load/store) with data operations to maximize
|
||||
// pipeline throughput.
|
||||
" cbz %[loops], 4f \n\t"
|
||||
|
||||
// The SIMD instructions do not touch the flags.
|
||||
"88: subs %[loops], %[loops], #1 \n\t"
|
||||
" " ROUND_A_FIRST()
|
||||
" " ROUND_B()
|
||||
" " ROUND_A()
|
||||
" " ROUND_B()
|
||||
" " ROUND_A()
|
||||
" " ROUND_B()
|
||||
" " ROUND_A()
|
||||
" " ROUND_B_LAST()
|
||||
" b.ne 88b \n\t"
|
||||
|
||||
// Enter a 4x unrolled loop for rounds of 4 or more.
|
||||
"4: cmp %[rounds], #4 \n\t"
|
||||
" b.lt 30f \n\t"
|
||||
" " ROUND_A_FIRST()
|
||||
" " ROUND_B()
|
||||
" " ROUND_A()
|
||||
" " ROUND_B_LAST()
|
||||
" sub %[rounds], %[rounds], #4 \n\t"
|
||||
|
||||
// Dispatch the remaining rounds 0..3.
|
||||
"30: cbz %[rounds], 0f \n\t"
|
||||
" cmp %[rounds], #2 \n\t"
|
||||
" b.eq 2f \n\t"
|
||||
" b.lt 1f \n\t"
|
||||
|
||||
// Block of non-interlaced encoding rounds, which can each
|
||||
// individually be jumped to. Rounds fall through to the next.
|
||||
"3: " ROUND()
|
||||
"2: " ROUND()
|
||||
"1: " ROUND()
|
||||
"0: \n\t"
|
||||
|
||||
// Outputs (modified).
|
||||
: [loops] "+r" (loops),
|
||||
[src] "+r" (*s),
|
||||
[dst] "+r" (*o),
|
||||
[t0] "=&w" (tmp0),
|
||||
[t1] "=&w" (tmp1),
|
||||
[t2] "=&w" (tmp2),
|
||||
[t3] "=&w" (tmp3)
|
||||
|
||||
// Inputs (not modified).
|
||||
: [rounds] "r" (rounds),
|
||||
[tbl] "r" (base64_table_enc_6bit),
|
||||
[n63] "w" (vdupq_n_u8(63))
|
||||
|
||||
// Clobbers.
|
||||
: "v2", "v3", "v4", "v5",
|
||||
"v8", "v9", "v10", "v11",
|
||||
"v12", "v13", "v14", "v15",
|
||||
"cc", "memory"
|
||||
);
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
31
3rdparty/base64/lib/arch/neon64/enc_reshuffle.c
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
static inline uint8x16x4_t
|
||||
enc_reshuffle (const uint8x16x3_t in)
|
||||
{
|
||||
uint8x16x4_t out;
|
||||
|
||||
// Input:
|
||||
// in[0] = a7 a6 a5 a4 a3 a2 a1 a0
|
||||
// in[1] = b7 b6 b5 b4 b3 b2 b1 b0
|
||||
// in[2] = c7 c6 c5 c4 c3 c2 c1 c0
|
||||
|
||||
// Output:
|
||||
// out[0] = 00 00 a7 a6 a5 a4 a3 a2
|
||||
// out[1] = 00 00 a1 a0 b7 b6 b5 b4
|
||||
// out[2] = 00 00 b3 b2 b1 b0 c7 c6
|
||||
// out[3] = 00 00 c5 c4 c3 c2 c1 c0
|
||||
|
||||
// Move the input bits to where they need to be in the outputs. Except
|
||||
// for the first output, the high two bits are not cleared.
|
||||
out.val[0] = vshrq_n_u8(in.val[0], 2);
|
||||
out.val[1] = vshrq_n_u8(in.val[1], 4);
|
||||
out.val[2] = vshrq_n_u8(in.val[2], 6);
|
||||
out.val[1] = vsliq_n_u8(out.val[1], in.val[0], 4);
|
||||
out.val[2] = vsliq_n_u8(out.val[2], in.val[1], 2);
|
||||
|
||||
// Clear the high two bits in the second, third and fourth output.
|
||||
out.val[1] = vandq_u8(out.val[1], vdupq_n_u8(0x3F));
|
||||
out.val[2] = vandq_u8(out.val[2], vdupq_n_u8(0x3F));
|
||||
out.val[3] = vandq_u8(in.val[2], vdupq_n_u8(0x3F));
|
||||
|
||||
return out;
|
||||
}
|
||||
56
3rdparty/base64/lib/arch/sse41/codec.c
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../../../include/libbase64.h"
|
||||
#include "../../tables/tables.h"
|
||||
#include "../../codecs.h"
|
||||
#include "config.h"
|
||||
#include "../../env.h"
|
||||
|
||||
#if HAVE_SSE41
|
||||
#include <smmintrin.h>
|
||||
|
||||
// Only enable inline assembly on supported compilers and on 64-bit CPUs.
|
||||
#ifndef BASE64_SSE41_USE_ASM
|
||||
# if (defined(__GNUC__) || defined(__clang__)) && BASE64_WORDSIZE == 64
|
||||
# define BASE64_SSE41_USE_ASM 1
|
||||
# else
|
||||
# define BASE64_SSE41_USE_ASM 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "../ssse3/dec_reshuffle.c"
|
||||
#include "../ssse3/dec_loop.c"
|
||||
|
||||
#if BASE64_SSE41_USE_ASM
|
||||
# include "../ssse3/enc_loop_asm.c"
|
||||
#else
|
||||
# include "../ssse3/enc_translate.c"
|
||||
# include "../ssse3/enc_reshuffle.c"
|
||||
# include "../ssse3/enc_loop.c"
|
||||
#endif
|
||||
|
||||
#endif // HAVE_SSE41
|
||||
|
||||
BASE64_ENC_FUNCTION(sse41)
|
||||
{
|
||||
#if HAVE_SSE41
|
||||
#include "../generic/enc_head.c"
|
||||
enc_loop_ssse3(&s, &slen, &o, &olen);
|
||||
#include "../generic/enc_tail.c"
|
||||
#else
|
||||
BASE64_ENC_STUB
|
||||
#endif
|
||||
}
|
||||
|
||||
BASE64_DEC_FUNCTION(sse41)
|
||||
{
|
||||
#if HAVE_SSE41
|
||||
#include "../generic/dec_head.c"
|
||||
dec_loop_ssse3(&s, &slen, &o, &olen);
|
||||
#include "../generic/dec_tail.c"
|
||||
#else
|
||||
BASE64_DEC_STUB
|
||||
#endif
|
||||
}
|
||||
56
3rdparty/base64/lib/arch/sse42/codec.c
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../../../include/libbase64.h"
|
||||
#include "../../tables/tables.h"
|
||||
#include "../../codecs.h"
|
||||
#include "config.h"
|
||||
#include "../../env.h"
|
||||
|
||||
#if HAVE_SSE42
|
||||
#include <nmmintrin.h>
|
||||
|
||||
// Only enable inline assembly on supported compilers and on 64-bit CPUs.
|
||||
#ifndef BASE64_SSE42_USE_ASM
|
||||
# if (defined(__GNUC__) || defined(__clang__)) && BASE64_WORDSIZE == 64
|
||||
# define BASE64_SSE42_USE_ASM 1
|
||||
# else
|
||||
# define BASE64_SSE42_USE_ASM 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "../ssse3/dec_reshuffle.c"
|
||||
#include "../ssse3/dec_loop.c"
|
||||
|
||||
#if BASE64_SSE42_USE_ASM
|
||||
# include "../ssse3/enc_loop_asm.c"
|
||||
#else
|
||||
# include "../ssse3/enc_translate.c"
|
||||
# include "../ssse3/enc_reshuffle.c"
|
||||
# include "../ssse3/enc_loop.c"
|
||||
#endif
|
||||
|
||||
#endif // HAVE_SSE42
|
||||
|
||||
BASE64_ENC_FUNCTION(sse42)
|
||||
{
|
||||
#if HAVE_SSE42
|
||||
#include "../generic/enc_head.c"
|
||||
enc_loop_ssse3(&s, &slen, &o, &olen);
|
||||
#include "../generic/enc_tail.c"
|
||||
#else
|
||||
BASE64_ENC_STUB
|
||||
#endif
|
||||
}
|
||||
|
||||
BASE64_DEC_FUNCTION(sse42)
|
||||
{
|
||||
#if HAVE_SSE42
|
||||
#include "../generic/dec_head.c"
|
||||
dec_loop_ssse3(&s, &slen, &o, &olen);
|
||||
#include "../generic/dec_tail.c"
|
||||
#else
|
||||
BASE64_DEC_STUB
|
||||
#endif
|
||||
}
|
||||
58
3rdparty/base64/lib/arch/ssse3/codec.c
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../../../include/libbase64.h"
|
||||
#include "../../tables/tables.h"
|
||||
#include "../../codecs.h"
|
||||
#include "config.h"
|
||||
#include "../../env.h"
|
||||
|
||||
#if HAVE_SSSE3
|
||||
#include <tmmintrin.h>
|
||||
|
||||
// Only enable inline assembly on supported compilers and on 64-bit CPUs.
|
||||
// 32-bit CPUs with SSSE3 support, such as low-end Atoms, only have eight XMM
|
||||
// registers, which is not enough to run the inline assembly.
|
||||
#ifndef BASE64_SSSE3_USE_ASM
|
||||
# if (defined(__GNUC__) || defined(__clang__)) && BASE64_WORDSIZE == 64
|
||||
# define BASE64_SSSE3_USE_ASM 1
|
||||
# else
|
||||
# define BASE64_SSSE3_USE_ASM 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "dec_reshuffle.c"
|
||||
#include "dec_loop.c"
|
||||
|
||||
#if BASE64_SSSE3_USE_ASM
|
||||
# include "enc_loop_asm.c"
|
||||
#else
|
||||
# include "enc_reshuffle.c"
|
||||
# include "enc_translate.c"
|
||||
# include "enc_loop.c"
|
||||
#endif
|
||||
|
||||
#endif // HAVE_SSSE3
|
||||
|
||||
BASE64_ENC_FUNCTION(ssse3)
|
||||
{
|
||||
#if HAVE_SSSE3
|
||||
#include "../generic/enc_head.c"
|
||||
enc_loop_ssse3(&s, &slen, &o, &olen);
|
||||
#include "../generic/enc_tail.c"
|
||||
#else
|
||||
BASE64_ENC_STUB
|
||||
#endif
|
||||
}
|
||||
|
||||
BASE64_DEC_FUNCTION(ssse3)
|
||||
{
|
||||
#if HAVE_SSSE3
|
||||
#include "../generic/dec_head.c"
|
||||
dec_loop_ssse3(&s, &slen, &o, &olen);
|
||||
#include "../generic/dec_tail.c"
|
||||
#else
|
||||
BASE64_DEC_STUB
|
||||
#endif
|
||||
}
|
||||
173
3rdparty/base64/lib/arch/ssse3/dec_loop.c
vendored
Normal file
@@ -0,0 +1,173 @@
|
||||
// The input consists of six character sets in the Base64 alphabet, which we
|
||||
// need to map back to the 6-bit values they represent. There are three ranges,
|
||||
// two singles, and then there's the rest.
|
||||
//
|
||||
// # From To Add Characters
|
||||
// 1 [43] [62] +19 +
|
||||
// 2 [47] [63] +16 /
|
||||
// 3 [48..57] [52..61] +4 0..9
|
||||
// 4 [65..90] [0..25] -65 A..Z
|
||||
// 5 [97..122] [26..51] -71 a..z
|
||||
// (6) Everything else => invalid input
|
||||
//
|
||||
// We will use lookup tables for character validation and offset computation.
|
||||
// Remember that 0x2X and 0x0X are the same index for _mm_shuffle_epi8, this
|
||||
// allows to mask with 0x2F instead of 0x0F and thus save one constant
|
||||
// declaration (register and/or memory access).
|
||||
//
|
||||
// For offsets:
|
||||
// Perfect hash for lut = ((src >> 4) & 0x2F) + ((src == 0x2F) ? 0xFF : 0x00)
|
||||
// 0000 = garbage
|
||||
// 0001 = /
|
||||
// 0010 = +
|
||||
// 0011 = 0-9
|
||||
// 0100 = A-Z
|
||||
// 0101 = A-Z
|
||||
// 0110 = a-z
|
||||
// 0111 = a-z
|
||||
// 1000 >= garbage
|
||||
//
|
||||
// For validation, here's the table.
|
||||
// A character is valid if and only if the AND of the 2 lookups equals 0:
|
||||
//
|
||||
// hi \ lo 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111
|
||||
// LUT 0x15 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x13 0x1A 0x1B 0x1B 0x1B 0x1A
|
||||
//
|
||||
// 0000 0x10 char NUL SOH STX ETX EOT ENQ ACK BEL BS HT LF VT FF CR SO SI
|
||||
// andlut 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10
|
||||
//
|
||||
// 0001 0x10 char DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC FS GS RS US
|
||||
// andlut 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10
|
||||
//
|
||||
// 0010 0x01 char ! " # $ % & ' ( ) * + , - . /
|
||||
// andlut 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x00 0x01 0x01 0x01 0x00
|
||||
//
|
||||
// 0011 0x02 char 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
|
||||
// andlut 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x02 0x02 0x02 0x02 0x02 0x02
|
||||
//
|
||||
// 0100 0x04 char @ A B C D E F G H I J K L M N O
|
||||
// andlut 0x04 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
|
||||
//
|
||||
// 0101 0x08 char P Q R S T U V W X Y Z [ \ ] ^ _
|
||||
// andlut 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x08 0x08 0x08 0x08 0x08
|
||||
//
|
||||
// 0110 0x04 char ` a b c d e f g h i j k l m n o
|
||||
// andlut 0x04 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
|
||||
// 0111 0x08 char p q r s t u v w x y z { | } ~
|
||||
// andlut 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x08 0x08 0x08 0x08 0x08
|
||||
//
|
||||
// 1000 0x10 andlut 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10
|
||||
// 1001 0x10 andlut 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10
|
||||
// 1010 0x10 andlut 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10
|
||||
// 1011 0x10 andlut 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10
|
||||
// 1100 0x10 andlut 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10
|
||||
// 1101 0x10 andlut 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10
|
||||
// 1110 0x10 andlut 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10
|
||||
// 1111 0x10 andlut 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10
|
||||
|
||||
static inline int
|
||||
dec_loop_ssse3_inner (const uint8_t **s, uint8_t **o, size_t *rounds)
|
||||
{
|
||||
const __m128i lut_lo = _mm_setr_epi8(
|
||||
0x15, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
|
||||
0x11, 0x11, 0x13, 0x1A, 0x1B, 0x1B, 0x1B, 0x1A);
|
||||
|
||||
const __m128i lut_hi = _mm_setr_epi8(
|
||||
0x10, 0x10, 0x01, 0x02, 0x04, 0x08, 0x04, 0x08,
|
||||
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10);
|
||||
|
||||
const __m128i lut_roll = _mm_setr_epi8(
|
||||
0, 16, 19, 4, -65, -65, -71, -71,
|
||||
0, 0, 0, 0, 0, 0, 0, 0);
|
||||
|
||||
const __m128i mask_2F = _mm_set1_epi8(0x2F);
|
||||
|
||||
// Load input:
|
||||
__m128i str = _mm_loadu_si128((__m128i *) *s);
|
||||
|
||||
// Table lookups:
|
||||
const __m128i hi_nibbles = _mm_and_si128(_mm_srli_epi32(str, 4), mask_2F);
|
||||
const __m128i lo_nibbles = _mm_and_si128(str, mask_2F);
|
||||
const __m128i hi = _mm_shuffle_epi8(lut_hi, hi_nibbles);
|
||||
const __m128i lo = _mm_shuffle_epi8(lut_lo, lo_nibbles);
|
||||
|
||||
// Check for invalid input: if any "and" values from lo and hi are not
|
||||
// zero, fall back on bytewise code to do error checking and reporting:
|
||||
if (_mm_movemask_epi8(_mm_cmpgt_epi8(_mm_and_si128(lo, hi), _mm_setzero_si128())) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const __m128i eq_2F = _mm_cmpeq_epi8(str, mask_2F);
|
||||
const __m128i roll = _mm_shuffle_epi8(lut_roll, _mm_add_epi8(eq_2F, hi_nibbles));
|
||||
|
||||
// Now simply add the delta values to the input:
|
||||
str = _mm_add_epi8(str, roll);
|
||||
|
||||
// Reshuffle the input to packed 12-byte output format:
|
||||
str = dec_reshuffle(str);
|
||||
|
||||
// Store the output:
|
||||
_mm_storeu_si128((__m128i *) *o, str);
|
||||
|
||||
*s += 16;
|
||||
*o += 12;
|
||||
*rounds -= 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline void
|
||||
dec_loop_ssse3 (const uint8_t **s, size_t *slen, uint8_t **o, size_t *olen)
|
||||
{
|
||||
if (*slen < 24) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Process blocks of 16 bytes per round. Because 4 extra zero bytes are
|
||||
// written after the output, ensure that there will be at least 8 bytes
|
||||
// of input data left to cover the gap. (6 data bytes and up to two
|
||||
// end-of-string markers.)
|
||||
size_t rounds = (*slen - 8) / 16;
|
||||
|
||||
*slen -= rounds * 16; // 16 bytes consumed per round
|
||||
*olen += rounds * 12; // 12 bytes produced per round
|
||||
|
||||
do {
|
||||
if (rounds >= 8) {
|
||||
if (dec_loop_ssse3_inner(s, o, &rounds) &&
|
||||
dec_loop_ssse3_inner(s, o, &rounds) &&
|
||||
dec_loop_ssse3_inner(s, o, &rounds) &&
|
||||
dec_loop_ssse3_inner(s, o, &rounds) &&
|
||||
dec_loop_ssse3_inner(s, o, &rounds) &&
|
||||
dec_loop_ssse3_inner(s, o, &rounds) &&
|
||||
dec_loop_ssse3_inner(s, o, &rounds) &&
|
||||
dec_loop_ssse3_inner(s, o, &rounds)) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (rounds >= 4) {
|
||||
if (dec_loop_ssse3_inner(s, o, &rounds) &&
|
||||
dec_loop_ssse3_inner(s, o, &rounds) &&
|
||||
dec_loop_ssse3_inner(s, o, &rounds) &&
|
||||
dec_loop_ssse3_inner(s, o, &rounds)) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (rounds >= 2) {
|
||||
if (dec_loop_ssse3_inner(s, o, &rounds) &&
|
||||
dec_loop_ssse3_inner(s, o, &rounds)) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
dec_loop_ssse3_inner(s, o, &rounds);
|
||||
break;
|
||||
|
||||
} while (rounds > 0);
|
||||
|
||||
// Adjust for any rounds that were skipped:
|
||||
*slen += rounds * 16;
|
||||
*olen -= rounds * 12;
|
||||
}
|
||||
33
3rdparty/base64/lib/arch/ssse3/dec_reshuffle.c
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
static inline __m128i
|
||||
dec_reshuffle (const __m128i in)
|
||||
{
|
||||
// in, bits, upper case are most significant bits, lower case are least significant bits
|
||||
// 00llllll 00kkkkLL 00jjKKKK 00JJJJJJ
|
||||
// 00iiiiii 00hhhhII 00ggHHHH 00GGGGGG
|
||||
// 00ffffff 00eeeeFF 00ddEEEE 00DDDDDD
|
||||
// 00cccccc 00bbbbCC 00aaBBBB 00AAAAAA
|
||||
|
||||
const __m128i merge_ab_and_bc = _mm_maddubs_epi16(in, _mm_set1_epi32(0x01400140));
|
||||
// 0000kkkk LLllllll 0000JJJJ JJjjKKKK
|
||||
// 0000hhhh IIiiiiii 0000GGGG GGggHHHH
|
||||
// 0000eeee FFffffff 0000DDDD DDddEEEE
|
||||
// 0000bbbb CCcccccc 0000AAAA AAaaBBBB
|
||||
|
||||
const __m128i out = _mm_madd_epi16(merge_ab_and_bc, _mm_set1_epi32(0x00011000));
|
||||
// 00000000 JJJJJJjj KKKKkkkk LLllllll
|
||||
// 00000000 GGGGGGgg HHHHhhhh IIiiiiii
|
||||
// 00000000 DDDDDDdd EEEEeeee FFffffff
|
||||
// 00000000 AAAAAAaa BBBBbbbb CCcccccc
|
||||
|
||||
// Pack bytes together:
|
||||
return _mm_shuffle_epi8(out, _mm_setr_epi8(
|
||||
2, 1, 0,
|
||||
6, 5, 4,
|
||||
10, 9, 8,
|
||||
14, 13, 12,
|
||||
-1, -1, -1, -1));
|
||||
// 00000000 00000000 00000000 00000000
|
||||
// LLllllll KKKKkkkk JJJJJJjj IIiiiiii
|
||||
// HHHHhhhh GGGGGGgg FFffffff EEEEeeee
|
||||
// DDDDDDdd CCcccccc BBBBbbbb AAAAAAaa
|
||||
}
|
||||
67
3rdparty/base64/lib/arch/ssse3/enc_loop.c
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
static inline void
|
||||
enc_loop_ssse3_inner (const uint8_t **s, uint8_t **o)
|
||||
{
|
||||
// Load input:
|
||||
__m128i str = _mm_loadu_si128((__m128i *) *s);
|
||||
|
||||
// Reshuffle:
|
||||
str = enc_reshuffle(str);
|
||||
|
||||
// Translate reshuffled bytes to the Base64 alphabet:
|
||||
str = enc_translate(str);
|
||||
|
||||
// Store:
|
||||
_mm_storeu_si128((__m128i *) *o, str);
|
||||
|
||||
*s += 12;
|
||||
*o += 16;
|
||||
}
|
||||
|
||||
static inline void
|
||||
enc_loop_ssse3 (const uint8_t **s, size_t *slen, uint8_t **o, size_t *olen)
|
||||
{
|
||||
if (*slen < 16) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Process blocks of 12 bytes at a time. Because blocks are loaded 16
|
||||
// bytes at a time, ensure that there will be at least 4 remaining
|
||||
// bytes after the last round, so that the final read will not pass
|
||||
// beyond the bounds of the input buffer:
|
||||
size_t rounds = (*slen - 4) / 12;
|
||||
|
||||
*slen -= rounds * 12; // 12 bytes consumed per round
|
||||
*olen += rounds * 16; // 16 bytes produced per round
|
||||
|
||||
do {
|
||||
if (rounds >= 8) {
|
||||
enc_loop_ssse3_inner(s, o);
|
||||
enc_loop_ssse3_inner(s, o);
|
||||
enc_loop_ssse3_inner(s, o);
|
||||
enc_loop_ssse3_inner(s, o);
|
||||
enc_loop_ssse3_inner(s, o);
|
||||
enc_loop_ssse3_inner(s, o);
|
||||
enc_loop_ssse3_inner(s, o);
|
||||
enc_loop_ssse3_inner(s, o);
|
||||
rounds -= 8;
|
||||
continue;
|
||||
}
|
||||
if (rounds >= 4) {
|
||||
enc_loop_ssse3_inner(s, o);
|
||||
enc_loop_ssse3_inner(s, o);
|
||||
enc_loop_ssse3_inner(s, o);
|
||||
enc_loop_ssse3_inner(s, o);
|
||||
rounds -= 4;
|
||||
continue;
|
||||
}
|
||||
if (rounds >= 2) {
|
||||
enc_loop_ssse3_inner(s, o);
|
||||
enc_loop_ssse3_inner(s, o);
|
||||
rounds -= 2;
|
||||
continue;
|
||||
}
|
||||
enc_loop_ssse3_inner(s, o);
|
||||
break;
|
||||
|
||||
} while (rounds > 0);
|
||||
}
|
||||
268
3rdparty/base64/lib/arch/ssse3/enc_loop_asm.c
vendored
Normal file
@@ -0,0 +1,268 @@
|
||||
// Apologies in advance for combining the preprocessor with inline assembly,
|
||||
// two notoriously gnarly parts of C, but it was necessary to avoid a lot of
|
||||
// code repetition. The preprocessor is used to template large sections of
|
||||
// inline assembly that differ only in the registers used. If the code was
|
||||
// written out by hand, it would become very large and hard to audit.
|
||||
|
||||
// Generate a block of inline assembly that loads register R0 from memory. The
|
||||
// offset at which the register is loaded is set by the given round.
|
||||
#define LOAD(R0, ROUND) \
|
||||
"lddqu ("#ROUND" * 12)(%[src]), %["R0"] \n\t"
|
||||
|
||||
// Generate a block of inline assembly that deinterleaves and shuffles register
|
||||
// R0 using preloaded constants. Outputs in R0 and R1.
|
||||
#define SHUF(R0, R1) \
|
||||
"pshufb %[lut0], %["R0"] \n\t" \
|
||||
"movdqa %["R0"], %["R1"] \n\t" \
|
||||
"pand %[msk0], %["R0"] \n\t" \
|
||||
"pand %[msk2], %["R1"] \n\t" \
|
||||
"pmulhuw %[msk1], %["R0"] \n\t" \
|
||||
"pmullw %[msk3], %["R1"] \n\t" \
|
||||
"por %["R1"], %["R0"] \n\t"
|
||||
|
||||
// Generate a block of inline assembly that takes R0 and R1 and translates
|
||||
// their contents to the base64 alphabet, using preloaded constants.
|
||||
#define TRAN(R0, R1, R2) \
|
||||
"movdqa %["R0"], %["R1"] \n\t" \
|
||||
"movdqa %["R0"], %["R2"] \n\t" \
|
||||
"psubusb %[n51], %["R1"] \n\t" \
|
||||
"pcmpgtb %[n25], %["R2"] \n\t" \
|
||||
"psubb %["R2"], %["R1"] \n\t" \
|
||||
"movdqa %[lut1], %["R2"] \n\t" \
|
||||
"pshufb %["R1"], %["R2"] \n\t" \
|
||||
"paddb %["R2"], %["R0"] \n\t"
|
||||
|
||||
// Generate a block of inline assembly that stores the given register R0 at an
|
||||
// offset set by the given round.
|
||||
#define STOR(R0, ROUND) \
|
||||
"movdqu %["R0"], ("#ROUND" * 16)(%[dst]) \n\t"
|
||||
|
||||
// Generate a block of inline assembly that generates a single self-contained
|
||||
// encoder round: fetch the data, process it, and store the result. Then update
|
||||
// the source and destination pointers.
|
||||
#define ROUND() \
|
||||
LOAD("a", 0) \
|
||||
SHUF("a", "b") \
|
||||
TRAN("a", "b", "c") \
|
||||
STOR("a", 0) \
|
||||
"add $12, %[src] \n\t" \
|
||||
"add $16, %[dst] \n\t"
|
||||
|
||||
// Define a macro that initiates a three-way interleaved encoding round by
|
||||
// preloading registers a, b and c from memory.
|
||||
// The register graph shows which registers are in use during each step, and
|
||||
// is a visual aid for choosing registers for that step. Symbol index:
|
||||
//
|
||||
// + indicates that a register is loaded by that step.
|
||||
// | indicates that a register is in use and must not be touched.
|
||||
// - indicates that a register is decommissioned by that step.
|
||||
// x indicates that a register is used as a temporary by that step.
|
||||
// V indicates that a register is an input or output to the macro.
|
||||
//
|
||||
#define ROUND_3_INIT() /* a b c d e f */ \
|
||||
LOAD("a", 0) /* + */ \
|
||||
SHUF("a", "d") /* | + */ \
|
||||
LOAD("b", 1) /* | + | */ \
|
||||
TRAN("a", "d", "e") /* | | - x */ \
|
||||
LOAD("c", 2) /* V V V */
|
||||
|
||||
// Define a macro that translates, shuffles and stores the input registers A, B
|
||||
// and C, and preloads registers D, E and F for the next round.
|
||||
// This macro can be arbitrarily daisy-chained by feeding output registers D, E
|
||||
// and F back into the next round as input registers A, B and C. The macro
|
||||
// carefully interleaves memory operations with data operations for optimal
|
||||
// pipelined performance.
|
||||
|
||||
#define ROUND_3(ROUND, A,B,C,D,E,F) /* A B C D E F */ \
|
||||
LOAD(D, (ROUND + 3)) /* V V V + */ \
|
||||
SHUF(B, E) /* | | | | + */ \
|
||||
STOR(A, (ROUND + 0)) /* - | | | | */ \
|
||||
TRAN(B, E, F) /* | | | - x */ \
|
||||
LOAD(E, (ROUND + 4)) /* | | | + */ \
|
||||
SHUF(C, A) /* + | | | | */ \
|
||||
STOR(B, (ROUND + 1)) /* | - | | | */ \
|
||||
TRAN(C, A, F) /* - | | | x */ \
|
||||
LOAD(F, (ROUND + 5)) /* | | | + */ \
|
||||
SHUF(D, A) /* + | | | | */ \
|
||||
STOR(C, (ROUND + 2)) /* | - | | | */ \
|
||||
TRAN(D, A, B) /* - x V V V */
|
||||
|
||||
// Define a macro that terminates a ROUND_3 macro by taking pre-loaded
|
||||
// registers D, E and F, and translating, shuffling and storing them.
|
||||
#define ROUND_3_END(ROUND, A,B,C,D,E,F) /* A B C D E F */ \
|
||||
SHUF(E, A) /* + V V V */ \
|
||||
STOR(D, (ROUND + 3)) /* | - | | */ \
|
||||
TRAN(E, A, B) /* - x | | */ \
|
||||
SHUF(F, C) /* + | | */ \
|
||||
STOR(E, (ROUND + 4)) /* | - | */ \
|
||||
TRAN(F, C, D) /* - x | */ \
|
||||
STOR(F, (ROUND + 5)) /* - */
|
||||
|
||||
// Define a type A round. Inputs are a, b, and c, outputs are d, e, and f.
|
||||
#define ROUND_3_A(ROUND) \
|
||||
ROUND_3(ROUND, "a", "b", "c", "d", "e", "f")
|
||||
|
||||
// Define a type B round. Inputs and outputs are swapped with regard to type A.
|
||||
#define ROUND_3_B(ROUND) \
|
||||
ROUND_3(ROUND, "d", "e", "f", "a", "b", "c")
|
||||
|
||||
// Terminating macro for a type A round.
|
||||
#define ROUND_3_A_LAST(ROUND) \
|
||||
ROUND_3_A(ROUND) \
|
||||
ROUND_3_END(ROUND, "a", "b", "c", "d", "e", "f")
|
||||
|
||||
// Terminating macro for a type B round.
|
||||
#define ROUND_3_B_LAST(ROUND) \
|
||||
ROUND_3_B(ROUND) \
|
||||
ROUND_3_END(ROUND, "d", "e", "f", "a", "b", "c")
|
||||
|
||||
// Suppress clang's warning that the literal string in the asm statement is
|
||||
// overlong (longer than the ISO-mandated minimum size of 4095 bytes for C99
|
||||
// compilers). It may be true, but the goal here is not C99 portability.
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Woverlength-strings"
|
||||
|
||||
static inline void
|
||||
enc_loop_ssse3 (const uint8_t **s, size_t *slen, uint8_t **o, size_t *olen)
|
||||
{
|
||||
// For a clearer explanation of the algorithm used by this function,
|
||||
// please refer to the plain (not inline assembly) implementation. This
|
||||
// function follows the same basic logic.
|
||||
|
||||
if (*slen < 16) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Process blocks of 12 bytes at a time. Input is read in blocks of 16
|
||||
// bytes, so "reserve" four bytes from the input buffer to ensure that
|
||||
// we never read beyond the end of the input buffer.
|
||||
size_t rounds = (*slen - 4) / 12;
|
||||
|
||||
*slen -= rounds * 12; // 12 bytes consumed per round
|
||||
*olen += rounds * 16; // 16 bytes produced per round
|
||||
|
||||
// Number of times to go through the 36x loop.
|
||||
size_t loops = rounds / 36;
|
||||
|
||||
// Number of rounds remaining after the 36x loop.
|
||||
rounds %= 36;
|
||||
|
||||
// Lookup tables.
|
||||
const __m128i lut0 = _mm_set_epi8(
|
||||
10, 11, 9, 10, 7, 8, 6, 7, 4, 5, 3, 4, 1, 2, 0, 1);
|
||||
|
||||
const __m128i lut1 = _mm_setr_epi8(
|
||||
65, 71, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -19, -16, 0, 0);
|
||||
|
||||
// Temporary registers.
|
||||
__m128i a, b, c, d, e, f;
|
||||
|
||||
__asm__ volatile (
|
||||
|
||||
// If there are 36 rounds or more, enter a 36x unrolled loop of
|
||||
// interleaved encoding rounds. The rounds interleave memory
|
||||
// operations (load/store) with data operations (table lookups,
|
||||
// etc) to maximize pipeline throughput.
|
||||
" test %[loops], %[loops] \n\t"
|
||||
" jz 18f \n\t"
|
||||
" jmp 36f \n\t"
|
||||
" \n\t"
|
||||
".balign 64 \n\t"
|
||||
"36: " ROUND_3_INIT()
|
||||
" " ROUND_3_A( 0)
|
||||
" " ROUND_3_B( 3)
|
||||
" " ROUND_3_A( 6)
|
||||
" " ROUND_3_B( 9)
|
||||
" " ROUND_3_A(12)
|
||||
" " ROUND_3_B(15)
|
||||
" " ROUND_3_A(18)
|
||||
" " ROUND_3_B(21)
|
||||
" " ROUND_3_A(24)
|
||||
" " ROUND_3_B(27)
|
||||
" " ROUND_3_A_LAST(30)
|
||||
" add $(12 * 36), %[src] \n\t"
|
||||
" add $(16 * 36), %[dst] \n\t"
|
||||
" dec %[loops] \n\t"
|
||||
" jnz 36b \n\t"
|
||||
|
||||
// Enter an 18x unrolled loop for rounds of 18 or more.
|
||||
"18: cmp $18, %[rounds] \n\t"
|
||||
" jl 9f \n\t"
|
||||
" " ROUND_3_INIT()
|
||||
" " ROUND_3_A(0)
|
||||
" " ROUND_3_B(3)
|
||||
" " ROUND_3_A(6)
|
||||
" " ROUND_3_B(9)
|
||||
" " ROUND_3_A_LAST(12)
|
||||
" sub $18, %[rounds] \n\t"
|
||||
" add $(12 * 18), %[src] \n\t"
|
||||
" add $(16 * 18), %[dst] \n\t"
|
||||
|
||||
// Enter a 9x unrolled loop for rounds of 9 or more.
|
||||
"9: cmp $9, %[rounds] \n\t"
|
||||
" jl 6f \n\t"
|
||||
" " ROUND_3_INIT()
|
||||
" " ROUND_3_A(0)
|
||||
" " ROUND_3_B_LAST(3)
|
||||
" sub $9, %[rounds] \n\t"
|
||||
" add $(12 * 9), %[src] \n\t"
|
||||
" add $(16 * 9), %[dst] \n\t"
|
||||
|
||||
// Enter a 6x unrolled loop for rounds of 6 or more.
|
||||
"6: cmp $6, %[rounds] \n\t"
|
||||
" jl 55f \n\t"
|
||||
" " ROUND_3_INIT()
|
||||
" " ROUND_3_A_LAST(0)
|
||||
" sub $6, %[rounds] \n\t"
|
||||
" add $(12 * 6), %[src] \n\t"
|
||||
" add $(16 * 6), %[dst] \n\t"
|
||||
|
||||
// Dispatch the remaining rounds 0..5.
|
||||
"55: cmp $3, %[rounds] \n\t"
|
||||
" jg 45f \n\t"
|
||||
" je 3f \n\t"
|
||||
" cmp $1, %[rounds] \n\t"
|
||||
" jg 2f \n\t"
|
||||
" je 1f \n\t"
|
||||
" jmp 0f \n\t"
|
||||
|
||||
"45: cmp $4, %[rounds] \n\t"
|
||||
" je 4f \n\t"
|
||||
|
||||
// Block of non-interlaced encoding rounds, which can each
|
||||
// individually be jumped to. Rounds fall through to the next.
|
||||
"5: " ROUND()
|
||||
"4: " ROUND()
|
||||
"3: " ROUND()
|
||||
"2: " ROUND()
|
||||
"1: " ROUND()
|
||||
"0: \n\t"
|
||||
|
||||
// Outputs (modified).
|
||||
: [rounds] "+r" (rounds),
|
||||
[loops] "+r" (loops),
|
||||
[src] "+r" (*s),
|
||||
[dst] "+r" (*o),
|
||||
[a] "=&x" (a),
|
||||
[b] "=&x" (b),
|
||||
[c] "=&x" (c),
|
||||
[d] "=&x" (d),
|
||||
[e] "=&x" (e),
|
||||
[f] "=&x" (f)
|
||||
|
||||
// Inputs (not modified).
|
||||
: [lut0] "x" (lut0),
|
||||
[lut1] "x" (lut1),
|
||||
[msk0] "x" (_mm_set1_epi32(0x0FC0FC00)),
|
||||
[msk1] "x" (_mm_set1_epi32(0x04000040)),
|
||||
[msk2] "x" (_mm_set1_epi32(0x003F03F0)),
|
||||
[msk3] "x" (_mm_set1_epi32(0x01000010)),
|
||||
[n51] "x" (_mm_set1_epi8(51)),
|
||||
[n25] "x" (_mm_set1_epi8(25))
|
||||
|
||||
// Clobbers.
|
||||
: "cc", "memory"
|
||||
);
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
48
3rdparty/base64/lib/arch/ssse3/enc_reshuffle.c
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
static inline __m128i
|
||||
enc_reshuffle (__m128i in)
|
||||
{
|
||||
// Input, bytes MSB to LSB:
|
||||
// 0 0 0 0 l k j i h g f e d c b a
|
||||
|
||||
in = _mm_shuffle_epi8(in, _mm_set_epi8(
|
||||
10, 11, 9, 10,
|
||||
7, 8, 6, 7,
|
||||
4, 5, 3, 4,
|
||||
1, 2, 0, 1));
|
||||
// in, bytes MSB to LSB:
|
||||
// k l j k
|
||||
// h i g h
|
||||
// e f d e
|
||||
// b c a b
|
||||
|
||||
const __m128i t0 = _mm_and_si128(in, _mm_set1_epi32(0x0FC0FC00));
|
||||
// bits, upper case are most significant bits, lower case are least significant bits
|
||||
// 0000kkkk LL000000 JJJJJJ00 00000000
|
||||
// 0000hhhh II000000 GGGGGG00 00000000
|
||||
// 0000eeee FF000000 DDDDDD00 00000000
|
||||
// 0000bbbb CC000000 AAAAAA00 00000000
|
||||
|
||||
const __m128i t1 = _mm_mulhi_epu16(t0, _mm_set1_epi32(0x04000040));
|
||||
// 00000000 00kkkkLL 00000000 00JJJJJJ
|
||||
// 00000000 00hhhhII 00000000 00GGGGGG
|
||||
// 00000000 00eeeeFF 00000000 00DDDDDD
|
||||
// 00000000 00bbbbCC 00000000 00AAAAAA
|
||||
|
||||
const __m128i t2 = _mm_and_si128(in, _mm_set1_epi32(0x003F03F0));
|
||||
// 00000000 00llllll 000000jj KKKK0000
|
||||
// 00000000 00iiiiii 000000gg HHHH0000
|
||||
// 00000000 00ffffff 000000dd EEEE0000
|
||||
// 00000000 00cccccc 000000aa BBBB0000
|
||||
|
||||
const __m128i t3 = _mm_mullo_epi16(t2, _mm_set1_epi32(0x01000010));
|
||||
// 00llllll 00000000 00jjKKKK 00000000
|
||||
// 00iiiiii 00000000 00ggHHHH 00000000
|
||||
// 00ffffff 00000000 00ddEEEE 00000000
|
||||
// 00cccccc 00000000 00aaBBBB 00000000
|
||||
|
||||
return _mm_or_si128(t1, t3);
|
||||
// 00llllll 00kkkkLL 00jjKKKK 00JJJJJJ
|
||||
// 00iiiiii 00hhhhII 00ggHHHH 00GGGGGG
|
||||
// 00ffffff 00eeeeFF 00ddEEEE 00DDDDDD
|
||||
// 00cccccc 00bbbbCC 00aaBBBB 00AAAAAA
|
||||
}
|
||||
33
3rdparty/base64/lib/arch/ssse3/enc_translate.c
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
static inline __m128i
|
||||
enc_translate (const __m128i in)
|
||||
{
|
||||
// A lookup table containing the absolute offsets for all ranges:
|
||||
const __m128i lut = _mm_setr_epi8(
|
||||
65, 71, -4, -4,
|
||||
-4, -4, -4, -4,
|
||||
-4, -4, -4, -4,
|
||||
-19, -16, 0, 0
|
||||
);
|
||||
|
||||
// Translate values 0..63 to the Base64 alphabet. There are five sets:
|
||||
// # From To Abs Index Characters
|
||||
// 0 [0..25] [65..90] +65 0 ABCDEFGHIJKLMNOPQRSTUVWXYZ
|
||||
// 1 [26..51] [97..122] +71 1 abcdefghijklmnopqrstuvwxyz
|
||||
// 2 [52..61] [48..57] -4 [2..11] 0123456789
|
||||
// 3 [62] [43] -19 12 +
|
||||
// 4 [63] [47] -16 13 /
|
||||
|
||||
// Create LUT indices from the input. The index for range #0 is right,
|
||||
// others are 1 less than expected:
|
||||
__m128i indices = _mm_subs_epu8(in, _mm_set1_epi8(51));
|
||||
|
||||
// mask is 0xFF (-1) for range #[1..4] and 0x00 for range #0:
|
||||
__m128i mask = _mm_cmpgt_epi8(in, _mm_set1_epi8(25));
|
||||
|
||||
// Subtract -1, so add 1 to indices for range #[1..4]. All indices are
|
||||
// now correct:
|
||||
indices = _mm_sub_epi8(indices, mask);
|
||||
|
||||
// Add offsets to input values:
|
||||
return _mm_add_epi8(in, _mm_shuffle_epi8(lut, indices));
|
||||
}
|
||||
305
3rdparty/base64/lib/codec_choose.c
vendored
Normal file
@@ -0,0 +1,305 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "../include/libbase64.h"
|
||||
#include "codecs.h"
|
||||
#include "config.h"
|
||||
#include "env.h"
|
||||
|
||||
#if (__x86_64__ || __i386__ || _M_X86 || _M_X64)
|
||||
#define BASE64_X86
|
||||
#if (HAVE_SSSE3 || HAVE_SSE41 || HAVE_SSE42 || HAVE_AVX || HAVE_AVX2 || HAVE_AVX512)
|
||||
#define BASE64_X86_SIMD
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef BASE64_X86
|
||||
#ifdef _MSC_VER
|
||||
#include <intrin.h>
|
||||
#define __cpuid_count(__level, __count, __eax, __ebx, __ecx, __edx) \
|
||||
{ \
|
||||
int info[4]; \
|
||||
__cpuidex(info, __level, __count); \
|
||||
__eax = info[0]; \
|
||||
__ebx = info[1]; \
|
||||
__ecx = info[2]; \
|
||||
__edx = info[3]; \
|
||||
}
|
||||
#define __cpuid(__level, __eax, __ebx, __ecx, __edx) \
|
||||
__cpuid_count(__level, 0, __eax, __ebx, __ecx, __edx)
|
||||
#else
|
||||
#include <cpuid.h>
|
||||
#if HAVE_AVX512 || HAVE_AVX2 || HAVE_AVX
|
||||
#if ((__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 2) || (__clang_major__ >= 3))
|
||||
static inline uint64_t _xgetbv (uint32_t index)
|
||||
{
|
||||
uint32_t eax, edx;
|
||||
__asm__ __volatile__("xgetbv" : "=a"(eax), "=d"(edx) : "c"(index));
|
||||
return ((uint64_t)edx << 32) | eax;
|
||||
}
|
||||
#else
|
||||
#error "Platform not supported"
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef bit_AVX512vl
|
||||
#define bit_AVX512vl (1 << 31)
|
||||
#endif
|
||||
#ifndef bit_AVX512vbmi
|
||||
#define bit_AVX512vbmi (1 << 1)
|
||||
#endif
|
||||
#ifndef bit_AVX2
|
||||
#define bit_AVX2 (1 << 5)
|
||||
#endif
|
||||
#ifndef bit_SSSE3
|
||||
#define bit_SSSE3 (1 << 9)
|
||||
#endif
|
||||
#ifndef bit_SSE41
|
||||
#define bit_SSE41 (1 << 19)
|
||||
#endif
|
||||
#ifndef bit_SSE42
|
||||
#define bit_SSE42 (1 << 20)
|
||||
#endif
|
||||
#ifndef bit_AVX
|
||||
#define bit_AVX (1 << 28)
|
||||
#endif
|
||||
|
||||
#define bit_XSAVE_XRSTORE (1 << 27)
|
||||
|
||||
#ifndef _XCR_XFEATURE_ENABLED_MASK
|
||||
#define _XCR_XFEATURE_ENABLED_MASK 0
|
||||
#endif
|
||||
|
||||
#define _XCR_XMM_AND_YMM_STATE_ENABLED_BY_OS 0x6
|
||||
#endif
|
||||
|
||||
// Function declarations:
|
||||
#define BASE64_CODEC_FUNCS(arch) \
|
||||
BASE64_ENC_FUNCTION(arch); \
|
||||
BASE64_DEC_FUNCTION(arch); \
|
||||
|
||||
BASE64_CODEC_FUNCS(avx512)
|
||||
BASE64_CODEC_FUNCS(avx2)
|
||||
BASE64_CODEC_FUNCS(neon32)
|
||||
BASE64_CODEC_FUNCS(neon64)
|
||||
BASE64_CODEC_FUNCS(plain)
|
||||
BASE64_CODEC_FUNCS(ssse3)
|
||||
BASE64_CODEC_FUNCS(sse41)
|
||||
BASE64_CODEC_FUNCS(sse42)
|
||||
BASE64_CODEC_FUNCS(avx)
|
||||
|
||||
static bool
|
||||
codec_choose_forced (struct codec *codec, int flags)
|
||||
{
|
||||
// If the user wants to use a certain codec,
|
||||
// always allow it, even if the codec is a no-op.
|
||||
// For testing purposes.
|
||||
|
||||
if (!(flags & 0xFFFF)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (flags & BASE64_FORCE_AVX2) {
|
||||
codec->enc = base64_stream_encode_avx2;
|
||||
codec->dec = base64_stream_decode_avx2;
|
||||
return true;
|
||||
}
|
||||
if (flags & BASE64_FORCE_NEON32) {
|
||||
codec->enc = base64_stream_encode_neon32;
|
||||
codec->dec = base64_stream_decode_neon32;
|
||||
return true;
|
||||
}
|
||||
if (flags & BASE64_FORCE_NEON64) {
|
||||
codec->enc = base64_stream_encode_neon64;
|
||||
codec->dec = base64_stream_decode_neon64;
|
||||
return true;
|
||||
}
|
||||
if (flags & BASE64_FORCE_PLAIN) {
|
||||
codec->enc = base64_stream_encode_plain;
|
||||
codec->dec = base64_stream_decode_plain;
|
||||
return true;
|
||||
}
|
||||
if (flags & BASE64_FORCE_SSSE3) {
|
||||
codec->enc = base64_stream_encode_ssse3;
|
||||
codec->dec = base64_stream_decode_ssse3;
|
||||
return true;
|
||||
}
|
||||
if (flags & BASE64_FORCE_SSE41) {
|
||||
codec->enc = base64_stream_encode_sse41;
|
||||
codec->dec = base64_stream_decode_sse41;
|
||||
return true;
|
||||
}
|
||||
if (flags & BASE64_FORCE_SSE42) {
|
||||
codec->enc = base64_stream_encode_sse42;
|
||||
codec->dec = base64_stream_decode_sse42;
|
||||
return true;
|
||||
}
|
||||
if (flags & BASE64_FORCE_AVX) {
|
||||
codec->enc = base64_stream_encode_avx;
|
||||
codec->dec = base64_stream_decode_avx;
|
||||
return true;
|
||||
}
|
||||
if (flags & BASE64_FORCE_AVX512) {
|
||||
codec->enc = base64_stream_encode_avx512;
|
||||
codec->dec = base64_stream_decode_avx512;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
codec_choose_arm (struct codec *codec)
|
||||
{
|
||||
#if (defined(__ARM_NEON__) || defined(__ARM_NEON)) && ((defined(__aarch64__) && HAVE_NEON64) || HAVE_NEON32)
|
||||
|
||||
// Unfortunately there is no portable way to check for NEON
|
||||
// support at runtime from userland in the same way that x86
|
||||
// has cpuid, so just stick to the compile-time configuration:
|
||||
|
||||
#if defined(__aarch64__) && HAVE_NEON64
|
||||
codec->enc = base64_stream_encode_neon64;
|
||||
codec->dec = base64_stream_decode_neon64;
|
||||
#else
|
||||
codec->enc = base64_stream_encode_neon32;
|
||||
codec->dec = base64_stream_decode_neon32;
|
||||
#endif
|
||||
|
||||
return true;
|
||||
|
||||
#else
|
||||
(void)codec;
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool
|
||||
codec_choose_x86 (struct codec *codec)
|
||||
{
|
||||
#ifdef BASE64_X86_SIMD
|
||||
|
||||
unsigned int eax, ebx = 0, ecx = 0, edx;
|
||||
unsigned int max_level;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
int info[4];
|
||||
__cpuidex(info, 0, 0);
|
||||
max_level = info[0];
|
||||
#else
|
||||
max_level = __get_cpuid_max(0, NULL);
|
||||
#endif
|
||||
|
||||
#if HAVE_AVX512 || HAVE_AVX2 || HAVE_AVX
|
||||
// Check for AVX/AVX2/AVX512 support:
|
||||
// Checking for AVX requires 3 things:
|
||||
// 1) CPUID indicates that the OS uses XSAVE and XRSTORE instructions
|
||||
// (allowing saving YMM registers on context switch)
|
||||
// 2) CPUID indicates support for AVX
|
||||
// 3) XGETBV indicates the AVX registers will be saved and restored on
|
||||
// context switch
|
||||
//
|
||||
// Note that XGETBV is only available on 686 or later CPUs, so the
|
||||
// instruction needs to be conditionally run.
|
||||
if (max_level >= 1) {
|
||||
__cpuid_count(1, 0, eax, ebx, ecx, edx);
|
||||
if (ecx & bit_XSAVE_XRSTORE) {
|
||||
uint64_t xcr_mask;
|
||||
xcr_mask = _xgetbv(_XCR_XFEATURE_ENABLED_MASK);
|
||||
if ((xcr_mask & _XCR_XMM_AND_YMM_STATE_ENABLED_BY_OS) == _XCR_XMM_AND_YMM_STATE_ENABLED_BY_OS) { // check multiple bits at once
|
||||
#if HAVE_AVX512
|
||||
if (max_level >= 7) {
|
||||
__cpuid_count(7, 0, eax, ebx, ecx, edx);
|
||||
if ((ebx & bit_AVX512vl) && (ecx & bit_AVX512vbmi)) {
|
||||
codec->enc = base64_stream_encode_avx512;
|
||||
codec->dec = base64_stream_decode_avx512;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if HAVE_AVX2
|
||||
if (max_level >= 7) {
|
||||
__cpuid_count(7, 0, eax, ebx, ecx, edx);
|
||||
if (ebx & bit_AVX2) {
|
||||
codec->enc = base64_stream_encode_avx2;
|
||||
codec->dec = base64_stream_decode_avx2;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if HAVE_AVX
|
||||
__cpuid_count(1, 0, eax, ebx, ecx, edx);
|
||||
if (ecx & bit_AVX) {
|
||||
codec->enc = base64_stream_encode_avx;
|
||||
codec->dec = base64_stream_decode_avx;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if HAVE_SSE42
|
||||
// Check for SSE42 support:
|
||||
if (max_level >= 1) {
|
||||
__cpuid(1, eax, ebx, ecx, edx);
|
||||
if (ecx & bit_SSE42) {
|
||||
codec->enc = base64_stream_encode_sse42;
|
||||
codec->dec = base64_stream_decode_sse42;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if HAVE_SSE41
|
||||
// Check for SSE41 support:
|
||||
if (max_level >= 1) {
|
||||
__cpuid(1, eax, ebx, ecx, edx);
|
||||
if (ecx & bit_SSE41) {
|
||||
codec->enc = base64_stream_encode_sse41;
|
||||
codec->dec = base64_stream_decode_sse41;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if HAVE_SSSE3
|
||||
// Check for SSSE3 support:
|
||||
if (max_level >= 1) {
|
||||
__cpuid(1, eax, ebx, ecx, edx);
|
||||
if (ecx & bit_SSSE3) {
|
||||
codec->enc = base64_stream_encode_ssse3;
|
||||
codec->dec = base64_stream_decode_ssse3;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#else
|
||||
(void)codec;
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
codec_choose (struct codec *codec, int flags)
|
||||
{
|
||||
// User forced a codec:
|
||||
if (codec_choose_forced(codec, flags)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Runtime feature detection:
|
||||
if (codec_choose_arm(codec)) {
|
||||
return;
|
||||
}
|
||||
if (codec_choose_x86(codec)) {
|
||||
return;
|
||||
}
|
||||
codec->enc = base64_stream_encode_plain;
|
||||
codec->dec = base64_stream_decode_plain;
|
||||
}
|
||||
65
3rdparty/base64/lib/codecs.h
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "../include/libbase64.h"
|
||||
#include "config.h"
|
||||
|
||||
// Function parameters for encoding functions:
|
||||
#define BASE64_ENC_PARAMS \
|
||||
( struct base64_state *state \
|
||||
, const char *src \
|
||||
, size_t srclen \
|
||||
, char *out \
|
||||
, size_t *outlen \
|
||||
)
|
||||
|
||||
// Function parameters for decoding functions:
|
||||
#define BASE64_DEC_PARAMS \
|
||||
( struct base64_state *state \
|
||||
, const char *src \
|
||||
, size_t srclen \
|
||||
, char *out \
|
||||
, size_t *outlen \
|
||||
)
|
||||
|
||||
// Function signature for encoding functions:
|
||||
#define BASE64_ENC_FUNCTION(arch) \
|
||||
void \
|
||||
base64_stream_encode_ ## arch \
|
||||
BASE64_ENC_PARAMS
|
||||
|
||||
// Function signature for decoding functions:
|
||||
#define BASE64_DEC_FUNCTION(arch) \
|
||||
int \
|
||||
base64_stream_decode_ ## arch \
|
||||
BASE64_DEC_PARAMS
|
||||
|
||||
// Cast away unused variable, silence compiler:
|
||||
#define UNUSED(x) ((void)(x))
|
||||
|
||||
// Stub function when encoder arch unsupported:
|
||||
#define BASE64_ENC_STUB \
|
||||
UNUSED(state); \
|
||||
UNUSED(src); \
|
||||
UNUSED(srclen); \
|
||||
UNUSED(out); \
|
||||
\
|
||||
*outlen = 0;
|
||||
|
||||
// Stub function when decoder arch unsupported:
|
||||
#define BASE64_DEC_STUB \
|
||||
UNUSED(state); \
|
||||
UNUSED(src); \
|
||||
UNUSED(srclen); \
|
||||
UNUSED(out); \
|
||||
UNUSED(outlen); \
|
||||
\
|
||||
return -1;
|
||||
|
||||
struct codec
|
||||
{
|
||||
void (* enc) BASE64_ENC_PARAMS;
|
||||
int (* dec) BASE64_DEC_PARAMS;
|
||||
};
|
||||
|
||||
extern void codec_choose (struct codec *, int flags);
|
||||
74
3rdparty/base64/lib/env.h
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
#ifndef BASE64_ENV_H
|
||||
#define BASE64_ENV_H
|
||||
|
||||
// This header file contains macro definitions that describe certain aspects of
|
||||
// the compile-time environment. Compatibility and portability macros go here.
|
||||
|
||||
// Define machine endianness. This is for GCC:
|
||||
#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
|
||||
# define BASE64_LITTLE_ENDIAN 1
|
||||
#else
|
||||
# define BASE64_LITTLE_ENDIAN 0
|
||||
#endif
|
||||
|
||||
// This is for Clang:
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
# define BASE64_LITTLE_ENDIAN 1
|
||||
#endif
|
||||
|
||||
#ifdef __BIG_ENDIAN__
|
||||
# define BASE64_LITTLE_ENDIAN 0
|
||||
#endif
|
||||
|
||||
// MSVC++ needs intrin.h for _byteswap_uint64 (issue #68):
|
||||
#if BASE64_LITTLE_ENDIAN && defined(_MSC_VER)
|
||||
# include <intrin.h>
|
||||
#endif
|
||||
|
||||
// Endian conversion functions:
|
||||
#if BASE64_LITTLE_ENDIAN
|
||||
# ifdef _MSC_VER
|
||||
// Microsoft Visual C++:
|
||||
# define BASE64_HTOBE32(x) _byteswap_ulong(x)
|
||||
# define BASE64_HTOBE64(x) _byteswap_uint64(x)
|
||||
# else
|
||||
// GCC and Clang:
|
||||
# define BASE64_HTOBE32(x) __builtin_bswap32(x)
|
||||
# define BASE64_HTOBE64(x) __builtin_bswap64(x)
|
||||
# endif
|
||||
#else
|
||||
// No conversion needed:
|
||||
# define BASE64_HTOBE32(x) (x)
|
||||
# define BASE64_HTOBE64(x) (x)
|
||||
#endif
|
||||
|
||||
// Detect word size:
|
||||
#if defined (__x86_64__)
|
||||
// This also works for the x32 ABI, which has a 64-bit word size.
|
||||
# define BASE64_WORDSIZE 64
|
||||
#elif defined (_INTEGRAL_MAX_BITS)
|
||||
# define BASE64_WORDSIZE _INTEGRAL_MAX_BITS
|
||||
#elif defined (__WORDSIZE)
|
||||
# define BASE64_WORDSIZE __WORDSIZE
|
||||
#elif defined (__SIZE_WIDTH__)
|
||||
# define BASE64_WORDSIZE __SIZE_WIDTH__
|
||||
#else
|
||||
# error BASE64_WORDSIZE_NOT_DEFINED
|
||||
#endif
|
||||
|
||||
// End-of-file definitions.
|
||||
// Almost end-of-file when waiting for the last '=' character:
|
||||
#define BASE64_AEOF 1
|
||||
// End-of-file when stream end has been reached or invalid input provided:
|
||||
#define BASE64_EOF 2
|
||||
|
||||
// GCC 7 defaults to issuing a warning for fallthrough in switch statements,
|
||||
// unless the fallthrough cases are marked with an attribute. As we use
|
||||
// fallthrough deliberately, define an alias for the attribute:
|
||||
#if __GNUC__ >= 7
|
||||
# define BASE64_FALLTHROUGH __attribute__((fallthrough));
|
||||
#else
|
||||
# define BASE64_FALLTHROUGH
|
||||
#endif
|
||||
|
||||
#endif // BASE64_ENV_H
|
||||
7
3rdparty/base64/lib/exports.txt
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
base64_encode
|
||||
base64_stream_encode
|
||||
base64_stream_encode_init
|
||||
base64_stream_encode_final
|
||||
base64_decode
|
||||
base64_stream_decode
|
||||
base64_stream_decode_init
|
||||
164
3rdparty/base64/lib/lib.c
vendored
Normal file
@@ -0,0 +1,164 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#ifdef _OPENMP
|
||||
#include <omp.h>
|
||||
#endif
|
||||
|
||||
#include "../include/libbase64.h"
|
||||
#include "tables/tables.h"
|
||||
#include "codecs.h"
|
||||
#include "env.h"
|
||||
|
||||
// These static function pointers are initialized once when the library is
|
||||
// first used, and remain in use for the remaining lifetime of the program.
|
||||
// The idea being that CPU features don't change at runtime.
|
||||
static struct codec codec = { NULL, NULL };
|
||||
|
||||
void
|
||||
base64_stream_encode_init (struct base64_state *state, int flags)
|
||||
{
|
||||
// If any of the codec flags are set, redo choice:
|
||||
if (codec.enc == NULL || flags & 0xFF) {
|
||||
codec_choose(&codec, flags);
|
||||
}
|
||||
state->eof = 0;
|
||||
state->bytes = 0;
|
||||
state->carry = 0;
|
||||
state->flags = flags;
|
||||
}
|
||||
|
||||
void
|
||||
base64_stream_encode
|
||||
( struct base64_state *state
|
||||
, const char *src
|
||||
, size_t srclen
|
||||
, char *out
|
||||
, size_t *outlen
|
||||
)
|
||||
{
|
||||
codec.enc(state, src, srclen, out, outlen);
|
||||
}
|
||||
|
||||
void
|
||||
base64_stream_encode_final
|
||||
( struct base64_state *state
|
||||
, char *out
|
||||
, size_t *outlen
|
||||
)
|
||||
{
|
||||
uint8_t *o = (uint8_t *)out;
|
||||
|
||||
if (state->bytes == 1) {
|
||||
*o++ = base64_table_enc_6bit[state->carry];
|
||||
*o++ = '=';
|
||||
*o++ = '=';
|
||||
*outlen = 3;
|
||||
return;
|
||||
}
|
||||
if (state->bytes == 2) {
|
||||
*o++ = base64_table_enc_6bit[state->carry];
|
||||
*o++ = '=';
|
||||
*outlen = 2;
|
||||
return;
|
||||
}
|
||||
*outlen = 0;
|
||||
}
|
||||
|
||||
void
|
||||
base64_stream_decode_init (struct base64_state *state, int flags)
|
||||
{
|
||||
// If any of the codec flags are set, redo choice:
|
||||
if (codec.dec == NULL || flags & 0xFFFF) {
|
||||
codec_choose(&codec, flags);
|
||||
}
|
||||
state->eof = 0;
|
||||
state->bytes = 0;
|
||||
state->carry = 0;
|
||||
state->flags = flags;
|
||||
}
|
||||
|
||||
int
|
||||
base64_stream_decode
|
||||
( struct base64_state *state
|
||||
, const char *src
|
||||
, size_t srclen
|
||||
, char *out
|
||||
, size_t *outlen
|
||||
)
|
||||
{
|
||||
return codec.dec(state, src, srclen, out, outlen);
|
||||
}
|
||||
|
||||
#ifdef _OPENMP
|
||||
|
||||
// Due to the overhead of initializing OpenMP and creating a team of
|
||||
// threads, we require the data length to be larger than a threshold:
|
||||
#define OMP_THRESHOLD 20000
|
||||
|
||||
// Conditionally include OpenMP-accelerated codec implementations:
|
||||
#include "lib_openmp.c"
|
||||
#endif
|
||||
|
||||
void
|
||||
base64_encode
|
||||
( const char *src
|
||||
, size_t srclen
|
||||
, char *out
|
||||
, size_t *outlen
|
||||
, int flags
|
||||
)
|
||||
{
|
||||
size_t s;
|
||||
size_t t;
|
||||
struct base64_state state;
|
||||
|
||||
#ifdef _OPENMP
|
||||
if (srclen >= OMP_THRESHOLD) {
|
||||
base64_encode_openmp(src, srclen, out, outlen, flags);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Init the stream reader:
|
||||
base64_stream_encode_init(&state, flags);
|
||||
|
||||
// Feed the whole string to the stream reader:
|
||||
base64_stream_encode(&state, src, srclen, out, &s);
|
||||
|
||||
// Finalize the stream by writing trailer if any:
|
||||
base64_stream_encode_final(&state, out + s, &t);
|
||||
|
||||
// Final output length is stream length plus tail:
|
||||
*outlen = s + t;
|
||||
}
|
||||
|
||||
int
|
||||
base64_decode
|
||||
( const char *src
|
||||
, size_t srclen
|
||||
, char *out
|
||||
, size_t *outlen
|
||||
, int flags
|
||||
)
|
||||
{
|
||||
int ret;
|
||||
struct base64_state state;
|
||||
|
||||
#ifdef _OPENMP
|
||||
if (srclen >= OMP_THRESHOLD) {
|
||||
return base64_decode_openmp(src, srclen, out, outlen, flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Init the stream reader:
|
||||
base64_stream_decode_init(&state, flags);
|
||||
|
||||
// Feed the whole string to the stream reader:
|
||||
ret = base64_stream_decode(&state, src, srclen, out, outlen);
|
||||
|
||||
// If when decoding a whole block, we're still waiting for input then fail:
|
||||
if (ret && (state.bytes == 0)) {
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
149
3rdparty/base64/lib/lib_openmp.c
vendored
Normal file
@@ -0,0 +1,149 @@
|
||||
// This code makes some assumptions on the implementation of
|
||||
// base64_stream_encode_init(), base64_stream_encode() and base64_stream_decode().
|
||||
// Basically these assumptions boil down to that when breaking the src into
|
||||
// parts, out parts can be written without side effects.
|
||||
// This is met when:
|
||||
// 1) base64_stream_encode() and base64_stream_decode() don't use globals;
|
||||
// 2) the shared variables src and out are not read or written outside of the
|
||||
// bounds of their parts, i.e. when base64_stream_encode() reads a multiple
|
||||
// of 3 bytes, it must write no more then a multiple of 4 bytes, not even
|
||||
// temporarily;
|
||||
// 3) the state flag can be discarded after base64_stream_encode() and
|
||||
// base64_stream_decode() on the parts.
|
||||
|
||||
static inline void
|
||||
base64_encode_openmp
|
||||
( const char *src
|
||||
, size_t srclen
|
||||
, char *out
|
||||
, size_t *outlen
|
||||
, int flags
|
||||
)
|
||||
{
|
||||
size_t s;
|
||||
size_t t;
|
||||
size_t sum = 0, len, last_len;
|
||||
struct base64_state state, initial_state;
|
||||
int num_threads, i;
|
||||
|
||||
// Request a number of threads but not necessarily get them:
|
||||
#pragma omp parallel
|
||||
{
|
||||
// Get the number of threads used from one thread only,
|
||||
// as num_threads is a shared var:
|
||||
#pragma omp single
|
||||
{
|
||||
num_threads = omp_get_num_threads();
|
||||
|
||||
// Split the input string into num_threads parts, each
|
||||
// part a multiple of 3 bytes. The remaining bytes will
|
||||
// be done later:
|
||||
len = srclen / (num_threads * 3);
|
||||
len *= 3;
|
||||
last_len = srclen - num_threads * len;
|
||||
|
||||
// Init the stream reader:
|
||||
base64_stream_encode_init(&state, flags);
|
||||
initial_state = state;
|
||||
}
|
||||
|
||||
// Single has an implicit barrier for all threads to wait here
|
||||
// for the above to complete:
|
||||
#pragma omp for firstprivate(state) private(s) reduction(+:sum) schedule(static,1)
|
||||
for (i = 0; i < num_threads; i++)
|
||||
{
|
||||
// Feed each part of the string to the stream reader:
|
||||
base64_stream_encode(&state, src + i * len, len, out + i * len * 4 / 3, &s);
|
||||
sum += s;
|
||||
}
|
||||
}
|
||||
|
||||
// As encoding should never fail and we encode an exact multiple
|
||||
// of 3 bytes, we can discard state:
|
||||
state = initial_state;
|
||||
|
||||
// Encode the remaining bytes:
|
||||
base64_stream_encode(&state, src + num_threads * len, last_len, out + num_threads * len * 4 / 3, &s);
|
||||
|
||||
// Finalize the stream by writing trailer if any:
|
||||
base64_stream_encode_final(&state, out + num_threads * len * 4 / 3 + s, &t);
|
||||
|
||||
// Final output length is stream length plus tail:
|
||||
sum += s + t;
|
||||
*outlen = sum;
|
||||
}
|
||||
|
||||
static inline int
|
||||
base64_decode_openmp
|
||||
( const char *src
|
||||
, size_t srclen
|
||||
, char *out
|
||||
, size_t *outlen
|
||||
, int flags
|
||||
)
|
||||
{
|
||||
int num_threads, result = 0, i;
|
||||
size_t sum = 0, len, last_len, s;
|
||||
struct base64_state state, initial_state;
|
||||
|
||||
// Request a number of threads but not necessarily get them:
|
||||
#pragma omp parallel
|
||||
{
|
||||
// Get the number of threads used from one thread only,
|
||||
// as num_threads is a shared var:
|
||||
#pragma omp single
|
||||
{
|
||||
num_threads = omp_get_num_threads();
|
||||
|
||||
// Split the input string into num_threads parts, each
|
||||
// part a multiple of 4 bytes. The remaining bytes will
|
||||
// be done later:
|
||||
len = srclen / (num_threads * 4);
|
||||
len *= 4;
|
||||
last_len = srclen - num_threads * len;
|
||||
|
||||
// Init the stream reader:
|
||||
base64_stream_decode_init(&state, flags);
|
||||
|
||||
initial_state = state;
|
||||
}
|
||||
|
||||
// Single has an implicit barrier to wait here for the above to
|
||||
// complete:
|
||||
#pragma omp for firstprivate(state) private(s) reduction(+:sum, result) schedule(static,1)
|
||||
for (i = 0; i < num_threads; i++)
|
||||
{
|
||||
int this_result;
|
||||
|
||||
// Feed each part of the string to the stream reader:
|
||||
this_result = base64_stream_decode(&state, src + i * len, len, out + i * len * 3 / 4, &s);
|
||||
sum += s;
|
||||
result += this_result;
|
||||
}
|
||||
}
|
||||
|
||||
// If `result' equals `-num_threads', then all threads returned -1,
|
||||
// indicating that the requested codec is not available:
|
||||
if (result == -num_threads) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// If `result' does not equal `num_threads', then at least one of the
|
||||
// threads hit a decode error:
|
||||
if (result != num_threads) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// So far so good, now decode whatever remains in the buffer. Reuse the
|
||||
// initial state, since we are at a 4-byte boundary:
|
||||
state = initial_state;
|
||||
result = base64_stream_decode(&state, src + num_threads * len, last_len, out + num_threads * len * 3 / 4, &s);
|
||||
sum += s;
|
||||
*outlen = sum;
|
||||
|
||||
// If when decoding a whole block, we're still waiting for input then fail:
|
||||
if (result && (state.bytes == 0)) {
|
||||
return result;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
1
3rdparty/base64/lib/tables/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
table_generator
|
||||
17
3rdparty/base64/lib/tables/Makefile
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
.PHONY: all clean
|
||||
|
||||
TARGETS := table_dec_32bit.h table_enc_12bit.h table_generator
|
||||
|
||||
all: $(TARGETS)
|
||||
|
||||
clean:
|
||||
$(RM) $(TARGETS)
|
||||
|
||||
table_dec_32bit.h: table_generator
|
||||
./$^ > $@
|
||||
|
||||
table_enc_12bit.h: table_enc_12bit.py
|
||||
./$^ > $@
|
||||
|
||||
table_generator: table_generator.c
|
||||
$(CC) $(CFLAGS) -o $@ $^
|
||||
393
3rdparty/base64/lib/tables/table_dec_32bit.h
vendored
Normal file
@@ -0,0 +1,393 @@
|
||||
#include <stdint.h>
|
||||
#define CHAR62 '+'
|
||||
#define CHAR63 '/'
|
||||
#define CHARPAD '='
|
||||
|
||||
|
||||
#if BASE64_LITTLE_ENDIAN
|
||||
|
||||
|
||||
/* SPECIAL DECODE TABLES FOR LITTLE ENDIAN (INTEL) CPUS */
|
||||
|
||||
const uint32_t base64_table_dec_32bit_d0[256] = {
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0x000000f8, 0xffffffff, 0xffffffff, 0xffffffff, 0x000000fc,
|
||||
0x000000d0, 0x000000d4, 0x000000d8, 0x000000dc, 0x000000e0, 0x000000e4,
|
||||
0x000000e8, 0x000000ec, 0x000000f0, 0x000000f4, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000,
|
||||
0x00000004, 0x00000008, 0x0000000c, 0x00000010, 0x00000014, 0x00000018,
|
||||
0x0000001c, 0x00000020, 0x00000024, 0x00000028, 0x0000002c, 0x00000030,
|
||||
0x00000034, 0x00000038, 0x0000003c, 0x00000040, 0x00000044, 0x00000048,
|
||||
0x0000004c, 0x00000050, 0x00000054, 0x00000058, 0x0000005c, 0x00000060,
|
||||
0x00000064, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0x00000068, 0x0000006c, 0x00000070, 0x00000074, 0x00000078,
|
||||
0x0000007c, 0x00000080, 0x00000084, 0x00000088, 0x0000008c, 0x00000090,
|
||||
0x00000094, 0x00000098, 0x0000009c, 0x000000a0, 0x000000a4, 0x000000a8,
|
||||
0x000000ac, 0x000000b0, 0x000000b4, 0x000000b8, 0x000000bc, 0x000000c0,
|
||||
0x000000c4, 0x000000c8, 0x000000cc, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff
|
||||
};
|
||||
|
||||
|
||||
const uint32_t base64_table_dec_32bit_d1[256] = {
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0x0000e003, 0xffffffff, 0xffffffff, 0xffffffff, 0x0000f003,
|
||||
0x00004003, 0x00005003, 0x00006003, 0x00007003, 0x00008003, 0x00009003,
|
||||
0x0000a003, 0x0000b003, 0x0000c003, 0x0000d003, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000,
|
||||
0x00001000, 0x00002000, 0x00003000, 0x00004000, 0x00005000, 0x00006000,
|
||||
0x00007000, 0x00008000, 0x00009000, 0x0000a000, 0x0000b000, 0x0000c000,
|
||||
0x0000d000, 0x0000e000, 0x0000f000, 0x00000001, 0x00001001, 0x00002001,
|
||||
0x00003001, 0x00004001, 0x00005001, 0x00006001, 0x00007001, 0x00008001,
|
||||
0x00009001, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0x0000a001, 0x0000b001, 0x0000c001, 0x0000d001, 0x0000e001,
|
||||
0x0000f001, 0x00000002, 0x00001002, 0x00002002, 0x00003002, 0x00004002,
|
||||
0x00005002, 0x00006002, 0x00007002, 0x00008002, 0x00009002, 0x0000a002,
|
||||
0x0000b002, 0x0000c002, 0x0000d002, 0x0000e002, 0x0000f002, 0x00000003,
|
||||
0x00001003, 0x00002003, 0x00003003, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff
|
||||
};
|
||||
|
||||
|
||||
const uint32_t base64_table_dec_32bit_d2[256] = {
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0x00800f00, 0xffffffff, 0xffffffff, 0xffffffff, 0x00c00f00,
|
||||
0x00000d00, 0x00400d00, 0x00800d00, 0x00c00d00, 0x00000e00, 0x00400e00,
|
||||
0x00800e00, 0x00c00e00, 0x00000f00, 0x00400f00, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000,
|
||||
0x00400000, 0x00800000, 0x00c00000, 0x00000100, 0x00400100, 0x00800100,
|
||||
0x00c00100, 0x00000200, 0x00400200, 0x00800200, 0x00c00200, 0x00000300,
|
||||
0x00400300, 0x00800300, 0x00c00300, 0x00000400, 0x00400400, 0x00800400,
|
||||
0x00c00400, 0x00000500, 0x00400500, 0x00800500, 0x00c00500, 0x00000600,
|
||||
0x00400600, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0x00800600, 0x00c00600, 0x00000700, 0x00400700, 0x00800700,
|
||||
0x00c00700, 0x00000800, 0x00400800, 0x00800800, 0x00c00800, 0x00000900,
|
||||
0x00400900, 0x00800900, 0x00c00900, 0x00000a00, 0x00400a00, 0x00800a00,
|
||||
0x00c00a00, 0x00000b00, 0x00400b00, 0x00800b00, 0x00c00b00, 0x00000c00,
|
||||
0x00400c00, 0x00800c00, 0x00c00c00, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff
|
||||
};
|
||||
|
||||
|
||||
const uint32_t base64_table_dec_32bit_d3[256] = {
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0x003e0000, 0xffffffff, 0xffffffff, 0xffffffff, 0x003f0000,
|
||||
0x00340000, 0x00350000, 0x00360000, 0x00370000, 0x00380000, 0x00390000,
|
||||
0x003a0000, 0x003b0000, 0x003c0000, 0x003d0000, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000,
|
||||
0x00010000, 0x00020000, 0x00030000, 0x00040000, 0x00050000, 0x00060000,
|
||||
0x00070000, 0x00080000, 0x00090000, 0x000a0000, 0x000b0000, 0x000c0000,
|
||||
0x000d0000, 0x000e0000, 0x000f0000, 0x00100000, 0x00110000, 0x00120000,
|
||||
0x00130000, 0x00140000, 0x00150000, 0x00160000, 0x00170000, 0x00180000,
|
||||
0x00190000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0x001a0000, 0x001b0000, 0x001c0000, 0x001d0000, 0x001e0000,
|
||||
0x001f0000, 0x00200000, 0x00210000, 0x00220000, 0x00230000, 0x00240000,
|
||||
0x00250000, 0x00260000, 0x00270000, 0x00280000, 0x00290000, 0x002a0000,
|
||||
0x002b0000, 0x002c0000, 0x002d0000, 0x002e0000, 0x002f0000, 0x00300000,
|
||||
0x00310000, 0x00320000, 0x00330000, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff
|
||||
};
|
||||
|
||||
|
||||
#else
|
||||
|
||||
|
||||
/* SPECIAL DECODE TABLES FOR BIG ENDIAN (IBM/MOTOROLA/SUN) CPUS */
|
||||
|
||||
const uint32_t base64_table_dec_32bit_d0[256] = {
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xf8000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xfc000000,
|
||||
0xd0000000, 0xd4000000, 0xd8000000, 0xdc000000, 0xe0000000, 0xe4000000,
|
||||
0xe8000000, 0xec000000, 0xf0000000, 0xf4000000, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000,
|
||||
0x04000000, 0x08000000, 0x0c000000, 0x10000000, 0x14000000, 0x18000000,
|
||||
0x1c000000, 0x20000000, 0x24000000, 0x28000000, 0x2c000000, 0x30000000,
|
||||
0x34000000, 0x38000000, 0x3c000000, 0x40000000, 0x44000000, 0x48000000,
|
||||
0x4c000000, 0x50000000, 0x54000000, 0x58000000, 0x5c000000, 0x60000000,
|
||||
0x64000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0x68000000, 0x6c000000, 0x70000000, 0x74000000, 0x78000000,
|
||||
0x7c000000, 0x80000000, 0x84000000, 0x88000000, 0x8c000000, 0x90000000,
|
||||
0x94000000, 0x98000000, 0x9c000000, 0xa0000000, 0xa4000000, 0xa8000000,
|
||||
0xac000000, 0xb0000000, 0xb4000000, 0xb8000000, 0xbc000000, 0xc0000000,
|
||||
0xc4000000, 0xc8000000, 0xcc000000, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff
|
||||
};
|
||||
|
||||
|
||||
const uint32_t base64_table_dec_32bit_d1[256] = {
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0x03e00000, 0xffffffff, 0xffffffff, 0xffffffff, 0x03f00000,
|
||||
0x03400000, 0x03500000, 0x03600000, 0x03700000, 0x03800000, 0x03900000,
|
||||
0x03a00000, 0x03b00000, 0x03c00000, 0x03d00000, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000,
|
||||
0x00100000, 0x00200000, 0x00300000, 0x00400000, 0x00500000, 0x00600000,
|
||||
0x00700000, 0x00800000, 0x00900000, 0x00a00000, 0x00b00000, 0x00c00000,
|
||||
0x00d00000, 0x00e00000, 0x00f00000, 0x01000000, 0x01100000, 0x01200000,
|
||||
0x01300000, 0x01400000, 0x01500000, 0x01600000, 0x01700000, 0x01800000,
|
||||
0x01900000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0x01a00000, 0x01b00000, 0x01c00000, 0x01d00000, 0x01e00000,
|
||||
0x01f00000, 0x02000000, 0x02100000, 0x02200000, 0x02300000, 0x02400000,
|
||||
0x02500000, 0x02600000, 0x02700000, 0x02800000, 0x02900000, 0x02a00000,
|
||||
0x02b00000, 0x02c00000, 0x02d00000, 0x02e00000, 0x02f00000, 0x03000000,
|
||||
0x03100000, 0x03200000, 0x03300000, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff
|
||||
};
|
||||
|
||||
|
||||
const uint32_t base64_table_dec_32bit_d2[256] = {
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0x000f8000, 0xffffffff, 0xffffffff, 0xffffffff, 0x000fc000,
|
||||
0x000d0000, 0x000d4000, 0x000d8000, 0x000dc000, 0x000e0000, 0x000e4000,
|
||||
0x000e8000, 0x000ec000, 0x000f0000, 0x000f4000, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000,
|
||||
0x00004000, 0x00008000, 0x0000c000, 0x00010000, 0x00014000, 0x00018000,
|
||||
0x0001c000, 0x00020000, 0x00024000, 0x00028000, 0x0002c000, 0x00030000,
|
||||
0x00034000, 0x00038000, 0x0003c000, 0x00040000, 0x00044000, 0x00048000,
|
||||
0x0004c000, 0x00050000, 0x00054000, 0x00058000, 0x0005c000, 0x00060000,
|
||||
0x00064000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0x00068000, 0x0006c000, 0x00070000, 0x00074000, 0x00078000,
|
||||
0x0007c000, 0x00080000, 0x00084000, 0x00088000, 0x0008c000, 0x00090000,
|
||||
0x00094000, 0x00098000, 0x0009c000, 0x000a0000, 0x000a4000, 0x000a8000,
|
||||
0x000ac000, 0x000b0000, 0x000b4000, 0x000b8000, 0x000bc000, 0x000c0000,
|
||||
0x000c4000, 0x000c8000, 0x000cc000, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff
|
||||
};
|
||||
|
||||
|
||||
const uint32_t base64_table_dec_32bit_d3[256] = {
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0x00003e00, 0xffffffff, 0xffffffff, 0xffffffff, 0x00003f00,
|
||||
0x00003400, 0x00003500, 0x00003600, 0x00003700, 0x00003800, 0x00003900,
|
||||
0x00003a00, 0x00003b00, 0x00003c00, 0x00003d00, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000,
|
||||
0x00000100, 0x00000200, 0x00000300, 0x00000400, 0x00000500, 0x00000600,
|
||||
0x00000700, 0x00000800, 0x00000900, 0x00000a00, 0x00000b00, 0x00000c00,
|
||||
0x00000d00, 0x00000e00, 0x00000f00, 0x00001000, 0x00001100, 0x00001200,
|
||||
0x00001300, 0x00001400, 0x00001500, 0x00001600, 0x00001700, 0x00001800,
|
||||
0x00001900, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0x00001a00, 0x00001b00, 0x00001c00, 0x00001d00, 0x00001e00,
|
||||
0x00001f00, 0x00002000, 0x00002100, 0x00002200, 0x00002300, 0x00002400,
|
||||
0x00002500, 0x00002600, 0x00002700, 0x00002800, 0x00002900, 0x00002a00,
|
||||
0x00002b00, 0x00002c00, 0x00002d00, 0x00002e00, 0x00002f00, 0x00003000,
|
||||
0x00003100, 0x00003200, 0x00003300, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
1031
3rdparty/base64/lib/tables/table_enc_12bit.h
vendored
Normal file
45
3rdparty/base64/lib/tables/table_enc_12bit.py
vendored
Executable file
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
def tr(x):
|
||||
"""Translate a 6-bit value to the Base64 alphabet."""
|
||||
s = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' \
|
||||
+ 'abcdefghijklmnopqrstuvwxyz' \
|
||||
+ '0123456789' \
|
||||
+ '+/'
|
||||
return ord(s[x])
|
||||
|
||||
def table(fn):
|
||||
"""Generate a 12-bit lookup table."""
|
||||
ret = []
|
||||
for n in range(0, 2**12):
|
||||
pre = "\n\t" if n % 8 == 0 else " "
|
||||
pre = "\t" if n == 0 else pre
|
||||
ret.append("{}0x{:04X}U,".format(pre, fn(n)))
|
||||
return "".join(ret)
|
||||
|
||||
def table_be():
|
||||
"""Generate a 12-bit big-endian lookup table."""
|
||||
return table(lambda n: (tr(n & 0x3F) << 0) | (tr(n >> 6) << 8))
|
||||
|
||||
def table_le():
|
||||
"""Generate a 12-bit little-endian lookup table."""
|
||||
return table(lambda n: (tr(n >> 6) << 0) | (tr(n & 0x3F) << 8))
|
||||
|
||||
def main():
|
||||
"""Entry point."""
|
||||
lines = [
|
||||
"#include <stdint.h>",
|
||||
"",
|
||||
"const uint16_t base64_table_enc_12bit[] = {",
|
||||
"#if BASE64_LITTLE_ENDIAN",
|
||||
table_le(),
|
||||
"#else",
|
||||
table_be(),
|
||||
"#endif",
|
||||
"};"
|
||||
]
|
||||
for line in lines:
|
||||
print(line)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
184
3rdparty/base64/lib/tables/table_generator.c
vendored
Normal file
@@ -0,0 +1,184 @@
|
||||
/**
|
||||
*
|
||||
* Copyright 2005, 2006 Nick Galbreath -- nickg [at] modp [dot] com
|
||||
* Copyright 2017 Matthieu Darbois
|
||||
* All rights reserved.
|
||||
*
|
||||
* http://modp.com/release/base64
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
/****************************/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
static uint8_t b64chars[64] = {
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
|
||||
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
|
||||
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
|
||||
};
|
||||
|
||||
static uint8_t padchar = '=';
|
||||
|
||||
static void printStart(void)
|
||||
{
|
||||
printf("#include <stdint.h>\n");
|
||||
printf("#define CHAR62 '%c'\n", b64chars[62]);
|
||||
printf("#define CHAR63 '%c'\n", b64chars[63]);
|
||||
printf("#define CHARPAD '%c'\n", padchar);
|
||||
}
|
||||
|
||||
static void clearDecodeTable(uint32_t* ary)
|
||||
{
|
||||
int i = 0;
|
||||
for (i = 0; i < 256; ++i) {
|
||||
ary[i] = 0xFFFFFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
/* dump uint32_t as hex digits */
|
||||
void uint32_array_to_c_hex(const uint32_t* ary, size_t sz, const char* name)
|
||||
{
|
||||
size_t i = 0;
|
||||
|
||||
printf("const uint32_t %s[%d] = {\n", name, (int)sz);
|
||||
for (;;) {
|
||||
printf("0x%08" PRIx32, ary[i]);
|
||||
++i;
|
||||
if (i == sz)
|
||||
break;
|
||||
if (i % 6 == 0) {
|
||||
printf(",\n");
|
||||
} else {
|
||||
printf(", ");
|
||||
}
|
||||
}
|
||||
printf("\n};\n");
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
uint32_t x;
|
||||
uint32_t i = 0;
|
||||
uint32_t ary[256];
|
||||
|
||||
/* over-ride standard alphabet */
|
||||
if (argc == 2) {
|
||||
uint8_t* replacements = (uint8_t*)argv[1];
|
||||
if (strlen((char*)replacements) != 3) {
|
||||
fprintf(stderr, "input must be a string of 3 characters '-', '.' or '_'\n");
|
||||
exit(1);
|
||||
}
|
||||
fprintf(stderr, "fusing '%s' as replacements in base64 encoding\n", replacements);
|
||||
b64chars[62] = replacements[0];
|
||||
b64chars[63] = replacements[1];
|
||||
padchar = replacements[2];
|
||||
}
|
||||
|
||||
printStart();
|
||||
|
||||
printf("\n\n#if BASE64_LITTLE_ENDIAN\n");
|
||||
|
||||
printf("\n\n/* SPECIAL DECODE TABLES FOR LITTLE ENDIAN (INTEL) CPUS */\n\n");
|
||||
|
||||
clearDecodeTable(ary);
|
||||
for (i = 0; i < 64; ++i) {
|
||||
x = b64chars[i];
|
||||
ary[x] = i << 2;
|
||||
}
|
||||
uint32_array_to_c_hex(ary, sizeof(ary) / sizeof(uint32_t), "base64_table_dec_32bit_d0");
|
||||
printf("\n\n");
|
||||
|
||||
clearDecodeTable(ary);
|
||||
for (i = 0; i < 64; ++i) {
|
||||
x = b64chars[i];
|
||||
ary[x] = ((i & 0x30) >> 4) | ((i & 0x0F) << 12);
|
||||
}
|
||||
uint32_array_to_c_hex(ary, sizeof(ary) / sizeof(uint32_t), "base64_table_dec_32bit_d1");
|
||||
printf("\n\n");
|
||||
|
||||
clearDecodeTable(ary);
|
||||
for (i = 0; i < 64; ++i) {
|
||||
x = b64chars[i];
|
||||
ary[x] = ((i & 0x03) << 22) | ((i & 0x3c) << 6);
|
||||
}
|
||||
uint32_array_to_c_hex(ary, sizeof(ary) / sizeof(uint32_t), "base64_table_dec_32bit_d2");
|
||||
printf("\n\n");
|
||||
|
||||
clearDecodeTable(ary);
|
||||
for (i = 0; i < 64; ++i) {
|
||||
x = b64chars[i];
|
||||
ary[x] = i << 16;
|
||||
}
|
||||
uint32_array_to_c_hex(ary, sizeof(ary) / sizeof(uint32_t), "base64_table_dec_32bit_d3");
|
||||
printf("\n\n");
|
||||
|
||||
printf("#else\n");
|
||||
|
||||
printf("\n\n/* SPECIAL DECODE TABLES FOR BIG ENDIAN (IBM/MOTOROLA/SUN) CPUS */\n\n");
|
||||
|
||||
clearDecodeTable(ary);
|
||||
for (i = 0; i < 64; ++i) {
|
||||
x = b64chars[i];
|
||||
ary[x] = i << 26;
|
||||
}
|
||||
uint32_array_to_c_hex(ary, sizeof(ary) / sizeof(uint32_t), "base64_table_dec_32bit_d0");
|
||||
printf("\n\n");
|
||||
|
||||
clearDecodeTable(ary);
|
||||
for (i = 0; i < 64; ++i) {
|
||||
x = b64chars[i];
|
||||
ary[x] = i << 20;
|
||||
}
|
||||
uint32_array_to_c_hex(ary, sizeof(ary) / sizeof(uint32_t), "base64_table_dec_32bit_d1");
|
||||
printf("\n\n");
|
||||
|
||||
clearDecodeTable(ary);
|
||||
for (i = 0; i < 64; ++i) {
|
||||
x = b64chars[i];
|
||||
ary[x] = i << 14;
|
||||
}
|
||||
uint32_array_to_c_hex(ary, sizeof(ary) / sizeof(uint32_t), "base64_table_dec_32bit_d2");
|
||||
printf("\n\n");
|
||||
|
||||
clearDecodeTable(ary);
|
||||
for (i = 0; i < 64; ++i) {
|
||||
x = b64chars[i];
|
||||
ary[x] = i << 8;
|
||||
}
|
||||
uint32_array_to_c_hex(ary, sizeof(ary) / sizeof(uint32_t), "base64_table_dec_32bit_d3");
|
||||
printf("\n\n");
|
||||
|
||||
printf("#endif\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
40
3rdparty/base64/lib/tables/tables.c
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
#include "tables.h"
|
||||
|
||||
const uint8_t
|
||||
base64_table_enc_6bit[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789"
|
||||
"+/";
|
||||
|
||||
// In the lookup table below, note that the value for '=' (character 61) is
|
||||
// 254, not 255. This character is used for in-band signaling of the end of
|
||||
// the datastream, and we will use that later. The characters A-Z, a-z, 0-9
|
||||
// and + / are mapped to their "decoded" values. The other bytes all map to
|
||||
// the value 255, which flags them as "invalid input".
|
||||
|
||||
const uint8_t
|
||||
base64_table_dec_8bit[] =
|
||||
{
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // 0..15
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // 16..31
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63, // 32..47
|
||||
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 254, 255, 255, // 48..63
|
||||
255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // 64..79
|
||||
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, // 80..95
|
||||
255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, // 96..111
|
||||
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255, // 112..127
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // 128..143
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
};
|
||||
|
||||
#if BASE64_WORDSIZE >= 32
|
||||
# include "table_dec_32bit.h"
|
||||
# include "table_enc_12bit.h"
|
||||
#endif
|
||||
23
3rdparty/base64/lib/tables/tables.h
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
#ifndef BASE64_TABLES_H
|
||||
#define BASE64_TABLES_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "../env.h"
|
||||
|
||||
// These tables are used by all codecs for fallback plain encoding/decoding:
|
||||
extern const uint8_t base64_table_enc_6bit[];
|
||||
extern const uint8_t base64_table_dec_8bit[];
|
||||
|
||||
// These tables are used for the 32-bit and 64-bit generic decoders:
|
||||
#if BASE64_WORDSIZE >= 32
|
||||
extern const uint32_t base64_table_dec_32bit_d0[];
|
||||
extern const uint32_t base64_table_dec_32bit_d1[];
|
||||
extern const uint32_t base64_table_dec_32bit_d2[];
|
||||
extern const uint32_t base64_table_dec_32bit_d3[];
|
||||
|
||||
// This table is used by the 32 and 64-bit generic encoders:
|
||||
extern const uint16_t base64_table_enc_12bit[];
|
||||
#endif
|
||||
|
||||
#endif // BASE64_TABLES_H
|
||||
10
kitty/uthash.h → 3rdparty/uthash.h
vendored
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2003-2021, Troy D. Hanson http://troydhanson.github.io/uthash/
|
||||
Copyright (c) 2003-2022, Troy D. Hanson https://troydhanson.github.io/uthash/
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -51,6 +51,8 @@ typedef unsigned char uint8_t;
|
||||
#else /* VS2008 or older (or VS2010 in C mode) */
|
||||
#define NO_DECLTYPE
|
||||
#endif
|
||||
#elif defined(__MCST__) /* Elbrus C Compiler */
|
||||
#define DECLTYPE(x) (__typeof(x))
|
||||
#elif defined(__BORLANDC__) || defined(__ICCARM__) || defined(__LCC__) || defined(__WATCOMC__)
|
||||
#define NO_DECLTYPE
|
||||
#else /* GNU, Sun and other compilers */
|
||||
@@ -450,7 +452,7 @@ do {
|
||||
|
||||
#define HASH_DELETE_HH(hh,head,delptrhh) \
|
||||
do { \
|
||||
struct UT_hash_handle *_hd_hh_del = (delptrhh); \
|
||||
const struct UT_hash_handle *_hd_hh_del = (delptrhh); \
|
||||
if ((_hd_hh_del->prev == NULL) && (_hd_hh_del->next == NULL)) { \
|
||||
HASH_BLOOM_FREE((head)->hh.tbl); \
|
||||
uthash_free((head)->hh.tbl->buckets, \
|
||||
@@ -593,7 +595,9 @@ do {
|
||||
|
||||
|
||||
/* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at
|
||||
* http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */
|
||||
* http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx
|
||||
* (archive link: https://archive.is/Ivcan )
|
||||
*/
|
||||
#define HASH_SAX(key,keylen,hashv) \
|
||||
do { \
|
||||
unsigned _sx_i; \
|
||||
@@ -27,6 +27,7 @@ def compile_terminfo(base):
|
||||
os.makedirs(odir, exist_ok=True)
|
||||
ofile = os.path.join(odir, xterm_kitty)
|
||||
shutil.move(tfile, ofile)
|
||||
return ofile
|
||||
|
||||
|
||||
def generate_terminfo():
|
||||
@@ -46,7 +47,14 @@ def generate_terminfo():
|
||||
with open('terminfo/kitty.termcap', 'w') as f:
|
||||
f.write(tcap)
|
||||
|
||||
compile_terminfo(os.path.join(base, 'terminfo'))
|
||||
dbfile = compile_terminfo(os.path.join(base, 'terminfo'))
|
||||
with open(dbfile, 'rb') as f:
|
||||
data = f.read()
|
||||
with open('kitty/terminfo.h', 'w') as f:
|
||||
print(f'static const uint8_t terminfo_data[{len(data)}] = ''{', file=f)
|
||||
for b in data:
|
||||
print(b, end=', ', file=f)
|
||||
print('};', file=f)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -242,7 +242,9 @@ func dependencies(args []string) {
|
||||
chdir_to_base()
|
||||
nf := flag.NewFlagSet("deps", flag.ExitOnError)
|
||||
docsptr := nf.Bool("for-docs", false, "download the dependencies needed to build the documentation")
|
||||
nf.Parse(args)
|
||||
if err := nf.Parse(args); err != nil {
|
||||
exit(err)
|
||||
}
|
||||
if *docsptr {
|
||||
dependencies_for_docs()
|
||||
fmt.Println("Dependencies needed to generate documentation have been installed. Build docs with ./dev.sh docs")
|
||||
@@ -323,7 +325,7 @@ func dependencies(args []string) {
|
||||
}); err != nil {
|
||||
exit(err)
|
||||
}
|
||||
fmt.Println(`Dependencies downloaded. Now build kitty with: make develop`)
|
||||
fmt.Println(`Dependencies downloaded. Now build kitty with: ./dev.sh build`)
|
||||
}
|
||||
|
||||
// }}}
|
||||
@@ -384,7 +386,9 @@ func docs(args []string) {
|
||||
nf := flag.NewFlagSet("deps", flag.ExitOnError)
|
||||
livereload := nf.Bool("live-reload", false, "build the docs and make them available via s local server with live reloading for ease of development")
|
||||
failwarn := nf.Bool("fail-warn", false, "make warnings fatal when building the docs")
|
||||
nf.Parse(args)
|
||||
if err := nf.Parse(args); err != nil {
|
||||
exit(err)
|
||||
}
|
||||
exe := filepath.Join(root_dir(), "bin", "sphinx-build")
|
||||
aexe := filepath.Join(root_dir(), "bin", "sphinx-autobuild")
|
||||
target := "docs"
|
||||
|
||||
@@ -46,7 +46,7 @@ def run(*args, **extra_env):
|
||||
return subprocess.call(list(args), env=env, cwd=cwd)
|
||||
|
||||
|
||||
SETUP_CMD = [PYTHON, 'setup.py', '--build-universal-binary']
|
||||
SETUP_CMD = [PYTHON, 'setup.py']
|
||||
|
||||
|
||||
def build_frozen_launcher(extra_include_dirs):
|
||||
|
||||
@@ -250,6 +250,15 @@
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "simde",
|
||||
"unix": {
|
||||
"filename": "simde-amalgamated-0.7.6.tar.xz",
|
||||
"hash": "sha256:703eac1f2af7de1f7e4aea2286130b98e1addcc0559426e78304c92e2b4eb5e1",
|
||||
"urls": ["https://github.com/simd-everywhere/simde/releases/download/v0.7.6/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "wayland",
|
||||
"os": "linux",
|
||||
|
||||
@@ -5,12 +5,13 @@ import subprocess
|
||||
ls_files = subprocess.check_output([ 'git', 'ls-files']).decode('utf-8')
|
||||
all_files = set(ls_files.splitlines())
|
||||
all_files.discard('')
|
||||
cp = subprocess.run(['git', 'check-attr', 'linguist-generated', '--stdin'],
|
||||
check=True, stdout=subprocess.PIPE, input='\n'.join(all_files).encode('utf-8'))
|
||||
for line in cp.stdout.decode().splitlines():
|
||||
if line.endswith(' true'):
|
||||
fname = line.split(':', 1)[0]
|
||||
all_files.discard(fname)
|
||||
for attr in ('linguist-generated', 'linguist-vendored'):
|
||||
cp = subprocess.run(['git', 'check-attr', attr, '--stdin'],
|
||||
check=True, stdout=subprocess.PIPE, input='\n'.join(all_files).encode('utf-8'))
|
||||
for line in cp.stdout.decode().splitlines():
|
||||
if line.endswith(' true'):
|
||||
fname = line.split(':', 1)[0]
|
||||
all_files.discard(fname)
|
||||
|
||||
all_files -= {'gen/nerd-fonts-glyphs.txt', 'gen/rowcolumn-diacritics.txt'}
|
||||
cp = subprocess.run(['cloc', '--list-file', '-'], input='\n'.join(all_files).encode())
|
||||
|
||||
BIN
docs/_static/poster.png
vendored
|
Before Width: | Height: | Size: 80 KiB After Width: | Height: | Size: 76 KiB |
@@ -104,6 +104,8 @@ or another OS window::
|
||||
map ctrl+f3 detach_window tab-prev
|
||||
# moves the window into the tab at the left of the active tab
|
||||
map ctrl+f3 detach_window tab-left
|
||||
# moves the window into a new tab created to the left of the active tab
|
||||
map ctrl+f3 detach_window new-tab-left
|
||||
# asks which tab to move the window into
|
||||
map ctrl+f4 detach_window ask
|
||||
|
||||
|
||||
@@ -54,14 +54,14 @@ particular desktop, but it should work for most major desktop environments.
|
||||
cp ~/.local/kitty.app/share/applications/kitty.desktop ~/.local/share/applications/
|
||||
# If you want to open text files and images in kitty via your file manager also add the kitty-open.desktop file
|
||||
cp ~/.local/kitty.app/share/applications/kitty-open.desktop ~/.local/share/applications/
|
||||
# Update the paths to the kitty and its icon in the kitty.desktop file(s)
|
||||
# Update the paths to the kitty and its icon in the kitty desktop file(s)
|
||||
sed -i "s|Icon=kitty|Icon=/home/$USER/.local/kitty.app/share/icons/hicolor/256x256/apps/kitty.png|g" ~/.local/share/applications/kitty*.desktop
|
||||
sed -i "s|Exec=kitty|Exec=/home/$USER/.local/kitty.app/bin/kitty|g" ~/.local/share/applications/kitty*.desktop
|
||||
|
||||
.. note::
|
||||
In :file:`kitty-open.desktop`, kitty is registered to handle some supported
|
||||
MIME types. This will cause kitty to take precedence on some systems where
|
||||
the default apps are not explicitly set. For example, you expect to use
|
||||
the default apps are not explicitly set. For example, if you expect to use
|
||||
other GUI file managers to open dir paths when using commands such as
|
||||
:program:`xdg-open`, you should configure the default opener for the MIME
|
||||
type ``inode/directory``::
|
||||
|
||||
@@ -30,7 +30,7 @@ to build kitty with your changes.
|
||||
|
||||
.. note::
|
||||
If you plan to run kitty from source long-term, there are a couple of
|
||||
caveats to be aware of. You should occassionally run ``./dev.sh deps``
|
||||
caveats to be aware of. You should occasionally run ``./dev.sh deps``
|
||||
to have the dependencies re-downloaded as they are updated periodically.
|
||||
Also, the built kitty executable assumes it will find source in whatever
|
||||
directory you first ran :code:`./dev.sh build` in. If you move/rename the
|
||||
@@ -96,6 +96,7 @@ Run-time dependencies:
|
||||
Build-time dependencies:
|
||||
|
||||
* ``gcc`` or ``clang``
|
||||
* ``simde``
|
||||
* ``go`` >= _build_go_version (see :file:`go.mod` for go packages used during building)
|
||||
* ``pkg-config``
|
||||
* For building on Linux in addition to the above dependencies you might also
|
||||
@@ -115,6 +116,7 @@ Build-time dependencies:
|
||||
- ``libssl-dev``
|
||||
- ``libpython3-dev``
|
||||
- ``libxxhash-dev``
|
||||
- ``libsmide-dev``
|
||||
|
||||
|
||||
Build and run from source with Nix
|
||||
|
||||
@@ -9,40 +9,200 @@ To update |kitty|, :doc:`follow the instructions <binary>`.
|
||||
Recent major new features
|
||||
---------------------------
|
||||
|
||||
File transfer over the tty device
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Wayland goodies [0.34]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Transfer files to and from remote computers over the ``TTY`` device itself.
|
||||
This means that file transfer works over nested SSH sessions, serial links,
|
||||
etc. Anywhere you have a terminal device, you can transfer files.
|
||||
Wayland users should rejoice as kitty now comes with major Wayland
|
||||
quality-of-life improvements:
|
||||
|
||||
Simply ssh into a remote computer using the :doc:`ssh kitten </kittens/ssh>`
|
||||
and run the :doc:`transfer kitten </kittens/transfer>` (which the ssh kitten
|
||||
makes available for you on the remote computer automatically). For example, to
|
||||
copy a file from a remote computer::
|
||||
* Draw GPU accelerated :doc:`desktop panels and background </kittens/panel>`
|
||||
running arbitrary terminal programs. For example, run `btop
|
||||
<https://github.com/aristocratos/btop/>`__ as your desktop background
|
||||
|
||||
<local computer> $ kitten ssh my-remote-computer
|
||||
<remote computer> $ kitten transfer some-file /path/on/local/computer
|
||||
* Background blur for transparent windows is now supported under KDE
|
||||
using a custom KDE specific protocol
|
||||
|
||||
The kitten can transfer files to and from the remote computer. It supports
|
||||
recursive transfer of directories, symlinks and hardlinks. It can even use the
|
||||
rsync algorithm to speed up repeated transfers of large files.
|
||||
* The kitty window decorations in GNOME are now fully functional with buttons
|
||||
and they follow system dark/light mode automatically
|
||||
|
||||
Truly convenient SSH
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
* kitty now supports fractional scaling in Wayland which means pixel perfect
|
||||
rendering when you use a fractional scale with no wasted performance on
|
||||
resizing an overdrawn pixmap in the compositor
|
||||
|
||||
The :doc:`ssh kitten <kittens/ssh>` is redesigned with powerful new features:
|
||||
With this release kitty's Wayland support is now on par with X11, provided
|
||||
you use a decent Wayland compositor.
|
||||
|
||||
* Automatic :ref:`shell_integration` on remote machines
|
||||
* Easily :ref:`clone local shell/editor config <real_world_ssh_kitten_config>` on remote machines
|
||||
* Easily :ref:`edit files in your local editor <edit_file>` on remote machines
|
||||
* Automatic :opt:`re-use of existing connections <kitten-ssh.share_connections>` to avoid connection setup latency
|
||||
Cheetah speed 🐆 [0.33]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
kitty has grown up and become a cheetah. It now parses data it receives in
|
||||
parallel :iss:`using SIMD vector CPU instructions <7005>` for a 2x speedup in
|
||||
benchmarks and a 10%-50% real world speedup depending on workload. There is a
|
||||
new benchmarking kitten ``kitten __benchmark__`` that can be used to measure
|
||||
terminal throughput. There is also :ref:`a table <throughput>` showing kitty is
|
||||
much faster than other terminal emulators based on the benchmark kitten. While
|
||||
kitty was already so fast that its performance was never a bottleneck, this
|
||||
improvement makes it even faster and more importantly reduces the energy
|
||||
consumption to do the same tasks.
|
||||
|
||||
.. }}}
|
||||
|
||||
Detailed list of changes
|
||||
-------------------------------------
|
||||
|
||||
0.34.0 [2024-04-15]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- Wayland: :doc:`panel kitten <kittens/panel>`: Add support for drawing desktop background and bars
|
||||
using the panel kitten for all compositors that support the `requisite Wayland
|
||||
protocol <https://wayland.app/protocols/wlr-layer-shell-unstable-v1>`__ which is practically speaking all of them but GNOME (:pull:`2590`)
|
||||
|
||||
- Show a small :opt:`scrollback indicator <scrollback_indicator_opacity>` along the right window edge when viewing
|
||||
the scrollback to keep track of scroll position (:iss:`2502`)
|
||||
|
||||
- Wayland: Support fractional scales so that there is no wasted drawing at larger scale followed by resizing in the compositor
|
||||
|
||||
- Wayland KDE: Support :opt:`background_blur`
|
||||
|
||||
- Wayland GNOME: The window titlebar now has buttons to minimize/maximize/close the window
|
||||
|
||||
- Wayland GNOME: The window titlebar color now follows the system light/dark color scheme preference, see :opt:`wayland_titlebar_color`
|
||||
|
||||
- Wayland KDE: Fix mouse cursor hiding not working in Plasma 6 (:iss:`7265`)
|
||||
|
||||
- Wayland IME: Fix a bug with handling synthetic keypresses generated by ZMK keyboard + fcitx (:pull:`7283`)
|
||||
|
||||
- A new option :opt:`terminfo_type` to allow passing the terminfo database embedded into the :envvar:`TERMINFO` env var directly instead of via a file
|
||||
|
||||
- Mouse reporting: Fix drag release event outside the window not being reported in legacy mouse reporting modes (:iss:`7244`)
|
||||
|
||||
- macOS: Fix a regression in the previous release that broke rendering of some symbols on some systems (:iss:`7249`)
|
||||
|
||||
- Fix handling of tab character when cursor is at end of line and wrapping is enabled (:iss:`7250`)
|
||||
|
||||
- Splits layout: Fix :ac:`move_window_forward` not working (:iss:`7264`)
|
||||
|
||||
- macOS: Fix an abort due to an assertion when a program tries to set an invalid window title (:iss:`7271`)
|
||||
|
||||
- fish shell integration: Fix clicking at the prompt causing autosuggestions to be accepted, needs fish >= 3.8.0 (:iss:`7168`)
|
||||
|
||||
- Linux: Fix for a regression in 0.32.0 that caused some CJK fonts to not render glyphs (:iss:`7263`)
|
||||
|
||||
- Wayland: Support preferred integer scales
|
||||
|
||||
- Wayland: A new option :opt:`wayland_enable_ime` to turn off Input Method Extensions which add latency and create bugs
|
||||
|
||||
- Wayland: Fix :opt:`hide_window_decorations` not working on non GNOME desktops
|
||||
|
||||
- When asking for quit confirmation because of a running program, mention the program name (:iss:`7331`)
|
||||
|
||||
- Fix flickering of prompt during window resize (:iss:`7324`)
|
||||
|
||||
0.33.1 [2024-03-21]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- Fix a regression in the previous release that caused requesting data from the clipboard via OSC 52 to instead return data from the primary selection (:iss:`7213`)
|
||||
|
||||
- Splits layout: Allow resizing until one of the halves in a split is minimally sized (:iss:`7220`)
|
||||
|
||||
- macOS: Fix text rendered with fallback fonts not respecting bold/italic styling (:disc:`7241`)
|
||||
|
||||
- macOS: When CoreText fails to find a fallback font for a character in the first Private Use Unicode Area, preferentially use the NERD font, if available, for it (:iss:`6043`)
|
||||
|
||||
|
||||
0.33.0 [2024-03-12]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- :ref:`Cheetah speed <throughput>` with a redesigned render loop and a 2x faster escape code
|
||||
parser that uses SIMD CPU vector instruction to parse data in parallel
|
||||
(:iss:`7005`)
|
||||
|
||||
- A new benchmark kitten (``kitten __benchmark__``) to measure terminal
|
||||
throughput performance
|
||||
|
||||
- Graphics protocol: Add a new delete mode for deleting images whose ids fall within a range. Useful for bulk deletion (:iss:`7080`)
|
||||
|
||||
- Keyboard protocol: Fix the :kbd:`Enter`, :kbd:`Tab` and :kbd:`Backspace` keys
|
||||
generating spurious release events even when report all keys as escape codes
|
||||
is not set (:iss:`7136`)
|
||||
|
||||
- macOS: The command line args from :file:`macos-launch-services-cmdline` are now
|
||||
prefixed to any args from ``open --args`` rather than overwriting them (:iss:`7135`)
|
||||
|
||||
- Allow specifying where the new tab is created for :ac:`detach_window` (:pull:`7134`)
|
||||
|
||||
- hints kitten: The option to set the text color for hints now allows arbitrary
|
||||
colors (:pull:`7150`)
|
||||
|
||||
- icat kitten: Add a command line argument to override terminal window size detection (:iss:`7165`)
|
||||
|
||||
- A new action :ac:`toggle_tab` to easily switch to and back from a tab with a single shortcut (:iss:`7203`)
|
||||
|
||||
- When :ac:`clearing terminal <clear_terminal>` add a new type ``to_cursor_scroll`` which can be
|
||||
used to clear to prompt while moving cleared lines into the scrollback
|
||||
|
||||
- Fix a performance bottleneck when dealing with thousands of small images
|
||||
(:iss:`7080`)
|
||||
|
||||
- kitten @ ls: Return the timestamp at which the window was created (:iss:`7178`)
|
||||
|
||||
- hints kitten: Use default editor rather than hardcoding vim to open file at specific line (:iss:`7186`)
|
||||
|
||||
- Remote control: Fix ``--match`` argument not working for @ls, @send-key,
|
||||
@set-background-image (:iss:`7192`)
|
||||
|
||||
- Keyboard protocol: Do not deliver a fake key release events on OS window focus out for engaged modifiers (:iss:`7196`)
|
||||
|
||||
- Ignore :opt:`startup_session` when kitty is invoked with command line options specifying a command to run (:pull:`7198`)
|
||||
|
||||
- Box drawing: Specialize rendering for the Fira Code progress bar/spinner glyphs
|
||||
|
||||
0.32.2 [2024-02-12]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- kitten @ load-config: Allow (re)loading kitty.conf via remote control
|
||||
|
||||
- Remote control: Allow running mappable actions via remote control (`kitten @ action`)
|
||||
|
||||
- kitten @ send-text: Add a new option to automatically wrap the sent text in
|
||||
bracketed paste escape codes if the program in the destination window has
|
||||
turned on bracketed paste.
|
||||
|
||||
- Fix a single key mapping not overriding a previously defined multi-key mapping
|
||||
|
||||
- macOS: Fix :code:`kitten @ select-window` leaving the keyboard in a partially functional state (:iss:`7074`)
|
||||
|
||||
- Graphics protocol: Improve display of images using Unicode placeholders or
|
||||
row/column boxes by resizing them using linear instead of nearest neighbor
|
||||
interpolation on the GPU (:iss:`7070`)
|
||||
|
||||
- When matching URLs use the definition of legal characters in URLs from the
|
||||
`WHATWG spec <https://url.spec.whatwg.org/#url-code-points>`__ rather than older standards (:iss:`7095`)
|
||||
|
||||
- hints kitten: Respect the kitty :opt:`url_excluded_characters` option
|
||||
(:iss:`7075`)
|
||||
|
||||
- macOS: Fix an abort when changing OS window chrome for a full screen window via remote control or the themes kitten (:iss:`7106`)
|
||||
|
||||
- Special case rendering of some more box drawing characters using shades from the block of symbols for legacy computing (:iss:`7110`)
|
||||
|
||||
- A new action :ac:`close_other_os_windows` to close non active OS windows (:disc:`7113`)
|
||||
|
||||
0.32.1 [2024-01-26]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- macOS: Fix a regression in the previous release that broke overriding keyboard shortcuts for actions present in the global menu bar (:iss:`7016`)
|
||||
|
||||
- Fix a regression in the previous release that caused multi-key sequences to not abort when pressing an unknown key (:iss:`7022`)
|
||||
|
||||
- Fix a regression in the previous release that caused `kitten @ launch --cwd=current` to fail over SSH (:iss:`7028`)
|
||||
|
||||
- Fix a regression in the previous release that caused `kitten @ send-text` with a match tab parameter to send text twice to the active window (:iss:`7027`)
|
||||
|
||||
- Fix a regression in the previous release that caused overriding of existing multi-key mappings to fail (:iss:`7044`, :iss:`7058`)
|
||||
|
||||
- Wayland+NVIDIA: Do not request an sRGB output buffer as a bug in Wayland causes kitty to not start (:iss:`7021`)
|
||||
|
||||
0.32.0 [2024-01-19]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
@@ -211,16 +211,16 @@ def commit_role(
|
||||
' Link to a github commit '
|
||||
try:
|
||||
commit_id = subprocess.check_output(
|
||||
f'git rev-list --max-count=1 --skip=# {text}'.split()).decode('utf-8').strip()
|
||||
f'git rev-list --max-count=1 {text}'.split()).decode('utf-8').strip()
|
||||
except Exception:
|
||||
msg = inliner.reporter.error(
|
||||
f'GitHub commit id "{text}" not recognized.', line=lineno)
|
||||
f'git commit id "{text}" not recognized.', line=lineno)
|
||||
prb = inliner.problematic(rawtext, rawtext, msg)
|
||||
return [prb], [msg]
|
||||
url = f'https://github.com/kovidgoyal/kitty/commit/{commit_id}'
|
||||
set_classes(options)
|
||||
short_id = subprocess.check_output(
|
||||
f'git rev-list --max-count=1 --abbrev-commit --skip=# {commit_id}'.split()).decode('utf-8').strip()
|
||||
f'git rev-list --max-count=1 --abbrev-commit {commit_id}'.split()).decode('utf-8').strip()
|
||||
node = nodes.reference(rawtext, f'commit: {short_id}', refuri=url, **options)
|
||||
return [node], []
|
||||
# }}}
|
||||
|
||||
@@ -16,10 +16,10 @@ frames-per-second. See below for an overview of all customization possibilities.
|
||||
You can open the config file within kitty by pressing :sc:`edit_config_file`
|
||||
(:kbd:`⌘+,` on macOS). A :file:`kitty.conf` with commented default
|
||||
configurations and descriptions will be created if the file does not exist.
|
||||
You can reload the config file within kitty by pressing :sc:`reload_config_file`
|
||||
(:kbd:`⌃+⌘+,` on macOS) or sending kitty the ``SIGUSR1`` signal.
|
||||
You can also display the current configuration by pressing :sc:`debug_config`
|
||||
(:kbd:`⌥+⌘+,` on macOS).
|
||||
You can reload the config file within kitty by pressing
|
||||
:sc:`reload_config_file` (:kbd:`⌃+⌘+,` on macOS) or sending kitty the
|
||||
``SIGUSR1`` signal with ``kill -SIGUSR1 $KITTY_PID``. You can also display the
|
||||
current configuration by pressing :sc:`debug_config` (:kbd:`⌥+⌘+,` on macOS).
|
||||
|
||||
.. _confloc:
|
||||
|
||||
|
||||
25
docs/faq.rst
@@ -263,11 +263,12 @@ fonts to be freely resizable, so it does not support bitmapped fonts.
|
||||
symbols from it automatically, and you can tell it to do so explicitly in
|
||||
case it doesn't with the :opt:`symbol_map` directive::
|
||||
|
||||
# Nerd Fonts v2.3.3
|
||||
# Nerd Fonts v3.1.0
|
||||
|
||||
symbol_map U+23FB-U+23FE,U+2665,U+26A1,U+2B58,U+E000-U+E00A,U+E0A0-U+E0A3,U+E0B0-U+E0D4,U+E200-U+E2A9,U+E300-U+E3E3,U+E5FA-U+E6AA,U+E700-U+E7C5,U+EA60-U+EBEB,U+F000-U+F2E0,U+F300-U+F32F,U+F400-U+F4A9,U+F500-U+F8FF,U+F0001-U+F1AF0 Symbols Nerd Font Mono
|
||||
symbol_map U+e000-U+e00a,U+ea60-U+ebeb,U+e0a0-U+e0c8,U+e0ca,U+e0cc-U+e0d4,U+e200-U+e2a9,U+e300-U+e3e3,U+e5fa-U+e6b1,U+e700-U+e7c5,U+f000-U+f2e0,U+f300-U+f372,U+f400-U+f532,U+f0001-U+f1af0 Symbols Nerd Font Mono
|
||||
|
||||
Those Unicode symbols beyond the ``E000-F8FF`` Unicode private use area are
|
||||
Those Unicode symbols not in the `Unicode private use areas
|
||||
<https://en.wikipedia.org/wiki/Private_Use_Areas>`__ are
|
||||
not included.
|
||||
|
||||
If your font is not listed in ``kitty +list-fonts`` it means that it is not
|
||||
@@ -386,7 +387,7 @@ You can also change the icon manually by following the steps:
|
||||
How do I map key presses in kitty to different keys in the terminal program?
|
||||
--------------------------------------------------------------------------------------
|
||||
|
||||
This is accomplished by using ``map`` with :sc:`send_text <send_text>` in :file:`kitty.conf`.
|
||||
This is accomplished by using ``map`` with :ac:`send_key` in :file:`kitty.conf`.
|
||||
For example::
|
||||
|
||||
map alt+s send_key ctrl+s
|
||||
@@ -396,7 +397,8 @@ you press the :kbd:`alt+s` key. To see this in action, run::
|
||||
|
||||
kitten show-key -m kitty
|
||||
|
||||
Which will print out what key events it receives.
|
||||
Which will print out what key events it receives. To send arbitrary text rather
|
||||
than a key press, see :sc:`send_text <send_text>` instead.
|
||||
|
||||
|
||||
How do I open a new window or tab with the same working directory as the current window?
|
||||
@@ -447,9 +449,6 @@ do not use them, if at all possible. kitty contains features that do all of what
|
||||
tmux does, but better, with the exception of remote persistence (:iss:`391`).
|
||||
If you still want to use tmux, read on.
|
||||
|
||||
Image display will not work, see `tmux issue
|
||||
<https://github.com/tmux/tmux/issues/1391>`__.
|
||||
|
||||
Using ancient versions of tmux such as 1.8 will cause gibberish on screen when
|
||||
pressing keys (:iss:`3541`).
|
||||
|
||||
@@ -458,11 +457,17 @@ and then switch to another and these terminals have different :envvar:`TERM`
|
||||
variables, tmux will break. You will need to restart it as tmux does not support
|
||||
multiple terminfo definitions.
|
||||
|
||||
Displaying images while inside programs such as nvim or ranger may not work
|
||||
depending on whether those programs have adopted support for the :ref:`unicode
|
||||
placeholders <graphics_unicode_placeholders>` workaround that kitty created
|
||||
for tmux refusing to support images.
|
||||
|
||||
If you use any of the advanced features that kitty has innovated, such as
|
||||
:doc:`styled underlines </underlines>`, :doc:`desktop notifications
|
||||
</desktop-notifications>`, :doc:`extended keyboard support
|
||||
</keyboard-protocol>`, etc. they may or may not work, depending on the whims of
|
||||
tmux's maintainer, your version of tmux, etc.
|
||||
</keyboard-protocol>`, :doc:`file transfer </kittens/transfer>`, etc.
|
||||
they may or may not work, depending on the whims of tmux's maintainer,
|
||||
your version of tmux, etc.
|
||||
|
||||
|
||||
I opened and closed a lot of windows/tabs and top shows kitty's memory usage is very high?
|
||||
|
||||
@@ -164,7 +164,8 @@ Variables that kitty sets when running child programs
|
||||
|
||||
.. envvar:: TERMINFO
|
||||
|
||||
Path to a directory containing the kitty terminfo database.
|
||||
Path to a directory containing the kitty terminfo database. Or the terminfo
|
||||
database itself encoded in base64. See :opt:`terminfo_type`.
|
||||
|
||||
.. envvar:: KITTY_INSTALLATION_DIR
|
||||
|
||||
@@ -230,3 +231,11 @@ Variables that kitty sets when running child programs
|
||||
|
||||
Set to ``1`` when kitty is running a shell because of the ``--hold`` flag. Can
|
||||
be used to specialize shell behavior in the shell rc files as desired.
|
||||
|
||||
.. envvar:: KITTY_SIMD
|
||||
|
||||
Set it to ``128`` to use 128 bit vector registers, ``256`` to use 256 bit
|
||||
vector registers or any other value to prevent kitty from using SIMD CPU
|
||||
vector instructions. Warning, this overrides CPU capability detection so
|
||||
will cause kitty to crash with SIGILL if your CPU does not support the
|
||||
necessary SIMD extensions.
|
||||
|
||||
@@ -460,7 +460,10 @@ When you specify a placement id, it will be added to the acknowledgement code
|
||||
above. Every placement is uniquely identified by the pair of the ``image id``
|
||||
and the ``placement id``. If you specify a placement id for an image that does
|
||||
not have an id (i.e. has id=0), it will be ignored. In particular this means
|
||||
there can exist multiple images with ``image id=0, placement id=0``.
|
||||
there can exist multiple images with ``image id=0, placement id=0``. Not
|
||||
specifying a placement id or using ``p=0`` for multiple put commands (``a=p``)
|
||||
with the same non-zero image id results in multiple placements the image.
|
||||
|
||||
An example response::
|
||||
|
||||
<ESC>_Gi=<image id>,p=<placement id>;OK<ESC>\
|
||||
@@ -634,7 +637,7 @@ terminal may apply other heuristics (but it doesn't have to).
|
||||
It is important to distinguish between virtual image placements and real images
|
||||
displayed on top of Unicode placeholders. Virtual placements are invisible and only play
|
||||
the role of prototypes for real images. Virtual placements can be deleted by a
|
||||
deletion command only when the `d` key is equal to ``i``, ``I``, ``n`` or ``N``.
|
||||
deletion command only when the `d` key is equal to ``i``, ``I``, ``r``, ``R``, ``n`` or ``N``.
|
||||
The key values ``a``, ``c``, ``p``, ``q``, ``x``, ``y``, ``z`` and their capital
|
||||
variants never affect virtual placements because they do not have a physical
|
||||
location on the screen.
|
||||
@@ -726,13 +729,14 @@ scrollback buffer. The values of the ``x`` and ``y`` keys are the same as cursor
|
||||
Value of ``d`` Meaning
|
||||
================= ============
|
||||
``a`` or ``A`` Delete all placements visible on screen
|
||||
``i`` or ``I`` Delete all images with the specified id, specified using the ``i`` key. If you specify a ``p`` key for the placement id as well, then only the placement with the specified image id and placement id will be deleted.
|
||||
``i`` or ``I`` Delete all images with the specified id, specified using the ``i`` key. If you specify a ``p`` key for the placement id as well, then only the placement with the specified image id and placement id will be deleted.
|
||||
``n`` or ``N`` Delete newest image with the specified number, specified using the ``I`` key. If you specify a ``p`` key for the
|
||||
placement id as well, then only the placement with the specified number and placement id will be deleted.
|
||||
``c`` or ``C`` Delete all placements that intersect with the current cursor position.
|
||||
``f`` or ``F`` Delete animation frames.
|
||||
``p`` or ``P`` Delete all placements that intersect a specific cell, the cell is specified using the ``x`` and ``y`` keys
|
||||
``q`` or ``Q`` Delete all placements that intersect a specific cell having a specific z-index. The cell and z-index is specified using the ``x``, ``y`` and ``z`` keys.
|
||||
``r`` or ``R`` Delete all images whose id is greater than or equal to the value of the ``x`` key and less than or equal to the value of the ``y`` (added in kitty version 0.33.0).
|
||||
``x`` or ``X`` Delete all placements that intersect the specified column, specified using the ``x`` key.
|
||||
``y`` or ``Y`` Delete all placements that intersect the specified row, specified using the ``y`` key.
|
||||
``z`` or ``Z`` Delete all placements that have the specified z-index, specified using the ``z`` key.
|
||||
@@ -1080,9 +1084,11 @@ Key Value Default Description
|
||||
**Keys for deleting images**
|
||||
-----------------------------------------------------------
|
||||
``d`` Single character. ``a`` What to delete.
|
||||
``(a, A, c, C, n, N,
|
||||
i, I, p, P, q, Q, x,
|
||||
X, y, Y, z, Z)``.
|
||||
``(
|
||||
a, A, c, C, n, N,
|
||||
i, I, p, P, q, Q, r,
|
||||
R, x, X, y, Y, z, Z
|
||||
)``.
|
||||
======= ==================== ========= =================
|
||||
|
||||
|
||||
|
||||
@@ -164,6 +164,12 @@ Add this to bashrc and then to plot a function, simply do:
|
||||
|
||||
iplot 'sin(x*3)*exp(x*.2)'
|
||||
|
||||
.. tool_tgutui:
|
||||
|
||||
`tgutui <https://github.com/tgu-ltd/tgutui>`_
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
A Terminal Operating Test hardware equipment
|
||||
|
||||
.. tool_onefetch:
|
||||
|
||||
`onefetch <https://github.com/o2sh/onefetch>`_
|
||||
@@ -189,13 +195,6 @@ A tool to display weather information in your terminal with curl
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
View and manage the system clipboard under Wayland in your kitty terminal
|
||||
|
||||
.. tool_dmenu_term:
|
||||
|
||||
`dmenu-term <https://github.com/maximbaz/dmenu-term>`_
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Run applications on your system with fuzzy find inside a kitty window
|
||||
|
||||
|
||||
Editor integration
|
||||
-----------------------
|
||||
|
||||
|
||||
@@ -49,8 +49,10 @@ In addition to kitty, this protocol is also implemented in:
|
||||
* The `dte text editor <https://gitlab.com/craigbarnes/dte/-/issues/138>`__
|
||||
* The `Helix text editor <https://github.com/helix-editor/helix/pull/4939>`__
|
||||
* The `far2l file manager <https://github.com/elfmz/far2l/commit/e1f2ee0ef2b8332e5fa3ad7f2e4afefe7c96fc3b>`__
|
||||
* The `yazi file manager <https://github.com/sxyazi/yazi>`__
|
||||
* The `awrit web browser <https://github.com/chase/awrit>`__
|
||||
* The `nushell shell <https://github.com/nushell/nushell/pull/10540>`__
|
||||
* The `fish shell <https://github.com/fish-shell/fish-shell/commit/8bf8b10f685d964101f491b9cc3da04117a308b4>`__
|
||||
|
||||
.. versionadded:: 0.20.0
|
||||
|
||||
@@ -83,7 +85,7 @@ text (``CSI`` is the bytes ``0x1b 0x5b``)::
|
||||
The ``number`` in the first form above will be either the Unicode codepoint for a
|
||||
key, such as ``97`` for the :kbd:`a` key, or one of the numbers from the
|
||||
:ref:`functional` table below. The ``modifiers`` optional parameter encodes any
|
||||
modifiers pressed for the key event. The encoding is described in the
|
||||
modifiers active for the key event. The encoding is described in the
|
||||
:ref:`modifiers` section.
|
||||
|
||||
The second form is used for a few functional keys, such as the :kbd:`Home`,
|
||||
@@ -105,9 +107,7 @@ do not. When a key event produces text, the text is sent directly as UTF-8
|
||||
encoded bytes. This is safe as UTF-8 contains no C0 control codes.
|
||||
When the key event does not have text, the key event is encoded as an escape code. In
|
||||
legacy compatibility mode (the default) this uses legacy escape codes, so old terminal
|
||||
applications continue to work. Key events that could not be represented in
|
||||
legacy mode are encoded using a ``CSI u`` escape code, that most terminal
|
||||
programs should just ignore. For more advanced features, such as release/repeat
|
||||
applications continue to work. For more advanced features, such as release/repeat
|
||||
reporting etc., applications can tell the terminal they want this information by
|
||||
sending an escape code to :ref:`progressively enhance <progressive_enhancement>` the data reported for
|
||||
key events.
|
||||
@@ -181,10 +181,12 @@ bit field with::
|
||||
num_lock 0b10000000 (128)
|
||||
|
||||
In the escape code, the modifier value is encoded as a decimal number which is
|
||||
``1 + actual modifiers``. So to represent :kbd:`shift` only, the value would be ``1 +
|
||||
1 = 2``, to represent :kbd:`ctrl+shift` the value would be ``1 + 0b101 = 6``
|
||||
and so on. If the modifier field is not present in the escape code, its default
|
||||
value is ``1`` which means no modifiers.
|
||||
``1 + actual modifiers``. So to represent :kbd:`shift` only, the value would be
|
||||
``1 + 1 = 2``, to represent :kbd:`ctrl+shift` the value would be ``1 + 0b101 =
|
||||
6`` and so on. If the modifier field is not present in the escape code, its
|
||||
default value is ``1`` which means no modifiers. If a modifier is *active* when
|
||||
the key event occurs, i.e. if the key is pressed or the lock (for caps lock/num
|
||||
lock) is enabled, the key event must have the bit for that modifier set.
|
||||
|
||||
When the key event is related to an actual modifier key, the corresponding
|
||||
modifier's bit must be set to the modifier state including the effect for the
|
||||
@@ -229,8 +231,10 @@ enhancement <progressive_enhancement>` mechanism described below. Some examples:
|
||||
shift+a -> CSI 97 ; 2 ; 65 u # The text 'A' is reported as 65
|
||||
option+a -> CSI 97 ; ; 229 u # The text 'å' is reported as 229
|
||||
|
||||
If multiple code points are present, they must be separated by colons.
|
||||
If no known key is associated with the text the key number ``0`` must be used.
|
||||
If multiple code points are present, they must be separated by colons. If no
|
||||
known key is associated with the text the key number ``0`` must be used. The
|
||||
associated text must not contain control codes (control codes are code points
|
||||
below U+0020 and codepoints in the C0 and C1 blocks).
|
||||
|
||||
|
||||
Non-Unicode keys
|
||||
@@ -336,7 +340,9 @@ much easier to integrate into the application event loop. The only exceptions
|
||||
are the :kbd:`Enter`, :kbd:`Tab` and :kbd:`Backspace` keys which still generate the same
|
||||
bytes as in legacy mode this is to allow the user to type and execute commands
|
||||
in the shell such as ``reset`` after a program that sets this mode crashes
|
||||
without clearing it.
|
||||
without clearing it. Note that the Lock modifiers are not reported for text
|
||||
producing keys, to keep them useable in legacy programs. To get lock modifiers
|
||||
for all keys use the :ref:`report_all_keys` enhancement.
|
||||
|
||||
.. _report_events:
|
||||
|
||||
@@ -348,6 +354,13 @@ and key release events. Normally only key press events are reported and key
|
||||
repeat events are treated as key press events. See :ref:`event_types` for
|
||||
details on how these are reported.
|
||||
|
||||
.. note::
|
||||
|
||||
The :kbd:`Enter`, :kbd:`Tab` and :kbd:`Backspace` keys will not have release
|
||||
events unless :ref:`report_all_keys` is also set, so that the user can still
|
||||
type reset at a shell prompt when a program that sets this mode ends without
|
||||
resetting it.
|
||||
|
||||
.. _report_alternates:
|
||||
|
||||
Report alternate keys
|
||||
@@ -482,6 +495,12 @@ must correspond to the :kbd:`Backspace` key.
|
||||
All keypad keys are reported as their equivalent non-keypad keys. To
|
||||
distinguish these, use the :ref:`disambiguate <disambiguate>` flag.
|
||||
|
||||
Terminals may choose what they want to do about functional keys that have no
|
||||
legacy encoding. kitty chooses to encode these using ``CSI u`` encoding even in
|
||||
legacy mode, so that they become usable even in programs that do not
|
||||
understand the full kitty keyboard protocol. However, terminals may instead choose to
|
||||
ignore such keys in legacy mode instead, or have an option to control this behavior.
|
||||
|
||||
.. _legacy_text:
|
||||
|
||||
Legacy text keys
|
||||
|
||||
@@ -26,8 +26,10 @@ and adding them to the command line for the next command.
|
||||
|
||||
You can also press :sc:`goto_file_line` to select anything that looks like a
|
||||
path or filename followed by a colon and a line number and open the file in
|
||||
:program:`vim` at the specified line number. The patterns and editor to be used
|
||||
can be modified using options passed to the kitten. For example::
|
||||
your default editor at the specified line number (opening at line number will
|
||||
work only if your editor supports the +linenum command line syntax or is a
|
||||
"known" editor). The patterns and editor to be used can be modified using
|
||||
options passed to the kitten. For example::
|
||||
|
||||
map ctrl+g kitten hints --type=linenum --linenum-action=tab nvim +{line} {path}
|
||||
|
||||
|
||||
@@ -45,15 +45,29 @@ from inside other programs to display images. In particular, :option:`--place`,
|
||||
:option:`--detect-support` and :option:`--print-window-size`.
|
||||
|
||||
If you are trying to integrate icat into a complex program like a file manager
|
||||
or editor, there are a few things to keep in mind. icat works by communicating
|
||||
or editor, there are a few things to keep in mind. icat normally works by communicating
|
||||
over the TTY device, it both writes to and reads from the TTY. So it is
|
||||
imperative that while it is running the host program does not do any TTY I/O.
|
||||
Any key presses or other input from the user on the TTY device will be
|
||||
discarded. At a minimum, you should use the :option:`--transfer-mode`
|
||||
command line arguments. To be really robust you should
|
||||
consider writing proper support for the :doc:`kitty graphics protocol
|
||||
</graphics-protocol>` in the program instead. Nowadays there are many libraries
|
||||
that have support for it.
|
||||
discarded. If you would instead like to use it just as a backend to generate
|
||||
the escape codes for image display, you need to pass it options to tell it the
|
||||
window dimensions, where to place the image in the window and the transfer mode
|
||||
to use. If you do that, it will not try to communicate with the TTY device at
|
||||
all. The requisite options are: :option:`--use-window-size`, :option:`--place`
|
||||
and :option:`--transfer-mode`, :option:`--stdin=no`.
|
||||
For example, to demonstrate usage without access to the TTY:
|
||||
|
||||
.. code:: sh
|
||||
|
||||
zsh -c 'setsid kitten icat --stdin=no --use-window-size $COLUMNS,$LINES,3000,2000 --transfer-mode=file myimage.png'
|
||||
|
||||
Here, ``setsid`` ensures icat has no access to the TTY device.
|
||||
The values, 3000, 2000 are made up. They are the window width and height in
|
||||
pixels, to obtain which access to the TTY is needed.
|
||||
|
||||
To be really robust you should consider writing proper support for the
|
||||
:doc:`kitty graphics protocol </graphics-protocol>` in the program instead.
|
||||
Nowadays there are many libraries that have support for it.
|
||||
|
||||
|
||||
.. include:: /generated/cli-kitten-icat.rst
|
||||
|
||||
@@ -10,12 +10,12 @@ Draw a GPU accelerated dock panel on your desktop
|
||||
|
||||
|
||||
You can use this kitten to draw a GPU accelerated panel on the edge of your
|
||||
screen, that shows the output from an arbitrary terminal program.
|
||||
screen or as the desktop wallpaper, that shows the output from an arbitrary
|
||||
terminal program.
|
||||
|
||||
It is useful for showing status information or notifications on your desktop
|
||||
using terminal programs instead of GUI toolkits.
|
||||
|
||||
|
||||
.. figure:: ../screenshots/panel.png
|
||||
:alt: Screenshot, showing a sample panel
|
||||
:align: center
|
||||
@@ -28,18 +28,32 @@ The screenshot above shows a sample panel that displays the current desktop and
|
||||
window title as well as miscellaneous system information such as network
|
||||
activity, CPU load, date/time, etc.
|
||||
|
||||
.. versionadded:: 0.34.0
|
||||
Support for Wayland
|
||||
|
||||
.. note::
|
||||
|
||||
This kitten currently only works on X11 desktops
|
||||
This kitten currently only works on X11 desktops and Wayland compositors
|
||||
that support the `wlr layer shell protocol
|
||||
<https://wayland.app/protocols/wlr-layer-shell-unstable-v1#compositor-support>`__
|
||||
(which is almost all of them except the, as usual, crippled GNOME).
|
||||
|
||||
Using this kitten is simple, for example::
|
||||
|
||||
kitty +kitten panel sh -c 'printf "\n\n\nHello, world."; sleep 5s'
|
||||
|
||||
This will show ``Hello, world.`` at the top edge of your screen for five
|
||||
seconds. Here the terminal program we are running is :program:`sh` with a script
|
||||
seconds. Here, the terminal program we are running is :program:`sh` with a script
|
||||
to print out ``Hello, world!``. You can make the terminal program as complex as
|
||||
you like, as demonstrated in the screenshot above.
|
||||
|
||||
If you are on Wayland, you can, for instance run::
|
||||
|
||||
kitty +kitten panel --edge=background htop
|
||||
|
||||
to display htop as your desktop background. Remember this works in everything
|
||||
but GNOME and also, in sway, you have to disable the background wallpaper as
|
||||
sway renders that over the panel kitten surface.
|
||||
|
||||
|
||||
.. include:: ../generated/cli-kitten-panel.rst
|
||||
|
||||
@@ -141,7 +141,7 @@ The Splits Layout
|
||||
--------------------
|
||||
|
||||
This is the most flexible layout. You can create any arrangement of windows
|
||||
by splitting exiting windows repeatedly. To best use this layout you should
|
||||
by splitting existing windows repeatedly. To best use this layout you should
|
||||
define a few extra key bindings in :file:`kitty.conf`::
|
||||
|
||||
# Create a new window splitting the space used by the existing one so that
|
||||
|
||||
@@ -81,7 +81,7 @@ control scripts. To run a kitten on a key press::
|
||||
|
||||
map f1 kitten mykitten.py
|
||||
|
||||
Many of kitty;s features are themselves implemented as kittens, for example,
|
||||
Many of kitty's features are themselves implemented as kittens, for example,
|
||||
:doc:`/kittens/unicode_input`, :doc:`/kittens/hints` and
|
||||
:doc:`/kittens/themes`. To learn about writing your own kittens, see
|
||||
:doc:`/kittens/custom`.
|
||||
@@ -189,16 +189,46 @@ has :code:`keyboard protocol` in its title. Run the show-key kitten as::
|
||||
Press :kbd:`ctrl+shift+t` and instead of a new tab opening, you will
|
||||
see the key press being reported by the kitten. :code:`--when-focus-on` can test
|
||||
the focused window using very powerful criteria, see :ref:`search_syntax` for
|
||||
details. A more practical example unmaps the key when the focused window is running vim::
|
||||
details. A more practical example unmaps the key when the focused window is
|
||||
running an editor::
|
||||
|
||||
map --when-focus-on var:in_editor
|
||||
map --when-focus-on var:in_editor kitty_mod+c
|
||||
|
||||
In order to make this work, you need the following lines in your :file:`.vimrc`::
|
||||
In order to make this work, you need to configure your editor as show below:
|
||||
|
||||
let &t_ti = &t_ti . "\\033]1337;SetUserVar=in_editor=MQo\\007"
|
||||
let &t_te = &t_te . "\\033]1337;SetUserVar=in_editor\\007"
|
||||
.. tab:: vim
|
||||
|
||||
These cause vim to set the :code:`in_editor` variable in kitty and unset it when leaving vim.
|
||||
In :file:`~/.vimrc` add:
|
||||
.. code-block:: vim
|
||||
|
||||
let &t_ti = &t_ti . "\\033]1337;SetUserVar=in_editor=MQo\\007"
|
||||
let &t_te = &t_te . "\\033]1337;SetUserVar=in_editor\\007"
|
||||
|
||||
.. tab:: neovim
|
||||
|
||||
In :file:`~/.config/nvim/init.lua` add:
|
||||
|
||||
.. code-block:: lua
|
||||
|
||||
vim.api.nvim_create_autocmd({ "VimEnter", "VimResume" }, {
|
||||
group = vim.api.nvim_create_augroup("KittySetVarVimEnter", { clear = true }),
|
||||
callback = function()
|
||||
io.stdout:write("\x1b]1337;SetUserVar=in_editor=MQo\007")
|
||||
end,
|
||||
})
|
||||
|
||||
vim.api.nvim_create_autocmd({ "VimLeave", "VimSuspend" }, {
|
||||
group = vim.api.nvim_create_augroup("KittyUnsetVarVimLeave", { clear = true }),
|
||||
callback = function()
|
||||
io.stdout:write("\x1b]1337;SetUserVar=in_editor\007")
|
||||
end,
|
||||
})
|
||||
|
||||
These cause the editor to set the :code:`in_editor` variable in kitty and unset it when exiting.
|
||||
As a result, the :kbd:`ctrl+shift+c` key will be passed to the editor instead of
|
||||
copying to clipboard. In the editor, you can map it to copy to the clipboard,
|
||||
thereby allowing use of a common shortcut both inside and outside the editor
|
||||
for copying to clipboard.
|
||||
|
||||
Sending arbitrary text or keys to the program running in kitty
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
@@ -251,8 +251,11 @@ The scrollback buffer
|
||||
-----------------------
|
||||
|
||||
|kitty| supports scrolling back to view history, just like most terminals. You
|
||||
can use either keyboard shortcuts or the mouse scroll wheel to do so. However,
|
||||
|kitty| has an extra, neat feature. Sometimes you need to explore the scrollback
|
||||
can use either keyboard shortcuts or the mouse scroll wheel to do so. While
|
||||
you are browsing the scrollback a :opt:`small indicator <scrollback_indicator_opacity>`
|
||||
is displayed along the right edge of the window to show how far back you are.
|
||||
|
||||
However, |kitty| has an extra, neat feature. Sometimes you need to explore the scrollback
|
||||
buffer in more detail, maybe search for some text or refer to it side-by-side
|
||||
while typing in a follow-up command. |kitty| allows you to do this by pressing
|
||||
the :sc:`show_scrollback` shortcut, which will open the scrollback buffer in
|
||||
|
||||
@@ -3,10 +3,14 @@ Performance
|
||||
|
||||
The main goals for |kitty| performance are user perceived latency while typing
|
||||
and "smoothness" while scrolling as well as CPU usage. |kitty| tries hard to
|
||||
find an optimum balance for these. To that end it keeps a cache of each rendered
|
||||
glyph in video RAM so that font rendering is not a bottleneck. Interaction with
|
||||
child programs takes place in a separate thread from rendering, to improve
|
||||
smoothness.
|
||||
find an optimum balance for these. To that end it keeps a cache of each
|
||||
rendered glyph in video RAM so that font rendering is not a bottleneck.
|
||||
Interaction with child programs takes place in a separate thread from
|
||||
rendering, to improve smoothness. Parsing of the byte stream is done using
|
||||
`vector CPU instructions
|
||||
<https://en.wikipedia.org/wiki/Single_instruction,_multiple_data>`__ for
|
||||
maximum performance. Updates to the screen typically require sending just a few
|
||||
bytes to the GPU.
|
||||
|
||||
There are two config options you can tune to adjust the performance,
|
||||
:opt:`repaint_delay` and :opt:`input_delay`. These control the artificial delays
|
||||
@@ -15,19 +19,110 @@ introduced into the render loop to reduce CPU usage. See
|
||||
option to further decrease latency at the cost of some `screen tearing
|
||||
<https://en.wikipedia.org/wiki/Screen_tearing>`__ while scrolling.
|
||||
|
||||
You can generate detailed per-function performance data using
|
||||
`gperftools <https://github.com/gperftools/gperftools>`__. Build |kitty| with
|
||||
``make profile``. Run kitty and perform the task you want to analyse, for
|
||||
example, scrolling a large file with :program:`less`. After you quit, function
|
||||
call statistics will be printed to STDOUT and you can use tools like
|
||||
*KCachegrind* for more detailed analysis.
|
||||
Benchmarks
|
||||
-------------
|
||||
|
||||
Here are some CPU usage numbers for the task of scrolling a file continuously in
|
||||
:program:`less`. The CPU usage is for the terminal process and X together and is
|
||||
measured using :program:`htop`. The measurements are taken at the same font and
|
||||
window size for all terminals on a ``Intel(R) Core(TM) i7-4820K CPU @ 3.70GHz``
|
||||
CPU with a ``Advanced Micro Devices, Inc. [AMD/ATI] Cape Verde XT [Radeon HD
|
||||
7770/8760 / R7 250X]`` GPU.
|
||||
Measuring terminal emulator performance is fairly subtle, there are three main
|
||||
axes on which performance is measured: Energy usage for typical tasks,
|
||||
Keyboard to screen latency, and throughput (processing large amounts of data).
|
||||
|
||||
Keyboard to screen latency
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This is measured either with dedicated hardware, or software such as `Typometer
|
||||
<https://pavelfatin.com/typometer/>`__. Third party measurements comparing
|
||||
kitty with other terminal emulators on various systems show kitty has best in
|
||||
class keyboard to screen latency.
|
||||
|
||||
Note that to minimize latency at the expense of more energy usage, use the
|
||||
following settings in kitty.conf::
|
||||
|
||||
input_delay 0
|
||||
repaint_delay 2
|
||||
sync_to_monitor no
|
||||
wayland_enable_ime no
|
||||
|
||||
`Hardware based measurement on macOS
|
||||
<https://thume.ca/2020/05/20/making-a-latency-tester/>`__ show that kitty and
|
||||
Apple's Terminal.app share the crown for best latency. These
|
||||
measurements were done with :opt:`input_delay` at its default value of ``3 ms``
|
||||
which means kitty's actual numbers would be even lower.
|
||||
|
||||
`Typometer based measurements on Linux
|
||||
<https://github.com/kovidgoyal/kitty/issues/2701#issuecomment-911089374>`__
|
||||
show that kitty has far and away the best latency of the terminals tested.
|
||||
|
||||
.. _throughput:
|
||||
|
||||
Throughput
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
kitty has a builtin kitten to measure throughput, it works by dumping large
|
||||
amounts of data of different types into the tty device and measuring how fast
|
||||
the terminal parses and responds to it. The measurements below were taken with
|
||||
the same font, font size and window size for all terminals, and default
|
||||
settings, on the same computer. They clearly show kitty has the fastest
|
||||
throughput. To run the tests yourself, run ``kitten __benchmark__`` in the
|
||||
terminal emulator you want to test, where the kitten binary is part of the
|
||||
kitty install.
|
||||
|
||||
The numbers are megabytes per second of data that the terminal
|
||||
processes. Measurements were taken under Linux/X11 with an ``AMD Ryzen 7 PRO
|
||||
5850U``. Entries are in order of decreasing performance. kitty is twice
|
||||
as fast as the next best.
|
||||
|
||||
================ ====== ======= ===== ====== =======
|
||||
Terminal ASCII Unicode CSI Images Average
|
||||
================ ====== ======= ===== ====== =======
|
||||
kitty 0.33 121.8 105.0 59.8 251.6 134.55
|
||||
gnometerm 3.50.1 33.4 55.0 16.1 142.8 61.83
|
||||
alacritty 0.13.1 43.1 46.5 32.5 94.1 54.05
|
||||
wezterm 20230712 16.4 26.0 11.1 140.5 48.5
|
||||
xterm 389 47.7 18.3 0.6 56.3 30.72
|
||||
konsole 23.08.04 25.2 37.7 23.6 23.4 27.48
|
||||
alacritty+tmux 30.3 7.8 14.7 46.1 24.73
|
||||
================ ====== ======= ===== ====== =======
|
||||
|
||||
In this table, each column represents different types of data. The CSI column
|
||||
is for data consisting of a mix of typical formatting escape codes and some
|
||||
ASCII only text.
|
||||
|
||||
.. note::
|
||||
|
||||
By default, the benchmark kitten suppresses actual rendering, to better
|
||||
focus on parser speed, you can pass it the ``--render`` flag to not suppress
|
||||
rendering. However, modern terminals typically render asynchronously,
|
||||
therefore the numbers are not really useful for comparison, as it is just a
|
||||
game about how much input to *batch* before rendering the next frame.
|
||||
However, even with rendering enabled kitty is still faster than all the
|
||||
rest. For brevity those numbers are not included.
|
||||
|
||||
.. note::
|
||||
|
||||
foot, iterm2 and Terminal.app are left out as they do not run under X11.
|
||||
Alacritty+tmux is included just to show the effect of putting a terminal
|
||||
multiplexer into the mix (halving throughput) and because alacritty isnt
|
||||
remotely comparable to any of the other terminals feature wise without tmux.
|
||||
|
||||
.. note::
|
||||
|
||||
konsole, gnome-terminal and xterm do not support the `Synchronized update
|
||||
<https://gitlab.com/gnachman/iterm2/-/wikis/synchronized-updates-spec>`__
|
||||
escape code used to suppress rendering, if and when they gain support for it
|
||||
their numbers are likely to improve by ``20 - 50%``, depending on how well they
|
||||
implement it.
|
||||
|
||||
|
||||
Energy usage
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
Sadly, I do not have the infrastructure to measure actual energy usage so CPU
|
||||
usage will have to stand in for it. Here are some CPU usage numbers for the
|
||||
task of scrolling a file continuously in :program:`less`. The CPU usage is for
|
||||
the terminal process and X together and is measured using :program:`htop`. The
|
||||
measurements are taken at the same font and window size for all terminals on a
|
||||
``Intel(R) Core(TM) i7-4820K CPU @ 3.70GHz`` CPU with a ``Advanced Micro
|
||||
Devices, Inc. [AMD/ATI] Cape Verde XT [Radeon HD 7770/8760 / R7 250X]`` GPU.
|
||||
|
||||
============== =========================
|
||||
Terminal CPU usage (X + terminal)
|
||||
@@ -40,21 +135,16 @@ gnome-terminal 15 - 17%
|
||||
konsole 29 - 31%
|
||||
============== =========================
|
||||
|
||||
|
||||
As you can see, |kitty| uses much less CPU than all terminals, except xterm, but
|
||||
its scrolling "smoothness" is much better than that of xterm (at least to my,
|
||||
admittedly biased, eyes).
|
||||
|
||||
Instrumenting kitty
|
||||
-----------------------
|
||||
|
||||
.. _perf-cat:
|
||||
|
||||
.. note::
|
||||
|
||||
Some people have asked why kitty does not perform better than terminal XXX
|
||||
in the test of sinking large amounts of data, such as catting a large text
|
||||
file. The answer is because this is not a goal for kitty. kitty deliberately
|
||||
throttles input parsing and output rendering to minimize resource usage
|
||||
while still being able to sink output faster than any real world program can
|
||||
produce it. Reducing CPU usage, and hence battery drain while achieving
|
||||
instant response times and smooth scrolling to a human eye is a far more
|
||||
important goal.
|
||||
You can generate detailed per-function performance data using
|
||||
`gperftools <https://github.com/gperftools/gperftools>`__. Build |kitty| with
|
||||
``make profile``. Run kitty and perform the task you want to analyse, for
|
||||
example, scrolling a large file with :program:`less`. After you quit, function
|
||||
call statistics will be displayed in *KCachegrind*. Hence, profiling is best done
|
||||
on Linux which has these tools easily available.
|
||||
|
||||
|
Before Width: | Height: | Size: 118 KiB After Width: | Height: | Size: 105 KiB |
|
Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 8.6 KiB |
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 958 KiB After Width: | Height: | Size: 870 KiB |
|
Before Width: | Height: | Size: 111 KiB After Width: | Height: | Size: 103 KiB |
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 110 KiB After Width: | Height: | Size: 100 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 23 KiB |