mirror of
https://github.com/kovidgoyal/kitty
synced 2026-06-14 04:28:00 +02:00
Compare commits
920 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
eb5dd364ae | ||
|
|
4a64f812ad | ||
|
|
c2acc2460b | ||
|
|
bea8fd25a7 | ||
|
|
1593baa9f9 | ||
|
|
0447b17af2 | ||
|
|
0d3c5497ff | ||
|
|
7826fefe30 | ||
|
|
10ca74f502 | ||
|
|
715548b144 | ||
|
|
43df7be977 | ||
|
|
9b5f665218 | ||
|
|
5e934c081e | ||
|
|
22dbc94c5f | ||
|
|
2df1273d53 | ||
|
|
54900183ec | ||
|
|
1c72a94b2f | ||
|
|
46bb027d14 | ||
|
|
37f0c8c0a8 | ||
|
|
cad7047a7a | ||
|
|
e6acc69460 | ||
|
|
40d8111717 | ||
|
|
970cc9ba7a | ||
|
|
6e685d01b0 | ||
|
|
b8c5c62585 | ||
|
|
7427e65f60 | ||
|
|
e656a75d5e | ||
|
|
1e249035c7 | ||
|
|
044f53b35b | ||
|
|
e20eff277b | ||
|
|
5ea1d14617 | ||
|
|
1bea64768e | ||
|
|
ab2af0c141 | ||
|
|
0a2fcf1805 | ||
|
|
858f0c1073 | ||
|
|
fb1124b1b9 | ||
|
|
c76db4bfb4 | ||
|
|
1e5d14c834 | ||
|
|
5583f60289 | ||
|
|
4519b3abee | ||
|
|
cff490f881 | ||
|
|
7d8c017215 | ||
|
|
91cdf4af00 | ||
|
|
79db8b43e0 | ||
|
|
c03d99e744 | ||
|
|
7c0cb5481f | ||
|
|
912c5ce4f9 | ||
|
|
39a3c38037 | ||
|
|
5dfe4427cf | ||
|
|
b2eac37164 | ||
|
|
ec8b7853c5 | ||
|
|
d9903f5283 | ||
|
|
ccfb979218 | ||
|
|
ff8387f8e7 | ||
|
|
017947de7f | ||
|
|
2a5ba519f5 | ||
|
|
b2587c1d54 | ||
|
|
7e5230e6f4 | ||
|
|
64cfe8171f | ||
|
|
a9b424e307 | ||
|
|
d9ccbcd0ce | ||
|
|
7cec82f453 | ||
|
|
18c0a449d2 | ||
|
|
00f8f340bf | ||
|
|
e9e889457d | ||
|
|
d41138c4c6 | ||
|
|
69a5c7e3b2 | ||
|
|
92befa26db | ||
|
|
22ac57c374 | ||
|
|
392a301cd8 | ||
|
|
a1f2a7df4d | ||
|
|
04eafbea9b | ||
|
|
cf6c00cebe | ||
|
|
08da87a622 | ||
|
|
59e3b202b9 | ||
|
|
a7bdbb11f2 | ||
|
|
b9fabc62a5 | ||
|
|
d483c3eb33 | ||
|
|
d191896528 | ||
|
|
ca6c607148 | ||
|
|
cc5424c054 | ||
|
|
77551cdfc1 | ||
|
|
c6eab841f9 | ||
|
|
99995fd9dc | ||
|
|
74388b4183 | ||
|
|
f1fc2126bc | ||
|
|
9a0e84293f | ||
|
|
847ef008e2 | ||
|
|
3c4f2aa1b8 | ||
|
|
6c8f499303 | ||
|
|
b0ba4b4a42 | ||
|
|
293cd40509 | ||
|
|
0d10ee1a8c | ||
|
|
d63b852b90 | ||
|
|
9560968a7d | ||
|
|
53980d00f0 | ||
|
|
5bc2cde454 | ||
|
|
d4ff54e0d8 | ||
|
|
f2075f99fd | ||
|
|
f46425c2f9 | ||
|
|
ad4e9bb42c | ||
|
|
97f5cad335 | ||
|
|
788295e534 | ||
|
|
336035f507 | ||
|
|
1883208cf6 | ||
|
|
8d1fde18f8 | ||
|
|
d7633b95d0 | ||
|
|
165f1ccfd1 | ||
|
|
063a663958 | ||
|
|
66bc86e4f2 | ||
|
|
15eb03c5e2 | ||
|
|
c064a2e559 | ||
|
|
9e815212dc | ||
|
|
cb418a0040 | ||
|
|
716bf714db | ||
|
|
f11f770011 | ||
|
|
8a1571f62c | ||
|
|
3876d518bd | ||
|
|
72e14053f5 | ||
|
|
bd7f38eb7d | ||
|
|
e19335377f | ||
|
|
382d2f1ed0 | ||
|
|
9bb85bd294 | ||
|
|
c10ea63818 | ||
|
|
4b3d29ecc3 | ||
|
|
b297c27e09 | ||
|
|
6a09804910 | ||
|
|
c2b4df0666 | ||
|
|
79f3692f1e | ||
|
|
35b2dcb065 | ||
|
|
2b751f56bd | ||
|
|
882d471c90 | ||
|
|
fc64ef41b3 | ||
|
|
b1e4c06220 | ||
|
|
ef9dada80d | ||
|
|
6d49686aee | ||
|
|
3cbb8d5c8f | ||
|
|
ea28e20915 | ||
|
|
4897c4df00 | ||
|
|
b3c5b1185c | ||
|
|
b961e65f22 | ||
|
|
6d9593944a | ||
|
|
a0d5f7a07b | ||
|
|
69e3e5c727 | ||
|
|
04506975e5 | ||
|
|
b5067c1369 | ||
|
|
0f52b69372 | ||
|
|
24bb28b773 | ||
|
|
553d833fd4 | ||
|
|
2d5ce6191e | ||
|
|
5fe77e38b7 | ||
|
|
9a08489112 | ||
|
|
2047ea8eec | ||
|
|
4d510e3318 | ||
|
|
87f7bd2f9e | ||
|
|
2ffe03ee48 | ||
|
|
4c56e76840 | ||
|
|
a3c8f32c1a | ||
|
|
176ffc7f51 | ||
|
|
70bc4f1033 | ||
|
|
0f2196357c | ||
|
|
2759ec1fe1 | ||
|
|
dee2e83fb4 | ||
|
|
65754a2032 | ||
|
|
77292a16d6 | ||
|
|
2402c6f253 | ||
|
|
77140fc798 | ||
|
|
cda97b5451 | ||
|
|
b247fda672 | ||
|
|
8dfe1fcca9 | ||
|
|
a6f13a64dc | ||
|
|
bd5fcb00e0 | ||
|
|
ac2ec44a7f | ||
|
|
d2444bae80 | ||
|
|
a6571ba8db | ||
|
|
5fab30b36f | ||
|
|
9a179a7e90 | ||
|
|
bc1da5525e | ||
|
|
995112d952 | ||
|
|
169315d33d | ||
|
|
114b8dff51 | ||
|
|
61429c73c7 | ||
|
|
2aa37de6ff | ||
|
|
a54586dfa9 | ||
|
|
b4f88b4f81 | ||
|
|
954b7f87a5 | ||
|
|
d113a6c2cf | ||
|
|
52cebf0150 | ||
|
|
827a7d5094 | ||
|
|
a04d19df4a | ||
|
|
7e1580ef09 | ||
|
|
f3ece8b7c4 | ||
|
|
be3b8fcfb7 | ||
|
|
9d5bb3b2f2 | ||
|
|
492ec3dfbf | ||
|
|
309a6e9319 | ||
|
|
12db4683ac | ||
|
|
30b736eed7 | ||
|
|
4d085a00e1 | ||
|
|
dfd84d85a2 | ||
|
|
cb139692f5 | ||
|
|
47836f5086 | ||
|
|
778adfcd3d | ||
|
|
24d9d502b1 | ||
|
|
8dadcf568c | ||
|
|
0f02725f50 | ||
|
|
3beb1e454a | ||
|
|
c174c3cb38 | ||
|
|
f05a58f363 | ||
|
|
9f42e915c8 | ||
|
|
52d5a4679f | ||
|
|
aee14a49f0 | ||
|
|
acf586867c | ||
|
|
7cb392c7ab | ||
|
|
f8d5e30300 | ||
|
|
be5a0e8559 | ||
|
|
7cffb2a714 | ||
|
|
6111bc8ed6 | ||
|
|
1c1519c6e4 | ||
|
|
b55883591d | ||
|
|
ae4a13b249 | ||
|
|
61c4f80e90 | ||
|
|
0ce996120a | ||
|
|
47b8b442dc | ||
|
|
32d23921df | ||
|
|
19374208e0 | ||
|
|
8c83284d5e | ||
|
|
9c25a183db | ||
|
|
24895f0225 | ||
|
|
eefb865e6e | ||
|
|
b1ec1c2678 | ||
|
|
ce583ea460 | ||
|
|
539a8706dc | ||
|
|
467e7e5041 | ||
|
|
d94a5bd386 | ||
|
|
480737a355 | ||
|
|
d63739a598 | ||
|
|
3526e59d3b | ||
|
|
7292d1c9df | ||
|
|
c9a95cacd9 | ||
|
|
8853f6bae2 | ||
|
|
beb18cc250 | ||
|
|
321f1a6650 | ||
|
|
8d8d89573c | ||
|
|
89ee128a92 | ||
|
|
defa2e29ac | ||
|
|
56963c693e | ||
|
|
f098240ace | ||
|
|
4b997a961c | ||
|
|
512a672398 | ||
|
|
6cfb451ec8 | ||
|
|
4a463f7712 | ||
|
|
5ea9700c82 | ||
|
|
1332cf8ac7 | ||
|
|
f8ab5f3f67 | ||
|
|
822311d523 | ||
|
|
713569fcfa | ||
|
|
7d32a77fe4 | ||
|
|
314fe4fe4a | ||
|
|
a9b412baba | ||
|
|
0300a355d0 | ||
|
|
fa53ac7896 | ||
|
|
cb15b98afd | ||
|
|
6a50af12d3 | ||
|
|
45a98b19c5 | ||
|
|
e9e1a7a7c3 | ||
|
|
6804d16519 | ||
|
|
ee8399ba56 | ||
|
|
c03dff2322 | ||
|
|
dc6edf9191 | ||
|
|
70a588cb36 | ||
|
|
81b032a161 | ||
|
|
ddb121b418 | ||
|
|
d2026574b8 | ||
|
|
187fa996f8 | ||
|
|
870522a792 | ||
|
|
5478f6665a | ||
|
|
5d5bbe9b96 | ||
|
|
3a6c7e78df | ||
|
|
10a2f246bc | ||
|
|
17ce474b79 | ||
|
|
d66074f19f | ||
|
|
1693107608 | ||
|
|
e15b16b072 | ||
|
|
9375e671bc | ||
|
|
0e11174aa5 | ||
|
|
baddc966dc | ||
|
|
119582a9d4 | ||
|
|
792b74503c | ||
|
|
4f1971c480 | ||
|
|
a8a1571ed1 | ||
|
|
a79dd3996a | ||
|
|
e6ef2fceea | ||
|
|
56063b96fd | ||
|
|
cae19bba60 | ||
|
|
1f91250a40 | ||
|
|
ee1e65e619 | ||
|
|
00dc5a8dc5 | ||
|
|
4d230f5035 | ||
|
|
73bc6e4bfc | ||
|
|
b78264183f | ||
|
|
455d0a6048 | ||
|
|
5d0dabe51c | ||
|
|
16e7ca3a95 | ||
|
|
70f3909cdc | ||
|
|
f73d32e15d | ||
|
|
3338e4fb25 | ||
|
|
726d4ca9bc | ||
|
|
32b7be2201 | ||
|
|
dc26db7759 | ||
|
|
8fd5b62560 | ||
|
|
619d4e3dc4 | ||
|
|
f03027c33d | ||
|
|
a95dc0ceb8 | ||
|
|
17b7703dab | ||
|
|
50968c12b1 | ||
|
|
edb9c924fe | ||
|
|
805bc499ee | ||
|
|
baa0270ef3 | ||
|
|
d310acc780 |
6
.gitattributes
vendored
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
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
.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
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
.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
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
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 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.
|
||||
146
3rdparty/base64/include/libbase64.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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
1
3rdparty/base64/lib/tables/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
table_generator
|
||||
17
3rdparty/base64/lib/tables/Makefile
vendored
Normal file
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
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
1031
3rdparty/base64/lib/tables/table_enc_12bit.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
45
3rdparty/base64/lib/tables/table_enc_12bit.py
vendored
Executable 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
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
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
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
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; \
|
||||
@@ -11,4 +11,4 @@ https://www.reddit.com/r/KittyTerminal[Reddit community]
|
||||
|
||||
Packaging status in various repositories:
|
||||
|
||||
image:https://repology.org/badge/vertical-allrepos/kitty.svg["Packaging status", link="https://repology.org/project/kitty/versions"]
|
||||
image:https://repology.org/badge/vertical-allrepos/kitty.svg?columns=3&header=kitty["Packaging status", link="https://repology.org/project/kitty/versions"]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python3
|
||||
#!/usr/bin/env python
|
||||
# License: GPL v3 Copyright: 2015, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python3
|
||||
#!/usr/bin/env python
|
||||
# vim:fileencoding=utf-8
|
||||
# License: GPL v3 Copyright: 2019, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -147,9 +147,9 @@
|
||||
{
|
||||
"name": "python",
|
||||
"unix": {
|
||||
"filename": "Python-3.9.4.tar.xz",
|
||||
"hash": "sha256:4b0e6644a76f8df864ae24ac500a51bbf68bd098f6a173e27d3b61cdca9aa134",
|
||||
"urls": ["https://www.python.org/ftp/python/3.9.4/{filename}"]
|
||||
"filename": "Python-3.11.6.tar.xz",
|
||||
"hash": "sha256:0fab78fa7f133f4f38210c6260d90d7c0d5c7198446419ce057ec7ac2e6f5f38",
|
||||
"urls": ["https://www.python.org/ftp/python/3.11.6/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
@@ -244,9 +244,18 @@
|
||||
{
|
||||
"name": "harfbuzz",
|
||||
"unix": {
|
||||
"filename": "harfbuzz-2.7.4.tar.xz",
|
||||
"hash": "sha256:6ad11d653347bd25d8317589df4e431a2de372c0cf9be3543368e07ec23bb8e7",
|
||||
"urls": ["https://github.com/harfbuzz/harfbuzz/releases/download/2.7.4/{filename}"]
|
||||
"filename": "harfbuzz-8.2.2.tar.xz",
|
||||
"hash": "sha256:e433ad85fbdf57f680be29479b3f964577379aaf319f557eb76569f0ecbc90f3",
|
||||
"urls": ["https://github.com/harfbuzz/harfbuzz/releases/download/8.2.2/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"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}"]
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -5,13 +5,14 @@ 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 -= {'nerd-fonts-glyphs.txt', 'rowcolumn-diacritics.txt'}
|
||||
all_files -= {'gen/nerd-fonts-glyphs.txt', 'gen/rowcolumn-diacritics.txt'}
|
||||
cp = subprocess.run(['cloc', '--list-file', '-'], input='\n'.join(all_files).encode())
|
||||
raise SystemExit(cp.returncode)
|
||||
|
||||
@@ -6,5 +6,6 @@ Mappable actions
|
||||
The actions described below can be mapped to any key press or mouse action
|
||||
using the ``map`` and ``mouse_map`` directives in :file:`kitty.conf`. For
|
||||
configuration examples, see the default shortcut links for each action.
|
||||
To read about keyboard mapping in more detail, see :doc:`mapping`.
|
||||
|
||||
.. include:: /generated/actions.rst
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -124,7 +126,9 @@ Other keyboard shortcuts
|
||||
----------------------------------
|
||||
|
||||
The full list of actions that can be mapped to key presses is available
|
||||
:doc:`here </actions>`.
|
||||
:doc:`here </actions>`. To learn how to do more sophisticated keyboard
|
||||
mappings, such as modal mappings, per application mappings, etc. see
|
||||
:doc:`mapping`.
|
||||
|
||||
================================== =======================
|
||||
Action Shortcut
|
||||
|
||||
@@ -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,6 +9,20 @@ To update |kitty|, :doc:`follow the instructions <binary>`.
|
||||
Recent major new features
|
||||
---------------------------
|
||||
|
||||
Cheetah speed 🐆
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
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.
|
||||
|
||||
|
||||
File transfer over the tty device
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -28,21 +42,229 @@ 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.
|
||||
|
||||
Truly convenient SSH
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The :doc:`ssh kitten <kittens/ssh>` is redesigned with powerful new features:
|
||||
|
||||
* 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
|
||||
|
||||
.. }}}
|
||||
|
||||
Detailed list of changes
|
||||
-------------------------------------
|
||||
|
||||
0.33.2 [future]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- Wayland: panel kitten: Add support for drawing desktop background and bars
|
||||
using the panel kitten for all compositors that support the requisite Wayland
|
||||
protocol which is practically speaking all of them but GNOME (:pull:`2590`)
|
||||
|
||||
- Wayland: Support fractional scales so that there is no wasted drawing at larger scale followed by resizing in the compositor
|
||||
|
||||
- Wayland: Support preferred integer scales
|
||||
|
||||
- Wayland KDE: Support :opt:`background_blur`
|
||||
|
||||
- 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`)
|
||||
|
||||
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]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- :ref:`conditional_mappings`
|
||||
|
||||
- Support for :ref:`modal_mappings` such as in modal editors like vim
|
||||
|
||||
- A new option :opt:`notify_on_cmd_finish` to show a desktop notification when a long running command finishes (:pull:`6817`)
|
||||
|
||||
- A new action :ac:`send_key` to simplify mapping key presses to other keys without needing :ac:`send_text`
|
||||
|
||||
- Allow focusing previously active OS windows via :ac:`nth_os_window` (:pull:`7009`)
|
||||
|
||||
- Wayland: Fix a regression in the previous release that broke copying to clipboard under wl-roots based compositors in some circumstances
|
||||
(:iss:`6890`)
|
||||
|
||||
- macOS: Fix some combining characters not being rendered (:iss:`6898`)
|
||||
|
||||
- macOS: Fix returning from full screen via the button when the titlebar is hidden not hiding the buttons (:iss:`6883`)
|
||||
|
||||
- macOS: Fix newly created OS windows not always appearing on the "active" monitor (:pull:`6932`)
|
||||
|
||||
- Font fallback: Fix the font used to render a character sometimes dependent on the order in which characters appear on screen (:iss:`6865`)
|
||||
|
||||
- panel kitten: Fix rendering with non-zero margin/padding in kitty.conf (:iss:`6923`)
|
||||
|
||||
- kitty keyboard protocol: Specify the behavior of the modifier bits during modifier key events (:iss:`6913`)
|
||||
|
||||
- Wayland: Enable support for the new cursor-shape protocol so that the mouse cursor is always rendered at the correct size in compositors that support this protocol (:iss:`6914`)
|
||||
|
||||
- GNOME Wayland: Fix remembered window size smaller than actual size (:iss:`6946`)
|
||||
|
||||
- Mouse reporting: Fix incorrect position reported for windows with padding (:iss:`6950`)
|
||||
|
||||
- Fix :ac:`focus_visible_window` not switching to other window in stack layout
|
||||
when only two windows are present (:iss:`6970`)
|
||||
|
||||
|
||||
0.31.0 [2023-11-08]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- Allow :ac:`easily running arbitrarily complex remote control scripts <remote_control_script>` without needing to turn on remote control (:iss:`6712`)
|
||||
|
||||
- A new option :opt:`menu_map` that allows adding entries to the global menubar on macOS (:disc:`6680`)
|
||||
|
||||
- A new :doc:`escape code <pointer-shapes>` that can be used by programs running in the terminal to change the shape of the mouse pointer (:iss:`6711`)
|
||||
|
||||
- Graphics protocol: Support for positioning :ref:`images relative to other images <relative_image_placement>` (:iss:`6400`)
|
||||
|
||||
- A new option :opt:`single_window_padding_width` to use a different padding when only a single window is visible (:iss:`6734`)
|
||||
|
||||
- A new mouse action ``mouse_selection word_and_line_from_point`` to select the current word under the mouse cursor and extend to end of line (:pull:`6663`)
|
||||
|
||||
- A new option :opt:`underline_hyperlinks` to control when hyperlinks are underlined (:iss:`6766`)
|
||||
|
||||
- Allow using the full range of standard mouse cursor shapes when customizing the mouse cursor
|
||||
|
||||
- macOS: When running the default shell with the login program fix :file:`~/.hushlogin` not being respected when opening windows not in the home directory (:iss:`6689`)
|
||||
|
||||
- macOS: Fix poor performance when using ligatures with some fonts, caused by slow harfbuzz shaping (:iss:`6743`)
|
||||
|
||||
- :option:`kitten @ set-background-opacity --toggle` - a new flag to easily switch opacity between the specified value and the default (:iss:`6691`)
|
||||
|
||||
- Fix a regression caused by rewrite of kittens to Go that made various kittens reset colors in a terminal when the colors were changed by escape code (:iss:`6708`)
|
||||
|
||||
- Fix trailing bracket not ignored when detecting a multi-line URL with the trailing bracket as the first character on the last line (:iss:`6710`)
|
||||
|
||||
- Fix the :option:`kitten @ launch --copy-env` option not copying current environment variables (:iss:`6724`)
|
||||
|
||||
- Fix a regression that broke :program:`kitten update-self` (:iss:`6729`)
|
||||
|
||||
- Two new event types for :ref:`watchers <watchers>`, :code:`on_title_change` and :code:`on_set_user_var`
|
||||
|
||||
- When pasting, if the text contains terminal control codes ask the user for permission. See :opt:`paste_actions` for details. Thanks to David Leadbeater for discovering this.
|
||||
|
||||
- Render Private Use Unicode symbols using two cells if the second cell contains an en-space as well as a normal space
|
||||
|
||||
- macOS: Fix a regression in the previous release that caused kitten @ ls to not report the environment variables for the default shell (:iss:`6749`)
|
||||
|
||||
- :doc:`Desktop notification protocol </desktop-notifications>`: Allow applications sending notifications to specify that the notification should only be displayed if the window is currently unfocused (:iss:`6755`)
|
||||
|
||||
- :doc:`unicode_input kitten </kittens/unicode_input>`: Fix a regression that broke the "Emoticons" tab (:iss:`6760`)
|
||||
|
||||
- Shell integration: Fix ``sudo --edit`` not working and also fix completions for sudo not working in zsh (:iss:`6754`, :iss:`6771`)
|
||||
|
||||
- A new action :ac:`set_window_title` to interactively change the title of the active window
|
||||
|
||||
- ssh kitten: Fix a regression that broken :kbd:`ctrl+space` mapping in zsh (:iss:`6780`)
|
||||
|
||||
- Wayland: Fix primary selections not working with the river compositor (:iss:`6785`)
|
||||
|
||||
|
||||
0.30.1 [2023-10-05]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -1304,10 +1526,10 @@ Detailed list of changes
|
||||
- Fix deleting windows that are not the last window via remote control leaving
|
||||
no window focused (:iss:`3619`)
|
||||
|
||||
- Add an option :option:`kitty @ get-text --add-cursor` to also get the current
|
||||
- Add an option :option:`kitten @ get-text --add-cursor` to also get the current
|
||||
cursor position and state as ANSI escape codes (:iss:`3625`)
|
||||
|
||||
- Add an option :option:`kitty @ get-text --add-wrap-markers` to add line wrap
|
||||
- Add an option :option:`kitten @ get-text --add-wrap-markers` to add line wrap
|
||||
markers to the output (:pull:`3633`)
|
||||
|
||||
- Improve rendering of curly underlines on HiDPI screens (:pull:`3637`)
|
||||
@@ -2911,7 +3133,7 @@ Detailed list of changes
|
||||
- diff kitten: Fix error when right hand side file is binary and left hand side
|
||||
file is text (:pull:`752`)
|
||||
|
||||
- kitty @ new-window: Add a new option :option:`kitty @ new-window --window-type`
|
||||
- kitty @ new-window: Add a new option :option:`kitten @ new-window --window-type`
|
||||
to create top-level OS windows (:iss:`770`)
|
||||
|
||||
- macOS: The :opt:`focus_follows_mouse` option now also works across top-level kitty OS windows
|
||||
@@ -3028,7 +3250,7 @@ Detailed list of changes
|
||||
- diff kitten: Fix default foreground/background colors not being restored when
|
||||
kitten quits (:iss:`637`)
|
||||
|
||||
- Fix :option:`kitty @ set-colors --all` not working when more than one window
|
||||
- Fix :option:`kitten @ set-colors --all` not working when more than one window
|
||||
present (:iss:`632`)
|
||||
|
||||
- Fix a regression that broke the legacy increase/decrease_font_size actions
|
||||
|
||||
211
docs/conf.py
211
docs/conf.py
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python3
|
||||
#!/usr/bin/env python
|
||||
# vim:fileencoding=utf-8
|
||||
#
|
||||
# Configuration file for the Sphinx documentation builder.
|
||||
@@ -7,18 +7,19 @@
|
||||
# full list see the documentation:
|
||||
# https://www.sphinx-doc.org/en/master/config
|
||||
|
||||
import glob
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
from functools import lru_cache, partial
|
||||
from typing import Any, Callable, Dict, Iterable, List, Tuple
|
||||
from typing import Any, Callable, Dict, Iterable, Iterator, List, Tuple
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.parsers.rst.roles import set_classes
|
||||
from pygments.lexer import RegexLexer, bygroups # type: ignore
|
||||
from pygments.token import Comment, Keyword, Literal, Name, Number, String, Whitespace # type: ignore
|
||||
from pygments.token import Comment, Error, Keyword, Literal, Name, Number, String, Whitespace # type: ignore
|
||||
from sphinx import addnodes, version_info
|
||||
from sphinx.util.logging import getLogger
|
||||
|
||||
@@ -27,7 +28,8 @@ if kitty_src not in sys.path:
|
||||
sys.path.insert(0, kitty_src)
|
||||
|
||||
from kitty.conf.types import Definition, expand_opt_references # noqa
|
||||
from kitty.constants import str_version, website_url # noqa
|
||||
from kitty.constants import str_version, website_url # noqa
|
||||
from kitty.fast_data_types import Shlex # noqa
|
||||
|
||||
# config {{{
|
||||
# -- Project information -----------------------------------------------------
|
||||
@@ -176,8 +178,8 @@ manpages_url = 'https://man7.org/linux/man-pages/man{section}/{page}.{section}.h
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
('invocation', 'kitty', 'kitty Documentation', [author], 1),
|
||||
('conf', 'kitty.conf', 'kitty terminal emulator configuration file', [author], 5)
|
||||
('invocation', 'kitty', 'The fast, feature rich terminal emulator', [author], 1),
|
||||
('conf', 'kitty.conf', 'Configuration file for kitty', [author], 5)
|
||||
]
|
||||
|
||||
|
||||
@@ -209,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], []
|
||||
# }}}
|
||||
@@ -251,20 +253,20 @@ if you specify a program-to-run you can use the special placeholder
|
||||
as_rst = partial(option_spec_as_rst, heading_char='_')
|
||||
from kitty.rc.base import all_command_names, command_for_name
|
||||
from kitty.remote_control import cli_msg, global_options_spec
|
||||
with open('generated/cli-kitty-at.rst', 'w') as f:
|
||||
with open('generated/cli-kitten-at.rst', 'w') as f:
|
||||
p = partial(print, file=f)
|
||||
p('kitty @')
|
||||
p('kitten @')
|
||||
p('-' * 80)
|
||||
p('.. program::', 'kitty @')
|
||||
p('.. program::', 'kitten @')
|
||||
p('\n\n' + as_rst(
|
||||
global_options_spec, message=cli_msg, usage='command ...', appname='kitty @'))
|
||||
global_options_spec, message=cli_msg, usage='command ...', appname='kitten @'))
|
||||
from kitty.rc.base import cli_params_for
|
||||
for cmd_name in sorted(all_command_names()):
|
||||
func = command_for_name(cmd_name)
|
||||
p(f'.. _at-{func.name}:\n')
|
||||
p('kitty @', func.name)
|
||||
p('kitten @', func.name)
|
||||
p('-' * 120)
|
||||
p('.. program::', 'kitty @', func.name)
|
||||
p('.. program::', 'kitten @', func.name)
|
||||
p('\n\n' + as_rst(*cli_params_for(func)))
|
||||
from kittens.runner import get_kitten_cli_docs
|
||||
|
||||
@@ -344,14 +346,70 @@ class ConfLexer(RegexLexer): # type: ignore
|
||||
aliases = ['conf']
|
||||
filenames = ['*.conf']
|
||||
|
||||
def map_flags(self: RegexLexer, val: str, start_pos: int) -> Iterator[Tuple[int, Any, str]]:
|
||||
expecting_arg = ''
|
||||
s = Shlex(val)
|
||||
from kitty.options.utils import allowed_key_map_options
|
||||
last_pos = 0
|
||||
while (tok := s.next_word())[0] > -1:
|
||||
x = tok[1]
|
||||
if tok[0] > last_pos:
|
||||
yield start_pos + last_pos, Whitespace, ' ' * (tok[0] - last_pos)
|
||||
last_pos = tok[0] + len(x)
|
||||
tok_start = start_pos + tok[0]
|
||||
if expecting_arg:
|
||||
yield tok_start, String, x
|
||||
expecting_arg = ''
|
||||
elif x.startswith('--'):
|
||||
expecting_arg = x[2:]
|
||||
k, sep, v = expecting_arg.partition('=')
|
||||
k = k.replace('-', '_')
|
||||
expecting_arg = k
|
||||
if expecting_arg not in allowed_key_map_options:
|
||||
yield tok_start, Error, x
|
||||
elif sep == '=':
|
||||
expecting_arg = ''
|
||||
yield tok_start, Name, x
|
||||
else:
|
||||
yield tok_start, Name, x
|
||||
else:
|
||||
break
|
||||
|
||||
def mapargs(self: RegexLexer, match: 're.Match[str]') -> Iterator[Tuple[int, Any, str]]:
|
||||
start_pos = match.start()
|
||||
val = match.group()
|
||||
parts = val.split(maxsplit=1)
|
||||
if parts[0].startswith('--'):
|
||||
seen = 0
|
||||
for (pos, token, text) in self.map_flags(val, start_pos):
|
||||
yield pos, token, text
|
||||
seen += len(text)
|
||||
start_pos += seen
|
||||
val = val[seen:]
|
||||
parts = val.split(maxsplit=1)
|
||||
|
||||
if not val:
|
||||
return
|
||||
yield start_pos, Literal, parts[0] # key spec
|
||||
if len(parts) == 1:
|
||||
return
|
||||
start_pos += len(parts[0])
|
||||
val = val[len(parts[0]):]
|
||||
m = re.match(r'(\s+)(\S+)', val)
|
||||
if m is None:
|
||||
return
|
||||
yield start_pos, Whitespace, m.group(1)
|
||||
yield start_pos + m.start(2), Name.Function, m.group(2) # action function
|
||||
yield start_pos + m.end(2), String, val[m.end(2):]
|
||||
|
||||
tokens = {
|
||||
'root': [
|
||||
(r'#.*?$', Comment.Single),
|
||||
(r'\s+$', Whitespace),
|
||||
(r'\s+', Whitespace),
|
||||
(r'(include)(\s+)(.+?)$', bygroups(Comment.Preproc, Whitespace, Name.Namespace)),
|
||||
(r'(map)(\s+)(\S+)(\s+)', bygroups(
|
||||
Keyword.Declaration, Whitespace, String, Whitespace), 'action'),
|
||||
(r'(map)(\s+)', bygroups(
|
||||
Keyword.Declaration, Whitespace), 'mapargs'),
|
||||
(r'(mouse_map)(\s+)(\S+)(\s+)(\S+)(\s+)(\S+)(\s+)', bygroups(
|
||||
Keyword.Declaration, Whitespace, String, Whitespace, Name.Variable, Whitespace, String, Whitespace), 'action'),
|
||||
(r'(symbol_map)(\s+)(\S+)(\s+)(.+?)$', bygroups(
|
||||
@@ -363,6 +421,9 @@ class ConfLexer(RegexLexer): # type: ignore
|
||||
(r'[a-z_0-9]+$', Name.Function, 'root'),
|
||||
(r'[a-z_0-9]+', Name.Function, 'args'),
|
||||
],
|
||||
'mapargs': [
|
||||
(r'.+$', mapargs, 'root'),
|
||||
],
|
||||
'args': [
|
||||
(r'\s+', Whitespace, 'args'),
|
||||
(r'\b(yes|no)\b$', Number.Bin, 'root'),
|
||||
@@ -529,6 +590,18 @@ def write_conf_docs(app: Any, all_kitten_names: Iterable[str]) -> None:
|
||||
from kitty.actions import as_rst
|
||||
with open('generated/actions.rst', 'w', encoding='utf-8') as f:
|
||||
f.write(as_rst())
|
||||
|
||||
from kitty.rc.base import MATCH_TAB_OPTION, MATCH_WINDOW_OPTION
|
||||
with open('generated/matching.rst', 'w') as f:
|
||||
print('Matching windows', file=f)
|
||||
print('______________________________', file=f)
|
||||
w = 'm' + MATCH_WINDOW_OPTION[MATCH_WINDOW_OPTION.find('Match') + 1:]
|
||||
print('When matching windows,', w, file=f)
|
||||
print('Matching tabs', file=f)
|
||||
print('______________________________', file=f)
|
||||
w = 'm' + MATCH_TAB_OPTION[MATCH_TAB_OPTION.find('Match') + 1:]
|
||||
print('When matching tabs,', w, file=f)
|
||||
|
||||
# }}}
|
||||
|
||||
|
||||
@@ -549,10 +622,13 @@ def add_html_context(app: Any, pagename: str, templatename: str, context: Any, d
|
||||
@lru_cache
|
||||
def monkeypatch_man_writer() -> None:
|
||||
'''
|
||||
Monkeypatch the docutils man translator to output better tables
|
||||
Monkeypatch the docutils man translator to be nicer
|
||||
'''
|
||||
from docutils.nodes import Element
|
||||
from docutils.writers.manpage import Table, Translator
|
||||
from sphinx.writers.manpage import ManualPageTranslator
|
||||
|
||||
# Generate nicer tables https://sourceforge.net/p/docutils/bugs/475/
|
||||
class PatchedTable(Table): # type: ignore
|
||||
_options: list[str]
|
||||
def __init__(self) -> None:
|
||||
@@ -572,15 +648,103 @@ def monkeypatch_man_writer() -> None:
|
||||
del ans[3] # top border
|
||||
del ans[-2] # bottom border
|
||||
return ans
|
||||
def visit_table(self: Translator, node: object) -> None:
|
||||
def visit_table(self: ManualPageTranslator, node: object) -> None:
|
||||
setattr(self, '_active_table', PatchedTable())
|
||||
setattr(Translator, 'visit_table', visit_table)
|
||||
setattr(ManualPageTranslator, 'visit_table', visit_table)
|
||||
|
||||
# Improve header generation
|
||||
def header(self: ManualPageTranslator) -> str:
|
||||
di = getattr(self, '_docinfo')
|
||||
di['ktitle'] = di['title'].replace('_', '-')
|
||||
th = (".TH \"%(ktitle)s\" %(manual_section)s"
|
||||
" \"%(date)s\" \"%(version)s\"") % di
|
||||
if di["manual_group"]:
|
||||
th += " \"%(manual_group)s\"" % di
|
||||
th += "\n"
|
||||
sh_tmpl: str = (".SH Name\n"
|
||||
"%(ktitle)s \\- %(subtitle)s\n")
|
||||
return th + sh_tmpl % di # type: ignore
|
||||
|
||||
setattr(ManualPageTranslator, 'header', header)
|
||||
|
||||
def visit_image(self: ManualPageTranslator, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def depart_image(self: ManualPageTranslator, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def depart_figure(self: ManualPageTranslator, node: Element) -> None:
|
||||
self.body.append(' (images not supported)\n')
|
||||
Translator.depart_figure(self, node)
|
||||
|
||||
setattr(ManualPageTranslator, 'visit_image', visit_image)
|
||||
setattr(ManualPageTranslator, 'depart_image', depart_image)
|
||||
setattr(ManualPageTranslator, 'depart_figure', depart_figure)
|
||||
|
||||
orig_astext = Translator.astext
|
||||
def astext(self: Translator) -> Any:
|
||||
b = []
|
||||
for line in self.body:
|
||||
if line.startswith('.SH'):
|
||||
x, y = line.split(' ', 1)
|
||||
parts = y.splitlines(keepends=True)
|
||||
parts[0] = parts[0].capitalize()
|
||||
line = x + ' ' + '\n'.join(parts)
|
||||
b.append(line)
|
||||
self.body = b
|
||||
return orig_astext(self)
|
||||
setattr(Translator, 'astext', astext)
|
||||
|
||||
|
||||
def setup_man_pages() -> None:
|
||||
from kittens.runner import get_kitten_cli_docs
|
||||
base = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
for x in glob.glob(os.path.join(base, 'docs/kittens/*.rst')):
|
||||
kn = os.path.basename(x).rpartition('.')[0]
|
||||
if kn == 'custom':
|
||||
continue
|
||||
cd = get_kitten_cli_docs(kn) or {}
|
||||
khn = kn.replace('_', '-')
|
||||
man_pages.append((f'kittens/{kn}', 'kitten-' + khn, cd.get('short_desc', 'kitten Documentation'), [author], 1))
|
||||
monkeypatch_man_writer()
|
||||
|
||||
|
||||
def build_extra_man_pages() -> None:
|
||||
base = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
kitten = os.environ.get('KITTEN_EXE_FOR_DOCS', os.path.join(base, 'kitty/launcher/kitten'))
|
||||
if not os.path.exists(kitten):
|
||||
kitten = os.path.join(base, 'kitty/launcher/kitty.app/Contents/MacOS/kitten')
|
||||
if not os.path.exists(kitten):
|
||||
subprocess.call(['find', os.path.join(base, 'kitty/launcher')])
|
||||
raise Exception(f'The kitten binary {kitten} is not built cannot generate man pages')
|
||||
raw = subprocess.check_output([kitten, '-h']).decode()
|
||||
started = 0
|
||||
names = set()
|
||||
for line in raw.splitlines():
|
||||
if line.strip() == '@':
|
||||
started = len(line.rstrip()[:-1])
|
||||
q = line.strip()
|
||||
if started and len(q.split()) == 1 and not q.startswith('-') and ':' not in q:
|
||||
if len(line) - len(line.lstrip()) == started:
|
||||
if not os.path.exists(os.path.join(base, f'docs/kittens/{q}.rst')):
|
||||
names.add(q)
|
||||
cwd = os.path.join(base, 'docs/_build/man')
|
||||
subprocess.check_call([kitten, '__generate_man_pages__'], cwd=cwd)
|
||||
subprocess.check_call([kitten, '__generate_man_pages__'] + list(names), cwd=cwd)
|
||||
|
||||
|
||||
if building_man_pages:
|
||||
setup_man_pages()
|
||||
|
||||
|
||||
def build_finished(*a: Any, **kw: Any) -> None:
|
||||
if building_man_pages:
|
||||
build_extra_man_pages()
|
||||
|
||||
|
||||
def setup(app: Any) -> None:
|
||||
os.makedirs('generated/conf', exist_ok=True)
|
||||
from kittens.runner import all_kitten_names
|
||||
monkeypatch_man_writer()
|
||||
kn = all_kitten_names()
|
||||
write_cli_docs(kn)
|
||||
write_remote_control_protocol_docs()
|
||||
@@ -589,10 +753,7 @@ def setup(app: Any) -> None:
|
||||
app.connect('source-read', replace_string)
|
||||
app.add_config_value('analytics_id', '', 'env')
|
||||
app.connect('html-page-context', add_html_context)
|
||||
app.connect('build-finished', build_finished)
|
||||
app.add_lexer('session', SessionLexer() if version_info[0] < 3 else SessionLexer)
|
||||
app.add_role('link', link_role)
|
||||
app.add_role('commit', commit_role)
|
||||
# monkey patch sphinx_inline_tabs to avoid a warning about parallel reads
|
||||
# see https://github.com/pradyunsg/sphinx-inline-tabs/issues/26
|
||||
inline_tabs = app.extensions['sphinx_inline_tabs']
|
||||
inline_tabs.parallel_read_safe = inline_tabs.parallel_write_safe = True
|
||||
|
||||
@@ -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:
|
||||
|
||||
|
||||
@@ -94,9 +94,9 @@ to display it based on what it does understand.
|
||||
revisions.
|
||||
|
||||
|
||||
======= ==================== ========= =================
|
||||
======= ==================== ========== =================
|
||||
Key Value Default Description
|
||||
======= ==================== ========= =================
|
||||
======= ==================== ========== =================
|
||||
``a`` Comma separated list ``focus`` What action to perform when the
|
||||
of ``report``, notification is clicked
|
||||
``focus``, with
|
||||
@@ -113,7 +113,19 @@ Key Value Default Description
|
||||
|
||||
``p`` One of ``title`` or ``title`` Whether the payload is the notification title or body. If a
|
||||
``body``. notification has no title, the body will be used as title.
|
||||
======= ==================== ========= =================
|
||||
|
||||
``o`` One of ``always``, ``always`` When to honor the notification request. ``unfocused`` means when the window
|
||||
``unfocused`` or the notification is sent on does not have keyboard focus. ``invisible``
|
||||
``invisible`` means the window both is unfocused
|
||||
and not visible to the user, for example, because it is in an inactive tab or
|
||||
its OS window is not currently active.
|
||||
``always`` is the default and always honors the request.
|
||||
======= ==================== ========== =================
|
||||
|
||||
|
||||
.. note::
|
||||
Support for the ``o`` key to prevent notifications from focused windows
|
||||
was added in kitty version 0.31.0
|
||||
|
||||
|
||||
.. note::
|
||||
|
||||
40
docs/faq.rst
40
docs/faq.rst
@@ -19,9 +19,9 @@ use Unicode characters from the private use area to represent symbols. Often
|
||||
these symbols are wide and should be rendered in two cells. However, since
|
||||
private use area symbols all have their width set to one in the Unicode
|
||||
standard, |kitty| renders them either smaller or truncated. The exception is if
|
||||
these characters are followed by a space or empty cell in which case kitty
|
||||
makes use of the extra cell to render them in two cells. This behavior can be
|
||||
turned off for specific symbols using :opt:`narrow_symbols`.
|
||||
these characters are followed by a space or en-space (U+2002) in which case
|
||||
kitty makes use of the extra cell to render them in two cells. This behavior
|
||||
can be turned off for specific symbols using :opt:`narrow_symbols`.
|
||||
|
||||
|
||||
Using a color theme with a background color does not work well in vim?
|
||||
@@ -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-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,23 +387,18 @@ 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_text normal,application \x13
|
||||
map alt+s send_key ctrl+s
|
||||
|
||||
This maps :kbd:`alt+s` to :kbd:`ctrl+s`. To figure out what bytes to use for
|
||||
the :sc:`send_text <send_text>` you can use the ``show_key`` kitten. Run::
|
||||
This causes the program running in kitty to receive the :kbd:`ctrl+s` key when
|
||||
you press the :kbd:`alt+s` key. To see this in action, run::
|
||||
|
||||
kitten show_key
|
||||
kitten show-key -m kitty
|
||||
|
||||
Then press the key you want to emulate. Note that this kitten will only show
|
||||
keys that actually reach the terminal program, in particular, keys mapped to
|
||||
actions in kitty will not be shown. To check those first map them to
|
||||
:ac:`no_op`. You can also start a kitty instance without any shortcuts to
|
||||
interfere::
|
||||
|
||||
kitty -o clear_all_shortcuts=yes kitten show_key
|
||||
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?
|
||||
@@ -453,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`).
|
||||
|
||||
@@ -464,6 +457,11 @@ 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
|
||||
|
||||
@@ -120,7 +120,7 @@ Variables that influence kitty behavior
|
||||
|
||||
.. envvar:: KITTY_RC_PASSWORD
|
||||
|
||||
Set this to a pass phrase to use the ``kitty @`` remote control command with
|
||||
Set this to a pass phrase to use the ``kitten @`` remote control command with
|
||||
:opt:`remote_control_password`.
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -179,8 +180,10 @@ Variables that kitty sets when running child programs
|
||||
|
||||
Set when the :doc:`remote control <remote-control>` facility is enabled and
|
||||
the a socket is used for control via :option:`kitty --listen-on` or :opt:`listen_on`.
|
||||
Contains the path to the socket. Avoid the need to use :option:`kitty @ --to` when
|
||||
issuing remote control commands.
|
||||
Contains the path to the socket. Avoid the need to use :option:`kitten @ --to` when
|
||||
issuing remote control commands. Can also be a file descriptor of the form
|
||||
fd:num instead of a socket address, in which case, remote control
|
||||
communication should proceed over the specified file descriptor.
|
||||
|
||||
.. envvar:: KITTY_PIPE_DATA
|
||||
|
||||
@@ -228,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.
|
||||
|
||||
@@ -48,6 +48,7 @@ Some programs and libraries that use the kitty graphics protocol:
|
||||
* `glkitty <https://github.com/michaeljclark/glkitty>`_ - C library to draw OpenGL shaders in the terminal with a glgears demo
|
||||
* `twitch-tui <https://github.com/Xithrius/twitch-tui>`_ - Twitch chat in the terminal
|
||||
* `awrit <https://github.com/chase/awrit>`_ - Chromium-based web browser rendered in Kitty with mouse and keyboard support
|
||||
* `fzf <https://github.com/junegunn/fzf/commit/d8188fce7b7bea982e7f9050c35e488e49fb8fd0>`_ - A command line fuzzy finder
|
||||
|
||||
Other terminals that have implemented the graphics protocol:
|
||||
|
||||
@@ -459,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>\
|
||||
@@ -478,18 +482,22 @@ Controlling displayed image layout
|
||||
|
||||
The image is rendered at the current cursor position, from the upper left corner of
|
||||
the current cell. You can also specify extra ``X=3`` and ``Y=4`` pixel offsets to display from
|
||||
a different origin within the cell. Note that the offsets must be smaller that the size of the cell.
|
||||
a different origin within the cell. Note that the offsets must be smaller than the size of the cell.
|
||||
|
||||
By default, the entire image will be displayed (images wider than the available
|
||||
width will be truncated on the right edge). You can choose a source rectangle (in pixels)
|
||||
as the part of the image to display. This is done with the keys: ``x, y, w, h`` which specify
|
||||
the top-left corner, width and height of the source rectangle.
|
||||
the top-left corner, width and height of the source rectangle. The displayed
|
||||
area is the intersection of the specified rectangle with the source image
|
||||
rectangle.
|
||||
|
||||
You can also ask the terminal emulator to display the image in a specified rectangle
|
||||
(num of columns / num of lines), using the control codes ``c,r``. ``c`` is the number of columns
|
||||
and `r` the number of rows. The image will be scaled (enlarged/shrunk) as needed to fit
|
||||
the specified area. Note that if you specify a start cell offset via the ``X,Y`` keys, it is not
|
||||
added to the number of rows/columns.
|
||||
added to the number of rows/columns. If only one of either ``r`` or ``c`` is
|
||||
specified, the other one is computed based on the source image aspect ratio, so
|
||||
that the image is displayed without distortion.
|
||||
|
||||
Finally, you can specify the image *z-index*, i.e. the vertical stacking order. Images
|
||||
placed in the same location with different z-index values will be blended if
|
||||
@@ -554,7 +562,7 @@ The image will eventually be fit to the specified rectangle, its aspect ratio
|
||||
preserved. Finally, the image can be actually displayed by using the
|
||||
placeholder character, encoding the image ID in its foreground color. The row
|
||||
and column values are specified with diacritics listed in
|
||||
:download:`rowcolumn-diacritics.txt <../rowcolumn-diacritics.txt>`. For
|
||||
:download:`rowcolumn-diacritics.txt <../gen/rowcolumn-diacritics.txt>`. For
|
||||
example, here is how you can print a ``2x2`` placeholder for image ID ``42``:
|
||||
|
||||
.. code-block:: sh
|
||||
@@ -629,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.
|
||||
@@ -639,6 +647,70 @@ placements from the protocol perspective. They cannot be manipulated using
|
||||
graphics commands, instead they should be moved, deleted, or modified by
|
||||
manipulating the underlying Unicode placeholder as normal text.
|
||||
|
||||
.. _relative_image_placement:
|
||||
|
||||
Relative placements
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. versionadded:: 0.31.0
|
||||
Support for positioning images relative to other images
|
||||
|
||||
You can specify that a placement is positioned relative to another placement.
|
||||
This is particularly useful in combination with
|
||||
:ref:`graphics_unicode_placeholders` above. It can be used to specify a single
|
||||
transparent pixel image using a Unicode placeholder, which moves around
|
||||
naturally with the text, the real image(s) can base their position relative to
|
||||
the placeholder.
|
||||
|
||||
To specify that a placement should be relative to another, use the
|
||||
``P=<image_id>,Q=<placement_id>`` keys, when creating the relative placement.
|
||||
For example::
|
||||
|
||||
<ESC>_Ga=p,i=<image_id>,p=<placement_id>,P=<parent_img_id>,Q=<parent_placement_id><ESC>\
|
||||
|
||||
This will create a *relative placement* that refers to the *parent placement*
|
||||
specified by the ``P`` and ``Q`` keys. When the parent placement moves, the
|
||||
relative placement moves along with it. The relative placement can be offset
|
||||
from the parent's location by a specified number of cells, using the ``H`` and
|
||||
``V`` keys for horizontal and vertical displacement. Positive values move right
|
||||
and down. Negative values move left and up. The origin is the top left cell of
|
||||
the parent placement.
|
||||
|
||||
The lifetime of a relative placement is tied to the lifetime of its parent. If
|
||||
its parent is deleted, it is deleted as well. If the image that the relative
|
||||
placement is a placement of, has no more placements, the image is deleted as
|
||||
well. Thus, a parent and its relative placements form a *group* that is managed
|
||||
together.
|
||||
|
||||
A relative placement can refer to another relative placement as its parent.
|
||||
Thus the relative placements can form a chain. It is implementation dependent
|
||||
how long a chain of such placements is allowed, but implementation must allow
|
||||
a chain of length at least 8. If the implementation max depth is exceeded, the
|
||||
terminal must respond with the ``ETOODEEP`` error code.
|
||||
|
||||
Virtual placements created for Unicode placeholder based images cannot also be
|
||||
relative placements. However, a relative placement can refer to a virtual
|
||||
placement as its parent. When a virtual placement is the parent, its position
|
||||
is derived from all the actual Unicode placeholder images that refer to it.
|
||||
The x position is the minimum of all the placeholder x positions and the y
|
||||
position is the minimum of all the placeholder y positions. If a client
|
||||
attempts to make a virtual placement relative the terminal must respond with
|
||||
the ``EINVAL`` error code.
|
||||
|
||||
Terminals are required to reject the creation of a relative placement
|
||||
that would create a cycle, such as when A is relative to B and B is relative to
|
||||
C and C is relative to A. In such cases, the terminal must respond with the
|
||||
``ECYCLE`` error code.
|
||||
|
||||
If a client attempts to create a reference to a placement that does not exist
|
||||
the terminal must respond with the ``ENOPARENT`` error code.
|
||||
|
||||
.. note::
|
||||
Since a relative placement gets its position specified based on another
|
||||
placement, instead of the cursor, the cursor must not move after a relative
|
||||
position, regardless of the value of the ``C`` key to control cursor
|
||||
movement.
|
||||
|
||||
|
||||
Deleting images
|
||||
---------------------
|
||||
@@ -657,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.
|
||||
@@ -959,8 +1032,11 @@ Key Value Default Description
|
||||
``C`` Positive integer ``0`` Cursor movement policy. ``0`` is the default, to move the cursor to after the image.
|
||||
``1`` is to not move the cursor at all when placing the image.
|
||||
``U`` Positive integer ``0`` Set to ``1`` to create a virtual placement for a Unicode placeholder.
|
||||
``1`` is to not move the cursor at all when placing the image.
|
||||
``z`` 32-bit integer ``0`` The *z-index* vertical stacking order of the image
|
||||
``P`` Positive integer ``0`` The id of a parent image for relative placement
|
||||
``Q`` Positive integer ``0`` The id of a placement in the parent image for relative placement
|
||||
``H`` 32-bit integer ``0`` The offset in cells in the horizontal direction for relative placement
|
||||
``V`` 32-bit integer ``0`` The offset in cells in the vertical direction for relative placement
|
||||
|
||||
**Keys for animation frame loading**
|
||||
-----------------------------------------------------------
|
||||
@@ -1008,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
|
||||
)``.
|
||||
======= ==================== ========= =================
|
||||
|
||||
|
||||
|
||||
@@ -47,6 +47,13 @@ graphics protocol.
|
||||
Another terminal file manager, with previews of file contents powered by kitty's
|
||||
graphics protocol.
|
||||
|
||||
.. _tool_presentterm:
|
||||
|
||||
`presenterm <https://github.com/mfontanini/presenterm>`_
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Show markdown based slides with images in your terminal, powered by the
|
||||
kitty graphics protocol.
|
||||
|
||||
.. _tool_term_image:
|
||||
|
||||
`term-image <https://github.com/AnonymouX47/term-image>`__
|
||||
@@ -182,13 +189,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
|
||||
-----------------------
|
||||
|
||||
@@ -232,16 +232,23 @@ running around inside nvim <https://github.com/giusgad/pets.nvim>`__.
|
||||
Scrollback manipulation
|
||||
-------------------------
|
||||
|
||||
.. tool_kitty_scrollback_nvim:
|
||||
|
||||
`kitty-scrollback.nvim <https://github.com/mikesmithgh/kitty-scrollback.nvim>`_
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Browse the scrollback buffer with Neovim, with simple key actions for efficient
|
||||
copy/paste and even execution of commands.
|
||||
|
||||
.. tool_kitty_search:
|
||||
|
||||
`kitty-search <https://github.com/trygveaa/kitty-kitten-search>`_
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Live incremental search of the scrollback buffer.
|
||||
|
||||
.. tool_kitty_grab:
|
||||
|
||||
`kitty-grab <https://github.com/yurikhan/kitty_grab>`_
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Keyboard based text selection for the kitty scrollback buffer.
|
||||
|
||||
|
||||
|
||||
@@ -36,6 +36,8 @@ In addition to kitty, this protocol is also implemented in:
|
||||
|
||||
* The `foot terminal <https://codeberg.org/dnkl/foot/issues/319>`__
|
||||
* The `WezTerm terminal <https://wezfurlong.org/wezterm/config/lua/config/enable_kitty_keyboard.html>`__
|
||||
* The `alacritty terminal <https://github.com/alacritty/alacritty/pull/7125>`__
|
||||
* The `rio terminal <https://github.com/raphamorim/rio/commit/cd463ca37677a0fc48daa8795ea46dadc92b1e95>`__
|
||||
* The `notcurses library
|
||||
<https://github.com/dankamongmen/notcurses/issues/2131>`__
|
||||
* The `crossterm library
|
||||
@@ -47,6 +49,7 @@ 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>`__
|
||||
|
||||
@@ -81,7 +84,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`,
|
||||
@@ -103,9 +106,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.
|
||||
@@ -179,11 +180,19 @@ 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
|
||||
current event. For example, when pressing the :kbd:`LEFT_CONTROL` key, the
|
||||
``ctrl`` bit must be set and when releasing it, it must be reset. When both
|
||||
left and right control keys are pressed and one is released, the release event
|
||||
must have the ``ctrl`` bit set. See :iss:`6913` for discussion of this design.
|
||||
|
||||
.. _event_types:
|
||||
|
||||
@@ -221,8 +230,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
|
||||
@@ -328,7 +339,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:
|
||||
|
||||
@@ -340,6 +353,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
|
||||
@@ -474,6 +494,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
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
broadcast
|
||||
==================================================
|
||||
|
||||
.. only:: man
|
||||
|
||||
Overview
|
||||
--------------
|
||||
|
||||
*Type text in all kitty windows simultaneously*
|
||||
|
||||
The ``broadcast`` kitten can be used to type text simultaneously in all
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
clipboard
|
||||
==================================================
|
||||
|
||||
.. only:: man
|
||||
|
||||
Overview
|
||||
--------------
|
||||
|
||||
*Copy/paste to the system clipboard from shell scripts*
|
||||
|
||||
.. highlight:: sh
|
||||
|
||||
@@ -56,7 +56,7 @@ Kittens have full access to internal kitty APIs. However these are neither
|
||||
entirely stable nor documented. You can instead use the kitty
|
||||
:doc:`Remote control API </remote-control>`. Simply call
|
||||
:code:`boss.call_remote_control()`, with the same arguments you
|
||||
would pass to ``kitty @``. For example:
|
||||
would pass to ``kitten @``. For example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -337,9 +337,10 @@ You can parse and read the options in your kitten using the following code:
|
||||
return ans
|
||||
|
||||
overrides = tuple(overrides) if overrides is not None else ()
|
||||
opts_dict, paths = _load_config(defaults, parse_config, merge_result_dicts, *paths, overrides=overrides)
|
||||
opts_dict, found_paths = _load_config(defaults, parse_config, merge_result_dicts, *paths, overrides=overrides)
|
||||
opts = Options(opts_dict)
|
||||
opts.config_paths = paths
|
||||
opts.config_paths = found_paths
|
||||
opts.all_config_paths = paths
|
||||
opts.config_overrides = overrides
|
||||
return opts
|
||||
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
Hints
|
||||
==========
|
||||
|
||||
.. only:: man
|
||||
|
||||
Overview
|
||||
--------------
|
||||
|
||||
|
||||
|kitty| has a *hints mode* to select and act on arbitrary text snippets
|
||||
currently visible on the screen. For example, you can press :sc:`open_url`
|
||||
to choose any URL visible on the screen and then open it using your default web
|
||||
@@ -20,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}
|
||||
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
Hyperlinked grep
|
||||
=================
|
||||
|
||||
.. only:: man
|
||||
|
||||
Overview
|
||||
--------------
|
||||
|
||||
|
||||
.. note::
|
||||
|
||||
As of ripgrep versions newer that 13.0 it supports hyperlinks
|
||||
@@ -39,7 +45,8 @@ Now, run a search with::
|
||||
Hold down the :kbd:`Ctrl+Shift` keys and click on any of the result lines, to
|
||||
open the file in :program:`vim` at the matching line. If you use some editor
|
||||
other than :program:`vim`, you should adjust the :file:`open-actions.conf` file
|
||||
accordingly.
|
||||
accordingly. TO open links with the keyboard instead, use
|
||||
:sc:`open_selected_hyperlink`.
|
||||
|
||||
Finally, add an alias to your shell's rc files to invoke the kitten as
|
||||
:command:`hg`::
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
icat
|
||||
========================================
|
||||
|
||||
.. only:: man
|
||||
|
||||
Overview
|
||||
--------------
|
||||
|
||||
|
||||
*Display images in the terminal*
|
||||
|
||||
The ``icat`` kitten can be used to display arbitrary images in the |kitty|
|
||||
terminal. Using it is as simple as::
|
||||
|
||||
kitten icat image.jpeg
|
||||
kitten icat image.jpeg
|
||||
|
||||
It supports all image types supported by `ImageMagick
|
||||
<https://www.imagemagick.org>`__. It even works over SSH. For details, see the
|
||||
|
||||
@@ -3,6 +3,11 @@ Draw a GPU accelerated dock panel on your desktop
|
||||
|
||||
.. highlight:: sh
|
||||
|
||||
.. only:: man
|
||||
|
||||
Overview
|
||||
--------------
|
||||
|
||||
|
||||
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.
|
||||
@@ -25,7 +30,10 @@ activity, CPU load, date/time, etc.
|
||||
|
||||
.. 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 usually crippled GNOME).
|
||||
|
||||
Using this kitten is simple, for example::
|
||||
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
Query terminal
|
||||
=================
|
||||
|
||||
.. only:: man
|
||||
|
||||
Overview
|
||||
--------------
|
||||
|
||||
|
||||
This kitten is used to query |kitty| from terminal programs about version, values
|
||||
of various runtime options controlling its features, etc.
|
||||
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
Remote files
|
||||
==============
|
||||
|
||||
.. only:: man
|
||||
|
||||
Overview
|
||||
--------------
|
||||
|
||||
|
||||
|kitty| has the ability to easily *Edit*, *Open* or *Download* files from a
|
||||
computer into which you are SSHed. In your SSH session run::
|
||||
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
Truly convenient SSH
|
||||
=========================================
|
||||
|
||||
.. only:: man
|
||||
|
||||
Overview
|
||||
----------------
|
||||
|
||||
* Automatic :ref:`shell_integration` on remote hosts
|
||||
|
||||
* Easily :ref:`clone local shell/editor config <real_world_ssh_kitten_config>` on remote hosts
|
||||
|
||||
* Automatic :opt:`re-use of existing connections <kitten-ssh.share_connections>` to avoid connection setup latency
|
||||
|
||||
* Make kitty itself available in the remote host :opt:`on demand <kitten-ssh.remote_kitty>`
|
||||
* Make the kitten binary available in the remote host :opt:`on demand <kitten-ssh.remote_kitty>`
|
||||
|
||||
* Easily :opt:`change terminal colors <kitten-ssh.color_scheme>` when connecting to remote hosts
|
||||
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
Changing kitty colors
|
||||
========================
|
||||
|
||||
.. only:: man
|
||||
|
||||
Overview
|
||||
--------------
|
||||
|
||||
|
||||
The themes kitten allows you to easily change color themes, from a collection of
|
||||
over three hundred pre-built themes available at `kitty-themes
|
||||
<https://github.com/kovidgoyal/kitty-themes>`_. To use it, simply run::
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
Transfer files
|
||||
================
|
||||
|
||||
.. only:: man
|
||||
|
||||
Overview
|
||||
--------------
|
||||
|
||||
|
||||
.. versionadded:: 0.30.0
|
||||
|
||||
.. _rsync: https://en.wikipedia.org/wiki/Rsync
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
Unicode input
|
||||
================
|
||||
|
||||
.. only:: man
|
||||
|
||||
Overview
|
||||
--------------
|
||||
|
||||
|
||||
You can input Unicode characters by name, hex code, recently used and even an
|
||||
editable favorites list. Press :sc:`input_unicode_character` to start the
|
||||
unicode input kitten, shown below.
|
||||
|
||||
@@ -83,7 +83,7 @@ the command line:
|
||||
data to STDIN.
|
||||
|
||||
``@input-line-number``
|
||||
Replaced the number of lines a pager should scroll to match the current
|
||||
Replaced by the number of lines a pager should scroll to match the current
|
||||
scroll position in kitty. See :opt:`scrollback_pager` for details.
|
||||
|
||||
``@scrolled-by``
|
||||
@@ -133,8 +133,21 @@ functions for the events you are interested in, for example:
|
||||
|
||||
def on_close(boss: Boss, window: Window, data: Dict[str, Any])-> None:
|
||||
# called when window is closed, typically when the program running in
|
||||
# it exits.
|
||||
# it exits
|
||||
|
||||
def on_set_user_var(boss: Boss, window: Window, data: Dict[str, Any]) -> None:
|
||||
# called when a "user variable" is set or deleted on a window. Here
|
||||
# data will contain key and value
|
||||
|
||||
def on_title_change(boss: Boss, window: Window, data: Dict[str, Any]) -> None:
|
||||
# called when the window title is changed on a window. Here
|
||||
# data will contain title and from_child. from_child will be True
|
||||
# when a title change was requested via escape code from the program
|
||||
# running in the terminal
|
||||
|
||||
def on_cmd_startstop(boss: Boss, window: Window, data: Dict[str, Any]) -> None:
|
||||
# called when the shell starts/stops executing a command. Here
|
||||
# data will contain is_start and time.
|
||||
|
||||
Every callback is passed a reference to the global ``Boss`` object as well as
|
||||
the ``Window`` object the action is occurring on. The ``data`` object is a dict
|
||||
|
||||
@@ -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
|
||||
|
||||
351
docs/mapping.rst
Normal file
351
docs/mapping.rst
Normal file
@@ -0,0 +1,351 @@
|
||||
:orphan:
|
||||
|
||||
Making your keyboard dance
|
||||
==============================
|
||||
|
||||
.. highlight:: conf
|
||||
|
||||
kitty has extremely powerful facilities for mapping keyboard actions.
|
||||
Things like combining actions, multi-key mappings, modal mappings,
|
||||
mappings that send arbitrary text, and mappings dependent on the program
|
||||
currently running in kitty.
|
||||
|
||||
Let's start with the basics. You can map a key press to an action in kitty using
|
||||
the following syntax::
|
||||
|
||||
map ctrl+a new_window_with_cwd
|
||||
|
||||
This will map the key press :kbd:`Ctrl+a` to open a new :term:`window`
|
||||
with the working directory set to the working directory of the current window.
|
||||
This is the basic operation of the map directive, the tip of the iceberg, for
|
||||
more read the sections below.
|
||||
|
||||
|
||||
Combining multiple actions on a single keypress
|
||||
-----------------------------------------------------
|
||||
|
||||
Multiple actions can be combined on a single keypress, like a macro. To do this
|
||||
map the key press to the :ac:`combine` action::
|
||||
|
||||
map key combine <separator> action1 <separator> action2 <separator> action3 ...
|
||||
|
||||
For example::
|
||||
|
||||
map kitty_mod+e combine : new_window : next_layout
|
||||
|
||||
This will create a new window and switch to the next available layout. You can
|
||||
also run arbitrarily powerful scripts on a key press. There are two major
|
||||
techniques for doing this, using remote control scripts or using kittens.
|
||||
|
||||
Remote control scripts
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
These can be written in any language and use the "kitten" binary to control
|
||||
kitty via its extensive :doc:`Remote control <remote-control>` API. First,
|
||||
if you just want to run a single remote control command on a key press,
|
||||
you can just do::
|
||||
|
||||
map f1 remote_control set-spacing margin=30
|
||||
|
||||
This will run the ``set-spacing`` command, changing window margins to 30 pixels. For
|
||||
more complex scripts, write a script file in any language you like and save it
|
||||
somewhere, preferably in the kitty configuration directory. Do not forget to make it
|
||||
executable. In the script file you run remote control commands by running the
|
||||
"kitten" binary, for example:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
#!/bin/sh
|
||||
|
||||
kitten @ set-spacing margin=30
|
||||
kitten @ new_window
|
||||
...
|
||||
|
||||
The script can perform arbitrarily complex logic and actions, limited only by
|
||||
the remote control API, that you can browse by running ``kitten @ --help``.
|
||||
To run the script you created on a key press, use::
|
||||
|
||||
map f1 remote_control_script /path/to/myscript
|
||||
|
||||
|
||||
Kittens
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
Here, kittens refer to Python scripts. The scripts have two parts, one that
|
||||
runs as a regular command line program inside a kitty window to, for example,
|
||||
ask the user for some input and a second part that runs inside the kitty
|
||||
process itself and can perform any operation on the kitty UI, which is itself
|
||||
implemented in Python. However, the kitty internal API is not documented and
|
||||
can (very rarely) change, so kittens are harder to get started with than remote
|
||||
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,
|
||||
:doc:`/kittens/unicode_input`, :doc:`/kittens/hints` and
|
||||
:doc:`/kittens/themes`. To learn about writing your own kittens, see
|
||||
:doc:`/kittens/custom`.
|
||||
|
||||
Syntax for specifying keys
|
||||
-----------------------------
|
||||
|
||||
A mapping maps a key press to some action. In their most basic form, keypresses
|
||||
are :code:`modifier+key`. Keys are identified simply by their lowercase Unicode
|
||||
characters. For example: :code:`a` for the :kbd:`A` key, :code:`[` for the left
|
||||
square bracket key, etc. For functional keys, such as :kbd:`Enter` or
|
||||
:kbd:`Escape`, the names are present at :ref:`Functional key definitions
|
||||
<functional>`. For modifier keys, the names are :kbd:`ctrl` (:kbd:`control`,
|
||||
:kbd:`⌃`), :kbd:`shift` (:kbd:`⇧`), :kbd:`alt` (:kbd:`opt`, :kbd:`option`,
|
||||
:kbd:`⌥`), :kbd:`super` (:kbd:`cmd`, :kbd:`command`, :kbd:`⌘`).
|
||||
|
||||
Additionally, you can use the name :opt:`kitty_mod` as a modifier, the default
|
||||
value of which is :kbd:`ctrl+shift`. The default kitty shortcuts are defined
|
||||
using this value, so by changing it in :file:`kitty.conf` you can change
|
||||
all the modifiers used by all the default shortcuts.
|
||||
|
||||
On Linux, you can also use XKB names for functional keys that don't have kitty
|
||||
names. See :link:`XKB keys
|
||||
<https://github.com/xkbcommon/libxkbcommon/blob/master/include/xkbcommon/xkbcommon-keysyms.h>`
|
||||
for a list of key names. The name to use is the part after the :code:`XKB_KEY_`
|
||||
prefix. Note that you can only use an XKB key name for keys that are not known
|
||||
as kitty keys.
|
||||
|
||||
Finally, you can use raw system key codes to map keys, again only for keys that
|
||||
are not known as kitty keys. To see the system key code for a key, start kitty
|
||||
with the :option:`kitty --debug-input` option, kitty will output some debug text
|
||||
for every key event. In that text look for :code:`native_code`, the value
|
||||
of that becomes the key name in the shortcut. For example:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
on_key_input: glfw key: 0x61 native_code: 0x61 action: PRESS mods: none text: 'a'
|
||||
|
||||
Here, the key name for the :kbd:`A` key is :code:`0x61` and you can use it with::
|
||||
|
||||
map ctrl+0x61 something
|
||||
|
||||
This maps :kbd:`Ctrl+A` to something.
|
||||
|
||||
|
||||
Multi-key mappings
|
||||
--------------------
|
||||
|
||||
A mapping in kitty can involve pressing multiple keys in sequence, with the
|
||||
syntax shown below::
|
||||
|
||||
map key1>key2>key3 action
|
||||
|
||||
For example::
|
||||
|
||||
map ctrl+f>2 set_font_size 20
|
||||
|
||||
The default mappings to run the :doc:`hints kitten </kittens/hints>` to select text on the screen are
|
||||
examples of multi-key mappings.
|
||||
|
||||
Unmapping default shortcuts
|
||||
-----------------------------
|
||||
|
||||
kitty comes with dozens of default keyboard mappings for common operations. See
|
||||
:doc:`actions` for the full list of actions and the default shortcuts that map
|
||||
to them. You can unmap an individual shortcut, so that it is passed on to the
|
||||
program running inside kitty, by mapping it to nothing, for example::
|
||||
|
||||
map kitty_mod+enter
|
||||
|
||||
This unmaps the default shortcut :sc:`new_window` to open a new window. Almost
|
||||
all default shortcuts are of the form ``modifier + key`` where the
|
||||
modifier defaults to :kbd:`Ctrl+Shift` and can be changed using the :opt:`kitty_mod` setting
|
||||
in :file:`kitty.conf`.
|
||||
|
||||
If you want to clear all default shortcuts, you can use
|
||||
:opt:`clear_all_shortcuts` in :file:`kitty.conf`.
|
||||
|
||||
If you would like kitty to completely ignore a key event, not even sending it to
|
||||
the program running in the terminal, map it to :ac:`discard_event`::
|
||||
|
||||
map kitty_mod+f1 discard_event
|
||||
|
||||
.. _conditional_mappings:
|
||||
|
||||
Conditional mappings depending on the state of the focused window
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Sometimes, you may want different mappings to be active when running a
|
||||
particular program in kitty, perhaps because it has some native functionality
|
||||
that duplicates kitty functions or there is a conflict, etc. kitty has the
|
||||
ability to create mappings that work only when the currently focused window
|
||||
matches some criteria, such as when it has a particular title or user variable.
|
||||
|
||||
Let's see some examples::
|
||||
|
||||
map --when-focus-on title:keyboard.protocol kitty_mod+t
|
||||
|
||||
This will cause :kbd:`kitty_mod+t` (the default shortcut for opening a new tab)
|
||||
to be unmapped only when the focused window
|
||||
has :code:`keyboard protocol` in its title. Run the show-key kitten as::
|
||||
|
||||
kitten show-key -m kitty
|
||||
|
||||
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 an editor::
|
||||
|
||||
map --when-focus-on var:in_editor kitty_mod+c
|
||||
|
||||
In order to make this work, you need to configure your editor as show below:
|
||||
|
||||
.. tab:: 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" }, {
|
||||
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" }, {
|
||||
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
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
This is accomplished by using ``map`` with :sc:`send_text <send_text>` in :file:`kitty.conf`.
|
||||
For example::
|
||||
|
||||
map f1 send_text normal,application Hello, world!
|
||||
|
||||
Now, pressing :kbd:`f1` will cause ``Hello, world!`` to show up at your shell
|
||||
prompt. To have the shell execute a command sent via ``send_text`` you need to
|
||||
also simulate pressing the enter key which is ``\r``. For example::
|
||||
|
||||
map f1 send_text normal,application echo Hello, world!\r
|
||||
|
||||
Now, if you press :kbd:`f1` when at shell prompt it will run the ``echo Hello,
|
||||
world!`` command.
|
||||
|
||||
To have one key press send another key press, use :ac:`send_key`::
|
||||
|
||||
map alt+s send_key ctrl+s
|
||||
|
||||
This causes the program running in kitty to receive the :kbd:`ctrl+s` key when
|
||||
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.
|
||||
|
||||
.. _modal_mappings:
|
||||
|
||||
Modal mappings
|
||||
--------------------------
|
||||
|
||||
kitty has the ability, like vim, to use *modal* key maps. Except that unlike
|
||||
vim it allows you to define your own arbitrary number of modes. To create a new
|
||||
mode, use ``map --new-mode <my mode name> <shortcut to enter mode>``. For
|
||||
example, lets create a mode to manage windows: switching focus, moving the window, etc.::
|
||||
|
||||
# Create a new "manage windows" mode (mw)
|
||||
map --new-mode mw kitty_mod+f7
|
||||
|
||||
# Switch focus to the neighboring window in the indicated direction using arrow keys
|
||||
map --mode mw left neighboring_window left
|
||||
map --mode mw right neighboring_window right
|
||||
map --mode mw up neighboring_window up
|
||||
map --mode mw down neighboring_window down
|
||||
|
||||
# Move the active window in the indicated direction
|
||||
map --mode mw shift+up move_window up
|
||||
map --mode mw shift+left move_window left
|
||||
map --mode mw shift+right move_window right
|
||||
map --mode mw shift+down move_window down
|
||||
|
||||
# Resize the active window
|
||||
map --mode mw n resize_window narrower
|
||||
map --mode mw w resize_window wider
|
||||
map --mode mw t resize_window taller
|
||||
map --mode mw s resize_window shorter
|
||||
|
||||
# Exit the manage window mode
|
||||
map --mode mw esc pop_keyboard_mode
|
||||
|
||||
Now, if you run kitty as:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
kitty -o enabled_layouts=vertical --session <(echo "launch\nlaunch\nlaunch")
|
||||
|
||||
Press :kbd:`Ctrl+Shift+F7` to enter the mode and then press the up and
|
||||
down arrow keys to focus the next/previous window. Press :kbd:`Shift+Up` or
|
||||
:kbd:`Shift+Down` to move the active window up and down. Press :kbd:`t` to make
|
||||
the active window taller and :kbd:`s` to make it shorter. To exit the mode
|
||||
press :kbd:`Esc`.
|
||||
|
||||
Pressing an unknown key while in a custom keyboard mode by default
|
||||
beeps. This can be controlled by the ``map --on-unknown`` option as shown
|
||||
below::
|
||||
|
||||
# Beep on unknown keys
|
||||
map --new-mode XXX --on-unknown beep ...
|
||||
# Ingore unknown keys silently
|
||||
map --new-mode XXX --on-unknown ignore ...
|
||||
# Beep and exit the keyboard mode on unknown key
|
||||
map --new-mode XXX --on-unknown end ...
|
||||
# Pass unknown keys to the program running in the active window
|
||||
map --new-mode XXX --on-unknown passthrough ...
|
||||
|
||||
When a key matches an action in a custom keyboard mode, the action is performed
|
||||
and the custom keyboard mode remains in effect. If you would rather have the
|
||||
keyboard mode end after the action you can use ``map --on-action`` as shown
|
||||
below::
|
||||
|
||||
# Have this keyboard mode automatically exit after performing any action
|
||||
map --new-mode XXX --on-action end ...
|
||||
|
||||
|
||||
All mappable actions
|
||||
------------------------
|
||||
|
||||
There is a list of :doc:`all mappable actions <actions>`.
|
||||
|
||||
Debugging mapping issues
|
||||
------------------------------
|
||||
|
||||
To debug mapping issues, kitty has several facilities. First, when you run
|
||||
kitty with the ``--debug-input`` command line flag it outputs details
|
||||
about all key events it receives form the system and how they are handled.
|
||||
|
||||
To see what key events are sent to applications, run kitty like this::
|
||||
|
||||
kitty kitten show-key
|
||||
|
||||
Press the keys you want to debug and the kitten will print out the bytes it
|
||||
receives. Note that this uses the legacy terminal keyboard protocol that does
|
||||
not support all keys and key events. To debug the :doc:`full kitty keyboard
|
||||
protocol that <keyboard-protocol>` that is nowadays being adopted by more and
|
||||
more programs, use::
|
||||
|
||||
kitty kitten show-key -m kitty
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user