mirror of
https://gitlab.uni-freiburg.de/opensourcevdi/spice-common
synced 2025-12-26 14:18:36 +00:00
Compare commits
724 Commits
before-spl
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4d5c60226c | ||
|
|
c1b8dbbb9b | ||
|
|
492c22f444 | ||
|
|
ebf052d051 | ||
|
|
2f5f1d3854 | ||
|
|
a791a224e7 | ||
|
|
8c0319e31d | ||
|
|
29dacb5f53 | ||
|
|
91fc091358 | ||
|
|
fe4395f3d7 | ||
|
|
bb8f66983a | ||
|
|
58d375e5ea | ||
|
|
8a19611049 | ||
|
|
a7b5474bf8 | ||
|
|
96dd787377 | ||
|
|
de79bac8e9 | ||
|
|
bac2aa4e2d | ||
|
|
18f753c52f | ||
|
|
bb0831cc10 | ||
|
|
fcfe9104bd | ||
|
|
c39f4fd002 | ||
|
|
91362d045a | ||
|
|
68188b0c21 | ||
|
|
c48140c493 | ||
|
|
6b662331f7 | ||
|
|
bd15c96f54 | ||
|
|
a627a14af0 | ||
|
|
6838f30079 | ||
|
|
e49301ebd1 | ||
|
|
d8fe0cbb84 | ||
|
|
d589542e04 | ||
|
|
3b81e67979 | ||
|
|
b24fe6b66b | ||
|
|
ef1b6ff7b8 | ||
|
|
404d74782c | ||
|
|
762e0abae3 | ||
|
|
fa0c199d33 | ||
|
|
0d7d0d35d8 | ||
|
|
b03c894c21 | ||
|
|
03bde6fdb2 | ||
|
|
243c314b3f | ||
|
|
c39cc1b1ef | ||
|
|
7daee890be | ||
|
|
2f045752d5 | ||
|
|
b843d02a1b | ||
|
|
ca1016eb15 | ||
|
|
8e0e13881e | ||
|
|
bca74fb6c9 | ||
|
|
35be203f42 | ||
|
|
283d82b0a3 | ||
|
|
8d9a79dd7d | ||
|
|
a95ba61d32 | ||
|
|
ba7af04f65 | ||
|
|
5d8feeb19a | ||
|
|
a5ee3cbac5 | ||
|
|
8d969b66ed | ||
|
|
5b93090e60 | ||
|
|
c00a152e00 | ||
|
|
7a84f60267 | ||
|
|
4c6b360f6b | ||
|
|
3caedf3bc2 | ||
|
|
a971c59166 | ||
|
|
05c0c26839 | ||
|
|
bb03ff099b | ||
|
|
8470ef9df2 | ||
|
|
402bc6b237 | ||
|
|
47e149705a | ||
|
|
81f0331469 | ||
|
|
61ce54ef6c | ||
|
|
713a3e09fb | ||
|
|
8f9eb611f8 | ||
|
|
911a7aa9c6 | ||
|
|
6a64d86d1d | ||
|
|
365d7019d5 | ||
|
|
35a9debe93 | ||
|
|
31a14b20d0 | ||
|
|
11009d1b64 | ||
|
|
a3ec7c173d | ||
|
|
ec4e44200a | ||
|
|
b2f919f109 | ||
|
|
19ea60416c | ||
|
|
2cec5f99af | ||
|
|
27fd63ff72 | ||
|
|
df66d9a151 | ||
|
|
8e82bf5661 | ||
|
|
03e1fb94e4 | ||
|
|
35f45282d4 | ||
|
|
b699221f00 | ||
|
|
ea864c70d9 | ||
|
|
d5d1d5b0bf | ||
|
|
a446b5b27b | ||
|
|
08fafdbb33 | ||
|
|
6595de58a2 | ||
|
|
109f6a4802 | ||
|
|
ac4763bd89 | ||
|
|
48944f6f41 | ||
|
|
87e2db9798 | ||
|
|
e761c2d4de | ||
|
|
151c23d235 | ||
|
|
26d3f6e138 | ||
|
|
f3d6c5f322 | ||
|
|
da6a405f25 | ||
|
|
2561f62283 | ||
|
|
34807c600c | ||
|
|
5a31a3850d | ||
|
|
785ac8de4f | ||
|
|
32beff2ff5 | ||
|
|
ead7790d47 | ||
|
|
f191053a8c | ||
|
|
3331ad1a04 | ||
|
|
a16c7027c5 | ||
|
|
99f6aa0028 | ||
|
|
d4248885e8 | ||
|
|
a5a86a1caf | ||
|
|
62b44b3073 | ||
|
|
2640ff294a | ||
|
|
4727c19d36 | ||
|
|
c392a7fee7 | ||
|
|
493475e012 | ||
|
|
60e0453698 | ||
|
|
7abd2b36d9 | ||
|
|
01417b7533 | ||
|
|
a52a0a0906 | ||
|
|
ff2e99d893 | ||
|
|
cc109a83b6 | ||
|
|
3b517a2243 | ||
|
|
4fc4c2db36 | ||
|
|
09fba0677d | ||
|
|
5bcfa711d9 | ||
|
|
47ba8e0f25 | ||
|
|
bfebdc5eb4 | ||
|
|
f236c1ef94 | ||
|
|
21edc8611d | ||
|
|
b628730115 | ||
|
|
4951c71553 | ||
|
|
bbb5163e61 | ||
|
|
1fbac71c84 | ||
|
|
e123f94939 | ||
|
|
a294cad01c | ||
|
|
5ef652b7e3 | ||
|
|
2f64e2edbb | ||
|
|
187df0cfdb | ||
|
|
79a9fad3a2 | ||
|
|
bd75d3f934 | ||
|
|
5f1f369e41 | ||
|
|
3cd3886b27 | ||
|
|
dac34baaab | ||
|
|
af66a4ccad | ||
|
|
81e2092fc7 | ||
|
|
387d1842d1 | ||
|
|
fce4486755 | ||
|
|
1cdc3cc3b0 | ||
|
|
cb00ccfaab | ||
|
|
302e30ff43 | ||
|
|
92d5dfd4bf | ||
|
|
db245ae740 | ||
|
|
86136f9a95 | ||
|
|
c5e7d92dc6 | ||
|
|
e8c76358ee | ||
|
|
4ccc20a7f6 | ||
|
|
60883a0321 | ||
|
|
a5de31bc8a | ||
|
|
7462c171e1 | ||
|
|
53c0c5a665 | ||
|
|
7fa8bda275 | ||
|
|
7f6c55790b | ||
|
|
02530a80df | ||
|
|
811fff0791 | ||
|
|
413da761ec | ||
|
|
3e116a6c71 | ||
|
|
e3af47fe9d | ||
|
|
ea20b8c013 | ||
|
|
e307130c18 | ||
|
|
9ca8914b7c | ||
|
|
2e914f3305 | ||
|
|
0a753b93b5 | ||
|
|
6c09f943ce | ||
|
|
57f2c61712 | ||
|
|
96700c849d | ||
|
|
5173ff871a | ||
|
|
3050b4e1f6 | ||
|
|
16aa8c98d8 | ||
|
|
3e6dedaa51 | ||
|
|
924f47a653 | ||
|
|
6dc745e877 | ||
|
|
2d32025f77 | ||
|
|
7f4da3ff36 | ||
|
|
c01a4a6fc3 | ||
|
|
a45f656aac | ||
|
|
ac8d27104b | ||
|
|
a4aad511f1 | ||
|
|
bb55f06a51 | ||
|
|
125cfa7fb2 | ||
|
|
6077523a5f | ||
|
|
aee2b91fe2 | ||
|
|
5b6878e72c | ||
|
|
2060672e81 | ||
|
|
87493929b4 | ||
|
|
ddfb8807c6 | ||
|
|
8a68e67afa | ||
|
|
979717350d | ||
|
|
b9dca950fb | ||
|
|
7d16536672 | ||
|
|
90f95c2f8c | ||
|
|
6b93b3fce8 | ||
|
|
bb15d4815a | ||
|
|
5dd0c2f70a | ||
|
|
d6c05fb046 | ||
|
|
12af62316d | ||
|
|
25c00ef146 | ||
|
|
e2fad781ec | ||
|
|
9b2c989dd9 | ||
|
|
83e1229417 | ||
|
|
f82a6c5349 | ||
|
|
f4a0fec5e9 | ||
|
|
82c2e2315c | ||
|
|
e8314732a7 | ||
|
|
f636ef42a0 | ||
|
|
3618db77b5 | ||
|
|
79a6ca2a51 | ||
|
|
291475318f | ||
|
|
c0cc563e10 | ||
|
|
8b21fc5ea1 | ||
|
|
0046ee5e81 | ||
|
|
a2d32a1fdd | ||
|
|
e3609f06a3 | ||
|
|
394b5d31c0 | ||
|
|
7a535a6141 | ||
|
|
7a6980def8 | ||
|
|
1ca7e2d765 | ||
|
|
499b10e494 | ||
|
|
946d3dda22 | ||
|
|
6ea60433de | ||
|
|
9bf4c32288 | ||
|
|
204ff1ae2e | ||
|
|
b4e07c31cf | ||
|
|
8069bf498d | ||
|
|
31d4622687 | ||
|
|
bb8d75bf31 | ||
|
|
6496437e80 | ||
|
|
e98e08594c | ||
|
|
3def5a8448 | ||
|
|
cd932df7a2 | ||
|
|
75863fb69f | ||
|
|
246f3a02b4 | ||
|
|
2b5cadcd8a | ||
|
|
7050511d9e | ||
|
|
1eff0d1207 | ||
|
|
4b0c25823f | ||
|
|
0385a67ef8 | ||
|
|
da4926bd26 | ||
|
|
f90ab1f19b | ||
|
|
252d1b61ed | ||
|
|
bc9df58162 | ||
|
|
1378d5cfc4 | ||
|
|
16deca6f1c | ||
|
|
5110dbcbb7 | ||
|
|
cfbae20c48 | ||
|
|
968ce158f0 | ||
|
|
30ff9c3807 | ||
|
|
3a6a84e172 | ||
|
|
e13c1d66b7 | ||
|
|
0ac8e55ddf | ||
|
|
8e8476d932 | ||
|
|
3f04e2649d | ||
|
|
638c77f3e6 | ||
|
|
345557f044 | ||
|
|
818b820644 | ||
|
|
656106b304 | ||
|
|
258123318d | ||
|
|
0fc3d4209f | ||
|
|
82a5f19d99 | ||
|
|
a3598f62aa | ||
|
|
32e2ed57b5 | ||
|
|
a526fea413 | ||
|
|
26dce6fede | ||
|
|
95743f40a2 | ||
|
|
a84f868e48 | ||
|
|
e95f05452a | ||
|
|
1dcdefa8b3 | ||
|
|
b208389334 | ||
|
|
992ebac6b5 | ||
|
|
f7d3a57ce4 | ||
|
|
42795a6d00 | ||
|
|
f522473842 | ||
|
|
72b0d603e1 | ||
|
|
e98f8a430f | ||
|
|
349a74d7c2 | ||
|
|
55070333f6 | ||
|
|
836bbd0e41 | ||
|
|
68c0f93889 | ||
|
|
160232f8f6 | ||
|
|
d58a5b6a5a | ||
|
|
5312ea3f35 | ||
|
|
70aa6d39b6 | ||
|
|
a1f6f42a33 | ||
|
|
0e550416f1 | ||
|
|
8152238618 | ||
|
|
423518768e | ||
|
|
4690e7239d | ||
|
|
b9dd7ed8f1 | ||
|
|
d240af18a4 | ||
|
|
fce119be44 | ||
|
|
7b2c2e620e | ||
|
|
763735d636 | ||
|
|
0629153699 | ||
|
|
d1d6210547 | ||
|
|
b17894e764 | ||
|
|
e2f7a9235f | ||
|
|
abdef4fd2a | ||
|
|
78a17ba00a | ||
|
|
8816d30e67 | ||
|
|
d84f5a5e63 | ||
|
|
20bda4dba9 | ||
|
|
129bd04766 | ||
|
|
f97c9c3900 | ||
|
|
df4ec5c318 | ||
|
|
617be0f74b | ||
|
|
420a15b776 | ||
|
|
a69fb1ec34 | ||
|
|
75d9842e7d | ||
|
|
b98f19b168 | ||
|
|
fc46379b37 | ||
|
|
754cd54e1a | ||
|
|
46fa9d5efb | ||
|
|
5729664523 | ||
|
|
885b1a6bb9 | ||
|
|
4c2d0e9772 | ||
|
|
2eaef9c16d | ||
|
|
8096b1206b | ||
|
|
fd0aba2750 | ||
|
|
f3478aa4b6 | ||
|
|
122be3d1f7 | ||
|
|
41c7ea6611 | ||
|
|
0dda6fbf55 | ||
|
|
3bf6e7b899 | ||
|
|
b0f1d31dd1 | ||
|
|
6ce1a61577 | ||
|
|
00d1cda4ce | ||
|
|
cd88d0294c | ||
|
|
fea48544a8 | ||
|
|
27e32fa8a6 | ||
|
|
5fda05740f | ||
|
|
552e842a16 | ||
|
|
29eff61cf8 | ||
|
|
d11df6b66b | ||
|
|
a3a2bb9ea7 | ||
|
|
637621a9b9 | ||
|
|
53f6d1269a | ||
|
|
94898df6b4 | ||
|
|
45e2844845 | ||
|
|
72ae9b2971 | ||
|
|
c208ca85cd | ||
|
|
c2f2096d90 | ||
|
|
c25c75b552 | ||
|
|
74e50b57ae | ||
|
|
70d4739ce2 | ||
|
|
429ad96537 | ||
|
|
a6d6e8435a | ||
|
|
6a882282f1 | ||
|
|
3306492247 | ||
|
|
65ba949fb0 | ||
|
|
9f6a671294 | ||
|
|
b64ee40a60 | ||
|
|
c39f2da17e | ||
|
|
8dd7374a1d | ||
|
|
9574246403 | ||
|
|
5684ed10be | ||
|
|
f122d3dadc | ||
|
|
db5bff3728 | ||
|
|
a25ebbac56 | ||
|
|
fffe755d9c | ||
|
|
eeab433539 | ||
|
|
518c57db20 | ||
|
|
14c595b609 | ||
|
|
dde1fe3533 | ||
|
|
2ff5c77fff | ||
|
|
f80b229e07 | ||
|
|
858a0bfae9 | ||
|
|
765652da1d | ||
|
|
30a33922d8 | ||
|
|
1d7acdcf57 | ||
|
|
31ebe7c6d5 | ||
|
|
564635e3c1 | ||
|
|
a607077883 | ||
|
|
f4a4d52702 | ||
|
|
36fd7325e5 | ||
|
|
5faba1e860 | ||
|
|
1d527e21d5 | ||
|
|
af682b1b06 | ||
|
|
0996c33d6d | ||
|
|
1fd73d0a98 | ||
|
|
4423ea5d2a | ||
|
|
ab7cae45bc | ||
|
|
c9ecd0e29e | ||
|
|
30e8237934 | ||
|
|
6439bec0de | ||
|
|
86dcd22d33 | ||
|
|
adb36c6185 | ||
|
|
a5871c80a9 | ||
|
|
580ca81536 | ||
|
|
5f241e655b | ||
|
|
6b409c4a79 | ||
|
|
48da2c6654 | ||
|
|
de1dee75c2 | ||
|
|
edaafa187d | ||
|
|
2c34cf49b5 | ||
|
|
31819a2424 | ||
|
|
63e575d5fc | ||
|
|
215b7571d4 | ||
|
|
e5a03766ec | ||
|
|
ced5c55925 | ||
|
|
4673a61cce | ||
|
|
7773c0d59b | ||
|
|
89426e491e | ||
|
|
3983097ed5 | ||
|
|
642308ecec | ||
|
|
38047fb46f | ||
|
|
22f8dd18f0 | ||
|
|
62f3024f42 | ||
|
|
073d064b86 | ||
|
|
0eb567e6fb | ||
|
|
806d3273fa | ||
|
|
3029eae630 | ||
|
|
15b8f28c14 | ||
|
|
57570953dc | ||
|
|
c5a61aaa30 | ||
|
|
1d47225a8e | ||
|
|
8f722db28e | ||
|
|
62b996ffb0 | ||
|
|
5359304713 | ||
|
|
4284011bdc | ||
|
|
d0139f824e | ||
|
|
bbd8f9a5e2 | ||
|
|
73282208f0 | ||
|
|
d3dd8bcea3 | ||
|
|
1c97fea956 | ||
|
|
384698af37 | ||
|
|
ad862c4d4b | ||
|
|
74439e8e6e | ||
|
|
a8f756eabf | ||
|
|
83b84428ec | ||
|
|
657e1c5291 | ||
|
|
3312a0f70b | ||
|
|
89b902789b | ||
|
|
bc73df4e47 | ||
|
|
739a859d79 | ||
|
|
2eaf7c9572 | ||
|
|
5603961ffa | ||
|
|
2a4bf49edd | ||
|
|
8473d0ae71 | ||
|
|
6a65f470d1 | ||
|
|
6c7552d543 | ||
|
|
55ec596798 | ||
|
|
51df6f775a | ||
|
|
5b6be16b37 | ||
|
|
2505f9ac96 | ||
|
|
0f45924f4c | ||
|
|
53ee80bd7d | ||
|
|
8af947e7b2 | ||
|
|
00db440878 | ||
|
|
279be89836 | ||
|
|
0853b579df | ||
|
|
2ccf106920 | ||
|
|
487f914a5d | ||
|
|
c5ed374a32 | ||
|
|
1cd26b87c1 | ||
|
|
f06f699d78 | ||
|
|
fd9ba72f1a | ||
|
|
472e563591 | ||
|
|
6424c0baee | ||
|
|
75cb2701d3 | ||
|
|
580adf7c36 | ||
|
|
6e04b94751 | ||
|
|
daf406a179 | ||
|
|
07b3150cb1 | ||
|
|
7790dacfd3 | ||
|
|
5376f1d88c | ||
|
|
0a6580d2e6 | ||
|
|
df56d585cb | ||
|
|
417dbedc0b | ||
|
|
efd1d3cb4d | ||
|
|
2ff25b7567 | ||
|
|
838596a257 | ||
|
|
93cd2f6836 | ||
|
|
b61f43f228 | ||
|
|
a18bed136f | ||
|
|
80cc3f680a | ||
|
|
397eb47816 | ||
|
|
c3f2d217af | ||
|
|
a78da942a7 | ||
|
|
1118712c59 | ||
|
|
2493c60ff7 | ||
|
|
98f9097c49 | ||
|
|
d7719d3e60 | ||
|
|
bdc9951049 | ||
|
|
76a0c2fae8 | ||
|
|
fc1f511bb8 | ||
|
|
2ee5cb522e | ||
|
|
02c82b468c | ||
|
|
d13fdd7fa9 | ||
|
|
47122befcd | ||
|
|
9057e0aef3 | ||
|
|
f8db887eb0 | ||
|
|
56a0cf2dad | ||
|
|
401801b5ba | ||
|
|
f471022453 | ||
|
|
437b817f49 | ||
|
|
899a7c75e3 | ||
|
|
304a16fdad | ||
|
|
d8c3568a31 | ||
|
|
f77805773f | ||
|
|
986ad88c28 | ||
|
|
04ed3b8cbe | ||
|
|
9749e7ed14 | ||
|
|
9b74e47ed3 | ||
|
|
fb6904f528 | ||
|
|
f7ec855af3 | ||
|
|
26a533d6eb | ||
|
|
523875d8c5 | ||
|
|
7b146745ee | ||
|
|
449c5da90f | ||
|
|
dd63a3b656 | ||
|
|
7665dcf1bb | ||
|
|
f88a7b7bec | ||
|
|
c48b0a0672 | ||
|
|
53f7f543f9 | ||
|
|
f2ed9a35a2 | ||
|
|
a1d1d396cd | ||
|
|
f717273002 | ||
|
|
f0f578abee | ||
|
|
eff8b1a0e4 | ||
|
|
179928fceb | ||
|
|
365866c4c9 | ||
|
|
0130e8dc39 | ||
|
|
184feb541a | ||
|
|
aa43c0d61e | ||
|
|
86b0568055 | ||
|
|
f4c729aad3 | ||
|
|
5720971c45 | ||
|
|
2d054e0e69 | ||
|
|
6183bbde24 | ||
|
|
5a7e5876e6 | ||
|
|
c04d4d55bc | ||
|
|
dcebede0ca | ||
|
|
127a76a3b8 | ||
|
|
1b5edbe49e | ||
|
|
fec803156b | ||
|
|
b216f66f10 | ||
|
|
838ec7d87b | ||
|
|
c6e6dacb30 | ||
|
|
d39dfbfef9 | ||
|
|
ba52c4cae2 | ||
|
|
14218d7d6b | ||
|
|
edac1b36b5 | ||
|
|
d2ee99e15f | ||
|
|
37325b4e88 | ||
|
|
3aad79d9c6 | ||
|
|
9287e53b6c | ||
|
|
d167e2ead8 | ||
|
|
f76fc28fc5 | ||
|
|
83c0d642ed | ||
|
|
6049db492f | ||
|
|
ac26fd7acb | ||
|
|
062bf67442 | ||
|
|
619b99511d | ||
|
|
862b9b1a9e | ||
|
|
137b1a549e | ||
|
|
f9e0a644ae | ||
|
|
dd57d05a52 | ||
|
|
fb3fe2272c | ||
|
|
df74a17238 | ||
|
|
2f1ba3b77f | ||
|
|
2195369372 | ||
|
|
ed873a9eb5 | ||
|
|
2da14b6cc8 | ||
|
|
5bfa9cadb3 | ||
|
|
268d3e3d2f | ||
|
|
5b3cdad921 | ||
|
|
8639bbdc9d | ||
|
|
a74209a9c3 | ||
|
|
c22fbffbc7 | ||
|
|
fbdd4e41c0 | ||
|
|
6f3918ce7c | ||
|
|
c8b4c5ec49 | ||
|
|
dde1c62a91 | ||
|
|
840bcfe7a2 | ||
|
|
9385db6875 | ||
|
|
d45b3e2765 | ||
|
|
7e4cfbe305 | ||
|
|
2c5041c3f8 | ||
|
|
dd4a446f5d | ||
|
|
60046b309d | ||
|
|
b3a00f4411 | ||
|
|
90a1240f27 | ||
|
|
7ea1cc54b1 | ||
|
|
6edeb43747 | ||
|
|
01955e7007 | ||
|
|
96ca358669 | ||
|
|
6175014ed7 | ||
|
|
a4f4ddf56c | ||
|
|
ae39a05620 | ||
|
|
d8e49b71d4 | ||
|
|
ead4b8810a | ||
|
|
793e5d0350 | ||
|
|
6674e1c136 | ||
|
|
57ce430ccd | ||
|
|
c108e4ee8c | ||
|
|
261d270cc8 | ||
|
|
1450bb4ddb | ||
|
|
31ef0c626d | ||
|
|
fa640286f4 | ||
|
|
9b3e972cdc | ||
|
|
b34169feb6 | ||
|
|
7e8ba10779 | ||
|
|
e443c9f603 | ||
|
|
0aadda70d5 | ||
|
|
b6faccb381 | ||
|
|
370ba35339 | ||
|
|
f88e851ed6 | ||
|
|
3363fe79f9 | ||
|
|
4857653686 | ||
|
|
8db88d2854 | ||
|
|
a7b93bd43d | ||
|
|
6440a1e533 | ||
|
|
4d8d2b6124 | ||
|
|
ffc3e8a327 | ||
|
|
fe93908238 | ||
|
|
fc27fb20b8 | ||
|
|
30e84783ca | ||
|
|
7cdf8de00a | ||
|
|
5ebeee5114 | ||
|
|
5aa31e753f | ||
|
|
b52948d792 | ||
|
|
063f4dd385 | ||
|
|
1a83284e9c | ||
|
|
149bb89adb | ||
|
|
9ffc614a6c | ||
|
|
df09927c3b | ||
|
|
c08e04b478 | ||
|
|
8a10919658 | ||
|
|
81f40cca5f | ||
|
|
b46d36bc1c | ||
|
|
5f2e99c3da | ||
|
|
be6392a5ad | ||
|
|
8543d04cd2 | ||
|
|
222607814f | ||
|
|
79502376d1 | ||
|
|
9b9592f80c | ||
|
|
f67bcd03e9 | ||
|
|
04dc2bee9e | ||
|
|
86e286ba20 | ||
|
|
2c55c9d0c6 | ||
|
|
c2f58492ad | ||
|
|
c6bd210ad0 | ||
|
|
c0b048ebef | ||
|
|
0c1b6de4ad | ||
|
|
c2adbb00dc | ||
|
|
9768ebf80d | ||
|
|
735e431671 | ||
|
|
7eba850ad5 | ||
|
|
b49c4794ee | ||
|
|
2449260c81 | ||
|
|
f8f6231ecd | ||
|
|
5020adc59f | ||
|
|
bf5511033d | ||
|
|
800784df43 | ||
|
|
d40a181a20 | ||
|
|
9dff18a399 | ||
|
|
d5d26cac49 | ||
|
|
535b52db66 | ||
|
|
a976c16cf3 | ||
|
|
5f44094940 | ||
|
|
22fc0b0145 | ||
|
|
178c7eaff6 | ||
|
|
cbf423f833 | ||
|
|
ffeb6ce677 | ||
|
|
2e4b605272 | ||
|
|
f37ba0d032 | ||
|
|
ff25524948 | ||
|
|
6af29a97ac | ||
|
|
6bb8d93bbf | ||
|
|
d77d056022 | ||
|
|
7814bdf71d | ||
|
|
39fef7a5da | ||
|
|
e96dbb4172 | ||
|
|
c678122d6a | ||
|
|
2ab866f522 | ||
|
|
e3f6941895 | ||
|
|
a0339261d4 | ||
|
|
1b41d15a99 | ||
|
|
fb24e4e28b | ||
|
|
c1e4e1be63 | ||
|
|
feaee86076 | ||
|
|
bc4f5db323 | ||
|
|
b6afcd632e | ||
|
|
2d4e0d2000 | ||
|
|
3df7798413 | ||
|
|
7f86151f18 | ||
|
|
69aecfc1bc | ||
|
|
a7cc3c6a56 | ||
|
|
7307fccb71 | ||
|
|
eb01d2fc46 | ||
|
|
51cf6fce72 | ||
|
|
f7af6264ea | ||
|
|
a1df67b3c5 | ||
|
|
13fb823795 | ||
|
|
61c30fcdcf | ||
|
|
f87bb23ad2 | ||
|
|
fbb6b9984a | ||
|
|
985ec9d6ec | ||
|
|
9f7d6175e7 | ||
|
|
3bc7d096b6 | ||
|
|
0a96fe9364 | ||
|
|
4feaffad8e | ||
|
|
508547c100 | ||
|
|
c4482c7ff2 | ||
|
|
e800e51d4e | ||
|
|
c968e76f96 | ||
|
|
3e4b2571a2 | ||
|
|
c1403ee6bf | ||
|
|
bb133148d8 | ||
|
|
cf705650d4 | ||
|
|
124f767b94 |
52
.gitlab-ci.yml
Normal file
52
.gitlab-ci.yml
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
image: fedora:latest
|
||||||
|
|
||||||
|
before_script:
|
||||||
|
- >
|
||||||
|
dnf install git libtool make libasan gawk
|
||||||
|
python3 python3-pyparsing glib-networking
|
||||||
|
meson ninja-build gdk-pixbuf2-devel
|
||||||
|
glib2-devel pixman-devel openssl-devel libjpeg-devel
|
||||||
|
libcacard-devel cyrus-sasl-devel lz4-devel opus-devel
|
||||||
|
gstreamer1-devel gstreamer1-plugins-base-devel
|
||||||
|
-y
|
||||||
|
- git clone ${CI_REPOSITORY_URL/spice-common.git/spice-protocol.git}
|
||||||
|
- meson --buildtype=release spice-protocol build-spice-protocol --prefix=/usr --werror
|
||||||
|
- ninja -C build-spice-protocol install
|
||||||
|
|
||||||
|
makecheck:
|
||||||
|
script:
|
||||||
|
- >
|
||||||
|
CFLAGS='-O2 -pipe -g -fsanitize=address -fno-omit-frame-pointer -Wframe-larger-than=40920'
|
||||||
|
LDFLAGS='-fsanitize=address -lasan'
|
||||||
|
./autogen.sh --enable-extra-checks
|
||||||
|
- make
|
||||||
|
- make check || (cat tests/test-suite.log && exit 1)
|
||||||
|
|
||||||
|
meson-makecheck:
|
||||||
|
script:
|
||||||
|
- >
|
||||||
|
CFLAGS='-O2 -pipe -g -fsanitize=address -fno-omit-frame-pointer -Wframe-larger-than=40920'
|
||||||
|
LDFLAGS='-fsanitize=address -lasan'
|
||||||
|
meson build -Dextra-checks=true || (cat build/meson-logs/meson-log.txt && exit 1)
|
||||||
|
- ninja -C build
|
||||||
|
- (cd build && meson test) || (cat build/meson-logs/testlog.txt && exit 1)
|
||||||
|
|
||||||
|
make-win:
|
||||||
|
script:
|
||||||
|
- >
|
||||||
|
dnf install mingw64-gcc mingw64-pkg-config mingw64-pixman mingw64-openssl
|
||||||
|
mingw64-opus mingw64-glib2 mingw64-glib-networking mingw64-gdk-pixbuf
|
||||||
|
'wine-core(x86-64)'
|
||||||
|
-y
|
||||||
|
- mkdir spice-protocol/build
|
||||||
|
- (cd spice-protocol/build && mingw64-meson --werror && ninja install)
|
||||||
|
- NOCONFIGURE=yes ./autogen.sh
|
||||||
|
- export WINEPATH='Z:\usr\x86_64-w64-mingw32\sys-root\mingw\bin'
|
||||||
|
- >
|
||||||
|
PYTHON=python3
|
||||||
|
CFLAGS='-O2 -pipe -g -fsanitize=address -fno-omit-frame-pointer -Wframe-larger-than=40920'
|
||||||
|
LDFLAGS='-fsanitize=address -lasan'
|
||||||
|
mingw64-configure --enable-extra-checks
|
||||||
|
- make
|
||||||
|
- export LANG=en_US.UTF-8
|
||||||
|
- make LOG_COMPILER=wine check || (cat tests/test-suite.log && exit 1)
|
||||||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[submodule "common/recorder"]
|
||||||
|
path = common/recorder
|
||||||
|
url = https://github.com/c3d/recorder.git
|
||||||
3
.gitpublish
Normal file
3
.gitpublish
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[gitpublishprofile "default"]
|
||||||
|
to = spice-devel@lists.freedesktop.org
|
||||||
|
prefix = PATCH spice-common
|
||||||
502
COPYING
Normal file
502
COPYING
Normal file
@ -0,0 +1,502 @@
|
|||||||
|
GNU LESSER GENERAL PUBLIC LICENSE
|
||||||
|
Version 2.1, February 1999
|
||||||
|
|
||||||
|
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
[This is the first released version of the Lesser GPL. It also counts
|
||||||
|
as the successor of the GNU Library Public License, version 2, hence
|
||||||
|
the version number 2.1.]
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The licenses for most software are designed to take away your
|
||||||
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
|
Licenses are intended to guarantee your freedom to share and change
|
||||||
|
free software--to make sure the software is free for all its users.
|
||||||
|
|
||||||
|
This license, the Lesser General Public License, applies to some
|
||||||
|
specially designated software packages--typically libraries--of the
|
||||||
|
Free Software Foundation and other authors who decide to use it. You
|
||||||
|
can use it too, but we suggest you first think carefully about whether
|
||||||
|
this license or the ordinary General Public License is the better
|
||||||
|
strategy to use in any particular case, based on the explanations below.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom of use,
|
||||||
|
not price. Our General Public Licenses are designed to make sure that
|
||||||
|
you have the freedom to distribute copies of free software (and charge
|
||||||
|
for this service if you wish); that you receive source code or can get
|
||||||
|
it if you want it; that you can change the software and use pieces of
|
||||||
|
it in new free programs; and that you are informed that you can do
|
||||||
|
these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to make restrictions that forbid
|
||||||
|
distributors to deny you these rights or to ask you to surrender these
|
||||||
|
rights. These restrictions translate to certain responsibilities for
|
||||||
|
you if you distribute copies of the library or if you modify it.
|
||||||
|
|
||||||
|
For example, if you distribute copies of the library, whether gratis
|
||||||
|
or for a fee, you must give the recipients all the rights that we gave
|
||||||
|
you. You must make sure that they, too, receive or can get the source
|
||||||
|
code. If you link other code with the library, you must provide
|
||||||
|
complete object files to the recipients, so that they can relink them
|
||||||
|
with the library after making changes to the library and recompiling
|
||||||
|
it. And you must show them these terms so they know their rights.
|
||||||
|
|
||||||
|
We protect your rights with a two-step method: (1) we copyright the
|
||||||
|
library, and (2) we offer you this license, which gives you legal
|
||||||
|
permission to copy, distribute and/or modify the library.
|
||||||
|
|
||||||
|
To protect each distributor, we want to make it very clear that
|
||||||
|
there is no warranty for the free library. Also, if the library is
|
||||||
|
modified by someone else and passed on, the recipients should know
|
||||||
|
that what they have is not the original version, so that the original
|
||||||
|
author's reputation will not be affected by problems that might be
|
||||||
|
introduced by others.
|
||||||
|
|
||||||
|
Finally, software patents pose a constant threat to the existence of
|
||||||
|
any free program. We wish to make sure that a company cannot
|
||||||
|
effectively restrict the users of a free program by obtaining a
|
||||||
|
restrictive license from a patent holder. Therefore, we insist that
|
||||||
|
any patent license obtained for a version of the library must be
|
||||||
|
consistent with the full freedom of use specified in this license.
|
||||||
|
|
||||||
|
Most GNU software, including some libraries, is covered by the
|
||||||
|
ordinary GNU General Public License. This license, the GNU Lesser
|
||||||
|
General Public License, applies to certain designated libraries, and
|
||||||
|
is quite different from the ordinary General Public License. We use
|
||||||
|
this license for certain libraries in order to permit linking those
|
||||||
|
libraries into non-free programs.
|
||||||
|
|
||||||
|
When a program is linked with a library, whether statically or using
|
||||||
|
a shared library, the combination of the two is legally speaking a
|
||||||
|
combined work, a derivative of the original library. The ordinary
|
||||||
|
General Public License therefore permits such linking only if the
|
||||||
|
entire combination fits its criteria of freedom. The Lesser General
|
||||||
|
Public License permits more lax criteria for linking other code with
|
||||||
|
the library.
|
||||||
|
|
||||||
|
We call this license the "Lesser" General Public License because it
|
||||||
|
does Less to protect the user's freedom than the ordinary General
|
||||||
|
Public License. It also provides other free software developers Less
|
||||||
|
of an advantage over competing non-free programs. These disadvantages
|
||||||
|
are the reason we use the ordinary General Public License for many
|
||||||
|
libraries. However, the Lesser license provides advantages in certain
|
||||||
|
special circumstances.
|
||||||
|
|
||||||
|
For example, on rare occasions, there may be a special need to
|
||||||
|
encourage the widest possible use of a certain library, so that it becomes
|
||||||
|
a de-facto standard. To achieve this, non-free programs must be
|
||||||
|
allowed to use the library. A more frequent case is that a free
|
||||||
|
library does the same job as widely used non-free libraries. In this
|
||||||
|
case, there is little to gain by limiting the free library to free
|
||||||
|
software only, so we use the Lesser General Public License.
|
||||||
|
|
||||||
|
In other cases, permission to use a particular library in non-free
|
||||||
|
programs enables a greater number of people to use a large body of
|
||||||
|
free software. For example, permission to use the GNU C Library in
|
||||||
|
non-free programs enables many more people to use the whole GNU
|
||||||
|
operating system, as well as its variant, the GNU/Linux operating
|
||||||
|
system.
|
||||||
|
|
||||||
|
Although the Lesser General Public License is Less protective of the
|
||||||
|
users' freedom, it does ensure that the user of a program that is
|
||||||
|
linked with the Library has the freedom and the wherewithal to run
|
||||||
|
that program using a modified version of the Library.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow. Pay close attention to the difference between a
|
||||||
|
"work based on the library" and a "work that uses the library". The
|
||||||
|
former contains code derived from the library, whereas the latter must
|
||||||
|
be combined with the library in order to run.
|
||||||
|
|
||||||
|
GNU LESSER GENERAL PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. This License Agreement applies to any software library or other
|
||||||
|
program which contains a notice placed by the copyright holder or
|
||||||
|
other authorized party saying it may be distributed under the terms of
|
||||||
|
this Lesser General Public License (also called "this License").
|
||||||
|
Each licensee is addressed as "you".
|
||||||
|
|
||||||
|
A "library" means a collection of software functions and/or data
|
||||||
|
prepared so as to be conveniently linked with application programs
|
||||||
|
(which use some of those functions and data) to form executables.
|
||||||
|
|
||||||
|
The "Library", below, refers to any such software library or work
|
||||||
|
which has been distributed under these terms. A "work based on the
|
||||||
|
Library" means either the Library or any derivative work under
|
||||||
|
copyright law: that is to say, a work containing the Library or a
|
||||||
|
portion of it, either verbatim or with modifications and/or translated
|
||||||
|
straightforwardly into another language. (Hereinafter, translation is
|
||||||
|
included without limitation in the term "modification".)
|
||||||
|
|
||||||
|
"Source code" for a work means the preferred form of the work for
|
||||||
|
making modifications to it. For a library, complete source code means
|
||||||
|
all the source code for all modules it contains, plus any associated
|
||||||
|
interface definition files, plus the scripts used to control compilation
|
||||||
|
and installation of the library.
|
||||||
|
|
||||||
|
Activities other than copying, distribution and modification are not
|
||||||
|
covered by this License; they are outside its scope. The act of
|
||||||
|
running a program using the Library is not restricted, and output from
|
||||||
|
such a program is covered only if its contents constitute a work based
|
||||||
|
on the Library (independent of the use of the Library in a tool for
|
||||||
|
writing it). Whether that is true depends on what the Library does
|
||||||
|
and what the program that uses the Library does.
|
||||||
|
|
||||||
|
1. You may copy and distribute verbatim copies of the Library's
|
||||||
|
complete source code as you receive it, in any medium, provided that
|
||||||
|
you conspicuously and appropriately publish on each copy an
|
||||||
|
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||||
|
all the notices that refer to this License and to the absence of any
|
||||||
|
warranty; and distribute a copy of this License along with the
|
||||||
|
Library.
|
||||||
|
|
||||||
|
You may charge a fee for the physical act of transferring a copy,
|
||||||
|
and you may at your option offer warranty protection in exchange for a
|
||||||
|
fee.
|
||||||
|
|
||||||
|
2. You may modify your copy or copies of the Library or any portion
|
||||||
|
of it, thus forming a work based on the Library, and copy and
|
||||||
|
distribute such modifications or work under the terms of Section 1
|
||||||
|
above, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) The modified work must itself be a software library.
|
||||||
|
|
||||||
|
b) You must cause the files modified to carry prominent notices
|
||||||
|
stating that you changed the files and the date of any change.
|
||||||
|
|
||||||
|
c) You must cause the whole of the work to be licensed at no
|
||||||
|
charge to all third parties under the terms of this License.
|
||||||
|
|
||||||
|
d) If a facility in the modified Library refers to a function or a
|
||||||
|
table of data to be supplied by an application program that uses
|
||||||
|
the facility, other than as an argument passed when the facility
|
||||||
|
is invoked, then you must make a good faith effort to ensure that,
|
||||||
|
in the event an application does not supply such function or
|
||||||
|
table, the facility still operates, and performs whatever part of
|
||||||
|
its purpose remains meaningful.
|
||||||
|
|
||||||
|
(For example, a function in a library to compute square roots has
|
||||||
|
a purpose that is entirely well-defined independent of the
|
||||||
|
application. Therefore, Subsection 2d requires that any
|
||||||
|
application-supplied function or table used by this function must
|
||||||
|
be optional: if the application does not supply it, the square
|
||||||
|
root function must still compute square roots.)
|
||||||
|
|
||||||
|
These requirements apply to the modified work as a whole. If
|
||||||
|
identifiable sections of that work are not derived from the Library,
|
||||||
|
and can be reasonably considered independent and separate works in
|
||||||
|
themselves, then this License, and its terms, do not apply to those
|
||||||
|
sections when you distribute them as separate works. But when you
|
||||||
|
distribute the same sections as part of a whole which is a work based
|
||||||
|
on the Library, the distribution of the whole must be on the terms of
|
||||||
|
this License, whose permissions for other licensees extend to the
|
||||||
|
entire whole, and thus to each and every part regardless of who wrote
|
||||||
|
it.
|
||||||
|
|
||||||
|
Thus, it is not the intent of this section to claim rights or contest
|
||||||
|
your rights to work written entirely by you; rather, the intent is to
|
||||||
|
exercise the right to control the distribution of derivative or
|
||||||
|
collective works based on the Library.
|
||||||
|
|
||||||
|
In addition, mere aggregation of another work not based on the Library
|
||||||
|
with the Library (or with a work based on the Library) on a volume of
|
||||||
|
a storage or distribution medium does not bring the other work under
|
||||||
|
the scope of this License.
|
||||||
|
|
||||||
|
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||||
|
License instead of this License to a given copy of the Library. To do
|
||||||
|
this, you must alter all the notices that refer to this License, so
|
||||||
|
that they refer to the ordinary GNU General Public License, version 2,
|
||||||
|
instead of to this License. (If a newer version than version 2 of the
|
||||||
|
ordinary GNU General Public License has appeared, then you can specify
|
||||||
|
that version instead if you wish.) Do not make any other change in
|
||||||
|
these notices.
|
||||||
|
|
||||||
|
Once this change is made in a given copy, it is irreversible for
|
||||||
|
that copy, so the ordinary GNU General Public License applies to all
|
||||||
|
subsequent copies and derivative works made from that copy.
|
||||||
|
|
||||||
|
This option is useful when you wish to copy part of the code of
|
||||||
|
the Library into a program that is not a library.
|
||||||
|
|
||||||
|
4. You may copy and distribute the Library (or a portion or
|
||||||
|
derivative of it, under Section 2) in object code or executable form
|
||||||
|
under the terms of Sections 1 and 2 above provided that you accompany
|
||||||
|
it with the complete corresponding machine-readable source code, which
|
||||||
|
must be distributed under the terms of Sections 1 and 2 above on a
|
||||||
|
medium customarily used for software interchange.
|
||||||
|
|
||||||
|
If distribution of object code is made by offering access to copy
|
||||||
|
from a designated place, then offering equivalent access to copy the
|
||||||
|
source code from the same place satisfies the requirement to
|
||||||
|
distribute the source code, even though third parties are not
|
||||||
|
compelled to copy the source along with the object code.
|
||||||
|
|
||||||
|
5. A program that contains no derivative of any portion of the
|
||||||
|
Library, but is designed to work with the Library by being compiled or
|
||||||
|
linked with it, is called a "work that uses the Library". Such a
|
||||||
|
work, in isolation, is not a derivative work of the Library, and
|
||||||
|
therefore falls outside the scope of this License.
|
||||||
|
|
||||||
|
However, linking a "work that uses the Library" with the Library
|
||||||
|
creates an executable that is a derivative of the Library (because it
|
||||||
|
contains portions of the Library), rather than a "work that uses the
|
||||||
|
library". The executable is therefore covered by this License.
|
||||||
|
Section 6 states terms for distribution of such executables.
|
||||||
|
|
||||||
|
When a "work that uses the Library" uses material from a header file
|
||||||
|
that is part of the Library, the object code for the work may be a
|
||||||
|
derivative work of the Library even though the source code is not.
|
||||||
|
Whether this is true is especially significant if the work can be
|
||||||
|
linked without the Library, or if the work is itself a library. The
|
||||||
|
threshold for this to be true is not precisely defined by law.
|
||||||
|
|
||||||
|
If such an object file uses only numerical parameters, data
|
||||||
|
structure layouts and accessors, and small macros and small inline
|
||||||
|
functions (ten lines or less in length), then the use of the object
|
||||||
|
file is unrestricted, regardless of whether it is legally a derivative
|
||||||
|
work. (Executables containing this object code plus portions of the
|
||||||
|
Library will still fall under Section 6.)
|
||||||
|
|
||||||
|
Otherwise, if the work is a derivative of the Library, you may
|
||||||
|
distribute the object code for the work under the terms of Section 6.
|
||||||
|
Any executables containing that work also fall under Section 6,
|
||||||
|
whether or not they are linked directly with the Library itself.
|
||||||
|
|
||||||
|
6. As an exception to the Sections above, you may also combine or
|
||||||
|
link a "work that uses the Library" with the Library to produce a
|
||||||
|
work containing portions of the Library, and distribute that work
|
||||||
|
under terms of your choice, provided that the terms permit
|
||||||
|
modification of the work for the customer's own use and reverse
|
||||||
|
engineering for debugging such modifications.
|
||||||
|
|
||||||
|
You must give prominent notice with each copy of the work that the
|
||||||
|
Library is used in it and that the Library and its use are covered by
|
||||||
|
this License. You must supply a copy of this License. If the work
|
||||||
|
during execution displays copyright notices, you must include the
|
||||||
|
copyright notice for the Library among them, as well as a reference
|
||||||
|
directing the user to the copy of this License. Also, you must do one
|
||||||
|
of these things:
|
||||||
|
|
||||||
|
a) Accompany the work with the complete corresponding
|
||||||
|
machine-readable source code for the Library including whatever
|
||||||
|
changes were used in the work (which must be distributed under
|
||||||
|
Sections 1 and 2 above); and, if the work is an executable linked
|
||||||
|
with the Library, with the complete machine-readable "work that
|
||||||
|
uses the Library", as object code and/or source code, so that the
|
||||||
|
user can modify the Library and then relink to produce a modified
|
||||||
|
executable containing the modified Library. (It is understood
|
||||||
|
that the user who changes the contents of definitions files in the
|
||||||
|
Library will not necessarily be able to recompile the application
|
||||||
|
to use the modified definitions.)
|
||||||
|
|
||||||
|
b) Use a suitable shared library mechanism for linking with the
|
||||||
|
Library. A suitable mechanism is one that (1) uses at run time a
|
||||||
|
copy of the library already present on the user's computer system,
|
||||||
|
rather than copying library functions into the executable, and (2)
|
||||||
|
will operate properly with a modified version of the library, if
|
||||||
|
the user installs one, as long as the modified version is
|
||||||
|
interface-compatible with the version that the work was made with.
|
||||||
|
|
||||||
|
c) Accompany the work with a written offer, valid for at
|
||||||
|
least three years, to give the same user the materials
|
||||||
|
specified in Subsection 6a, above, for a charge no more
|
||||||
|
than the cost of performing this distribution.
|
||||||
|
|
||||||
|
d) If distribution of the work is made by offering access to copy
|
||||||
|
from a designated place, offer equivalent access to copy the above
|
||||||
|
specified materials from the same place.
|
||||||
|
|
||||||
|
e) Verify that the user has already received a copy of these
|
||||||
|
materials or that you have already sent this user a copy.
|
||||||
|
|
||||||
|
For an executable, the required form of the "work that uses the
|
||||||
|
Library" must include any data and utility programs needed for
|
||||||
|
reproducing the executable from it. However, as a special exception,
|
||||||
|
the materials to be distributed need not include anything that is
|
||||||
|
normally distributed (in either source or binary form) with the major
|
||||||
|
components (compiler, kernel, and so on) of the operating system on
|
||||||
|
which the executable runs, unless that component itself accompanies
|
||||||
|
the executable.
|
||||||
|
|
||||||
|
It may happen that this requirement contradicts the license
|
||||||
|
restrictions of other proprietary libraries that do not normally
|
||||||
|
accompany the operating system. Such a contradiction means you cannot
|
||||||
|
use both them and the Library together in an executable that you
|
||||||
|
distribute.
|
||||||
|
|
||||||
|
7. You may place library facilities that are a work based on the
|
||||||
|
Library side-by-side in a single library together with other library
|
||||||
|
facilities not covered by this License, and distribute such a combined
|
||||||
|
library, provided that the separate distribution of the work based on
|
||||||
|
the Library and of the other library facilities is otherwise
|
||||||
|
permitted, and provided that you do these two things:
|
||||||
|
|
||||||
|
a) Accompany the combined library with a copy of the same work
|
||||||
|
based on the Library, uncombined with any other library
|
||||||
|
facilities. This must be distributed under the terms of the
|
||||||
|
Sections above.
|
||||||
|
|
||||||
|
b) Give prominent notice with the combined library of the fact
|
||||||
|
that part of it is a work based on the Library, and explaining
|
||||||
|
where to find the accompanying uncombined form of the same work.
|
||||||
|
|
||||||
|
8. You may not copy, modify, sublicense, link with, or distribute
|
||||||
|
the Library except as expressly provided under this License. Any
|
||||||
|
attempt otherwise to copy, modify, sublicense, link with, or
|
||||||
|
distribute the Library is void, and will automatically terminate your
|
||||||
|
rights under this License. However, parties who have received copies,
|
||||||
|
or rights, from you under this License will not have their licenses
|
||||||
|
terminated so long as such parties remain in full compliance.
|
||||||
|
|
||||||
|
9. You are not required to accept this License, since you have not
|
||||||
|
signed it. However, nothing else grants you permission to modify or
|
||||||
|
distribute the Library or its derivative works. These actions are
|
||||||
|
prohibited by law if you do not accept this License. Therefore, by
|
||||||
|
modifying or distributing the Library (or any work based on the
|
||||||
|
Library), you indicate your acceptance of this License to do so, and
|
||||||
|
all its terms and conditions for copying, distributing or modifying
|
||||||
|
the Library or works based on it.
|
||||||
|
|
||||||
|
10. Each time you redistribute the Library (or any work based on the
|
||||||
|
Library), the recipient automatically receives a license from the
|
||||||
|
original licensor to copy, distribute, link with or modify the Library
|
||||||
|
subject to these terms and conditions. You may not impose any further
|
||||||
|
restrictions on the recipients' exercise of the rights granted herein.
|
||||||
|
You are not responsible for enforcing compliance by third parties with
|
||||||
|
this License.
|
||||||
|
|
||||||
|
11. If, as a consequence of a court judgment or allegation of patent
|
||||||
|
infringement or for any other reason (not limited to patent issues),
|
||||||
|
conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot
|
||||||
|
distribute so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you
|
||||||
|
may not distribute the Library at all. For example, if a patent
|
||||||
|
license would not permit royalty-free redistribution of the Library by
|
||||||
|
all those who receive copies directly or indirectly through you, then
|
||||||
|
the only way you could satisfy both it and this License would be to
|
||||||
|
refrain entirely from distribution of the Library.
|
||||||
|
|
||||||
|
If any portion of this section is held invalid or unenforceable under any
|
||||||
|
particular circumstance, the balance of the section is intended to apply,
|
||||||
|
and the section as a whole is intended to apply in other circumstances.
|
||||||
|
|
||||||
|
It is not the purpose of this section to induce you to infringe any
|
||||||
|
patents or other property right claims or to contest validity of any
|
||||||
|
such claims; this section has the sole purpose of protecting the
|
||||||
|
integrity of the free software distribution system which is
|
||||||
|
implemented by public license practices. Many people have made
|
||||||
|
generous contributions to the wide range of software distributed
|
||||||
|
through that system in reliance on consistent application of that
|
||||||
|
system; it is up to the author/donor to decide if he or she is willing
|
||||||
|
to distribute software through any other system and a licensee cannot
|
||||||
|
impose that choice.
|
||||||
|
|
||||||
|
This section is intended to make thoroughly clear what is believed to
|
||||||
|
be a consequence of the rest of this License.
|
||||||
|
|
||||||
|
12. If the distribution and/or use of the Library is restricted in
|
||||||
|
certain countries either by patents or by copyrighted interfaces, the
|
||||||
|
original copyright holder who places the Library under this License may add
|
||||||
|
an explicit geographical distribution limitation excluding those countries,
|
||||||
|
so that distribution is permitted only in or among countries not thus
|
||||||
|
excluded. In such case, this License incorporates the limitation as if
|
||||||
|
written in the body of this License.
|
||||||
|
|
||||||
|
13. The Free Software Foundation may publish revised and/or new
|
||||||
|
versions of the Lesser General Public License from time to time.
|
||||||
|
Such new versions will be similar in spirit to the present version,
|
||||||
|
but may differ in detail to address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the Library
|
||||||
|
specifies a version number of this License which applies to it and
|
||||||
|
"any later version", you have the option of following the terms and
|
||||||
|
conditions either of that version or of any later version published by
|
||||||
|
the Free Software Foundation. If the Library does not specify a
|
||||||
|
license version number, you may choose any version ever published by
|
||||||
|
the Free Software Foundation.
|
||||||
|
|
||||||
|
14. If you wish to incorporate parts of the Library into other free
|
||||||
|
programs whose distribution conditions are incompatible with these,
|
||||||
|
write to the author to ask for permission. For software which is
|
||||||
|
copyrighted by the Free Software Foundation, write to the Free
|
||||||
|
Software Foundation; we sometimes make exceptions for this. Our
|
||||||
|
decision will be guided by the two goals of preserving the free status
|
||||||
|
of all derivatives of our free software and of promoting the sharing
|
||||||
|
and reuse of software generally.
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||||
|
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||||
|
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||||
|
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||||
|
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||||
|
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||||
|
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||||
|
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||||
|
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||||
|
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||||
|
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||||
|
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||||
|
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||||
|
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||||
|
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||||
|
DAMAGES.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Libraries
|
||||||
|
|
||||||
|
If you develop a new library, and you want it to be of the greatest
|
||||||
|
possible use to the public, we recommend making it free software that
|
||||||
|
everyone can redistribute and change. You can do so by permitting
|
||||||
|
redistribution under these terms (or, alternatively, under the terms of the
|
||||||
|
ordinary General Public License).
|
||||||
|
|
||||||
|
To apply these terms, attach the following notices to the library. It is
|
||||||
|
safest to attach them to the start of each source file to most effectively
|
||||||
|
convey the exclusion of warranty; and each file should have at least the
|
||||||
|
"copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the library's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or your
|
||||||
|
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||||
|
necessary. Here is a sample; alter the names:
|
||||||
|
|
||||||
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||||
|
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||||
|
|
||||||
|
<signature of Ty Coon>, 1 April 1990
|
||||||
|
Ty Coon, President of Vice
|
||||||
|
|
||||||
|
That's all there is to it!
|
||||||
33
Makefile.am
Normal file
33
Makefile.am
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
NULL =
|
||||||
|
ACLOCAL_AMFLAGS = -I m4
|
||||||
|
|
||||||
|
SUBDIRS = python_modules common docs
|
||||||
|
|
||||||
|
if ENABLE_TESTS
|
||||||
|
SUBDIRS += tests
|
||||||
|
endif
|
||||||
|
|
||||||
|
EXTRA_DIST = \
|
||||||
|
meson.build \
|
||||||
|
meson_options.txt \
|
||||||
|
spice_codegen.py \
|
||||||
|
spice.proto \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
DISTCLEANFILES = *.pyc
|
||||||
|
|
||||||
|
MAINTAINERCLEANFILES = \
|
||||||
|
$(srcdir)/INSTALL \
|
||||||
|
$(srcdir)/aclocal.m4 \
|
||||||
|
$(srcdir)/autoscan.log \
|
||||||
|
$(srcdir)/build-aux \
|
||||||
|
$(srcdir)/config.h.in \
|
||||||
|
$(srcdir)/m4/libtool.m4 \
|
||||||
|
$(srcdir)/m4/ltoptions.m4 \
|
||||||
|
$(srcdir)/m4/ltsugar.m4 \
|
||||||
|
$(srcdir)/m4/ltversion.m4 \
|
||||||
|
$(srcdir)/m4/lt~obsolete.m4 \
|
||||||
|
`find "$(srcdir)" -type f -name Makefile.in -print` \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
-include $(top_srcdir)/git.mk
|
||||||
17
autogen.sh
Executable file
17
autogen.sh
Executable file
@ -0,0 +1,17 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -e # exit on errors
|
||||||
|
|
||||||
|
srcdir=`dirname $0`
|
||||||
|
test -z "$srcdir" && srcdir=.
|
||||||
|
|
||||||
|
olddir=`pwd`
|
||||||
|
cd "$srcdir"
|
||||||
|
|
||||||
|
mkdir -p m4
|
||||||
|
autoreconf --verbose --force --install
|
||||||
|
|
||||||
|
cd "$olddir"
|
||||||
|
if [ -z "$NOCONFIGURE" ]; then
|
||||||
|
"$srcdir"/configure --enable-maintainer-mode --enable-python-checks ${1+"$@"}
|
||||||
|
fi
|
||||||
9
common/.gitignore
vendored
9
common/.gitignore
vendored
@ -1,9 +0,0 @@
|
|||||||
*.la
|
|
||||||
*.lo
|
|
||||||
*.loT
|
|
||||||
*.o
|
|
||||||
.deps
|
|
||||||
.dirstamp
|
|
||||||
.libs
|
|
||||||
Makefile
|
|
||||||
Makefile.in
|
|
||||||
@ -1,27 +1,44 @@
|
|||||||
if OS_WIN32
|
|
||||||
SUBDIRS = win
|
|
||||||
endif
|
|
||||||
|
|
||||||
NULL =
|
NULL =
|
||||||
|
|
||||||
noinst_LTLIBRARIES = libspice-common.la
|
# Avoid need for python(pyparsing) by end users
|
||||||
|
CLIENT_MARSHALLERS = \
|
||||||
|
generated_client_demarshallers.c \
|
||||||
|
generated_client_marshallers.c \
|
||||||
|
generated_client_marshallers.h \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
SERVER_MARSHALLERS = \
|
||||||
|
generated_server_demarshallers.c \
|
||||||
|
generated_server_marshallers.c \
|
||||||
|
generated_server_marshallers.h \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
BUILT_SOURCES = $(CLIENT_MARSHALLERS) $(SERVER_MARSHALLERS)
|
||||||
|
|
||||||
|
noinst_LTLIBRARIES = libspice-common.la libspice-common-server.la libspice-common-client.la
|
||||||
libspice_common_la_SOURCES = \
|
libspice_common_la_SOURCES = \
|
||||||
bitops.h \
|
agent.c \
|
||||||
|
agent.h \
|
||||||
|
backtrace.c \
|
||||||
|
backtrace.h \
|
||||||
canvas_utils.c \
|
canvas_utils.c \
|
||||||
canvas_utils.h \
|
canvas_utils.h \
|
||||||
|
demarshallers.h \
|
||||||
draw.h \
|
draw.h \
|
||||||
lines.c \
|
lines.c \
|
||||||
lines.h \
|
lines.h \
|
||||||
|
log.c \
|
||||||
|
log.h \
|
||||||
lz.c \
|
lz.c \
|
||||||
lz.h \
|
lz.h \
|
||||||
lz_common.h \
|
lz_common.h \
|
||||||
lz_config.h \
|
lz_config.h \
|
||||||
|
macros.h \
|
||||||
marshaller.c \
|
marshaller.c \
|
||||||
marshaller.h \
|
marshaller.h \
|
||||||
mem.c \
|
mem.c \
|
||||||
mem.h \
|
mem.h \
|
||||||
messages.h \
|
messages.h \
|
||||||
mutex.h \
|
|
||||||
pixman_utils.c \
|
pixman_utils.c \
|
||||||
pixman_utils.h \
|
pixman_utils.h \
|
||||||
quic.c \
|
quic.c \
|
||||||
@ -33,44 +50,112 @@ libspice_common_la_SOURCES = \
|
|||||||
ring.h \
|
ring.h \
|
||||||
rop3.c \
|
rop3.c \
|
||||||
rop3.h \
|
rop3.h \
|
||||||
spice_common.h \
|
snd_codec.c \
|
||||||
ssl_verify.c \
|
snd_codec.h \
|
||||||
ssl_verify.h \
|
udev.c \
|
||||||
backtrace.c \
|
udev.h \
|
||||||
backtrace.h \
|
utils.c \
|
||||||
|
utils.h \
|
||||||
|
verify.h \
|
||||||
|
recorder.h \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
if SUPPORT_GL
|
if ENABLE_RECORDER
|
||||||
libspice_common_la_SOURCES += \
|
libspice_common_la_SOURCES += \
|
||||||
gl_utils.h \
|
recorder/recorder.c \
|
||||||
glc.h \
|
recorder/recorder.h \
|
||||||
glc.c \
|
recorder/recorder_ring.c \
|
||||||
ogl_ctx.h \
|
recorder/recorder_ring.h \
|
||||||
ogl_ctx.c \
|
|
||||||
$(NULL)
|
$(NULL)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
INCLUDES = \
|
if ENABLE_AGENT_INTERFACE
|
||||||
$(GL_CFLAGS) \
|
libspice_common_la_SOURCES += \
|
||||||
$(PIXMAN_CFLAGS) \
|
agent_interface.c \
|
||||||
$(PROTOCOL_CFLAGS) \
|
agent_interface.h \
|
||||||
$(VISIBILITY_HIDDEN_CFLAGS) \
|
|
||||||
$(WARN_CFLAGS) \
|
|
||||||
-std=gnu99 \
|
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
endif
|
||||||
|
|
||||||
EXTRA_DIST = \
|
# These 2 files are not build as part of spice-common
|
||||||
canvas_base.c \
|
# build system, but modules using spice-common will build
|
||||||
canvas_base.h \
|
# them with the appropriate options. We need to let automake
|
||||||
gdi_canvas.c \
|
# know that these are source files so that it can properly
|
||||||
gdi_canvas.h \
|
# track these files dependencies
|
||||||
gl_canvas.c \
|
EXTRA_libspice_common_la_SOURCES = \
|
||||||
gl_canvas.h \
|
|
||||||
sw_canvas.c \
|
sw_canvas.c \
|
||||||
sw_canvas.h \
|
sw_canvas.h \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
libspice_common_client_la_SOURCES = \
|
||||||
|
client_marshallers.h \
|
||||||
|
ssl_verify.c \
|
||||||
|
ssl_verify.h \
|
||||||
|
$(CLIENT_MARSHALLERS) \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
libspice_common_client_la_LIBADD = \
|
||||||
|
$(GIO2_LIBS) \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
libspice_common_server_la_SOURCES = \
|
||||||
|
$(SERVER_MARSHALLERS) \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
AM_CPPFLAGS = \
|
||||||
|
-I$(top_srcdir) \
|
||||||
|
-I$(top_builddir) \
|
||||||
|
$(SPICE_COMMON_CFLAGS) \
|
||||||
|
$(PROTOCOL_CFLAGS) \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
libspice_common_la_LIBADD = \
|
||||||
|
$(SPICE_COMMON_LIBS) \
|
||||||
|
$(UDEV_LIBS) \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
MARSHALLERS_DEPS = \
|
||||||
|
$(top_srcdir)/python_modules/__init__.py \
|
||||||
|
$(top_srcdir)/python_modules/codegen.py \
|
||||||
|
$(top_srcdir)/python_modules/demarshal.py \
|
||||||
|
$(top_srcdir)/python_modules/marshal.py \
|
||||||
|
$(top_srcdir)/python_modules/ptypes.py \
|
||||||
|
$(top_srcdir)/python_modules/spice_parser.py \
|
||||||
|
$(top_srcdir)/spice_codegen.py \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
# Note despite being autogenerated these are not part of CLEANFILES, they are
|
||||||
|
# actually a part of EXTRA_DIST, to avoid the need for pyparser by end users
|
||||||
|
generated_client_demarshallers.c generated_messages.h: $(top_srcdir)/spice.proto $(MARSHALLERS_DEPS)
|
||||||
|
$(AM_V_GEN)$(PYTHON) $(top_srcdir)/spice_codegen.py --generate-demarshallers --client --include common/messages.h \
|
||||||
|
--generated-declaration-file generated_messages.h $< $@ >/dev/null
|
||||||
|
|
||||||
|
generated_client_marshallers.c generated_client_marshallers.h: $(top_srcdir)/spice.proto $(MARSHALLERS_DEPS)
|
||||||
|
$(AM_V_GEN)$(PYTHON) $(top_srcdir)/spice_codegen.py --generate-marshallers -P --include common/client_marshallers.h --client \
|
||||||
|
--generate-header $< $@ >/dev/null
|
||||||
|
|
||||||
|
generated_server_demarshallers.c: $(top_srcdir)/spice.proto $(MARSHALLERS_DEPS)
|
||||||
|
$(AM_V_GEN)$(PYTHON) $(top_srcdir)/spice_codegen.py --generate-demarshallers --server --include common/messages.h $< $@ >/dev/null
|
||||||
|
|
||||||
|
STRUCTS = -M String -M Rect -M Point -M DisplayBase -M Fill -M Opaque -M Copy -M Blend -M Blackness -M Whiteness -M Invers -M Rop3 -M Stroke -M Text -M Transparent -M AlphaBlend -M Composite
|
||||||
|
generated_server_marshallers.c generated_server_marshallers.h: $(top_srcdir)/spice.proto $(MARSHALLERS_DEPS)
|
||||||
|
$(AM_V_GEN)$(PYTHON) $(top_srcdir)/spice_codegen.py --generate-marshallers $(STRUCTS) --server --include common/messages.h \
|
||||||
|
--generate-header $< $@ >/dev/null
|
||||||
|
|
||||||
|
EXTRA_DIST = \
|
||||||
|
$(CLIENT_MARSHALLERS) \
|
||||||
|
$(SERVER_MARSHALLERS) \
|
||||||
|
generated_messages.h \
|
||||||
|
meson.build \
|
||||||
|
canvas_base.c \
|
||||||
|
canvas_base.h \
|
||||||
lz_compress_tmpl.c \
|
lz_compress_tmpl.c \
|
||||||
lz_decompress_tmpl.c \
|
lz_decompress_tmpl.c \
|
||||||
quic_family_tmpl.c \
|
quic_family_tmpl.c \
|
||||||
quic_rgb_tmpl.c \
|
|
||||||
quic_tmpl.c \
|
quic_tmpl.c \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
|
GITIGNOREFILES = \
|
||||||
|
generated_messages.h \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
-include $(top_srcdir)/git.mk
|
||||||
|
|||||||
361
common/agent.c
Normal file
361
common/agent.c
Normal file
@ -0,0 +1,361 @@
|
|||||||
|
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||||
|
/*
|
||||||
|
Copyright (C) 2020 Red Hat, Inc.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include "agent.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
// Windows is always little endian
|
||||||
|
# define FIX_ENDIAN16(x) (x) = (x)
|
||||||
|
# define FIX_ENDIAN32(x) (x) = (x)
|
||||||
|
# define FIX_ENDIAN64(x) (x) = (x)
|
||||||
|
#else
|
||||||
|
# include <glib.h>
|
||||||
|
# define FIX_ENDIAN16(x) (x) = GUINT16_FROM_LE(x)
|
||||||
|
# define FIX_ENDIAN32(x) (x) = GUINT32_FROM_LE(x)
|
||||||
|
# define FIX_ENDIAN64(x) (x) = GUINT64_FROM_LE(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <spice/start-packed.h>
|
||||||
|
typedef struct SPICE_ATTR_PACKED {
|
||||||
|
uint16_t v;
|
||||||
|
} uint16_unaligned_t;
|
||||||
|
|
||||||
|
typedef struct SPICE_ATTR_PACKED {
|
||||||
|
uint32_t v;
|
||||||
|
} uint32_unaligned_t;
|
||||||
|
|
||||||
|
typedef struct SPICE_ATTR_PACKED {
|
||||||
|
uint64_t v;
|
||||||
|
} uint64_unaligned_t;
|
||||||
|
#include <spice/end-packed.h>
|
||||||
|
|
||||||
|
static const int agent_message_min_size[] =
|
||||||
|
{
|
||||||
|
-1, /* Does not exist */
|
||||||
|
sizeof(VDAgentMouseState), /* VD_AGENT_MOUSE_STATE */
|
||||||
|
sizeof(VDAgentMonitorsConfig), /* VD_AGENT_MONITORS_CONFIG */
|
||||||
|
sizeof(VDAgentReply), /* VD_AGENT_REPLY */
|
||||||
|
sizeof(VDAgentClipboard), /* VD_AGENT_CLIPBOARD */
|
||||||
|
sizeof(VDAgentDisplayConfig), /* VD_AGENT_DISPLAY_CONFIG */
|
||||||
|
sizeof(VDAgentAnnounceCapabilities), /* VD_AGENT_ANNOUNCE_CAPABILITIES */
|
||||||
|
sizeof(VDAgentClipboardGrab), /* VD_AGENT_CLIPBOARD_GRAB */
|
||||||
|
sizeof(VDAgentClipboardRequest), /* VD_AGENT_CLIPBOARD_REQUEST */
|
||||||
|
sizeof(VDAgentClipboardRelease), /* VD_AGENT_CLIPBOARD_RELEASE */
|
||||||
|
sizeof(VDAgentFileXferStartMessage), /* VD_AGENT_FILE_XFER_START */
|
||||||
|
sizeof(VDAgentFileXferStatusMessage), /* VD_AGENT_FILE_XFER_STATUS */
|
||||||
|
sizeof(VDAgentFileXferDataMessage), /* VD_AGENT_FILE_XFER_DATA */
|
||||||
|
0, /* VD_AGENT_CLIENT_DISCONNECTED */
|
||||||
|
sizeof(VDAgentMaxClipboard), /* VD_AGENT_MAX_CLIPBOARD */
|
||||||
|
sizeof(VDAgentAudioVolumeSync), /* VD_AGENT_AUDIO_VOLUME_SYNC */
|
||||||
|
sizeof(VDAgentGraphicsDeviceInfo), /* VD_AGENT_GRAPHICS_DEVICE_INFO */
|
||||||
|
};
|
||||||
|
|
||||||
|
static AgentCheckResult
|
||||||
|
agent_message_check_size(const VDAgentMessage *message_header,
|
||||||
|
const uint32_t *capabilities, uint32_t capabilities_size)
|
||||||
|
{
|
||||||
|
if (message_header->protocol != VD_AGENT_PROTOCOL) {
|
||||||
|
return AGENT_CHECK_WRONG_PROTOCOL_VERSION;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message_header->type >= SPICE_N_ELEMENTS(agent_message_min_size) ||
|
||||||
|
agent_message_min_size[message_header->type] < 0) {
|
||||||
|
return AGENT_CHECK_UNKNOWN_MESSAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t min_size = agent_message_min_size[message_header->type];
|
||||||
|
|
||||||
|
if (VD_AGENT_HAS_CAPABILITY(capabilities, capabilities_size,
|
||||||
|
VD_AGENT_CAP_CLIPBOARD_SELECTION)) {
|
||||||
|
switch (message_header->type) {
|
||||||
|
case VD_AGENT_CLIPBOARD_GRAB:
|
||||||
|
case VD_AGENT_CLIPBOARD_REQUEST:
|
||||||
|
case VD_AGENT_CLIPBOARD:
|
||||||
|
case VD_AGENT_CLIPBOARD_RELEASE:
|
||||||
|
min_size += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (VD_AGENT_HAS_CAPABILITY(capabilities, capabilities_size,
|
||||||
|
VD_AGENT_CAP_CLIPBOARD_GRAB_SERIAL)
|
||||||
|
&& message_header->type == VD_AGENT_CLIPBOARD_GRAB) {
|
||||||
|
min_size += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (message_header->type) {
|
||||||
|
case VD_AGENT_MONITORS_CONFIG:
|
||||||
|
case VD_AGENT_FILE_XFER_START:
|
||||||
|
case VD_AGENT_FILE_XFER_DATA:
|
||||||
|
case VD_AGENT_CLIPBOARD:
|
||||||
|
case VD_AGENT_CLIPBOARD_GRAB:
|
||||||
|
case VD_AGENT_AUDIO_VOLUME_SYNC:
|
||||||
|
case VD_AGENT_ANNOUNCE_CAPABILITIES:
|
||||||
|
case VD_AGENT_GRAPHICS_DEVICE_INFO:
|
||||||
|
case VD_AGENT_FILE_XFER_STATUS:
|
||||||
|
if (message_header->size < min_size) {
|
||||||
|
return AGENT_CHECK_INVALID_SIZE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case VD_AGENT_MOUSE_STATE:
|
||||||
|
case VD_AGENT_DISPLAY_CONFIG:
|
||||||
|
case VD_AGENT_REPLY:
|
||||||
|
case VD_AGENT_CLIPBOARD_REQUEST:
|
||||||
|
case VD_AGENT_CLIPBOARD_RELEASE:
|
||||||
|
case VD_AGENT_MAX_CLIPBOARD:
|
||||||
|
case VD_AGENT_CLIENT_DISCONNECTED:
|
||||||
|
if (message_header->size != min_size) {
|
||||||
|
return AGENT_CHECK_INVALID_SIZE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return AGENT_CHECK_UNKNOWN_MESSAGE;
|
||||||
|
}
|
||||||
|
return AGENT_CHECK_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void uint16_from_le(uint8_t *_msg, uint32_t size, uint32_t offset)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
uint16_unaligned_t *msg = (uint16_unaligned_t *)(_msg + offset);
|
||||||
|
|
||||||
|
/* size % 2 should be 0 - extra bytes are ignored */
|
||||||
|
for (i = 0; i < size / 2; i++) {
|
||||||
|
FIX_ENDIAN16(msg[i].v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void uint32_from_le(uint8_t *_msg, uint32_t size, uint32_t offset)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
uint32_unaligned_t *msg = (uint32_unaligned_t *)(_msg + offset);
|
||||||
|
|
||||||
|
/* size % 4 should be 0 - extra bytes are ignored */
|
||||||
|
for (i = 0; i < size / 4; i++) {
|
||||||
|
FIX_ENDIAN32(msg[i].v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
agent_message_clipboard_from_le(const VDAgentMessage *message_header, uint8_t *data,
|
||||||
|
const uint32_t *capabilities, uint32_t capabilities_size)
|
||||||
|
{
|
||||||
|
size_t min_size = agent_message_min_size[message_header->type];
|
||||||
|
uint32_unaligned_t *data_type = (uint32_unaligned_t *) data;
|
||||||
|
|
||||||
|
if (VD_AGENT_HAS_CAPABILITY(capabilities, capabilities_size,
|
||||||
|
VD_AGENT_CAP_CLIPBOARD_SELECTION)) {
|
||||||
|
min_size += 4;
|
||||||
|
data_type++;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (message_header->type) {
|
||||||
|
case VD_AGENT_CLIPBOARD_REQUEST:
|
||||||
|
case VD_AGENT_CLIPBOARD:
|
||||||
|
FIX_ENDIAN32(data_type->v);
|
||||||
|
break;
|
||||||
|
case VD_AGENT_CLIPBOARD_GRAB:
|
||||||
|
uint32_from_le(data, message_header->size - min_size, min_size);
|
||||||
|
break;
|
||||||
|
case VD_AGENT_CLIPBOARD_RELEASE:
|
||||||
|
// empty
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
agent_message_file_xfer_from_le(const VDAgentMessage *message_header, uint8_t *data)
|
||||||
|
{
|
||||||
|
uint32_unaligned_t *id = (uint32_unaligned_t *)data;
|
||||||
|
FIX_ENDIAN32(id->v);
|
||||||
|
id++; // result
|
||||||
|
|
||||||
|
switch (message_header->type) {
|
||||||
|
case VD_AGENT_FILE_XFER_DATA: {
|
||||||
|
VDAgentFileXferDataMessage *msg = (VDAgentFileXferDataMessage *) data;
|
||||||
|
FIX_ENDIAN64(msg->size);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case VD_AGENT_FILE_XFER_STATUS: {
|
||||||
|
VDAgentFileXferStatusMessage *msg = (VDAgentFileXferStatusMessage *) data;
|
||||||
|
FIX_ENDIAN32(msg->result);
|
||||||
|
// from client/server we don't expect any detail
|
||||||
|
switch (msg->result) {
|
||||||
|
case VD_AGENT_FILE_XFER_STATUS_NOT_ENOUGH_SPACE:
|
||||||
|
if (message_header->size >= sizeof(VDAgentFileXferStatusMessage) +
|
||||||
|
sizeof(VDAgentFileXferStatusNotEnoughSpace)) {
|
||||||
|
VDAgentFileXferStatusNotEnoughSpace *err =
|
||||||
|
(VDAgentFileXferStatusNotEnoughSpace*) msg->data;
|
||||||
|
FIX_ENDIAN64(err->disk_free_space);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case VD_AGENT_FILE_XFER_STATUS_ERROR:
|
||||||
|
if (message_header->size >= sizeof(VDAgentFileXferStatusMessage) +
|
||||||
|
sizeof(VDAgentFileXferStatusError)) {
|
||||||
|
VDAgentFileXferStatusError *err =
|
||||||
|
(VDAgentFileXferStatusError *) msg->data;
|
||||||
|
FIX_ENDIAN32(err->error_code);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static AgentCheckResult
|
||||||
|
agent_message_graphics_device_info_check_from_le(const VDAgentMessage *message_header,
|
||||||
|
uint8_t *data)
|
||||||
|
{
|
||||||
|
uint8_t *const end = data + message_header->size;
|
||||||
|
uint32_unaligned_t *u32 = (uint32_unaligned_t *) data;
|
||||||
|
FIX_ENDIAN32(u32->v);
|
||||||
|
const uint32_t count = u32->v;
|
||||||
|
data += 4;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < count; ++i) {
|
||||||
|
if ((size_t) (end - data) < sizeof(VDAgentDeviceDisplayInfo)) {
|
||||||
|
return AGENT_CHECK_TRUNCATED;
|
||||||
|
}
|
||||||
|
uint32_from_le(data, sizeof(VDAgentDeviceDisplayInfo), 0);
|
||||||
|
VDAgentDeviceDisplayInfo *info = (VDAgentDeviceDisplayInfo *) data;
|
||||||
|
data += sizeof(VDAgentDeviceDisplayInfo);
|
||||||
|
if (!info->device_address_len) {
|
||||||
|
return AGENT_CHECK_INVALID_DATA;
|
||||||
|
}
|
||||||
|
if ((size_t) (end - data) < info->device_address_len) {
|
||||||
|
return AGENT_CHECK_TRUNCATED;
|
||||||
|
}
|
||||||
|
info->device_address[info->device_address_len - 1] = 0;
|
||||||
|
data += info->device_address_len;
|
||||||
|
}
|
||||||
|
return AGENT_CHECK_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static AgentCheckResult
|
||||||
|
agent_message_monitors_config_from_le(const VDAgentMessage *message_header, uint8_t *message)
|
||||||
|
{
|
||||||
|
uint32_from_le(message, sizeof(VDAgentMonitorsConfig), 0);
|
||||||
|
VDAgentMonitorsConfig *vdata = (VDAgentMonitorsConfig*) message;
|
||||||
|
vdata->flags &= VD_AGENT_CONFIG_MONITORS_FLAG_USE_POS|
|
||||||
|
VD_AGENT_CONFIG_MONITORS_FLAG_PHYSICAL_SIZE;
|
||||||
|
size_t element_size = sizeof(vdata->monitors[0]);
|
||||||
|
if ((vdata->flags & VD_AGENT_CONFIG_MONITORS_FLAG_PHYSICAL_SIZE) != 0) {
|
||||||
|
element_size += sizeof(VDAgentMonitorMM);
|
||||||
|
}
|
||||||
|
const size_t max_monitors =
|
||||||
|
(message_header->size - sizeof(*vdata)) / element_size;
|
||||||
|
if (vdata->num_of_monitors > max_monitors) {
|
||||||
|
return AGENT_CHECK_TRUNCATED;
|
||||||
|
}
|
||||||
|
uint32_from_le(message, sizeof(vdata->monitors[0]) * vdata->num_of_monitors,
|
||||||
|
sizeof(*vdata));
|
||||||
|
if ((vdata->flags & VD_AGENT_CONFIG_MONITORS_FLAG_PHYSICAL_SIZE) != 0) {
|
||||||
|
uint16_from_le(message, sizeof(VDAgentMonitorMM) * vdata->num_of_monitors,
|
||||||
|
sizeof(*vdata) + sizeof(vdata->monitors[0]) * vdata->num_of_monitors);
|
||||||
|
}
|
||||||
|
return AGENT_CHECK_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
AgentCheckResult
|
||||||
|
agent_check_message(const VDAgentMessage *message_header, uint8_t *message,
|
||||||
|
const uint32_t *capabilities, uint32_t capabilities_size)
|
||||||
|
{
|
||||||
|
AgentCheckResult res;
|
||||||
|
|
||||||
|
res = agent_message_check_size(message_header, capabilities, capabilities_size);
|
||||||
|
if (res != AGENT_CHECK_NO_ERROR) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (message_header->type) {
|
||||||
|
case VD_AGENT_MOUSE_STATE:
|
||||||
|
uint32_from_le(message, 3 * sizeof(uint32_t), 0);
|
||||||
|
break;
|
||||||
|
case VD_AGENT_REPLY:
|
||||||
|
case VD_AGENT_DISPLAY_CONFIG:
|
||||||
|
case VD_AGENT_MAX_CLIPBOARD:
|
||||||
|
case VD_AGENT_ANNOUNCE_CAPABILITIES:
|
||||||
|
uint32_from_le(message, message_header->size, 0);
|
||||||
|
break;
|
||||||
|
case VD_AGENT_MONITORS_CONFIG:
|
||||||
|
return agent_message_monitors_config_from_le(message_header, message);
|
||||||
|
|
||||||
|
case VD_AGENT_CLIPBOARD:
|
||||||
|
case VD_AGENT_CLIPBOARD_GRAB:
|
||||||
|
case VD_AGENT_CLIPBOARD_REQUEST:
|
||||||
|
case VD_AGENT_CLIPBOARD_RELEASE:
|
||||||
|
agent_message_clipboard_from_le(message_header, message,
|
||||||
|
capabilities, capabilities_size);
|
||||||
|
break;
|
||||||
|
case VD_AGENT_FILE_XFER_START:
|
||||||
|
case VD_AGENT_FILE_XFER_STATUS:
|
||||||
|
case VD_AGENT_FILE_XFER_DATA:
|
||||||
|
agent_message_file_xfer_from_le(message_header, message);
|
||||||
|
break;
|
||||||
|
case VD_AGENT_CLIENT_DISCONNECTED:
|
||||||
|
break;
|
||||||
|
case VD_AGENT_GRAPHICS_DEVICE_INFO:
|
||||||
|
return agent_message_graphics_device_info_check_from_le(message_header, message);
|
||||||
|
|
||||||
|
case VD_AGENT_AUDIO_VOLUME_SYNC: {
|
||||||
|
VDAgentAudioVolumeSync *vdata = (VDAgentAudioVolumeSync *)message;
|
||||||
|
const size_t max_channels =
|
||||||
|
(message_header->size - sizeof(*vdata)) / sizeof(vdata->volume[0]);
|
||||||
|
if (vdata->nchannels > max_channels) {
|
||||||
|
return AGENT_CHECK_TRUNCATED;
|
||||||
|
}
|
||||||
|
uint16_from_le(message, message_header->size - sizeof(*vdata), sizeof(*vdata));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return AGENT_CHECK_UNKNOWN_MESSAGE;
|
||||||
|
}
|
||||||
|
return AGENT_CHECK_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
agent_prepare_filexfer_status(AgentFileXferStatusMessageFull *status, size_t *status_size,
|
||||||
|
const uint32_t *capabilities, uint32_t capabilities_size)
|
||||||
|
{
|
||||||
|
if (*status_size < sizeof(status->common)) {
|
||||||
|
*status_size = sizeof(status->common);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if there are details but no cap for detail remove it
|
||||||
|
if (!VD_AGENT_HAS_CAPABILITY(capabilities, capabilities_size,
|
||||||
|
VD_AGENT_CAP_FILE_XFER_DETAILED_ERRORS)) {
|
||||||
|
*status_size = sizeof(status->common);
|
||||||
|
|
||||||
|
// if detail cap is not provided and error > threshold set to error
|
||||||
|
if (status->common.result >= VD_AGENT_FILE_XFER_STATUS_NOT_ENOUGH_SPACE) {
|
||||||
|
status->common.result = VD_AGENT_FILE_XFER_STATUS_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fix endian
|
||||||
|
switch (status->common.result) {
|
||||||
|
case VD_AGENT_FILE_XFER_STATUS_NOT_ENOUGH_SPACE:
|
||||||
|
FIX_ENDIAN64(status->not_enough_space.disk_free_space);
|
||||||
|
break;
|
||||||
|
case VD_AGENT_FILE_XFER_STATUS_ERROR:
|
||||||
|
FIX_ENDIAN32(status->error.error_code);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// header should be done last
|
||||||
|
FIX_ENDIAN32(status->common.id);
|
||||||
|
FIX_ENDIAN32(status->common.result);
|
||||||
|
}
|
||||||
83
common/agent.h
Normal file
83
common/agent.h
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||||
|
/*
|
||||||
|
Copyright (C) 2020 Red Hat, Inc.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <spice/macros.h>
|
||||||
|
#include <spice/vd_agent.h>
|
||||||
|
|
||||||
|
SPICE_BEGIN_DECLS
|
||||||
|
|
||||||
|
#include <spice/start-packed.h>
|
||||||
|
|
||||||
|
/* This helper macro is to define a structure in a way compatible with
|
||||||
|
* Microsoft compiler */
|
||||||
|
#define SPICE_INNER_FIELD_STATUS_ERROR(type, name) \
|
||||||
|
struct SPICE_ATTR_PACKED { \
|
||||||
|
char common_ ## name[sizeof(VDAgentFileXferStatusMessage)]; \
|
||||||
|
type name; \
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Structure to fill with transfer status.
|
||||||
|
* Fill as much details as you can and call agent_prepare_filexfer_status
|
||||||
|
* before sending to adjust for capabilities and endianness.
|
||||||
|
* If any detail are filled the status_size passed to agent_prepare_filexfer_status
|
||||||
|
* should be updated.
|
||||||
|
*/
|
||||||
|
typedef union SPICE_ATTR_PACKED AgentFileXferStatusMessageFull {
|
||||||
|
VDAgentFileXferStatusMessage common;
|
||||||
|
SPICE_INNER_FIELD_STATUS_ERROR(VDAgentFileXferStatusNotEnoughSpace, not_enough_space);
|
||||||
|
SPICE_INNER_FIELD_STATUS_ERROR(VDAgentFileXferStatusError, error);
|
||||||
|
} AgentFileXferStatusMessageFull;
|
||||||
|
|
||||||
|
#undef SPICE_INNER_FIELD_STATUS_ERROR
|
||||||
|
|
||||||
|
#include <spice/end-packed.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare AgentFileXferStatusMessageFull to
|
||||||
|
* be sent to network.
|
||||||
|
* Avoid protocol incompatibilities and endian issues
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
agent_prepare_filexfer_status(AgentFileXferStatusMessageFull *status, size_t *status_size,
|
||||||
|
const uint32_t *capabilities, uint32_t capabilities_size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Possible results checking a message.
|
||||||
|
* Beside AGENT_CHECK_NO_ERROR all other conditions are errors.
|
||||||
|
*/
|
||||||
|
typedef enum AgentCheckResult {
|
||||||
|
AGENT_CHECK_NO_ERROR,
|
||||||
|
AGENT_CHECK_WRONG_PROTOCOL_VERSION,
|
||||||
|
AGENT_CHECK_UNKNOWN_MESSAGE,
|
||||||
|
AGENT_CHECK_INVALID_SIZE,
|
||||||
|
AGENT_CHECK_TRUNCATED,
|
||||||
|
AGENT_CHECK_INVALID_DATA,
|
||||||
|
} AgentCheckResult;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check message from network and fix endianness
|
||||||
|
* Returns AGENT_CHECK_NO_ERROR if message is valid.
|
||||||
|
* message buffer size should be message_header->size.
|
||||||
|
*/
|
||||||
|
AgentCheckResult
|
||||||
|
agent_check_message(const VDAgentMessage *message_header, uint8_t *message,
|
||||||
|
const uint32_t *capabilities, uint32_t capabilities_size);
|
||||||
|
|
||||||
|
SPICE_END_DECLS
|
||||||
510
common/agent_interface.c
Normal file
510
common/agent_interface.c
Normal file
@ -0,0 +1,510 @@
|
|||||||
|
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||||
|
/*
|
||||||
|
Copyright (C) 2019 Red Hat, Inc.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <glib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <sys/eventfd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <poll.h>
|
||||||
|
|
||||||
|
#include <common/agent_interface.h>
|
||||||
|
|
||||||
|
typedef struct sockaddr SA;
|
||||||
|
|
||||||
|
static GThread *recorder_comm_thr;
|
||||||
|
static bool agent_terminated = false;
|
||||||
|
static int terminate_efd = -1;
|
||||||
|
static FILE *communication_f = NULL;
|
||||||
|
|
||||||
|
#define NB_MAX_RECORDERS 16
|
||||||
|
static recorder_info *recorders[NB_MAX_RECORDERS];
|
||||||
|
static uint32_t nb_recorders = 0;
|
||||||
|
|
||||||
|
static forward_quality_cb_t forward_quality_cb;
|
||||||
|
static void *forward_quality_cb_data;
|
||||||
|
|
||||||
|
static on_connect_cb_t on_connect_cb;
|
||||||
|
static void *on_connect_cb_data;
|
||||||
|
|
||||||
|
static uintptr_t recorder_tick(void);
|
||||||
|
|
||||||
|
#ifndef RECORDER_HZ
|
||||||
|
#define RECORDER_HZ 1000000
|
||||||
|
#endif // RECORDER_HZ
|
||||||
|
|
||||||
|
static GMutex mutex_socket;
|
||||||
|
|
||||||
|
static int agent_initialize_communication(int socket)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
int ret = -1;
|
||||||
|
FILE *socket_f;
|
||||||
|
|
||||||
|
g_mutex_lock(&mutex_socket);
|
||||||
|
|
||||||
|
if (communication_f != NULL) {
|
||||||
|
g_warning("A client is already connected, rejecting the connection.");
|
||||||
|
|
||||||
|
goto unlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
socket_f = fdopen(socket, "w+b");
|
||||||
|
|
||||||
|
fprintf(socket_f, "Recorders: ");
|
||||||
|
for (i = 0; i < nb_recorders; i++) {
|
||||||
|
g_debug("Sending %s", recorders[i]->name);
|
||||||
|
fprintf(socket_f, "%s;", recorders[i]->name);
|
||||||
|
}
|
||||||
|
fprintf(socket_f, "\n");
|
||||||
|
fflush(socket_f);
|
||||||
|
|
||||||
|
for (i = 0; i < nb_recorders; i++) {
|
||||||
|
char enable;
|
||||||
|
|
||||||
|
if (read(socket, &enable, sizeof(enable)) != sizeof(enable)) {
|
||||||
|
g_warning("Invalid read on the client socket");
|
||||||
|
|
||||||
|
goto unlock;
|
||||||
|
}
|
||||||
|
if (enable != '0' && enable != '1') {
|
||||||
|
g_critical("Invalid enable-value received for recorder '%s': %u",
|
||||||
|
recorders[i]->name, enable);
|
||||||
|
|
||||||
|
goto unlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enable == '0') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
recorders[i]->trace = 1;
|
||||||
|
g_info("Enable recorder '%s'", recorders[i]->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (on_connect_cb && on_connect_cb(on_connect_cb_data)) {
|
||||||
|
goto unlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
communication_f = socket_f;
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
unlock:
|
||||||
|
g_mutex_unlock(&mutex_socket);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void agent_finalize_communication(int socket)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
g_info("Communication socket closed.");
|
||||||
|
|
||||||
|
g_mutex_lock(&mutex_socket);
|
||||||
|
g_assert(socket == fileno(communication_f));
|
||||||
|
|
||||||
|
fclose(communication_f);
|
||||||
|
communication_f = NULL;
|
||||||
|
|
||||||
|
for (i = 0; i < nb_recorders; i++) {
|
||||||
|
recorders[i]->trace = 0;
|
||||||
|
}
|
||||||
|
g_mutex_unlock(&mutex_socket);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void forward_quality(const char *quality)
|
||||||
|
{
|
||||||
|
if (!forward_quality_cb) {
|
||||||
|
g_warning("Quality: No callback set, dropping the message (%s).", quality);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_info("Quality: Forwarding '%s'", quality);
|
||||||
|
|
||||||
|
forward_quality_cb(forward_quality_cb_data, quality);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int agent_process_communication(int socket)
|
||||||
|
{
|
||||||
|
static char msg_in[128];
|
||||||
|
|
||||||
|
static long unsigned int len = 0;
|
||||||
|
|
||||||
|
g_assert(socket == fileno(communication_f));
|
||||||
|
|
||||||
|
int nbytes = read(socket, msg_in + len, 1);
|
||||||
|
|
||||||
|
if (nbytes < 0 && errno == EINTR) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nbytes <= 0) {
|
||||||
|
agent_finalize_communication(socket);
|
||||||
|
return -1; // socket closed
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg_in[len] == '\0') {
|
||||||
|
// process quality indicator
|
||||||
|
forward_quality(msg_in);
|
||||||
|
len = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
len += nbytes;
|
||||||
|
|
||||||
|
if (len >= sizeof(msg_in) - 1) {
|
||||||
|
msg_in[sizeof(msg_in) - 1] = '\0';
|
||||||
|
g_warning("Invalid message received (too long?): %s", msg_in);
|
||||||
|
len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int make_socket(guint port)
|
||||||
|
{
|
||||||
|
struct sockaddr_in servaddr;
|
||||||
|
int listen_socket = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
|
||||||
|
if (listen_socket == -1) {
|
||||||
|
g_critical("socket creation failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int enable = 1;
|
||||||
|
if (setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0) {
|
||||||
|
g_critical("setsockopt(SO_REUSEADDR) failed");
|
||||||
|
close(listen_socket);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&servaddr, 0, sizeof(servaddr));
|
||||||
|
|
||||||
|
servaddr.sin_family = AF_INET;
|
||||||
|
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||||
|
servaddr.sin_port = htons(port);
|
||||||
|
|
||||||
|
if (bind(listen_socket, (SA *) &servaddr, sizeof(servaddr)) != 0) {
|
||||||
|
g_critical("socket bind failed");
|
||||||
|
close(listen_socket);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return listen_socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gpointer handle_communications(gpointer user_data)
|
||||||
|
{
|
||||||
|
struct pollfd fds[3];
|
||||||
|
int nb_fd = 0;
|
||||||
|
int listen_socket;
|
||||||
|
int i;
|
||||||
|
guint port = GPOINTER_TO_UINT(user_data);
|
||||||
|
|
||||||
|
listen_socket = make_socket(port);
|
||||||
|
if (listen_socket < 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_debug("Listening!");
|
||||||
|
|
||||||
|
if ((listen(listen_socket, 1)) != 0) {
|
||||||
|
g_critical("listen failed: %m");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
fds[0].fd = terminate_efd;
|
||||||
|
fds[0].events = POLLIN;
|
||||||
|
fds[1].fd = listen_socket;
|
||||||
|
fds[1].events = POLLIN;
|
||||||
|
nb_fd = 2;
|
||||||
|
|
||||||
|
while (!agent_terminated) {
|
||||||
|
|
||||||
|
/* Block until input arrives on one or more active sockets. */
|
||||||
|
int ret = poll(fds, nb_fd, -1);
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
g_critical("poll failed: %m");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Service all the sockets with input pending. */
|
||||||
|
for (i = 0; i < nb_fd; i++) {
|
||||||
|
int fd = fds[i].fd;
|
||||||
|
if (fd == terminate_efd) {
|
||||||
|
if (fds[i].revents & POLLIN) {
|
||||||
|
g_assert(agent_terminated);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (fd == listen_socket) {
|
||||||
|
if (fds[i].revents & ~POLLIN) {
|
||||||
|
g_critical("server socket closed");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!(fds[i].revents & POLLIN)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Connection request on original socket. */
|
||||||
|
int new_fd = accept(listen_socket, NULL, NULL);
|
||||||
|
|
||||||
|
if (new_fd < 0) {
|
||||||
|
g_critical("accept failed: %m");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nb_fd == 3) {
|
||||||
|
close(new_fd);
|
||||||
|
g_warning("Too many clients accepted ...");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_debug("Agent Interface: client connected!");
|
||||||
|
|
||||||
|
if (agent_initialize_communication(new_fd)) {
|
||||||
|
close(new_fd);
|
||||||
|
g_warning("Initialization failed ...");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
fds[nb_fd].fd = new_fd;
|
||||||
|
fds[nb_fd].events = POLLIN;
|
||||||
|
nb_fd++;
|
||||||
|
|
||||||
|
/* fds array modified, restart the poll. */
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
if (!(fds[i].revents & POLLIN)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Data arriving on an already-connected socket. */
|
||||||
|
if (agent_process_communication(fd) < 0) {
|
||||||
|
nb_fd--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
close(terminate_efd);
|
||||||
|
close(listen_socket);
|
||||||
|
|
||||||
|
g_info("Agent interface thread: bye!");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void recorder_deregister(void);
|
||||||
|
|
||||||
|
static void recorder_initialization(unsigned int port)
|
||||||
|
{
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
terminate_efd = eventfd(0, 0);
|
||||||
|
if (terminate_efd == -1) {
|
||||||
|
g_critical("eventfd failed: %m");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
recorder_comm_thr = g_thread_try_new("smart_agent_interface",
|
||||||
|
handle_communications,
|
||||||
|
GUINT_TO_POINTER((guint) port), &error);
|
||||||
|
if (error) {
|
||||||
|
g_assert(!recorder_comm_thr);
|
||||||
|
g_critical("Error: Could not start the agent interface thread: %s", error->message);
|
||||||
|
g_error_free(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
atexit(recorder_deregister);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void recorder_interrupt_communications(void)
|
||||||
|
{
|
||||||
|
agent_terminated = true;
|
||||||
|
|
||||||
|
uint64_t msg = 1;
|
||||||
|
ssize_t s = write(terminate_efd, &msg, sizeof(uint64_t));
|
||||||
|
|
||||||
|
if (s != sizeof(uint64_t)) {
|
||||||
|
g_warning("failed to send recorder thread termination event: %m");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void recorder_deregister(void)
|
||||||
|
{
|
||||||
|
if (recorder_comm_thr) {
|
||||||
|
recorder_interrupt_communications();
|
||||||
|
g_thread_join(recorder_comm_thr);
|
||||||
|
recorder_comm_thr = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void recorder_activate(recorder_info *recorder)
|
||||||
|
{
|
||||||
|
if (nb_recorders >= NB_MAX_RECORDERS) {
|
||||||
|
g_critical("Too many recorders configured (nb max: %d)", NB_MAX_RECORDERS);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
recorders[nb_recorders] = recorder;
|
||||||
|
nb_recorders++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void do_send_entry(FILE *dest, recorder_info *info, recorder_entry *entry, va_list args)
|
||||||
|
{
|
||||||
|
fprintf(dest, "Name: %s\nFunction: %s\nTime: %lu\n",
|
||||||
|
info->name, entry->where, entry->timestamp);
|
||||||
|
|
||||||
|
vfprintf(dest, entry->format, args);
|
||||||
|
fprintf(dest, "\n\n");
|
||||||
|
|
||||||
|
fflush(dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void recorder_trace_entry(recorder_info *info, recorder_entry *entry, ...)
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Show a recorder entry when a trace is enabled
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
|
||||||
|
if (strchr(entry->format, '\n') != NULL) {
|
||||||
|
g_critical("Agent records cannot contain '\n' char ... (%s)", entry->where);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// send info/entry to the socket
|
||||||
|
g_mutex_lock(&mutex_socket);
|
||||||
|
|
||||||
|
if (communication_f == NULL) {
|
||||||
|
g_mutex_unlock(&mutex_socket);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
va_start(args, entry);
|
||||||
|
do_send_entry(communication_f, info, entry, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
if (g_strcmp0(g_getenv("SPICE_AGENT_LOG_RECORDS"), "1") == 0) {
|
||||||
|
va_start(args, entry);
|
||||||
|
do_send_entry(stderr, info, entry, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_mutex_unlock(&mutex_socket);
|
||||||
|
}
|
||||||
|
|
||||||
|
void agent_interface_start(unsigned int port)
|
||||||
|
{
|
||||||
|
g_info("Launch on port %u", port);
|
||||||
|
recorder_initialization(port);
|
||||||
|
}
|
||||||
|
|
||||||
|
void agent_interface_set_forward_quality_cb(forward_quality_cb_t cb, void *data)
|
||||||
|
{
|
||||||
|
g_debug("Received forward_quality callback");
|
||||||
|
forward_quality_cb = cb;
|
||||||
|
forward_quality_cb_data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void agent_interface_set_on_connect_cb(on_connect_cb_t cb, void *data)
|
||||||
|
{
|
||||||
|
g_debug("Received on_connect callback");
|
||||||
|
on_connect_cb = cb;
|
||||||
|
on_connect_cb_data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void recorder_append(recorder_info *rec,
|
||||||
|
const char *where,
|
||||||
|
const char *format,
|
||||||
|
uintptr_t a0,
|
||||||
|
uintptr_t a1,
|
||||||
|
uintptr_t a2,
|
||||||
|
uintptr_t a3)
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Enter a record entry in ring buffer with given set of args
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
{
|
||||||
|
recorder_entry entry;
|
||||||
|
|
||||||
|
if (!rec->trace) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry.format = format;
|
||||||
|
entry.timestamp = recorder_tick();
|
||||||
|
entry.where = where;
|
||||||
|
|
||||||
|
recorder_trace_entry(rec, &entry, a0, a1, a2, a3);
|
||||||
|
}
|
||||||
|
|
||||||
|
void recorder_append2(recorder_info *rec,
|
||||||
|
const char *where,
|
||||||
|
const char *format,
|
||||||
|
uintptr_t a0,
|
||||||
|
uintptr_t a1,
|
||||||
|
uintptr_t a2,
|
||||||
|
uintptr_t a3,
|
||||||
|
uintptr_t a4,
|
||||||
|
uintptr_t a5,
|
||||||
|
uintptr_t a6,
|
||||||
|
uintptr_t a7)
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Enter a double record (up to 8 args)
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
{
|
||||||
|
recorder_entry entry;
|
||||||
|
|
||||||
|
if (!rec->trace) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry.format = format;
|
||||||
|
entry.timestamp = recorder_tick();
|
||||||
|
entry.where = where;
|
||||||
|
|
||||||
|
recorder_trace_entry(rec, &entry, a0, a1, a2, a3, a4, a5, a6, a7);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
//
|
||||||
|
// Support functions
|
||||||
|
//
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
static uintptr_t recorder_tick(void)
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Return the "ticks" as stored in the recorder
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
{
|
||||||
|
struct timeval t;
|
||||||
|
|
||||||
|
gettimeofday(&t, NULL);
|
||||||
|
|
||||||
|
return t.tv_sec * RECORDER_HZ + t.tv_usec / (1000000 / RECORDER_HZ);
|
||||||
|
}
|
||||||
564
common/agent_interface.h
Normal file
564
common/agent_interface.h
Normal file
@ -0,0 +1,564 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// *****************************************************************************
|
||||||
|
// This software is licensed under the GNU Lesser General Public License v2+
|
||||||
|
// (C) 2017-2019, Christophe de Dinechin <christophe@dinechin.org>
|
||||||
|
// *****************************************************************************
|
||||||
|
// This file was part of Recorder
|
||||||
|
//
|
||||||
|
// Recorder is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 2 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Recorder is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with Recorder, in a file named COPYING.
|
||||||
|
// If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// *****************************************************************************
|
||||||
|
/* This file is based on Recorder's recorder.h file, that describes a general-
|
||||||
|
* purpose instrumentation interface. agent_interface.h is a trimmed-down
|
||||||
|
* version of it. */
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
recorder_dump_on_common_signals(unsigned add, unsigned remove)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
//
|
||||||
|
// Recorder data structures
|
||||||
|
//
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
typedef struct recorder_entry
|
||||||
|
/// ---------------------------------------------------------------------------
|
||||||
|
/// Entry in the flight recorder.
|
||||||
|
///----------------------------------------------------------------------------
|
||||||
|
/// Notice that the arguments are stored as "intptr_t" because that type
|
||||||
|
/// is guaranteed to be the same size as a pointer. This allows us to
|
||||||
|
/// properly align recorder entries to powers of 2 for efficiency.
|
||||||
|
/// Also read explanations of \ref _recorder_double and \ref _recorder_float
|
||||||
|
/// below regarding how to use floating-point with the recorder.
|
||||||
|
{
|
||||||
|
const char *format; ///< Printf-style format for record + file/line
|
||||||
|
uintptr_t timestamp; ///< Time at which record took place
|
||||||
|
const char *where; ///< Source code function
|
||||||
|
uintptr_t args[4]; ///< Four arguments, for a total of 8 fields
|
||||||
|
} recorder_entry;
|
||||||
|
|
||||||
|
|
||||||
|
/// A global counter indicating the order of entries across recorders.
|
||||||
|
/// this is incremented atomically for each record() call.
|
||||||
|
/// It must be exposed because all XYZ_record() implementations need to
|
||||||
|
/// touch the same shared variable in order to provide a global order.
|
||||||
|
extern uintptr_t recorder_order;
|
||||||
|
|
||||||
|
typedef struct recorder_info
|
||||||
|
///----------------------------------------------------------------------------
|
||||||
|
/// A linked list of the activated recorders
|
||||||
|
///----------------------------------------------------------------------------
|
||||||
|
{
|
||||||
|
intptr_t trace; ///< Trace this recorder
|
||||||
|
const char * name; ///< Name of this parameter / recorder
|
||||||
|
const char * description;///< Description of what is recorded
|
||||||
|
recorder_entry data[0]; ///< Data for this recorder
|
||||||
|
} recorder_info;
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
//
|
||||||
|
// Adding data to a recorder
|
||||||
|
//
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
extern void recorder_append(recorder_info *rec,
|
||||||
|
const char *where,
|
||||||
|
const char *format,
|
||||||
|
uintptr_t a0,
|
||||||
|
uintptr_t a1,
|
||||||
|
uintptr_t a2,
|
||||||
|
uintptr_t a3);
|
||||||
|
extern void recorder_append2(recorder_info *rec,
|
||||||
|
const char *where,
|
||||||
|
const char *format,
|
||||||
|
uintptr_t a0,
|
||||||
|
uintptr_t a1,
|
||||||
|
uintptr_t a2,
|
||||||
|
uintptr_t a3,
|
||||||
|
uintptr_t a4,
|
||||||
|
uintptr_t a5,
|
||||||
|
uintptr_t a6,
|
||||||
|
uintptr_t a7);
|
||||||
|
extern void recorder_append3(recorder_info *rec,
|
||||||
|
const char *where,
|
||||||
|
const char *format,
|
||||||
|
uintptr_t a0,
|
||||||
|
uintptr_t a1,
|
||||||
|
uintptr_t a2,
|
||||||
|
uintptr_t a3,
|
||||||
|
uintptr_t a4,
|
||||||
|
uintptr_t a5,
|
||||||
|
uintptr_t a6,
|
||||||
|
uintptr_t a7,
|
||||||
|
uintptr_t a8,
|
||||||
|
uintptr_t a9,
|
||||||
|
uintptr_t a10,
|
||||||
|
uintptr_t a11);
|
||||||
|
|
||||||
|
/// Activate a recorder (during construction time)
|
||||||
|
extern void recorder_activate(recorder_info *recorder);
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
//
|
||||||
|
// Declaration of recorders and tweaks
|
||||||
|
//
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
#define RECORDER_DECLARE(Name) \
|
||||||
|
/* ----------------------------------------------------------------*/ \
|
||||||
|
/* Declare a recorder with the given name (for use in headers) */ \
|
||||||
|
/* ----------------------------------------------------------------*/ \
|
||||||
|
extern recorder_info * const recorder_info_ptr_for_##Name; \
|
||||||
|
extern struct recorder_info_for_##Name recorder_info_for_##Name
|
||||||
|
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
//
|
||||||
|
// Definition of recorders and tweaks
|
||||||
|
//
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
#define RECORDER(Name, Size, Info) RECORDER_DEFINE(Name,Size,Info)
|
||||||
|
|
||||||
|
#define RECORDER_DEFINE(Name, Size, Info) \
|
||||||
|
/*!----------------------------------------------------------------*/ \
|
||||||
|
/*! Define a recorder type with Size elements */ \
|
||||||
|
/*!----------------------------------------------------------------*/ \
|
||||||
|
/*! \param Name is the C name fo the recorder. \
|
||||||
|
*! \param Size is the number of entries in the circular buffer. \
|
||||||
|
*! \param Info is a description of the recorder for help. */ \
|
||||||
|
\
|
||||||
|
/* The entry in linked list for this type */ \
|
||||||
|
struct recorder_info_for_##Name \
|
||||||
|
{ \
|
||||||
|
recorder_info info; \
|
||||||
|
recorder_entry data[Size]; \
|
||||||
|
} \
|
||||||
|
recorder_info_for_##Name = \
|
||||||
|
{ \
|
||||||
|
{ \
|
||||||
|
0, #Name, Info, {} \
|
||||||
|
}, \
|
||||||
|
{} \
|
||||||
|
}; \
|
||||||
|
recorder_info * const recorder_info_ptr_for_##Name = \
|
||||||
|
&recorder_info_for_##Name.info; \
|
||||||
|
\
|
||||||
|
RECORDER_CONSTRUCTOR \
|
||||||
|
static void recorder_activate_##Name(void) \
|
||||||
|
/* ----------------------------------------------------------------*/ \
|
||||||
|
/* Activate recorder before entering main() */ \
|
||||||
|
/* ----------------------------------------------------------------*/ \
|
||||||
|
{ \
|
||||||
|
recorder_activate(RECORDER_INFO(Name)); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
/* Purposefully generate compile error if macro not followed by ; */ \
|
||||||
|
extern void recorder_activate(recorder_info *recorder)
|
||||||
|
|
||||||
|
typedef struct SpiceDummyTweak {
|
||||||
|
intptr_t tweak_value;
|
||||||
|
} SpiceDummyTweak;
|
||||||
|
|
||||||
|
typedef struct SpiceEmptyStruct {
|
||||||
|
char dummy[0];
|
||||||
|
} SpiceEmptyStruct;
|
||||||
|
|
||||||
|
#define RECORDER_TWEAK_DECLARE(rec) \
|
||||||
|
extern const SpiceDummyTweak spice_recorder_tweak_ ## rec
|
||||||
|
|
||||||
|
#define RECORDER_TWEAK_DEFINE(rec, value, comment) \
|
||||||
|
const SpiceDummyTweak spice_recorder_tweak_ ## rec = { (value) }
|
||||||
|
|
||||||
|
#define RECORDER_TWEAK(rec) \
|
||||||
|
((spice_recorder_tweak_ ## rec).tweak_value)
|
||||||
|
|
||||||
|
#define RECORDER_TRACE(rec) \
|
||||||
|
(sizeof(struct recorder_info_for_ ## rec) != sizeof(SpiceEmptyStruct))
|
||||||
|
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
//
|
||||||
|
// Access to recorder and tweak info
|
||||||
|
//
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
#define RECORDER_INFO(Name) (recorder_info_ptr_for_##Name)
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
//
|
||||||
|
// Recording stuff
|
||||||
|
//
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
#define record(Name, ...) RECORD_MACRO(Name, __VA_ARGS__)
|
||||||
|
#define RECORD(Name,...) RECORD_MACRO(Name, __VA_ARGS__)
|
||||||
|
#define RECORD_MACRO(Name, ...) \
|
||||||
|
RECORD_(RECORD,RECORD_COUNT_(__VA_ARGS__),Name,__VA_ARGS__)
|
||||||
|
#define RECORD_(RECORD,RCOUNT,Name,...) \
|
||||||
|
RECORD__(RECORD,RCOUNT,Name,__VA_ARGS__)
|
||||||
|
#define RECORD__(RECORD,RCOUNT,Name,...) \
|
||||||
|
RECORD##RCOUNT(Name,__VA_ARGS__)
|
||||||
|
#define RECORD_COUNT_(...) RECORD_COUNT__(Dummy,##__VA_ARGS__,_X,_X,_12,_11,_10,_9,_8,_7,_6,_5,_4,_3,_2,_1,_0)
|
||||||
|
#define RECORD_COUNT__(Dummy,_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_N,...) _N
|
||||||
|
|
||||||
|
#define RECORD_0(Name, Format) \
|
||||||
|
recorder_append(RECORDER_INFO(Name), \
|
||||||
|
RECORDER_SOURCE_FUNCTION, \
|
||||||
|
RECORDER_SOURCE_LOCATION \
|
||||||
|
Format, 0, 0, 0, 0)
|
||||||
|
#define RECORD_1(Name, Format, a) \
|
||||||
|
recorder_append(RECORDER_INFO(Name), \
|
||||||
|
RECORDER_SOURCE_FUNCTION, \
|
||||||
|
RECORDER_SOURCE_LOCATION \
|
||||||
|
Format, \
|
||||||
|
RECORDER_ARG(a), 0, 0, 0)
|
||||||
|
#define RECORD_2(Name, Format, a,b) \
|
||||||
|
recorder_append(RECORDER_INFO(Name), \
|
||||||
|
RECORDER_SOURCE_FUNCTION, \
|
||||||
|
RECORDER_SOURCE_LOCATION \
|
||||||
|
Format, \
|
||||||
|
RECORDER_ARG(a), \
|
||||||
|
RECORDER_ARG(b), 0, 0)
|
||||||
|
#define RECORD_3(Name, Format, a,b,c) \
|
||||||
|
recorder_append(RECORDER_INFO(Name), \
|
||||||
|
RECORDER_SOURCE_FUNCTION, \
|
||||||
|
RECORDER_SOURCE_LOCATION \
|
||||||
|
Format, \
|
||||||
|
RECORDER_ARG(a), \
|
||||||
|
RECORDER_ARG(b), \
|
||||||
|
RECORDER_ARG(c), 0)
|
||||||
|
#define RECORD_4(Name, Format, a,b,c,d) \
|
||||||
|
recorder_append(RECORDER_INFO(Name), \
|
||||||
|
RECORDER_SOURCE_FUNCTION, \
|
||||||
|
RECORDER_SOURCE_LOCATION \
|
||||||
|
Format, \
|
||||||
|
RECORDER_ARG(a), \
|
||||||
|
RECORDER_ARG(b), \
|
||||||
|
RECORDER_ARG(c), \
|
||||||
|
RECORDER_ARG(d))
|
||||||
|
#define RECORD_5(Name, Format, a,b,c,d,e) \
|
||||||
|
recorder_append2(RECORDER_INFO(Name), \
|
||||||
|
RECORDER_SOURCE_FUNCTION, \
|
||||||
|
RECORDER_SOURCE_LOCATION \
|
||||||
|
Format, \
|
||||||
|
RECORDER_ARG(a), \
|
||||||
|
RECORDER_ARG(b), \
|
||||||
|
RECORDER_ARG(c), \
|
||||||
|
RECORDER_ARG(d), \
|
||||||
|
RECORDER_ARG(e), 0, 0, 0)
|
||||||
|
#define RECORD_6(Name, Format, a,b,c,d,e,f) \
|
||||||
|
recorder_append2(RECORDER_INFO(Name), \
|
||||||
|
RECORDER_SOURCE_FUNCTION, \
|
||||||
|
RECORDER_SOURCE_LOCATION \
|
||||||
|
Format, \
|
||||||
|
RECORDER_ARG(a), \
|
||||||
|
RECORDER_ARG(b), \
|
||||||
|
RECORDER_ARG(c), \
|
||||||
|
RECORDER_ARG(d), \
|
||||||
|
RECORDER_ARG(e), \
|
||||||
|
RECORDER_ARG(f), 0, 0)
|
||||||
|
#define RECORD_7(Name, Format, a,b,c,d,e,f,g) \
|
||||||
|
recorder_append2(RECORDER_INFO(Name), \
|
||||||
|
RECORDER_SOURCE_FUNCTION, \
|
||||||
|
RECORDER_SOURCE_LOCATION \
|
||||||
|
Format, \
|
||||||
|
RECORDER_ARG(a), \
|
||||||
|
RECORDER_ARG(b), \
|
||||||
|
RECORDER_ARG(c), \
|
||||||
|
RECORDER_ARG(d), \
|
||||||
|
RECORDER_ARG(e), \
|
||||||
|
RECORDER_ARG(f), \
|
||||||
|
RECORDER_ARG(g), 0)
|
||||||
|
#define RECORD_8(Name, Format, a,b,c,d,e,f,g,h) \
|
||||||
|
recorder_append2(RECORDER_INFO(Name), \
|
||||||
|
RECORDER_SOURCE_FUNCTION, \
|
||||||
|
RECORDER_SOURCE_LOCATION \
|
||||||
|
Format, \
|
||||||
|
RECORDER_ARG(a), \
|
||||||
|
RECORDER_ARG(b), \
|
||||||
|
RECORDER_ARG(c), \
|
||||||
|
RECORDER_ARG(d), \
|
||||||
|
RECORDER_ARG(e), \
|
||||||
|
RECORDER_ARG(f), \
|
||||||
|
RECORDER_ARG(g), \
|
||||||
|
RECORDER_ARG(h))
|
||||||
|
#define RECORD_9(Name, Format, a,b,c,d,e,f,g,h,i) \
|
||||||
|
recorder_append3(RECORDER_INFO(Name), \
|
||||||
|
RECORDER_SOURCE_FUNCTION, \
|
||||||
|
RECORDER_SOURCE_LOCATION \
|
||||||
|
Format, \
|
||||||
|
RECORDER_ARG(a), \
|
||||||
|
RECORDER_ARG(b), \
|
||||||
|
RECORDER_ARG(c), \
|
||||||
|
RECORDER_ARG(d), \
|
||||||
|
RECORDER_ARG(e), \
|
||||||
|
RECORDER_ARG(f), \
|
||||||
|
RECORDER_ARG(g), \
|
||||||
|
RECORDER_ARG(h), \
|
||||||
|
RECORDER_ARG(i), 0,0,0)
|
||||||
|
#define RECORD_10(Name, Format, a,b,c,d,e,f,g,h,i,j) \
|
||||||
|
recorder_append3(RECORDER_INFO(Name), \
|
||||||
|
RECORDER_SOURCE_FUNCTION, \
|
||||||
|
RECORDER_SOURCE_LOCATION \
|
||||||
|
Format, \
|
||||||
|
RECORDER_ARG(a), \
|
||||||
|
RECORDER_ARG(b), \
|
||||||
|
RECORDER_ARG(c), \
|
||||||
|
RECORDER_ARG(d), \
|
||||||
|
RECORDER_ARG(e), \
|
||||||
|
RECORDER_ARG(f), \
|
||||||
|
RECORDER_ARG(g), \
|
||||||
|
RECORDER_ARG(h), \
|
||||||
|
RECORDER_ARG(i), \
|
||||||
|
RECORDER_ARG(j), 0,0)
|
||||||
|
#define RECORD_11(Name, Format, a,b,c,d,e,f,g,h,i,j,k) \
|
||||||
|
recorder_append3(RECORDER_INFO(Name), \
|
||||||
|
RECORDER_SOURCE_FUNCTION, \
|
||||||
|
RECORDER_SOURCE_LOCATION \
|
||||||
|
Format, \
|
||||||
|
RECORDER_ARG(a), \
|
||||||
|
RECORDER_ARG(b), \
|
||||||
|
RECORDER_ARG(c), \
|
||||||
|
RECORDER_ARG(d), \
|
||||||
|
RECORDER_ARG(e), \
|
||||||
|
RECORDER_ARG(f), \
|
||||||
|
RECORDER_ARG(g), \
|
||||||
|
RECORDER_ARG(h), \
|
||||||
|
RECORDER_ARG(i), \
|
||||||
|
RECORDER_ARG(j), \
|
||||||
|
RECORDER_ARG(k),0)
|
||||||
|
#define RECORD_12(Name,Format,a,b,c,d,e,f,g,h,i,j,k,l) \
|
||||||
|
recorder_append3(RECORDER_INFO(Name), \
|
||||||
|
RECORDER_SOURCE_FUNCTION, \
|
||||||
|
RECORDER_SOURCE_LOCATION \
|
||||||
|
Format, \
|
||||||
|
RECORDER_ARG(a), \
|
||||||
|
RECORDER_ARG(b), \
|
||||||
|
RECORDER_ARG(c), \
|
||||||
|
RECORDER_ARG(d), \
|
||||||
|
RECORDER_ARG(e), \
|
||||||
|
RECORDER_ARG(f), \
|
||||||
|
RECORDER_ARG(g), \
|
||||||
|
RECORDER_ARG(h), \
|
||||||
|
RECORDER_ARG(i), \
|
||||||
|
RECORDER_ARG(j), \
|
||||||
|
RECORDER_ARG(k), \
|
||||||
|
RECORDER_ARG(l))
|
||||||
|
#define RECORD_X(Name, ...) RECORD_TOO_MANY_ARGS(printf(__VA_ARGS__))
|
||||||
|
|
||||||
|
|
||||||
|
// Some ugly macro drudgery to make things easy to use. Adjust type.
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#define RECORDER_ARG(arg) _recorder_arg(arg)
|
||||||
|
#else // !__cplusplus
|
||||||
|
|
||||||
|
#if defined(__GNUC__) && !defined(__clang__)
|
||||||
|
# if __GNUC__ <= 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 9)
|
||||||
|
# define RECORDER_WITHOUT_GENERIC
|
||||||
|
# endif
|
||||||
|
#endif // __GNUC__
|
||||||
|
|
||||||
|
#ifdef RECORDER_WITHOUT_GENERIC
|
||||||
|
#define RECORDER_ARG(arg) ((uintptr_t) (arg))
|
||||||
|
#else // !RECORDER_WITHOUT_GENERIC
|
||||||
|
#define RECORDER_ARG(arg) \
|
||||||
|
_Generic(arg, \
|
||||||
|
unsigned char: _recorder_unsigned, \
|
||||||
|
unsigned short: _recorder_unsigned, \
|
||||||
|
unsigned: _recorder_unsigned, \
|
||||||
|
unsigned long: _recorder_unsigned, \
|
||||||
|
unsigned long long:_recorder_unsigned, \
|
||||||
|
char: _recorder_char, \
|
||||||
|
signed char: _recorder_signed, \
|
||||||
|
signed short: _recorder_signed, \
|
||||||
|
signed: _recorder_signed, \
|
||||||
|
signed long: _recorder_signed, \
|
||||||
|
signed long long: _recorder_signed, \
|
||||||
|
float: _recorder_float, \
|
||||||
|
double: _recorder_double, \
|
||||||
|
default: _recorder_pointer)(arg)
|
||||||
|
#endif // RECORDER_WITHOUT_GENERIC
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
//
|
||||||
|
// Timing information
|
||||||
|
//
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
#define RECORD_TIMING_BEGIN(rec) \
|
||||||
|
do { RECORD(rec, "begin");
|
||||||
|
#define RECORD_TIMING_END(rec, op, name, value) \
|
||||||
|
RECORD(rec, "end" op name); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
//
|
||||||
|
// Support macros
|
||||||
|
//
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
#define RECORDER_SOURCE_FUNCTION __func__ /* Works in C99 and C++11 */
|
||||||
|
#define RECORDER_SOURCE_LOCATION __FILE__ ":" RECORDER_STRING(__LINE__) ":"
|
||||||
|
#define RECORDER_STRING(LINE) RECORDER_STRING_(LINE)
|
||||||
|
#define RECORDER_STRING_(LINE) #LINE
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#define RECORDER_CONSTRUCTOR __attribute__((constructor))
|
||||||
|
#else
|
||||||
|
#define RECORDER_CONSTRUCTOR
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
//
|
||||||
|
// Utility: Convert floating point values for vararg format
|
||||||
|
//
|
||||||
|
// ============================================================================
|
||||||
|
//
|
||||||
|
// The recorder stores only uintptr_t in recorder entries. Integer types
|
||||||
|
// are promoted, pointer types are converted. Floating point values
|
||||||
|
// are converted a floating point type of the same size as uintptr_t,
|
||||||
|
// i.e. float are converted to double on 64-bit platforms, and conversely.
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
// In C++, we don't use _Generic but actual overloading
|
||||||
|
template <class inttype>
|
||||||
|
static inline uintptr_t _recorder_arg(inttype i)
|
||||||
|
{
|
||||||
|
return (uintptr_t) i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline uintptr_t _recorder_arg(const std::string &arg)
|
||||||
|
{
|
||||||
|
return (uintptr_t) arg.c_str();
|
||||||
|
}
|
||||||
|
#define _recorder_float _recorder_arg
|
||||||
|
#define _recorder_double _recorder_arg
|
||||||
|
|
||||||
|
#else // !__cplusplus
|
||||||
|
|
||||||
|
static inline uintptr_t _recorder_char(char c)
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Necessary because of the way generic selections work
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
{
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline uintptr_t _recorder_unsigned(uintptr_t i)
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Necessary because of the way generic selections work
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline uintptr_t _recorder_signed(intptr_t i)
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Necessary because of the way generic selections work
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
{
|
||||||
|
return (uintptr_t) i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline uintptr_t _recorder_pointer(const void *i)
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Necessary because of the way generic selections work
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
{
|
||||||
|
return (uintptr_t) i;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
|
||||||
|
static inline uintptr_t _recorder_float(float f)
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Convert floating point number to intptr_t representation for recorder
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
{
|
||||||
|
if (sizeof(float) == sizeof(intptr_t)) {
|
||||||
|
union { float f; uintptr_t i; } u;
|
||||||
|
u.f = f;
|
||||||
|
return u.i;
|
||||||
|
} else {
|
||||||
|
union { double d; uintptr_t i; } u;
|
||||||
|
u.d = (double) f;
|
||||||
|
return u.i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline uintptr_t _recorder_double(double d)
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Convert double-precision floating point number to intptr_t representation
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
{
|
||||||
|
if (sizeof(double) == sizeof(intptr_t)) {
|
||||||
|
union { double d; uintptr_t i; } u;
|
||||||
|
u.d = d;
|
||||||
|
return u.i;
|
||||||
|
} else {
|
||||||
|
// Better to lose precision than not store any data
|
||||||
|
union { float f; uintptr_t i; } u;
|
||||||
|
u.f = d;
|
||||||
|
return u.i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Agent-Interface specific definitions
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
// launch the Agent-Interface server socket
|
||||||
|
extern void agent_interface_start(unsigned int port);
|
||||||
|
|
||||||
|
//
|
||||||
|
typedef void (*forward_quality_cb_t)(void *, const char *);
|
||||||
|
extern void agent_interface_set_forward_quality_cb(forward_quality_cb_t cb, void *data);
|
||||||
|
|
||||||
|
// set a callback function triggered when a new client connects to the socket
|
||||||
|
typedef int (*on_connect_cb_t)(void *);
|
||||||
|
extern void agent_interface_set_on_connect_cb(on_connect_cb_t cb, void *data);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif // __cplusplus
|
||||||
@ -22,18 +22,20 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdlib.h>
|
#if !defined(WIN32) || defined(__MINGW32__)
|
||||||
#include <stdio.h>
|
|
||||||
|
#include "backtrace.h"
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#ifndef __MINGW32__
|
#ifndef __MINGW32__
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "spice_common.h"
|
|
||||||
|
|
||||||
#define GSTACK_PATH "/usr/bin/gstack"
|
#define GSTACK_PATH "/usr/bin/gstack"
|
||||||
|
|
||||||
#if HAVE_EXECINFO_H
|
#if HAVE_EXECINFO_H
|
||||||
@ -75,7 +77,6 @@ static int spice_backtrace_gstack(void)
|
|||||||
/* CHILD */
|
/* CHILD */
|
||||||
char parent[16];
|
char parent[16];
|
||||||
|
|
||||||
seteuid(0);
|
|
||||||
close(STDIN_FILENO);
|
close(STDIN_FILENO);
|
||||||
close(STDOUT_FILENO);
|
close(STDOUT_FILENO);
|
||||||
dup2(pipefd[1],STDOUT_FILENO);
|
dup2(pipefd[1],STDOUT_FILENO);
|
||||||
@ -131,3 +132,4 @@ void spice_backtrace(void)
|
|||||||
spice_backtrace_backtrace();
|
spice_backtrace_backtrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|||||||
@ -16,8 +16,8 @@
|
|||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef BACKTRACE_H
|
#ifndef H_SPICE_COMMON_BACKTRACE
|
||||||
#define BACKTRACE_H
|
#define H_SPICE_COMMON_BACKTRACE
|
||||||
|
|
||||||
#include <spice/macros.h>
|
#include <spice/macros.h>
|
||||||
|
|
||||||
@ -31,4 +31,4 @@ void spice_backtrace(void);
|
|||||||
|
|
||||||
SPICE_END_DECLS
|
SPICE_END_DECLS
|
||||||
|
|
||||||
#endif // BACKTRACE_H
|
#endif // H_SPICE_COMMON_BACKTRACE
|
||||||
|
|||||||
@ -1,91 +0,0 @@
|
|||||||
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
||||||
/*
|
|
||||||
Copyright (C) 2009 Red Hat, Inc.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
|
|
||||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef BITOPS_H
|
|
||||||
#define BITOPS_H
|
|
||||||
|
|
||||||
#include <spice/macros.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
|
|
||||||
static inline int spice_bit_find_msb(unsigned int val)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
asm ("bsrl %1,%0\n\t"
|
|
||||||
"jnz 1f\n\t"
|
|
||||||
"movl $-1,%0\n"
|
|
||||||
"1:"
|
|
||||||
: "=r"(ret) : "r"(val));
|
|
||||||
return ret + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#elif defined(WIN32) && !defined(_WIN64)
|
|
||||||
static INLINE int spice_bit_find_msb(uint32_t val)
|
|
||||||
{
|
|
||||||
uint32_t r;
|
|
||||||
__asm {
|
|
||||||
bsr eax, val
|
|
||||||
jnz found
|
|
||||||
mov eax, -1
|
|
||||||
|
|
||||||
found:
|
|
||||||
mov r, eax
|
|
||||||
}
|
|
||||||
return r + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
static INLINE int spice_bit_find_msb(unsigned int val)
|
|
||||||
{
|
|
||||||
signed char index = 31;
|
|
||||||
|
|
||||||
if(val == 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
|
||||||
if(val & 0x80000000) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
val <<= 1;
|
|
||||||
} while(--index >= 0);
|
|
||||||
|
|
||||||
return index+1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static INLINE int spice_bit_next_pow2(unsigned int val)
|
|
||||||
{
|
|
||||||
if ((val & (val - 1)) == 0) {
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
return 1 << spice_bit_find_msb(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
1114
common/canvas_base.c
1114
common/canvas_base.c
File diff suppressed because it is too large
Load Diff
@ -16,24 +16,17 @@
|
|||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _H_CANVAS_BASE
|
#ifndef H_SPICE_COMMON_CANVAS_BASE
|
||||||
#define _H_CANVAS_BASE
|
#define H_SPICE_COMMON_CANVAS_BASE
|
||||||
|
|
||||||
#ifndef SPICE_CANVAS_INTERNAL
|
#include <spice/macros.h>
|
||||||
#error "This header shouldn't be included directly"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "pixman_utils.h"
|
#include "pixman_utils.h"
|
||||||
#include "lz.h"
|
#include "lz.h"
|
||||||
#include "region.h"
|
#include "region.h"
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
#ifdef WIN32
|
|
||||||
#include <windows.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
SPICE_BEGIN_DECLS
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef void (*spice_destroy_fn_t)(void *data);
|
typedef void (*spice_destroy_fn_t)(void *data);
|
||||||
|
|
||||||
@ -64,7 +57,7 @@ typedef struct {
|
|||||||
} SpiceImageCacheOps;
|
} SpiceImageCacheOps;
|
||||||
|
|
||||||
struct _SpiceImageCache {
|
struct _SpiceImageCache {
|
||||||
SpiceImageCacheOps *ops;
|
const SpiceImageCacheOps *ops;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -73,7 +66,7 @@ typedef struct {
|
|||||||
} SpiceImageSurfacesOps;
|
} SpiceImageSurfacesOps;
|
||||||
|
|
||||||
struct _SpiceImageSurfaces {
|
struct _SpiceImageSurfaces {
|
||||||
SpiceImageSurfacesOps *ops;
|
const SpiceImageSurfacesOps *ops;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -137,6 +130,7 @@ typedef struct {
|
|||||||
void (*draw_text)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceText *text);
|
void (*draw_text)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceText *text);
|
||||||
void (*draw_stroke)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceStroke *stroke);
|
void (*draw_stroke)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceStroke *stroke);
|
||||||
void (*draw_rop3)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceRop3 *rop3);
|
void (*draw_rop3)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceRop3 *rop3);
|
||||||
|
void (*draw_composite)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceComposite *composite);
|
||||||
void (*draw_blend)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceBlend *blend);
|
void (*draw_blend)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceBlend *blend);
|
||||||
void (*draw_blackness)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceBlackness *blackness);
|
void (*draw_blackness)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceBlackness *blackness);
|
||||||
void (*draw_whiteness)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceWhiteness *whiteness);
|
void (*draw_whiteness)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceWhiteness *whiteness);
|
||||||
@ -144,9 +138,6 @@ typedef struct {
|
|||||||
void (*draw_transparent)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceTransparent* transparent);
|
void (*draw_transparent)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceTransparent* transparent);
|
||||||
void (*draw_alpha_blend)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceAlphaBlend* alpha_blend);
|
void (*draw_alpha_blend)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceAlphaBlend* alpha_blend);
|
||||||
void (*put_image)(SpiceCanvas *canvas,
|
void (*put_image)(SpiceCanvas *canvas,
|
||||||
#ifdef WIN32
|
|
||||||
HDC dc,
|
|
||||||
#endif
|
|
||||||
const SpiceRect *dest, const uint8_t *src_data,
|
const SpiceRect *dest, const uint8_t *src_data,
|
||||||
uint32_t src_width, uint32_t src_height, int src_stride,
|
uint32_t src_width, uint32_t src_height, int src_stride,
|
||||||
const QRegion *clip);
|
const QRegion *clip);
|
||||||
@ -310,18 +301,13 @@ typedef struct {
|
|||||||
void (*copy_region)(SpiceCanvas *canvas,
|
void (*copy_region)(SpiceCanvas *canvas,
|
||||||
pixman_region32_t *dest_region,
|
pixman_region32_t *dest_region,
|
||||||
int dx, int dy);
|
int dx, int dy);
|
||||||
pixman_image_t *(*get_image)(SpiceCanvas *canvas);
|
pixman_image_t *(*get_image)(SpiceCanvas *canvas, int force_opaque);
|
||||||
} SpiceCanvasOps;
|
} SpiceCanvasOps;
|
||||||
|
|
||||||
void spice_canvas_set_usr_data(SpiceCanvas *canvas, void *data, spice_destroy_fn_t destroy_fn);
|
|
||||||
void *spice_canvas_get_usr_data(SpiceCanvas *canvas);
|
|
||||||
|
|
||||||
struct _SpiceCanvas {
|
struct _SpiceCanvas {
|
||||||
SpiceCanvasOps *ops;
|
SpiceCanvasOps *ops;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef __cplusplus
|
SPICE_END_DECLS
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -15,42 +15,21 @@
|
|||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "canvas_utils.h"
|
#include "canvas_utils.h"
|
||||||
|
|
||||||
#include <spice/macros.h>
|
|
||||||
|
|
||||||
#ifdef __GNUC__
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#endif
|
|
||||||
#include "mem.h"
|
#include "mem.h"
|
||||||
|
|
||||||
#ifdef WIN32
|
typedef struct PixmanData {
|
||||||
static int gdi_handlers = 0;
|
uint8_t *data;
|
||||||
#endif
|
pixman_format_code_t format;
|
||||||
|
} PixmanData;
|
||||||
|
|
||||||
#ifndef CANVAS_ERROR
|
static void release_data(SPICE_GNUC_UNUSED pixman_image_t *image,
|
||||||
#define CANVAS_ERROR(format, ...) { \
|
void *release_data)
|
||||||
printf("%s: " format "\n", __FUNCTION__, ## __VA_ARGS__); \
|
|
||||||
abort(); \
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void release_data(pixman_image_t *image, void *release_data)
|
|
||||||
{
|
{
|
||||||
PixmanData *data = (PixmanData *)release_data;
|
PixmanData *data = (PixmanData *)release_data;
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
if (data->bitmap) {
|
|
||||||
DeleteObject((HBITMAP)data->bitmap);
|
|
||||||
CloseHandle(data->mutex);
|
|
||||||
gdi_handlers--;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
free(data->data);
|
free(data->data);
|
||||||
|
|
||||||
free(data);
|
free(data);
|
||||||
@ -65,7 +44,7 @@ pixman_image_add_data(pixman_image_t *image)
|
|||||||
if (data == NULL) {
|
if (data == NULL) {
|
||||||
data = (PixmanData *)calloc(1, sizeof(PixmanData));
|
data = (PixmanData *)calloc(1, sizeof(PixmanData));
|
||||||
if (data == NULL) {
|
if (data == NULL) {
|
||||||
CANVAS_ERROR("out of memory");
|
spice_error("out of memory");
|
||||||
}
|
}
|
||||||
pixman_image_set_destroy_function(image,
|
pixman_image_set_destroy_function(image,
|
||||||
release_data,
|
release_data,
|
||||||
@ -85,20 +64,24 @@ spice_pixman_image_set_format(pixman_image_t *image,
|
|||||||
data->format = format;
|
data->format = format;
|
||||||
}
|
}
|
||||||
|
|
||||||
pixman_format_code_t
|
|
||||||
spice_pixman_image_get_format(pixman_image_t *image)
|
int spice_pixman_image_get_format(pixman_image_t *image, pixman_format_code_t *format)
|
||||||
{
|
{
|
||||||
PixmanData *data;
|
PixmanData *data;
|
||||||
|
|
||||||
data = (PixmanData *)pixman_image_get_destroy_data(image);
|
spice_return_val_if_fail(format != NULL, 0);
|
||||||
if (data != NULL &&
|
|
||||||
data->format != 0)
|
|
||||||
return data->format;
|
|
||||||
|
|
||||||
CANVAS_ERROR("Unknown pixman image type");
|
data = (PixmanData *)pixman_image_get_destroy_data(image);
|
||||||
|
if (data != NULL && data->format != 0) {
|
||||||
|
*format = data->format;
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static INLINE pixman_image_t *__surface_create_stride(pixman_format_code_t format, int width, int height,
|
spice_warn_if_reached();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pixman_image_t *surface_create_stride(pixman_format_code_t format, int width, int height,
|
||||||
int stride)
|
int stride)
|
||||||
{
|
{
|
||||||
uint8_t *data;
|
uint8_t *data;
|
||||||
@ -117,7 +100,8 @@ static INLINE pixman_image_t *__surface_create_stride(pixman_format_code_t forma
|
|||||||
|
|
||||||
if (surface == NULL) {
|
if (surface == NULL) {
|
||||||
free(data);
|
free(data);
|
||||||
CANVAS_ERROR("create surface failed, out of memory");
|
data = NULL;
|
||||||
|
spice_error("create surface failed, out of memory");
|
||||||
}
|
}
|
||||||
|
|
||||||
pixman_data = pixman_image_add_data(surface);
|
pixman_data = pixman_image_add_data(surface);
|
||||||
@ -127,98 +111,8 @@ static INLINE pixman_image_t *__surface_create_stride(pixman_format_code_t forma
|
|||||||
return surface;
|
return surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
pixman_image_t *surface_create(HDC dc, pixman_format_code_t format,
|
|
||||||
int width, int height, int top_down)
|
|
||||||
#else
|
|
||||||
pixman_image_t * surface_create(pixman_format_code_t format, int width, int height, int top_down)
|
pixman_image_t * surface_create(pixman_format_code_t format, int width, int height, int top_down)
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
#ifdef WIN32
|
|
||||||
/*
|
|
||||||
* Windows xp allow only 10,000 of gdi handlers, considering the fact that
|
|
||||||
* we limit here the number to 5000, we dont use atomic operations to sync
|
|
||||||
* this calculation against the other canvases (in case of multiple
|
|
||||||
* monitors), in worst case there will be little more than 5000 gdi
|
|
||||||
* handlers.
|
|
||||||
*/
|
|
||||||
if (dc && gdi_handlers < 5000) {
|
|
||||||
uint8_t *data;
|
|
||||||
uint8_t *src;
|
|
||||||
struct {
|
|
||||||
BITMAPINFO inf;
|
|
||||||
RGBQUAD palette[255];
|
|
||||||
} bitmap_info;
|
|
||||||
int nstride;
|
|
||||||
pixman_image_t *surface;
|
|
||||||
PixmanData *pixman_data;
|
|
||||||
HBITMAP bitmap;
|
|
||||||
HANDLE mutex;
|
|
||||||
|
|
||||||
memset(&bitmap_info, 0, sizeof(bitmap_info));
|
|
||||||
bitmap_info.inf.bmiHeader.biSize = sizeof(bitmap_info.inf.bmiHeader);
|
|
||||||
bitmap_info.inf.bmiHeader.biWidth = width;
|
|
||||||
|
|
||||||
bitmap_info.inf.bmiHeader.biHeight = (!top_down) ? height : -height;
|
|
||||||
|
|
||||||
bitmap_info.inf.bmiHeader.biPlanes = 1;
|
|
||||||
switch (format) {
|
|
||||||
case PIXMAN_a8r8g8b8:
|
|
||||||
case PIXMAN_x8r8g8b8:
|
|
||||||
bitmap_info.inf.bmiHeader.biBitCount = 32;
|
|
||||||
nstride = width * 4;
|
|
||||||
break;
|
|
||||||
case PIXMAN_x1r5g5b5:
|
|
||||||
case PIXMAN_r5g6b5:
|
|
||||||
bitmap_info.inf.bmiHeader.biBitCount = 16;
|
|
||||||
nstride = SPICE_ALIGN(width * 2, 4);
|
|
||||||
break;
|
|
||||||
case PIXMAN_a8:
|
|
||||||
bitmap_info.inf.bmiHeader.biBitCount = 8;
|
|
||||||
nstride = SPICE_ALIGN(width, 4);
|
|
||||||
break;
|
|
||||||
case PIXMAN_a1:
|
|
||||||
bitmap_info.inf.bmiHeader.biBitCount = 1;
|
|
||||||
nstride = SPICE_ALIGN(width, 32) / 8;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
CANVAS_ERROR("invalid format");
|
|
||||||
}
|
|
||||||
|
|
||||||
bitmap_info.inf.bmiHeader.biCompression = BI_RGB;
|
|
||||||
|
|
||||||
mutex = CreateMutex(NULL, 0, NULL);
|
|
||||||
if (!mutex) {
|
|
||||||
CANVAS_ERROR("Unable to CreateMutex");
|
|
||||||
}
|
|
||||||
|
|
||||||
bitmap = CreateDIBSection(dc, &bitmap_info.inf, 0, (VOID **)&data, NULL, 0);
|
|
||||||
if (!bitmap) {
|
|
||||||
CloseHandle(mutex);
|
|
||||||
CANVAS_ERROR("Unable to CreateDIBSection");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (top_down) {
|
|
||||||
src = data;
|
|
||||||
} else {
|
|
||||||
src = data + nstride * (height - 1);
|
|
||||||
nstride = -nstride;
|
|
||||||
}
|
|
||||||
|
|
||||||
surface = pixman_image_create_bits(format, width, height, (uint32_t *)src, nstride);
|
|
||||||
if (surface == NULL) {
|
|
||||||
CloseHandle(mutex);
|
|
||||||
DeleteObject(bitmap);
|
|
||||||
CANVAS_ERROR("create surface failed, out of memory");
|
|
||||||
}
|
|
||||||
pixman_data = pixman_image_add_data(surface);
|
|
||||||
pixman_data->format = format;
|
|
||||||
pixman_data->bitmap = bitmap;
|
|
||||||
pixman_data->mutex = mutex;
|
|
||||||
gdi_handlers++;
|
|
||||||
return surface;
|
|
||||||
} else {
|
|
||||||
#endif
|
|
||||||
if (top_down) {
|
if (top_down) {
|
||||||
pixman_image_t *surface;
|
pixman_image_t *surface;
|
||||||
PixmanData *data;
|
PixmanData *data;
|
||||||
@ -233,8 +127,19 @@ pixman_image_t * surface_create(pixman_format_code_t format, int width, int heig
|
|||||||
switch (format) {
|
switch (format) {
|
||||||
case PIXMAN_a8r8g8b8:
|
case PIXMAN_a8r8g8b8:
|
||||||
case PIXMAN_x8r8g8b8:
|
case PIXMAN_x8r8g8b8:
|
||||||
|
#ifdef WORDS_BIGENDIAN
|
||||||
|
case PIXMAN_b8g8r8a8:
|
||||||
|
case PIXMAN_b8g8r8x8:
|
||||||
|
#endif
|
||||||
stride = width * 4;
|
stride = width * 4;
|
||||||
break;
|
break;
|
||||||
|
case PIXMAN_r8g8b8:
|
||||||
|
#ifdef WORDS_BIGENDIAN
|
||||||
|
case PIXMAN_b8g8r8:
|
||||||
|
#endif
|
||||||
|
// NOTE: LZ4 also decodes to RGB24
|
||||||
|
stride = SPICE_ALIGN(width * 3, 4);
|
||||||
|
break;
|
||||||
case PIXMAN_x1r5g5b5:
|
case PIXMAN_x1r5g5b5:
|
||||||
case PIXMAN_r5g6b5:
|
case PIXMAN_r5g6b5:
|
||||||
stride = SPICE_ALIGN(width * 2, 4);
|
stride = SPICE_ALIGN(width * 2, 4);
|
||||||
@ -246,34 +151,11 @@ pixman_image_t * surface_create(pixman_format_code_t format, int width, int heig
|
|||||||
stride = SPICE_ALIGN(width, 32) / 8;
|
stride = SPICE_ALIGN(width, 32) / 8;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
CANVAS_ERROR("invalid format");
|
spice_error("invalid format");
|
||||||
}
|
}
|
||||||
stride = -stride;
|
stride = -stride;
|
||||||
return __surface_create_stride(format, width, height, stride);
|
return surface_create_stride(format, width, height, stride);
|
||||||
}
|
}
|
||||||
#ifdef WIN32
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
pixman_image_t *surface_create_stride(HDC dc, pixman_format_code_t format, int width, int height,
|
|
||||||
int stride)
|
|
||||||
#else
|
|
||||||
pixman_image_t *surface_create_stride(pixman_format_code_t format, int width, int height,
|
|
||||||
int stride)
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
#ifdef WIN32
|
|
||||||
if (dc) {
|
|
||||||
if (abs(stride) == (width * 4)) {
|
|
||||||
return surface_create(dc, format, width, height, (stride > 0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return __surface_create_stride(format, width, height, stride);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pixman_image_t *alloc_lz_image_surface(LzDecodeUsrData *canvas_data,
|
pixman_image_t *alloc_lz_image_surface(LzDecodeUsrData *canvas_data,
|
||||||
@ -285,15 +167,14 @@ pixman_image_t *alloc_lz_image_surface(LzDecodeUsrData *canvas_data,
|
|||||||
|
|
||||||
stride = (gross_pixels / height) * (PIXMAN_FORMAT_BPP (pixman_format) / 8);
|
stride = (gross_pixels / height) * (PIXMAN_FORMAT_BPP (pixman_format) / 8);
|
||||||
|
|
||||||
|
/* pixman requires strides to be 4-byte aligned */
|
||||||
|
stride = SPICE_ALIGN(stride, 4);
|
||||||
|
|
||||||
if (!top_down) {
|
if (!top_down) {
|
||||||
stride = -stride;
|
stride = -stride;
|
||||||
}
|
}
|
||||||
|
|
||||||
surface = surface_create_stride(
|
surface = surface_create_stride(pixman_format, width, height, stride);
|
||||||
#ifdef WIN32
|
|
||||||
canvas_data->dc,
|
|
||||||
#endif
|
|
||||||
pixman_format, width, height, stride);
|
|
||||||
canvas_data->out_surface = surface;
|
canvas_data->out_surface = surface;
|
||||||
return surface;
|
return surface;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,56 +16,29 @@
|
|||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _H_CANVAS_UTILS
|
#ifndef H_SPICE_COMMON_CANVAS_UTILS
|
||||||
#define _H_CANVAS_UTILS
|
#define H_SPICE_COMMON_CANVAS_UTILS
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
#include <windows.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <spice/types.h>
|
#include <spice/types.h>
|
||||||
|
#include <spice/macros.h>
|
||||||
|
|
||||||
#include "pixman_utils.h"
|
#include "pixman_utils.h"
|
||||||
#include "lz.h"
|
#include "lz.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
SPICE_BEGIN_DECLS
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct PixmanData {
|
|
||||||
#ifdef WIN32
|
|
||||||
HBITMAP bitmap;
|
|
||||||
HANDLE mutex;
|
|
||||||
#endif
|
|
||||||
uint8_t *data;
|
|
||||||
pixman_format_code_t format;
|
|
||||||
} PixmanData;
|
|
||||||
|
|
||||||
void spice_pixman_image_set_format(pixman_image_t *image,
|
void spice_pixman_image_set_format(pixman_image_t *image,
|
||||||
pixman_format_code_t format);
|
pixman_format_code_t format);
|
||||||
pixman_format_code_t spice_pixman_image_get_format(pixman_image_t *image);
|
int spice_pixman_image_get_format(pixman_image_t *image, pixman_format_code_t *format);
|
||||||
|
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
pixman_image_t *surface_create(HDC dc, pixman_format_code_t format,
|
|
||||||
int width, int height, int top_down);
|
|
||||||
#else
|
|
||||||
pixman_image_t *surface_create(pixman_format_code_t format, int width, int height, int top_down);
|
pixman_image_t *surface_create(pixman_format_code_t format, int width, int height, int top_down);
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
pixman_image_t *surface_create_stride(HDC dc, pixman_format_code_t format, int width, int height,
|
|
||||||
int stride);
|
|
||||||
#else
|
|
||||||
pixman_image_t *surface_create_stride(pixman_format_code_t format, int width, int height,
|
pixman_image_t *surface_create_stride(pixman_format_code_t format, int width, int height,
|
||||||
int stride);
|
int stride);
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct LzDecodeUsrData {
|
typedef struct LzDecodeUsrData {
|
||||||
#ifdef WIN32
|
|
||||||
HDC dc;
|
|
||||||
#endif
|
|
||||||
pixman_image_t *out_surface;
|
pixman_image_t *out_surface;
|
||||||
} LzDecodeUsrData;
|
} LzDecodeUsrData;
|
||||||
|
|
||||||
@ -73,8 +46,7 @@ typedef struct LzDecodeUsrData {
|
|||||||
pixman_image_t *alloc_lz_image_surface(LzDecodeUsrData *canvas_data,
|
pixman_image_t *alloc_lz_image_surface(LzDecodeUsrData *canvas_data,
|
||||||
pixman_format_code_t pixman_format, int width,
|
pixman_format_code_t pixman_format, int width,
|
||||||
int height, int gross_pixels, int top_down);
|
int height, int gross_pixels, int top_down);
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
SPICE_END_DECLS
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2009 Red Hat, Inc.
|
Copyright (C) 2010 Red Hat, Inc.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
@ -16,23 +16,19 @@
|
|||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _H_GLCTX
|
#ifndef H_SPICE_COMMON_CLIENT_MARSHALLERS
|
||||||
#define _H_GLCTX
|
#define H_SPICE_COMMON_CLIENT_MARSHALLERS
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#include <spice/protocol.h>
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct OGLCtx OGLCtx;
|
#include "messages.h"
|
||||||
|
#include "common/generated_client_marshallers.h"
|
||||||
|
#include "marshaller.h"
|
||||||
|
|
||||||
const char *oglctx_type_str(OGLCtx *ctx);
|
SPICE_BEGIN_DECLS
|
||||||
void oglctx_make_current(OGLCtx *ctx);
|
|
||||||
OGLCtx *pbuf_create(int width, int heigth);
|
|
||||||
OGLCtx *pixmap_create(int width, int heigth);
|
|
||||||
void oglctx_destroy(OGLCtx *ctx);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
SpiceMessageMarshallers *spice_message_marshallers_get(void);
|
||||||
}
|
|
||||||
#endif
|
SPICE_END_DECLS
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
38
common/demarshallers.h
Normal file
38
common/demarshallers.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
Copyright (C) 2010 Red Hat, Inc.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#ifndef H_SPICE_COMMON_DEMARSHALLERS
|
||||||
|
#define H_SPICE_COMMON_DEMARSHALLERS
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <spice/macros.h>
|
||||||
|
|
||||||
|
SPICE_BEGIN_DECLS
|
||||||
|
|
||||||
|
typedef void (*message_destructor_t)(uint8_t *message);
|
||||||
|
typedef uint8_t * (*spice_parse_channel_func_t)(uint8_t *message_start, uint8_t *message_end,
|
||||||
|
uint16_t message_type, int minor,
|
||||||
|
size_t *size_out,
|
||||||
|
message_destructor_t *free_message);
|
||||||
|
|
||||||
|
spice_parse_channel_func_t
|
||||||
|
spice_get_server_channel_parser(uint32_t channel, unsigned int *max_message_type);
|
||||||
|
spice_parse_channel_func_t
|
||||||
|
spice_get_client_channel_parser(uint32_t channel, unsigned int *max_message_type);
|
||||||
|
|
||||||
|
SPICE_END_DECLS
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -28,16 +28,15 @@
|
|||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _H_SPICE_DRAW
|
#ifndef H_SPICE_COMMON_DRAW
|
||||||
#define _H_SPICE_DRAW
|
#define H_SPICE_COMMON_DRAW
|
||||||
|
|
||||||
|
#include <spice/macros.h>
|
||||||
#include <spice/types.h>
|
#include <spice/types.h>
|
||||||
#include <spice/enums.h>
|
#include <spice/enums.h>
|
||||||
#include "mem.h"
|
#include "mem.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
SPICE_BEGIN_DECLS
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define SPICE_GET_ADDRESS(addr) ((void *)(uintptr_t)(addr))
|
#define SPICE_GET_ADDRESS(addr) ((void *)(uintptr_t)(addr))
|
||||||
#define SPICE_SET_ADDRESS(addr, val) ((addr) = (uintptr_t)(val))
|
#define SPICE_SET_ADDRESS(addr, val) ((addr) = (uintptr_t)(val))
|
||||||
@ -83,7 +82,7 @@ typedef struct SpiceClipRects {
|
|||||||
} SpiceClipRects;
|
} SpiceClipRects;
|
||||||
|
|
||||||
typedef struct SpiceClip {
|
typedef struct SpiceClip {
|
||||||
uint32_t type;
|
uint8_t type;
|
||||||
SpiceClipRects *rects;
|
SpiceClipRects *rects;
|
||||||
} SpiceClip;
|
} SpiceClip;
|
||||||
|
|
||||||
@ -121,7 +120,7 @@ typedef struct SpiceSurface {
|
|||||||
typedef struct SpiceQUICData {
|
typedef struct SpiceQUICData {
|
||||||
uint32_t data_size;
|
uint32_t data_size;
|
||||||
SpiceChunks *data;
|
SpiceChunks *data;
|
||||||
} SpiceQUICData, SpiceLZRGBData, SpiceJPEGData;
|
} SpiceQUICData, SpiceLZRGBData, SpiceJPEGData, SpiceLZ4Data;
|
||||||
|
|
||||||
typedef struct SpiceLZPLTData {
|
typedef struct SpiceLZPLTData {
|
||||||
uint8_t flags;
|
uint8_t flags;
|
||||||
@ -154,6 +153,7 @@ typedef struct SpiceImage {
|
|||||||
SpiceLZRGBData lz_rgb;
|
SpiceLZRGBData lz_rgb;
|
||||||
SpiceLZPLTData lz_plt;
|
SpiceLZPLTData lz_plt;
|
||||||
SpiceJPEGData jpeg;
|
SpiceJPEGData jpeg;
|
||||||
|
SpiceLZ4Data lz4;
|
||||||
SpiceZlibGlzRGBData zlib_glz;
|
SpiceZlibGlzRGBData zlib_glz;
|
||||||
SpiceJPEGAlphaData jpeg_alpha;
|
SpiceJPEGAlphaData jpeg_alpha;
|
||||||
} u;
|
} u;
|
||||||
@ -224,6 +224,26 @@ typedef struct SpiceRop3 {
|
|||||||
SpiceQMask mask;
|
SpiceQMask mask;
|
||||||
} SpiceRop3;
|
} SpiceRop3;
|
||||||
|
|
||||||
|
/* Given in 16.16 fixed point */
|
||||||
|
typedef struct SpiceTransform {
|
||||||
|
uint32_t t00;
|
||||||
|
uint32_t t01;
|
||||||
|
uint32_t t02;
|
||||||
|
uint32_t t10;
|
||||||
|
uint32_t t11;
|
||||||
|
uint32_t t12;
|
||||||
|
} SpiceTransform;
|
||||||
|
|
||||||
|
typedef struct SpiceComposite {
|
||||||
|
uint32_t flags;
|
||||||
|
SpiceImage *src_bitmap;
|
||||||
|
SpiceImage *mask_bitmap;
|
||||||
|
SpiceTransform src_transform;
|
||||||
|
SpiceTransform mask_transform;
|
||||||
|
SpicePoint16 src_origin;
|
||||||
|
SpicePoint16 mask_origin;
|
||||||
|
} SpiceComposite;
|
||||||
|
|
||||||
typedef struct SpiceBlackness {
|
typedef struct SpiceBlackness {
|
||||||
SpiceQMask mask;
|
SpiceQMask mask;
|
||||||
} SpiceBlackness, SpiceInvers, SpiceWhiteness;
|
} SpiceBlackness, SpiceInvers, SpiceWhiteness;
|
||||||
@ -274,8 +294,12 @@ typedef struct SpiceCursorHeader {
|
|||||||
uint16_t hot_spot_y;
|
uint16_t hot_spot_y;
|
||||||
} SpiceCursorHeader;
|
} SpiceCursorHeader;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
static inline int spice_image_descriptor_is_lossy(const SpiceImageDescriptor *descriptor)
|
||||||
|
{
|
||||||
|
return descriptor->type == SPICE_IMAGE_TYPE_JPEG ||
|
||||||
|
descriptor->type == SPICE_IMAGE_TYPE_JPEG_ALPHA;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* _H_SPICE_DRAW */
|
SPICE_END_DECLS
|
||||||
|
|
||||||
|
#endif // H_SPICE_COMMON_DRAW
|
||||||
|
|||||||
1858
common/gdi_canvas.c
1858
common/gdi_canvas.c
File diff suppressed because it is too large
Load Diff
@ -1,51 +0,0 @@
|
|||||||
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
||||||
/*
|
|
||||||
Copyright (C) 2009 Red Hat, Inc.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _H__GDI_CANVAS
|
|
||||||
#define _H__GDI_CANVAS
|
|
||||||
|
|
||||||
#ifndef SPICE_CANVAS_INTERNAL
|
|
||||||
#error "This header shouldn't be included directly"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "pixman_utils.h"
|
|
||||||
#include "canvas_base.h"
|
|
||||||
#include "region.h"
|
|
||||||
|
|
||||||
SpiceCanvas *gdi_canvas_create(int width, int height,
|
|
||||||
HDC dc, class RecurciveMutex *lock, uint32_t format,
|
|
||||||
SpiceImageCache *bits_cache,
|
|
||||||
SpicePaletteCache *palette_cache,
|
|
||||||
SpiceImageSurfaces *surfaces,
|
|
||||||
SpiceGlzDecoder *glz_decoder,
|
|
||||||
SpiceJpegDecoder *jpeg_decoder,
|
|
||||||
SpiceZlibDecoder *zlib_decoder);
|
|
||||||
|
|
||||||
void gdi_canvas_init(void);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1,906 +0,0 @@
|
|||||||
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
||||||
/*
|
|
||||||
Copyright (C) 2009 Red Hat, Inc.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include <config.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef SPICE_CANVAS_INTERNAL
|
|
||||||
#error "This file shouldn't be compiled directly"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "quic.h"
|
|
||||||
#include "rop3.h"
|
|
||||||
#include "region.h"
|
|
||||||
|
|
||||||
#define GL_CANVAS
|
|
||||||
#include "canvas_base.c"
|
|
||||||
|
|
||||||
typedef struct GLCanvas GLCanvas;
|
|
||||||
|
|
||||||
struct GLCanvas {
|
|
||||||
CanvasBase base;
|
|
||||||
GLCCtx glc;
|
|
||||||
void *private_data;
|
|
||||||
int private_data_size;
|
|
||||||
int textures_lost;
|
|
||||||
};
|
|
||||||
|
|
||||||
static inline uint8_t *copy_opposite_image(GLCanvas *canvas, void *data, int stride, int height)
|
|
||||||
{
|
|
||||||
uint8_t *ret_data = (uint8_t *)data;
|
|
||||||
uint8_t *dest;
|
|
||||||
uint8_t *src;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (!canvas->private_data) {
|
|
||||||
canvas->private_data = spice_malloc_n(height, stride);
|
|
||||||
if (!canvas->private_data) {
|
|
||||||
return ret_data;
|
|
||||||
}
|
|
||||||
canvas->private_data_size = stride * height;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (canvas->private_data_size < (stride * height)) {
|
|
||||||
free(canvas->private_data);
|
|
||||||
canvas->private_data = spice_malloc_n(height, stride);
|
|
||||||
if (!canvas->private_data) {
|
|
||||||
return ret_data;
|
|
||||||
}
|
|
||||||
canvas->private_data_size = stride * height;
|
|
||||||
}
|
|
||||||
|
|
||||||
dest = (uint8_t *)canvas->private_data;
|
|
||||||
src = (uint8_t *)data + (height - 1) * stride;
|
|
||||||
|
|
||||||
for (i = 0; i < height; ++i) {
|
|
||||||
memcpy(dest, src, stride);
|
|
||||||
dest += stride;
|
|
||||||
src -= stride;
|
|
||||||
}
|
|
||||||
return (uint8_t *)canvas->private_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
static pixman_image_t *canvas_surf_to_trans_surf(GLCImage *image,
|
|
||||||
uint32_t trans_color)
|
|
||||||
{
|
|
||||||
int width = image->width;
|
|
||||||
int height = image->height;
|
|
||||||
uint8_t *src_line;
|
|
||||||
uint8_t *end_src_line;
|
|
||||||
int src_stride;
|
|
||||||
uint8_t *dest_line;
|
|
||||||
int dest_stride;
|
|
||||||
pixman_image_t *ret;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
ret = pixman_image_create_bits(PIXMAN_a8r8g8b8, width, height, NULL, 0);
|
|
||||||
if (ret == NULL) {
|
|
||||||
CANVAS_ERROR("create surface failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
src_line = image->pixels;
|
|
||||||
src_stride = image->stride;
|
|
||||||
end_src_line = src_line + src_stride * height;
|
|
||||||
|
|
||||||
dest_line = (uint8_t *)pixman_image_get_data(ret);
|
|
||||||
dest_stride = pixman_image_get_stride(ret);
|
|
||||||
|
|
||||||
for (; src_line < end_src_line; src_line += src_stride, dest_line += dest_stride) {
|
|
||||||
for (i = 0; i < width; i++) {
|
|
||||||
if ((((uint32_t*)src_line)[i] & 0x00ffffff) == trans_color) {
|
|
||||||
((uint32_t*)dest_line)[i] = 0;
|
|
||||||
} else {
|
|
||||||
((uint32_t*)dest_line)[i] = (((uint32_t*)src_line)[i]) | 0xff000000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static GLCPath get_path(GLCanvas *canvas, SpicePath *s)
|
|
||||||
{
|
|
||||||
GLCPath path = glc_path_create(canvas->glc);
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < s->num_segments; i++) {
|
|
||||||
SpicePathSeg* seg = s->segments[i];
|
|
||||||
SpicePointFix* point = seg->points;
|
|
||||||
SpicePointFix* end_point = point + seg->count;
|
|
||||||
|
|
||||||
if (seg->flags & SPICE_PATH_BEGIN) {
|
|
||||||
glc_path_move_to(path, fix_to_double(point->x), fix_to_double(point->y));
|
|
||||||
point++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (seg->flags & SPICE_PATH_BEZIER) {
|
|
||||||
ASSERT((point - end_point) % 3 == 0);
|
|
||||||
for (; point + 2 < end_point; point += 3) {
|
|
||||||
glc_path_curve_to(path,
|
|
||||||
fix_to_double(point[0].x), fix_to_double(point[0].y),
|
|
||||||
fix_to_double(point[1].x), fix_to_double(point[1].y),
|
|
||||||
fix_to_double(point[2].x), fix_to_double(point[2].y));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (; point < end_point; point++) {
|
|
||||||
glc_path_line_to(path, fix_to_double(point->x), fix_to_double(point->y));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (seg->flags & SPICE_PATH_END) {
|
|
||||||
if (seg->flags & SPICE_PATH_CLOSE) {
|
|
||||||
glc_path_close(path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define SET_GLC_RECT(dest, src) { \
|
|
||||||
(dest)->x = (src)->left; \
|
|
||||||
(dest)->y = (src)->top; \
|
|
||||||
(dest)->width = (src)->right - (src)->left; \
|
|
||||||
(dest)->height = (src)->bottom - (src)->top; \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define SET_GLC_BOX(dest, src) { \
|
|
||||||
(dest)->x = (src)->x1; \
|
|
||||||
(dest)->y = (src)->y1; \
|
|
||||||
(dest)->width = (src)->x2 - (src)->x1; \
|
|
||||||
(dest)->height = (src)->y2 - (src)->y1; \
|
|
||||||
}
|
|
||||||
|
|
||||||
static void set_clip(GLCanvas *canvas, SpiceRect *bbox, SpiceClip *clip)
|
|
||||||
{
|
|
||||||
GLCRect rect;
|
|
||||||
glc_clip_reset(canvas->glc);
|
|
||||||
|
|
||||||
switch (clip->type) {
|
|
||||||
case SPICE_CLIP_TYPE_NONE:
|
|
||||||
break;
|
|
||||||
case SPICE_CLIP_TYPE_RECTS: {
|
|
||||||
uint32_t n = clip->rects->num_rects;
|
|
||||||
SpiceRect *now = clip->rects->rects;
|
|
||||||
SpiceRect *end = now + n;
|
|
||||||
|
|
||||||
if (n == 0) {
|
|
||||||
rect.x = rect.y = 0;
|
|
||||||
rect.width = rect.height = 0;
|
|
||||||
glc_clip_rect(canvas->glc, &rect, GLC_CLIP_OP_SET);
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
SET_GLC_RECT(&rect, now);
|
|
||||||
glc_clip_rect(canvas->glc, &rect, GLC_CLIP_OP_SET);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (now++; now < end; now++) {
|
|
||||||
SET_GLC_RECT(&rect, now);
|
|
||||||
glc_clip_rect(canvas->glc, &rect, GLC_CLIP_OP_OR);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
CANVAS_ERROR("invalid clip type");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void set_mask(GLCanvas *canvas, SpiceQMask *mask, int x, int y)
|
|
||||||
{
|
|
||||||
pixman_image_t *image;
|
|
||||||
|
|
||||||
if (!(image = canvas_get_mask(&canvas->base, mask, NULL))) {
|
|
||||||
glc_clear_mask(canvas->glc, GLC_MASK_A);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
glc_set_mask(canvas->glc, x - mask->pos.x, y - mask->pos.y,
|
|
||||||
pixman_image_get_width(image),
|
|
||||||
pixman_image_get_height(image),
|
|
||||||
pixman_image_get_stride(image),
|
|
||||||
(uint8_t *)pixman_image_get_data(image), GLC_MASK_A);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void surface_to_image(GLCanvas *canvas, pixman_image_t *surface, GLCImage *image,
|
|
||||||
int ignore_stride)
|
|
||||||
{
|
|
||||||
int depth = pixman_image_get_depth(surface);
|
|
||||||
|
|
||||||
ASSERT(depth == 32 || depth == 24);
|
|
||||||
image->format = (depth == 24) ? GLC_IMAGE_RGB32 : GLC_IMAGE_ARGB32;
|
|
||||||
image->width = pixman_image_get_width(surface);
|
|
||||||
image->height = pixman_image_get_height(surface);
|
|
||||||
image->stride = pixman_image_get_stride(surface);
|
|
||||||
image->pixels = (uint8_t *)pixman_image_get_data(surface);
|
|
||||||
image->pallet = NULL;
|
|
||||||
if (ignore_stride) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (image->stride < 0) {
|
|
||||||
image->stride = -image->stride;
|
|
||||||
image->pixels = image->pixels - (image->height - 1) * image->stride;
|
|
||||||
} else {
|
|
||||||
image->pixels = copy_opposite_image(canvas, image->pixels, image->stride, image->height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void set_brush(GLCanvas *canvas, SpiceBrush *brush)
|
|
||||||
{
|
|
||||||
switch (brush->type) {
|
|
||||||
case SPICE_BRUSH_TYPE_SOLID: {
|
|
||||||
uint32_t color = brush->u.color;
|
|
||||||
double r, g, b;
|
|
||||||
|
|
||||||
b = (double)(color & canvas->base.color_mask) / canvas->base.color_mask;
|
|
||||||
color >>= canvas->base.color_shift;
|
|
||||||
g = (double)(color & canvas->base.color_mask) / canvas->base.color_mask;
|
|
||||||
color >>= canvas->base.color_shift;
|
|
||||||
r = (double)(color & canvas->base.color_mask) / canvas->base.color_mask;
|
|
||||||
glc_set_rgb(canvas->glc, r, g, b);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SPICE_BRUSH_TYPE_PATTERN: {
|
|
||||||
GLCImage image;
|
|
||||||
GLCPattern pattern;
|
|
||||||
pixman_image_t *surface;
|
|
||||||
|
|
||||||
surface = canvas_get_image(&canvas->base, brush->u.pattern.pat, FALSE);
|
|
||||||
surface_to_image(canvas, surface, &image, 0);
|
|
||||||
|
|
||||||
pattern = glc_pattern_create(canvas->glc, -brush->u.pattern.pos.x,
|
|
||||||
-brush->u.pattern.pos.y, &image);
|
|
||||||
|
|
||||||
glc_set_pattern(canvas->glc, pattern);
|
|
||||||
glc_pattern_destroy(pattern);
|
|
||||||
pixman_image_unref (surface);
|
|
||||||
}
|
|
||||||
case SPICE_BRUSH_TYPE_NONE:
|
|
||||||
return;
|
|
||||||
default:
|
|
||||||
CANVAS_ERROR("invalid brush type");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void set_op(GLCanvas *canvas, uint16_t rop_decriptor)
|
|
||||||
{
|
|
||||||
GLCOp op;
|
|
||||||
|
|
||||||
switch (rop_decriptor) {
|
|
||||||
case SPICE_ROPD_OP_PUT:
|
|
||||||
op = GLC_OP_COPY;
|
|
||||||
break;
|
|
||||||
case SPICE_ROPD_OP_XOR:
|
|
||||||
op = GLC_OP_XOR;
|
|
||||||
break;
|
|
||||||
case SPICE_ROPD_OP_BLACKNESS:
|
|
||||||
op = GLC_OP_CLEAR;
|
|
||||||
break;
|
|
||||||
case SPICE_ROPD_OP_WHITENESS:
|
|
||||||
op = GLC_OP_SET;
|
|
||||||
break;
|
|
||||||
case SPICE_ROPD_OP_PUT | SPICE_ROPD_INVERS_BRUSH:
|
|
||||||
case SPICE_ROPD_OP_PUT | SPICE_ROPD_INVERS_SRC:
|
|
||||||
op = GLC_OP_COPY_INVERTED;
|
|
||||||
break;
|
|
||||||
case SPICE_ROPD_OP_INVERS:
|
|
||||||
op = GLC_OP_INVERT;
|
|
||||||
break;
|
|
||||||
case SPICE_ROPD_OP_AND:
|
|
||||||
op = GLC_OP_AND;
|
|
||||||
break;
|
|
||||||
case SPICE_ROPD_OP_AND | SPICE_ROPD_INVERS_RES:
|
|
||||||
op = GLC_OP_NAND;
|
|
||||||
break;
|
|
||||||
case SPICE_ROPD_OP_OR:
|
|
||||||
op = GLC_OP_OR;
|
|
||||||
break;
|
|
||||||
case SPICE_ROPD_OP_OR | SPICE_ROPD_INVERS_RES:
|
|
||||||
op = GLC_OP_NOR;
|
|
||||||
break;
|
|
||||||
case SPICE_ROPD_OP_XOR | SPICE_ROPD_INVERS_RES:
|
|
||||||
op = GLC_OP_EQUIV;
|
|
||||||
break;
|
|
||||||
case SPICE_ROPD_OP_AND | SPICE_ROPD_INVERS_DEST:
|
|
||||||
op = GLC_OP_AND_REVERSE;
|
|
||||||
break;
|
|
||||||
case SPICE_ROPD_OP_AND | SPICE_ROPD_INVERS_BRUSH:
|
|
||||||
case SPICE_ROPD_OP_AND | SPICE_ROPD_INVERS_SRC:
|
|
||||||
op = GLC_OP_AND_INVERTED;
|
|
||||||
break;
|
|
||||||
case SPICE_ROPD_OP_OR | SPICE_ROPD_INVERS_DEST:
|
|
||||||
op = GLC_OP_OR_REVERSE;
|
|
||||||
break;
|
|
||||||
case SPICE_ROPD_OP_OR | SPICE_ROPD_INVERS_BRUSH:
|
|
||||||
case SPICE_ROPD_OP_OR | SPICE_ROPD_INVERS_SRC:
|
|
||||||
op = GLC_OP_OR_INVERTED;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
WARN("GLC_OP_NOOP");
|
|
||||||
op = GLC_OP_NOOP;
|
|
||||||
}
|
|
||||||
glc_set_op(canvas->glc, op);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void gl_canvas_draw_fill(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceFill *fill)
|
|
||||||
{
|
|
||||||
GLCanvas *canvas = (GLCanvas *)spice_canvas;
|
|
||||||
GLCRect rect;
|
|
||||||
set_clip(canvas, bbox, clip);
|
|
||||||
set_mask(canvas, &fill->mask, bbox->left, bbox->top);
|
|
||||||
set_brush(canvas, &fill->brush);
|
|
||||||
set_op(canvas, fill->rop_descriptor);
|
|
||||||
SET_GLC_RECT(&rect, bbox);
|
|
||||||
|
|
||||||
glc_fill_rect(canvas->glc, &rect);
|
|
||||||
glc_flush(canvas->glc);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void gl_canvas_draw_copy(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceCopy *copy)
|
|
||||||
{
|
|
||||||
GLCanvas *canvas = (GLCanvas *)spice_canvas;
|
|
||||||
pixman_image_t *surface;
|
|
||||||
GLCRecti src;
|
|
||||||
GLCRecti dest;
|
|
||||||
GLCImage image;
|
|
||||||
|
|
||||||
set_clip(canvas, bbox, clip);
|
|
||||||
set_mask(canvas, ©->mask, bbox->left, bbox->top);
|
|
||||||
set_op(canvas, copy->rop_descriptor);
|
|
||||||
|
|
||||||
//todo: optimize get_image (use ogl conversion + remove unnecessary copy of 32bpp)
|
|
||||||
surface = canvas_get_image(&canvas->base, copy->src_bitmap, FALSE);
|
|
||||||
surface_to_image(canvas, surface, &image, 0);
|
|
||||||
SET_GLC_RECT(&dest, bbox);
|
|
||||||
SET_GLC_RECT(&src, ©->src_area);
|
|
||||||
glc_draw_image(canvas->glc, &dest, &src, &image, 0, 1);
|
|
||||||
|
|
||||||
pixman_image_unref(surface);
|
|
||||||
glc_flush(canvas->glc);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void gl_canvas_draw_opaque(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceOpaque *opaque)
|
|
||||||
{
|
|
||||||
GLCanvas *canvas = (GLCanvas *)spice_canvas;
|
|
||||||
pixman_image_t *surface;
|
|
||||||
GLCRecti src;
|
|
||||||
GLCRecti dest;
|
|
||||||
GLCRect fill_rect;
|
|
||||||
GLCImage image;
|
|
||||||
|
|
||||||
set_clip(canvas, bbox, clip);
|
|
||||||
set_mask(canvas, &opaque->mask, bbox->left, bbox->top);
|
|
||||||
|
|
||||||
glc_set_op(canvas->glc, (opaque->rop_descriptor & SPICE_ROPD_INVERS_SRC) ? GLC_OP_COPY_INVERTED :
|
|
||||||
GLC_OP_COPY);
|
|
||||||
surface = canvas_get_image(&canvas->base, opaque->src_bitmap, FALSE);
|
|
||||||
surface_to_image(canvas, surface, &image, 0);
|
|
||||||
SET_GLC_RECT(&dest, bbox);
|
|
||||||
SET_GLC_RECT(&src, &opaque->src_area);
|
|
||||||
glc_draw_image(canvas->glc, &dest, &src, &image, 0, 1);
|
|
||||||
pixman_image_unref(surface);
|
|
||||||
|
|
||||||
set_brush(canvas, &opaque->brush);
|
|
||||||
set_op(canvas, opaque->rop_descriptor & ~SPICE_ROPD_INVERS_SRC);
|
|
||||||
SET_GLC_RECT(&fill_rect, bbox);
|
|
||||||
glc_fill_rect(canvas->glc, &fill_rect);
|
|
||||||
|
|
||||||
glc_flush(canvas->glc);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void gl_canvas_draw_alpha_blend(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceAlphaBlend *alpha_blend)
|
|
||||||
{
|
|
||||||
GLCanvas *canvas = (GLCanvas *)spice_canvas;
|
|
||||||
pixman_image_t *surface;
|
|
||||||
GLCRecti src;
|
|
||||||
GLCRecti dest;
|
|
||||||
GLCImage image;
|
|
||||||
|
|
||||||
set_clip(canvas, bbox, clip);
|
|
||||||
glc_clear_mask(canvas->glc, GLC_MASK_A);
|
|
||||||
glc_set_op(canvas->glc, GLC_OP_COPY);
|
|
||||||
|
|
||||||
surface = canvas_get_image(&canvas->base, alpha_blend->src_bitmap, FALSE);
|
|
||||||
surface_to_image(canvas, surface, &image, 0);
|
|
||||||
SET_GLC_RECT(&dest, bbox);
|
|
||||||
SET_GLC_RECT(&src, &alpha_blend->src_area);
|
|
||||||
glc_draw_image(canvas->glc, &dest, &src, &image, 0, (double)alpha_blend->alpha / 0xff);
|
|
||||||
|
|
||||||
pixman_image_unref(surface);
|
|
||||||
glc_flush(canvas->glc);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void gl_canvas_draw_blend(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceBlend *blend)
|
|
||||||
{
|
|
||||||
GLCanvas *canvas = (GLCanvas *)spice_canvas;
|
|
||||||
pixman_image_t *surface;
|
|
||||||
GLCRecti src;
|
|
||||||
GLCRecti dest;
|
|
||||||
GLCImage image;
|
|
||||||
|
|
||||||
set_clip(canvas, bbox, clip);
|
|
||||||
set_mask(canvas, &blend->mask, bbox->left, bbox->top);
|
|
||||||
set_op(canvas, blend->rop_descriptor);
|
|
||||||
|
|
||||||
surface = canvas_get_image(&canvas->base, blend->src_bitmap, FALSE);
|
|
||||||
SET_GLC_RECT(&dest, bbox);
|
|
||||||
SET_GLC_RECT(&src, &blend->src_area);
|
|
||||||
surface_to_image(canvas, surface, &image, 0);
|
|
||||||
glc_draw_image(canvas->glc, &dest, &src, &image, 0, 1);
|
|
||||||
|
|
||||||
pixman_image_unref(surface);
|
|
||||||
glc_flush(canvas->glc);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void gl_canvas_draw_transparent(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceTransparent *transparent)
|
|
||||||
{
|
|
||||||
GLCanvas *canvas = (GLCanvas *)spice_canvas;
|
|
||||||
pixman_image_t *surface;
|
|
||||||
pixman_image_t *trans_surf;
|
|
||||||
GLCImage image;
|
|
||||||
GLCRecti src;
|
|
||||||
GLCRecti dest;
|
|
||||||
|
|
||||||
set_clip(canvas, bbox, clip);
|
|
||||||
glc_clear_mask(canvas->glc, GLC_MASK_A);
|
|
||||||
glc_set_op(canvas->glc, GLC_OP_COPY);
|
|
||||||
|
|
||||||
surface = canvas_get_image(&canvas->base, transparent->src_bitmap, FALSE);
|
|
||||||
surface_to_image(canvas, surface, &image, 0);
|
|
||||||
|
|
||||||
trans_surf = canvas_surf_to_trans_surf(&image, transparent->true_color);
|
|
||||||
pixman_image_unref(surface);
|
|
||||||
|
|
||||||
surface_to_image(canvas, trans_surf, &image, 1);
|
|
||||||
SET_GLC_RECT(&dest, bbox);
|
|
||||||
SET_GLC_RECT(&src, &transparent->src_area);
|
|
||||||
glc_draw_image(canvas->glc, &dest, &src, &image, 0, 1);
|
|
||||||
|
|
||||||
pixman_image_unref(trans_surf);
|
|
||||||
glc_flush(canvas->glc);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void fill_common(GLCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceQMask * mask, GLCOp op)
|
|
||||||
{
|
|
||||||
GLCRect rect;
|
|
||||||
|
|
||||||
set_clip(canvas, bbox, clip);
|
|
||||||
set_mask(canvas, mask, bbox->left, bbox->top);
|
|
||||||
glc_set_op(canvas->glc, op);
|
|
||||||
SET_GLC_RECT(&rect, bbox);
|
|
||||||
glc_fill_rect(canvas->glc, &rect);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void gl_canvas_draw_whiteness(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceWhiteness *whiteness)
|
|
||||||
{
|
|
||||||
GLCanvas *canvas = (GLCanvas *)spice_canvas;
|
|
||||||
fill_common(canvas, bbox, clip, &whiteness->mask, GLC_OP_SET);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void gl_canvas_draw_blackness(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceBlackness *blackness)
|
|
||||||
{
|
|
||||||
GLCanvas *canvas = (GLCanvas *)spice_canvas;
|
|
||||||
fill_common(canvas, bbox, clip, &blackness->mask, GLC_OP_CLEAR);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void gl_canvas_draw_invers(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceInvers *invers)
|
|
||||||
{
|
|
||||||
GLCanvas *canvas = (GLCanvas *)spice_canvas;
|
|
||||||
fill_common(canvas, bbox, clip, &invers->mask, GLC_OP_INVERT);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void gl_canvas_draw_rop3(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceRop3 *rop3)
|
|
||||||
{
|
|
||||||
GLCanvas *canvas = (GLCanvas *)spice_canvas;
|
|
||||||
pixman_image_t *d;
|
|
||||||
pixman_image_t *s;
|
|
||||||
GLCImage image;
|
|
||||||
SpicePoint src_pos;
|
|
||||||
uint8_t *data_opp;
|
|
||||||
int src_stride;
|
|
||||||
|
|
||||||
set_clip(canvas, bbox, clip);
|
|
||||||
set_mask(canvas, &rop3->mask, bbox->left, bbox->top);
|
|
||||||
|
|
||||||
glc_set_op(canvas->glc, GLC_OP_COPY);
|
|
||||||
|
|
||||||
image.format = GLC_IMAGE_RGB32;
|
|
||||||
image.width = bbox->right - bbox->left;
|
|
||||||
image.height = bbox->bottom - bbox->top;
|
|
||||||
|
|
||||||
image.pallet = NULL;
|
|
||||||
|
|
||||||
d = pixman_image_create_bits(PIXMAN_x8r8g8b8, image.width, image.height, NULL, 0);
|
|
||||||
if (d == NULL) {
|
|
||||||
CANVAS_ERROR("create surface failed");
|
|
||||||
}
|
|
||||||
image.pixels = (uint8_t *)pixman_image_get_data(d);
|
|
||||||
image.stride = pixman_image_get_stride(d);
|
|
||||||
|
|
||||||
glc_read_pixels(canvas->glc, bbox->left, bbox->top, &image);
|
|
||||||
data_opp = copy_opposite_image(canvas, image.pixels,
|
|
||||||
image.stride,
|
|
||||||
pixman_image_get_height(d));
|
|
||||||
memcpy(image.pixels, data_opp,
|
|
||||||
image.stride * pixman_image_get_height(d));
|
|
||||||
|
|
||||||
s = canvas_get_image(&canvas->base, rop3->src_bitmap, FALSE);
|
|
||||||
src_stride = pixman_image_get_stride(s);
|
|
||||||
if (src_stride > 0) {
|
|
||||||
data_opp = copy_opposite_image(canvas, (uint8_t *)pixman_image_get_data(s),
|
|
||||||
src_stride, pixman_image_get_height(s));
|
|
||||||
memcpy((uint8_t *)pixman_image_get_data(s), data_opp,
|
|
||||||
src_stride * pixman_image_get_height(s));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!rect_is_same_size(bbox, &rop3->src_area)) {
|
|
||||||
pixman_image_t *scaled_s = canvas_scale_surface(s, &rop3->src_area, image.width,
|
|
||||||
image.height, rop3->scale_mode);
|
|
||||||
pixman_image_unref(s);
|
|
||||||
s = scaled_s;
|
|
||||||
src_pos.x = 0;
|
|
||||||
src_pos.y = 0;
|
|
||||||
} else {
|
|
||||||
src_pos.x = rop3->src_area.left;
|
|
||||||
src_pos.y = rop3->src_area.top;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pixman_image_get_width(s) - src_pos.x < image.width ||
|
|
||||||
pixman_image_get_height(s) - src_pos.y < image.height) {
|
|
||||||
CANVAS_ERROR("bad src bitmap size");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rop3->brush.type == SPICE_BRUSH_TYPE_PATTERN) {
|
|
||||||
pixman_image_t *p = canvas_get_image(&canvas->base, rop3->brush.u.pattern.pat, FALSE);
|
|
||||||
SpicePoint pat_pos;
|
|
||||||
|
|
||||||
pat_pos.x = (bbox->left - rop3->brush.u.pattern.pos.x) % pixman_image_get_width(p);
|
|
||||||
|
|
||||||
pat_pos.y = (bbox->top - rop3->brush.u.pattern.pos.y) % pixman_image_get_height(p);
|
|
||||||
|
|
||||||
//for now (bottom-top)
|
|
||||||
if (pat_pos.y < 0) {
|
|
||||||
pat_pos.y = pixman_image_get_height(p) + pat_pos.y;
|
|
||||||
}
|
|
||||||
pat_pos.y = (image.height + pat_pos.y) % pixman_image_get_height(p);
|
|
||||||
pat_pos.y = pixman_image_get_height(p) - pat_pos.y;
|
|
||||||
|
|
||||||
do_rop3_with_pattern(rop3->rop3, d, s, &src_pos, p, &pat_pos);
|
|
||||||
pixman_image_unref(p);
|
|
||||||
} else {
|
|
||||||
uint32_t color = (canvas->base.color_shift) == 8 ? rop3->brush.u.color :
|
|
||||||
canvas_16bpp_to_32bpp(rop3->brush.u.color);
|
|
||||||
do_rop3_with_color(rop3->rop3, d, s, &src_pos, color);
|
|
||||||
}
|
|
||||||
|
|
||||||
pixman_image_unref(s);
|
|
||||||
|
|
||||||
GLCRecti dest;
|
|
||||||
GLCRecti src;
|
|
||||||
dest.x = bbox->left;
|
|
||||||
dest.y = bbox->top;
|
|
||||||
|
|
||||||
image.pixels = copy_opposite_image(canvas, image.pixels, pixman_image_get_stride(d),
|
|
||||||
pixman_image_get_height(d));
|
|
||||||
|
|
||||||
src.x = src.y = 0;
|
|
||||||
dest.width = src.width = image.width;
|
|
||||||
dest.height = src.height = image.height;
|
|
||||||
glc_draw_image(canvas->glc, &dest, &src, &image, 0, 1);
|
|
||||||
pixman_image_unref(d);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void gl_canvas_draw_stroke(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceStroke *stroke)
|
|
||||||
{
|
|
||||||
GLCanvas *canvas = (GLCanvas *)spice_canvas;
|
|
||||||
GLCPath path;
|
|
||||||
|
|
||||||
set_clip(canvas, bbox, clip);
|
|
||||||
glc_clear_mask(canvas->glc, GLC_MASK_A);
|
|
||||||
set_op(canvas, stroke->fore_mode);
|
|
||||||
set_brush(canvas, &stroke->brush);
|
|
||||||
|
|
||||||
if (stroke->attr.flags & SPICE_LINE_FLAGS_STYLED) {
|
|
||||||
WARN("SPICE_LINE_FLAGS_STYLED");
|
|
||||||
}
|
|
||||||
glc_set_line_width(canvas->glc, 1.0);
|
|
||||||
|
|
||||||
path = get_path(canvas, stroke->path);
|
|
||||||
glc_stroke_path(canvas->glc, path);
|
|
||||||
glc_path_destroy(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void gl_canvas_draw_text(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceText *text)
|
|
||||||
{
|
|
||||||
GLCanvas *canvas = (GLCanvas *)spice_canvas;
|
|
||||||
GLCRect rect;
|
|
||||||
SpiceString *str;
|
|
||||||
|
|
||||||
set_clip(canvas, bbox, clip);
|
|
||||||
glc_clear_mask(canvas->glc, GLC_MASK_A);
|
|
||||||
|
|
||||||
if (!rect_is_empty(&text->back_area)) {
|
|
||||||
set_brush(canvas, &text->back_brush);
|
|
||||||
set_op(canvas, text->back_mode);
|
|
||||||
SET_GLC_RECT(&rect, bbox);
|
|
||||||
glc_fill_rect(canvas->glc, &rect);
|
|
||||||
}
|
|
||||||
|
|
||||||
str = (SpiceString *)SPICE_GET_ADDRESS(text->str);
|
|
||||||
set_brush(canvas, &text->fore_brush);
|
|
||||||
set_op(canvas, text->fore_mode);
|
|
||||||
if (str->flags & SPICE_STRING_FLAGS_RASTER_A1) {
|
|
||||||
SpicePoint pos;
|
|
||||||
pixman_image_t *mask = canvas_get_str_mask(&canvas->base, str, 1, &pos);
|
|
||||||
_glc_fill_mask(canvas->glc, pos.x, pos.y,
|
|
||||||
pixman_image_get_width(mask),
|
|
||||||
pixman_image_get_height(mask),
|
|
||||||
pixman_image_get_stride(mask),
|
|
||||||
(uint8_t *)pixman_image_get_data(mask));
|
|
||||||
pixman_image_unref(mask);
|
|
||||||
} else if (str->flags & SPICE_STRING_FLAGS_RASTER_A4) {
|
|
||||||
SpicePoint pos;
|
|
||||||
pixman_image_t *mask = canvas_get_str_mask(&canvas->base, str, 4, &pos);
|
|
||||||
glc_fill_alpha(canvas->glc, pos.x, pos.y,
|
|
||||||
pixman_image_get_width(mask),
|
|
||||||
pixman_image_get_height(mask),
|
|
||||||
pixman_image_get_stride(mask),
|
|
||||||
(uint8_t *)pixman_image_get_data(mask));
|
|
||||||
|
|
||||||
pixman_image_unref(mask);
|
|
||||||
} else if (str->flags & SPICE_STRING_FLAGS_RASTER_A8) {
|
|
||||||
WARN("untested path A8 glyphs, doing nothing");
|
|
||||||
if (0) {
|
|
||||||
SpicePoint pos;
|
|
||||||
pixman_image_t *mask = canvas_get_str_mask(&canvas->base, str, 8, &pos);
|
|
||||||
glc_fill_alpha(canvas->glc, pos.x, pos.y,
|
|
||||||
pixman_image_get_width(mask),
|
|
||||||
pixman_image_get_height(mask),
|
|
||||||
pixman_image_get_stride(mask),
|
|
||||||
(uint8_t *)pixman_image_get_data(mask));
|
|
||||||
pixman_image_unref(mask);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
WARN("untested path vector glyphs, doing nothing");
|
|
||||||
if (0) {
|
|
||||||
//draw_vector_str(canvas, str, &text->fore_brush, text->fore_mode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
glc_flush(canvas->glc);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void gl_canvas_clear(SpiceCanvas *spice_canvas)
|
|
||||||
{
|
|
||||||
GLCanvas *canvas = (GLCanvas *)spice_canvas;
|
|
||||||
glc_clear(canvas->glc);
|
|
||||||
glc_flush(canvas->glc);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void gl_canvas_copy_bits(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpicePoint *src_pos)
|
|
||||||
{
|
|
||||||
GLCanvas *canvas = (GLCanvas *)spice_canvas;
|
|
||||||
set_clip(canvas, bbox, clip);
|
|
||||||
glc_clear_mask(canvas->glc, GLC_MASK_A);
|
|
||||||
glc_set_op(canvas->glc, GLC_OP_COPY);
|
|
||||||
glc_copy_pixels(canvas->glc, bbox->left, bbox->top, src_pos->x, src_pos->y,
|
|
||||||
bbox->right - bbox->left, bbox->bottom - bbox->top);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void gl_canvas_read_bits(SpiceCanvas *spice_canvas, uint8_t *dest, int dest_stride, const SpiceRect *area)
|
|
||||||
{
|
|
||||||
GLCanvas *canvas = (GLCanvas *)spice_canvas;
|
|
||||||
GLCImage image;
|
|
||||||
|
|
||||||
ASSERT(dest_stride > 0);
|
|
||||||
image.format = GLC_IMAGE_RGB32;
|
|
||||||
image.height = area->bottom - area->top;
|
|
||||||
image.width = area->right - area->left;
|
|
||||||
image.pixels = dest;
|
|
||||||
image.stride = dest_stride;
|
|
||||||
glc_read_pixels(canvas->glc, area->left, area->top, &image);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void gl_canvas_group_start(SpiceCanvas *spice_canvas, QRegion *region)
|
|
||||||
{
|
|
||||||
GLCanvas *canvas = (GLCanvas *)spice_canvas;
|
|
||||||
GLCRect *glc_rects;
|
|
||||||
GLCRect *now, *end;
|
|
||||||
int num_rect;
|
|
||||||
pixman_box32_t *rects;
|
|
||||||
|
|
||||||
canvas_base_group_start(spice_canvas, region);
|
|
||||||
|
|
||||||
rects = pixman_region32_rectangles(region, &num_rect);
|
|
||||||
|
|
||||||
glc_rects = spice_new(GLCRect, num_rect);
|
|
||||||
now = glc_rects;
|
|
||||||
end = glc_rects + num_rect;
|
|
||||||
|
|
||||||
for (; now < end; now++, rects++) {
|
|
||||||
SET_GLC_BOX(now, rects);
|
|
||||||
}
|
|
||||||
glc_mask_rects(canvas->glc, num_rect, glc_rects, GLC_MASK_B);
|
|
||||||
|
|
||||||
free(glc_rects);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void gl_canvas_put_image(SpiceCanvas *spice_canvas, const SpiceRect *dest, const uint8_t *src_data,
|
|
||||||
uint32_t src_width, uint32_t src_height, int src_stride,
|
|
||||||
const QRegion *clip)
|
|
||||||
{
|
|
||||||
GLCanvas *canvas = (GLCanvas *)spice_canvas;
|
|
||||||
GLCRecti src;
|
|
||||||
GLCRecti gldest;
|
|
||||||
GLCImage image;
|
|
||||||
uint32_t i;
|
|
||||||
|
|
||||||
ASSERT(src_stride <= 0)
|
|
||||||
glc_clip_reset(canvas->glc);
|
|
||||||
|
|
||||||
if (clip) {
|
|
||||||
int num_rects;
|
|
||||||
pixman_box32_t *rects = pixman_region32_rectangles((pixman_region32_t *)clip,
|
|
||||||
&num_rects);
|
|
||||||
GLCRect rect;
|
|
||||||
if (num_rects == 0) {
|
|
||||||
rect.x = rect.y = rect.width = rect.height = 0;
|
|
||||||
glc_clip_rect(canvas->glc, &rect, GLC_CLIP_OP_SET);
|
|
||||||
} else {
|
|
||||||
SET_GLC_BOX(&rect, rects);
|
|
||||||
glc_clip_rect(canvas->glc, &rect, GLC_CLIP_OP_SET);
|
|
||||||
for (i = 1; i < num_rects; i++) {
|
|
||||||
SET_GLC_BOX(&rect, rects + i);
|
|
||||||
glc_clip_rect(canvas->glc, &rect, GLC_CLIP_OP_OR);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SET_GLC_RECT(&gldest, dest);
|
|
||||||
src.x = src.y = 0;
|
|
||||||
src.width = src_width;
|
|
||||||
src.height = src_height;
|
|
||||||
|
|
||||||
image.format = GLC_IMAGE_RGB32;
|
|
||||||
image.width = src_width;
|
|
||||||
image.height = src_height;
|
|
||||||
src_stride = -src_stride;
|
|
||||||
image.stride = src_stride;
|
|
||||||
image.pixels = (uint8_t *)src_data - (src_height - 1) * src_stride;
|
|
||||||
image.pallet = NULL;
|
|
||||||
glc_draw_image(canvas->glc, &gldest, &src, &image, 0, 1);
|
|
||||||
|
|
||||||
glc_flush(canvas->glc);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void gl_canvas_group_end(SpiceCanvas *spice_canvas)
|
|
||||||
{
|
|
||||||
GLCanvas *canvas = (GLCanvas *)spice_canvas;
|
|
||||||
|
|
||||||
canvas_base_group_end(spice_canvas);
|
|
||||||
glc_clear_mask(canvas->glc, GLC_MASK_B);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int need_init = 1;
|
|
||||||
static SpiceCanvasOps gl_canvas_ops;
|
|
||||||
|
|
||||||
SpiceCanvas *gl_canvas_create(int width, int height, uint32_t format
|
|
||||||
#ifdef SW_CANVAS_CACHE
|
|
||||||
, SpiceImageCache *bits_cache
|
|
||||||
, SpicePaletteCache *palette_cache
|
|
||||||
#elif defined(SW_CANVAS_IMAGE_CACHE)
|
|
||||||
, SpiceImageCache *bits_cache
|
|
||||||
#endif
|
|
||||||
, SpiceImageSurfaces *surfaces
|
|
||||||
, SpiceGlzDecoder *glz_decoder
|
|
||||||
, SpiceJpegDecoder *jpeg_decoder
|
|
||||||
, SpiceZlibDecoder *zlib_decoder
|
|
||||||
)
|
|
||||||
{
|
|
||||||
GLCanvas *canvas;
|
|
||||||
int init_ok;
|
|
||||||
|
|
||||||
if (need_init) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
canvas = spice_new0(GLCanvas, 1);
|
|
||||||
|
|
||||||
if (!(canvas->glc = glc_create(width, height))) {
|
|
||||||
goto error_1;
|
|
||||||
}
|
|
||||||
canvas->private_data = NULL;
|
|
||||||
init_ok = canvas_base_init(&canvas->base, &gl_canvas_ops,
|
|
||||||
width, height, format
|
|
||||||
#ifdef SW_CANVAS_CACHE
|
|
||||||
, bits_cache
|
|
||||||
, palette_cache
|
|
||||||
#elif defined(SW_CANVAS_IMAGE_CACHE)
|
|
||||||
, bits_cache
|
|
||||||
#endif
|
|
||||||
, surfaces
|
|
||||||
, glz_decoder
|
|
||||||
, jpeg_decoder
|
|
||||||
, zlib_decoder
|
|
||||||
);
|
|
||||||
if (!init_ok) {
|
|
||||||
goto error_2;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (SpiceCanvas *)canvas;
|
|
||||||
|
|
||||||
error_2:
|
|
||||||
glc_destroy(canvas->glc, 0);
|
|
||||||
error_1:
|
|
||||||
free(canvas);
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void gl_canvas_set_textures_lost(SpiceCanvas *spice_canvas,
|
|
||||||
int textures_lost)
|
|
||||||
{
|
|
||||||
GLCanvas *canvas = (GLCanvas *)spice_canvas;
|
|
||||||
|
|
||||||
canvas->textures_lost = textures_lost;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void gl_canvas_destroy(SpiceCanvas *spice_canvas)
|
|
||||||
{
|
|
||||||
GLCanvas *canvas = (GLCanvas *)spice_canvas;
|
|
||||||
|
|
||||||
if (!canvas) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
canvas_base_destroy(&canvas->base);
|
|
||||||
glc_destroy(canvas->glc, canvas->textures_lost);
|
|
||||||
free(canvas->private_data);
|
|
||||||
free(canvas);
|
|
||||||
}
|
|
||||||
|
|
||||||
void gl_canvas_init(void) //unsafe global function
|
|
||||||
{
|
|
||||||
if (!need_init) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
need_init = 0;
|
|
||||||
|
|
||||||
canvas_base_init_ops(&gl_canvas_ops);
|
|
||||||
gl_canvas_ops.draw_fill = gl_canvas_draw_fill;
|
|
||||||
gl_canvas_ops.draw_copy = gl_canvas_draw_copy;
|
|
||||||
gl_canvas_ops.draw_opaque = gl_canvas_draw_opaque;
|
|
||||||
gl_canvas_ops.copy_bits = gl_canvas_copy_bits;
|
|
||||||
gl_canvas_ops.draw_text = gl_canvas_draw_text;
|
|
||||||
gl_canvas_ops.draw_stroke = gl_canvas_draw_stroke;
|
|
||||||
gl_canvas_ops.draw_rop3 = gl_canvas_draw_rop3;
|
|
||||||
gl_canvas_ops.draw_blend = gl_canvas_draw_blend;
|
|
||||||
gl_canvas_ops.draw_blackness = gl_canvas_draw_blackness;
|
|
||||||
gl_canvas_ops.draw_whiteness = gl_canvas_draw_whiteness;
|
|
||||||
gl_canvas_ops.draw_invers = gl_canvas_draw_invers;
|
|
||||||
gl_canvas_ops.draw_transparent = gl_canvas_draw_transparent;
|
|
||||||
gl_canvas_ops.draw_alpha_blend = gl_canvas_draw_alpha_blend;
|
|
||||||
gl_canvas_ops.put_image = gl_canvas_put_image;
|
|
||||||
gl_canvas_ops.clear = gl_canvas_clear;
|
|
||||||
gl_canvas_ops.read_bits = gl_canvas_read_bits;
|
|
||||||
gl_canvas_ops.group_start = gl_canvas_group_start;
|
|
||||||
gl_canvas_ops.group_end = gl_canvas_group_end;
|
|
||||||
gl_canvas_ops.destroy = gl_canvas_destroy;
|
|
||||||
|
|
||||||
rop3_init();
|
|
||||||
}
|
|
||||||
@ -1,53 +0,0 @@
|
|||||||
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
||||||
/*
|
|
||||||
Copyright (C) 2009 Red Hat, Inc.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "glc.h"
|
|
||||||
#include "canvas_base.h"
|
|
||||||
#include "region.h"
|
|
||||||
|
|
||||||
#ifndef SPICE_CANVAS_INTERNAL
|
|
||||||
#error "This header shouldn't be included directly"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef _H__GL_CANVAS
|
|
||||||
#define _H__GL_CANVAS
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
SpiceCanvas *gl_canvas_create(int width, int height, uint32_t format
|
|
||||||
#ifdef SW_CANVAS_CACHE
|
|
||||||
, SpiceImageCache *bits_cache
|
|
||||||
, SpicePaletteCache *palette_cache
|
|
||||||
#elif defined(SW_CANVAS_IMAGE_CACHE)
|
|
||||||
, SpiceImageCache *bits_cache
|
|
||||||
#endif
|
|
||||||
, SpiceImageSurfaces *surfaces
|
|
||||||
, SpiceGlzDecoder *glz_decoder
|
|
||||||
, SpiceJpegDecoder *jpeg_decoder
|
|
||||||
, SpiceZlibDecoder *zlib_decoder
|
|
||||||
);
|
|
||||||
void gl_canvas_set_textures_lost(SpiceCanvas *canvas, int textures_lost);
|
|
||||||
void gl_canvas_init(void);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1,61 +0,0 @@
|
|||||||
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
||||||
/*
|
|
||||||
Copyright (C) 2009 Red Hat, Inc.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
|
|
||||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef GL_UTILS_H
|
|
||||||
#define GL_UTILS_H
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef RED_DEBUG
|
|
||||||
#define GLC_ERROR_TEST_FLUSH { \
|
|
||||||
GLenum gl_err; glFlush(); \
|
|
||||||
if ((gl_err = glGetError()) != GL_NO_ERROR) { \
|
|
||||||
printf("%s[%d]: opengl error: %s\n", __FUNCTION__, __LINE__, \
|
|
||||||
gluErrorString(gl_err)); \
|
|
||||||
abort(); \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define GLC_ERROR_TEST_FINISH { \
|
|
||||||
GLenum gl_err; glFinish(); \
|
|
||||||
if ((gl_err = glGetError()) != GL_NO_ERROR) { \
|
|
||||||
printf("%s[%d]: opengl error: %s\n", __FUNCTION__, __LINE__, \
|
|
||||||
gluErrorString(gl_err)); \
|
|
||||||
abort(); \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
#define GLC_ERROR_TEST_FLUSH ;
|
|
||||||
|
|
||||||
#define GLC_ERROR_TEST_FINISH ;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "bitops.h"
|
|
||||||
|
|
||||||
#define find_msb spice_bit_find_msb
|
|
||||||
#define gl_get_to_power_two spice_bit_next_pow2
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
1513
common/glc.c
1513
common/glc.c
File diff suppressed because it is too large
Load Diff
167
common/glc.h
167
common/glc.h
@ -1,167 +0,0 @@
|
|||||||
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
||||||
/*
|
|
||||||
Copyright (C) 2009 Red Hat, Inc.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
|
|
||||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _H_GL_CANVASE
|
|
||||||
#define _H_GL_CANVASE
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef void * GLCCtx;
|
|
||||||
typedef void * GLCPattern;
|
|
||||||
typedef void * GLCPath;
|
|
||||||
|
|
||||||
typedef struct GLCRect {
|
|
||||||
double x;
|
|
||||||
double y;
|
|
||||||
double width;
|
|
||||||
double height;
|
|
||||||
} GLCRect;
|
|
||||||
|
|
||||||
typedef struct GLCRecti {
|
|
||||||
int x;
|
|
||||||
int y;
|
|
||||||
int width;
|
|
||||||
int height;
|
|
||||||
} GLCRecti;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
GLC_IMAGE_RGB32,
|
|
||||||
GLC_IMAGE_ARGB32,
|
|
||||||
} GLCImageFormat;
|
|
||||||
|
|
||||||
typedef struct GLCPImage {
|
|
||||||
GLCImageFormat format;
|
|
||||||
int width;
|
|
||||||
int height;
|
|
||||||
int stride;
|
|
||||||
uint8_t *pixels;
|
|
||||||
uint32_t *pallet;
|
|
||||||
} GLCImage;
|
|
||||||
|
|
||||||
GLCPattern glc_pattern_create(GLCCtx glc, int x_orign, int y_orign, const GLCImage *image);
|
|
||||||
void glc_pattern_set(GLCPattern pattern, int x_orign, int y_orign, const GLCImage *image);
|
|
||||||
void glc_pattern_destroy(GLCPattern pattern);
|
|
||||||
|
|
||||||
void glc_path_move_to(GLCPath path, double x, double y);
|
|
||||||
void glc_path_line_to(GLCPath path, double x, double y);
|
|
||||||
void glc_path_curve_to(GLCPath path, double p1_x, double p1_y, double p2_x, double p2_y,
|
|
||||||
double p3_x, double p3_y);
|
|
||||||
void glc_path_rel_move_to(GLCPath path, double x, double y);
|
|
||||||
void glc_path_rel_line_to(GLCPath path, double x, double y);
|
|
||||||
void glc_path_rel_curve_to(GLCPath path, double p1_x, double p1_y, double p2_x, double p2_y,
|
|
||||||
double p3_x, double p3_y);
|
|
||||||
void glc_path_close(GLCPath path);
|
|
||||||
|
|
||||||
void glc_path_cleare(GLCPath);
|
|
||||||
GLCPath glc_path_create(GLCCtx glc);
|
|
||||||
void glc_path_destroy(GLCPath path);
|
|
||||||
|
|
||||||
void glc_set_rgb(GLCCtx glc, double red, double green, double blue);
|
|
||||||
void glc_set_rgba(GLCCtx glc, double red, double green, double blue, double alpha);
|
|
||||||
void glc_set_pattern(GLCCtx glc, GLCPattern pattern);
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
GLC_OP_CLEAR = 0x1500,
|
|
||||||
GLC_OP_SET = 0x150F,
|
|
||||||
GLC_OP_COPY = 0x1503,
|
|
||||||
GLC_OP_COPY_INVERTED = 0x150C,
|
|
||||||
GLC_OP_NOOP = 0x1505,
|
|
||||||
GLC_OP_INVERT = 0x150A,
|
|
||||||
GLC_OP_AND = 0x1501,
|
|
||||||
GLC_OP_NAND = 0x150E,
|
|
||||||
GLC_OP_OR = 0x1507,
|
|
||||||
GLC_OP_NOR = 0x1508,
|
|
||||||
GLC_OP_XOR = 0x1506,
|
|
||||||
GLC_OP_EQUIV = 0x1509,
|
|
||||||
GLC_OP_AND_REVERSE = 0x1502,
|
|
||||||
GLC_OP_AND_INVERTED = 0x1504,
|
|
||||||
GLC_OP_OR_REVERSE = 0x150B,
|
|
||||||
GLC_OP_OR_INVERTED = 0x150D,
|
|
||||||
} GLCOp;
|
|
||||||
|
|
||||||
void glc_set_op(GLCCtx glc, GLCOp op);
|
|
||||||
void glc_set_alpha_factor(GLCCtx glc, double alpah);
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
GLC_FILL_MODE_WINDING_ODD,
|
|
||||||
GLC_FILL_MODE_WINDING_NONZERO,
|
|
||||||
} GLCFillMode;
|
|
||||||
|
|
||||||
void glc_set_fill_mode(GLCCtx glc, GLCFillMode mode);
|
|
||||||
void glc_set_line_width(GLCCtx glc, double width);
|
|
||||||
void glc_set_line_end_cap(GLCCtx glc, int style);
|
|
||||||
void glc_set_line_join(GLCCtx glc, int style);
|
|
||||||
void glc_set_miter_limit(GLCCtx glc, int limit);
|
|
||||||
void glc_set_line_dash(GLCCtx glc, const double *dashes, int num_dashes, double offset);
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
GLC_MASK_A,
|
|
||||||
GLC_MASK_B,
|
|
||||||
} GLCMaskID;
|
|
||||||
|
|
||||||
void glc_set_mask(GLCCtx glc, int x_dest, int y_dest, int width, int height,
|
|
||||||
int stride, const uint8_t *bitmap, GLCMaskID id);
|
|
||||||
void glc_mask_rects(GLCCtx glc, int num_rect, GLCRect *rects, GLCMaskID id);
|
|
||||||
void glc_clear_mask(GLCCtx glc, GLCMaskID id);
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
GLC_CLIP_OP_SET,
|
|
||||||
GLC_CLIP_OP_OR,
|
|
||||||
GLC_CLIP_OP_AND,
|
|
||||||
GLC_CLIP_OP_EXCLUDE,
|
|
||||||
} GLCClipOp;
|
|
||||||
|
|
||||||
void glc_clip_rect(GLCCtx glc, const GLCRect *rect, GLCClipOp op);
|
|
||||||
void glc_clip_path(GLCCtx glc, GLCPath path, GLCClipOp op);
|
|
||||||
void glc_clip_mask(GLCCtx glc, int x_dest, int y_dest, int width, int height, int stride,
|
|
||||||
const uint8_t *bitmap, GLCClipOp op);
|
|
||||||
void glc_clip_reset(GLCCtx glc);
|
|
||||||
|
|
||||||
void glc_fill_rect(GLCCtx glc, const GLCRect *rect);
|
|
||||||
void glc_fill_path(GLCCtx glc, GLCPath path);
|
|
||||||
void _glc_fill_mask(GLCCtx glc, int x_dest, int y_dest, int width, int height, int stride,
|
|
||||||
const uint8_t *bitmap);
|
|
||||||
void glc_fill_alpha(GLCCtx glc, int x_dest, int y_dest, int width, int height, int stride,
|
|
||||||
const uint8_t *alpha_mask);
|
|
||||||
|
|
||||||
void glc_stroke_rect(GLCCtx glc, const GLCRect *rect);
|
|
||||||
void glc_stroke_path(GLCCtx glc, GLCPath path);
|
|
||||||
|
|
||||||
void glc_draw_image(GLCCtx glc, const GLCRecti *dest, const GLCRecti *src, const GLCImage *image,
|
|
||||||
int scale_mode, double alpha);
|
|
||||||
|
|
||||||
void glc_copy_pixels(GLCCtx glc, int x_dest, int y_dest, int x_src, int y_src, int width,
|
|
||||||
int height);
|
|
||||||
void glc_read_pixels(GLCCtx glc, int x, int y, GLCImage *image);
|
|
||||||
|
|
||||||
void glc_flush(GLCCtx glc);
|
|
||||||
void glc_clear(GLCCtx glc);
|
|
||||||
GLCCtx glc_create(int width, int height);
|
|
||||||
void glc_destroy(GLCCtx glc, int textures_lost);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -45,9 +45,7 @@ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
|||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
|
|
||||||
******************************************************************/
|
******************************************************************/
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <spice/macros.h>
|
#include <spice/macros.h>
|
||||||
@ -84,7 +82,7 @@ typedef struct lineGC *GCPtr;
|
|||||||
#define miWideDash spice_canvas_wide_dash_line
|
#define miWideDash spice_canvas_wide_dash_line
|
||||||
#define miWideLine spice_canvas_wide_line
|
#define miWideLine spice_canvas_wide_line
|
||||||
|
|
||||||
static INLINE int ICEIL (double x)
|
static inline int ICEIL (double x)
|
||||||
{
|
{
|
||||||
int _cTmp = (int)x;
|
int _cTmp = (int)x;
|
||||||
return ((x == _cTmp) || (x < 0.0)) ? _cTmp : _cTmp + 1;
|
return ((x == _cTmp) || (x < 0.0)) ? _cTmp : _cTmp + 1;
|
||||||
@ -412,7 +410,7 @@ miStepDash (int dist, /* distance to step */
|
|||||||
totallen = 0;
|
totallen = 0;
|
||||||
for (i = 0; i < numInDashList; i++)
|
for (i = 0; i < numInDashList; i++)
|
||||||
totallen += pDash[i];
|
totallen += pDash[i];
|
||||||
if (totallen <= dist)
|
if (totallen > 0 && totallen <= dist)
|
||||||
dist = dist % totallen;
|
dist = dist % totallen;
|
||||||
while (dist >= pDash[dashIndex]) {
|
while (dist >= pDash[dashIndex]) {
|
||||||
dist -= pDash[dashIndex];
|
dist -= pDash[dashIndex];
|
||||||
@ -806,14 +804,14 @@ miFillUniqueSpanGroup (GCPtr pGC, SpanGroup * spanGroup, Boolean foreground)
|
|||||||
newwidths = xrealloc (newspans->widths,
|
newwidths = xrealloc (newspans->widths,
|
||||||
ysizes[index] * sizeof (int));
|
ysizes[index] * sizeof (int));
|
||||||
if (!newpoints || !newwidths) {
|
if (!newpoints || !newwidths) {
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < ylength; i++) {
|
for (i = 0; i < ylength; i++) {
|
||||||
xfree (yspans[i].points);
|
xfree (yspans[i].points);
|
||||||
xfree (yspans[i].widths);
|
xfree (yspans[i].widths);
|
||||||
}
|
}
|
||||||
xfree (yspans);
|
xfree (yspans);
|
||||||
xfree (ysizes);
|
xfree (ysizes);
|
||||||
|
xfree (newpoints);
|
||||||
|
xfree (newwidths);
|
||||||
miDisposeSpanGroup (spanGroup);
|
miDisposeSpanGroup (spanGroup);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -836,8 +834,6 @@ miFillUniqueSpanGroup (GCPtr pGC, SpanGroup * spanGroup, Boolean foreground)
|
|||||||
points = (DDXPointRec*)xalloc (count * sizeof (DDXPointRec));
|
points = (DDXPointRec*)xalloc (count * sizeof (DDXPointRec));
|
||||||
widths = (int *)xalloc (count * sizeof (int));
|
widths = (int *)xalloc (count * sizeof (int));
|
||||||
if (!points || !widths) {
|
if (!points || !widths) {
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < ylength; i++) {
|
for (i = 0; i < ylength; i++) {
|
||||||
xfree (yspans[i].points);
|
xfree (yspans[i].points);
|
||||||
xfree (yspans[i].widths);
|
xfree (yspans[i].widths);
|
||||||
@ -929,7 +925,7 @@ end of the line, we will find the largest number of Y steps that
|
|||||||
satisfies the inequality. In that case, since we are representing
|
satisfies the inequality. In that case, since we are representing
|
||||||
the Y steps as (dy - N), we will actually want to solve for the
|
the Y steps as (dy - N), we will actually want to solve for the
|
||||||
smallest N in that equation.
|
smallest N in that equation.
|
||||||
|
|
||||||
Case 1: X major, starting X coordinate moved by M steps
|
Case 1: X major, starting X coordinate moved by M steps
|
||||||
|
|
||||||
-2dx <= 2Mdy - 2Ndx - dx - B < 0
|
-2dx <= 2Mdy - 2Ndx - dx - B < 0
|
||||||
@ -977,7 +973,7 @@ steps, so we want the highest N, so we use the < inequality:
|
|||||||
= floor((2Mdy + dx + B + 2dx - 1) / 2dx) - 1
|
= floor((2Mdy + dx + B + 2dx - 1) / 2dx) - 1
|
||||||
= floor((2Mdy + dx + B + 2dx - 1 - 2dx) / 2dx)
|
= floor((2Mdy + dx + B + 2dx - 1 - 2dx) / 2dx)
|
||||||
= floor((2Mdy + dx + B - 1) / 2dx)
|
= floor((2Mdy + dx + B - 1) / 2dx)
|
||||||
|
|
||||||
Case 3: Y major, starting X coordinate moved by M steps
|
Case 3: Y major, starting X coordinate moved by M steps
|
||||||
|
|
||||||
-2dy <= 2Ndx - 2Mdy - dy - B < 0
|
-2dy <= 2Ndx - 2Mdy - dy - B < 0
|
||||||
@ -1023,7 +1019,7 @@ Same analysis as Case 4, but we want the smallest number of Y steps
|
|||||||
which means the largest N, so we use the <= inequality:
|
which means the largest N, so we use the <= inequality:
|
||||||
|
|
||||||
N = floor((2Mdy + dy - B) / 2dx)
|
N = floor((2Mdy + dy - B) / 2dx)
|
||||||
|
|
||||||
Now let's try the Y coordinates, we have the same 4 cases.
|
Now let's try the Y coordinates, we have the same 4 cases.
|
||||||
|
|
||||||
Case 5: X major, starting Y coordinate moved by N steps
|
Case 5: X major, starting Y coordinate moved by N steps
|
||||||
@ -1068,7 +1064,7 @@ Same derivations as Case 6, but we want the smallest # of X steps
|
|||||||
which means the largest M, so use the <= inequality:
|
which means the largest M, so use the <= inequality:
|
||||||
|
|
||||||
M = floor((2Ndx + dx - B) / 2dy)
|
M = floor((2Ndx + dx - B) / 2dy)
|
||||||
|
|
||||||
Case 7: Y major, starting Y coordinate moved by N steps
|
Case 7: Y major, starting Y coordinate moved by N steps
|
||||||
|
|
||||||
-2dy <= 2Ndx - 2Mdy - dy - B < 0
|
-2dy <= 2Ndx - 2Mdy - dy - B < 0
|
||||||
@ -1113,7 +1109,7 @@ steps which means the largest M, so we use the < inequality:
|
|||||||
= floor((2Ndx + dy + B + 2dy - 1) / 2dy) - 1
|
= floor((2Ndx + dy + B + 2dy - 1) / 2dy) - 1
|
||||||
= floor((2Ndx + dy + B + 2dy - 1 - 2dy) / 2dy)
|
= floor((2Ndx + dy + B + 2dy - 1 - 2dy) / 2dy)
|
||||||
= floor((2Ndx + dy + B - 1) / 2dy)
|
= floor((2Ndx + dy + B - 1) / 2dy)
|
||||||
|
|
||||||
So, our equations are:
|
So, our equations are:
|
||||||
|
|
||||||
1: X major move x1 to x1+M floor((2Mdy + dx - B) / 2dx)
|
1: X major move x1 to x1+M floor((2Mdy + dx - B) / 2dx)
|
||||||
@ -1826,7 +1822,7 @@ miFillRectPolyHelper (GCPtr pGC, Boolean foreground, SpanDataPtr spanData, int x
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
miPolyBuildEdge (double x0, double y0, double k, /* x0 * dy - y0 * dx */
|
miPolyBuildEdge (SPICE_GNUC_UNUSED double x0, double y0, double k, /* x0 * dy - y0 * dx */
|
||||||
int dx, int dy, int xi, int yi, int left, PolyEdgePtr edge)
|
int dx, int dy, int xi, int yi, int left, PolyEdgePtr edge)
|
||||||
{
|
{
|
||||||
int x, y, e;
|
int x, y, e;
|
||||||
@ -1837,15 +1833,6 @@ miPolyBuildEdge (double x0, double y0, double k, /* x0 * dy - y0 * dx */
|
|||||||
dx = -dx;
|
dx = -dx;
|
||||||
k = -k;
|
k = -k;
|
||||||
}
|
}
|
||||||
#ifdef NOTDEF
|
|
||||||
{
|
|
||||||
double realk, kerror;
|
|
||||||
realk = x0 * dy - y0 * dx;
|
|
||||||
kerror = Fabs (realk - k);
|
|
||||||
if (kerror > .1)
|
|
||||||
printf ("realk: %g k: %g\n", realk, k);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
y = ICEIL (y0);
|
y = ICEIL (y0);
|
||||||
xady = ICEIL (k) + y * dx;
|
xady = ICEIL (k) + y * dx;
|
||||||
|
|
||||||
@ -1970,7 +1957,11 @@ miPolyBuildPoly (PolyVertexPtr vertices,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
miLineOnePoint (GCPtr pGC, Boolean foreground, SpanDataPtr spanData, int x, int y)
|
miLineOnePoint (GCPtr pGC,
|
||||||
|
Boolean foreground,
|
||||||
|
SPICE_GNUC_UNUSED SpanDataPtr spanData,
|
||||||
|
int x,
|
||||||
|
int y)
|
||||||
{
|
{
|
||||||
DDXPointRec pt;
|
DDXPointRec pt;
|
||||||
int wid;
|
int wid;
|
||||||
@ -2430,7 +2421,7 @@ miLineArc (GCPtr pGC,
|
|||||||
int xorgi = 0, yorgi = 0;
|
int xorgi = 0, yorgi = 0;
|
||||||
Spans spanRec;
|
Spans spanRec;
|
||||||
int n;
|
int n;
|
||||||
PolyEdgeRec edge1, edge2;
|
PolyEdgeRec edge1 = { 0 }, edge2 = { 0 };
|
||||||
int edgey1, edgey2;
|
int edgey1, edgey2;
|
||||||
Boolean edgeleft1, edgeleft2;
|
Boolean edgeleft1, edgeleft2;
|
||||||
|
|
||||||
@ -2501,13 +2492,18 @@ miLineArc (GCPtr pGC,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
miLineProjectingCap (GCPtr pGC, Boolean foreground,
|
miLineProjectingCap (GCPtr pGC,
|
||||||
SpanDataPtr spanData, LineFacePtr face, Boolean isLeft,
|
Boolean foreground,
|
||||||
double xorg, double yorg, Boolean isInt)
|
SpanDataPtr spanData,
|
||||||
|
LineFacePtr face,
|
||||||
|
Boolean isLeft,
|
||||||
|
SPICE_GNUC_UNUSED double xorg,
|
||||||
|
SPICE_GNUC_UNUSED double yorg,
|
||||||
|
Boolean isInt)
|
||||||
{
|
{
|
||||||
int xorgi = 0, yorgi = 0;
|
int xorgi = 0, yorgi = 0;
|
||||||
int lw;
|
int lw;
|
||||||
PolyEdgeRec lefts[2], rights[2];
|
PolyEdgeRec lefts[4], rights[4];
|
||||||
int lefty, righty, topy, bottomy;
|
int lefty, righty, topy, bottomy;
|
||||||
PolyEdgePtr left, right;
|
PolyEdgePtr left, right;
|
||||||
PolyEdgePtr top, bottom;
|
PolyEdgePtr top, bottom;
|
||||||
@ -2665,7 +2661,7 @@ miWideSegment (GCPtr pGC,
|
|||||||
PolyEdgePtr top, bottom;
|
PolyEdgePtr top, bottom;
|
||||||
int lefty, righty, topy, bottomy;
|
int lefty, righty, topy, bottomy;
|
||||||
int signdx;
|
int signdx;
|
||||||
PolyEdgeRec lefts[2], rights[2];
|
PolyEdgeRec lefts[4], rights[4];
|
||||||
LineFacePtr tface;
|
LineFacePtr tface;
|
||||||
int lw = pGC->lineWidth;
|
int lw = pGC->lineWidth;
|
||||||
|
|
||||||
@ -2980,9 +2976,9 @@ miWideDashSegment (GCPtr pGC,
|
|||||||
double L, l;
|
double L, l;
|
||||||
double k;
|
double k;
|
||||||
PolyVertexRec vertices[4];
|
PolyVertexRec vertices[4];
|
||||||
PolyVertexRec saveRight = { 0 }, saveBottom;
|
PolyVertexRec saveRight = { 0, 0 }, saveBottom;
|
||||||
PolySlopeRec slopes[4];
|
PolySlopeRec slopes[4];
|
||||||
PolyEdgeRec left[2], right[2];
|
PolyEdgeRec left[4], right[4];
|
||||||
LineFaceRec lcapFace, rcapFace;
|
LineFaceRec lcapFace, rcapFace;
|
||||||
int nleft, nright;
|
int nleft, nright;
|
||||||
int h;
|
int h;
|
||||||
|
|||||||
@ -46,17 +46,17 @@ SOFTWARE.
|
|||||||
|
|
||||||
******************************************************************/
|
******************************************************************/
|
||||||
|
|
||||||
#ifndef LINES_H
|
#ifndef H_SPICE_COMMON_LINES
|
||||||
#define LINES_H
|
#define H_SPICE_COMMON_LINES
|
||||||
|
|
||||||
#include <pixman_utils.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <spice/macros.h>
|
||||||
|
|
||||||
|
#include "pixman_utils.h"
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
SPICE_BEGIN_DECLS
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct lineGC lineGC;
|
typedef struct lineGC lineGC;
|
||||||
|
|
||||||
@ -131,8 +131,6 @@ extern int spice_canvas_clip_spans(pixman_region32_t *clip_region,
|
|||||||
int *new_widths,
|
int *new_widths,
|
||||||
int sorted);
|
int sorted);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
SPICE_END_DECLS
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* LINES_H */
|
#endif // H_SPICE_COMMON_LINES
|
||||||
|
|||||||
71
common/log.c
Normal file
71
common/log.c
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
Copyright (C) 2012-2015 Red Hat, Inc.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <common/recorder.h>
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
#include "backtrace.h"
|
||||||
|
|
||||||
|
#define G_LOG_DOMAIN "Spice"
|
||||||
|
|
||||||
|
SPICE_CONSTRUCTOR_FUNC(spice_log_init)
|
||||||
|
{
|
||||||
|
recorder_dump_on_common_signals(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
G_GNUC_PRINTF(5, 0)
|
||||||
|
static void spice_logv(const char *log_domain,
|
||||||
|
GLogLevelFlags log_level,
|
||||||
|
const char *strloc,
|
||||||
|
const char *function,
|
||||||
|
const char *format,
|
||||||
|
va_list args)
|
||||||
|
{
|
||||||
|
GString *log_msg;
|
||||||
|
|
||||||
|
log_msg = g_string_new(NULL);
|
||||||
|
if (strloc && function) {
|
||||||
|
g_string_append_printf(log_msg, "%s:%s: ", strloc, function);
|
||||||
|
}
|
||||||
|
if (format) {
|
||||||
|
g_string_append_vprintf(log_msg, format, args);
|
||||||
|
}
|
||||||
|
g_log(log_domain, log_level, "%s", log_msg->str);
|
||||||
|
g_string_free(log_msg, TRUE);
|
||||||
|
|
||||||
|
if ((log_level & G_LOG_LEVEL_CRITICAL) != 0) {
|
||||||
|
spice_backtrace();
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void spice_log(GLogLevelFlags log_level,
|
||||||
|
const char *strloc,
|
||||||
|
const char *function,
|
||||||
|
const char *format,
|
||||||
|
...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
|
||||||
|
va_start (args, format);
|
||||||
|
spice_logv (G_LOG_DOMAIN, log_level, strloc, function, format, args);
|
||||||
|
va_end (args);
|
||||||
|
}
|
||||||
110
common/log.h
Normal file
110
common/log.h
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
Copyright (C) 2012 Red Hat, Inc.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef H_SPICE_COMMON_LOG
|
||||||
|
#define H_SPICE_COMMON_LOG
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <glib.h>
|
||||||
|
#include <spice/macros.h>
|
||||||
|
|
||||||
|
#include "macros.h"
|
||||||
|
|
||||||
|
SPICE_BEGIN_DECLS
|
||||||
|
|
||||||
|
#ifdef SPICE_LOG_DOMAIN
|
||||||
|
#error Do not use obsolete SPICE_LOG_DOMAIN macro, is currently unused
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SPICE_STRLOC __FILE__ ":" G_STRINGIFY (__LINE__)
|
||||||
|
|
||||||
|
void spice_log(GLogLevelFlags log_level,
|
||||||
|
const char *strloc,
|
||||||
|
const char *function,
|
||||||
|
const char *format,
|
||||||
|
...) G_GNUC_PRINTF(4, 5);
|
||||||
|
|
||||||
|
/* FIXME: name is misleading, this aborts.. */
|
||||||
|
#define spice_return_if_fail(x) G_STMT_START { \
|
||||||
|
if G_LIKELY(x) { } else { \
|
||||||
|
spice_critical("condition `%s' failed", #x); \
|
||||||
|
return; \
|
||||||
|
} \
|
||||||
|
} G_STMT_END
|
||||||
|
|
||||||
|
/* FIXME: name is misleading, this aborts.. */
|
||||||
|
#define spice_return_val_if_fail(x, val) G_STMT_START { \
|
||||||
|
if G_LIKELY(x) { } else { \
|
||||||
|
spice_critical("condition `%s' failed", #x); \
|
||||||
|
return (val); \
|
||||||
|
} \
|
||||||
|
} G_STMT_END
|
||||||
|
|
||||||
|
#define spice_warn_if_reached() G_STMT_START { \
|
||||||
|
spice_log(G_LOG_LEVEL_WARNING, SPICE_STRLOC, __FUNCTION__, "should not be reached"); \
|
||||||
|
} G_STMT_END
|
||||||
|
|
||||||
|
#define spice_info(...) G_STMT_START { \
|
||||||
|
spice_log(G_LOG_LEVEL_INFO, SPICE_STRLOC, __FUNCTION__, "" __VA_ARGS__); \
|
||||||
|
} G_STMT_END
|
||||||
|
|
||||||
|
#define spice_debug(...) G_STMT_START { \
|
||||||
|
spice_log(G_LOG_LEVEL_DEBUG, SPICE_STRLOC, __FUNCTION__, "" __VA_ARGS__); \
|
||||||
|
} G_STMT_END
|
||||||
|
|
||||||
|
#define spice_warning(...) G_STMT_START { \
|
||||||
|
spice_log(G_LOG_LEVEL_WARNING, SPICE_STRLOC, __FUNCTION__, "" __VA_ARGS__); \
|
||||||
|
} G_STMT_END
|
||||||
|
|
||||||
|
#define spice_critical(...) G_STMT_START { \
|
||||||
|
spice_log(G_LOG_LEVEL_CRITICAL, SPICE_STRLOC, __FUNCTION__, "" __VA_ARGS__); \
|
||||||
|
SPICE_UNREACHABLE; \
|
||||||
|
} G_STMT_END
|
||||||
|
|
||||||
|
#define spice_error(...) G_STMT_START { \
|
||||||
|
spice_log(G_LOG_LEVEL_ERROR, SPICE_STRLOC, __FUNCTION__, "" __VA_ARGS__); \
|
||||||
|
SPICE_UNREACHABLE; \
|
||||||
|
} G_STMT_END
|
||||||
|
|
||||||
|
#define spice_warn_if_fail(x) G_STMT_START { \
|
||||||
|
if G_LIKELY(x) { } else { \
|
||||||
|
spice_warning("condition `%s' failed", #x); \
|
||||||
|
} \
|
||||||
|
} G_STMT_END
|
||||||
|
|
||||||
|
#define spice_assert(x) G_STMT_START { \
|
||||||
|
if G_LIKELY(x) { } else { \
|
||||||
|
spice_error("assertion `%s' failed", #x); \
|
||||||
|
} \
|
||||||
|
} G_STMT_END
|
||||||
|
|
||||||
|
#if ENABLE_EXTRA_CHECKS
|
||||||
|
enum { spice_extra_checks = 1 };
|
||||||
|
#else
|
||||||
|
enum { spice_extra_checks = 0 };
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define spice_extra_assert(x) G_STMT_START { \
|
||||||
|
if (!spice_extra_checks || G_LIKELY(x)) { } else { \
|
||||||
|
spice_error("assertion `%s' failed", #x); \
|
||||||
|
} \
|
||||||
|
} G_STMT_END
|
||||||
|
|
||||||
|
SPICE_END_DECLS
|
||||||
|
|
||||||
|
#endif // H_SPICE_COMMON_LOG
|
||||||
183
common/lz.c
183
common/lz.c
@ -43,29 +43,16 @@
|
|||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "lz.h"
|
#include "lz.h"
|
||||||
|
|
||||||
#define DEBUG
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
|
|
||||||
#define ASSERT(usr, x) \
|
|
||||||
if (!(x)) (usr)->error(usr, "%s: ASSERT %s failed\n", __FUNCTION__, #x);
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#define ASSERT(usr, x)
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define HASH_LOG 13
|
#define HASH_LOG 13
|
||||||
#define HASH_SIZE (1 << HASH_LOG)
|
#define HASH_SIZE (1 << HASH_LOG)
|
||||||
#define HASH_MASK (HASH_SIZE - 1)
|
#define HASH_MASK (HASH_SIZE - 1)
|
||||||
|
|
||||||
|
/* Maximum image size, mainly to avoid possible integer overflows */
|
||||||
|
#define SPICE_MAX_IMAGE_SIZE (1024 * 1024 * 1024 - 1)
|
||||||
|
|
||||||
typedef struct LzImageSegment LzImageSegment;
|
typedef struct LzImageSegment LzImageSegment;
|
||||||
struct LzImageSegment {
|
struct LzImageSegment {
|
||||||
@ -102,7 +89,6 @@ typedef struct Encoder {
|
|||||||
// (2) a pointer to the first byte in the segment that matches the word
|
// (2) a pointer to the first byte in the segment that matches the word
|
||||||
HashEntry htab[HASH_SIZE];
|
HashEntry htab[HASH_SIZE];
|
||||||
|
|
||||||
uint8_t *io_start;
|
|
||||||
uint8_t *io_now;
|
uint8_t *io_now;
|
||||||
uint8_t *io_end;
|
uint8_t *io_end;
|
||||||
size_t io_bytes_count;
|
size_t io_bytes_count;
|
||||||
@ -113,7 +99,7 @@ typedef struct Encoder {
|
|||||||
/****************************************************/
|
/****************************************************/
|
||||||
/* functions for managing the pool of image segments*/
|
/* functions for managing the pool of image segments*/
|
||||||
/****************************************************/
|
/****************************************************/
|
||||||
static INLINE LzImageSegment *lz_alloc_image_seg(Encoder *encoder);
|
static inline LzImageSegment *lz_alloc_image_seg(Encoder *encoder);
|
||||||
static void lz_reset_image_seg(Encoder *encoder);
|
static void lz_reset_image_seg(Encoder *encoder);
|
||||||
static int lz_read_image_segments(Encoder *encoder, uint8_t *first_lines,
|
static int lz_read_image_segments(Encoder *encoder, uint8_t *first_lines,
|
||||||
unsigned int num_first_lines);
|
unsigned int num_first_lines);
|
||||||
@ -121,7 +107,7 @@ static int lz_read_image_segments(Encoder *encoder, uint8_t *first_lines,
|
|||||||
|
|
||||||
// return a free image segment if one exists. Make allocation if needed. adds it to the
|
// return a free image segment if one exists. Make allocation if needed. adds it to the
|
||||||
// tail of the image segments lists
|
// tail of the image segments lists
|
||||||
static INLINE LzImageSegment *lz_alloc_image_seg(Encoder *encoder)
|
static inline LzImageSegment *lz_alloc_image_seg(Encoder *encoder)
|
||||||
{
|
{
|
||||||
LzImageSegment *ret;
|
LzImageSegment *ret;
|
||||||
|
|
||||||
@ -148,7 +134,7 @@ static INLINE LzImageSegment *lz_alloc_image_seg(Encoder *encoder)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// adding seg to the head of free segments (lz_reset_image_seg removes it from used ones)
|
// adding seg to the head of free segments (lz_reset_image_seg removes it from used ones)
|
||||||
static INLINE void __lz_free_image_seg(Encoder *encoder, LzImageSegment *seg)
|
static inline void __lz_free_image_seg(Encoder *encoder, LzImageSegment *seg)
|
||||||
{
|
{
|
||||||
seg->next = encoder->free_image_segs;
|
seg->next = encoder->free_image_segs;
|
||||||
encoder->free_image_segs = seg;
|
encoder->free_image_segs = seg;
|
||||||
@ -184,7 +170,7 @@ static int lz_read_image_segments(Encoder *encoder, uint8_t *first_lines,
|
|||||||
uint8_t* lines = first_lines;
|
uint8_t* lines = first_lines;
|
||||||
int row;
|
int row;
|
||||||
|
|
||||||
ASSERT(encoder->usr, !encoder->head_image_segs);
|
spice_return_val_if_fail(!encoder->head_image_segs, FALSE);
|
||||||
|
|
||||||
image_seg = lz_alloc_image_seg(encoder);
|
image_seg = lz_alloc_image_seg(encoder);
|
||||||
if (!image_seg) {
|
if (!image_seg) {
|
||||||
@ -224,7 +210,7 @@ error_1:
|
|||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
* Handling encoding and decoding of a byte
|
* Handling encoding and decoding of a byte
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
static INLINE int more_io_bytes(Encoder *encoder)
|
static inline int more_io_bytes(Encoder *encoder)
|
||||||
{
|
{
|
||||||
uint8_t *io_ptr;
|
uint8_t *io_ptr;
|
||||||
int num_io_bytes = encoder->usr->more_space(encoder->usr, &io_ptr);
|
int num_io_bytes = encoder->usr->more_space(encoder->usr, &io_ptr);
|
||||||
@ -234,20 +220,20 @@ static INLINE int more_io_bytes(Encoder *encoder)
|
|||||||
return num_io_bytes;
|
return num_io_bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
static INLINE void encode(Encoder *encoder, uint8_t byte)
|
static inline void encode(Encoder *encoder, uint8_t byte)
|
||||||
{
|
{
|
||||||
if (encoder->io_now == encoder->io_end) {
|
if (encoder->io_now == encoder->io_end) {
|
||||||
if (more_io_bytes(encoder) <= 0) {
|
if (more_io_bytes(encoder) <= 0) {
|
||||||
encoder->usr->error(encoder->usr, "%s: no more bytes\n", __FUNCTION__);
|
encoder->usr->error(encoder->usr, "%s: no more bytes\n", __FUNCTION__);
|
||||||
}
|
}
|
||||||
ASSERT(encoder->usr, encoder->io_now);
|
spice_return_if_fail(encoder->io_now);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT(encoder->usr, encoder->io_now < encoder->io_end);
|
spice_return_if_fail(encoder->io_now < encoder->io_end);
|
||||||
*(encoder->io_now++) = byte;
|
*(encoder->io_now++) = byte;
|
||||||
}
|
}
|
||||||
|
|
||||||
static INLINE void encode_32(Encoder *encoder, unsigned int word)
|
static inline void encode_32(Encoder *encoder, unsigned int word)
|
||||||
{
|
{
|
||||||
encode(encoder, (uint8_t)(word >> 24));
|
encode(encoder, (uint8_t)(word >> 24));
|
||||||
encode(encoder, (uint8_t)(word >> 16) & 0x0000ff);
|
encode(encoder, (uint8_t)(word >> 16) & 0x0000ff);
|
||||||
@ -255,37 +241,32 @@ static INLINE void encode_32(Encoder *encoder, unsigned int word)
|
|||||||
encode(encoder, (uint8_t)(word & 0x0000ff));
|
encode(encoder, (uint8_t)(word & 0x0000ff));
|
||||||
}
|
}
|
||||||
|
|
||||||
static INLINE void encode_copy_count(Encoder *encoder, uint8_t copy_count)
|
static inline void encode_copy_count(Encoder *encoder, uint8_t copy_count)
|
||||||
{
|
{
|
||||||
encode(encoder, copy_count);
|
encode(encoder, copy_count);
|
||||||
encoder->io_last_copy = encoder->io_now - 1; // io_now cannot be the first byte of the buffer
|
encoder->io_last_copy = encoder->io_now - 1; // io_now cannot be the first byte of the buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
static INLINE void update_copy_count(Encoder *encoder, uint8_t copy_count)
|
static inline void update_copy_count(Encoder *encoder, uint8_t copy_count)
|
||||||
{
|
{
|
||||||
ASSERT(encoder->usr, encoder->io_last_copy);
|
spice_return_if_fail(encoder->io_last_copy);
|
||||||
*(encoder->io_last_copy) = copy_count;
|
*(encoder->io_last_copy) = copy_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
static INLINE void encode_level(Encoder *encoder, uint8_t level_code)
|
|
||||||
{
|
|
||||||
*(encoder->io_start) |= level_code;
|
|
||||||
}
|
|
||||||
|
|
||||||
// decrease the io ptr by 1
|
// decrease the io ptr by 1
|
||||||
static INLINE void compress_output_prev(Encoder *encoder)
|
static inline void compress_output_prev(Encoder *encoder)
|
||||||
{
|
{
|
||||||
// io_now cannot be the first byte of the buffer
|
// io_now cannot be the first byte of the buffer
|
||||||
encoder->io_now--;
|
encoder->io_now--;
|
||||||
// the function should be called only when copy count is written unnecessarily by lz_compress
|
// the function should be called only when copy count is written unnecessarily by lz_compress
|
||||||
ASSERT(encoder->usr, encoder->io_now == encoder->io_last_copy)
|
spice_return_if_fail(encoder->io_now == encoder->io_last_copy);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int encoder_reset(Encoder *encoder, uint8_t *io_ptr, uint8_t *io_ptr_end)
|
static int encoder_reset(Encoder *encoder, uint8_t *io_ptr, uint8_t *io_ptr_end)
|
||||||
{
|
{
|
||||||
ASSERT(encoder->usr, io_ptr <= io_ptr_end);
|
spice_return_val_if_fail(io_ptr <= io_ptr_end, FALSE);
|
||||||
|
|
||||||
encoder->io_bytes_count = io_ptr_end - io_ptr;
|
encoder->io_bytes_count = io_ptr_end - io_ptr;
|
||||||
encoder->io_start = io_ptr;
|
|
||||||
encoder->io_now = io_ptr;
|
encoder->io_now = io_ptr;
|
||||||
encoder->io_end = io_ptr_end;
|
encoder->io_end = io_ptr_end;
|
||||||
encoder->io_last_copy = NULL;
|
encoder->io_last_copy = NULL;
|
||||||
@ -293,20 +274,20 @@ static int encoder_reset(Encoder *encoder, uint8_t *io_ptr, uint8_t *io_ptr_end)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static INLINE uint8_t decode(Encoder *encoder)
|
static inline uint8_t decode(Encoder *encoder)
|
||||||
{
|
{
|
||||||
if (encoder->io_now == encoder->io_end) {
|
if (encoder->io_now == encoder->io_end) {
|
||||||
int num_io_bytes = more_io_bytes(encoder);
|
int num_io_bytes = more_io_bytes(encoder);
|
||||||
if (num_io_bytes <= 0) {
|
if (num_io_bytes <= 0) {
|
||||||
encoder->usr->error(encoder->usr, "%s: no more bytes\n", __FUNCTION__);
|
encoder->usr->error(encoder->usr, "%s: no more bytes\n", __FUNCTION__);
|
||||||
}
|
}
|
||||||
ASSERT(encoder->usr, encoder->io_now);
|
spice_assert(encoder->io_now);
|
||||||
}
|
}
|
||||||
ASSERT(encoder->usr, encoder->io_now < encoder->io_end);
|
spice_assert(encoder->io_now < encoder->io_end);
|
||||||
return *(encoder->io_now++);
|
return *(encoder->io_now++);
|
||||||
}
|
}
|
||||||
|
|
||||||
static INLINE uint32_t decode_32(Encoder *encoder)
|
static inline uint32_t decode_32(Encoder *encoder)
|
||||||
{
|
{
|
||||||
uint32_t word = 0;
|
uint32_t word = 0;
|
||||||
word |= decode(encoder);
|
word |= decode(encoder);
|
||||||
@ -319,7 +300,7 @@ static INLINE uint32_t decode_32(Encoder *encoder)
|
|||||||
return word;
|
return word;
|
||||||
}
|
}
|
||||||
|
|
||||||
static INLINE int is_io_to_decode_end(Encoder *encoder)
|
static inline int is_io_to_decode_end(Encoder *encoder)
|
||||||
{
|
{
|
||||||
if (encoder->io_now != encoder->io_end) {
|
if (encoder->io_now != encoder->io_end) {
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@ -393,30 +374,23 @@ void lz_destroy(LzContext *lz)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#ifdef __GNUC__
|
#include <spice/start-packed.h>
|
||||||
#define ATTR_PACKED __attribute__ ((__packed__))
|
|
||||||
#else
|
|
||||||
#define ATTR_PACKED
|
|
||||||
#pragma pack(push)
|
|
||||||
#pragma pack(1)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/* the palette images will be treated as one byte pixels. Their width should be transformed
|
/* the palette images will be treated as one byte pixels. Their width should be transformed
|
||||||
accordingly.
|
accordingly.
|
||||||
*/
|
*/
|
||||||
typedef struct ATTR_PACKED one_byte_pixel_t {
|
typedef struct SPICE_ATTR_PACKED one_byte_pixel_t {
|
||||||
uint8_t a;
|
uint8_t a;
|
||||||
} one_byte_pixel_t;
|
} one_byte_pixel_t;
|
||||||
|
|
||||||
typedef struct ATTR_PACKED rgb32_pixel_t {
|
typedef struct SPICE_ATTR_PACKED rgb32_pixel_t {
|
||||||
uint8_t b;
|
uint8_t b;
|
||||||
uint8_t g;
|
uint8_t g;
|
||||||
uint8_t r;
|
uint8_t r;
|
||||||
uint8_t pad;
|
uint8_t pad;
|
||||||
} rgb32_pixel_t;
|
} rgb32_pixel_t;
|
||||||
|
|
||||||
typedef struct ATTR_PACKED rgb24_pixel_t {
|
typedef struct SPICE_ATTR_PACKED rgb24_pixel_t {
|
||||||
uint8_t b;
|
uint8_t b;
|
||||||
uint8_t g;
|
uint8_t g;
|
||||||
uint8_t r;
|
uint8_t r;
|
||||||
@ -424,11 +398,7 @@ typedef struct ATTR_PACKED rgb24_pixel_t {
|
|||||||
|
|
||||||
typedef uint16_t rgb16_pixel_t;
|
typedef uint16_t rgb16_pixel_t;
|
||||||
|
|
||||||
#ifndef __GNUC__
|
#include <spice/end-packed.h>
|
||||||
#pragma pack(pop)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#undef ATTR_PACKED
|
|
||||||
|
|
||||||
|
|
||||||
#define MAX_COPY 32
|
#define MAX_COPY 32
|
||||||
@ -476,6 +446,13 @@ typedef uint16_t rgb16_pixel_t;
|
|||||||
#define TO_RGB32
|
#define TO_RGB32
|
||||||
#include "lz_decompress_tmpl.c"
|
#include "lz_decompress_tmpl.c"
|
||||||
|
|
||||||
|
#define LZ_A8
|
||||||
|
#include "lz_compress_tmpl.c"
|
||||||
|
#define LZ_A8
|
||||||
|
#include "lz_decompress_tmpl.c"
|
||||||
|
#define LZ_A8
|
||||||
|
#define TO_RGB32
|
||||||
|
#include "lz_decompress_tmpl.c"
|
||||||
|
|
||||||
#define LZ_RGB16
|
#define LZ_RGB16
|
||||||
#include "lz_compress_tmpl.c"
|
#include "lz_compress_tmpl.c"
|
||||||
@ -504,6 +481,44 @@ typedef uint16_t rgb16_pixel_t;
|
|||||||
#undef LZ_UNEXPECT_CONDITIONAL
|
#undef LZ_UNEXPECT_CONDITIONAL
|
||||||
#undef LZ_EXPECT_CONDITIONAL
|
#undef LZ_EXPECT_CONDITIONAL
|
||||||
|
|
||||||
|
static void lz_set_sizes(Encoder *encoder, int type, int width, int height, int stride)
|
||||||
|
{
|
||||||
|
if (width < 0) {
|
||||||
|
encoder->usr->error(encoder->usr, "invalid lz width %d\n", width);
|
||||||
|
}
|
||||||
|
if (height < 0) {
|
||||||
|
encoder->usr->error(encoder->usr, "invalid lz height %d\n", height);
|
||||||
|
}
|
||||||
|
if (stride < 0) {
|
||||||
|
encoder->usr->error(encoder->usr, "invalid lz stride %d\n", stride);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IS_IMAGE_TYPE_PLT[type]) {
|
||||||
|
if (stride > (width / PLT_PIXELS_PER_BYTE[type])) {
|
||||||
|
if (((width % PLT_PIXELS_PER_BYTE[type]) == 0) || (
|
||||||
|
(stride - (width / PLT_PIXELS_PER_BYTE[type])) > 1)) {
|
||||||
|
encoder->usr->error(encoder->usr, "stride overflows (plt)\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (stride != width * RGB_BYTES_PER_PIXEL[type]) {
|
||||||
|
encoder->usr->error(encoder->usr, "stride != width*bytes_per_pixel (rgb) %d != %d * %d (%d)\n",
|
||||||
|
stride, width, RGB_BYTES_PER_PIXEL[type],
|
||||||
|
type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// avoid too big images
|
||||||
|
if ((uint64_t) stride * height > SPICE_MAX_IMAGE_SIZE) {
|
||||||
|
encoder->usr->error(encoder->usr, "image too large\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
encoder->type = type;
|
||||||
|
encoder->width = width;
|
||||||
|
encoder->height = height;
|
||||||
|
encoder->stride = stride;
|
||||||
|
}
|
||||||
|
|
||||||
int lz_encode(LzContext *lz, LzImageType type, int width, int height, int top_down,
|
int lz_encode(LzContext *lz, LzImageType type, int width, int height, int top_down,
|
||||||
uint8_t *lines, unsigned int num_lines, int stride,
|
uint8_t *lines, unsigned int num_lines, int stride,
|
||||||
uint8_t *io_ptr, unsigned int num_io_bytes)
|
uint8_t *io_ptr, unsigned int num_io_bytes)
|
||||||
@ -511,23 +526,7 @@ int lz_encode(LzContext *lz, LzImageType type, int width, int height, int top_do
|
|||||||
Encoder *encoder = (Encoder *)lz;
|
Encoder *encoder = (Encoder *)lz;
|
||||||
uint8_t *io_ptr_end = io_ptr + num_io_bytes;
|
uint8_t *io_ptr_end = io_ptr + num_io_bytes;
|
||||||
|
|
||||||
encoder->type = type;
|
lz_set_sizes(encoder, type, width, height, stride);
|
||||||
encoder->width = width;
|
|
||||||
encoder->height = height;
|
|
||||||
encoder->stride = stride;
|
|
||||||
|
|
||||||
if (IS_IMAGE_TYPE_PLT[encoder->type]) {
|
|
||||||
if (encoder->stride > (width / PLT_PIXELS_PER_BYTE[encoder->type])) {
|
|
||||||
if (((width % PLT_PIXELS_PER_BYTE[encoder->type]) == 0) || (
|
|
||||||
(encoder->stride - (width / PLT_PIXELS_PER_BYTE[encoder->type])) > 1)) {
|
|
||||||
encoder->usr->error(encoder->usr, "stride overflows (plt)\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (encoder->stride != width * RGB_BYTES_PER_PIXEL[encoder->type]) {
|
|
||||||
encoder->usr->error(encoder->usr, "stride != width*bytes_per_pixel (rgb)\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// assign the output buffer
|
// assign the output buffer
|
||||||
if (!encoder_reset(encoder, io_ptr, io_ptr_end)) {
|
if (!encoder_reset(encoder, io_ptr, io_ptr_end)) {
|
||||||
@ -571,6 +570,9 @@ int lz_encode(LzContext *lz, LzImageType type, int width, int height, int top_do
|
|||||||
case LZ_IMAGE_TYPE_XXXA:
|
case LZ_IMAGE_TYPE_XXXA:
|
||||||
lz_rgb_alpha_compress(encoder);
|
lz_rgb_alpha_compress(encoder);
|
||||||
break;
|
break;
|
||||||
|
case LZ_IMAGE_TYPE_A8:
|
||||||
|
lz_a8_compress(encoder);
|
||||||
|
break;
|
||||||
case LZ_IMAGE_TYPE_INVALID:
|
case LZ_IMAGE_TYPE_INVALID:
|
||||||
default:
|
default:
|
||||||
encoder->usr->error(encoder->usr, "bad image type\n");
|
encoder->usr->error(encoder->usr, "bad image type\n");
|
||||||
@ -610,10 +612,15 @@ void lz_decode_begin(LzContext *lz, uint8_t *io_ptr, unsigned int num_io_bytes,
|
|||||||
encoder->usr->error(encoder->usr, "bad version\n");
|
encoder->usr->error(encoder->usr, "bad version\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
encoder->type = (LzImageType)decode_32(encoder);
|
int type = decode_32(encoder);
|
||||||
encoder->width = decode_32(encoder);
|
if (type <= LZ_IMAGE_TYPE_INVALID || type > LZ_IMAGE_TYPE_A8) {
|
||||||
encoder->height = decode_32(encoder);
|
encoder->usr->error(encoder->usr, "invalid lz type %d\n", type);
|
||||||
encoder->stride = decode_32(encoder);
|
}
|
||||||
|
int width = decode_32(encoder);
|
||||||
|
int height = decode_32(encoder);
|
||||||
|
int stride = decode_32(encoder);
|
||||||
|
lz_set_sizes(encoder, type, width, height, stride);
|
||||||
|
|
||||||
*out_top_down = decode_32(encoder);
|
*out_top_down = decode_32(encoder);
|
||||||
|
|
||||||
*out_width = encoder->width;
|
*out_width = encoder->width;
|
||||||
@ -646,6 +653,7 @@ void lz_decode(LzContext *lz, LzImageType to_type, uint8_t *buf)
|
|||||||
if (!encoder->palette) {
|
if (!encoder->palette) {
|
||||||
encoder->usr->error(encoder->usr,
|
encoder->usr->error(encoder->usr,
|
||||||
"a palette is missing (for bpp to rgb decoding)\n");
|
"a palette is missing (for bpp to rgb decoding)\n");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
switch (encoder->type) {
|
switch (encoder->type) {
|
||||||
case LZ_IMAGE_TYPE_PLT1_BE:
|
case LZ_IMAGE_TYPE_PLT1_BE:
|
||||||
@ -707,7 +715,7 @@ void lz_decode(LzContext *lz, LzImageType to_type, uint8_t *buf)
|
|||||||
if (encoder->type == to_type) {
|
if (encoder->type == to_type) {
|
||||||
out_size = lz_rgb32_decompress(encoder, (rgb32_pixel_t *)buf, size);
|
out_size = lz_rgb32_decompress(encoder, (rgb32_pixel_t *)buf, size);
|
||||||
alpha_size = lz_rgb_alpha_decompress(encoder, (rgb32_pixel_t *)buf, size);
|
alpha_size = lz_rgb_alpha_decompress(encoder, (rgb32_pixel_t *)buf, size);
|
||||||
ASSERT(encoder->usr, alpha_size == size);
|
spice_assert(alpha_size == size);
|
||||||
} else {
|
} else {
|
||||||
encoder->usr->error(encoder->usr, "unsupported output format\n");
|
encoder->usr->error(encoder->usr, "unsupported output format\n");
|
||||||
}
|
}
|
||||||
@ -720,6 +728,17 @@ void lz_decode(LzContext *lz, LzImageType to_type, uint8_t *buf)
|
|||||||
encoder->usr->error(encoder->usr, "unsupported output format\n");
|
encoder->usr->error(encoder->usr, "unsupported output format\n");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case LZ_IMAGE_TYPE_A8:
|
||||||
|
if (encoder->type == to_type) {
|
||||||
|
alpha_size = lz_a8_decompress(encoder, (one_byte_pixel_t *)buf, size);
|
||||||
|
out_size = alpha_size;
|
||||||
|
} else if (to_type == LZ_IMAGE_TYPE_RGB32) {
|
||||||
|
alpha_size = lz_a8_to_rgb32_decompress(encoder, (rgb32_pixel_t *)buf, size);
|
||||||
|
out_size = alpha_size;
|
||||||
|
} else {
|
||||||
|
encoder->usr->error(encoder->usr, "unsupported output format\n");
|
||||||
|
}
|
||||||
|
break;
|
||||||
case LZ_IMAGE_TYPE_PLT1_LE:
|
case LZ_IMAGE_TYPE_PLT1_LE:
|
||||||
case LZ_IMAGE_TYPE_PLT1_BE:
|
case LZ_IMAGE_TYPE_PLT1_BE:
|
||||||
case LZ_IMAGE_TYPE_PLT4_LE:
|
case LZ_IMAGE_TYPE_PLT4_LE:
|
||||||
@ -731,8 +750,8 @@ void lz_decode(LzContext *lz, LzImageType to_type, uint8_t *buf)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT(encoder->usr, is_io_to_decode_end(encoder));
|
spice_assert(is_io_to_decode_end(encoder));
|
||||||
ASSERT(encoder->usr, out_size == size);
|
spice_assert(out_size == size);
|
||||||
|
|
||||||
if (out_size != size) {
|
if (out_size != size) {
|
||||||
encoder->usr->error(encoder->usr, "bad decode size\n");
|
encoder->usr->error(encoder->usr, "bad decode size\n");
|
||||||
|
|||||||
24
common/lz.h
24
common/lz.h
@ -3,24 +3,26 @@
|
|||||||
dictionary compression for images based on fastlz (http://www.fastlz.org/)
|
dictionary compression for images based on fastlz (http://www.fastlz.org/)
|
||||||
(Distributed under MIT license).
|
(Distributed under MIT license).
|
||||||
*/
|
*/
|
||||||
#ifndef __LZ_H
|
#ifndef H_SPICE_COMMON_LZ
|
||||||
#define __LZ_H
|
#define H_SPICE_COMMON_LZ
|
||||||
|
|
||||||
|
#include <spice/macros.h>
|
||||||
|
|
||||||
#include "lz_common.h"
|
#include "lz_common.h"
|
||||||
#include "lz_config.h"
|
#include "lz_config.h"
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
|
#include "macros.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
SPICE_BEGIN_DECLS
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef void *LzContext;
|
typedef void *LzContext;
|
||||||
|
|
||||||
typedef struct LzUsrContext LzUsrContext;
|
typedef struct LzUsrContext LzUsrContext;
|
||||||
struct LzUsrContext {
|
struct LzUsrContext {
|
||||||
void (*error)(LzUsrContext *usr, const char *fmt, ...);
|
SPICE_GNUC_NORETURN
|
||||||
void (*warn)(LzUsrContext *usr, const char *fmt, ...);
|
SPICE_GNUC_PRINTF(2, 3) void (*error)(LzUsrContext *usr, const char *fmt, ...);
|
||||||
void (*info)(LzUsrContext *usr, const char *fmt, ...);
|
SPICE_GNUC_PRINTF(2, 3) void (*warn)(LzUsrContext *usr, const char *fmt, ...);
|
||||||
|
SPICE_GNUC_PRINTF(2, 3) void (*info)(LzUsrContext *usr, const char *fmt, ...);
|
||||||
void *(*malloc)(LzUsrContext *usr, int size);
|
void *(*malloc)(LzUsrContext *usr, int size);
|
||||||
void (*free)(LzUsrContext *usr, void *ptr);
|
void (*free)(LzUsrContext *usr, void *ptr);
|
||||||
int (*more_space)(LzUsrContext *usr, uint8_t **io_ptr); // get the next chunk of the
|
int (*more_space)(LzUsrContext *usr, uint8_t **io_ptr); // get the next chunk of the
|
||||||
@ -75,8 +77,6 @@ LzContext *lz_create(LzUsrContext *usr);
|
|||||||
|
|
||||||
void lz_destroy(LzContext *lz);
|
void lz_destroy(LzContext *lz);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
SPICE_END_DECLS
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // __LZ_H
|
#endif // H_SPICE_COMMON_LZ
|
||||||
|
|||||||
@ -20,14 +20,13 @@
|
|||||||
|
|
||||||
/*common header for encoder and decoder*/
|
/*common header for encoder and decoder*/
|
||||||
|
|
||||||
#ifndef _LZ_COMMON_H
|
#ifndef H_SPICE_COMMON_LZ_COMMON
|
||||||
#define _LZ_COMMON_H
|
#define H_SPICE_COMMON_LZ_COMMON
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#include <spice/macros.h>
|
||||||
extern "C" {
|
#include "verify.h"
|
||||||
#endif
|
|
||||||
|
|
||||||
//#define DEBUG
|
SPICE_BEGIN_DECLS
|
||||||
|
|
||||||
/* change the max window size will require change in the encoding format*/
|
/* change the max window size will require change in the encoding format*/
|
||||||
#define LZ_MAX_WINDOW_SIZE (1 << 25)
|
#define LZ_MAX_WINDOW_SIZE (1 << 25)
|
||||||
@ -44,26 +43,30 @@ typedef enum {
|
|||||||
LZ_IMAGE_TYPE_RGB24,
|
LZ_IMAGE_TYPE_RGB24,
|
||||||
LZ_IMAGE_TYPE_RGB32,
|
LZ_IMAGE_TYPE_RGB32,
|
||||||
LZ_IMAGE_TYPE_RGBA,
|
LZ_IMAGE_TYPE_RGBA,
|
||||||
LZ_IMAGE_TYPE_XXXA
|
LZ_IMAGE_TYPE_XXXA,
|
||||||
|
LZ_IMAGE_TYPE_A8
|
||||||
} LzImageType;
|
} LzImageType;
|
||||||
|
|
||||||
#define LZ_IMAGE_TYPE_MASK 0x0f
|
#define LZ_IMAGE_TYPE_MASK 0x0f
|
||||||
#define LZ_IMAGE_TYPE_LOG 4 // number of bits required for coding the image type
|
#define LZ_IMAGE_TYPE_LOG 4 // number of bits required for coding the image type
|
||||||
|
|
||||||
/* access to the arrays is based on the image types */
|
/* access to the arrays is based on the image types */
|
||||||
static const int IS_IMAGE_TYPE_PLT[] = {0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0};
|
static const int IS_IMAGE_TYPE_PLT[] = {0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0};
|
||||||
static const int IS_IMAGE_TYPE_RGB[] = {0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1};
|
static const int IS_IMAGE_TYPE_RGB[] = {0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1};
|
||||||
static const int PLT_PIXELS_PER_BYTE[] = {0, 8, 8, 2, 2, 1};
|
static const int PLT_PIXELS_PER_BYTE[] = {0, 8, 8, 2, 2, 1};
|
||||||
static const int RGB_BYTES_PER_PIXEL[] = {0, 1, 1, 1, 1, 1, 2, 3, 4, 4, 4};
|
static const int RGB_BYTES_PER_PIXEL[] = {0, 1, 1, 1, 1, 1, 2, 3, 4, 4, 4, 1};
|
||||||
|
|
||||||
|
verify(SPICE_N_ELEMENTS(IS_IMAGE_TYPE_PLT) == (LZ_IMAGE_TYPE_A8 + 1));
|
||||||
|
verify(SPICE_N_ELEMENTS(IS_IMAGE_TYPE_RGB) == (LZ_IMAGE_TYPE_A8 + 1));
|
||||||
|
verify(SPICE_N_ELEMENTS(PLT_PIXELS_PER_BYTE) == (LZ_IMAGE_TYPE_PLT8 + 1));
|
||||||
|
verify(SPICE_N_ELEMENTS(RGB_BYTES_PER_PIXEL) == (LZ_IMAGE_TYPE_A8 + 1));
|
||||||
|
|
||||||
#define LZ_MAGIC (*(uint32_t *)"LZ ")
|
/* ASCII "LZ " */
|
||||||
|
#define LZ_MAGIC 0x20205a4c
|
||||||
#define LZ_VERSION_MAJOR 1U
|
#define LZ_VERSION_MAJOR 1U
|
||||||
#define LZ_VERSION_MINOR 1U
|
#define LZ_VERSION_MINOR 1U
|
||||||
#define LZ_VERSION ((LZ_VERSION_MAJOR << 16) | (LZ_VERSION_MINOR & 0xffff))
|
#define LZ_VERSION ((LZ_VERSION_MAJOR << 16) | (LZ_VERSION_MINOR & 0xffff))
|
||||||
|
|
||||||
#ifdef __cplusplus
|
SPICE_END_DECLS
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // _LZ_COMMON_H
|
#endif // H_SPICE_COMMON_LZ_COMMON
|
||||||
|
|||||||
@ -40,11 +40,9 @@
|
|||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#endif
|
|
||||||
|
|
||||||
#define DJB2_START 5381;
|
#define DJB2_START 5381
|
||||||
#define DJB2_HASH(hash, c) (hash = ((hash << 5) + hash) ^ (c)) //|{hash = ((hash << 5) + hash) + c;}
|
#define DJB2_HASH(hash, c) (hash = ((hash << 5) + hash) ^ (c)) //|{hash = ((hash << 5) + hash) + c;}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -71,6 +69,21 @@
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef LZ_A8
|
||||||
|
#define PIXEL one_byte_pixel_t
|
||||||
|
#define FNAME(name) lz_a8_##name
|
||||||
|
#define ENCODE_PIXEL(e, pix) encode(e, (pix).a) // gets the pixel and write only the needed bytes
|
||||||
|
// from the pixel
|
||||||
|
#define SAME_PIXEL(pix1, pix2) ((pix1).a == (pix2).a)
|
||||||
|
#define HASH_FUNC(v, p) { \
|
||||||
|
v = DJB2_START; \
|
||||||
|
DJB2_HASH(v, p[0].a); \
|
||||||
|
DJB2_HASH(v, p[1].a); \
|
||||||
|
DJB2_HASH(v, p[2].a); \
|
||||||
|
v &= HASH_MASK; \
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef LZ_RGB_ALPHA
|
#ifdef LZ_RGB_ALPHA
|
||||||
//#undef LZ_RGB_ALPHA
|
//#undef LZ_RGB_ALPHA
|
||||||
#define PIXEL rgb32_pixel_t
|
#define PIXEL rgb32_pixel_t
|
||||||
@ -90,9 +103,8 @@
|
|||||||
#ifdef LZ_RGB16
|
#ifdef LZ_RGB16
|
||||||
#define PIXEL rgb16_pixel_t
|
#define PIXEL rgb16_pixel_t
|
||||||
#define FNAME(name) lz_rgb16_##name
|
#define FNAME(name) lz_rgb16_##name
|
||||||
#define GET_r(pix) (((pix) >> 10) & 0x1f)
|
#define GET_rgb(pix) ((pix) & 0x7fffu)
|
||||||
#define GET_g(pix) (((pix) >> 5) & 0x1f)
|
#define SAME_PIXEL(p1, p2) (GET_rgb(p1) == GET_rgb(p2))
|
||||||
#define GET_b(pix) ((pix) & 0x1f)
|
|
||||||
#define ENCODE_PIXEL(e, pix) {encode(e, (pix) >> 8); encode(e, (pix) & 0xff);}
|
#define ENCODE_PIXEL(e, pix) {encode(e, (pix) >> 8); encode(e, (pix) & 0xff);}
|
||||||
|
|
||||||
#define HASH_FUNC(v, p) { \
|
#define HASH_FUNC(v, p) { \
|
||||||
@ -110,20 +122,17 @@
|
|||||||
#ifdef LZ_RGB24
|
#ifdef LZ_RGB24
|
||||||
#define PIXEL rgb24_pixel_t
|
#define PIXEL rgb24_pixel_t
|
||||||
#define FNAME(name) lz_rgb24_##name
|
#define FNAME(name) lz_rgb24_##name
|
||||||
#define ENCODE_PIXEL(e, pix) {encode(e, (pix).b); encode(e, (pix).g); encode(e, (pix).r);}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef LZ_RGB32
|
#ifdef LZ_RGB32
|
||||||
#define PIXEL rgb32_pixel_t
|
#define PIXEL rgb32_pixel_t
|
||||||
#define FNAME(name) lz_rgb32_##name
|
#define FNAME(name) lz_rgb32_##name
|
||||||
#define ENCODE_PIXEL(e, pix) {encode(e, (pix).b); encode(e, (pix).g); encode(e, (pix).r);}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#if defined(LZ_RGB24) || defined(LZ_RGB32)
|
#if defined(LZ_RGB24) || defined(LZ_RGB32)
|
||||||
#define GET_r(pix) ((pix).r)
|
#define ENCODE_PIXEL(e, pix) {encode(e, (pix).b); encode(e, (pix).g); encode(e, (pix).r);}
|
||||||
#define GET_g(pix) ((pix).g)
|
#define SAME_PIXEL(p1, p2) ((p1).r == (p2).r && (p1).g == (p2).g && (p1).b == (p2).b)
|
||||||
#define GET_b(pix) ((pix).b)
|
|
||||||
#define HASH_FUNC(v, p) { \
|
#define HASH_FUNC(v, p) { \
|
||||||
v = DJB2_START; \
|
v = DJB2_START; \
|
||||||
DJB2_HASH(v, p[0].r); \
|
DJB2_HASH(v, p[0].r); \
|
||||||
@ -139,12 +148,6 @@
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(LZ_RGB16) || defined(LZ_RGB24) || defined(LZ_RGB32)
|
|
||||||
#define SAME_PIXEL(p1, p2) (GET_r(p1) == GET_r(p2) && GET_g(p1) == GET_g(p2) && \
|
|
||||||
GET_b(p1) == GET_b(p2))
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define PIXEL_ID(pix_ptr, seg_ptr) (pix_ptr - ((PIXEL *)seg_ptr->lines) + seg_ptr->size_delta)
|
#define PIXEL_ID(pix_ptr, seg_ptr) (pix_ptr - ((PIXEL *)seg_ptr->lines) + seg_ptr->size_delta)
|
||||||
|
|
||||||
// when encoding, the ref can be in previous segment, and we should check that it doesn't
|
// when encoding, the ref can be in previous segment, and we should check that it doesn't
|
||||||
@ -177,7 +180,7 @@ static void FNAME(compress_seg)(Encoder *encoder, LzImageSegment *seg, PIXEL *fr
|
|||||||
size_t distance;
|
size_t distance;
|
||||||
|
|
||||||
/* minimum match length */
|
/* minimum match length */
|
||||||
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA)
|
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA) || defined(LZ_A8)
|
||||||
size_t len = 3;
|
size_t len = 3;
|
||||||
#elif defined(LZ_RGB16)
|
#elif defined(LZ_RGB16)
|
||||||
size_t len = 2;
|
size_t len = 2;
|
||||||
@ -199,9 +202,7 @@ static void FNAME(compress_seg)(Encoder *encoder, LzImageSegment *seg, PIXEL *fr
|
|||||||
ip += 3;
|
ip += 3;
|
||||||
ref = anchor + 2;
|
ref = anchor + 2;
|
||||||
ref_limit = (PIXEL *)(seg->lines_end);
|
ref_limit = (PIXEL *)(seg->lines_end);
|
||||||
#if defined(LZ_RGB16) || defined(LZ_RGB24) || defined(LZ_RGB32)
|
|
||||||
len = 3;
|
|
||||||
#endif
|
|
||||||
goto match;
|
goto match;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -234,7 +235,7 @@ static void FNAME(compress_seg)(Encoder *encoder, LzImageSegment *seg, PIXEL *fr
|
|||||||
ip++;
|
ip++;
|
||||||
|
|
||||||
/* minimum match length for rgb16 is 2 and for plt and alpha is 3 */
|
/* minimum match length for rgb16 is 2 and for plt and alpha is 3 */
|
||||||
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA) || defined(LZ_RGB16)
|
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA) || defined(LZ_RGB16) || defined(LZ_A8)
|
||||||
if (!SAME_PIXEL(*ref, *ip)) {
|
if (!SAME_PIXEL(*ref, *ip)) {
|
||||||
ref++;
|
ref++;
|
||||||
ip++;
|
ip++;
|
||||||
@ -244,7 +245,7 @@ static void FNAME(compress_seg)(Encoder *encoder, LzImageSegment *seg, PIXEL *fr
|
|||||||
ip++;
|
ip++;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA)
|
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA) || defined(LZ_A8)
|
||||||
if (!SAME_PIXEL(*ref, *ip)) {
|
if (!SAME_PIXEL(*ref, *ip)) {
|
||||||
ref++;
|
ref++;
|
||||||
ip++;
|
ip++;
|
||||||
@ -255,7 +256,7 @@ static void FNAME(compress_seg)(Encoder *encoder, LzImageSegment *seg, PIXEL *fr
|
|||||||
#endif
|
#endif
|
||||||
/* far, needs at least 5-byte match */
|
/* far, needs at least 5-byte match */
|
||||||
if (distance >= MAX_DISTANCE) {
|
if (distance >= MAX_DISTANCE) {
|
||||||
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA)
|
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA) || defined(LZ_A8)
|
||||||
if (ref >= (ref_limit - 1)) {
|
if (ref >= (ref_limit - 1)) {
|
||||||
goto literal;
|
goto literal;
|
||||||
}
|
}
|
||||||
@ -272,7 +273,7 @@ static void FNAME(compress_seg)(Encoder *encoder, LzImageSegment *seg, PIXEL *fr
|
|||||||
ref++;
|
ref++;
|
||||||
ip++;
|
ip++;
|
||||||
len++;
|
len++;
|
||||||
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA)
|
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA) || defined(LZ_A8)
|
||||||
if (!SAME_PIXEL(*ref, *ip)) {
|
if (!SAME_PIXEL(*ref, *ip)) {
|
||||||
ref++;
|
ref++;
|
||||||
ip++;
|
ip++;
|
||||||
@ -310,7 +311,6 @@ match: // RLE or dictionary (both are encoded by distance from ref (-1) a
|
|||||||
// TODO: maybe separate a run from the same seg or from different ones in order
|
// TODO: maybe separate a run from the same seg or from different ones in order
|
||||||
// to spare ref < ref_limit and that way we can also perform 8 calls of
|
// to spare ref < ref_limit and that way we can also perform 8 calls of
|
||||||
// (ref++ != ip++) outside a loop
|
// (ref++ != ip++) outside a loop
|
||||||
for (;;) {
|
|
||||||
while ((ip < ip_bound) && (ref < ref_limit)) {
|
while ((ip < ip_bound) && (ref < ref_limit)) {
|
||||||
if (!SAME_PIXEL(*ref, *ip)) {
|
if (!SAME_PIXEL(*ref, *ip)) {
|
||||||
ref++;
|
ref++;
|
||||||
@ -321,8 +321,6 @@ match: // RLE or dictionary (both are encoded by distance from ref (-1) a
|
|||||||
ip++;
|
ip++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if we have copied something, adjust the copy count */
|
/* if we have copied something, adjust the copy count */
|
||||||
@ -393,27 +391,23 @@ match: // RLE or dictionary (both are encoded by distance from ref (-1) a
|
|||||||
|
|
||||||
/* update the hash at match boundary */
|
/* update the hash at match boundary */
|
||||||
#if defined(LZ_RGB16) || defined(LZ_RGB24) || defined(LZ_RGB32)
|
#if defined(LZ_RGB16) || defined(LZ_RGB24) || defined(LZ_RGB32)
|
||||||
if (ip > anchor) {
|
if (ip > anchor)
|
||||||
#endif
|
#endif
|
||||||
|
{
|
||||||
HASH_FUNC(hval, ip);
|
HASH_FUNC(hval, ip);
|
||||||
encoder->htab[hval].ref = (uint8_t *)ip;
|
encoder->htab[hval].ref = (uint8_t *)ip;
|
||||||
ip++;
|
|
||||||
encoder->htab[hval].image_seg = seg;
|
encoder->htab[hval].image_seg = seg;
|
||||||
#if defined(LZ_RGB16) || defined(LZ_RGB24) || defined(LZ_RGB32)
|
|
||||||
} else {ip++;
|
|
||||||
}
|
}
|
||||||
#endif
|
ip++;
|
||||||
#if defined(LZ_RGB24) || defined(LZ_RGB32)
|
#if defined(LZ_RGB24) || defined(LZ_RGB32)
|
||||||
if (ip > anchor) {
|
if (ip > anchor)
|
||||||
#endif
|
#endif
|
||||||
|
{
|
||||||
HASH_FUNC(hval, ip);
|
HASH_FUNC(hval, ip);
|
||||||
encoder->htab[hval].ref = (uint8_t *)ip;
|
encoder->htab[hval].ref = (uint8_t *)ip;
|
||||||
ip++;
|
|
||||||
encoder->htab[hval].image_seg = seg;
|
encoder->htab[hval].image_seg = seg;
|
||||||
#if defined(LZ_RGB24) || defined(LZ_RGB32)
|
|
||||||
} else {ip++;
|
|
||||||
}
|
}
|
||||||
#endif
|
ip++;
|
||||||
/* assuming literal copy */
|
/* assuming literal copy */
|
||||||
encode_copy_count(encoder, MAX_COPY - 1);
|
encode_copy_count(encoder, MAX_COPY - 1);
|
||||||
continue;
|
continue;
|
||||||
@ -513,17 +507,11 @@ static void FNAME(compress)(Encoder *encoder)
|
|||||||
#undef PIXEL
|
#undef PIXEL
|
||||||
#undef ENCODE_PIXEL
|
#undef ENCODE_PIXEL
|
||||||
#undef SAME_PIXEL
|
#undef SAME_PIXEL
|
||||||
#undef LZ_READU16
|
|
||||||
#undef HASH_FUNC
|
#undef HASH_FUNC
|
||||||
#undef BYTES_TO_16
|
#undef GET_rgb
|
||||||
#undef HASH_FUNC_16
|
|
||||||
#undef GET_r
|
|
||||||
#undef GET_g
|
|
||||||
#undef GET_b
|
|
||||||
#undef GET_CODE
|
|
||||||
#undef LZ_PLT
|
#undef LZ_PLT
|
||||||
#undef LZ_RGB_ALPHA
|
#undef LZ_RGB_ALPHA
|
||||||
#undef LZ_RGB16
|
#undef LZ_RGB16
|
||||||
#undef LZ_RGB24
|
#undef LZ_RGB24
|
||||||
#undef LZ_RGB32
|
#undef LZ_RGB32
|
||||||
#undef HASH_FUNC2
|
#undef LZ_A8
|
||||||
|
|||||||
@ -18,8 +18,8 @@
|
|||||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __LZ_CONFIG_H
|
#ifndef H_SPICE_COMMON_LZ_CONFIG
|
||||||
#define __LZ_CONFIG_H
|
#define H_SPICE_COMMON_LZ_CONFIG
|
||||||
|
|
||||||
#include <spice/types.h>
|
#include <spice/types.h>
|
||||||
#include <spice/macros.h>
|
#include <spice/macros.h>
|
||||||
@ -36,4 +36,4 @@
|
|||||||
#endif // QXLDD
|
#endif // QXLDD
|
||||||
#endif //__GNUC__
|
#endif //__GNUC__
|
||||||
|
|
||||||
#endif //__LZ_CONFIG_H
|
#endif // H_SPICE_COMMON_LZ_CONFIG
|
||||||
|
|||||||
@ -59,9 +59,7 @@
|
|||||||
COPY_COMP_PIXEL(encoder, out) - copies pixel from the compressed buffer to the decompressed
|
COPY_COMP_PIXEL(encoder, out) - copies pixel from the compressed buffer to the decompressed
|
||||||
buffer. Increases out.
|
buffer. Increases out.
|
||||||
*/
|
*/
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(LZ_RGB_ALPHA)
|
#if !defined(LZ_RGB_ALPHA)
|
||||||
#define COPY_PIXEL(p, out) (*out++ = p)
|
#define COPY_PIXEL(p, out) (*out++ = p)
|
||||||
@ -153,6 +151,26 @@
|
|||||||
#endif // TO_RGB32
|
#endif // TO_RGB32
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef CAST_PLT_DISTANCE
|
||||||
|
#define CAST_PLT_DISTANCE(dist) (dist)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef LZ_A8
|
||||||
|
#ifndef TO_RGB32
|
||||||
|
#define OUT_PIXEL one_byte_pixel_t
|
||||||
|
#define FNAME(name) lz_a8_##name
|
||||||
|
#define COPY_COMP_PIXEL(encoder, out) {out->a = decode(encoder); out++;}
|
||||||
|
#else // TO_RGB32
|
||||||
|
#define OUT_PIXEL rgb32_pixel_t
|
||||||
|
#define FNAME(name) lz_a8_to_rgb32_##name
|
||||||
|
#define COPY_COMP_PIXEL(encoder, out) { \
|
||||||
|
(out)->b = (out)->g = (out)->r = 0; \
|
||||||
|
(out)->pad = decode(encoder); \
|
||||||
|
(out)++; \
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef LZ_RGB16
|
#ifdef LZ_RGB16
|
||||||
#ifndef TO_RGB32
|
#ifndef TO_RGB32
|
||||||
#define OUT_PIXEL rgb16_pixel_t
|
#define OUT_PIXEL rgb16_pixel_t
|
||||||
@ -204,18 +222,18 @@
|
|||||||
static size_t FNAME(decompress)(Encoder *encoder, OUT_PIXEL *out_buf, int size)
|
static size_t FNAME(decompress)(Encoder *encoder, OUT_PIXEL *out_buf, int size)
|
||||||
{
|
{
|
||||||
OUT_PIXEL *op = out_buf;
|
OUT_PIXEL *op = out_buf;
|
||||||
OUT_PIXEL *op_limit = out_buf + size;
|
OUT_PIXEL *const op_limit = out_buf + size;
|
||||||
uint32_t ctrl = decode(encoder);
|
|
||||||
int loop = TRUE;
|
|
||||||
|
|
||||||
do {
|
for (;;) {
|
||||||
const OUT_PIXEL *ref = op;
|
uint32_t ctrl = decode(encoder);
|
||||||
uint32_t len = ctrl >> 5;
|
|
||||||
uint32_t ofs = (ctrl & 31) << 8; // 5 MSb of distance
|
|
||||||
|
|
||||||
if (ctrl >= MAX_COPY) { // reference (dictionary/RLE)
|
if (ctrl >= MAX_COPY) { // reference (dictionary/RLE)
|
||||||
/* retrieving the reference and the match length */
|
/* retrieving the reference and the match length */
|
||||||
|
|
||||||
|
const OUT_PIXEL *ref = op;
|
||||||
|
uint32_t len = ctrl >> 5;
|
||||||
|
uint32_t ofs = (ctrl & 31) << 8; // 5 MSb of distance
|
||||||
|
|
||||||
uint8_t code;
|
uint8_t code;
|
||||||
len--;
|
len--;
|
||||||
//ref -= ofs;
|
//ref -= ofs;
|
||||||
@ -237,7 +255,7 @@ static size_t FNAME(decompress)(Encoder *encoder, OUT_PIXEL *out_buf, int size)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA)
|
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA) || defined(LZ_A8)
|
||||||
len += 3; // length is biased by 2 + 1 (fixing bias)
|
len += 3; // length is biased by 2 + 1 (fixing bias)
|
||||||
#elif defined(LZ_RGB16)
|
#elif defined(LZ_RGB16)
|
||||||
len += 2; // length is biased by 1 + 1 (fixing bias)
|
len += 2; // length is biased by 1 + 1 (fixing bias)
|
||||||
@ -246,17 +264,13 @@ static size_t FNAME(decompress)(Encoder *encoder, OUT_PIXEL *out_buf, int size)
|
|||||||
#endif
|
#endif
|
||||||
ofs += 1; // offset is biased by 1 (fixing bias)
|
ofs += 1; // offset is biased by 1 (fixing bias)
|
||||||
|
|
||||||
#if defined(TO_RGB32)
|
|
||||||
#if defined(PLT4_BE) || defined(PLT4_LE) || defined(PLT1_BE) || defined(PLT1_LE)
|
|
||||||
ofs = CAST_PLT_DISTANCE(ofs);
|
ofs = CAST_PLT_DISTANCE(ofs);
|
||||||
len = CAST_PLT_DISTANCE(len);
|
len = CAST_PLT_DISTANCE(len);
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
ref -= ofs;
|
ref -= ofs;
|
||||||
|
|
||||||
ASSERT(encoder->usr, op + len <= op_limit);
|
spice_assert(op + len <= op_limit);
|
||||||
ASSERT(encoder->usr, ref + len <= op_limit);
|
spice_assert(ref + len <= op_limit);
|
||||||
ASSERT(encoder->usr, ref >= out_buf);
|
spice_assert(ref >= out_buf);
|
||||||
|
|
||||||
// TODO: optimize by not calling loop at least 3 times when not PLT_TO_RGB32 (len is
|
// TODO: optimize by not calling loop at least 3 times when not PLT_TO_RGB32 (len is
|
||||||
// always >=3). in PLT_TO_RGB32 len >= 3*number_of_pixels_per_byte
|
// always >=3). in PLT_TO_RGB32 len >= 3*number_of_pixels_per_byte
|
||||||
@ -267,41 +281,31 @@ static size_t FNAME(decompress)(Encoder *encoder, OUT_PIXEL *out_buf, int size)
|
|||||||
// because the number of pixel copied is larger
|
// because the number of pixel copied is larger
|
||||||
// then one...
|
// then one...
|
||||||
/* optimize copy for a run */
|
/* optimize copy for a run */
|
||||||
OUT_PIXEL b = *ref;
|
const OUT_PIXEL b = *ref;
|
||||||
for (; len; --len) {
|
for (; len; --len) {
|
||||||
COPY_PIXEL(b, op);
|
COPY_PIXEL(b, op);
|
||||||
ASSERT(encoder->usr, op <= op_limit);
|
spice_extra_assert(op <= op_limit);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (; len; --len) {
|
for (; len; --len) {
|
||||||
COPY_REF_PIXEL(ref, op);
|
COPY_REF_PIXEL(ref, op);
|
||||||
ASSERT(encoder->usr, op <= op_limit);
|
spice_extra_assert(op <= op_limit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else { // copy
|
} else { // copy
|
||||||
ctrl++; // copy count is biased by 1
|
ctrl++; // copy count is biased by 1
|
||||||
#if defined(TO_RGB32) && (defined(PLT4_BE) || defined(PLT4_LE) || defined(PLT1_BE) || \
|
spice_assert(op + CAST_PLT_DISTANCE(ctrl) <= op_limit);
|
||||||
defined(PLT1_LE))
|
|
||||||
ASSERT(encoder->usr, op + CAST_PLT_DISTANCE(ctrl) <= op_limit);
|
do {
|
||||||
#else
|
|
||||||
ASSERT(encoder->usr, op + ctrl <= op_limit);
|
|
||||||
#endif
|
|
||||||
COPY_COMP_PIXEL(encoder, op);
|
COPY_COMP_PIXEL(encoder, op);
|
||||||
|
spice_extra_assert(op <= op_limit);
|
||||||
ASSERT(encoder->usr, op <= op_limit);
|
} while(--ctrl);
|
||||||
|
|
||||||
for (--ctrl; ctrl; ctrl--) {
|
|
||||||
COPY_COMP_PIXEL(encoder, op);
|
|
||||||
ASSERT(encoder->usr, op <= op_limit);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LZ_EXPECT_CONDITIONAL(op < op_limit)) {
|
if (LZ_UNEXPECT_CONDITIONAL(op >= op_limit)) {
|
||||||
ctrl = decode(encoder);
|
break;
|
||||||
} else {
|
}
|
||||||
loop = FALSE;
|
|
||||||
}
|
}
|
||||||
} while (LZ_EXPECT_CONDITIONAL(loop));
|
|
||||||
|
|
||||||
return (op - out_buf);
|
return (op - out_buf);
|
||||||
}
|
}
|
||||||
@ -315,6 +319,7 @@ static size_t FNAME(decompress)(Encoder *encoder, OUT_PIXEL *out_buf, int size)
|
|||||||
#undef LZ_RGB16
|
#undef LZ_RGB16
|
||||||
#undef LZ_RGB24
|
#undef LZ_RGB24
|
||||||
#undef LZ_RGB32
|
#undef LZ_RGB32
|
||||||
|
#undef LZ_A8
|
||||||
#undef LZ_RGB_ALPHA
|
#undef LZ_RGB_ALPHA
|
||||||
#undef TO_RGB32
|
#undef TO_RGB32
|
||||||
#undef OUT_PIXEL
|
#undef OUT_PIXEL
|
||||||
|
|||||||
56
common/macros.h
Normal file
56
common/macros.h
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||||
|
/*
|
||||||
|
Copyright (C) 2009 Red Hat, Inc.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef H_SPICE_COMMON_MACROS
|
||||||
|
#define H_SPICE_COMMON_MACROS
|
||||||
|
|
||||||
|
#include "verify.h"
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#define SPICE_CONSTRUCTOR_FUNC(func_name) \
|
||||||
|
static void __attribute__((constructor)) func_name(void)
|
||||||
|
#define SPICE_DESTRUCTOR_FUNC(func_name) \
|
||||||
|
static void __attribute__((destructor)) func_name(void)
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
#define SPICE_CONSTRUCTOR_FUNC(func_name) \
|
||||||
|
static void func_name(void); \
|
||||||
|
static int func_name ## _wrapper(void) { func_name(); return 0; } \
|
||||||
|
__pragma(section(".CRT$XCU",read)) \
|
||||||
|
__declspec(allocate(".CRT$XCU")) static int (* _array ## func_name)(void) = func_name ## _wrapper; \
|
||||||
|
static void func_name(void)
|
||||||
|
#define SPICE_DESTRUCTOR_FUNC(func_name) \
|
||||||
|
static void func_name(void); \
|
||||||
|
static int func_name ## _wrapper(void) { func_name(); return 0; } \
|
||||||
|
__pragma(section(".CRT$XPU",read)) \
|
||||||
|
__declspec(allocate(".CRT$XPU")) static int (* _array ## func_name)(void) = func_name ## _wrapper; \
|
||||||
|
static void func_name(void)
|
||||||
|
#else
|
||||||
|
#error Please implement SPICE_CONSTRUCTOR_FUNC and SPICE_DESTRUCTOR_FUNC for this compiler
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SPICE_VERIFY(cond) verify_expr(cond, (void)1)
|
||||||
|
|
||||||
|
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
|
||||||
|
#define SPICE_UNREACHABLE __builtin_unreachable()
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
#define SPICE_UNREACHABLE __assume(0)
|
||||||
|
#else
|
||||||
|
#define SPICE_UNREACHABLE for(;;) continue
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // H_SPICE_COMMON_MACROS
|
||||||
@ -15,34 +15,60 @@
|
|||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#endif
|
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
#include "marshaller.h"
|
#include "marshaller.h"
|
||||||
#include "mem.h"
|
#include "mem.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <spice/start-packed.h>
|
||||||
|
typedef struct SPICE_ATTR_PACKED {
|
||||||
|
int16_t val;
|
||||||
|
} int16_unaligned_t;
|
||||||
|
|
||||||
|
typedef struct SPICE_ATTR_PACKED {
|
||||||
|
uint16_t val;
|
||||||
|
} uint16_unaligned_t;
|
||||||
|
|
||||||
|
typedef struct SPICE_ATTR_PACKED {
|
||||||
|
int32_t val;
|
||||||
|
} int32_unaligned_t;
|
||||||
|
|
||||||
|
typedef struct SPICE_ATTR_PACKED {
|
||||||
|
uint32_t val;
|
||||||
|
} uint32_unaligned_t;
|
||||||
|
|
||||||
|
typedef struct SPICE_ATTR_PACKED {
|
||||||
|
int64_t val;
|
||||||
|
} int64_unaligned_t;
|
||||||
|
|
||||||
|
typedef struct SPICE_ATTR_PACKED {
|
||||||
|
uint64_t val;
|
||||||
|
} uint64_unaligned_t;
|
||||||
|
#include <spice/end-packed.h>
|
||||||
|
|
||||||
|
#define write_int8(ptr,v) (*(int8_t *)(ptr) = v)
|
||||||
|
#define write_uint8(ptr,v) (*(uint8_t *)(ptr) = v)
|
||||||
|
|
||||||
#ifdef WORDS_BIGENDIAN
|
#ifdef WORDS_BIGENDIAN
|
||||||
#define write_int8(ptr,v) (*((int8_t *)(ptr)) = v)
|
#define write_int16(ptr,v) (((uint16_unaligned_t *)(ptr))->val = SPICE_BYTESWAP16((uint16_t)(v)))
|
||||||
#define write_uint8(ptr,v) (*((uint8_t *)(ptr)) = v)
|
#define write_uint16(ptr,v) (((uint16_unaligned_t *)(ptr))->val = SPICE_BYTESWAP16((uint16_t)(v)))
|
||||||
#define write_int16(ptr,v) (*((int16_t *)(ptr)) = SPICE_BYTESWAP16((uint16_t)(v)))
|
#define write_int32(ptr,v) (((uint32_unaligned_t *)(ptr))->val = SPICE_BYTESWAP32((uint32_t)(v)))
|
||||||
#define write_uint16(ptr,v) (*((uint16_t *)(ptr)) = SPICE_BYTESWAP16((uint16_t)(v)))
|
#define write_uint32(ptr,v) (((uint32_unaligned_t *)(ptr))->val = SPICE_BYTESWAP32((uint32_t)(v)))
|
||||||
#define write_int32(ptr,v) (*((int32_t *)(ptr)) = SPICE_BYTESWAP32((uint32_t)(v)))
|
#define write_int64(ptr,v) (((uint64_unaligned_t *)(ptr))->val = SPICE_BYTESWAP64((uint64_t)(v)))
|
||||||
#define write_uint32(ptr,v) (*((uint32_t *)(ptr)) = SPICE_BYTESWAP32((uint32_t)(v)))
|
#define write_uint64(ptr,v) (((uint64_unaligned_t *)(ptr))->val = SPICE_BYTESWAP64((uint64_t)(v)))
|
||||||
#define write_int64(ptr,v) (*((int64_t *)(ptr)) = SPICE_BYTESWAP64((uint64_t)(v)))
|
|
||||||
#define write_uint64(ptr,v) (*((uint64_t *)(ptr)) = SPICE_BYTESWAP64((uint64_t)(v)))
|
|
||||||
#else
|
#else
|
||||||
#define write_int8(ptr,v) (*((int8_t *)(ptr)) = v)
|
#define write_int16(ptr,v) (((int16_unaligned_t *)(ptr))->val = v)
|
||||||
#define write_uint8(ptr,v) (*((uint8_t *)(ptr)) = v)
|
#define write_uint16(ptr,v) (((uint16_unaligned_t *)(ptr))->val = v)
|
||||||
#define write_int16(ptr,v) (*((int16_t *)(ptr)) = v)
|
#define write_int32(ptr,v) (((int32_unaligned_t *)(ptr))->val = v)
|
||||||
#define write_uint16(ptr,v) (*((uint16_t *)(ptr)) = v)
|
#define write_uint32(ptr,v) (((uint32_unaligned_t *)(ptr))->val = v)
|
||||||
#define write_int32(ptr,v) (*((int32_t *)(ptr)) = v)
|
#define write_int64(ptr,v) (((int64_unaligned_t *)(ptr))->val = v)
|
||||||
#define write_uint32(ptr,v) (*((uint32_t *)(ptr)) = v)
|
#define write_uint64(ptr,v) (((uint64_unaligned_t *)(ptr))->val = v)
|
||||||
#define write_int64(ptr,v) (*((int64_t *)(ptr)) = v)
|
|
||||||
#define write_uint64(ptr,v) (*((uint64_t *)(ptr)) = v)
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -68,7 +94,6 @@ typedef struct SpiceMarshallerData SpiceMarshallerData;
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
SpiceMarshaller *marshaller;
|
SpiceMarshaller *marshaller;
|
||||||
int item_nr;
|
int item_nr;
|
||||||
int is_64bit;
|
|
||||||
size_t offset;
|
size_t offset;
|
||||||
} MarshallerRef;
|
} MarshallerRef;
|
||||||
|
|
||||||
@ -80,25 +105,26 @@ struct SpiceMarshaller {
|
|||||||
MarshallerRef pointer_ref;
|
MarshallerRef pointer_ref;
|
||||||
|
|
||||||
int n_items;
|
int n_items;
|
||||||
int items_size; /* number of items availible in items */
|
int items_size; /* number of items available in items */
|
||||||
MarshallerItem *items;
|
MarshallerItem *items;
|
||||||
|
|
||||||
MarshallerItem static_items[N_STATIC_ITEMS];
|
MarshallerItem static_items[N_STATIC_ITEMS];
|
||||||
|
int num_fd;
|
||||||
|
int fd[4];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SpiceMarshallerData {
|
struct SpiceMarshallerData {
|
||||||
size_t total_size;
|
size_t total_size;
|
||||||
size_t base;
|
size_t base;
|
||||||
SpiceMarshaller *marshallers;
|
|
||||||
SpiceMarshaller *last_marshaller;
|
SpiceMarshaller *last_marshaller;
|
||||||
|
|
||||||
size_t current_buffer_position;
|
size_t current_buffer_position;
|
||||||
MarshallerBuffer *current_buffer;
|
MarshallerBuffer *current_buffer;
|
||||||
MarshallerItem *current_buffer_item;
|
MarshallerItem *current_buffer_item;
|
||||||
MarshallerBuffer *buffers;
|
|
||||||
|
|
||||||
SpiceMarshaller static_marshaller;
|
// first marshaller and buffer are statically allocated here
|
||||||
MarshallerBuffer static_buffer;
|
SpiceMarshaller marshallers[1];
|
||||||
|
MarshallerBuffer buffers[1];
|
||||||
};
|
};
|
||||||
|
|
||||||
static void spice_marshaller_init(SpiceMarshaller *m,
|
static void spice_marshaller_init(SpiceMarshaller *m,
|
||||||
@ -111,6 +137,8 @@ static void spice_marshaller_init(SpiceMarshaller *m,
|
|||||||
m->n_items = 0;
|
m->n_items = 0;
|
||||||
m->items_size = N_STATIC_ITEMS;
|
m->items_size = N_STATIC_ITEMS;
|
||||||
m->items = m->static_items;
|
m->items = m->static_items;
|
||||||
|
m->fd[0] = m->fd[1] = m->fd[2] = m->fd[3] = -1;
|
||||||
|
m->num_fd = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SpiceMarshaller *spice_marshaller_new(void)
|
SpiceMarshaller *spice_marshaller_new(void)
|
||||||
@ -120,16 +148,15 @@ SpiceMarshaller *spice_marshaller_new(void)
|
|||||||
|
|
||||||
d = spice_new(SpiceMarshallerData, 1);
|
d = spice_new(SpiceMarshallerData, 1);
|
||||||
|
|
||||||
d->last_marshaller = d->marshallers = &d->static_marshaller;
|
d->last_marshaller = d->marshallers;
|
||||||
d->total_size = 0;
|
d->total_size = 0;
|
||||||
d->base = 0;
|
d->base = 0;
|
||||||
d->buffers = &d->static_buffer;
|
|
||||||
d->buffers->next = NULL;
|
d->buffers->next = NULL;
|
||||||
d->current_buffer = d->buffers;
|
d->current_buffer = d->buffers;
|
||||||
d->current_buffer_position = 0;
|
d->current_buffer_position = 0;
|
||||||
d->current_buffer_item = NULL;
|
d->current_buffer_item = NULL;
|
||||||
|
|
||||||
m = &d->static_marshaller;
|
m = d->marshallers;
|
||||||
spice_marshaller_init(m, d);
|
spice_marshaller_init(m, d);
|
||||||
|
|
||||||
return m;
|
return m;
|
||||||
@ -160,6 +187,7 @@ void spice_marshaller_reset(SpiceMarshaller *m)
|
|||||||
{
|
{
|
||||||
SpiceMarshaller *m2, *next;
|
SpiceMarshaller *m2, *next;
|
||||||
SpiceMarshallerData *d;
|
SpiceMarshallerData *d;
|
||||||
|
int i;
|
||||||
|
|
||||||
/* Only supported for root marshaller */
|
/* Only supported for root marshaller */
|
||||||
assert(m->data->marshallers == m);
|
assert(m->data->marshallers == m);
|
||||||
@ -179,6 +207,14 @@ void spice_marshaller_reset(SpiceMarshaller *m)
|
|||||||
m->n_items = 0;
|
m->n_items = 0;
|
||||||
m->total_size = 0;
|
m->total_size = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < m->num_fd; i++) {
|
||||||
|
if (m->fd[i] >= 0) {
|
||||||
|
close(m->fd[i]);
|
||||||
|
m->fd[i] = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m->num_fd = 0;
|
||||||
|
|
||||||
d = m->data;
|
d = m->data;
|
||||||
d->last_marshaller = d->marshallers;
|
d->last_marshaller = d->marshallers;
|
||||||
d->total_size = 0;
|
d->total_size = 0;
|
||||||
@ -238,6 +274,11 @@ static size_t remaining_buffer_size(SpiceMarshallerData *d)
|
|||||||
return MARSHALLER_BUFFER_SIZE - d->current_buffer_position;
|
return MARSHALLER_BUFFER_SIZE - d->current_buffer_position;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void reserve_space_free_data(uint8_t *data, SPICE_GNUC_UNUSED void *opaque)
|
||||||
|
{
|
||||||
|
free(data);
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t *spice_marshaller_reserve_space(SpiceMarshaller *m, size_t size)
|
uint8_t *spice_marshaller_reserve_space(SpiceMarshaller *m, size_t size)
|
||||||
{
|
{
|
||||||
MarshallerItem *item;
|
MarshallerItem *item;
|
||||||
@ -276,7 +317,7 @@ uint8_t *spice_marshaller_reserve_space(SpiceMarshaller *m, size_t size)
|
|||||||
/* Large item, allocate by itself */
|
/* Large item, allocate by itself */
|
||||||
item->data = (uint8_t *)spice_malloc(size);
|
item->data = (uint8_t *)spice_malloc(size);
|
||||||
item->len = size;
|
item->len = size;
|
||||||
item->free_data = (spice_marshaller_item_free_func)free;
|
item->free_data = reserve_space_free_data;
|
||||||
item->opaque = NULL;
|
item->opaque = NULL;
|
||||||
} else {
|
} else {
|
||||||
/* Use next buffer */
|
/* Use next buffer */
|
||||||
@ -310,7 +351,7 @@ void spice_marshaller_unreserve_space(SpiceMarshaller *m, size_t size)
|
|||||||
item->len -= size;
|
item->len -= size;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t *spice_marshaller_add_ref_full(SpiceMarshaller *m, uint8_t *data, size_t size,
|
uint8_t *spice_marshaller_add_by_ref_full(SpiceMarshaller *m, uint8_t *data, size_t size,
|
||||||
spice_marshaller_item_free_func free_data, void *opaque)
|
spice_marshaller_item_free_func free_data, void *opaque)
|
||||||
{
|
{
|
||||||
MarshallerItem *item;
|
MarshallerItem *item;
|
||||||
@ -333,7 +374,7 @@ uint8_t *spice_marshaller_add_ref_full(SpiceMarshaller *m, uint8_t *data, size_t
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t *spice_marshaller_add(SpiceMarshaller *m, uint8_t *data, size_t size)
|
uint8_t *spice_marshaller_add(SpiceMarshaller *m, const uint8_t *data, size_t size)
|
||||||
{
|
{
|
||||||
uint8_t *ptr;
|
uint8_t *ptr;
|
||||||
|
|
||||||
@ -342,17 +383,20 @@ uint8_t *spice_marshaller_add(SpiceMarshaller *m, uint8_t *data, size_t size)
|
|||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t *spice_marshaller_add_ref(SpiceMarshaller *m, uint8_t *data, size_t size)
|
uint8_t *spice_marshaller_add_by_ref(SpiceMarshaller *m, const uint8_t *data, size_t size)
|
||||||
{
|
{
|
||||||
return spice_marshaller_add_ref_full(m, data, size, NULL, NULL);
|
/* the cast to no-const here is safe as data is used for writing only if
|
||||||
|
* free_data pointer is not NULL
|
||||||
|
*/
|
||||||
|
return spice_marshaller_add_by_ref_full(m, (uint8_t *) data, size, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void spice_marshaller_add_ref_chunks(SpiceMarshaller *m, SpiceChunks *chunks)
|
void spice_marshaller_add_chunks_by_ref(SpiceMarshaller *m, SpiceChunks *chunks)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
for (i = 0; i < chunks->num_chunks; i++) {
|
for (i = 0; i < chunks->num_chunks; i++) {
|
||||||
spice_marshaller_add_ref(m, chunks->chunk[i].data,
|
spice_marshaller_add_by_ref(m, chunks->chunk[i].data,
|
||||||
chunks->chunk[i].len);
|
chunks->chunk[i].len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -373,13 +417,13 @@ SpiceMarshaller *spice_marshaller_get_submarshaller(SpiceMarshaller *m)
|
|||||||
return m2;
|
return m2;
|
||||||
}
|
}
|
||||||
|
|
||||||
SpiceMarshaller *spice_marshaller_get_ptr_submarshaller(SpiceMarshaller *m, int is_64bit)
|
SpiceMarshaller *spice_marshaller_get_ptr_submarshaller(SpiceMarshaller *m)
|
||||||
{
|
{
|
||||||
SpiceMarshaller *m2;
|
SpiceMarshaller *m2;
|
||||||
uint8_t *p;
|
uint8_t *p;
|
||||||
int size;
|
int size;
|
||||||
|
|
||||||
size = is_64bit ? 8 : 4;
|
size = 4;
|
||||||
|
|
||||||
p = spice_marshaller_reserve_space(m, size);
|
p = spice_marshaller_reserve_space(m, size);
|
||||||
memset(p, 0, size);
|
memset(p, 0, size);
|
||||||
@ -387,12 +431,11 @@ SpiceMarshaller *spice_marshaller_get_ptr_submarshaller(SpiceMarshaller *m, int
|
|||||||
m2->pointer_ref.marshaller = m;
|
m2->pointer_ref.marshaller = m;
|
||||||
m2->pointer_ref.item_nr = m->n_items - 1;
|
m2->pointer_ref.item_nr = m->n_items - 1;
|
||||||
m2->pointer_ref.offset = m->items[m->n_items - 1].len - size;
|
m2->pointer_ref.offset = m->items[m->n_items - 1].len - size;
|
||||||
m2->pointer_ref.is_64bit = is_64bit;
|
|
||||||
|
|
||||||
return m2;
|
return m2;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t *lookup_ref(MarshallerRef *ref)
|
static uint8_t *lookup_ref(MarshallerRef *ref)
|
||||||
{
|
{
|
||||||
MarshallerItem *item;
|
MarshallerItem *item;
|
||||||
|
|
||||||
@ -419,7 +462,7 @@ uint8_t *spice_marshaller_linearize(SpiceMarshaller *m, size_t skip_bytes,
|
|||||||
/* Only supported for root marshaller */
|
/* Only supported for root marshaller */
|
||||||
assert(m->data->marshallers == m);
|
assert(m->data->marshallers == m);
|
||||||
|
|
||||||
if (m->n_items == 1) {
|
if (m->n_items == 1 && m->next == NULL) {
|
||||||
*free_res = FALSE;
|
*free_res = FALSE;
|
||||||
if (m->items[0].len <= skip_bytes) {
|
if (m->items[0].len <= skip_bytes) {
|
||||||
*len = 0;
|
*len = 0;
|
||||||
@ -492,18 +535,19 @@ void spice_marshaller_flush(SpiceMarshaller *m)
|
|||||||
for (m2 = m; m2 != NULL; m2 = m2->next) {
|
for (m2 = m; m2 != NULL; m2 = m2->next) {
|
||||||
if (m2->pointer_ref.marshaller != NULL && m2->total_size > 0) {
|
if (m2->pointer_ref.marshaller != NULL && m2->total_size > 0) {
|
||||||
ptr_pos = lookup_ref(&m2->pointer_ref);
|
ptr_pos = lookup_ref(&m2->pointer_ref);
|
||||||
if (m2->pointer_ref.is_64bit) {
|
write_uint32(ptr_pos, spice_marshaller_get_offset(m2));
|
||||||
write_uint64(ptr_pos,
|
|
||||||
spice_marshaller_get_offset(m2));
|
|
||||||
} else {
|
|
||||||
write_uint32(ptr_pos,
|
|
||||||
spice_marshaller_get_offset(m2));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef WIN32
|
#ifdef WIN32
|
||||||
|
// this definition is ABI compatible with WSABUF
|
||||||
|
struct iovec {
|
||||||
|
unsigned long iov_len;
|
||||||
|
void *iov_base;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
int spice_marshaller_fill_iovec(SpiceMarshaller *m, struct iovec *vec,
|
int spice_marshaller_fill_iovec(SpiceMarshaller *m, struct iovec *vec,
|
||||||
int n_vec, size_t skip_bytes)
|
int n_vec, size_t skip_bytes)
|
||||||
{
|
{
|
||||||
@ -525,7 +569,7 @@ int spice_marshaller_fill_iovec(SpiceMarshaller *m, struct iovec *vec,
|
|||||||
if (v == n_vec) {
|
if (v == n_vec) {
|
||||||
return v; /* Not enough space in vec */
|
return v; /* Not enough space in vec */
|
||||||
}
|
}
|
||||||
vec[v].iov_base = (void *)item->data + skip_bytes;
|
vec[v].iov_base = (uint8_t *)item->data + skip_bytes;
|
||||||
vec[v].iov_len = item->len - skip_bytes;
|
vec[v].iov_len = item->len - skip_bytes;
|
||||||
skip_bytes = 0;
|
skip_bytes = 0;
|
||||||
v++;
|
v++;
|
||||||
@ -535,7 +579,6 @@ int spice_marshaller_fill_iovec(SpiceMarshaller *m, struct iovec *vec,
|
|||||||
|
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
void *spice_marshaller_add_uint64(SpiceMarshaller *m, uint64_t v)
|
void *spice_marshaller_add_uint64(SpiceMarshaller *m, uint64_t v)
|
||||||
{
|
{
|
||||||
@ -564,7 +607,7 @@ void *spice_marshaller_add_uint32(SpiceMarshaller *m, uint32_t v)
|
|||||||
return (void *)ptr;
|
return (void *)ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void spice_marshaller_set_uint32(SpiceMarshaller *m, void *ref, uint32_t v)
|
void spice_marshaller_set_uint32(SPICE_GNUC_UNUSED SpiceMarshaller *m, void *ref, uint32_t v)
|
||||||
{
|
{
|
||||||
write_uint32((uint8_t *)ref, v);
|
write_uint32((uint8_t *)ref, v);
|
||||||
}
|
}
|
||||||
@ -613,3 +656,26 @@ void *spice_marshaller_add_int8(SpiceMarshaller *m, int8_t v)
|
|||||||
write_int8(ptr, v);
|
write_int8(ptr, v);
|
||||||
return (void *)ptr;
|
return (void *)ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void spice_marshaller_add_fd(SpiceMarshaller *m, int fd)
|
||||||
|
{
|
||||||
|
spice_assert(m->num_fd < 4);
|
||||||
|
|
||||||
|
if (fd != -1) {
|
||||||
|
m->fd[m->num_fd] = dup(fd);
|
||||||
|
if (m->fd[m->num_fd] == -1) {
|
||||||
|
perror("dup");
|
||||||
|
}
|
||||||
|
m->num_fd++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int spice_marshaller_get_fds(SpiceMarshaller *m, int fd[4])
|
||||||
|
{
|
||||||
|
int num_fd = m->num_fd;
|
||||||
|
|
||||||
|
memcpy(fd, m->fd, sizeof(m->fd));
|
||||||
|
m->num_fd = 0;
|
||||||
|
|
||||||
|
return num_fd;
|
||||||
|
}
|
||||||
|
|||||||
@ -16,18 +16,20 @@
|
|||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _H_MARSHALLER
|
#ifndef H_SPICE_COMMON_MARSHALLER
|
||||||
#define _H_MARSHALLER
|
#define H_SPICE_COMMON_MARSHALLER
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <spice/macros.h>
|
||||||
#include <spice/types.h>
|
#include <spice/types.h>
|
||||||
#include "mem.h"
|
#include "mem.h"
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
#include <sys/uio.h>
|
#include <sys/uio.h>
|
||||||
|
#else
|
||||||
|
struct iovec;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
SPICE_BEGIN_DECLS
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct SpiceMarshaller SpiceMarshaller;
|
typedef struct SpiceMarshaller SpiceMarshaller;
|
||||||
typedef void (*spice_marshaller_item_free_func)(uint8_t *data, void *opaque);
|
typedef void (*spice_marshaller_item_free_func)(uint8_t *data, void *opaque);
|
||||||
@ -37,11 +39,11 @@ void spice_marshaller_reset(SpiceMarshaller *m);
|
|||||||
void spice_marshaller_destroy(SpiceMarshaller *m);
|
void spice_marshaller_destroy(SpiceMarshaller *m);
|
||||||
uint8_t *spice_marshaller_reserve_space(SpiceMarshaller *m, size_t size);
|
uint8_t *spice_marshaller_reserve_space(SpiceMarshaller *m, size_t size);
|
||||||
void spice_marshaller_unreserve_space(SpiceMarshaller *m, size_t size);
|
void spice_marshaller_unreserve_space(SpiceMarshaller *m, size_t size);
|
||||||
uint8_t *spice_marshaller_add(SpiceMarshaller *m, uint8_t *data, size_t size);
|
uint8_t *spice_marshaller_add(SpiceMarshaller *m, const uint8_t *data, size_t size);
|
||||||
uint8_t *spice_marshaller_add_ref(SpiceMarshaller *m, uint8_t *data, size_t size);
|
uint8_t *spice_marshaller_add_by_ref(SpiceMarshaller *m, const uint8_t *data, size_t size);
|
||||||
uint8_t *spice_marshaller_add_ref_full(SpiceMarshaller *m, uint8_t *data, size_t size,
|
uint8_t *spice_marshaller_add_by_ref_full(SpiceMarshaller *m, uint8_t *data, size_t size,
|
||||||
spice_marshaller_item_free_func free_data, void *opaque);
|
spice_marshaller_item_free_func free_data, void *opaque);
|
||||||
void spice_marshaller_add_ref_chunks(SpiceMarshaller *m, SpiceChunks *chunks);
|
void spice_marshaller_add_chunks_by_ref(SpiceMarshaller *m, SpiceChunks *chunks);
|
||||||
void spice_marshaller_flush(SpiceMarshaller *m);
|
void spice_marshaller_flush(SpiceMarshaller *m);
|
||||||
void spice_marshaller_set_base(SpiceMarshaller *m, size_t base);
|
void spice_marshaller_set_base(SpiceMarshaller *m, size_t base);
|
||||||
uint8_t *spice_marshaller_linearize(SpiceMarshaller *m, size_t skip,
|
uint8_t *spice_marshaller_linearize(SpiceMarshaller *m, size_t skip,
|
||||||
@ -51,11 +53,9 @@ size_t spice_marshaller_get_offset(SpiceMarshaller *m);
|
|||||||
size_t spice_marshaller_get_size(SpiceMarshaller *m);
|
size_t spice_marshaller_get_size(SpiceMarshaller *m);
|
||||||
size_t spice_marshaller_get_total_size(SpiceMarshaller *m);
|
size_t spice_marshaller_get_total_size(SpiceMarshaller *m);
|
||||||
SpiceMarshaller *spice_marshaller_get_submarshaller(SpiceMarshaller *m);
|
SpiceMarshaller *spice_marshaller_get_submarshaller(SpiceMarshaller *m);
|
||||||
SpiceMarshaller *spice_marshaller_get_ptr_submarshaller(SpiceMarshaller *m, int is_64bit);
|
SpiceMarshaller *spice_marshaller_get_ptr_submarshaller(SpiceMarshaller *m);
|
||||||
#ifndef WIN32
|
|
||||||
int spice_marshaller_fill_iovec(SpiceMarshaller *m, struct iovec *vec,
|
int spice_marshaller_fill_iovec(SpiceMarshaller *m, struct iovec *vec,
|
||||||
int n_vec, size_t skip_bytes);
|
int n_vec, size_t skip_bytes);
|
||||||
#endif
|
|
||||||
void *spice_marshaller_add_uint64(SpiceMarshaller *m, uint64_t v);
|
void *spice_marshaller_add_uint64(SpiceMarshaller *m, uint64_t v);
|
||||||
void *spice_marshaller_add_int64(SpiceMarshaller *m, int64_t v);
|
void *spice_marshaller_add_int64(SpiceMarshaller *m, int64_t v);
|
||||||
void *spice_marshaller_add_uint32(SpiceMarshaller *m, uint32_t v);
|
void *spice_marshaller_add_uint32(SpiceMarshaller *m, uint32_t v);
|
||||||
@ -67,8 +67,9 @@ void *spice_marshaller_add_int8(SpiceMarshaller *m, int8_t v);
|
|||||||
|
|
||||||
void spice_marshaller_set_uint32(SpiceMarshaller *m, void *ref, uint32_t v);
|
void spice_marshaller_set_uint32(SpiceMarshaller *m, void *ref, uint32_t v);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
void spice_marshaller_add_fd(SpiceMarshaller *m, int fd);
|
||||||
}
|
int spice_marshaller_get_fds(SpiceMarshaller *m, int fd[4]);
|
||||||
#endif
|
|
||||||
|
SPICE_END_DECLS
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
50
common/mem.c
50
common/mem.c
@ -15,20 +15,17 @@
|
|||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "mem.h"
|
#include "mem.h"
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#ifndef MALLOC_ERROR
|
#ifndef MALLOC_ERROR
|
||||||
#define MALLOC_ERROR(format, ...) { \
|
#define MALLOC_ERROR(...) SPICE_STMT_START { \
|
||||||
printf(format "\n", ## __VA_ARGS__); \
|
spice_error(__VA_ARGS__); \
|
||||||
abort(); \
|
abort(); \
|
||||||
}
|
} SPICE_STMT_END
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
size_t spice_strnlen(const char *str, size_t max_len)
|
size_t spice_strnlen(const char *str, size_t max_len)
|
||||||
@ -46,13 +43,15 @@ size_t spice_strnlen(const char *str, size_t max_len)
|
|||||||
char *spice_strdup(const char *str)
|
char *spice_strdup(const char *str)
|
||||||
{
|
{
|
||||||
char *copy;
|
char *copy;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
if (str == NULL) {
|
if (str == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
copy = (char *)spice_malloc(strlen(str) + 1);
|
len = strlen(str) + 1;
|
||||||
strcpy(copy, str);
|
copy = (char *)spice_malloc(len);
|
||||||
|
memcpy(copy, str, len);
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,8 +93,7 @@ void *spice_malloc(size_t n_bytes)
|
|||||||
return mem;
|
return mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
MALLOC_ERROR("spice_malloc: panic: unable to allocate %lu bytes\n",
|
MALLOC_ERROR("unable to allocate %lu bytes", (unsigned long)n_bytes);
|
||||||
(unsigned long)n_bytes);
|
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -111,8 +109,7 @@ void *spice_malloc0(size_t n_bytes)
|
|||||||
return mem;
|
return mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
MALLOC_ERROR("spice_malloc0: panic: unable to allocate %lu bytes\n",
|
MALLOC_ERROR("unable to allocate %lu bytes", (unsigned long)n_bytes);
|
||||||
(unsigned long)n_bytes);
|
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -126,8 +123,7 @@ void *spice_realloc(void *mem, size_t n_bytes)
|
|||||||
return mem;
|
return mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
MALLOC_ERROR("spice_realloc: panic: unable to allocate %lu bytes\n",
|
MALLOC_ERROR("unable to allocate %lu bytes", (unsigned long)n_bytes);
|
||||||
(unsigned long)n_bytes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free(mem);
|
free(mem);
|
||||||
@ -140,7 +136,7 @@ void *spice_realloc(void *mem, size_t n_bytes)
|
|||||||
void *spice_malloc_n(size_t n_blocks, size_t n_block_bytes)
|
void *spice_malloc_n(size_t n_blocks, size_t n_block_bytes)
|
||||||
{
|
{
|
||||||
if (SIZE_OVERFLOWS (n_blocks, n_block_bytes)) {
|
if (SIZE_OVERFLOWS (n_blocks, n_block_bytes)) {
|
||||||
MALLOC_ERROR("spice_malloc_n: overflow allocating %lu*%lu bytes",
|
MALLOC_ERROR("overflow allocating %lu*%lu bytes",
|
||||||
(unsigned long)n_blocks, (unsigned long)n_block_bytes);
|
(unsigned long)n_blocks, (unsigned long)n_block_bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -295,3 +291,25 @@ size_t spice_buffer_remove(SpiceBuffer *buffer, size_t len)
|
|||||||
buffer->offset -= len;
|
buffer->offset -= len;
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef SPICE_DEBUG_ALIGNMENT
|
||||||
|
void spice_alignment_warning(const char *loc, void *p, unsigned sz)
|
||||||
|
{
|
||||||
|
static const char *last_loc = NULL;
|
||||||
|
if (loc != last_loc) {
|
||||||
|
last_loc = loc;
|
||||||
|
spice_log(G_LOG_LEVEL_WARNING, loc, __FUNCTION__,
|
||||||
|
"Misaligned access at %p, alignment %u", p, sz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void spice_alignment_debug(const char *loc, void *p, unsigned sz)
|
||||||
|
{
|
||||||
|
static const char *last_loc = NULL;
|
||||||
|
if (loc != last_loc) {
|
||||||
|
last_loc = loc;
|
||||||
|
spice_log(G_LOG_LEVEL_DEBUG, loc, __FUNCTION__,
|
||||||
|
"Expected misaligned access at %p, alignment %u", p, sz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // SPICE_DEBUG_ALIGNMENT
|
||||||
|
|||||||
59
common/mem.h
59
common/mem.h
@ -16,19 +16,14 @@
|
|||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _H_MEM
|
#ifndef H_SPICE_COMMON_MEM
|
||||||
#define _H_MEM
|
#define H_SPICE_COMMON_MEM
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <spice/macros.h>
|
#include <spice/macros.h>
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
SPICE_BEGIN_DECLS
|
||||||
# include <config.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef STDC_HEADERS
|
#ifdef STDC_HEADERS
|
||||||
# include <stdlib.h>
|
# include <stdlib.h>
|
||||||
@ -134,7 +129,6 @@ size_t spice_strnlen(const char *str, size_t max_len);
|
|||||||
#else
|
#else
|
||||||
|
|
||||||
/* Unoptimized version: always call the _n() function. */
|
/* Unoptimized version: always call the _n() function. */
|
||||||
|
|
||||||
#define _SPICE_NEW(struct_type, n_structs, func) \
|
#define _SPICE_NEW(struct_type, n_structs, func) \
|
||||||
((struct_type *) spice_##func##_n ((n_structs), sizeof (struct_type)))
|
((struct_type *) spice_##func##_n ((n_structs), sizeof (struct_type)))
|
||||||
#define _SPICE_RENEW(struct_type, mem, n_structs, func) \
|
#define _SPICE_RENEW(struct_type, mem, n_structs, func) \
|
||||||
@ -142,6 +136,46 @@ size_t spice_strnlen(const char *str, size_t max_len);
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Cast to a type with stricter alignment constraints (to build with clang) */
|
||||||
|
|
||||||
|
/* Misaligned cast to a type with stricter alignment */
|
||||||
|
#ifndef SPICE_DEBUG_ALIGNMENT
|
||||||
|
#define SPICE_UNALIGNED_CAST(type, value) ((type)(void *)(value))
|
||||||
|
#define SPICE_ALIGNED_CAST(type, value) ((type)(void *)(value))
|
||||||
|
|
||||||
|
#else // SPICE_DEBUG_ALIGNMENT
|
||||||
|
#define SPICE_ALIGNED_CAST(type, value) \
|
||||||
|
((type)spice_alignment_check(G_STRLOC, \
|
||||||
|
(void *)(value), \
|
||||||
|
__alignof(*((type)0))))
|
||||||
|
|
||||||
|
#define SPICE_UNALIGNED_CAST(type, value) \
|
||||||
|
((type)spice_alignment_weak_check(G_STRLOC, \
|
||||||
|
(void *)(value), \
|
||||||
|
__alignof(*((type)0))))
|
||||||
|
|
||||||
|
extern void spice_alignment_warning(const char *loc, void *p, unsigned sz);
|
||||||
|
extern void spice_alignment_debug(const char *loc, void *p, unsigned sz);
|
||||||
|
|
||||||
|
static inline void *spice_alignment_check(const char *loc,
|
||||||
|
void *ptr, unsigned sz)
|
||||||
|
{
|
||||||
|
if (G_UNLIKELY(((uintptr_t) ptr & (sz-1U)) != 0))
|
||||||
|
spice_alignment_warning(loc, ptr, sz);
|
||||||
|
return ptr;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void *spice_alignment_weak_check(const char *loc,
|
||||||
|
void *ptr, unsigned sz)
|
||||||
|
{
|
||||||
|
if (G_UNLIKELY(((uintptr_t) ptr & (sz-1U)) != 0))
|
||||||
|
spice_alignment_debug(loc, ptr, sz);
|
||||||
|
return ptr;
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif // SPICE_DEBUG_ALIGNMENT
|
||||||
|
|
||||||
#define spice_new(struct_type, n_structs) _SPICE_NEW(struct_type, n_structs, malloc)
|
#define spice_new(struct_type, n_structs) _SPICE_NEW(struct_type, n_structs, malloc)
|
||||||
#define spice_new0(struct_type, n_structs) _SPICE_NEW(struct_type, n_structs, malloc0)
|
#define spice_new0(struct_type, n_structs) _SPICE_NEW(struct_type, n_structs, malloc0)
|
||||||
#define spice_renew(struct_type, mem, n_structs) _SPICE_RENEW(struct_type, mem, n_structs, realloc)
|
#define spice_renew(struct_type, mem, n_structs) _SPICE_RENEW(struct_type, mem, n_structs, realloc)
|
||||||
@ -156,7 +190,6 @@ void spice_buffer_append(SpiceBuffer *buffer, const void *data, size_t len);
|
|||||||
size_t spice_buffer_copy(SpiceBuffer *buffer, void *dest, size_t len);
|
size_t spice_buffer_copy(SpiceBuffer *buffer, void *dest, size_t len);
|
||||||
size_t spice_buffer_remove(SpiceBuffer *buffer, size_t len);
|
size_t spice_buffer_remove(SpiceBuffer *buffer, size_t len);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
SPICE_END_DECLS
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
194
common/meson.build
Normal file
194
common/meson.build
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
#
|
||||||
|
# libspice-common
|
||||||
|
#
|
||||||
|
spice_common_sources = [
|
||||||
|
'agent.c',
|
||||||
|
'agent.h',
|
||||||
|
'backtrace.c',
|
||||||
|
'backtrace.h',
|
||||||
|
'canvas_utils.c',
|
||||||
|
'canvas_utils.h',
|
||||||
|
'demarshallers.h',
|
||||||
|
'draw.h',
|
||||||
|
'lines.c',
|
||||||
|
'lines.h',
|
||||||
|
'log.c',
|
||||||
|
'log.h',
|
||||||
|
'lz.c',
|
||||||
|
'lz.h',
|
||||||
|
'lz_common.h',
|
||||||
|
'lz_config.h',
|
||||||
|
'macros.h',
|
||||||
|
'marshaller.c',
|
||||||
|
'marshaller.h',
|
||||||
|
'mem.c',
|
||||||
|
'mem.h',
|
||||||
|
'messages.h',
|
||||||
|
'pixman_utils.c',
|
||||||
|
'pixman_utils.h',
|
||||||
|
'quic.c',
|
||||||
|
'quic.h',
|
||||||
|
'quic_config.h',
|
||||||
|
'rect.h',
|
||||||
|
'region.c',
|
||||||
|
'region.h',
|
||||||
|
'ring.h',
|
||||||
|
'rop3.c',
|
||||||
|
'rop3.h',
|
||||||
|
'snd_codec.c',
|
||||||
|
'snd_codec.h',
|
||||||
|
'utils.c',
|
||||||
|
'utils.h',
|
||||||
|
'udev.c',
|
||||||
|
'udev.h',
|
||||||
|
'verify.h',
|
||||||
|
'recorder.h'
|
||||||
|
]
|
||||||
|
|
||||||
|
if get_option('instrumentation') == 'recorder'
|
||||||
|
spice_common_sources += [
|
||||||
|
'recorder/recorder.c',
|
||||||
|
'recorder/recorder.h',
|
||||||
|
'recorder/recorder_ring.c',
|
||||||
|
'recorder/recorder_ring.h'
|
||||||
|
]
|
||||||
|
endif
|
||||||
|
if get_option('instrumentation') == 'agent'
|
||||||
|
spice_common_sources += [
|
||||||
|
'agent_interface.c',
|
||||||
|
'agent_interface.h'
|
||||||
|
]
|
||||||
|
endif
|
||||||
|
|
||||||
|
spice_common_lib = static_library('spice-common', spice_common_sources,
|
||||||
|
install : false,
|
||||||
|
include_directories : spice_common_include,
|
||||||
|
dependencies : spice_common_deps)
|
||||||
|
|
||||||
|
spice_common_dep = declare_dependency(link_with : spice_common_lib,
|
||||||
|
include_directories : spice_common_include,
|
||||||
|
dependencies : spice_common_deps)
|
||||||
|
|
||||||
|
|
||||||
|
# client_demarshallers
|
||||||
|
if spice_common_generate_client_code or spice_common_generate_server_code
|
||||||
|
codegen_cmd = [python, spice_codegen]
|
||||||
|
codegen_args = ['--generate-demarshallers',
|
||||||
|
'--client',
|
||||||
|
'--include', 'common/messages.h',
|
||||||
|
'--generated-declaration-file', '@OUTPUT1@',
|
||||||
|
'@INPUT@', '@OUTPUT0@']
|
||||||
|
|
||||||
|
client_demarshallers = custom_target('client_demarshallers',
|
||||||
|
input : [spice_proto],
|
||||||
|
output : ['generated_client_demarshallers.c', 'generated_messages.h'],
|
||||||
|
install : false,
|
||||||
|
command : [codegen_cmd, codegen_args],
|
||||||
|
depend_files : [spice_codegen_files, 'messages.h'])
|
||||||
|
endif
|
||||||
|
|
||||||
|
#
|
||||||
|
# libspice-common-client
|
||||||
|
#
|
||||||
|
if spice_common_generate_client_code
|
||||||
|
# client_marshallers
|
||||||
|
codegen_args = ['--generate-marshallers',
|
||||||
|
'--generate-header',
|
||||||
|
'-P',
|
||||||
|
'--client',
|
||||||
|
'--include', 'common/client_marshallers.h',
|
||||||
|
'@INPUT0@', '@OUTPUT0@']
|
||||||
|
|
||||||
|
client_marshallers = custom_target('client_marshallers',
|
||||||
|
input : [spice_proto, client_demarshallers],
|
||||||
|
output : ['generated_client_marshallers.c', 'generated_client_marshallers.h'],
|
||||||
|
install : false,
|
||||||
|
command : [codegen_cmd, codegen_args],
|
||||||
|
depend_files : [spice_codegen_files, 'client_marshallers.h'])
|
||||||
|
|
||||||
|
spice_common_client_sources = [
|
||||||
|
client_demarshallers,
|
||||||
|
client_marshallers,
|
||||||
|
'client_marshallers.h',
|
||||||
|
'ssl_verify.c',
|
||||||
|
'ssl_verify.h',
|
||||||
|
]
|
||||||
|
|
||||||
|
spice_common_client_lib = static_library('spice-common-client', spice_common_client_sources,
|
||||||
|
install : false,
|
||||||
|
dependencies : [spice_common_dep, gio2_deps])
|
||||||
|
|
||||||
|
spice_common_client_dep = declare_dependency(sources : client_marshallers[1],
|
||||||
|
link_with : spice_common_client_lib,
|
||||||
|
dependencies : [spice_common_dep, gio2_deps])
|
||||||
|
endif
|
||||||
|
|
||||||
|
#
|
||||||
|
# libspice-common-server
|
||||||
|
#
|
||||||
|
if spice_common_generate_server_code
|
||||||
|
structs_args = [
|
||||||
|
'-M', 'String',
|
||||||
|
'-M', 'Rect',
|
||||||
|
'-M', 'Point',
|
||||||
|
'-M', 'DisplayBase',
|
||||||
|
'-M', 'Fill',
|
||||||
|
'-M', 'Opaque',
|
||||||
|
'-M', 'Copy',
|
||||||
|
'-M', 'Blend',
|
||||||
|
'-M', 'Blackness',
|
||||||
|
'-M', 'Whiteness',
|
||||||
|
'-M', 'Invers',
|
||||||
|
'-M', 'Rop3',
|
||||||
|
'-M', 'Stroke',
|
||||||
|
'-M', 'Text',
|
||||||
|
'-M', 'Transparent',
|
||||||
|
'-M', 'AlphaBlend',
|
||||||
|
'-M', 'Composite',
|
||||||
|
]
|
||||||
|
|
||||||
|
targets = [
|
||||||
|
{ 'name' : 'server_demarshallers',
|
||||||
|
'input' : [ spice_proto, client_demarshallers ],
|
||||||
|
'output' : ['generated_server_demarshallers.c'],
|
||||||
|
'codegen_args' : ['--generate-demarshallers',
|
||||||
|
'--server',
|
||||||
|
'--include', 'common/messages.h',
|
||||||
|
'@INPUT0@', '@OUTPUT0@'],
|
||||||
|
},
|
||||||
|
{ 'name' : 'server_marshallers',
|
||||||
|
'input' : [ spice_proto, client_demarshallers ],
|
||||||
|
'output' : ['generated_server_marshallers.c', 'generated_server_marshallers.h'],
|
||||||
|
'codegen_args' : ['--generate-marshallers',
|
||||||
|
'--generate-header',
|
||||||
|
'--server',
|
||||||
|
structs_args,
|
||||||
|
'--include', 'common/messages.h',
|
||||||
|
'@INPUT0@', '@OUTPUT0@']
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
spice_common_server_sources = []
|
||||||
|
spice_common_server_dep_sources = []
|
||||||
|
|
||||||
|
foreach t : targets
|
||||||
|
target = custom_target(t['name'],
|
||||||
|
input : t['input'],
|
||||||
|
output : t['output'],
|
||||||
|
install : false,
|
||||||
|
command : [codegen_cmd, t['codegen_args']],
|
||||||
|
depend_files : [spice_codegen_files, 'messages.h'])
|
||||||
|
spice_common_server_sources += target
|
||||||
|
if t['output'].length() > 1
|
||||||
|
spice_common_server_dep_sources += target[1]
|
||||||
|
endif
|
||||||
|
endforeach
|
||||||
|
|
||||||
|
spice_common_server_lib = static_library('spice-common-server', spice_common_server_sources,
|
||||||
|
install : false,
|
||||||
|
dependencies : spice_common_dep)
|
||||||
|
|
||||||
|
spice_common_server_dep = declare_dependency(sources : spice_common_server_dep_sources,
|
||||||
|
link_with : spice_common_server_lib,
|
||||||
|
dependencies : spice_common_dep)
|
||||||
|
endif
|
||||||
@ -28,498 +28,46 @@
|
|||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _H_MESSAGES
|
#ifndef H_SPICE_COMMON_MESSAGES
|
||||||
#define _H_MESSAGES
|
#define H_SPICE_COMMON_MESSAGES
|
||||||
|
|
||||||
#include <spice/protocol.h>
|
#include <spice/protocol.h>
|
||||||
#include "draw.h"
|
#include <spice/macros.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef USE_SMARTCARD
|
||||||
extern "C" {
|
#include <libcacard.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct SpiceMsgData {
|
#include "draw.h"
|
||||||
uint32_t data_size;
|
|
||||||
uint8_t data[0];
|
|
||||||
} SpiceMsgData;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgEmpty {
|
SPICE_BEGIN_DECLS
|
||||||
} SpiceMsgEmpty;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgInputsInit {
|
typedef struct SpiceMsgCompressedData {
|
||||||
uint32_t keyboard_modifiers;
|
|
||||||
} SpiceMsgInputsInit;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgInputsKeyModifiers {
|
|
||||||
uint32_t modifiers;
|
|
||||||
} SpiceMsgInputsKeyModifiers;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgMainMultiMediaTime {
|
|
||||||
uint32_t time;
|
|
||||||
} SpiceMsgMainMultiMediaTime;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgMainMigrationBegin {
|
|
||||||
uint16_t port;
|
|
||||||
uint16_t sport;
|
|
||||||
uint32_t host_size;
|
|
||||||
uint8_t *host_data;
|
|
||||||
uint16_t pub_key_type;
|
|
||||||
uint32_t pub_key_size;
|
|
||||||
uint8_t *pub_key_data;
|
|
||||||
uint32_t cert_subject_size;
|
|
||||||
uint8_t *cert_subject_data;
|
|
||||||
} SpiceMsgMainMigrationBegin;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgMainMigrationSwitchHost {
|
|
||||||
uint16_t port;
|
|
||||||
uint16_t sport;
|
|
||||||
uint32_t host_size;
|
|
||||||
uint8_t *host_data;
|
|
||||||
uint32_t cert_subject_size;
|
|
||||||
uint8_t *cert_subject_data;
|
|
||||||
} SpiceMsgMainMigrationSwitchHost;
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct SpiceMsgMigrate {
|
|
||||||
uint32_t flags;
|
|
||||||
} SpiceMsgMigrate;
|
|
||||||
|
|
||||||
typedef struct SpiceResourceID {
|
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
uint64_t id;
|
uint32_t uncompressed_size;
|
||||||
} SpiceResourceID;
|
uint32_t compressed_size;
|
||||||
|
uint8_t *compressed_data;
|
||||||
typedef struct SpiceResourceList {
|
} SpiceMsgCompressedData;
|
||||||
uint16_t count;
|
|
||||||
SpiceResourceID resources[0];
|
|
||||||
} SpiceResourceList;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgSetAck {
|
|
||||||
uint32_t generation;
|
|
||||||
uint32_t window;
|
|
||||||
} SpiceMsgSetAck;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgcAckSync {
|
|
||||||
uint32_t generation;
|
|
||||||
} SpiceMsgcAckSync;
|
|
||||||
|
|
||||||
typedef struct SpiceWaitForChannel {
|
|
||||||
uint8_t channel_type;
|
|
||||||
uint8_t channel_id;
|
|
||||||
uint64_t message_serial;
|
|
||||||
} SpiceWaitForChannel;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgWaitForChannels {
|
|
||||||
uint8_t wait_count;
|
|
||||||
SpiceWaitForChannel wait_list[0];
|
|
||||||
} SpiceMsgWaitForChannels;
|
|
||||||
|
|
||||||
typedef struct SpiceChannelId {
|
|
||||||
uint8_t type;
|
|
||||||
uint8_t id;
|
|
||||||
} SpiceChannelId;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgMainInit {
|
|
||||||
uint32_t session_id;
|
|
||||||
uint32_t display_channels_hint;
|
|
||||||
uint32_t supported_mouse_modes;
|
|
||||||
uint32_t current_mouse_mode;
|
|
||||||
uint32_t agent_connected;
|
|
||||||
uint32_t agent_tokens;
|
|
||||||
uint32_t multi_media_time;
|
|
||||||
uint32_t ram_hint;
|
|
||||||
} SpiceMsgMainInit;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgDisconnect {
|
|
||||||
uint64_t time_stamp;
|
|
||||||
uint32_t reason; // SPICE_ERR_?
|
|
||||||
} SpiceMsgDisconnect;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgNotify {
|
|
||||||
uint64_t time_stamp;
|
|
||||||
uint32_t severity;
|
|
||||||
uint32_t visibilty;
|
|
||||||
uint32_t what;
|
|
||||||
uint32_t message_len;
|
|
||||||
uint8_t message[0];
|
|
||||||
} SpiceMsgNotify;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgChannels {
|
|
||||||
uint32_t num_of_channels;
|
|
||||||
SpiceChannelId channels[0];
|
|
||||||
} SpiceMsgChannels;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgMainName {
|
|
||||||
uint32_t name_len;
|
|
||||||
uint8_t name[0];
|
|
||||||
} SpiceMsgMainName;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgMainUuid {
|
|
||||||
uint8_t uuid[16];
|
|
||||||
} SpiceMsgMainUuid;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgMainMouseMode {
|
|
||||||
uint32_t supported_modes;
|
|
||||||
uint32_t current_mode;
|
|
||||||
} SpiceMsgMainMouseMode;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgPing {
|
|
||||||
uint32_t id;
|
|
||||||
uint64_t timestamp;
|
|
||||||
void *data;
|
|
||||||
uint32_t data_len;
|
|
||||||
} SpiceMsgPing;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgMainAgentDisconnect {
|
|
||||||
uint32_t error_code; // SPICE_ERR_?
|
|
||||||
} SpiceMsgMainAgentDisconnect;
|
|
||||||
|
|
||||||
#define SPICE_AGENT_MAX_DATA_SIZE 2048
|
#define SPICE_AGENT_MAX_DATA_SIZE 2048
|
||||||
|
|
||||||
typedef struct SpiceMsgMainAgentTokens {
|
#ifdef USE_SMARTCARD
|
||||||
uint32_t num_tokens;
|
typedef struct SpiceMsgSmartcard {
|
||||||
} SpiceMsgMainAgentTokens, SpiceMsgcMainAgentTokens, SpiceMsgcMainAgentStart;
|
VSCMsgType type;
|
||||||
|
uint32_t length;
|
||||||
typedef struct SpiceMsgcClientInfo {
|
uint32_t reader_id;
|
||||||
uint64_t cache_size;
|
|
||||||
} SpiceMsgcClientInfo;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgcMainMouseModeRequest {
|
|
||||||
uint32_t mode;
|
|
||||||
} SpiceMsgcMainMouseModeRequest;
|
|
||||||
|
|
||||||
typedef struct SpiceCursor {
|
|
||||||
uint32_t flags;
|
|
||||||
SpiceCursorHeader header;
|
|
||||||
uint32_t data_size;
|
|
||||||
uint8_t *data;
|
|
||||||
} SpiceCursor;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgDisplayMode {
|
|
||||||
uint32_t x_res;
|
|
||||||
uint32_t y_res;
|
|
||||||
uint32_t bits;
|
|
||||||
} SpiceMsgDisplayMode;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgSurfaceCreate {
|
|
||||||
uint32_t surface_id;
|
|
||||||
uint32_t width;
|
|
||||||
uint32_t height;
|
|
||||||
uint32_t format;
|
|
||||||
uint32_t flags;
|
|
||||||
} SpiceMsgSurfaceCreate;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgSurfaceDestroy {
|
|
||||||
uint32_t surface_id;
|
|
||||||
} SpiceMsgSurfaceDestroy;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgDisplayBase {
|
|
||||||
uint32_t surface_id;
|
|
||||||
SpiceRect box;
|
|
||||||
SpiceClip clip;
|
|
||||||
} SpiceMsgDisplayBase;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgDisplayDrawFill {
|
|
||||||
SpiceMsgDisplayBase base;
|
|
||||||
SpiceFill data;
|
|
||||||
} SpiceMsgDisplayDrawFill;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgDisplayDrawOpaque {
|
|
||||||
SpiceMsgDisplayBase base;
|
|
||||||
SpiceOpaque data;
|
|
||||||
} SpiceMsgDisplayDrawOpaque;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgDisplayDrawCopy {
|
|
||||||
SpiceMsgDisplayBase base;
|
|
||||||
SpiceCopy data;
|
|
||||||
} SpiceMsgDisplayDrawCopy;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgDisplayDrawTransparent {
|
|
||||||
SpiceMsgDisplayBase base;
|
|
||||||
SpiceTransparent data;
|
|
||||||
} SpiceMsgDisplayDrawTransparent;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgDisplayDrawAlphaBlend {
|
|
||||||
SpiceMsgDisplayBase base;
|
|
||||||
SpiceAlphaBlend data;
|
|
||||||
} SpiceMsgDisplayDrawAlphaBlend;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgDisplayCopyBits {
|
|
||||||
SpiceMsgDisplayBase base;
|
|
||||||
SpicePoint src_pos;
|
|
||||||
} SpiceMsgDisplayCopyBits;
|
|
||||||
|
|
||||||
typedef SpiceMsgDisplayDrawCopy SpiceMsgDisplayDrawBlend;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgDisplayDrawRop3 {
|
|
||||||
SpiceMsgDisplayBase base;
|
|
||||||
SpiceRop3 data;
|
|
||||||
} SpiceMsgDisplayDrawRop3;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgDisplayDrawBlackness {
|
|
||||||
SpiceMsgDisplayBase base;
|
|
||||||
SpiceBlackness data;
|
|
||||||
} SpiceMsgDisplayDrawBlackness;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgDisplayDrawWhiteness {
|
|
||||||
SpiceMsgDisplayBase base;
|
|
||||||
SpiceWhiteness data;
|
|
||||||
} SpiceMsgDisplayDrawWhiteness;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgDisplayDrawInvers {
|
|
||||||
SpiceMsgDisplayBase base;
|
|
||||||
SpiceInvers data;
|
|
||||||
} SpiceMsgDisplayDrawInvers;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgDisplayDrawStroke {
|
|
||||||
SpiceMsgDisplayBase base;
|
|
||||||
SpiceStroke data;
|
|
||||||
} SpiceMsgDisplayDrawStroke;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgDisplayDrawText {
|
|
||||||
SpiceMsgDisplayBase base;
|
|
||||||
SpiceText data;
|
|
||||||
} SpiceMsgDisplayDrawText;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgDisplayInvalOne {
|
|
||||||
uint64_t id;
|
|
||||||
} SpiceMsgDisplayInvalOne;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgDisplayStreamCreate {
|
|
||||||
uint32_t surface_id;
|
|
||||||
uint32_t id;
|
|
||||||
uint32_t flags;
|
|
||||||
uint32_t codec_type;
|
|
||||||
uint64_t stamp;
|
|
||||||
uint32_t stream_width;
|
|
||||||
uint32_t stream_height;
|
|
||||||
uint32_t src_width;
|
|
||||||
uint32_t src_height;
|
|
||||||
SpiceRect dest;
|
|
||||||
SpiceClip clip;
|
|
||||||
} SpiceMsgDisplayStreamCreate;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgDisplayStreamData {
|
|
||||||
uint32_t id;
|
|
||||||
uint32_t multi_media_time;
|
|
||||||
uint32_t data_size;
|
|
||||||
uint8_t data[0];
|
uint8_t data[0];
|
||||||
} SpiceMsgDisplayStreamData;
|
} SpiceMsgSmartcard;
|
||||||
|
|
||||||
typedef struct SpiceMsgDisplayStreamClip {
|
|
||||||
uint32_t id;
|
|
||||||
SpiceClip clip;
|
|
||||||
} SpiceMsgDisplayStreamClip;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgDisplayStreamDestroy {
|
|
||||||
uint32_t id;
|
|
||||||
} SpiceMsgDisplayStreamDestroy;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgCursorInit {
|
|
||||||
SpicePoint16 position;
|
|
||||||
uint16_t trail_length;
|
|
||||||
uint16_t trail_frequency;
|
|
||||||
uint8_t visible;
|
|
||||||
SpiceCursor cursor;
|
|
||||||
} SpiceMsgCursorInit;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgCursorSet {
|
|
||||||
SpicePoint16 position;
|
|
||||||
uint8_t visible;
|
|
||||||
SpiceCursor cursor;
|
|
||||||
} SpiceMsgCursorSet;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgCursorMove {
|
|
||||||
SpicePoint16 position;
|
|
||||||
} SpiceMsgCursorMove;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgCursorTrail {
|
|
||||||
uint16_t length;
|
|
||||||
uint16_t frequency;
|
|
||||||
} SpiceMsgCursorTrail;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgcDisplayInit {
|
|
||||||
uint8_t pixmap_cache_id;
|
|
||||||
int64_t pixmap_cache_size; //in pixels
|
|
||||||
uint8_t glz_dictionary_id;
|
|
||||||
int32_t glz_dictionary_window_size; // in pixels
|
|
||||||
} SpiceMsgcDisplayInit;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgcKeyDown {
|
|
||||||
uint32_t code;
|
|
||||||
} SpiceMsgcKeyDown;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgcKeyUp {
|
|
||||||
uint32_t code;
|
|
||||||
} SpiceMsgcKeyUp;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgcKeyModifiers {
|
|
||||||
uint32_t modifiers;
|
|
||||||
} SpiceMsgcKeyModifiers;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgcMouseMotion {
|
|
||||||
int32_t dx;
|
|
||||||
int32_t dy;
|
|
||||||
uint32_t buttons_state;
|
|
||||||
} SpiceMsgcMouseMotion;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgcMousePosition {
|
|
||||||
uint32_t x;
|
|
||||||
uint32_t y;
|
|
||||||
uint32_t buttons_state;
|
|
||||||
uint8_t display_id;
|
|
||||||
} SpiceMsgcMousePosition;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgcMousePress {
|
|
||||||
int32_t button;
|
|
||||||
int32_t buttons_state;
|
|
||||||
} SpiceMsgcMousePress;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgcMouseRelease {
|
|
||||||
int32_t button;
|
|
||||||
int32_t buttons_state;
|
|
||||||
} SpiceMsgcMouseRelease;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgAudioVolume {
|
|
||||||
uint8_t nchannels;
|
|
||||||
uint16_t volume[0];
|
|
||||||
} SpiceMsgAudioVolume;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgAudioMute {
|
|
||||||
uint8_t mute;
|
|
||||||
} SpiceMsgAudioMute;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgPlaybackMode {
|
|
||||||
uint32_t time;
|
|
||||||
uint32_t mode; //SPICE_AUDIO_DATA_MODE_?
|
|
||||||
uint8_t *data;
|
|
||||||
uint32_t data_size;
|
|
||||||
} SpiceMsgPlaybackMode, SpiceMsgcRecordMode;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgPlaybackStart {
|
|
||||||
uint32_t channels;
|
|
||||||
uint32_t format; //SPICE_AUDIO_FMT_?
|
|
||||||
uint32_t frequency;
|
|
||||||
uint32_t time;
|
|
||||||
} SpiceMsgPlaybackStart;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgPlaybackPacket {
|
|
||||||
uint32_t time;
|
|
||||||
uint8_t *data;
|
|
||||||
uint32_t data_size;
|
|
||||||
} SpiceMsgPlaybackPacket, SpiceMsgcRecordPacket;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgRecordStart {
|
|
||||||
uint32_t channels;
|
|
||||||
uint32_t format; //SPICE_AUDIO_FMT_?
|
|
||||||
uint32_t frequency;
|
|
||||||
} SpiceMsgRecordStart;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgcRecordStartMark {
|
|
||||||
uint32_t time;
|
|
||||||
} SpiceMsgcRecordStartMark;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgTunnelInit {
|
|
||||||
uint16_t max_num_of_sockets;
|
|
||||||
uint32_t max_socket_data_size;
|
|
||||||
} SpiceMsgTunnelInit;
|
|
||||||
|
|
||||||
typedef uint8_t SpiceTunnelIPv4[4];
|
|
||||||
|
|
||||||
typedef struct SpiceMsgTunnelIpInfo {
|
|
||||||
uint16_t type;
|
|
||||||
union {
|
|
||||||
SpiceTunnelIPv4 ipv4;
|
|
||||||
} u;
|
|
||||||
uint8_t data[0];
|
|
||||||
} SpiceMsgTunnelIpInfo;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgTunnelServiceIpMap {
|
|
||||||
uint32_t service_id;
|
|
||||||
SpiceMsgTunnelIpInfo virtual_ip;
|
|
||||||
} SpiceMsgTunnelServiceIpMap;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgTunnelSocketOpen {
|
|
||||||
uint16_t connection_id;
|
|
||||||
uint32_t service_id;
|
|
||||||
uint32_t tokens;
|
|
||||||
} SpiceMsgTunnelSocketOpen;
|
|
||||||
|
|
||||||
/* connection id must be the first field in msgs directed to a specific connection */
|
|
||||||
|
|
||||||
typedef struct SpiceMsgTunnelSocketFin {
|
|
||||||
uint16_t connection_id;
|
|
||||||
} SpiceMsgTunnelSocketFin;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgTunnelSocketClose {
|
|
||||||
uint16_t connection_id;
|
|
||||||
} SpiceMsgTunnelSocketClose;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgTunnelSocketData {
|
|
||||||
uint16_t connection_id;
|
|
||||||
uint8_t data[0];
|
|
||||||
} SpiceMsgTunnelSocketData;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgTunnelSocketTokens {
|
|
||||||
uint16_t connection_id;
|
|
||||||
uint32_t num_tokens;
|
|
||||||
} SpiceMsgTunnelSocketTokens;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgTunnelSocketClosedAck {
|
|
||||||
uint16_t connection_id;
|
|
||||||
} SpiceMsgTunnelSocketClosedAck;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgcTunnelAddGenericService {
|
|
||||||
uint32_t type;
|
|
||||||
uint32_t id;
|
|
||||||
uint32_t group;
|
|
||||||
uint32_t port;
|
|
||||||
uint64_t name;
|
|
||||||
uint64_t description;
|
|
||||||
union {
|
|
||||||
SpiceMsgTunnelIpInfo ip;
|
|
||||||
} u;
|
|
||||||
} SpiceMsgcTunnelAddGenericService;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgcTunnelRemoveService {
|
|
||||||
uint32_t id;
|
|
||||||
} SpiceMsgcTunnelRemoveService;
|
|
||||||
|
|
||||||
/* connection id must be the first field in msgs directed to a specific connection */
|
|
||||||
|
|
||||||
typedef struct SpiceMsgcTunnelSocketOpenAck {
|
|
||||||
uint16_t connection_id;
|
|
||||||
uint32_t tokens;
|
|
||||||
} SpiceMsgcTunnelSocketOpenAck;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgcTunnelSocketOpenNack {
|
|
||||||
uint16_t connection_id;
|
|
||||||
} SpiceMsgcTunnelSocketOpenNack;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgcTunnelSocketData {
|
|
||||||
uint16_t connection_id;
|
|
||||||
uint8_t data[0];
|
|
||||||
} SpiceMsgcTunnelSocketData;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgcTunnelSocketFin {
|
|
||||||
uint16_t connection_id;
|
|
||||||
} SpiceMsgcTunnelSocketFin;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgcTunnelSocketClosed {
|
|
||||||
uint16_t connection_id;
|
|
||||||
} SpiceMsgcTunnelSocketClosed;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgcTunnelSocketClosedAck {
|
|
||||||
uint16_t connection_id;
|
|
||||||
} SpiceMsgcTunnelSocketClosedAck;
|
|
||||||
|
|
||||||
typedef struct SpiceMsgcTunnelSocketTokens {
|
|
||||||
uint16_t connection_id;
|
|
||||||
uint32_t num_tokens;
|
|
||||||
} SpiceMsgcTunnelSocketTokens;
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* _H_SPICE_PROTOCOL */
|
#include <common/generated_messages.h>
|
||||||
|
|
||||||
|
typedef SpiceMsgMainAgentTokens SpiceMsgcMainAgentTokens;
|
||||||
|
typedef SpiceMsgMainAgentTokens SpiceMsgcMainAgentStart;
|
||||||
|
typedef SpiceMsgDisplayDrawCopy SpiceMsgDisplayDrawBlend;
|
||||||
|
typedef SpiceMsgPlaybackMode SpiceMsgcRecordMode;
|
||||||
|
typedef SpiceMsgPlaybackPacket SpiceMsgcRecordPacket;
|
||||||
|
|
||||||
|
SPICE_END_DECLS
|
||||||
|
|
||||||
|
#endif // H_SPICE_COMMON_MESSAGES
|
||||||
|
|||||||
@ -1,44 +0,0 @@
|
|||||||
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
||||||
/*
|
|
||||||
Copyright (C) 2009 Red Hat, Inc.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _H_MUTEX
|
|
||||||
#define _H_MUTEX
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#include <windows.h>
|
|
||||||
typedef CRITICAL_SECTION mutex_t;
|
|
||||||
#define MUTEX_INIT(mutex) InitializeCriticalSection(&mutex)
|
|
||||||
#define MUTEX_LOCK(mutex) EnterCriticalSection(&mutex)
|
|
||||||
#define MUTEX_UNLOCK(mutex) LeaveCriticalSection(&mutex)
|
|
||||||
#else
|
|
||||||
#include <pthread.h>
|
|
||||||
typedef pthread_mutex_t mutex_t;
|
|
||||||
#define MUTEX_INIT(mutex) pthread_mutex_init(&mutex, NULL);
|
|
||||||
#define MUTEX_LOCK(mutex) pthread_mutex_lock(&mutex)
|
|
||||||
#define MUTEX_UNLOCK(mutex) pthread_mutex_unlock(&mutex)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // _H_MUTEX
|
|
||||||
251
common/ogl_ctx.c
251
common/ogl_ctx.c
@ -1,251 +0,0 @@
|
|||||||
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
||||||
/*
|
|
||||||
Copyright (C) 2009 Red Hat, Inc.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include <config.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <X11/Xlib.h>
|
|
||||||
#include <GL/glx.h>
|
|
||||||
|
|
||||||
#include "ogl_ctx.h"
|
|
||||||
#include "spice_common.h"
|
|
||||||
|
|
||||||
enum {
|
|
||||||
OGLCTX_TYPE_PBUF,
|
|
||||||
OGLCTX_TYPE_PIXMAP,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct OGLCtx {
|
|
||||||
int type;
|
|
||||||
Display *x_display;
|
|
||||||
GLXContext glx_context;
|
|
||||||
GLXDrawable drawable;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct OGLPixmapCtx {
|
|
||||||
OGLCtx base;
|
|
||||||
Pixmap pixmap;
|
|
||||||
} OGLPixmapCtx;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const char *oglctx_type_str(OGLCtx *ctx)
|
|
||||||
{
|
|
||||||
static const char *pbuf_str = "pbuf";
|
|
||||||
static const char *pixmap_str = "pixmap";
|
|
||||||
static const char *invalid_str = "invalid";
|
|
||||||
|
|
||||||
switch (ctx->type) {
|
|
||||||
case OGLCTX_TYPE_PBUF:
|
|
||||||
return pbuf_str;
|
|
||||||
case OGLCTX_TYPE_PIXMAP:
|
|
||||||
return pixmap_str;
|
|
||||||
default:
|
|
||||||
return invalid_str;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void oglctx_make_current(OGLCtx *ctx)
|
|
||||||
{
|
|
||||||
if (!glXMakeCurrent(ctx->x_display, ctx->drawable, ctx->glx_context)) {
|
|
||||||
printf("%s: failed\n", __FUNCTION__);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
OGLCtx *pbuf_create(int width, int heigth)
|
|
||||||
{
|
|
||||||
OGLCtx *ctx;
|
|
||||||
Display *x_display;
|
|
||||||
int num_configs;
|
|
||||||
GLXFBConfig *fb_config;
|
|
||||||
GLXPbuffer glx_pbuf;
|
|
||||||
GLXContext glx_context;
|
|
||||||
|
|
||||||
const int glx_attributes[] = { GLX_RENDER_TYPE, GLX_RGBA_BIT,
|
|
||||||
GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT,
|
|
||||||
GLX_RED_SIZE, 8,
|
|
||||||
GLX_GREEN_SIZE, 8,
|
|
||||||
GLX_BLUE_SIZE, 8,
|
|
||||||
GLX_ALPHA_SIZE, 8,
|
|
||||||
GLX_STENCIL_SIZE, 4,
|
|
||||||
0 };
|
|
||||||
|
|
||||||
int pbuf_attrib[] = { GLX_PRESERVED_CONTENTS, True,
|
|
||||||
GLX_PBUFFER_WIDTH, width,
|
|
||||||
GLX_PBUFFER_HEIGHT, heigth,
|
|
||||||
GLX_LARGEST_PBUFFER, False,
|
|
||||||
0, 0 };
|
|
||||||
|
|
||||||
if (!(ctx = calloc(1, sizeof(*ctx)))) {
|
|
||||||
printf("%s: alloc pbuf failed\n", __FUNCTION__);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(x_display = XOpenDisplay(NULL))) {
|
|
||||||
printf("%s: open display failed\n", __FUNCTION__);
|
|
||||||
goto error_1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(fb_config = glXChooseFBConfig(x_display, 0, glx_attributes, &num_configs)) ||
|
|
||||||
!num_configs) {
|
|
||||||
printf("%s: choose fb config failed\n", __FUNCTION__);
|
|
||||||
goto error_2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(glx_pbuf = glXCreatePbuffer(x_display, fb_config[0], pbuf_attrib))) {
|
|
||||||
goto error_3;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(glx_context = glXCreateNewContext(x_display, fb_config[0], GLX_RGBA_TYPE, NULL, True))) {
|
|
||||||
printf("%s: create context failed\n", __FUNCTION__);
|
|
||||||
goto error_4;
|
|
||||||
}
|
|
||||||
|
|
||||||
XFree(fb_config);
|
|
||||||
|
|
||||||
ctx->type = OGLCTX_TYPE_PBUF;
|
|
||||||
ctx->drawable = glx_pbuf;
|
|
||||||
ctx->glx_context = glx_context;
|
|
||||||
ctx->x_display = x_display;
|
|
||||||
|
|
||||||
return ctx;
|
|
||||||
|
|
||||||
error_4:
|
|
||||||
glXDestroyPbuffer(x_display, glx_pbuf);
|
|
||||||
|
|
||||||
error_3:
|
|
||||||
XFree(fb_config);
|
|
||||||
|
|
||||||
error_2:
|
|
||||||
XCloseDisplay(x_display);
|
|
||||||
|
|
||||||
error_1:
|
|
||||||
free(ctx);
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
OGLCtx *pixmap_create(int width, int heigth)
|
|
||||||
{
|
|
||||||
Display *x_display;
|
|
||||||
int num_configs;
|
|
||||||
GLXFBConfig *fb_config;
|
|
||||||
GLXPixmap glx_pixmap;
|
|
||||||
GLXContext glx_context;
|
|
||||||
Pixmap pixmap;
|
|
||||||
int screen;
|
|
||||||
Window root_window;
|
|
||||||
OGLPixmapCtx *pix;
|
|
||||||
|
|
||||||
const int glx_attributes[] = { GLX_RENDER_TYPE, GLX_RGBA_BIT,
|
|
||||||
GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
|
|
||||||
GLX_RED_SIZE, 8,
|
|
||||||
GLX_GREEN_SIZE, 8,
|
|
||||||
GLX_BLUE_SIZE, 8,
|
|
||||||
GLX_ALPHA_SIZE, 8,
|
|
||||||
GLX_STENCIL_SIZE, 4,
|
|
||||||
0 };
|
|
||||||
|
|
||||||
if (!(pix = calloc(1, sizeof(*pix)))) {
|
|
||||||
printf("%s: alloc pix failed\n", __FUNCTION__);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(x_display = XOpenDisplay(NULL))) {
|
|
||||||
printf("%s: open display failed\n", __FUNCTION__);
|
|
||||||
goto error_1;
|
|
||||||
}
|
|
||||||
|
|
||||||
screen = DefaultScreen(x_display);
|
|
||||||
root_window = RootWindow(x_display, screen);
|
|
||||||
|
|
||||||
if (!(fb_config = glXChooseFBConfig(x_display, 0, glx_attributes, &num_configs)) ||
|
|
||||||
!num_configs) {
|
|
||||||
printf("%s: choose fb config failed\n", __FUNCTION__);
|
|
||||||
goto error_2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(pixmap = XCreatePixmap(x_display, root_window, width, heigth, 32 /*use fb config*/))) {
|
|
||||||
printf("%s: create x pixmap failed\n", __FUNCTION__);
|
|
||||||
goto error_3;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(glx_pixmap = glXCreatePixmap(x_display, fb_config[0], pixmap, NULL))) {
|
|
||||||
printf("%s: create glx pixmap failed\n", __FUNCTION__);
|
|
||||||
goto error_4;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (!(glx_context = glXCreateNewContext(x_display, fb_config[0], GLX_RGBA_TYPE, NULL, True))) {
|
|
||||||
printf("%s: create context failed\n", __FUNCTION__);
|
|
||||||
goto error_5;
|
|
||||||
}
|
|
||||||
|
|
||||||
XFree(fb_config);
|
|
||||||
|
|
||||||
pix->base.type = OGLCTX_TYPE_PIXMAP;
|
|
||||||
pix->base.x_display = x_display;
|
|
||||||
pix->base.drawable = glx_pixmap;
|
|
||||||
pix->base.glx_context = glx_context;
|
|
||||||
pix->pixmap = pixmap;
|
|
||||||
|
|
||||||
return &pix->base;
|
|
||||||
|
|
||||||
error_5:
|
|
||||||
glXDestroyPixmap(x_display, glx_pixmap);
|
|
||||||
|
|
||||||
error_4:
|
|
||||||
XFreePixmap(x_display, pixmap);
|
|
||||||
|
|
||||||
error_3:
|
|
||||||
XFree(fb_config);
|
|
||||||
|
|
||||||
error_2:
|
|
||||||
XCloseDisplay(x_display);
|
|
||||||
|
|
||||||
error_1:
|
|
||||||
free(pix);
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void oglctx_destroy(OGLCtx *ctx)
|
|
||||||
{
|
|
||||||
if (!ctx) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// test is current ?
|
|
||||||
|
|
||||||
glXDestroyContext(ctx->x_display, ctx->glx_context);
|
|
||||||
switch (ctx->type) {
|
|
||||||
case OGLCTX_TYPE_PBUF:
|
|
||||||
glXDestroyPbuffer(ctx->x_display, ctx->drawable);
|
|
||||||
break;
|
|
||||||
case OGLCTX_TYPE_PIXMAP:
|
|
||||||
glXDestroyPixmap(ctx->x_display, ctx->drawable);
|
|
||||||
XFreePixmap(ctx->x_display, ((OGLPixmapCtx *)ctx)->pixmap);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
PANIC("invalid ogl ctx type");
|
|
||||||
}
|
|
||||||
|
|
||||||
XCloseDisplay(ctx->x_display);
|
|
||||||
free(ctx);
|
|
||||||
}
|
|
||||||
@ -15,22 +15,26 @@
|
|||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "pixman_utils.h"
|
#include "pixman_utils.h"
|
||||||
#include "spice_common.h"
|
|
||||||
#include <spice/macros.h>
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
|
||||||
#include "mem.h"
|
#include "mem.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* src is used for most OPs, hidden within _equation attribute. For some
|
||||||
|
* operations (such as "clear" and "noop") src is not used and then we have
|
||||||
|
* to add SPICE_GNUC_UNUSED, that's just a __attribute__((__unused__)), to
|
||||||
|
* make GCC happy.
|
||||||
|
* Also, according to GCC documentation [0], the unused attribute "(...) means
|
||||||
|
* that the variable is meant to be possibly unused. GCC does not produce a
|
||||||
|
* warning for this variable.". So, we are safe adding it, even if src is used
|
||||||
|
* for most OPs.
|
||||||
|
*/
|
||||||
#define SOLID_RASTER_OP(_name, _size, _type, _equation) \
|
#define SOLID_RASTER_OP(_name, _size, _type, _equation) \
|
||||||
static void \
|
static void \
|
||||||
solid_rop_ ## _name ## _ ## _size (_type *ptr, int len, _type src) \
|
solid_rop_ ## _name ## _ ## _size (_type *ptr, int len, SPICE_GNUC_UNUSED _type src) \
|
||||||
{ \
|
{ \
|
||||||
while (len--) { \
|
while (len--) { \
|
||||||
_type dst = *ptr; \
|
_type dst = *ptr; \
|
||||||
@ -206,12 +210,12 @@ void spice_pixman_fill_rect(pixman_image_t *dest,
|
|||||||
depth = spice_pixman_image_get_bpp(dest);
|
depth = spice_pixman_image_get_bpp(dest);
|
||||||
/* stride is in bytes, depth in bits */
|
/* stride is in bytes, depth in bits */
|
||||||
|
|
||||||
ASSERT(x >= 0);
|
spice_assert(x >= 0);
|
||||||
ASSERT(y >= 0);
|
spice_assert(y >= 0);
|
||||||
ASSERT(width > 0);
|
spice_assert(width > 0);
|
||||||
ASSERT(height > 0);
|
spice_assert(height > 0);
|
||||||
ASSERT(x + width <= pixman_image_get_width(dest));
|
spice_assert(x + width <= pixman_image_get_width(dest));
|
||||||
ASSERT(y + height <= pixman_image_get_height(dest));
|
spice_assert(y + height <= pixman_image_get_height(dest));
|
||||||
|
|
||||||
if (pixman_fill(bits,
|
if (pixman_fill(bits,
|
||||||
stride / 4,
|
stride / 4,
|
||||||
@ -231,7 +235,7 @@ void spice_pixman_fill_rect(pixman_image_t *dest,
|
|||||||
byte_width = 2 * width;
|
byte_width = 2 * width;
|
||||||
value = (value & 0xffff) * 0x00010001;
|
value = (value & 0xffff) * 0x00010001;
|
||||||
} else {
|
} else {
|
||||||
ASSERT (depth == 32)
|
spice_assert (depth == 32);
|
||||||
byte_line = ((uint8_t *)bits) + stride * y + x * 4;
|
byte_line = ((uint8_t *)bits) + stride * y + x * 4;
|
||||||
byte_width = 4 * width;
|
byte_width = 4 * width;
|
||||||
}
|
}
|
||||||
@ -298,13 +302,13 @@ void spice_pixman_fill_rect_rop(pixman_image_t *dest,
|
|||||||
depth = spice_pixman_image_get_bpp(dest);
|
depth = spice_pixman_image_get_bpp(dest);
|
||||||
/* stride is in bytes, depth in bits */
|
/* stride is in bytes, depth in bits */
|
||||||
|
|
||||||
ASSERT(x >= 0);
|
spice_assert(x >= 0);
|
||||||
ASSERT(y >= 0);
|
spice_assert(y >= 0);
|
||||||
ASSERT(width > 0);
|
spice_assert(width > 0);
|
||||||
ASSERT(height > 0);
|
spice_assert(height > 0);
|
||||||
ASSERT(x + width <= pixman_image_get_width(dest));
|
spice_assert(x + width <= pixman_image_get_width(dest));
|
||||||
ASSERT(y + height <= pixman_image_get_height(dest));
|
spice_assert(y + height <= pixman_image_get_height(dest));
|
||||||
ASSERT(rop >= 0 && rop < 16);
|
spice_assert(rop < 16);
|
||||||
|
|
||||||
if (depth == 8) {
|
if (depth == 8) {
|
||||||
solid_rop_8_func_t rop_func = solid_rops_8[rop];
|
solid_rop_8_func_t rop_func = solid_rops_8[rop];
|
||||||
@ -358,13 +362,13 @@ void spice_pixman_tile_rect(pixman_image_t *dest,
|
|||||||
tile_width = pixman_image_get_width(tile);
|
tile_width = pixman_image_get_width(tile);
|
||||||
tile_height = pixman_image_get_height(tile);
|
tile_height = pixman_image_get_height(tile);
|
||||||
|
|
||||||
ASSERT(x >= 0);
|
spice_assert(x >= 0);
|
||||||
ASSERT(y >= 0);
|
spice_assert(y >= 0);
|
||||||
ASSERT(width > 0);
|
spice_assert(width > 0);
|
||||||
ASSERT(height > 0);
|
spice_assert(height > 0);
|
||||||
ASSERT(x + width <= pixman_image_get_width(dest));
|
spice_assert(x + width <= pixman_image_get_width(dest));
|
||||||
ASSERT(y + height <= pixman_image_get_height(dest));
|
spice_assert(y + height <= pixman_image_get_height(dest));
|
||||||
ASSERT(depth == spice_pixman_image_get_bpp(tile));
|
spice_assert(depth == spice_pixman_image_get_bpp(tile));
|
||||||
|
|
||||||
tile_start_x = (x - offset_x) % tile_width;
|
tile_start_x = (x - offset_x) % tile_width;
|
||||||
if (tile_start_x < 0) {
|
if (tile_start_x < 0) {
|
||||||
@ -406,7 +410,7 @@ void spice_pixman_tile_rect(pixman_image_t *dest,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ASSERT (depth == 32);
|
spice_assert (depth == 32);
|
||||||
|
|
||||||
byte_line = ((uint8_t *)bits) + stride * y + x * 4;
|
byte_line = ((uint8_t *)bits) + stride * y + x * 4;
|
||||||
tile_line = ((uint8_t *)tile_bits) + tile_stride * tile_start_y + tile_start_x * 4;
|
tile_line = ((uint8_t *)tile_bits) + tile_stride * tile_start_y + tile_start_x * 4;
|
||||||
@ -449,14 +453,14 @@ void spice_pixman_tile_rect_rop(pixman_image_t *dest,
|
|||||||
tile_width = pixman_image_get_width(tile);
|
tile_width = pixman_image_get_width(tile);
|
||||||
tile_height = pixman_image_get_height(tile);
|
tile_height = pixman_image_get_height(tile);
|
||||||
|
|
||||||
ASSERT(x >= 0);
|
spice_assert(x >= 0);
|
||||||
ASSERT(y >= 0);
|
spice_assert(y >= 0);
|
||||||
ASSERT(width > 0);
|
spice_assert(width > 0);
|
||||||
ASSERT(height > 0);
|
spice_assert(height > 0);
|
||||||
ASSERT(x + width <= pixman_image_get_width(dest));
|
spice_assert(x + width <= pixman_image_get_width(dest));
|
||||||
ASSERT(y + height <= pixman_image_get_height(dest));
|
spice_assert(y + height <= pixman_image_get_height(dest));
|
||||||
ASSERT(rop >= 0 && rop < 16);
|
spice_assert(rop < 16);
|
||||||
ASSERT(depth == spice_pixman_image_get_bpp(tile));
|
spice_assert(depth == spice_pixman_image_get_bpp(tile));
|
||||||
|
|
||||||
tile_start_x = (x - offset_x) % tile_width;
|
tile_start_x = (x - offset_x) % tile_width;
|
||||||
if (tile_start_x < 0) {
|
if (tile_start_x < 0) {
|
||||||
@ -504,7 +508,7 @@ void spice_pixman_tile_rect_rop(pixman_image_t *dest,
|
|||||||
} else {
|
} else {
|
||||||
tiled_rop_32_func_t rop_func = tiled_rops_32[rop];
|
tiled_rop_32_func_t rop_func = tiled_rops_32[rop];
|
||||||
|
|
||||||
ASSERT (depth == 32);
|
spice_assert (depth == 32);
|
||||||
|
|
||||||
byte_line = ((uint8_t *)bits) + stride * y + x * 4;
|
byte_line = ((uint8_t *)bits) + stride * y + x * 4;
|
||||||
tile_line = ((uint8_t *)tile_bits) + tile_stride * tile_start_y + tile_start_x * 4;
|
tile_line = ((uint8_t *)tile_bits) + tile_stride * tile_start_y + tile_start_x * 4;
|
||||||
@ -536,6 +540,11 @@ void spice_pixman_blit(pixman_image_t *dest,
|
|||||||
uint8_t *src_line;
|
uint8_t *src_line;
|
||||||
int byte_width;
|
int byte_width;
|
||||||
|
|
||||||
|
if (!src) {
|
||||||
|
fprintf(stderr, "missing src!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
bits = pixman_image_get_data(dest);
|
bits = pixman_image_get_data(dest);
|
||||||
stride = pixman_image_get_stride(dest);
|
stride = pixman_image_get_stride(dest);
|
||||||
depth = spice_pixman_image_get_bpp(dest);
|
depth = spice_pixman_image_get_bpp(dest);
|
||||||
@ -569,17 +578,17 @@ void spice_pixman_blit(pixman_image_t *dest,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT(src_x >= 0);
|
spice_assert(src_x >= 0);
|
||||||
ASSERT(src_y >= 0);
|
spice_assert(src_y >= 0);
|
||||||
ASSERT(dest_x >= 0);
|
spice_assert(dest_x >= 0);
|
||||||
ASSERT(dest_y >= 0);
|
spice_assert(dest_y >= 0);
|
||||||
ASSERT(width > 0);
|
spice_assert(width > 0);
|
||||||
ASSERT(height > 0);
|
spice_assert(height > 0);
|
||||||
ASSERT(dest_x + width <= pixman_image_get_width(dest));
|
spice_assert(dest_x + width <= pixman_image_get_width(dest));
|
||||||
ASSERT(dest_y + height <= pixman_image_get_height(dest));
|
spice_assert(dest_y + height <= pixman_image_get_height(dest));
|
||||||
ASSERT(src_x + width <= pixman_image_get_width(src));
|
spice_assert(src_x + width <= pixman_image_get_width(src));
|
||||||
ASSERT(src_y + height <= pixman_image_get_height(src));
|
spice_assert(src_y + height <= pixman_image_get_height(src));
|
||||||
ASSERT(depth == src_depth);
|
spice_assert(depth == src_depth);
|
||||||
|
|
||||||
if (pixman_blt(src_bits,
|
if (pixman_blt(src_bits,
|
||||||
bits,
|
bits,
|
||||||
@ -601,7 +610,7 @@ void spice_pixman_blit(pixman_image_t *dest,
|
|||||||
byte_width = width * 2;
|
byte_width = width * 2;
|
||||||
src_line = ((uint8_t *)src_bits) + src_stride * src_y + src_x * 2;
|
src_line = ((uint8_t *)src_bits) + src_stride * src_y + src_x * 2;
|
||||||
} else {
|
} else {
|
||||||
ASSERT (depth == 32);
|
spice_assert (depth == 32);
|
||||||
byte_line = ((uint8_t *)bits) + stride * dest_y + dest_x * 4;
|
byte_line = ((uint8_t *)bits) + stride * dest_y + dest_x * 4;
|
||||||
byte_width = width * 4;
|
byte_width = width * 4;
|
||||||
src_line = ((uint8_t *)src_bits) + src_stride * src_y + src_x * 4;
|
src_line = ((uint8_t *)src_bits) + src_stride * src_y + src_x * 4;
|
||||||
@ -660,17 +669,17 @@ void spice_pixman_blit_rop (pixman_image_t *dest,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT(src_x >= 0);
|
spice_assert(src_x >= 0);
|
||||||
ASSERT(src_y >= 0);
|
spice_assert(src_y >= 0);
|
||||||
ASSERT(dest_x >= 0);
|
spice_assert(dest_x >= 0);
|
||||||
ASSERT(dest_y >= 0);
|
spice_assert(dest_y >= 0);
|
||||||
ASSERT(width > 0);
|
spice_assert(width > 0);
|
||||||
ASSERT(height > 0);
|
spice_assert(height > 0);
|
||||||
ASSERT(dest_x + width <= pixman_image_get_width(dest));
|
spice_assert(dest_x + width <= pixman_image_get_width(dest));
|
||||||
ASSERT(dest_y + height <= pixman_image_get_height(dest));
|
spice_assert(dest_y + height <= pixman_image_get_height(dest));
|
||||||
ASSERT(src_x + width <= pixman_image_get_width(src));
|
spice_assert(src_x + width <= pixman_image_get_width(src));
|
||||||
ASSERT(src_y + height <= pixman_image_get_height(src));
|
spice_assert(src_y + height <= pixman_image_get_height(src));
|
||||||
ASSERT(depth == src_depth);
|
spice_assert(depth == src_depth);
|
||||||
|
|
||||||
if (depth == 8) {
|
if (depth == 8) {
|
||||||
copy_rop_8_func_t rop_func = copy_rops_8[rop];
|
copy_rop_8_func_t rop_func = copy_rops_8[rop];
|
||||||
@ -697,7 +706,7 @@ void spice_pixman_blit_rop (pixman_image_t *dest,
|
|||||||
} else {
|
} else {
|
||||||
copy_rop_32_func_t rop_func = copy_rops_32[rop];
|
copy_rop_32_func_t rop_func = copy_rops_32[rop];
|
||||||
|
|
||||||
ASSERT (depth == 32);
|
spice_assert (depth == 32);
|
||||||
byte_line = ((uint8_t *)bits) + stride * dest_y + dest_x * 4;
|
byte_line = ((uint8_t *)bits) + stride * dest_y + dest_x * 4;
|
||||||
src_line = ((uint8_t *)src_bits) + src_stride * src_y + src_x * 4;
|
src_line = ((uint8_t *)src_bits) + src_stride * src_y + src_x * 4;
|
||||||
|
|
||||||
@ -756,17 +765,17 @@ void spice_pixman_blit_colorkey (pixman_image_t *dest,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT(src_x >= 0);
|
spice_assert(src_x >= 0);
|
||||||
ASSERT(src_y >= 0);
|
spice_assert(src_y >= 0);
|
||||||
ASSERT(dest_x >= 0);
|
spice_assert(dest_x >= 0);
|
||||||
ASSERT(dest_y >= 0);
|
spice_assert(dest_y >= 0);
|
||||||
ASSERT(width > 0);
|
spice_assert(width > 0);
|
||||||
ASSERT(height > 0);
|
spice_assert(height > 0);
|
||||||
ASSERT(dest_x + width <= pixman_image_get_width(dest));
|
spice_assert(dest_x + width <= pixman_image_get_width(dest));
|
||||||
ASSERT(dest_y + height <= pixman_image_get_height(dest));
|
spice_assert(dest_y + height <= pixman_image_get_height(dest));
|
||||||
ASSERT(src_x + width <= pixman_image_get_width(src));
|
spice_assert(src_x + width <= pixman_image_get_width(src));
|
||||||
ASSERT(src_y + height <= pixman_image_get_height(src));
|
spice_assert(src_y + height <= pixman_image_get_height(src));
|
||||||
ASSERT(depth == spice_pixman_image_get_bpp(src));
|
spice_assert(depth == spice_pixman_image_get_bpp(src));
|
||||||
|
|
||||||
if (depth == 8) {
|
if (depth == 8) {
|
||||||
byte_line = ((uint8_t *)bits) + stride * dest_y + dest_x;
|
byte_line = ((uint8_t *)bits) + stride * dest_y + dest_x;
|
||||||
@ -806,7 +815,7 @@ void spice_pixman_blit_colorkey (pixman_image_t *dest,
|
|||||||
src_line += src_stride;
|
src_line += src_stride;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ASSERT (depth == 32);
|
spice_assert (depth == 32);
|
||||||
byte_line = ((uint8_t *)bits) + stride * dest_y + dest_x * 4;
|
byte_line = ((uint8_t *)bits) + stride * dest_y + dest_x * 4;
|
||||||
src_line = ((uint8_t *)src_bits) + src_stride * src_y + src_x * 4;
|
src_line = ((uint8_t *)src_bits) + src_stride * src_y + src_x * 4;
|
||||||
|
|
||||||
@ -924,8 +933,7 @@ pixman_format_code_t spice_surface_format_to_pixman(uint32_t surface_format)
|
|||||||
case SPICE_SURFACE_FMT_32_ARGB:
|
case SPICE_SURFACE_FMT_32_ARGB:
|
||||||
return PIXMAN_a8r8g8b8;
|
return PIXMAN_a8r8g8b8;
|
||||||
default:
|
default:
|
||||||
printf("Unknown surface format %d\n", surface_format);
|
g_error("Unknown surface format %d\n", surface_format);
|
||||||
abort();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return (pixman_format_code_t)0; /* Not reached */
|
return (pixman_format_code_t)0; /* Not reached */
|
||||||
@ -958,10 +966,12 @@ pixman_format_code_t spice_bitmap_format_to_pixman(int bitmap_format,
|
|||||||
case SPICE_BITMAP_FMT_RGBA:
|
case SPICE_BITMAP_FMT_RGBA:
|
||||||
return PIXMAN_a8r8g8b8;
|
return PIXMAN_a8r8g8b8;
|
||||||
|
|
||||||
|
case SPICE_BITMAP_FMT_8BIT_A:
|
||||||
|
return PIXMAN_a8;
|
||||||
|
|
||||||
case SPICE_BITMAP_FMT_INVALID:
|
case SPICE_BITMAP_FMT_INVALID:
|
||||||
default:
|
default:
|
||||||
printf("Unknown bitmap format %d\n", bitmap_format);
|
g_error("Unknown bitmap format %d\n", bitmap_format);
|
||||||
abort();
|
|
||||||
return PIXMAN_a8r8g8b8;
|
return PIXMAN_a8r8g8b8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -985,25 +995,13 @@ pixman_image_t *spice_bitmap_try_as_pixman(int src_format,
|
|||||||
|
|
||||||
switch (src_format) {
|
switch (src_format) {
|
||||||
case SPICE_BITMAP_FMT_32BIT:
|
case SPICE_BITMAP_FMT_32BIT:
|
||||||
#ifdef WORDS_BIGENDIAN
|
pixman_format = PIXMAN_LE_x8r8g8b8;
|
||||||
pixman_format = PIXMAN_b8g8r8x8;
|
|
||||||
#else
|
|
||||||
pixman_format = PIXMAN_x8r8g8b8;
|
|
||||||
#endif
|
|
||||||
break;
|
break;
|
||||||
case SPICE_BITMAP_FMT_RGBA:
|
case SPICE_BITMAP_FMT_RGBA:
|
||||||
#ifdef WORDS_BIGENDIAN
|
pixman_format = PIXMAN_LE_a8r8g8b8;
|
||||||
pixman_format = PIXMAN_b8g8r8a8;
|
|
||||||
#else
|
|
||||||
pixman_format = PIXMAN_a8r8g8b8;
|
|
||||||
#endif
|
|
||||||
break;
|
break;
|
||||||
case SPICE_BITMAP_FMT_24BIT:
|
case SPICE_BITMAP_FMT_24BIT:
|
||||||
#ifdef WORDS_BIGENDIAN
|
pixman_format = PIXMAN_LE_r8g8b8;
|
||||||
pixman_format = PIXMAN_b8g8r8;
|
|
||||||
#else
|
|
||||||
pixman_format = PIXMAN_r8g8b8;
|
|
||||||
#endif
|
|
||||||
break;
|
break;
|
||||||
case SPICE_BITMAP_FMT_16BIT:
|
case SPICE_BITMAP_FMT_16BIT:
|
||||||
#ifdef WORDS_BIGENDIAN
|
#ifdef WORDS_BIGENDIAN
|
||||||
@ -1037,26 +1035,6 @@ pixman_image_t *spice_bitmap_try_as_pixman(int src_format,
|
|||||||
#define UINT32_FROM_LE(x) (x)
|
#define UINT32_FROM_LE(x) (x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static INLINE uint32_t rgb_16_555_to_32(uint16_t color)
|
|
||||||
{
|
|
||||||
uint32_t ret;
|
|
||||||
|
|
||||||
ret = ((color & 0x001f) << 3) | ((color & 0x001c) >> 2);
|
|
||||||
ret |= ((color & 0x03e0) << 6) | ((color & 0x0380) << 1);
|
|
||||||
ret |= ((color & 0x7c00) << 9) | ((color & 0x7000) << 4);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static INLINE uint16_t rgb_32_to_16_555(uint32_t color)
|
|
||||||
{
|
|
||||||
return
|
|
||||||
(((color) >> 3) & 0x001f) |
|
|
||||||
(((color) >> 6) & 0x03e0) |
|
|
||||||
(((color) >> 9) & 0x7c00);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void bitmap_32_to_32(uint8_t* dest, int dest_stride,
|
static void bitmap_32_to_32(uint8_t* dest, int dest_stride,
|
||||||
uint8_t* src, int src_stride,
|
uint8_t* src, int src_stride,
|
||||||
int width, uint8_t* end)
|
int width, uint8_t* end)
|
||||||
@ -1078,6 +1056,15 @@ static void bitmap_32_to_32(uint8_t* dest, int dest_stride,
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void bitmap_8_to_8(uint8_t* dest, int dest_stride,
|
||||||
|
uint8_t* src, int src_stride,
|
||||||
|
int width, uint8_t* end)
|
||||||
|
{
|
||||||
|
for (; src != end; src += src_stride, dest += dest_stride) {
|
||||||
|
memcpy(dest, src, width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void bitmap_24_to_32(uint8_t* dest, int dest_stride,
|
static void bitmap_24_to_32(uint8_t* dest, int dest_stride,
|
||||||
uint8_t* src, int src_stride,
|
uint8_t* src, int src_stride,
|
||||||
int width, uint8_t* end)
|
int width, uint8_t* end)
|
||||||
@ -1131,7 +1118,7 @@ static void bitmap_8_32_to_32(uint8_t *dest, int dest_stride,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!palette) {
|
if (!palette) {
|
||||||
PANIC("No palette");
|
spice_error("No palette");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1177,7 +1164,7 @@ static void bitmap_8_16_to_16_555(uint8_t *dest, int dest_stride,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!palette) {
|
if (!palette) {
|
||||||
PANIC("No palette");
|
spice_error("No palette");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1223,7 +1210,7 @@ static void bitmap_4be_32_to_32(uint8_t* dest, int dest_stride,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!palette) {
|
if (!palette) {
|
||||||
PANIC("No palette");
|
spice_error("No palette");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1273,7 +1260,7 @@ static void bitmap_4be_16_to_16_555(uint8_t* dest, int dest_stride,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!palette) {
|
if (!palette) {
|
||||||
PANIC("No palette");
|
spice_error("No palette");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1310,7 +1297,7 @@ static void bitmap_4be_16_to_16_555(uint8_t* dest, int dest_stride,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static INLINE int test_bit_be(void* addr, int bit)
|
static inline int test_bit_be(void* addr, int bit)
|
||||||
{
|
{
|
||||||
return !!(((uint8_t*)addr)[bit >> 3] & (0x80 >> (bit & 0x07)));
|
return !!(((uint8_t*)addr)[bit >> 3] & (0x80 >> (bit & 0x07)));
|
||||||
}
|
}
|
||||||
@ -1323,7 +1310,7 @@ static void bitmap_1be_32_to_32(uint8_t* dest, int dest_stride,
|
|||||||
uint32_t fore_color;
|
uint32_t fore_color;
|
||||||
uint32_t back_color;
|
uint32_t back_color;
|
||||||
|
|
||||||
ASSERT(palette != NULL);
|
spice_assert(palette != NULL);
|
||||||
|
|
||||||
if (!palette) {
|
if (!palette) {
|
||||||
return;
|
return;
|
||||||
@ -1355,7 +1342,7 @@ static void bitmap_1be_16_to_16_555(uint8_t* dest, int dest_stride,
|
|||||||
uint16_t fore_color;
|
uint16_t fore_color;
|
||||||
uint16_t back_color;
|
uint16_t back_color;
|
||||||
|
|
||||||
ASSERT(palette != NULL);
|
spice_assert(palette != NULL);
|
||||||
|
|
||||||
if (!palette) {
|
if (!palette) {
|
||||||
return;
|
return;
|
||||||
@ -1380,6 +1367,25 @@ static void bitmap_1be_16_to_16_555(uint8_t* dest, int dest_stride,
|
|||||||
|
|
||||||
#ifdef NOT_USED_ATM
|
#ifdef NOT_USED_ATM
|
||||||
|
|
||||||
|
static inline uint32_t rgb_16_555_to_32(uint16_t color)
|
||||||
|
{
|
||||||
|
uint32_t ret;
|
||||||
|
|
||||||
|
ret = ((color & 0x001f) << 3) | ((color & 0x001c) >> 2);
|
||||||
|
ret |= ((color & 0x03e0) << 6) | ((color & 0x0380) << 1);
|
||||||
|
ret |= ((color & 0x7c00) << 9) | ((color & 0x7000) << 4);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint16_t rgb_32_to_16_555(uint32_t color)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
(((color) >> 3) & 0x001f) |
|
||||||
|
(((color) >> 6) & 0x03e0) |
|
||||||
|
(((color) >> 9) & 0x7c00);
|
||||||
|
}
|
||||||
|
|
||||||
static void bitmap_16_to_32(uint8_t* dest, int dest_stride,
|
static void bitmap_16_to_32(uint8_t* dest, int dest_stride,
|
||||||
uint8_t* src, int src_stride,
|
uint8_t* src, int src_stride,
|
||||||
int width, uint8_t* end)
|
int width, uint8_t* end)
|
||||||
@ -1461,7 +1467,7 @@ pixman_image_t *spice_bitmap_to_pixman(pixman_image_t *dest_image,
|
|||||||
dest = (uint8_t *)pixman_image_get_data(dest_image);
|
dest = (uint8_t *)pixman_image_get_data(dest_image);
|
||||||
dest_stride = pixman_image_get_stride(dest_image);
|
dest_stride = pixman_image_get_stride(dest_image);
|
||||||
if (!(flags & SPICE_BITMAP_FLAGS_TOP_DOWN)) {
|
if (!(flags & SPICE_BITMAP_FLAGS_TOP_DOWN)) {
|
||||||
ASSERT(height > 0);
|
spice_assert(height > 0);
|
||||||
dest += dest_stride * (height - 1);
|
dest += dest_stride * (height - 1);
|
||||||
dest_stride = -dest_stride;
|
dest_stride = -dest_stride;
|
||||||
}
|
}
|
||||||
@ -1472,6 +1478,9 @@ pixman_image_t *spice_bitmap_to_pixman(pixman_image_t *dest_image,
|
|||||||
case SPICE_BITMAP_FMT_RGBA:
|
case SPICE_BITMAP_FMT_RGBA:
|
||||||
bitmap_32_to_32(dest, dest_stride, src, src_stride, width, end);
|
bitmap_32_to_32(dest, dest_stride, src, src_stride, width, end);
|
||||||
break;
|
break;
|
||||||
|
case SPICE_BITMAP_FMT_8BIT_A:
|
||||||
|
bitmap_8_to_8(dest, dest_stride, src, src_stride, width, end);
|
||||||
|
break;
|
||||||
case SPICE_BITMAP_FMT_24BIT:
|
case SPICE_BITMAP_FMT_24BIT:
|
||||||
bitmap_24_to_32(dest, dest_stride, src, src_stride, width, end);
|
bitmap_24_to_32(dest, dest_stride, src, src_stride, width, end);
|
||||||
break;
|
break;
|
||||||
@ -1485,7 +1494,7 @@ pixman_image_t *spice_bitmap_to_pixman(pixman_image_t *dest_image,
|
|||||||
} else if (palette_surface_format == SPICE_SURFACE_FMT_16_555) {
|
} else if (palette_surface_format == SPICE_SURFACE_FMT_16_555) {
|
||||||
bitmap_8_16_to_16_555(dest, dest_stride, src, src_stride, width, end, palette);
|
bitmap_8_16_to_16_555(dest, dest_stride, src, src_stride, width, end, palette);
|
||||||
} else {
|
} else {
|
||||||
PANIC("Unsupported palette format");
|
spice_error("Unsupported palette format");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SPICE_BITMAP_FMT_4BIT_BE:
|
case SPICE_BITMAP_FMT_4BIT_BE:
|
||||||
@ -1495,7 +1504,7 @@ pixman_image_t *spice_bitmap_to_pixman(pixman_image_t *dest_image,
|
|||||||
} else if (palette_surface_format == SPICE_SURFACE_FMT_16_555) {
|
} else if (palette_surface_format == SPICE_SURFACE_FMT_16_555) {
|
||||||
bitmap_4be_16_to_16_555(dest, dest_stride, src, src_stride, width, end, palette);
|
bitmap_4be_16_to_16_555(dest, dest_stride, src, src_stride, width, end, palette);
|
||||||
} else {
|
} else {
|
||||||
PANIC("Unsupported palette format");
|
spice_error("Unsupported palette format");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SPICE_BITMAP_FMT_1BIT_BE:
|
case SPICE_BITMAP_FMT_1BIT_BE:
|
||||||
@ -1505,11 +1514,11 @@ pixman_image_t *spice_bitmap_to_pixman(pixman_image_t *dest_image,
|
|||||||
} else if (palette_surface_format == SPICE_SURFACE_FMT_16_555) {
|
} else if (palette_surface_format == SPICE_SURFACE_FMT_16_555) {
|
||||||
bitmap_1be_16_to_16_555(dest, dest_stride, src, src_stride, width, end, palette);
|
bitmap_1be_16_to_16_555(dest, dest_stride, src, src_stride, width, end, palette);
|
||||||
} else {
|
} else {
|
||||||
PANIC("Unsupported palette format");
|
spice_error("Unsupported palette format");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
PANIC("Unsupported bitmap format");
|
spice_error("Unsupported bitmap format");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -16,20 +16,29 @@
|
|||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _H__PIXMAN_UTILS
|
#ifndef H_SPICE_COMMON_PIXMAN_UTILS
|
||||||
#define _H__PIXMAN_UTILS
|
#define H_SPICE_COMMON_PIXMAN_UTILS
|
||||||
|
|
||||||
#include <spice/types.h>
|
#include <spice/types.h>
|
||||||
|
#include <spice/macros.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#define PIXMAN_DONT_DEFINE_STDINT
|
#define PIXMAN_DONT_DEFINE_STDINT
|
||||||
#include <pixman.h>
|
#include <pixman.h>
|
||||||
|
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef WORDS_BIGENDIAN
|
||||||
extern "C" {
|
# define PIXMAN_LE_x8r8g8b8 PIXMAN_b8g8r8x8
|
||||||
|
# define PIXMAN_LE_a8r8g8b8 PIXMAN_b8g8r8a8
|
||||||
|
# define PIXMAN_LE_r8g8b8 PIXMAN_b8g8r8
|
||||||
|
#else
|
||||||
|
# define PIXMAN_LE_x8r8g8b8 PIXMAN_x8r8g8b8
|
||||||
|
# define PIXMAN_LE_a8r8g8b8 PIXMAN_a8r8g8b8
|
||||||
|
# define PIXMAN_LE_r8g8b8 PIXMAN_r8g8b8
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
SPICE_BEGIN_DECLS
|
||||||
|
|
||||||
/* This lists all possible 2 argument binary raster ops.
|
/* This lists all possible 2 argument binary raster ops.
|
||||||
* This enum has the same values as the X11 GXcopy type
|
* This enum has the same values as the X11 GXcopy type
|
||||||
* and same as the GL constants (GL_AND etc) if you
|
* and same as the GL constants (GL_AND etc) if you
|
||||||
@ -129,8 +138,6 @@ void spice_pixman_copy_rect(pixman_image_t *image,
|
|||||||
int w, int h,
|
int w, int h,
|
||||||
int dest_x, int dest_y);
|
int dest_x, int dest_y);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
SPICE_END_DECLS
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* _H__PIXMAN_UTILS */
|
#endif // H_SPICE_COMMON_PIXMAN_UTILS
|
||||||
|
|||||||
711
common/quic.c
711
common/quic.c
File diff suppressed because it is too large
Load Diff
@ -16,14 +16,13 @@
|
|||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __QUIC_H
|
#ifndef H_SPICE_COMMON_QUIC
|
||||||
#define __QUIC_H
|
#define H_SPICE_COMMON_QUIC
|
||||||
|
|
||||||
#include "quic_config.h"
|
#include <spice/macros.h>
|
||||||
|
#include "macros.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
SPICE_BEGIN_DECLS
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
QUIC_IMAGE_TYPE_INVALID,
|
QUIC_IMAGE_TYPE_INVALID,
|
||||||
@ -41,9 +40,10 @@ typedef void *QuicContext;
|
|||||||
|
|
||||||
typedef struct QuicUsrContext QuicUsrContext;
|
typedef struct QuicUsrContext QuicUsrContext;
|
||||||
struct QuicUsrContext {
|
struct QuicUsrContext {
|
||||||
void (*error)(QuicUsrContext *usr, const char *fmt, ...);
|
SPICE_GNUC_NORETURN
|
||||||
void (*warn)(QuicUsrContext *usr, const char *fmt, ...);
|
SPICE_GNUC_PRINTF(2, 3) void (*error)(QuicUsrContext *usr, const char *fmt, ...);
|
||||||
void (*info)(QuicUsrContext *usr, const char *fmt, ...);
|
SPICE_GNUC_PRINTF(2, 3) void (*warn)(QuicUsrContext *usr, const char *fmt, ...);
|
||||||
|
SPICE_GNUC_PRINTF(2, 3) void (*info)(QuicUsrContext *usr, const char *fmt, ...);
|
||||||
void *(*malloc)(QuicUsrContext *usr, int size);
|
void *(*malloc)(QuicUsrContext *usr, int size);
|
||||||
void (*free)(QuicUsrContext *usr, void *ptr);
|
void (*free)(QuicUsrContext *usr, void *ptr);
|
||||||
int (*more_space)(QuicUsrContext *usr, uint32_t **io_ptr, int rows_completed);
|
int (*more_space)(QuicUsrContext *usr, uint32_t **io_ptr, int rows_completed);
|
||||||
@ -63,10 +63,6 @@ int quic_decode(QuicContext *quic, QuicImageType type, uint8_t *buf, int stride)
|
|||||||
QuicContext *quic_create(QuicUsrContext *usr);
|
QuicContext *quic_create(QuicUsrContext *usr);
|
||||||
void quic_destroy(QuicContext *quic);
|
void quic_destroy(QuicContext *quic);
|
||||||
|
|
||||||
void quic_init(void);
|
SPICE_END_DECLS
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -16,15 +16,13 @@
|
|||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __QUIC_CONFIG_H
|
#ifndef H_SPICE_COMMON_QUIC_CONFIG
|
||||||
#define __QUIC_CONFIG_H
|
#define H_SPICE_COMMON_QUIC_CONFIG
|
||||||
|
|
||||||
#include <spice/types.h>
|
#include <spice/types.h>
|
||||||
#include <spice/macros.h>
|
#include <spice/macros.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
SPICE_BEGIN_DECLS
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -41,8 +39,6 @@ extern "C" {
|
|||||||
#endif // QXLDD
|
#endif // QXLDD
|
||||||
#endif //__GNUC__
|
#endif //__GNUC__
|
||||||
|
|
||||||
#ifdef __cplusplus
|
SPICE_END_DECLS
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -15,9 +15,7 @@
|
|||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef QUIC_FAMILY_8BPC
|
#ifdef QUIC_FAMILY_8BPC
|
||||||
#undef QUIC_FAMILY_8BPC
|
#undef QUIC_FAMILY_8BPC
|
||||||
@ -34,26 +32,19 @@
|
|||||||
#define BPC 5
|
#define BPC 5
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static inline unsigned int FNAME(golomb_code)(const BYTE n, const unsigned int l)
|
||||||
static unsigned int FNAME(golomb_code_len)(const BYTE n, const unsigned int l)
|
|
||||||
{
|
{
|
||||||
if (n < VNAME(family).nGRcodewords[l]) {
|
return VNAME(family).golomb_code[n][l];
|
||||||
return (n >> l) + 1 + l;
|
|
||||||
} else {
|
|
||||||
return VNAME(family).notGRcwlen[l];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void FNAME(golomb_coding)(const BYTE n, const unsigned int l, unsigned int * const codeword,
|
static inline unsigned int FNAME(golomb_code_len)(const BYTE n, const unsigned int l)
|
||||||
unsigned int * const codewordlen)
|
|
||||||
{
|
{
|
||||||
if (n < VNAME(family).nGRcodewords[l]) {
|
return VNAME(family).golomb_code_len[n][l];
|
||||||
(*codeword) = bitat[l] | (n & bppmask[l]);
|
|
||||||
(*codewordlen) = (n >> l) + l + 1;
|
|
||||||
} else {
|
|
||||||
(*codeword) = n - VNAME(family).nGRcodewords[l];
|
|
||||||
(*codewordlen) = VNAME(family).notGRcwlen[l];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void FNAME(golomb_coding)(Encoder *encoder, const BYTE n, const unsigned int l)
|
||||||
|
{
|
||||||
|
encode(encoder, FNAME(golomb_code)(n, l), FNAME(golomb_code_len)(n, l));
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int FNAME(golomb_decoding)(const unsigned int l, const unsigned int bits,
|
static unsigned int FNAME(golomb_decoding)(const unsigned int l, const unsigned int bits,
|
||||||
@ -74,13 +65,16 @@ static unsigned int FNAME(golomb_decoding)(const unsigned int l, const unsigned
|
|||||||
|
|
||||||
/* update the bucket using just encoded curval */
|
/* update the bucket using just encoded curval */
|
||||||
static void FNAME(update_model)(CommonState *state, s_bucket * const bucket,
|
static void FNAME(update_model)(CommonState *state, s_bucket * const bucket,
|
||||||
const BYTE curval, unsigned int bpp)
|
const BYTE curval)
|
||||||
{
|
{
|
||||||
|
SPICE_VERIFY(BPC >= 1);
|
||||||
|
spice_return_if_fail (bucket != NULL);
|
||||||
|
|
||||||
|
const unsigned int bpp = BPC;
|
||||||
COUNTER * const pcounters = bucket->pcounters;
|
COUNTER * const pcounters = bucket->pcounters;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
unsigned int bestcode;
|
unsigned int bestcode;
|
||||||
unsigned int bestcodelen;
|
unsigned int bestcodelen;
|
||||||
//unsigned int bpp = encoder->bpp;
|
|
||||||
|
|
||||||
/* update counters, find minimum */
|
/* update counters, find minimum */
|
||||||
|
|
||||||
@ -107,9 +101,14 @@ static void FNAME(update_model)(CommonState *state, s_bucket * const bucket,
|
|||||||
|
|
||||||
static s_bucket *FNAME(find_bucket)(Channel *channel, const unsigned int val)
|
static s_bucket *FNAME(find_bucket)(Channel *channel, const unsigned int val)
|
||||||
{
|
{
|
||||||
ASSERT(channel->encoder->usr, val < (0x1U << BPC));
|
spice_extra_assert(val < (0x1U << BPC));
|
||||||
|
|
||||||
return channel->_buckets_ptrs[val];
|
/* The and (&) here is to avoid buffer overflows in case of garbage or malicious
|
||||||
|
* attempts. Is much faster then using comparisons and save us from such situations.
|
||||||
|
* Note that on normal build the check above won't be compiled as this code path
|
||||||
|
* is pretty hot and would cause speed regressions.
|
||||||
|
*/
|
||||||
|
return channel->_buckets_ptrs[val & ((1U << BPC) - 1)];
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef FNAME
|
#undef FNAME
|
||||||
|
|||||||
@ -1,765 +0,0 @@
|
|||||||
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
||||||
/*
|
|
||||||
Copyright (C) 2009 Red Hat, Inc.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include <config.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef QUIC_RGB32
|
|
||||||
#undef QUIC_RGB32
|
|
||||||
#define PIXEL rgb32_pixel_t
|
|
||||||
#define FNAME(name) quic_rgb32_##name
|
|
||||||
#define golomb_coding golomb_coding_8bpc
|
|
||||||
#define golomb_decoding golomb_decoding_8bpc
|
|
||||||
#define update_model update_model_8bpc
|
|
||||||
#define find_bucket find_bucket_8bpc
|
|
||||||
#define family family_8bpc
|
|
||||||
#define BPC 8
|
|
||||||
#define BPC_MASK 0xffU
|
|
||||||
#define COMPRESS_IMP
|
|
||||||
#define SET_r(pix, val) ((pix)->r = val)
|
|
||||||
#define GET_r(pix) ((pix)->r)
|
|
||||||
#define SET_g(pix, val) ((pix)->g = val)
|
|
||||||
#define GET_g(pix) ((pix)->g)
|
|
||||||
#define SET_b(pix, val) ((pix)->b = val)
|
|
||||||
#define GET_b(pix) ((pix)->b)
|
|
||||||
#define UNCOMPRESS_PIX_START(pix) ((pix)->pad = 0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef QUIC_RGB24
|
|
||||||
#undef QUIC_RGB24
|
|
||||||
#define PIXEL rgb24_pixel_t
|
|
||||||
#define FNAME(name) quic_rgb24_##name
|
|
||||||
#define golomb_coding golomb_coding_8bpc
|
|
||||||
#define golomb_decoding golomb_decoding_8bpc
|
|
||||||
#define update_model update_model_8bpc
|
|
||||||
#define find_bucket find_bucket_8bpc
|
|
||||||
#define family family_8bpc
|
|
||||||
#define BPC 8
|
|
||||||
#define BPC_MASK 0xffU
|
|
||||||
#define COMPRESS_IMP
|
|
||||||
#define SET_r(pix, val) ((pix)->r = val)
|
|
||||||
#define GET_r(pix) ((pix)->r)
|
|
||||||
#define SET_g(pix, val) ((pix)->g = val)
|
|
||||||
#define GET_g(pix) ((pix)->g)
|
|
||||||
#define SET_b(pix, val) ((pix)->b = val)
|
|
||||||
#define GET_b(pix) ((pix)->b)
|
|
||||||
#define UNCOMPRESS_PIX_START(pix)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef QUIC_RGB16
|
|
||||||
#undef QUIC_RGB16
|
|
||||||
#define PIXEL rgb16_pixel_t
|
|
||||||
#define FNAME(name) quic_rgb16_##name
|
|
||||||
#define golomb_coding golomb_coding_5bpc
|
|
||||||
#define golomb_decoding golomb_decoding_5bpc
|
|
||||||
#define update_model update_model_5bpc
|
|
||||||
#define find_bucket find_bucket_5bpc
|
|
||||||
#define family family_5bpc
|
|
||||||
#define BPC 5
|
|
||||||
#define BPC_MASK 0x1fU
|
|
||||||
#define COMPRESS_IMP
|
|
||||||
#define SET_r(pix, val) (*(pix) = (*(pix) & ~(0x1f << 10)) | ((val) << 10))
|
|
||||||
#define GET_r(pix) ((*(pix) >> 10) & 0x1f)
|
|
||||||
#define SET_g(pix, val) (*(pix) = (*(pix) & ~(0x1f << 5)) | ((val) << 5))
|
|
||||||
#define GET_g(pix) ((*(pix) >> 5) & 0x1f)
|
|
||||||
#define SET_b(pix, val) (*(pix) = (*(pix) & ~0x1f) | (val))
|
|
||||||
#define GET_b(pix) (*(pix) & 0x1f)
|
|
||||||
#define UNCOMPRESS_PIX_START(pix) (*(pix) = 0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef QUIC_RGB16_TO_32
|
|
||||||
#undef QUIC_RGB16_TO_32
|
|
||||||
#define PIXEL rgb32_pixel_t
|
|
||||||
#define FNAME(name) quic_rgb16_to_32_##name
|
|
||||||
#define golomb_coding golomb_coding_5bpc
|
|
||||||
#define golomb_decoding golomb_decoding_5bpc
|
|
||||||
#define update_model update_model_5bpc
|
|
||||||
#define find_bucket find_bucket_5bpc
|
|
||||||
#define family family_5bpc
|
|
||||||
#define BPC 5
|
|
||||||
#define BPC_MASK 0x1fU
|
|
||||||
|
|
||||||
#define SET_r(pix, val) ((pix)->r = ((val) << 3) | (((val) & 0x1f) >> 2))
|
|
||||||
#define GET_r(pix) ((pix)->r >> 3)
|
|
||||||
#define SET_g(pix, val) ((pix)->g = ((val) << 3) | (((val) & 0x1f) >> 2))
|
|
||||||
#define GET_g(pix) ((pix)->g >> 3)
|
|
||||||
#define SET_b(pix, val) ((pix)->b = ((val) << 3) | (((val) & 0x1f) >> 2))
|
|
||||||
#define GET_b(pix) ((pix)->b >> 3)
|
|
||||||
#define UNCOMPRESS_PIX_START(pix) ((pix)->pad = 0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define SAME_PIXEL(p1, p2) \
|
|
||||||
(GET_r(p1) == GET_r(p2) && GET_g(p1) == GET_g(p2) && \
|
|
||||||
GET_b(p1) == GET_b(p2))
|
|
||||||
|
|
||||||
|
|
||||||
#define _PIXEL_A(channel, curr) ((unsigned int)GET_##channel((curr) - 1))
|
|
||||||
#define _PIXEL_B(channel, prev) ((unsigned int)GET_##channel(prev))
|
|
||||||
#define _PIXEL_C(channel, prev) ((unsigned int)GET_##channel((prev) - 1))
|
|
||||||
|
|
||||||
/* a */
|
|
||||||
|
|
||||||
#define DECORELATE_0(channel, curr, bpc_mask)\
|
|
||||||
family.xlatU2L[(unsigned)((int)GET_##channel(curr) - (int)_PIXEL_A(channel, curr)) & bpc_mask]
|
|
||||||
|
|
||||||
#define CORELATE_0(channel, curr, correlate, bpc_mask)\
|
|
||||||
((family.xlatL2U[correlate] + _PIXEL_A(channel, curr)) & bpc_mask)
|
|
||||||
|
|
||||||
#ifdef PRED_1
|
|
||||||
|
|
||||||
/* (a+b)/2 */
|
|
||||||
#define DECORELATE(channel, prev, curr, bpc_mask, r) \
|
|
||||||
r = family.xlatU2L[(unsigned)((int)GET_##channel(curr) - (int)((_PIXEL_A(channel, curr) + \
|
|
||||||
_PIXEL_B(channel, prev)) >> 1)) & bpc_mask]
|
|
||||||
|
|
||||||
#define CORELATE(channel, prev, curr, correlate, bpc_mask, r) \
|
|
||||||
SET_##channel(r, ((family.xlatL2U[correlate] + \
|
|
||||||
(int)((_PIXEL_A(channel, curr) + _PIXEL_B(channel, prev)) >> 1)) & bpc_mask))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef PRED_2
|
|
||||||
|
|
||||||
/* .75a+.75b-.5c */
|
|
||||||
#define DECORELATE(channel, prev, curr, bpc_mask, r) { \
|
|
||||||
int p = ((int)(3 * (_PIXEL_A(channel, curr) + _PIXEL_B(channel, prev))) - \
|
|
||||||
(int)(_PIXEL_C(channel, prev) << 1)) >> 2; \
|
|
||||||
if (p < 0) { \
|
|
||||||
p = 0; \
|
|
||||||
} else if ((unsigned)p > bpc_mask) { \
|
|
||||||
p = bpc_mask; \
|
|
||||||
} \
|
|
||||||
r = family.xlatU2L[(unsigned)((int)GET_##channel(curr) - p) & bpc_mask]; \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define CORELATE(channel, prev, curr, correlate, bpc_mask, r) { \
|
|
||||||
const int p = ((int)(3 * (_PIXEL_A(channel, curr) + _PIXEL_B(channel, prev))) - \
|
|
||||||
(int)(_PIXEL_C(channel, prev) << 1) ) >> 2; \
|
|
||||||
const unsigned int s = family.xlatL2U[correlate]; \
|
|
||||||
if (!(p & ~bpc_mask)) { \
|
|
||||||
SET_##channel(r, (s + (unsigned)p) & bpc_mask); \
|
|
||||||
} else if (p < 0) { \
|
|
||||||
SET_##channel(r, s); \
|
|
||||||
} else { \
|
|
||||||
SET_##channel(r, (s + bpc_mask) & bpc_mask); \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#define COMPRESS_ONE_ROW0_0(channel) \
|
|
||||||
correlate_row_##channel[0] = family.xlatU2L[GET_##channel(cur_row)]; \
|
|
||||||
golomb_coding(correlate_row_##channel[0], find_bucket(channel_##channel, \
|
|
||||||
correlate_row_##channel[-1])->bestcode, \
|
|
||||||
&codeword, &codewordlen); \
|
|
||||||
encode(encoder, codeword, codewordlen);
|
|
||||||
|
|
||||||
#define COMPRESS_ONE_ROW0(channel, index) \
|
|
||||||
correlate_row_##channel[index] = DECORELATE_0(channel, &cur_row[index], bpc_mask); \
|
|
||||||
golomb_coding(correlate_row_##channel[index], find_bucket(channel_##channel, \
|
|
||||||
correlate_row_##channel[index -1])->bestcode, \
|
|
||||||
&codeword, &codewordlen); \
|
|
||||||
encode(encoder, codeword, codewordlen);
|
|
||||||
|
|
||||||
#define UPDATE_MODEL(index) \
|
|
||||||
update_model(&encoder->rgb_state, find_bucket(channel_r, correlate_row_r[index - 1]), \
|
|
||||||
correlate_row_r[index], bpc); \
|
|
||||||
update_model(&encoder->rgb_state, find_bucket(channel_g, correlate_row_g[index - 1]), \
|
|
||||||
correlate_row_g[index], bpc); \
|
|
||||||
update_model(&encoder->rgb_state, find_bucket(channel_b, correlate_row_b[index - 1]), \
|
|
||||||
correlate_row_b[index], bpc);
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef RLE_PRED_1
|
|
||||||
#define RLE_PRED_1_IMP \
|
|
||||||
if (SAME_PIXEL(&cur_row[i - 1], &prev_row[i])) { \
|
|
||||||
if (run_index != i && SAME_PIXEL(&prev_row[i - 1], &prev_row[i]) && \
|
|
||||||
i + 1 < end && SAME_PIXEL(&prev_row[i], &prev_row[i + 1])) { \
|
|
||||||
goto do_run; \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
#define RLE_PRED_1_IMP
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef RLE_PRED_2
|
|
||||||
#define RLE_PRED_2_IMP \
|
|
||||||
if (SAME_PIXEL(&prev_row[i - 1], &prev_row[i])) { \
|
|
||||||
if (run_index != i && i > 2 && SAME_PIXEL(&cur_row[i - 1], &cur_row[i - 2])) { \
|
|
||||||
goto do_run; \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
#define RLE_PRED_2_IMP
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef RLE_PRED_3
|
|
||||||
#define RLE_PRED_3_IMP \
|
|
||||||
if (i > 1 && SAME_PIXEL(&cur_row[i - 1], &cur_row[i - 2]) && i != run_index) { \
|
|
||||||
goto do_run; \
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
#define RLE_PRED_3_IMP
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef COMPRESS_IMP
|
|
||||||
|
|
||||||
static void FNAME(compress_row0_seg)(Encoder *encoder, int i,
|
|
||||||
const PIXEL * const cur_row,
|
|
||||||
const int end,
|
|
||||||
const unsigned int waitmask,
|
|
||||||
const unsigned int bpc,
|
|
||||||
const unsigned int bpc_mask)
|
|
||||||
{
|
|
||||||
Channel * const channel_r = encoder->channels;
|
|
||||||
Channel * const channel_g = channel_r + 1;
|
|
||||||
Channel * const channel_b = channel_g + 1;
|
|
||||||
|
|
||||||
BYTE * const correlate_row_r = channel_r->correlate_row;
|
|
||||||
BYTE * const correlate_row_g = channel_g->correlate_row;
|
|
||||||
BYTE * const correlate_row_b = channel_b->correlate_row;
|
|
||||||
int stopidx;
|
|
||||||
|
|
||||||
ASSERT(encoder->usr, end - i > 0);
|
|
||||||
|
|
||||||
if (!i) {
|
|
||||||
unsigned int codeword, codewordlen;
|
|
||||||
|
|
||||||
COMPRESS_ONE_ROW0_0(r);
|
|
||||||
COMPRESS_ONE_ROW0_0(g);
|
|
||||||
COMPRESS_ONE_ROW0_0(b);
|
|
||||||
|
|
||||||
if (encoder->rgb_state.waitcnt) {
|
|
||||||
encoder->rgb_state.waitcnt--;
|
|
||||||
} else {
|
|
||||||
encoder->rgb_state.waitcnt = (tabrand(&encoder->rgb_state.tabrand_seed) & waitmask);
|
|
||||||
UPDATE_MODEL(0);
|
|
||||||
}
|
|
||||||
stopidx = ++i + encoder->rgb_state.waitcnt;
|
|
||||||
} else {
|
|
||||||
stopidx = i + encoder->rgb_state.waitcnt;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (stopidx < end) {
|
|
||||||
for (; i <= stopidx; i++) {
|
|
||||||
unsigned int codeword, codewordlen;
|
|
||||||
COMPRESS_ONE_ROW0(r, i);
|
|
||||||
COMPRESS_ONE_ROW0(g, i);
|
|
||||||
COMPRESS_ONE_ROW0(b, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
UPDATE_MODEL(stopidx);
|
|
||||||
stopidx = i + (tabrand(&encoder->rgb_state.tabrand_seed) & waitmask);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (; i < end; i++) {
|
|
||||||
unsigned int codeword, codewordlen;
|
|
||||||
|
|
||||||
COMPRESS_ONE_ROW0(r, i);
|
|
||||||
COMPRESS_ONE_ROW0(g, i);
|
|
||||||
COMPRESS_ONE_ROW0(b, i);
|
|
||||||
}
|
|
||||||
encoder->rgb_state.waitcnt = stopidx - end;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void FNAME(compress_row0)(Encoder *encoder, const PIXEL *cur_row,
|
|
||||||
unsigned int width)
|
|
||||||
{
|
|
||||||
const unsigned int bpc = BPC;
|
|
||||||
const unsigned int bpc_mask = BPC_MASK;
|
|
||||||
int pos = 0;
|
|
||||||
|
|
||||||
while ((wmimax > (int)encoder->rgb_state.wmidx) && (encoder->rgb_state.wmileft <= width)) {
|
|
||||||
if (encoder->rgb_state.wmileft) {
|
|
||||||
FNAME(compress_row0_seg)(encoder, pos, cur_row, pos + encoder->rgb_state.wmileft,
|
|
||||||
bppmask[encoder->rgb_state.wmidx], bpc, bpc_mask);
|
|
||||||
width -= encoder->rgb_state.wmileft;
|
|
||||||
pos += encoder->rgb_state.wmileft;
|
|
||||||
}
|
|
||||||
|
|
||||||
encoder->rgb_state.wmidx++;
|
|
||||||
set_wm_trigger(&encoder->rgb_state);
|
|
||||||
encoder->rgb_state.wmileft = wminext;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (width) {
|
|
||||||
FNAME(compress_row0_seg)(encoder, pos, cur_row, pos + width,
|
|
||||||
bppmask[encoder->rgb_state.wmidx], bpc, bpc_mask);
|
|
||||||
if (wmimax > (int)encoder->rgb_state.wmidx) {
|
|
||||||
encoder->rgb_state.wmileft -= width;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT(encoder->usr, (int)encoder->rgb_state.wmidx <= wmimax);
|
|
||||||
ASSERT(encoder->usr, encoder->rgb_state.wmidx <= 32);
|
|
||||||
ASSERT(encoder->usr, wminext > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define COMPRESS_ONE_0(channel) \
|
|
||||||
correlate_row_##channel[0] = family.xlatU2L[(unsigned)((int)GET_##channel(cur_row) - \
|
|
||||||
(int)GET_##channel(prev_row) ) & bpc_mask]; \
|
|
||||||
golomb_coding(correlate_row_##channel[0], \
|
|
||||||
find_bucket(channel_##channel, correlate_row_##channel[-1])->bestcode, \
|
|
||||||
&codeword, &codewordlen); \
|
|
||||||
encode(encoder, codeword, codewordlen);
|
|
||||||
|
|
||||||
#define COMPRESS_ONE(channel, index) \
|
|
||||||
DECORELATE(channel, &prev_row[index], &cur_row[index],bpc_mask, \
|
|
||||||
correlate_row_##channel[index]); \
|
|
||||||
golomb_coding(correlate_row_##channel[index], \
|
|
||||||
find_bucket(channel_##channel, correlate_row_##channel[index - 1])->bestcode, \
|
|
||||||
&codeword, &codewordlen); \
|
|
||||||
encode(encoder, codeword, codewordlen);
|
|
||||||
|
|
||||||
static void FNAME(compress_row_seg)(Encoder *encoder, int i,
|
|
||||||
const PIXEL * const prev_row,
|
|
||||||
const PIXEL * const cur_row,
|
|
||||||
const int end,
|
|
||||||
const unsigned int waitmask,
|
|
||||||
const unsigned int bpc,
|
|
||||||
const unsigned int bpc_mask)
|
|
||||||
{
|
|
||||||
Channel * const channel_r = encoder->channels;
|
|
||||||
Channel * const channel_g = channel_r + 1;
|
|
||||||
Channel * const channel_b = channel_g + 1;
|
|
||||||
|
|
||||||
BYTE * const correlate_row_r = channel_r->correlate_row;
|
|
||||||
BYTE * const correlate_row_g = channel_g->correlate_row;
|
|
||||||
BYTE * const correlate_row_b = channel_b->correlate_row;
|
|
||||||
int stopidx;
|
|
||||||
#ifdef RLE
|
|
||||||
int run_index = 0;
|
|
||||||
int run_size;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ASSERT(encoder->usr, end - i > 0);
|
|
||||||
|
|
||||||
if (!i) {
|
|
||||||
unsigned int codeword, codewordlen;
|
|
||||||
|
|
||||||
COMPRESS_ONE_0(r);
|
|
||||||
COMPRESS_ONE_0(g);
|
|
||||||
COMPRESS_ONE_0(b);
|
|
||||||
|
|
||||||
if (encoder->rgb_state.waitcnt) {
|
|
||||||
encoder->rgb_state.waitcnt--;
|
|
||||||
} else {
|
|
||||||
encoder->rgb_state.waitcnt = (tabrand(&encoder->rgb_state.tabrand_seed) & waitmask);
|
|
||||||
UPDATE_MODEL(0);
|
|
||||||
}
|
|
||||||
stopidx = ++i + encoder->rgb_state.waitcnt;
|
|
||||||
} else {
|
|
||||||
stopidx = i + encoder->rgb_state.waitcnt;
|
|
||||||
}
|
|
||||||
for (;;) {
|
|
||||||
while (stopidx < end) {
|
|
||||||
for (; i <= stopidx; i++) {
|
|
||||||
unsigned int codeword, codewordlen;
|
|
||||||
#ifdef RLE
|
|
||||||
RLE_PRED_1_IMP;
|
|
||||||
RLE_PRED_2_IMP;
|
|
||||||
RLE_PRED_3_IMP;
|
|
||||||
#endif
|
|
||||||
COMPRESS_ONE(r, i);
|
|
||||||
COMPRESS_ONE(g, i);
|
|
||||||
COMPRESS_ONE(b, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
UPDATE_MODEL(stopidx);
|
|
||||||
stopidx = i + (tabrand(&encoder->rgb_state.tabrand_seed) & waitmask);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (; i < end; i++) {
|
|
||||||
unsigned int codeword, codewordlen;
|
|
||||||
#ifdef RLE
|
|
||||||
RLE_PRED_1_IMP;
|
|
||||||
RLE_PRED_2_IMP;
|
|
||||||
RLE_PRED_3_IMP;
|
|
||||||
#endif
|
|
||||||
COMPRESS_ONE(r, i);
|
|
||||||
COMPRESS_ONE(g, i);
|
|
||||||
COMPRESS_ONE(b, i);
|
|
||||||
}
|
|
||||||
encoder->rgb_state.waitcnt = stopidx - end;
|
|
||||||
|
|
||||||
return;
|
|
||||||
|
|
||||||
#ifdef RLE
|
|
||||||
do_run:
|
|
||||||
run_index = i;
|
|
||||||
encoder->rgb_state.waitcnt = stopidx - i;
|
|
||||||
run_size = 0;
|
|
||||||
|
|
||||||
while (SAME_PIXEL(&cur_row[i], &cur_row[i - 1])) {
|
|
||||||
run_size++;
|
|
||||||
if (++i == end) {
|
|
||||||
encode_run(encoder, run_size);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
encode_run(encoder, run_size);
|
|
||||||
stopidx = i + encoder->rgb_state.waitcnt;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void FNAME(compress_row)(Encoder *encoder,
|
|
||||||
const PIXEL * const prev_row,
|
|
||||||
const PIXEL * const cur_row,
|
|
||||||
unsigned int width)
|
|
||||||
|
|
||||||
{
|
|
||||||
const unsigned int bpc = BPC;
|
|
||||||
const unsigned int bpc_mask = BPC_MASK;
|
|
||||||
unsigned int pos = 0;
|
|
||||||
|
|
||||||
while ((wmimax > (int)encoder->rgb_state.wmidx) && (encoder->rgb_state.wmileft <= width)) {
|
|
||||||
if (encoder->rgb_state.wmileft) {
|
|
||||||
FNAME(compress_row_seg)(encoder, pos, prev_row, cur_row,
|
|
||||||
pos + encoder->rgb_state.wmileft,
|
|
||||||
bppmask[encoder->rgb_state.wmidx],
|
|
||||||
bpc, bpc_mask);
|
|
||||||
width -= encoder->rgb_state.wmileft;
|
|
||||||
pos += encoder->rgb_state.wmileft;
|
|
||||||
}
|
|
||||||
|
|
||||||
encoder->rgb_state.wmidx++;
|
|
||||||
set_wm_trigger(&encoder->rgb_state);
|
|
||||||
encoder->rgb_state.wmileft = wminext;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (width) {
|
|
||||||
FNAME(compress_row_seg)(encoder, pos, prev_row, cur_row, pos + width,
|
|
||||||
bppmask[encoder->rgb_state.wmidx], bpc, bpc_mask);
|
|
||||||
if (wmimax > (int)encoder->rgb_state.wmidx) {
|
|
||||||
encoder->rgb_state.wmileft -= width;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT(encoder->usr, (int)encoder->rgb_state.wmidx <= wmimax);
|
|
||||||
ASSERT(encoder->usr, encoder->rgb_state.wmidx <= 32);
|
|
||||||
ASSERT(encoder->usr, wminext > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define UNCOMPRESS_ONE_ROW0_0(channel) \
|
|
||||||
correlate_row_##channel[0] = (BYTE)golomb_decoding(find_bucket(channel_##channel, \
|
|
||||||
correlate_row_##channel[-1])->bestcode, \
|
|
||||||
encoder->io_word, &codewordlen); \
|
|
||||||
SET_##channel(&cur_row[0], (BYTE)family.xlatL2U[correlate_row_##channel[0]]); \
|
|
||||||
decode_eatbits(encoder, codewordlen);
|
|
||||||
|
|
||||||
#define UNCOMPRESS_ONE_ROW0(channel) \
|
|
||||||
correlate_row_##channel[i] = (BYTE)golomb_decoding(find_bucket(channel_##channel, \
|
|
||||||
correlate_row_##channel[i - 1])->bestcode, \
|
|
||||||
encoder->io_word, \
|
|
||||||
&codewordlen); \
|
|
||||||
SET_##channel(&cur_row[i], CORELATE_0(channel, &cur_row[i], correlate_row_##channel[i], \
|
|
||||||
bpc_mask)); \
|
|
||||||
decode_eatbits(encoder, codewordlen);
|
|
||||||
|
|
||||||
static void FNAME(uncompress_row0_seg)(Encoder *encoder, int i,
|
|
||||||
PIXEL * const cur_row,
|
|
||||||
const int end,
|
|
||||||
const unsigned int waitmask,
|
|
||||||
const unsigned int bpc,
|
|
||||||
const unsigned int bpc_mask)
|
|
||||||
{
|
|
||||||
Channel * const channel_r = encoder->channels;
|
|
||||||
Channel * const channel_g = channel_r + 1;
|
|
||||||
Channel * const channel_b = channel_g + 1;
|
|
||||||
|
|
||||||
BYTE * const correlate_row_r = channel_r->correlate_row;
|
|
||||||
BYTE * const correlate_row_g = channel_g->correlate_row;
|
|
||||||
BYTE * const correlate_row_b = channel_b->correlate_row;
|
|
||||||
int stopidx;
|
|
||||||
|
|
||||||
ASSERT(encoder->usr, end - i > 0);
|
|
||||||
|
|
||||||
if (!i) {
|
|
||||||
unsigned int codewordlen;
|
|
||||||
|
|
||||||
UNCOMPRESS_PIX_START(&cur_row[i]);
|
|
||||||
UNCOMPRESS_ONE_ROW0_0(r);
|
|
||||||
UNCOMPRESS_ONE_ROW0_0(g);
|
|
||||||
UNCOMPRESS_ONE_ROW0_0(b);
|
|
||||||
|
|
||||||
if (encoder->rgb_state.waitcnt) {
|
|
||||||
--encoder->rgb_state.waitcnt;
|
|
||||||
} else {
|
|
||||||
encoder->rgb_state.waitcnt = (tabrand(&encoder->rgb_state.tabrand_seed) & waitmask);
|
|
||||||
UPDATE_MODEL(0);
|
|
||||||
}
|
|
||||||
stopidx = ++i + encoder->rgb_state.waitcnt;
|
|
||||||
} else {
|
|
||||||
stopidx = i + encoder->rgb_state.waitcnt;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (stopidx < end) {
|
|
||||||
for (; i <= stopidx; i++) {
|
|
||||||
unsigned int codewordlen;
|
|
||||||
|
|
||||||
UNCOMPRESS_PIX_START(&cur_row[i]);
|
|
||||||
UNCOMPRESS_ONE_ROW0(r);
|
|
||||||
UNCOMPRESS_ONE_ROW0(g);
|
|
||||||
UNCOMPRESS_ONE_ROW0(b);
|
|
||||||
}
|
|
||||||
UPDATE_MODEL(stopidx);
|
|
||||||
stopidx = i + (tabrand(&encoder->rgb_state.tabrand_seed) & waitmask);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (; i < end; i++) {
|
|
||||||
unsigned int codewordlen;
|
|
||||||
|
|
||||||
UNCOMPRESS_PIX_START(&cur_row[i]);
|
|
||||||
UNCOMPRESS_ONE_ROW0(r);
|
|
||||||
UNCOMPRESS_ONE_ROW0(g);
|
|
||||||
UNCOMPRESS_ONE_ROW0(b);
|
|
||||||
}
|
|
||||||
encoder->rgb_state.waitcnt = stopidx - end;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void FNAME(uncompress_row0)(Encoder *encoder,
|
|
||||||
PIXEL * const cur_row,
|
|
||||||
unsigned int width)
|
|
||||||
|
|
||||||
{
|
|
||||||
const unsigned int bpc = BPC;
|
|
||||||
const unsigned int bpc_mask = BPC_MASK;
|
|
||||||
unsigned int pos = 0;
|
|
||||||
|
|
||||||
while ((wmimax > (int)encoder->rgb_state.wmidx) && (encoder->rgb_state.wmileft <= width)) {
|
|
||||||
if (encoder->rgb_state.wmileft) {
|
|
||||||
FNAME(uncompress_row0_seg)(encoder, pos, cur_row,
|
|
||||||
pos + encoder->rgb_state.wmileft,
|
|
||||||
bppmask[encoder->rgb_state.wmidx],
|
|
||||||
bpc, bpc_mask);
|
|
||||||
pos += encoder->rgb_state.wmileft;
|
|
||||||
width -= encoder->rgb_state.wmileft;
|
|
||||||
}
|
|
||||||
|
|
||||||
encoder->rgb_state.wmidx++;
|
|
||||||
set_wm_trigger(&encoder->rgb_state);
|
|
||||||
encoder->rgb_state.wmileft = wminext;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (width) {
|
|
||||||
FNAME(uncompress_row0_seg)(encoder, pos, cur_row, pos + width,
|
|
||||||
bppmask[encoder->rgb_state.wmidx], bpc, bpc_mask);
|
|
||||||
if (wmimax > (int)encoder->rgb_state.wmidx) {
|
|
||||||
encoder->rgb_state.wmileft -= width;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT(encoder->usr, (int)encoder->rgb_state.wmidx <= wmimax);
|
|
||||||
ASSERT(encoder->usr, encoder->rgb_state.wmidx <= 32);
|
|
||||||
ASSERT(encoder->usr, wminext > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define UNCOMPRESS_ONE_0(channel) \
|
|
||||||
correlate_row_##channel[0] = (BYTE)golomb_decoding(find_bucket(channel_##channel, \
|
|
||||||
correlate_row_##channel[-1])->bestcode, \
|
|
||||||
encoder->io_word, &codewordlen); \
|
|
||||||
SET_##channel(&cur_row[0], (family.xlatL2U[correlate_row_##channel[0]] + \
|
|
||||||
GET_##channel(prev_row)) & bpc_mask); \
|
|
||||||
decode_eatbits(encoder, codewordlen);
|
|
||||||
|
|
||||||
#define UNCOMPRESS_ONE(channel) \
|
|
||||||
correlate_row_##channel[i] = (BYTE)golomb_decoding(find_bucket(channel_##channel, \
|
|
||||||
correlate_row_##channel[i - 1])->bestcode, \
|
|
||||||
encoder->io_word, \
|
|
||||||
&codewordlen); \
|
|
||||||
CORELATE(channel, &prev_row[i], &cur_row[i], correlate_row_##channel[i], bpc_mask, \
|
|
||||||
&cur_row[i]); \
|
|
||||||
decode_eatbits(encoder, codewordlen);
|
|
||||||
|
|
||||||
static void FNAME(uncompress_row_seg)(Encoder *encoder,
|
|
||||||
const PIXEL * const prev_row,
|
|
||||||
PIXEL * const cur_row,
|
|
||||||
int i,
|
|
||||||
const int end,
|
|
||||||
const unsigned int bpc,
|
|
||||||
const unsigned int bpc_mask)
|
|
||||||
{
|
|
||||||
Channel * const channel_r = encoder->channels;
|
|
||||||
Channel * const channel_g = channel_r + 1;
|
|
||||||
Channel * const channel_b = channel_g + 1;
|
|
||||||
|
|
||||||
BYTE * const correlate_row_r = channel_r->correlate_row;
|
|
||||||
BYTE * const correlate_row_g = channel_g->correlate_row;
|
|
||||||
BYTE * const correlate_row_b = channel_b->correlate_row;
|
|
||||||
const unsigned int waitmask = bppmask[encoder->rgb_state.wmidx];
|
|
||||||
int stopidx;
|
|
||||||
#ifdef RLE
|
|
||||||
int run_index = 0;
|
|
||||||
int run_end;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ASSERT(encoder->usr, end - i > 0);
|
|
||||||
|
|
||||||
if (!i) {
|
|
||||||
unsigned int codewordlen;
|
|
||||||
|
|
||||||
UNCOMPRESS_PIX_START(&cur_row[i]);
|
|
||||||
UNCOMPRESS_ONE_0(r);
|
|
||||||
UNCOMPRESS_ONE_0(g);
|
|
||||||
UNCOMPRESS_ONE_0(b);
|
|
||||||
|
|
||||||
if (encoder->rgb_state.waitcnt) {
|
|
||||||
--encoder->rgb_state.waitcnt;
|
|
||||||
} else {
|
|
||||||
encoder->rgb_state.waitcnt = (tabrand(&encoder->rgb_state.tabrand_seed) & waitmask);
|
|
||||||
UPDATE_MODEL(0);
|
|
||||||
}
|
|
||||||
stopidx = ++i + encoder->rgb_state.waitcnt;
|
|
||||||
} else {
|
|
||||||
stopidx = i + encoder->rgb_state.waitcnt;
|
|
||||||
}
|
|
||||||
for (;;) {
|
|
||||||
while (stopidx < end) {
|
|
||||||
for (; i <= stopidx; i++) {
|
|
||||||
unsigned int codewordlen;
|
|
||||||
#ifdef RLE
|
|
||||||
RLE_PRED_1_IMP;
|
|
||||||
RLE_PRED_2_IMP;
|
|
||||||
RLE_PRED_3_IMP;
|
|
||||||
#endif
|
|
||||||
UNCOMPRESS_PIX_START(&cur_row[i]);
|
|
||||||
UNCOMPRESS_ONE(r);
|
|
||||||
UNCOMPRESS_ONE(g);
|
|
||||||
UNCOMPRESS_ONE(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
UPDATE_MODEL(stopidx);
|
|
||||||
|
|
||||||
stopidx = i + (tabrand(&encoder->rgb_state.tabrand_seed) & waitmask);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (; i < end; i++) {
|
|
||||||
unsigned int codewordlen;
|
|
||||||
#ifdef RLE
|
|
||||||
RLE_PRED_1_IMP;
|
|
||||||
RLE_PRED_2_IMP;
|
|
||||||
RLE_PRED_3_IMP;
|
|
||||||
#endif
|
|
||||||
UNCOMPRESS_PIX_START(&cur_row[i]);
|
|
||||||
UNCOMPRESS_ONE(r);
|
|
||||||
UNCOMPRESS_ONE(g);
|
|
||||||
UNCOMPRESS_ONE(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
encoder->rgb_state.waitcnt = stopidx - end;
|
|
||||||
|
|
||||||
return;
|
|
||||||
|
|
||||||
#ifdef RLE
|
|
||||||
do_run:
|
|
||||||
encoder->rgb_state.waitcnt = stopidx - i;
|
|
||||||
run_index = i;
|
|
||||||
run_end = i + decode_run(encoder);
|
|
||||||
|
|
||||||
for (; i < run_end; i++) {
|
|
||||||
UNCOMPRESS_PIX_START(&cur_row[i]);
|
|
||||||
SET_r(&cur_row[i], GET_r(&cur_row[i - 1]));
|
|
||||||
SET_g(&cur_row[i], GET_g(&cur_row[i - 1]));
|
|
||||||
SET_b(&cur_row[i], GET_b(&cur_row[i - 1]));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i == end) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
stopidx = i + encoder->rgb_state.waitcnt;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void FNAME(uncompress_row)(Encoder *encoder,
|
|
||||||
const PIXEL * const prev_row,
|
|
||||||
PIXEL * const cur_row,
|
|
||||||
unsigned int width)
|
|
||||||
|
|
||||||
{
|
|
||||||
const unsigned int bpc = BPC;
|
|
||||||
const unsigned int bpc_mask = BPC_MASK;
|
|
||||||
unsigned int pos = 0;
|
|
||||||
|
|
||||||
while ((wmimax > (int)encoder->rgb_state.wmidx) && (encoder->rgb_state.wmileft <= width)) {
|
|
||||||
if (encoder->rgb_state.wmileft) {
|
|
||||||
FNAME(uncompress_row_seg)(encoder, prev_row, cur_row, pos,
|
|
||||||
pos + encoder->rgb_state.wmileft, bpc, bpc_mask);
|
|
||||||
pos += encoder->rgb_state.wmileft;
|
|
||||||
width -= encoder->rgb_state.wmileft;
|
|
||||||
}
|
|
||||||
|
|
||||||
encoder->rgb_state.wmidx++;
|
|
||||||
set_wm_trigger(&encoder->rgb_state);
|
|
||||||
encoder->rgb_state.wmileft = wminext;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (width) {
|
|
||||||
FNAME(uncompress_row_seg)(encoder, prev_row, cur_row, pos,
|
|
||||||
pos + width, bpc, bpc_mask);
|
|
||||||
if (wmimax > (int)encoder->rgb_state.wmidx) {
|
|
||||||
encoder->rgb_state.wmileft -= width;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT(encoder->usr, (int)encoder->rgb_state.wmidx <= wmimax);
|
|
||||||
ASSERT(encoder->usr, encoder->rgb_state.wmidx <= 32);
|
|
||||||
ASSERT(encoder->usr, wminext > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef PIXEL
|
|
||||||
#undef FNAME
|
|
||||||
#undef _PIXEL_A
|
|
||||||
#undef _PIXEL_B
|
|
||||||
#undef _PIXEL_C
|
|
||||||
#undef SAME_PIXEL
|
|
||||||
#undef RLE_PRED_1_IMP
|
|
||||||
#undef RLE_PRED_2_IMP
|
|
||||||
#undef RLE_PRED_3_IMP
|
|
||||||
#undef UPDATE_MODEL
|
|
||||||
#undef DECORELATE_0
|
|
||||||
#undef DECORELATE
|
|
||||||
#undef COMPRESS_ONE_ROW0_0
|
|
||||||
#undef COMPRESS_ONE_ROW0
|
|
||||||
#undef COMPRESS_ONE_0
|
|
||||||
#undef COMPRESS_ONE
|
|
||||||
#undef CORELATE_0
|
|
||||||
#undef CORELATE
|
|
||||||
#undef UNCOMPRESS_ONE_ROW0_0
|
|
||||||
#undef UNCOMPRESS_ONE_ROW0
|
|
||||||
#undef UNCOMPRESS_ONE_0
|
|
||||||
#undef UNCOMPRESS_ONE
|
|
||||||
#undef golomb_coding
|
|
||||||
#undef golomb_decoding
|
|
||||||
#undef update_model
|
|
||||||
#undef find_bucket
|
|
||||||
#undef family
|
|
||||||
#undef BPC
|
|
||||||
#undef BPC_MASK
|
|
||||||
#undef COMPRESS_IMP
|
|
||||||
#undef SET_r
|
|
||||||
#undef GET_r
|
|
||||||
#undef SET_g
|
|
||||||
#undef GET_g
|
|
||||||
#undef SET_b
|
|
||||||
#undef GET_b
|
|
||||||
#undef UNCOMPRESS_PIX_START
|
|
||||||
File diff suppressed because it is too large
Load Diff
1
common/recorder
Submodule
1
common/recorder
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit d5cbf6caba60d580401c72d0cd18c316cf1be211
|
||||||
106
common/recorder.h
Normal file
106
common/recorder.h
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
/*
|
||||||
|
Copyright (C) 2018 Red Hat, Inc.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
/* This file include recorder library headers or if disabled provide
|
||||||
|
* replacement declarations */
|
||||||
|
|
||||||
|
#ifdef ENABLE_RECORDER
|
||||||
|
#include <common/recorder/recorder.h>
|
||||||
|
|
||||||
|
#elif defined(ENABLE_AGENT_INTERFACE)
|
||||||
|
#include <common/agent_interface.h>
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <spice/macros.h>
|
||||||
|
|
||||||
|
/* Replacement declarations.
|
||||||
|
* There declarations should generate no code (beside when no optimization are
|
||||||
|
* selected) but catch some possible programming warnings/errors at
|
||||||
|
* compile/link time like:
|
||||||
|
* - usage of undeclared recorders;
|
||||||
|
* - recording formats and arguments;
|
||||||
|
* - matching RECORD_TIMING_BEGIN and RECORD_TIMING_END.
|
||||||
|
* The only exceptions are tweaks which just generate a variable to hold the
|
||||||
|
* value.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct SpiceEmptyStruct {
|
||||||
|
char dummy[0];
|
||||||
|
} SpiceEmptyStruct;
|
||||||
|
|
||||||
|
typedef struct SpiceDummyTweak {
|
||||||
|
intptr_t tweak_value;
|
||||||
|
} SpiceDummyTweak;
|
||||||
|
|
||||||
|
#define RECORDER_DECLARE(rec) \
|
||||||
|
extern const SpiceEmptyStruct spice_recorder_ ## rec
|
||||||
|
#define RECORDER(rec, num_rings, comment) \
|
||||||
|
RECORDER_DEFINE(rec, num_rings, comment)
|
||||||
|
#define RECORDER_DEFINE(rec, num_rings, comment) \
|
||||||
|
const SpiceEmptyStruct SPICE_GNUC_UNUSED spice_recorder_ ## rec = {}
|
||||||
|
#define RECORDER_TRACE(rec) \
|
||||||
|
(sizeof(spice_recorder_ ## rec) != sizeof(SpiceEmptyStruct))
|
||||||
|
#define RECORDER_TWEAK_DECLARE(rec) \
|
||||||
|
extern const SpiceDummyTweak spice_recorder_tweak_ ## rec
|
||||||
|
#define RECORDER_TWEAK_DEFINE(rec, value, comment) \
|
||||||
|
const SpiceDummyTweak spice_recorder_tweak_ ## rec = { (value) }
|
||||||
|
#define RECORDER_TWEAK(rec) \
|
||||||
|
((spice_recorder_tweak_ ## rec).tweak_value)
|
||||||
|
#define RECORD(rec, ...) do { \
|
||||||
|
if (sizeof((spice_recorder_ ## rec).dummy)) printf(__VA_ARGS__); \
|
||||||
|
} while(0)
|
||||||
|
#define RECORD_TIMING_BEGIN(rec) \
|
||||||
|
do { RECORD(rec, "begin");
|
||||||
|
#define RECORD_TIMING_END(rec, op, name, value) \
|
||||||
|
RECORD(rec, "end" op name); \
|
||||||
|
} while(0)
|
||||||
|
#define record(...) \
|
||||||
|
RECORD(__VA_ARGS__)
|
||||||
|
static inline void
|
||||||
|
recorder_dump_on_common_signals(unsigned add, unsigned remove)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(ENABLE_AGENT_INTERFACE)
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
/* Stubs for Agent-Interface specific definitions */
|
||||||
|
static inline void
|
||||||
|
agent_interface_start(unsigned int port)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef void (*forward_quality_cb_t)(void *, const char *);
|
||||||
|
static inline void
|
||||||
|
agent_interface_set_forward_quality_cb(forward_quality_cb_t cb, void *data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef int (*on_connect_cb_t)(void *);
|
||||||
|
static inline void
|
||||||
|
agent_interface_set_on_connect_cb(on_connect_cb_t cb, void *data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif // __cplusplus
|
||||||
|
#endif
|
||||||
@ -16,17 +16,16 @@
|
|||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _H_RECT
|
#ifndef H_SPICE_COMMON_RECT
|
||||||
#define _H_RECT
|
#define H_SPICE_COMMON_RECT
|
||||||
|
|
||||||
#include "draw.h"
|
|
||||||
#include <spice/macros.h>
|
#include <spice/macros.h>
|
||||||
|
#include "draw.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
SPICE_BEGIN_DECLS
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static INLINE void rect_sect(SpiceRect* r, const SpiceRect* bounds)
|
static inline void rect_sect(SpiceRect* r, const SpiceRect* bounds)
|
||||||
{
|
{
|
||||||
r->left = MAX(r->left, bounds->left);
|
r->left = MAX(r->left, bounds->left);
|
||||||
r->right = MIN(r->right, bounds->right);
|
r->right = MIN(r->right, bounds->right);
|
||||||
@ -37,7 +36,7 @@ static INLINE void rect_sect(SpiceRect* r, const SpiceRect* bounds)
|
|||||||
r->bottom = MAX(r->top, r->bottom);
|
r->bottom = MAX(r->top, r->bottom);
|
||||||
}
|
}
|
||||||
|
|
||||||
static INLINE void rect_offset(SpiceRect* r, int dx, int dy)
|
static inline void rect_offset(SpiceRect* r, int dx, int dy)
|
||||||
{
|
{
|
||||||
r->left += dx;
|
r->left += dx;
|
||||||
r->right += dx;
|
r->right += dx;
|
||||||
@ -45,24 +44,24 @@ static INLINE void rect_offset(SpiceRect* r, int dx, int dy)
|
|||||||
r->bottom += dy;
|
r->bottom += dy;
|
||||||
}
|
}
|
||||||
|
|
||||||
static INLINE int rect_is_empty(const SpiceRect* r)
|
static inline int rect_is_empty(const SpiceRect* r)
|
||||||
{
|
{
|
||||||
return r->top == r->bottom || r->left == r->right;
|
return r->top == r->bottom || r->left == r->right;
|
||||||
}
|
}
|
||||||
|
|
||||||
static INLINE int rect_intersects(const SpiceRect* r1, const SpiceRect* r2)
|
static inline int rect_intersects(const SpiceRect* r1, const SpiceRect* r2)
|
||||||
{
|
{
|
||||||
return r1->left < r2->right && r1->right > r2->left &&
|
return r1->left < r2->right && r1->right > r2->left &&
|
||||||
r1->top < r2->bottom && r1->bottom > r2->top;
|
r1->top < r2->bottom && r1->bottom > r2->top;
|
||||||
}
|
}
|
||||||
|
|
||||||
static INLINE int rect_is_equal(const SpiceRect *r1, const SpiceRect *r2)
|
static inline int rect_is_equal(const SpiceRect *r1, const SpiceRect *r2)
|
||||||
{
|
{
|
||||||
return r1->top == r2->top && r1->left == r2->left &&
|
return r1->top == r2->top && r1->left == r2->left &&
|
||||||
r1->bottom == r2->bottom && r1->right == r2->right;
|
r1->bottom == r2->bottom && r1->right == r2->right;
|
||||||
}
|
}
|
||||||
|
|
||||||
static INLINE void rect_union(SpiceRect *dest, const SpiceRect *r)
|
static inline void rect_union(SpiceRect *dest, const SpiceRect *r)
|
||||||
{
|
{
|
||||||
dest->top = MIN(dest->top, r->top);
|
dest->top = MIN(dest->top, r->top);
|
||||||
dest->left = MIN(dest->left, r->left);
|
dest->left = MIN(dest->left, r->left);
|
||||||
@ -70,15 +69,29 @@ static INLINE void rect_union(SpiceRect *dest, const SpiceRect *r)
|
|||||||
dest->right = MAX(dest->right, r->right);
|
dest->right = MAX(dest->right, r->right);
|
||||||
}
|
}
|
||||||
|
|
||||||
static INLINE int rect_is_same_size(const SpiceRect *r1, const SpiceRect *r2)
|
static inline int rect_is_same_size(const SpiceRect *r1, const SpiceRect *r2)
|
||||||
{
|
{
|
||||||
return r1->right - r1->left == r2->right - r2->left &&
|
return r1->right - r1->left == r2->right - r2->left &&
|
||||||
r1->bottom - r1->top == r2->bottom - r2->top;
|
r1->bottom - r1->top == r2->bottom - r2->top;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
static inline int rect_contains(const SpiceRect *big_rect, const SpiceRect *small_rect)
|
||||||
|
{
|
||||||
|
return big_rect->left <= small_rect->left && big_rect->right >= small_rect->right &&
|
||||||
|
big_rect->top <= small_rect->top && big_rect->bottom >= small_rect->bottom;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
static inline int rect_get_area(const SpiceRect *r)
|
||||||
|
{
|
||||||
|
return (r->right - r->left) * (r->bottom - r->top);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void rect_debug(const SpiceRect *r)
|
||||||
|
{
|
||||||
|
spice_debug("(%d, %d) (%d, %d)", r->left, r->top, r->right, r->bottom);
|
||||||
|
}
|
||||||
|
|
||||||
|
SPICE_END_DECLS
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
||||||
@ -117,6 +130,21 @@ static inline int rect_is_same_size(const SpiceRect& r1, const SpiceRect& r2)
|
|||||||
return rect_is_same_size(&r1, &r2);
|
return rect_is_same_size(&r1, &r2);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
static inline int rect_contains(const SpiceRect& big_rect, const SpiceRect& small_rect)
|
||||||
|
{
|
||||||
|
return rect_contains(&big_rect, &small_rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int rect_get_area(const SpiceRect& r)
|
||||||
|
{
|
||||||
|
return rect_get_area(&r);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void rect_debug(const SpiceRect &r)
|
||||||
|
{
|
||||||
|
rect_debug(&r);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
394
common/region.c
394
common/region.c
@ -15,9 +15,7 @@
|
|||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -386,6 +384,17 @@ void region_ret_rects(const QRegion *rgn, SpiceRect *rects, uint32_t num_rects)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void region_extents(const QRegion *rgn, SpiceRect *r)
|
||||||
|
{
|
||||||
|
pixman_box32_t *extents;
|
||||||
|
|
||||||
|
extents = pixman_region32_extents((pixman_region32_t *)rgn);
|
||||||
|
|
||||||
|
r->left = extents->x1;
|
||||||
|
r->top = extents->y1;
|
||||||
|
r->right = extents->x2;
|
||||||
|
r->bottom = extents->y2;
|
||||||
|
}
|
||||||
|
|
||||||
int region_is_equal(const QRegion *rgn1, const QRegion *rgn2)
|
int region_is_equal(const QRegion *rgn1, const QRegion *rgn2)
|
||||||
{
|
{
|
||||||
@ -409,7 +418,7 @@ int region_bounds_intersects(const QRegion *rgn1, const QRegion *rgn2)
|
|||||||
pixman_box32_t *extents1, *extents2;
|
pixman_box32_t *extents1, *extents2;
|
||||||
|
|
||||||
extents1 = pixman_region32_extents((pixman_region32_t *)rgn1);
|
extents1 = pixman_region32_extents((pixman_region32_t *)rgn1);
|
||||||
extents2 = pixman_region32_extents((pixman_region32_t *)rgn1);
|
extents2 = pixman_region32_extents((pixman_region32_t *)rgn2);
|
||||||
|
|
||||||
return EXTENTCHECK(extents1, extents2);
|
return EXTENTCHECK(extents1, extents2);
|
||||||
}
|
}
|
||||||
@ -441,6 +450,7 @@ void region_xor(QRegion *rgn, const QRegion *other_rgn)
|
|||||||
{
|
{
|
||||||
pixman_region32_t intersection;
|
pixman_region32_t intersection;
|
||||||
|
|
||||||
|
pixman_region32_init(&intersection);
|
||||||
pixman_region32_copy(&intersection, rgn);
|
pixman_region32_copy(&intersection, rgn);
|
||||||
pixman_region32_intersect(&intersection,
|
pixman_region32_intersect(&intersection,
|
||||||
&intersection,
|
&intersection,
|
||||||
@ -510,381 +520,3 @@ void region_dump(const QRegion *rgn, const char *prefix)
|
|||||||
rects[i].y2);
|
rects[i].y2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef REGION_TEST
|
|
||||||
|
|
||||||
static int slow_region_test(const QRegion *rgn, const QRegion *other_rgn, int query)
|
|
||||||
{
|
|
||||||
pixman_region32_t intersection;
|
|
||||||
int res;
|
|
||||||
|
|
||||||
pixman_region32_init(&intersection);
|
|
||||||
pixman_region32_intersect(&intersection,
|
|
||||||
(pixman_region32_t *)rgn,
|
|
||||||
(pixman_region32_t *)other_rgn);
|
|
||||||
|
|
||||||
res = 0;
|
|
||||||
|
|
||||||
if (query & REGION_TEST_SHARED &&
|
|
||||||
pixman_region32_not_empty(&intersection)) {
|
|
||||||
res |= REGION_TEST_SHARED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (query & REGION_TEST_LEFT_EXCLUSIVE &&
|
|
||||||
!pixman_region32_equal(&intersection, (pixman_region32_t *)rgn)) {
|
|
||||||
res |= REGION_TEST_LEFT_EXCLUSIVE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (query & REGION_TEST_RIGHT_EXCLUSIVE &&
|
|
||||||
!pixman_region32_equal(&intersection, (pixman_region32_t *)other_rgn)) {
|
|
||||||
res |= REGION_TEST_RIGHT_EXCLUSIVE;
|
|
||||||
}
|
|
||||||
|
|
||||||
pixman_region32_fini(&intersection);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int rect_is_valid(const SpiceRect *r)
|
|
||||||
{
|
|
||||||
if (r->top > r->bottom || r->left > r->right) {
|
|
||||||
printf("%s: invalid rect\n", __FUNCTION__);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rect_set(SpiceRect *r, int32_t top, int32_t left, int32_t bottom, int32_t right)
|
|
||||||
{
|
|
||||||
r->top = top;
|
|
||||||
r->left = left;
|
|
||||||
r->bottom = bottom;
|
|
||||||
r->right = right;
|
|
||||||
ASSERT(rect_is_valid(r));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void random_region(QRegion *reg)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
int num_rects;
|
|
||||||
int x, y, w, h;
|
|
||||||
SpiceRect _r;
|
|
||||||
SpiceRect *r = &_r;
|
|
||||||
|
|
||||||
region_clear(reg);
|
|
||||||
|
|
||||||
num_rects = rand() % 20;
|
|
||||||
for (i = 0; i < num_rects; i++) {
|
|
||||||
x = rand()%100;
|
|
||||||
y = rand()%100;
|
|
||||||
w = rand()%100;
|
|
||||||
h = rand()%100;
|
|
||||||
rect_set(r,
|
|
||||||
x, y,
|
|
||||||
x+w, y+h);
|
|
||||||
region_add(reg, r);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test(const QRegion *r1, const QRegion *r2, int *expected)
|
|
||||||
{
|
|
||||||
printf("r1 is_empty %s [%s]\n",
|
|
||||||
region_is_empty(r1) ? "TRUE" : "FALSE",
|
|
||||||
(region_is_empty(r1) == *(expected++)) ? "OK" : "ERR");
|
|
||||||
printf("r2 is_empty %s [%s]\n",
|
|
||||||
region_is_empty(r2) ? "TRUE" : "FALSE",
|
|
||||||
(region_is_empty(r2) == *(expected++)) ? "OK" : "ERR");
|
|
||||||
printf("is_equal %s [%s]\n",
|
|
||||||
region_is_equal(r1, r2) ? "TRUE" : "FALSE",
|
|
||||||
(region_is_equal(r1, r2) == *(expected++)) ? "OK" : "ERR");
|
|
||||||
printf("intersects %s [%s]\n",
|
|
||||||
region_intersects(r1, r2) ? "TRUE" : "FALSE",
|
|
||||||
(region_intersects(r1, r2) == *(expected++)) ? "OK" : "ERR");
|
|
||||||
printf("contains %s [%s]\n",
|
|
||||||
region_contains(r1, r2) ? "TRUE" : "FALSE",
|
|
||||||
(region_contains(r1, r2) == *(expected++)) ? "OK" : "ERR");
|
|
||||||
}
|
|
||||||
|
|
||||||
enum {
|
|
||||||
EXPECT_R1_EMPTY,
|
|
||||||
EXPECT_R2_EMPTY,
|
|
||||||
EXPECT_EQUAL,
|
|
||||||
EXPECT_SECT,
|
|
||||||
EXPECT_CONT,
|
|
||||||
};
|
|
||||||
|
|
||||||
int main(void)
|
|
||||||
{
|
|
||||||
QRegion _r1, _r2, _r3;
|
|
||||||
QRegion *r1 = &_r1;
|
|
||||||
QRegion *r2 = &_r2;
|
|
||||||
QRegion *r3 = &_r3;
|
|
||||||
SpiceRect _r;
|
|
||||||
SpiceRect *r = &_r;
|
|
||||||
int expected[5];
|
|
||||||
int i, j;
|
|
||||||
|
|
||||||
region_init(r1);
|
|
||||||
region_init(r2);
|
|
||||||
|
|
||||||
printf("dump r1 empty rgn [%s]\n", region_is_valid(r1) ? "VALID" : "INVALID");
|
|
||||||
region_dump(r1, "");
|
|
||||||
expected[EXPECT_R1_EMPTY] = TRUE;
|
|
||||||
expected[EXPECT_R2_EMPTY] = TRUE;
|
|
||||||
expected[EXPECT_EQUAL] = TRUE;
|
|
||||||
expected[EXPECT_SECT] = FALSE;
|
|
||||||
expected[EXPECT_CONT] = TRUE;
|
|
||||||
test(r1, r2, expected);
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
region_clone(r3, r1);
|
|
||||||
printf("dump r3 clone rgn [%s]\n", region_is_valid(r3) ? "VALID" : "INVALID");
|
|
||||||
region_dump(r3, "");
|
|
||||||
expected[EXPECT_R1_EMPTY] = TRUE;
|
|
||||||
expected[EXPECT_R2_EMPTY] = TRUE;
|
|
||||||
expected[EXPECT_EQUAL] = TRUE;
|
|
||||||
expected[EXPECT_SECT] = FALSE;
|
|
||||||
expected[EXPECT_CONT] = TRUE;
|
|
||||||
test(r1, r3, expected);
|
|
||||||
region_destroy(r3);
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
rect_set(r, 0, 0, 100, 100);
|
|
||||||
region_add(r1, r);
|
|
||||||
printf("dump r1 [%s]\n", region_is_valid(r1) ? "VALID" : "INVALID");
|
|
||||||
region_dump(r1, "");
|
|
||||||
expected[EXPECT_R1_EMPTY] = FALSE;
|
|
||||||
expected[EXPECT_R2_EMPTY] = TRUE;
|
|
||||||
expected[EXPECT_EQUAL] = FALSE;
|
|
||||||
expected[EXPECT_SECT] = FALSE;
|
|
||||||
expected[EXPECT_CONT] = TRUE;
|
|
||||||
test(r1, r2, expected);
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
region_clear(r1);
|
|
||||||
rect_set(r, 0, 0, 0, 0);
|
|
||||||
region_add(r1, r);
|
|
||||||
printf("dump r1 [%s]\n", region_is_valid(r1) ? "VALID" : "INVALID");
|
|
||||||
region_dump(r1, "");
|
|
||||||
expected[EXPECT_R1_EMPTY] = TRUE;
|
|
||||||
expected[EXPECT_R2_EMPTY] = TRUE;
|
|
||||||
expected[EXPECT_EQUAL] = TRUE;
|
|
||||||
expected[EXPECT_SECT] = FALSE;
|
|
||||||
expected[EXPECT_CONT] = TRUE;
|
|
||||||
test(r1, r2, expected);
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
rect_set(r, -100, -100, 0, 0);
|
|
||||||
region_add(r1, r);
|
|
||||||
printf("dump r1 [%s]\n", region_is_valid(r1) ? "VALID" : "INVALID");
|
|
||||||
region_dump(r1, "");
|
|
||||||
expected[EXPECT_R1_EMPTY] = FALSE;
|
|
||||||
expected[EXPECT_R2_EMPTY] = TRUE;
|
|
||||||
expected[EXPECT_EQUAL] = FALSE;
|
|
||||||
expected[EXPECT_SECT] = FALSE;
|
|
||||||
expected[EXPECT_CONT] = TRUE;
|
|
||||||
test(r1, r2, expected);
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
region_clear(r1);
|
|
||||||
rect_set(r, -100, -100, 100, 100);
|
|
||||||
region_add(r1, r);
|
|
||||||
printf("dump r1 [%s]\n", region_is_valid(r1) ? "VALID" : "INVALID");
|
|
||||||
region_dump(r1, "");
|
|
||||||
expected[EXPECT_R1_EMPTY] = FALSE;
|
|
||||||
expected[EXPECT_R2_EMPTY] = TRUE;
|
|
||||||
expected[EXPECT_EQUAL] = FALSE;
|
|
||||||
expected[EXPECT_SECT] = FALSE;
|
|
||||||
expected[EXPECT_CONT] = TRUE;
|
|
||||||
test(r1, r2, expected);
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
|
|
||||||
region_clear(r1);
|
|
||||||
region_clear(r2);
|
|
||||||
|
|
||||||
rect_set(r, 100, 100, 200, 200);
|
|
||||||
region_add(r1, r);
|
|
||||||
printf("dump r1 [%s]\n", region_is_valid(r1) ? "VALID" : "INVALID");
|
|
||||||
region_dump(r1, "");
|
|
||||||
expected[EXPECT_R1_EMPTY] = FALSE;
|
|
||||||
expected[EXPECT_R2_EMPTY] = TRUE;
|
|
||||||
expected[EXPECT_EQUAL] = FALSE;
|
|
||||||
expected[EXPECT_SECT] = FALSE;
|
|
||||||
expected[EXPECT_CONT] = TRUE;
|
|
||||||
test(r1, r2, expected);
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
rect_set(r, 300, 300, 400, 400);
|
|
||||||
region_add(r1, r);
|
|
||||||
printf("dump r1 [%s]\n", region_is_valid(r1) ? "VALID" : "INVALID");
|
|
||||||
region_dump(r1, "");
|
|
||||||
expected[EXPECT_R1_EMPTY] = FALSE;
|
|
||||||
expected[EXPECT_R2_EMPTY] = TRUE;
|
|
||||||
expected[EXPECT_EQUAL] = FALSE;
|
|
||||||
expected[EXPECT_SECT] = FALSE;
|
|
||||||
expected[EXPECT_CONT] = TRUE;
|
|
||||||
test(r1, r2, expected);
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
rect_set(r, 500, 500, 600, 600);
|
|
||||||
region_add(r2, r);
|
|
||||||
printf("dump r2 [%s]\n", region_is_valid(r2) ? "VALID" : "INVALID");
|
|
||||||
region_dump(r2, "");
|
|
||||||
expected[EXPECT_R1_EMPTY] = FALSE;
|
|
||||||
expected[EXPECT_R2_EMPTY] = FALSE;
|
|
||||||
expected[EXPECT_EQUAL] = FALSE;
|
|
||||||
expected[EXPECT_SECT] = FALSE;
|
|
||||||
expected[EXPECT_CONT] = FALSE;
|
|
||||||
test(r1, r2, expected);
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
region_clear(r2);
|
|
||||||
|
|
||||||
rect_set(r, 100, 100, 200, 200);
|
|
||||||
region_add(r2, r);
|
|
||||||
rect_set(r, 300, 300, 400, 400);
|
|
||||||
region_add(r2, r);
|
|
||||||
printf("dump r2 [%s]\n", region_is_valid(r2) ? "VALID" : "INVALID");
|
|
||||||
region_dump(r2, "");
|
|
||||||
expected[EXPECT_R1_EMPTY] = FALSE;
|
|
||||||
expected[EXPECT_R2_EMPTY] = FALSE;
|
|
||||||
expected[EXPECT_EQUAL] = TRUE;
|
|
||||||
expected[EXPECT_SECT] = TRUE;
|
|
||||||
expected[EXPECT_CONT] = TRUE;
|
|
||||||
test(r1, r2, expected);
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
region_clear(r2);
|
|
||||||
|
|
||||||
rect_set(r, 100, 100, 200, 200);
|
|
||||||
region_add(r2, r);
|
|
||||||
printf("dump r2 [%s]\n", region_is_valid(r2) ? "VALID" : "INVALID");
|
|
||||||
region_dump(r2, "");
|
|
||||||
expected[EXPECT_R1_EMPTY] = FALSE;
|
|
||||||
expected[EXPECT_R2_EMPTY] = FALSE;
|
|
||||||
expected[EXPECT_EQUAL] = FALSE;
|
|
||||||
expected[EXPECT_SECT] = TRUE;
|
|
||||||
expected[EXPECT_CONT] = TRUE;
|
|
||||||
test(r1, r2, expected);
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
region_clear(r2);
|
|
||||||
|
|
||||||
rect_set(r, -2000, -2000, -1000, -1000);
|
|
||||||
region_add(r2, r);
|
|
||||||
printf("dump r2 [%s]\n", region_is_valid(r2) ? "VALID" : "INVALID");
|
|
||||||
region_dump(r2, "");
|
|
||||||
expected[EXPECT_R1_EMPTY] = FALSE;
|
|
||||||
expected[EXPECT_R2_EMPTY] = FALSE;
|
|
||||||
expected[EXPECT_EQUAL] = FALSE;
|
|
||||||
expected[EXPECT_SECT] = FALSE;
|
|
||||||
expected[EXPECT_CONT] = FALSE;
|
|
||||||
test(r1, r2, expected);
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
region_clear(r2);
|
|
||||||
|
|
||||||
rect_set(r, -2000, -2000, 1000, 1000);
|
|
||||||
region_add(r2, r);
|
|
||||||
printf("dump r2 [%s]\n", region_is_valid(r2) ? "VALID" : "INVALID");
|
|
||||||
region_dump(r2, "");
|
|
||||||
expected[EXPECT_R1_EMPTY] = FALSE;
|
|
||||||
expected[EXPECT_R2_EMPTY] = FALSE;
|
|
||||||
expected[EXPECT_EQUAL] = FALSE;
|
|
||||||
expected[EXPECT_SECT] = TRUE;
|
|
||||||
expected[EXPECT_CONT] = FALSE;
|
|
||||||
test(r1, r2, expected);
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
region_clear(r2);
|
|
||||||
|
|
||||||
rect_set(r, 150, 150, 175, 175);
|
|
||||||
region_add(r2, r);
|
|
||||||
printf("dump r2 [%s]\n", region_is_valid(r2) ? "VALID" : "INVALID");
|
|
||||||
region_dump(r2, "");
|
|
||||||
expected[EXPECT_R1_EMPTY] = FALSE;
|
|
||||||
expected[EXPECT_R2_EMPTY] = FALSE;
|
|
||||||
expected[EXPECT_EQUAL] = FALSE;
|
|
||||||
expected[EXPECT_SECT] = TRUE;
|
|
||||||
expected[EXPECT_CONT] = TRUE;
|
|
||||||
test(r1, r2, expected);
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
region_clear(r2);
|
|
||||||
|
|
||||||
rect_set(r, 150, 150, 350, 350);
|
|
||||||
region_add(r2, r);
|
|
||||||
printf("dump r2 [%s]\n", region_is_valid(r2) ? "VALID" : "INVALID");
|
|
||||||
region_dump(r2, "");
|
|
||||||
expected[EXPECT_R1_EMPTY] = FALSE;
|
|
||||||
expected[EXPECT_R2_EMPTY] = FALSE;
|
|
||||||
expected[EXPECT_EQUAL] = FALSE;
|
|
||||||
expected[EXPECT_SECT] = TRUE;
|
|
||||||
expected[EXPECT_CONT] = FALSE;
|
|
||||||
test(r1, r2, expected);
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
region_and(r2, r1);
|
|
||||||
printf("dump r2 and r1 [%s]\n", region_is_valid(r2) ? "VALID" : "INVALID");
|
|
||||||
region_dump(r2, "");
|
|
||||||
expected[EXPECT_R1_EMPTY] = FALSE;
|
|
||||||
expected[EXPECT_R2_EMPTY] = FALSE;
|
|
||||||
expected[EXPECT_EQUAL] = FALSE;
|
|
||||||
expected[EXPECT_SECT] = TRUE;
|
|
||||||
expected[EXPECT_CONT] = FALSE;
|
|
||||||
test(r2, r1, expected);
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
|
|
||||||
region_clone(r3, r1);
|
|
||||||
printf("dump r3 clone rgn [%s]\n", region_is_valid(r3) ? "VALID" : "INVALID");
|
|
||||||
region_dump(r3, "");
|
|
||||||
expected[EXPECT_R1_EMPTY] = FALSE;
|
|
||||||
expected[EXPECT_R2_EMPTY] = FALSE;
|
|
||||||
expected[EXPECT_EQUAL] = TRUE;
|
|
||||||
expected[EXPECT_SECT] = TRUE;
|
|
||||||
expected[EXPECT_CONT] = TRUE;
|
|
||||||
test(r1, r3, expected);
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
j = 0;
|
|
||||||
for (i = 0; i < 1000000; i++) {
|
|
||||||
int res1, res2, test;
|
|
||||||
int tests[] = {
|
|
||||||
REGION_TEST_LEFT_EXCLUSIVE,
|
|
||||||
REGION_TEST_RIGHT_EXCLUSIVE,
|
|
||||||
REGION_TEST_SHARED,
|
|
||||||
REGION_TEST_LEFT_EXCLUSIVE | REGION_TEST_RIGHT_EXCLUSIVE,
|
|
||||||
REGION_TEST_LEFT_EXCLUSIVE | REGION_TEST_SHARED,
|
|
||||||
REGION_TEST_RIGHT_EXCLUSIVE | REGION_TEST_SHARED,
|
|
||||||
REGION_TEST_LEFT_EXCLUSIVE | REGION_TEST_RIGHT_EXCLUSIVE | REGION_TEST_SHARED
|
|
||||||
};
|
|
||||||
|
|
||||||
random_region(r1);
|
|
||||||
random_region(r2);
|
|
||||||
|
|
||||||
for (test = 0; test < 7; test++) {
|
|
||||||
res1 = region_test(r1, r2, tests[test]);
|
|
||||||
res2 = slow_region_test(r1, r2, tests[test]);
|
|
||||||
if (res1 != res2) {
|
|
||||||
printf ("Error in region_test %d, got %d, expected %d, query=%d\n",
|
|
||||||
j, res1, res2, tests[test]);
|
|
||||||
printf ("r1:\n");
|
|
||||||
region_dump(r1, "");
|
|
||||||
printf ("r2:\n");
|
|
||||||
region_dump(r2, "");
|
|
||||||
}
|
|
||||||
j++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
region_destroy(r3);
|
|
||||||
region_destroy(r1);
|
|
||||||
region_destroy(r2);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||
@ -16,21 +16,24 @@
|
|||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _H_REGION
|
#ifndef H_SPICE_COMMON_REGION
|
||||||
#define _H_REGION
|
#define H_SPICE_COMMON_REGION
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "draw.h"
|
#include <spice/macros.h>
|
||||||
#include <pixman_utils.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#include "draw.h"
|
||||||
extern "C" {
|
#include "pixman_utils.h"
|
||||||
#endif
|
|
||||||
|
SPICE_BEGIN_DECLS
|
||||||
|
|
||||||
typedef pixman_region32_t QRegion;
|
typedef pixman_region32_t QRegion;
|
||||||
|
|
||||||
|
/* the left region is not contained entirely within the right region */
|
||||||
#define REGION_TEST_LEFT_EXCLUSIVE (1 << 0)
|
#define REGION_TEST_LEFT_EXCLUSIVE (1 << 0)
|
||||||
|
/* the right region is not contained entirely within the left region */
|
||||||
#define REGION_TEST_RIGHT_EXCLUSIVE (1 << 1)
|
#define REGION_TEST_RIGHT_EXCLUSIVE (1 << 1)
|
||||||
|
/* the regions overlap */
|
||||||
#define REGION_TEST_SHARED (1 << 2)
|
#define REGION_TEST_SHARED (1 << 2)
|
||||||
#define REGION_TEST_ALL \
|
#define REGION_TEST_ALL \
|
||||||
(REGION_TEST_LEFT_EXCLUSIVE | REGION_TEST_RIGHT_EXCLUSIVE | REGION_TEST_SHARED)
|
(REGION_TEST_LEFT_EXCLUSIVE | REGION_TEST_RIGHT_EXCLUSIVE | REGION_TEST_SHARED)
|
||||||
@ -41,6 +44,7 @@ void region_destroy(QRegion *rgn);
|
|||||||
void region_clone(QRegion *dest, const QRegion *src);
|
void region_clone(QRegion *dest, const QRegion *src);
|
||||||
SpiceRect *region_dup_rects(const QRegion *rgn, uint32_t *num_rects);
|
SpiceRect *region_dup_rects(const QRegion *rgn, uint32_t *num_rects);
|
||||||
void region_ret_rects(const QRegion *rgn, SpiceRect *rects, uint32_t num_rects);
|
void region_ret_rects(const QRegion *rgn, SpiceRect *rects, uint32_t num_rects);
|
||||||
|
void region_extents(const QRegion *rgn, SpiceRect *r);
|
||||||
|
|
||||||
int region_test(const QRegion *rgn, const QRegion *other_rgn, int query);
|
int region_test(const QRegion *rgn, const QRegion *other_rgn, int query);
|
||||||
int region_is_valid(const QRegion *rgn);
|
int region_is_valid(const QRegion *rgn);
|
||||||
@ -61,10 +65,9 @@ void region_remove(QRegion *rgn, const SpiceRect *r);
|
|||||||
|
|
||||||
void region_offset(QRegion *rgn, int32_t dx, int32_t dy);
|
void region_offset(QRegion *rgn, int32_t dx, int32_t dy);
|
||||||
|
|
||||||
|
|
||||||
void region_dump(const QRegion *rgn, const char *prefix);
|
void region_dump(const QRegion *rgn, const char *prefix);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
SPICE_END_DECLS
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -16,14 +16,12 @@
|
|||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _H_RING2
|
#ifndef H_SPICE_COMMON_RING
|
||||||
#define _H_RING2
|
#define H_SPICE_COMMON_RING
|
||||||
|
|
||||||
#include "spice_common.h"
|
#include "log.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
SPICE_BEGIN_DECLS
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct Ring RingItem;
|
typedef struct Ring RingItem;
|
||||||
typedef struct Ring {
|
typedef struct Ring {
|
||||||
@ -48,14 +46,14 @@ static inline int ring_item_is_linked(RingItem *item)
|
|||||||
|
|
||||||
static inline int ring_is_empty(Ring *ring)
|
static inline int ring_is_empty(Ring *ring)
|
||||||
{
|
{
|
||||||
ASSERT(ring->next != NULL && ring->prev != NULL);
|
spice_assert(ring->next != NULL && ring->prev != NULL);
|
||||||
return ring == ring->next;
|
return ring == ring->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void ring_add(Ring *ring, RingItem *item)
|
static inline void ring_add(Ring *ring, RingItem *item)
|
||||||
{
|
{
|
||||||
ASSERT(ring->next != NULL && ring->prev != NULL);
|
spice_assert(ring->next != NULL && ring->prev != NULL);
|
||||||
ASSERT(item->next == NULL && item->prev == NULL);
|
spice_assert(item->next == NULL && item->prev == NULL);
|
||||||
|
|
||||||
item->next = ring->next;
|
item->next = ring->next;
|
||||||
item->prev = ring;
|
item->prev = ring;
|
||||||
@ -72,54 +70,43 @@ static inline void ring_add_before(RingItem *item, RingItem *pos)
|
|||||||
ring_add(pos->prev, item);
|
ring_add(pos->prev, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void __ring_remove(RingItem *item)
|
|
||||||
{
|
|
||||||
item->next->prev = item->prev;
|
|
||||||
item->prev->next = item->next;
|
|
||||||
item->prev = item->next = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void ring_remove(RingItem *item)
|
static inline void ring_remove(RingItem *item)
|
||||||
{
|
{
|
||||||
ASSERT(item->next != NULL && item->prev != NULL);
|
spice_assert(item->next != NULL && item->prev != NULL);
|
||||||
ASSERT(item->next != item);
|
spice_assert(item->next != item);
|
||||||
|
|
||||||
__ring_remove(item);
|
item->next->prev = item->prev;
|
||||||
|
item->prev->next = item->next;
|
||||||
|
item->prev = item->next = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline RingItem *ring_get_head(Ring *ring)
|
static inline RingItem *ring_get_head(Ring *ring)
|
||||||
{
|
{
|
||||||
RingItem *ret;
|
spice_assert(ring->next != NULL && ring->prev != NULL);
|
||||||
|
|
||||||
ASSERT(ring->next != NULL && ring->prev != NULL);
|
|
||||||
|
|
||||||
if (ring_is_empty(ring)) {
|
if (ring_is_empty(ring)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
ret = ring->next;
|
return ring->next;
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline RingItem *ring_get_tail(Ring *ring)
|
static inline RingItem *ring_get_tail(Ring *ring)
|
||||||
{
|
{
|
||||||
RingItem *ret;
|
spice_assert(ring->next != NULL && ring->prev != NULL);
|
||||||
|
|
||||||
ASSERT(ring->next != NULL && ring->prev != NULL);
|
|
||||||
|
|
||||||
if (ring_is_empty(ring)) {
|
if (ring_is_empty(ring)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
ret = ring->prev;
|
return ring->prev;
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline RingItem *ring_next(Ring *ring, RingItem *pos)
|
static inline RingItem *ring_next(Ring *ring, RingItem *pos)
|
||||||
{
|
{
|
||||||
RingItem *ret;
|
RingItem *ret;
|
||||||
|
|
||||||
ASSERT(ring->next != NULL && ring->prev != NULL);
|
spice_assert(ring->next != NULL && ring->prev != NULL);
|
||||||
ASSERT(pos);
|
spice_assert(pos);
|
||||||
ASSERT(pos->next != NULL && pos->prev != NULL);
|
spice_assert(pos->next != NULL && pos->prev != NULL);
|
||||||
ret = pos->next;
|
ret = pos->next;
|
||||||
return (ret == ring) ? NULL : ret;
|
return (ret == ring) ? NULL : ret;
|
||||||
}
|
}
|
||||||
@ -128,9 +115,9 @@ static inline RingItem *ring_prev(Ring *ring, RingItem *pos)
|
|||||||
{
|
{
|
||||||
RingItem *ret;
|
RingItem *ret;
|
||||||
|
|
||||||
ASSERT(ring->next != NULL && ring->prev != NULL);
|
spice_assert(ring->next != NULL && ring->prev != NULL);
|
||||||
ASSERT(pos);
|
spice_assert(pos);
|
||||||
ASSERT(pos->next != NULL && pos->prev != NULL);
|
spice_assert(pos->next != NULL && pos->prev != NULL);
|
||||||
ret = pos->prev;
|
ret = pos->prev;
|
||||||
return (ret == ring) ? NULL : ret;
|
return (ret == ring) ? NULL : ret;
|
||||||
}
|
}
|
||||||
@ -157,16 +144,12 @@ static inline unsigned int ring_get_length(Ring *ring)
|
|||||||
RingItem *i;
|
RingItem *i;
|
||||||
unsigned int ret = 0;
|
unsigned int ret = 0;
|
||||||
|
|
||||||
for (i = ring_get_head(ring);
|
RING_FOREACH(i, ring)
|
||||||
i != NULL;
|
|
||||||
i = ring_next(ring, i))
|
|
||||||
ret++;
|
ret++;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
SPICE_END_DECLS
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -15,14 +15,9 @@
|
|||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include "rop3.h"
|
#include "rop3.h"
|
||||||
#include "spice_common.h"
|
|
||||||
|
|
||||||
typedef void (*rop3_with_pattern_handler_t)(pixman_image_t *d, pixman_image_t *s,
|
typedef void (*rop3_with_pattern_handler_t)(pixman_image_t *d, pixman_image_t *s,
|
||||||
SpicePoint *src_pos, pixman_image_t *p,
|
SpicePoint *src_pos, pixman_image_t *p,
|
||||||
@ -43,17 +38,21 @@ static rop3_test_handler_t rop3_test_handlers_32[ROP3_NUM_OPS];
|
|||||||
static rop3_test_handler_t rop3_test_handlers_16[ROP3_NUM_OPS];
|
static rop3_test_handler_t rop3_test_handlers_16[ROP3_NUM_OPS];
|
||||||
|
|
||||||
|
|
||||||
static void default_rop3_with_pattern_handler(pixman_image_t *d, pixman_image_t *s,
|
static void default_rop3_with_pattern_handler(SPICE_GNUC_UNUSED pixman_image_t *d,
|
||||||
SpicePoint *src_pos, pixman_image_t *p,
|
SPICE_GNUC_UNUSED pixman_image_t *s,
|
||||||
SpicePoint *pat_pos)
|
SPICE_GNUC_UNUSED SpicePoint *src_pos,
|
||||||
|
SPICE_GNUC_UNUSED pixman_image_t *p,
|
||||||
|
SPICE_GNUC_UNUSED SpicePoint *pat_pos)
|
||||||
{
|
{
|
||||||
WARN("not implemented");
|
spice_critical("not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void default_rop3_withe_color_handler(pixman_image_t *d, pixman_image_t *s, SpicePoint *src_pos,
|
static void default_rop3_withe_color_handler(SPICE_GNUC_UNUSED pixman_image_t *d,
|
||||||
uint32_t rgb)
|
SPICE_GNUC_UNUSED pixman_image_t *s,
|
||||||
|
SPICE_GNUC_UNUSED SpicePoint *src_pos,
|
||||||
|
SPICE_GNUC_UNUSED uint32_t rgb)
|
||||||
{
|
{
|
||||||
WARN("not implemented");
|
spice_critical("not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void default_rop3_test_handler(void)
|
static void default_rop3_test_handler(void)
|
||||||
@ -374,16 +373,10 @@ ROP3_HANDLERS(DPSoo, *src | *pat | *dest, 0xfe);
|
|||||||
rop3_test_handlers_32[index] = rop3_test32_##op; \
|
rop3_test_handlers_32[index] = rop3_test32_##op; \
|
||||||
rop3_test_handlers_16[index] = rop3_test16_##op;
|
rop3_test_handlers_16[index] = rop3_test16_##op;
|
||||||
|
|
||||||
void rop3_init(void)
|
SPICE_CONSTRUCTOR_FUNC(rop3_global_init)
|
||||||
{
|
{
|
||||||
static int need_init = 1;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (!need_init) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
need_init = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < ROP3_NUM_OPS; i++) {
|
for (i = 0; i < ROP3_NUM_OPS; i++) {
|
||||||
rop3_with_pattern_handlers_32[i] = default_rop3_with_pattern_handler;
|
rop3_with_pattern_handlers_32[i] = default_rop3_with_pattern_handler;
|
||||||
rop3_with_pattern_handlers_16[i] = default_rop3_with_pattern_handler;
|
rop3_with_pattern_handlers_16[i] = default_rop3_with_pattern_handler;
|
||||||
@ -624,8 +617,8 @@ void do_rop3_with_pattern(uint8_t rop3, pixman_image_t *d, pixman_image_t *s, Sp
|
|||||||
int bpp;
|
int bpp;
|
||||||
|
|
||||||
bpp = spice_pixman_image_get_bpp(d);
|
bpp = spice_pixman_image_get_bpp(d);
|
||||||
ASSERT (bpp == spice_pixman_image_get_bpp(s));
|
spice_assert(bpp == spice_pixman_image_get_bpp(s));
|
||||||
ASSERT (bpp == spice_pixman_image_get_bpp(p));
|
spice_assert(bpp == spice_pixman_image_get_bpp(p));
|
||||||
|
|
||||||
if (bpp == 32) {
|
if (bpp == 32) {
|
||||||
rop3_with_pattern_handlers_32[rop3](d, s, src_pos, p, pat_pos);
|
rop3_with_pattern_handlers_32[rop3](d, s, src_pos, p, pat_pos);
|
||||||
@ -640,7 +633,7 @@ void do_rop3_with_color(uint8_t rop3, pixman_image_t *d, pixman_image_t *s, Spic
|
|||||||
int bpp;
|
int bpp;
|
||||||
|
|
||||||
bpp = spice_pixman_image_get_bpp(d);
|
bpp = spice_pixman_image_get_bpp(d);
|
||||||
ASSERT (bpp == spice_pixman_image_get_bpp(s));
|
spice_assert(bpp == spice_pixman_image_get_bpp(s));
|
||||||
|
|
||||||
if (bpp == 32) {
|
if (bpp == 32) {
|
||||||
rop3_with_color_handlers_32[rop3](d, s, src_pos, rgb);
|
rop3_with_color_handlers_32[rop3](d, s, src_pos, rgb);
|
||||||
|
|||||||
@ -16,27 +16,22 @@
|
|||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _H_ROP3
|
#ifndef H_SPICE_COMMON_ROP3
|
||||||
#define _H_ROP3
|
#define H_SPICE_COMMON_ROP3
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <spice/macros.h>
|
||||||
|
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
#include "pixman_utils.h"
|
#include "pixman_utils.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
SPICE_BEGIN_DECLS
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void do_rop3_with_pattern(uint8_t rop3, pixman_image_t *d, pixman_image_t *s, SpicePoint *src_pos,
|
void do_rop3_with_pattern(uint8_t rop3, pixman_image_t *d, pixman_image_t *s, SpicePoint *src_pos,
|
||||||
pixman_image_t *p, SpicePoint *pat_pos);
|
pixman_image_t *p, SpicePoint *pat_pos);
|
||||||
void do_rop3_with_color(uint8_t rop3, pixman_image_t *d, pixman_image_t *s, SpicePoint *src_pos,
|
void do_rop3_with_color(uint8_t rop3, pixman_image_t *d, pixman_image_t *s, SpicePoint *src_pos,
|
||||||
uint32_t rgb);
|
uint32_t rgb);
|
||||||
|
|
||||||
void rop3_init(void);
|
SPICE_END_DECLS
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
276
common/snd_codec.c
Normal file
276
common/snd_codec.c
Normal file
@ -0,0 +1,276 @@
|
|||||||
|
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||||
|
/*
|
||||||
|
Copyright (C) 2013 Jeremy White
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* snd_codec.c
|
||||||
|
General purpose sound codec routines for use by Spice.
|
||||||
|
These routines abstract the work of picking a codec and
|
||||||
|
encoding and decoding the buffers.
|
||||||
|
|
||||||
|
See below for documentation of the public routines.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#if HAVE_OPUS
|
||||||
|
#include <opus.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <spice/macros.h>
|
||||||
|
#include <spice/enums.h>
|
||||||
|
|
||||||
|
#include "snd_codec.h"
|
||||||
|
#include "mem.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
typedef struct SndCodecInternal
|
||||||
|
{
|
||||||
|
SpiceAudioDataMode mode;
|
||||||
|
int frequency;
|
||||||
|
|
||||||
|
#if HAVE_OPUS
|
||||||
|
OpusEncoder *opus_encoder;
|
||||||
|
OpusDecoder *opus_decoder;
|
||||||
|
#endif
|
||||||
|
} SndCodecInternal;
|
||||||
|
|
||||||
|
|
||||||
|
/* Opus support routines */
|
||||||
|
#if HAVE_OPUS
|
||||||
|
static void snd_codec_destroy_opus(SndCodecInternal *codec)
|
||||||
|
{
|
||||||
|
if (codec->opus_decoder) {
|
||||||
|
opus_decoder_destroy(codec->opus_decoder);
|
||||||
|
codec->opus_decoder = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (codec->opus_encoder) {
|
||||||
|
opus_encoder_destroy(codec->opus_encoder);
|
||||||
|
codec->opus_encoder = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static SndCodecResult snd_codec_create_opus(SndCodecInternal *codec, int purpose)
|
||||||
|
{
|
||||||
|
int opus_error;
|
||||||
|
|
||||||
|
if (purpose & SND_CODEC_ENCODE) {
|
||||||
|
codec->opus_encoder = opus_encoder_create(codec->frequency,
|
||||||
|
SND_CODEC_PLAYBACK_CHAN,
|
||||||
|
OPUS_APPLICATION_AUDIO, &opus_error);
|
||||||
|
if (! codec->opus_encoder) {
|
||||||
|
g_warning("create opus encoder failed; error %d", opus_error);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (purpose & SND_CODEC_DECODE) {
|
||||||
|
codec->opus_decoder = opus_decoder_create(codec->frequency,
|
||||||
|
SND_CODEC_PLAYBACK_CHAN, &opus_error);
|
||||||
|
if (! codec->opus_decoder) {
|
||||||
|
g_warning("create opus decoder failed; error %d", opus_error);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
codec->mode = SPICE_AUDIO_DATA_MODE_OPUS;
|
||||||
|
return SND_CODEC_OK;
|
||||||
|
|
||||||
|
error:
|
||||||
|
snd_codec_destroy_opus(codec);
|
||||||
|
return SND_CODEC_UNAVAILABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SndCodecResult
|
||||||
|
snd_codec_encode_opus(SndCodecInternal *codec, uint8_t *in_ptr, int in_size,
|
||||||
|
uint8_t *out_ptr, int *out_size)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
if (in_size != SND_CODEC_OPUS_FRAME_SIZE * SND_CODEC_PLAYBACK_CHAN * 2)
|
||||||
|
return SND_CODEC_INVALID_ENCODE_SIZE;
|
||||||
|
n = opus_encode(codec->opus_encoder, (opus_int16 *) in_ptr, SND_CODEC_OPUS_FRAME_SIZE, out_ptr, *out_size);
|
||||||
|
if (n < 0) {
|
||||||
|
g_warning("opus_encode failed %d", n);
|
||||||
|
return SND_CODEC_ENCODE_FAILED;
|
||||||
|
}
|
||||||
|
*out_size = n;
|
||||||
|
return SND_CODEC_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SndCodecResult
|
||||||
|
snd_codec_decode_opus(SndCodecInternal *codec, uint8_t *in_ptr, int in_size,
|
||||||
|
uint8_t *out_ptr, int *out_size)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
n = opus_decode(codec->opus_decoder, in_ptr, in_size, (opus_int16 *) out_ptr,
|
||||||
|
*out_size / SND_CODEC_PLAYBACK_CHAN / 2, 0);
|
||||||
|
if (n < 0) {
|
||||||
|
g_warning("opus_decode failed %d", n);
|
||||||
|
return SND_CODEC_DECODE_FAILED;
|
||||||
|
}
|
||||||
|
*out_size = n * SND_CODEC_PLAYBACK_CHAN * 2 /* 16 fmt */;
|
||||||
|
return SND_CODEC_OK;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------
|
||||||
|
** PUBLIC INTERFACE
|
||||||
|
**--------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
snd_codec_is_capable
|
||||||
|
Returns true if the current spice implementation can
|
||||||
|
use the given codec, false otherwise.
|
||||||
|
mode must be a SPICE_AUDIO_DATA_MODE_XXX enum from spice/enum.h
|
||||||
|
*/
|
||||||
|
bool snd_codec_is_capable(SpiceAudioDataMode mode, int frequency)
|
||||||
|
{
|
||||||
|
#if HAVE_OPUS
|
||||||
|
if (mode == SPICE_AUDIO_DATA_MODE_OPUS &&
|
||||||
|
(frequency == SND_CODEC_ANY_FREQUENCY ||
|
||||||
|
frequency == 48000 || frequency == 24000 ||
|
||||||
|
frequency == 16000 || frequency == 12000 ||
|
||||||
|
frequency == 8000) )
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
snd_codec_create
|
||||||
|
Create a codec control. Required for most functions in this library.
|
||||||
|
Parameters:
|
||||||
|
1. codec Pointer to preallocated codec control
|
||||||
|
2. mode SPICE_AUDIO_DATA_MODE_XXX enum from spice/enum.h
|
||||||
|
3. encode TRUE if encoding is desired
|
||||||
|
4. decode TRUE if decoding is desired
|
||||||
|
Returns:
|
||||||
|
SND_CODEC_OK if all went well; a different code if not.
|
||||||
|
|
||||||
|
snd_codec_destroy is the obvious partner of snd_codec_create.
|
||||||
|
*/
|
||||||
|
SndCodecResult
|
||||||
|
snd_codec_create(SndCodec *codec, SpiceAudioDataMode mode, int frequency, int purpose)
|
||||||
|
{
|
||||||
|
SndCodecResult rc = SND_CODEC_UNAVAILABLE;
|
||||||
|
SndCodecInternal **c = codec;
|
||||||
|
|
||||||
|
*c = spice_new0(SndCodecInternal, 1);
|
||||||
|
(*c)->frequency = frequency;
|
||||||
|
|
||||||
|
#if HAVE_OPUS
|
||||||
|
if (mode == SPICE_AUDIO_DATA_MODE_OPUS)
|
||||||
|
rc = snd_codec_create_opus(*c, purpose);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
snd_codec_destroy
|
||||||
|
The obvious companion to snd_codec_create
|
||||||
|
*/
|
||||||
|
void snd_codec_destroy(SndCodec *codec)
|
||||||
|
{
|
||||||
|
SndCodecInternal **c = codec;
|
||||||
|
if (! c || ! *c)
|
||||||
|
return;
|
||||||
|
|
||||||
|
#if HAVE_OPUS
|
||||||
|
snd_codec_destroy_opus(*c);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
free(*c);
|
||||||
|
*c = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
snd_codec_frame_size
|
||||||
|
Returns the size, in frames, of the raw PCM frame buffer
|
||||||
|
required by this codec. To get bytes, you'll need
|
||||||
|
to multiply by channels and sample width.
|
||||||
|
*/
|
||||||
|
int snd_codec_frame_size(SndCodec codec)
|
||||||
|
{
|
||||||
|
#if HAVE_OPUS
|
||||||
|
SndCodecInternal *c = codec;
|
||||||
|
if (c && c->mode == SPICE_AUDIO_DATA_MODE_OPUS)
|
||||||
|
return SND_CODEC_OPUS_FRAME_SIZE;
|
||||||
|
#endif
|
||||||
|
return SND_CODEC_MAX_FRAME_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
snd_codec_encode
|
||||||
|
Encode a block of data to a compressed buffer.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
1. codec Pointer to codec control previously allocated + created
|
||||||
|
2. in_ptr Pointer to uncompressed PCM data
|
||||||
|
3. in_size Input size
|
||||||
|
4. out_ptr Pointer to area to write encoded data
|
||||||
|
5. out_size On input, the maximum size of the output buffer; on
|
||||||
|
successful return, it will hold the number of bytes
|
||||||
|
returned.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
SND_CODEC_OK if all went well
|
||||||
|
*/
|
||||||
|
SndCodecResult
|
||||||
|
snd_codec_encode(SndCodec codec, uint8_t *in_ptr, int in_size, uint8_t *out_ptr, int *out_size)
|
||||||
|
{
|
||||||
|
#if HAVE_OPUS
|
||||||
|
SndCodecInternal *c = codec;
|
||||||
|
if (c && c->mode == SPICE_AUDIO_DATA_MODE_OPUS)
|
||||||
|
return snd_codec_encode_opus(c, in_ptr, in_size, out_ptr, out_size);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return SND_CODEC_ENCODER_UNAVAILABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
snd_codec_decode
|
||||||
|
Decode a block of data from a compressed buffer.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
1. codec Pointer to codec control previously allocated + created
|
||||||
|
2. in_ptr Pointer to compressed data
|
||||||
|
3. in_size Input size
|
||||||
|
4. out_ptr Pointer to area to write decoded data
|
||||||
|
5. out_size On input, the maximum size of the output buffer; on
|
||||||
|
successful return, it will hold the number of bytes
|
||||||
|
returned.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
SND_CODEC_OK if all went well
|
||||||
|
*/
|
||||||
|
SndCodecResult
|
||||||
|
snd_codec_decode(SndCodec codec, uint8_t *in_ptr, int in_size, uint8_t *out_ptr, int *out_size)
|
||||||
|
{
|
||||||
|
#if HAVE_OPUS
|
||||||
|
SndCodecInternal *c = codec;
|
||||||
|
if (c && c->mode == SPICE_AUDIO_DATA_MODE_OPUS)
|
||||||
|
return snd_codec_decode_opus(c, in_ptr, in_size, out_ptr, out_size);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return SND_CODEC_DECODER_UNAVAILABLE;
|
||||||
|
}
|
||||||
69
common/snd_codec.h
Normal file
69
common/snd_codec.h
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||||
|
/*
|
||||||
|
Copyright (C) 2013 Jeremy White <jwhite@codeweavers.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef H_SPICE_COMMON_SND_CODEC
|
||||||
|
#define H_SPICE_COMMON_SND_CODEC
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <spice/enums.h>
|
||||||
|
|
||||||
|
#define SND_CODEC_OPUS_FRAME_SIZE 480
|
||||||
|
#define SND_CODEC_OPUS_PLAYBACK_FREQ 48000
|
||||||
|
#define SND_CODEC_OPUS_COMPRESSED_FRAME_BYTES 480
|
||||||
|
|
||||||
|
#define SND_CODEC_PLAYBACK_CHAN 2
|
||||||
|
|
||||||
|
#define SND_CODEC_MAX_FRAME_SIZE SND_CODEC_OPUS_FRAME_SIZE
|
||||||
|
#define SND_CODEC_MAX_FRAME_BYTES (SND_CODEC_MAX_FRAME_SIZE * SND_CODEC_PLAYBACK_CHAN * 2 /* FMT_S16 */)
|
||||||
|
#define SND_CODEC_MAX_COMPRESSED_BYTES SND_CODEC_OPUS_COMPRESSED_FRAME_BYTES
|
||||||
|
|
||||||
|
#define SND_CODEC_ANY_FREQUENCY -1
|
||||||
|
|
||||||
|
#define SND_CODEC_ENCODE 0x0001
|
||||||
|
#define SND_CODEC_DECODE 0x0002
|
||||||
|
|
||||||
|
SPICE_BEGIN_DECLS
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SND_CODEC_OK,
|
||||||
|
SND_CODEC_UNAVAILABLE,
|
||||||
|
SND_CODEC_ENCODER_UNAVAILABLE,
|
||||||
|
SND_CODEC_DECODER_UNAVAILABLE,
|
||||||
|
SND_CODEC_ENCODE_FAILED,
|
||||||
|
SND_CODEC_DECODE_FAILED,
|
||||||
|
SND_CODEC_INVALID_ENCODE_SIZE,
|
||||||
|
} SndCodecResult;
|
||||||
|
|
||||||
|
typedef struct SndCodecInternal * SndCodec;
|
||||||
|
|
||||||
|
bool snd_codec_is_capable(SpiceAudioDataMode mode, int frequency);
|
||||||
|
|
||||||
|
SndCodecResult snd_codec_create(SndCodec *codec,
|
||||||
|
SpiceAudioDataMode mode, int frequency, int purpose);
|
||||||
|
void snd_codec_destroy(SndCodec *codec);
|
||||||
|
|
||||||
|
int snd_codec_frame_size(SndCodec codec);
|
||||||
|
|
||||||
|
SndCodecResult snd_codec_encode(SndCodec codec, uint8_t *in_ptr, int in_size,
|
||||||
|
uint8_t *out_ptr, int *out_size);
|
||||||
|
SndCodecResult snd_codec_decode(SndCodec codec, uint8_t *in_ptr, int in_size,
|
||||||
|
uint8_t *out_ptr, int *out_size);
|
||||||
|
|
||||||
|
SPICE_END_DECLS
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -1,78 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (C) 2009 Red Hat, Inc.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef H_SPICE_COMMON
|
|
||||||
#define H_SPICE_COMMON
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include "backtrace.h"
|
|
||||||
|
|
||||||
#define ASSERT(x) if (!(x)) { \
|
|
||||||
printf("%s: ASSERT %s failed\n", __FUNCTION__, #x); \
|
|
||||||
spice_backtrace(); \
|
|
||||||
abort(); \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define PANIC(format, ...) do { \
|
|
||||||
printf("%s: panic: " format "\n", __FUNCTION__, ## __VA_ARGS__ ); \
|
|
||||||
abort(); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define PANIC_ON(x) if ((x)) { \
|
|
||||||
printf("%s: panic %s\n", __FUNCTION__, #x); \
|
|
||||||
abort(); \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define red_error(format, ...) do { \
|
|
||||||
printf("%s: " format "\n", __FUNCTION__, ## __VA_ARGS__ ); \
|
|
||||||
abort(); \
|
|
||||||
} while (0)
|
|
||||||
#define red_printf(format, ...) \
|
|
||||||
printf("%s: " format "\n", __FUNCTION__, ## __VA_ARGS__ )
|
|
||||||
|
|
||||||
#define red_printf_once(format, ...) do { \
|
|
||||||
static int do_print = TRUE; \
|
|
||||||
if (do_print) { \
|
|
||||||
do_print = FALSE; \
|
|
||||||
printf("%s: " format "\n", __FUNCTION__, ## __VA_ARGS__ ); \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define WARN(format, ...) red_printf("warning: "format, ##__VA_ARGS__ );
|
|
||||||
#define WARN_ONCE red_printf_once
|
|
||||||
|
|
||||||
#define red_printf_some(every, format, ...) do { \
|
|
||||||
static int count = 0; \
|
|
||||||
if (count++ % (every) == 0) { \
|
|
||||||
printf("%s: " format "\n", __FUNCTION__, ## __VA_ARGS__ ); \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define red_printf_debug(debug, prefix, format, ...) do { \
|
|
||||||
static int debug_level = -1; \
|
|
||||||
if (debug_level == -1) { \
|
|
||||||
debug_level = getenv("SPICE_DEBUG_LEVEL") != NULL ? atoi(getenv("SPICE_DEBUG_LEVEL")) : 0; \
|
|
||||||
} \
|
|
||||||
if (debug <= debug_level) { \
|
|
||||||
printf("%s: %s: " format "\n", prefix, __FUNCTION__, ## __VA_ARGS__ ); \
|
|
||||||
} \
|
|
||||||
} while(0)
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -16,12 +16,11 @@
|
|||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "mem.h"
|
#include "mem.h"
|
||||||
#include "ssl_verify.h"
|
#include "ssl_verify.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
@ -29,21 +28,14 @@
|
|||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#endif
|
#endif
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <gio/gio.h>
|
||||||
|
|
||||||
#ifndef SPICE_DEBUG
|
#if OPENSSL_VERSION_NUMBER < 0x10100000 || \
|
||||||
# define SPICE_DEBUG(format, ...)
|
(defined (LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000)
|
||||||
#endif
|
static const unsigned char *ASN1_STRING_get0_data(const ASN1_STRING *asn1)
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
static int inet_aton(const char* ip, struct in_addr* in_addr)
|
|
||||||
{
|
{
|
||||||
unsigned long addr = inet_addr(ip);
|
return M_ASN1_STRING_data(asn1);
|
||||||
|
|
||||||
if (addr == INADDR_NONE) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
in_addr->S_un.S_addr = addr;
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -58,36 +50,41 @@ static int verify_pubkey(X509* cert, const char *key, size_t key_size)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!cert) {
|
if (!cert) {
|
||||||
SPICE_DEBUG("warning: no cert!");
|
spice_debug("warning: no cert!");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
cert_pubkey = X509_get_pubkey(cert);
|
cert_pubkey = X509_get_pubkey(cert);
|
||||||
if (!cert_pubkey) {
|
if (!cert_pubkey) {
|
||||||
SPICE_DEBUG("warning: reading public key from certificate failed");
|
spice_debug("warning: reading public key from certificate failed");
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
bio = BIO_new_mem_buf((void*)key, key_size);
|
bio = BIO_new_mem_buf((void*)key, key_size);
|
||||||
if (!bio) {
|
if (!bio) {
|
||||||
SPICE_DEBUG("creating BIO failed");
|
spice_debug("creating BIO failed");
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
orig_pubkey = d2i_PUBKEY_bio(bio, NULL);
|
orig_pubkey = d2i_PUBKEY_bio(bio, NULL);
|
||||||
if (!orig_pubkey) {
|
if (!orig_pubkey) {
|
||||||
SPICE_DEBUG("reading pubkey from bio failed");
|
spice_debug("reading pubkey from bio failed");
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if OPENSSL_VERSION_NUMBER >= 0x30000000
|
||||||
|
ret = EVP_PKEY_eq(orig_pubkey, cert_pubkey);
|
||||||
|
#else
|
||||||
ret = EVP_PKEY_cmp(orig_pubkey, cert_pubkey);
|
ret = EVP_PKEY_cmp(orig_pubkey, cert_pubkey);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (ret == 1)
|
if (ret == 1) {
|
||||||
SPICE_DEBUG("public keys match");
|
spice_debug("public keys match");
|
||||||
else if (ret == 0)
|
} else if (ret == 0) {
|
||||||
SPICE_DEBUG("public keys mismatch");
|
spice_debug("public keys mismatch");
|
||||||
else
|
} else {
|
||||||
SPICE_DEBUG("public keys types mismatch");
|
spice_debug("public keys types mismatch");
|
||||||
|
}
|
||||||
|
|
||||||
finish:
|
finish:
|
||||||
if (bio)
|
if (bio)
|
||||||
@ -162,19 +159,14 @@ static int verify_hostname(X509* cert, const char *hostname)
|
|||||||
{
|
{
|
||||||
GENERAL_NAMES* subject_alt_names;
|
GENERAL_NAMES* subject_alt_names;
|
||||||
int found_dns_name = 0;
|
int found_dns_name = 0;
|
||||||
struct in_addr addr;
|
|
||||||
int addr_len = 0;
|
|
||||||
int cn_match = 0;
|
int cn_match = 0;
|
||||||
X509_NAME* subject;
|
X509_NAME* subject;
|
||||||
|
|
||||||
if (!cert) {
|
spice_return_val_if_fail(hostname != NULL, 0);
|
||||||
SPICE_DEBUG("warning: no cert!");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// only IpV4 supported
|
if (!cert) {
|
||||||
if (inet_aton(hostname, &addr)) {
|
spice_debug("warning: no cert!");
|
||||||
addr_len = sizeof(struct in_addr);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* try matching against:
|
/* try matching against:
|
||||||
@ -200,30 +192,56 @@ static int verify_hostname(X509* cert, const char *hostname)
|
|||||||
const GENERAL_NAME* name = sk_GENERAL_NAME_value(subject_alt_names, i);
|
const GENERAL_NAME* name = sk_GENERAL_NAME_value(subject_alt_names, i);
|
||||||
if (name->type == GEN_DNS) {
|
if (name->type == GEN_DNS) {
|
||||||
found_dns_name = 1;
|
found_dns_name = 1;
|
||||||
if (_gnutls_hostname_compare((char *)ASN1_STRING_data(name->d.dNSName),
|
if (_gnutls_hostname_compare((const char *)ASN1_STRING_get0_data(name->d.dNSName),
|
||||||
ASN1_STRING_length(name->d.dNSName),
|
ASN1_STRING_length(name->d.dNSName),
|
||||||
hostname)) {
|
hostname)) {
|
||||||
SPICE_DEBUG("alt name match=%s", ASN1_STRING_data(name->d.dNSName));
|
spice_debug("alt name match=%s", ASN1_STRING_get0_data(name->d.dNSName));
|
||||||
GENERAL_NAMES_free(subject_alt_names);
|
GENERAL_NAMES_free(subject_alt_names);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
} else if (name->type == GEN_IPADD) {
|
} else if (name->type == GEN_IPADD) {
|
||||||
int alt_ip_len = ASN1_STRING_length(name->d.iPAddress);
|
GInetAddress * ip;
|
||||||
|
const guint8 * ip_binary;
|
||||||
|
int alt_ip_len;
|
||||||
|
int ip_len;
|
||||||
|
|
||||||
found_dns_name = 1;
|
found_dns_name = 1;
|
||||||
if ((addr_len == alt_ip_len)&&
|
|
||||||
!memcmp(ASN1_STRING_data(name->d.iPAddress), &addr, addr_len)) {
|
ip = g_inet_address_new_from_string(hostname);
|
||||||
SPICE_DEBUG("alt name IP match=%s",
|
if (ip == NULL) {
|
||||||
inet_ntoa(*((struct in_addr*)ASN1_STRING_data(name->d.dNSName))));
|
spice_warning("Could not parse hostname: %s", hostname);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ip_len = g_inet_address_get_native_size(ip);
|
||||||
|
ip_binary = g_inet_address_to_bytes(ip);
|
||||||
|
|
||||||
|
alt_ip_len = ASN1_STRING_length(name->d.iPAddress);
|
||||||
|
|
||||||
|
if ((ip_len == alt_ip_len) &&
|
||||||
|
(memcmp(ASN1_STRING_get0_data(name->d.iPAddress), ip_binary, ip_len)) == 0) {
|
||||||
|
GInetAddress * alt_ip = NULL;
|
||||||
|
gchar * alt_ip_string = NULL;
|
||||||
|
|
||||||
|
alt_ip = g_inet_address_new_from_bytes(ASN1_STRING_get0_data(name->d.iPAddress),
|
||||||
|
g_inet_address_get_family(ip));
|
||||||
|
alt_ip_string = g_inet_address_to_string(alt_ip);
|
||||||
|
spice_debug("alt name IP match=%s", alt_ip_string);
|
||||||
|
|
||||||
|
g_free(alt_ip_string);
|
||||||
|
g_object_unref(alt_ip);
|
||||||
|
g_object_unref(ip);
|
||||||
GENERAL_NAMES_free(subject_alt_names);
|
GENERAL_NAMES_free(subject_alt_names);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
g_object_unref(ip);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GENERAL_NAMES_free(subject_alt_names);
|
GENERAL_NAMES_free(subject_alt_names);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (found_dns_name) {
|
if (found_dns_name) {
|
||||||
SPICE_DEBUG("warning: SubjectAltName mismatch");
|
spice_debug("warning: SubjectAltName mismatch");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,38 +262,41 @@ static int verify_hostname(X509* cert, const char *hostname)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_gnutls_hostname_compare((char*)ASN1_STRING_data(cn_asn1),
|
if (_gnutls_hostname_compare((const char*)ASN1_STRING_get0_data(cn_asn1),
|
||||||
ASN1_STRING_length(cn_asn1),
|
ASN1_STRING_length(cn_asn1),
|
||||||
hostname)) {
|
hostname)) {
|
||||||
SPICE_DEBUG("common name match=%s", (char*)ASN1_STRING_data(cn_asn1));
|
spice_debug("common name match=%s", (char*)ASN1_STRING_get0_data(cn_asn1));
|
||||||
cn_match = 1;
|
cn_match = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cn_match)
|
if (!cn_match) {
|
||||||
SPICE_DEBUG("warning: common name mismatch");
|
spice_debug("warning: common name mismatch");
|
||||||
|
}
|
||||||
|
|
||||||
return cn_match;
|
return cn_match;
|
||||||
}
|
}
|
||||||
|
|
||||||
X509_NAME* subject_to_x509_name(const char *subject, int *nentries)
|
static X509_NAME* subject_to_x509_name(const char *subject, int *nentries)
|
||||||
{
|
{
|
||||||
X509_NAME* in_subject;
|
X509_NAME* in_subject;
|
||||||
const char *p;
|
const char *p;
|
||||||
char *key, *val, *k, *v = NULL;
|
char *key, *val = NULL, *k, *v = NULL;
|
||||||
enum {
|
enum {
|
||||||
KEY,
|
KEY,
|
||||||
VALUE
|
VALUE
|
||||||
} state;
|
} state;
|
||||||
|
|
||||||
key = (char*)alloca(strlen(subject));
|
spice_return_val_if_fail(subject != NULL, NULL);
|
||||||
val = (char*)alloca(strlen(subject));
|
spice_return_val_if_fail(nentries != NULL, NULL);
|
||||||
|
|
||||||
|
key = (char*)alloca(strlen(subject)+1);
|
||||||
in_subject = X509_NAME_new();
|
in_subject = X509_NAME_new();
|
||||||
|
|
||||||
if (!in_subject || !key || !val) {
|
if (!in_subject || !key) {
|
||||||
SPICE_DEBUG("failed to allocate");
|
spice_debug("failed to allocate");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -288,7 +309,7 @@ X509_NAME* subject_to_x509_name(const char *subject, int *nentries)
|
|||||||
if (*p == '\\') {
|
if (*p == '\\') {
|
||||||
++p;
|
++p;
|
||||||
if (*p != '\\' && *p != ',') {
|
if (*p != '\\' && *p != ',') {
|
||||||
SPICE_DEBUG("Invalid character after \\");
|
spice_debug("Invalid character after \\");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
escape = 1;
|
escape = 1;
|
||||||
@ -307,6 +328,7 @@ X509_NAME* subject_to_x509_name(const char *subject, int *nentries)
|
|||||||
} else if (*p == '=' && !escape) {
|
} else if (*p == '=' && !escape) {
|
||||||
state = VALUE;
|
state = VALUE;
|
||||||
*k = 0;
|
*k = 0;
|
||||||
|
val = k + 1;
|
||||||
v = val;
|
v = val;
|
||||||
} else
|
} else
|
||||||
*k++ = *p;
|
*k++ = *p;
|
||||||
@ -322,7 +344,7 @@ X509_NAME* subject_to_x509_name(const char *subject, int *nentries)
|
|||||||
MBSTRING_UTF8,
|
MBSTRING_UTF8,
|
||||||
(const unsigned char*)val,
|
(const unsigned char*)val,
|
||||||
-1, -1, 0)) {
|
-1, -1, 0)) {
|
||||||
SPICE_DEBUG("warning: failed to add entry %s=%s to X509_NAME",
|
spice_debug("warning: failed to add entry %s=%s to X509_NAME",
|
||||||
key, val);
|
key, val);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@ -349,89 +371,145 @@ fail:
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int verify_subject(X509* cert, SpiceOpenSSLVerify* verify)
|
static int verify_subject(X509* cert, SpiceOpenSSLVerify* verify)
|
||||||
{
|
{
|
||||||
X509_NAME *cert_subject = NULL;
|
X509_NAME *cert_subject = NULL;
|
||||||
|
X509_NAME* in_subject;
|
||||||
int ret;
|
int ret;
|
||||||
int in_entries;
|
int in_entries;
|
||||||
|
|
||||||
if (!cert) {
|
if (!cert) {
|
||||||
SPICE_DEBUG("warning: no cert!");
|
spice_debug("warning: no cert!");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
cert_subject = X509_get_subject_name(cert);
|
cert_subject = X509_get_subject_name(cert);
|
||||||
if (!cert_subject) {
|
if (!cert_subject) {
|
||||||
SPICE_DEBUG("warning: reading certificate subject failed");
|
spice_debug("warning: reading certificate subject failed");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!verify->in_subject) {
|
in_subject = subject_to_x509_name(verify->subject, &in_entries);
|
||||||
verify->in_subject = subject_to_x509_name(verify->subject, &in_entries);
|
if (!in_subject) {
|
||||||
if (!verify->in_subject) {
|
spice_debug("warning: no in_subject!");
|
||||||
SPICE_DEBUG("warning: no in_subject!");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* Note: this check is redundant with the pre-condition in X509_NAME_cmp */
|
/* Note: this check is redundant with the pre-condition in X509_NAME_cmp */
|
||||||
if (X509_NAME_entry_count(cert_subject) != in_entries) {
|
if (X509_NAME_entry_count(cert_subject) != in_entries) {
|
||||||
SPICE_DEBUG("subject mismatch: #entries cert=%d, input=%d",
|
spice_debug("subject mismatch: #entries cert=%d, input=%d",
|
||||||
X509_NAME_entry_count(cert_subject), in_entries);
|
X509_NAME_entry_count(cert_subject), in_entries);
|
||||||
|
X509_NAME_free(in_subject);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = X509_NAME_cmp(cert_subject, verify->in_subject);
|
ret = X509_NAME_cmp(cert_subject, in_subject);
|
||||||
|
|
||||||
if (ret == 0)
|
if (ret == 0) {
|
||||||
SPICE_DEBUG("subjects match");
|
spice_debug("subjects match");
|
||||||
else
|
} else {
|
||||||
SPICE_DEBUG("subjects mismatch");
|
char *p;
|
||||||
|
spice_debug("subjects mismatch");
|
||||||
|
|
||||||
|
p = X509_NAME_oneline(cert_subject, NULL, 0);
|
||||||
|
spice_debug("cert_subject: %s", p);
|
||||||
|
free(p);
|
||||||
|
|
||||||
|
p = X509_NAME_oneline(in_subject, NULL, 0);
|
||||||
|
spice_debug("in_subject: %s", p);
|
||||||
|
free(p);
|
||||||
|
}
|
||||||
|
X509_NAME_free(in_subject);
|
||||||
|
|
||||||
return !ret;
|
return !ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int openssl_verify(int preverify_ok, X509_STORE_CTX *ctx)
|
static int openssl_verify(int preverify_ok, X509_STORE_CTX *ctx)
|
||||||
{
|
{
|
||||||
int depth;
|
int depth, err;
|
||||||
SpiceOpenSSLVerify *v;
|
SpiceOpenSSLVerify *v;
|
||||||
SSL *ssl;
|
SSL *ssl;
|
||||||
X509* cert;
|
X509* cert;
|
||||||
|
char buf[256];
|
||||||
|
unsigned int failed_verifications;
|
||||||
|
|
||||||
ssl = (SSL*)X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
|
ssl = (SSL*)X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
|
||||||
v = (SpiceOpenSSLVerify*)SSL_get_app_data(ssl);
|
v = (SpiceOpenSSLVerify*)SSL_get_app_data(ssl);
|
||||||
|
|
||||||
|
cert = X509_STORE_CTX_get_current_cert(ctx);
|
||||||
|
X509_NAME_oneline(X509_get_subject_name(cert), buf, 256);
|
||||||
depth = X509_STORE_CTX_get_error_depth(ctx);
|
depth = X509_STORE_CTX_get_error_depth(ctx);
|
||||||
|
err = X509_STORE_CTX_get_error(ctx);
|
||||||
if (depth > 0) {
|
if (depth > 0) {
|
||||||
if (!preverify_ok) {
|
if (!preverify_ok) {
|
||||||
SPICE_DEBUG("openssl verify failed at depth=%d", depth);
|
spice_warning("Error in certificate chain verification: %s (num=%d:depth%d:%s)",
|
||||||
|
X509_verify_cert_error_string(err), err, depth, buf);
|
||||||
v->all_preverify_ok = 0;
|
v->all_preverify_ok = 0;
|
||||||
|
|
||||||
|
/* if certificate verification failed, we can still authorize the server */
|
||||||
|
/* if its public key matches the one we hold in the peer_connect_options. */
|
||||||
|
if (err == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN &&
|
||||||
|
v->verifyop & SPICE_SSL_VERIFY_OP_PUBKEY)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (err == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN)
|
||||||
|
spice_debug("server certificate not being signed by the provided CA");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
} else
|
} else
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* depth == 0 */
|
/* depth == 0 */
|
||||||
cert = X509_STORE_CTX_get_current_cert(ctx);
|
|
||||||
if (!cert) {
|
if (!cert) {
|
||||||
SPICE_DEBUG("failed to get server certificate");
|
spice_debug("failed to get server certificate");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (v->verifyop & SPICE_SSL_VERIFY_OP_PUBKEY &&
|
failed_verifications = 0;
|
||||||
verify_pubkey(cert, v->pubkey, v->pubkey_size))
|
if (v->verifyop & SPICE_SSL_VERIFY_OP_PUBKEY) {
|
||||||
|
if (verify_pubkey(cert, v->pubkey, v->pubkey_size))
|
||||||
return 1;
|
return 1;
|
||||||
|
else
|
||||||
|
failed_verifications |= SPICE_SSL_VERIFY_OP_PUBKEY;
|
||||||
|
}
|
||||||
|
|
||||||
if (!v->all_preverify_ok || !preverify_ok)
|
if (!preverify_ok) {
|
||||||
|
err = X509_STORE_CTX_get_error(ctx);
|
||||||
|
depth = X509_STORE_CTX_get_error_depth(ctx);
|
||||||
|
spice_warning("Error in server certificate verification: %s (num=%d:depth%d:%s)",
|
||||||
|
X509_verify_cert_error_string(err), err, depth, buf);
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
if (!v->all_preverify_ok) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (v->verifyop & SPICE_SSL_VERIFY_OP_HOSTNAME &&
|
if (v->verifyop & SPICE_SSL_VERIFY_OP_SUBJECT) {
|
||||||
verify_hostname(cert, v->hostname))
|
if (verify_subject(cert, v))
|
||||||
return 1;
|
return 1;
|
||||||
|
else
|
||||||
|
failed_verifications |= SPICE_SSL_VERIFY_OP_SUBJECT;
|
||||||
|
} else if (v->verifyop & SPICE_SSL_VERIFY_OP_HOSTNAME) {
|
||||||
|
if (verify_hostname(cert, v->hostname))
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
failed_verifications |= SPICE_SSL_VERIFY_OP_HOSTNAME;
|
||||||
|
}
|
||||||
|
|
||||||
if (v->verifyop & SPICE_SSL_VERIFY_OP_SUBJECT &&
|
/* If we reach this code, this means all the tests failed, thus
|
||||||
verify_subject(cert, v))
|
* verification failed
|
||||||
return 1;
|
*/
|
||||||
|
if (failed_verifications & SPICE_SSL_VERIFY_OP_PUBKEY)
|
||||||
|
spice_warning("ssl: pubkey verification failed");
|
||||||
|
|
||||||
|
if (failed_verifications & SPICE_SSL_VERIFY_OP_HOSTNAME)
|
||||||
|
spice_warning("ssl: hostname '%s' verification failed", v->hostname);
|
||||||
|
|
||||||
|
if (failed_verifications & SPICE_SSL_VERIFY_OP_SUBJECT)
|
||||||
|
spice_warning("ssl: subject '%s' verification failed", v->subject);
|
||||||
|
|
||||||
|
spice_warning("ssl: verification failed");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -473,9 +551,6 @@ void spice_openssl_verify_free(SpiceOpenSSLVerify* verify)
|
|||||||
free(verify->subject);
|
free(verify->subject);
|
||||||
free(verify->hostname);
|
free(verify->hostname);
|
||||||
|
|
||||||
if (verify->in_subject)
|
|
||||||
X509_NAME_free(verify->in_subject);
|
|
||||||
|
|
||||||
if (verify->ssl)
|
if (verify->ssl)
|
||||||
SSL_set_app_data(verify->ssl, NULL);
|
SSL_set_app_data(verify->ssl, NULL);
|
||||||
free(verify);
|
free(verify);
|
||||||
|
|||||||
@ -16,12 +16,16 @@
|
|||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef SSL_VERIFY_H
|
#ifndef H_SPICE_COMMON_SSL_VERIFY
|
||||||
#define SSL_VERIFY_H
|
#define H_SPICE_COMMON_SSL_VERIFY
|
||||||
|
|
||||||
#if defined(WIN32) && !defined(__MINGW32__)
|
#if defined(WIN32)
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <wincrypt.h>
|
#include <wincrypt.h>
|
||||||
|
#ifdef X509_NAME
|
||||||
|
/* wincrypt.h has already a different define... */
|
||||||
|
#undef X509_NAME
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <openssl/rsa.h>
|
#include <openssl/rsa.h>
|
||||||
@ -29,12 +33,11 @@
|
|||||||
#include <openssl/x509.h>
|
#include <openssl/x509.h>
|
||||||
#include <openssl/ssl.h>
|
#include <openssl/ssl.h>
|
||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
#undef X509_NAME
|
|
||||||
#include <openssl/x509v3.h>
|
#include <openssl/x509v3.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#include <spice/macros.h>
|
||||||
extern "C" {
|
|
||||||
#endif
|
SPICE_BEGIN_DECLS
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SPICE_SSL_VERIFY_OP_NONE = 0,
|
SPICE_SSL_VERIFY_OP_NONE = 0,
|
||||||
@ -51,7 +54,6 @@ typedef struct {
|
|||||||
char *pubkey;
|
char *pubkey;
|
||||||
size_t pubkey_size;
|
size_t pubkey_size;
|
||||||
char *subject;
|
char *subject;
|
||||||
X509_NAME *in_subject;
|
|
||||||
} SpiceOpenSSLVerify;
|
} SpiceOpenSSLVerify;
|
||||||
|
|
||||||
SpiceOpenSSLVerify* spice_openssl_verify_new(SSL *ssl, SPICE_SSL_VERIFY_OP verifyop,
|
SpiceOpenSSLVerify* spice_openssl_verify_new(SSL *ssl, SPICE_SSL_VERIFY_OP verifyop,
|
||||||
@ -60,7 +62,6 @@ SpiceOpenSSLVerify* spice_openssl_verify_new(SSL *ssl, SPICE_SSL_VERIFY_OP verif
|
|||||||
const char *subject);
|
const char *subject);
|
||||||
void spice_openssl_verify_free(SpiceOpenSSLVerify* verify);
|
void spice_openssl_verify_free(SpiceOpenSSLVerify* verify);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
SPICE_END_DECLS
|
||||||
}
|
|
||||||
#endif // __cplusplus
|
#endif // H_SPICE_COMMON_SSL_VERIFY
|
||||||
#endif // SSL_VERIFY_H
|
|
||||||
|
|||||||
@ -15,21 +15,13 @@
|
|||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#ifdef __MINGW32__
|
#ifdef __MINGW32__
|
||||||
#undef HAVE_STDLIB_H
|
#undef HAVE_STDLIB_H
|
||||||
#endif
|
#endif
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef SPICE_CANVAS_INTERNAL
|
|
||||||
#error "This file shouldn't be compiled directly"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include "sw_canvas.h"
|
#include "sw_canvas.h"
|
||||||
#define CANVAS_USE_PIXMAN
|
|
||||||
#define CANVAS_SINGLE_INSTANCE
|
|
||||||
#include "canvas_base.c"
|
#include "canvas_base.c"
|
||||||
#include "rect.h"
|
#include "rect.h"
|
||||||
#include "region.h"
|
#include "region.h"
|
||||||
@ -83,15 +75,33 @@ static pixman_image_t *canvas_get_pixman_brush(SwCanvas *canvas,
|
|||||||
case SPICE_BRUSH_TYPE_NONE:
|
case SPICE_BRUSH_TYPE_NONE:
|
||||||
return NULL;
|
return NULL;
|
||||||
default:
|
default:
|
||||||
CANVAS_ERROR("invalid brush type");
|
spice_warn_if_reached();
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static pixman_image_t *get_image(SpiceCanvas *canvas)
|
static pixman_image_t *get_image(SpiceCanvas *canvas, int force_opaque)
|
||||||
{
|
{
|
||||||
SwCanvas *sw_canvas = (SwCanvas *)canvas;
|
SwCanvas *sw_canvas = (SwCanvas *)canvas;
|
||||||
|
pixman_format_code_t format;
|
||||||
|
|
||||||
|
spice_pixman_image_get_format(sw_canvas->image, &format);
|
||||||
|
if (force_opaque && PIXMAN_FORMAT_A (format) != 0) {
|
||||||
|
uint32_t *data;
|
||||||
|
int stride;
|
||||||
|
int width, height;
|
||||||
|
|
||||||
|
/* Remove alpha bits from format */
|
||||||
|
format = (pixman_format_code_t)(((uint32_t)format) & ~(0xf << 12));
|
||||||
|
data = pixman_image_get_data(sw_canvas->image);
|
||||||
|
stride = pixman_image_get_stride(sw_canvas->image);
|
||||||
|
width = pixman_image_get_width(sw_canvas->image);
|
||||||
|
height = pixman_image_get_height(sw_canvas->image);
|
||||||
|
return pixman_image_create_bits(format, width, height, data, stride);
|
||||||
|
} else {
|
||||||
pixman_image_ref(sw_canvas->image);
|
pixman_image_ref(sw_canvas->image);
|
||||||
|
}
|
||||||
|
|
||||||
return sw_canvas->image;
|
return sw_canvas->image;
|
||||||
}
|
}
|
||||||
@ -343,7 +353,7 @@ static void clear_dest_alpha(pixman_image_t *dest,
|
|||||||
}
|
}
|
||||||
|
|
||||||
stride = pixman_image_get_stride(dest);
|
stride = pixman_image_get_stride(dest);
|
||||||
data = (uint32_t *) (
|
data = SPICE_ALIGNED_CAST(uint32_t *,
|
||||||
(uint8_t *)pixman_image_get_data(dest) + y * stride + 4 * x);
|
(uint8_t *)pixman_image_get_data(dest) + y * stride + 4 * x);
|
||||||
|
|
||||||
if ((*data & 0xff000000U) == 0xff000000U) {
|
if ((*data & 0xff000000U) == 0xff000000U) {
|
||||||
@ -477,7 +487,7 @@ static void __scale_image(SpiceCanvas *spice_canvas,
|
|||||||
|
|
||||||
pixman_image_set_transform(src, &transform);
|
pixman_image_set_transform(src, &transform);
|
||||||
pixman_image_set_repeat(src, PIXMAN_REPEAT_NONE);
|
pixman_image_set_repeat(src, PIXMAN_REPEAT_NONE);
|
||||||
ASSERT(scale_mode == SPICE_IMAGE_SCALE_MODE_INTERPOLATE ||
|
spice_return_if_fail(scale_mode == SPICE_IMAGE_SCALE_MODE_INTERPOLATE ||
|
||||||
scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST);
|
scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST);
|
||||||
pixman_image_set_filter(src,
|
pixman_image_set_filter(src,
|
||||||
(scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST) ?
|
(scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST) ?
|
||||||
@ -539,11 +549,13 @@ static void __scale_image_rop(SpiceCanvas *spice_canvas,
|
|||||||
pixman_box32_t *rects;
|
pixman_box32_t *rects;
|
||||||
int n_rects, i;
|
int n_rects, i;
|
||||||
pixman_fixed_t fsx, fsy;
|
pixman_fixed_t fsx, fsy;
|
||||||
|
pixman_format_code_t format;
|
||||||
|
|
||||||
fsx = ((pixman_fixed_48_16_t) src_width * 65536) / dest_width;
|
fsx = ((pixman_fixed_48_16_t) src_width * 65536) / dest_width;
|
||||||
fsy = ((pixman_fixed_48_16_t) src_height * 65536) / dest_height;
|
fsy = ((pixman_fixed_48_16_t) src_height * 65536) / dest_height;
|
||||||
|
|
||||||
scaled = pixman_image_create_bits(spice_pixman_image_get_format(src),
|
spice_return_if_fail(spice_pixman_image_get_format(src, &format));
|
||||||
|
scaled = pixman_image_create_bits(format,
|
||||||
dest_width,
|
dest_width,
|
||||||
dest_height,
|
dest_height,
|
||||||
NULL, 0);
|
NULL, 0);
|
||||||
@ -558,7 +570,7 @@ static void __scale_image_rop(SpiceCanvas *spice_canvas,
|
|||||||
|
|
||||||
pixman_image_set_transform(src, &transform);
|
pixman_image_set_transform(src, &transform);
|
||||||
pixman_image_set_repeat(src, PIXMAN_REPEAT_NONE);
|
pixman_image_set_repeat(src, PIXMAN_REPEAT_NONE);
|
||||||
ASSERT(scale_mode == SPICE_IMAGE_SCALE_MODE_INTERPOLATE ||
|
spice_return_if_fail(scale_mode == SPICE_IMAGE_SCALE_MODE_INTERPOLATE ||
|
||||||
scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST);
|
scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST);
|
||||||
pixman_image_set_filter(src,
|
pixman_image_set_filter(src,
|
||||||
(scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST) ?
|
(scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST) ?
|
||||||
@ -659,7 +671,7 @@ static void __blend_image(SpiceCanvas *spice_canvas,
|
|||||||
|
|
||||||
mask = NULL;
|
mask = NULL;
|
||||||
if (overall_alpha != 0xff) {
|
if (overall_alpha != 0xff) {
|
||||||
pixman_color_t color = { 0 };
|
pixman_color_t color = { 0, 0, 0, 0 };
|
||||||
color.alpha = overall_alpha * 0x101;
|
color.alpha = overall_alpha * 0x101;
|
||||||
mask = pixman_image_create_solid_fill(&color);
|
mask = pixman_image_create_solid_fill(&color);
|
||||||
}
|
}
|
||||||
@ -752,14 +764,14 @@ static void __blend_scale_image(SpiceCanvas *spice_canvas,
|
|||||||
|
|
||||||
mask = NULL;
|
mask = NULL;
|
||||||
if (overall_alpha != 0xff) {
|
if (overall_alpha != 0xff) {
|
||||||
pixman_color_t color = { 0 };
|
pixman_color_t color = { 0, 0, 0, 0 };
|
||||||
color.alpha = overall_alpha * 0x101;
|
color.alpha = overall_alpha * 0x101;
|
||||||
mask = pixman_image_create_solid_fill(&color);
|
mask = pixman_image_create_solid_fill(&color);
|
||||||
}
|
}
|
||||||
|
|
||||||
pixman_image_set_transform(src, &transform);
|
pixman_image_set_transform(src, &transform);
|
||||||
pixman_image_set_repeat(src, PIXMAN_REPEAT_NONE);
|
pixman_image_set_repeat(src, PIXMAN_REPEAT_NONE);
|
||||||
ASSERT(scale_mode == SPICE_IMAGE_SCALE_MODE_INTERPOLATE ||
|
spice_return_if_fail(scale_mode == SPICE_IMAGE_SCALE_MODE_INTERPOLATE ||
|
||||||
scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST);
|
scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST);
|
||||||
pixman_image_set_filter(src,
|
pixman_image_set_filter(src,
|
||||||
(scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST) ?
|
(scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST) ?
|
||||||
@ -895,11 +907,13 @@ static void __colorkey_scale_image(SpiceCanvas *spice_canvas,
|
|||||||
pixman_box32_t *rects;
|
pixman_box32_t *rects;
|
||||||
int n_rects, i;
|
int n_rects, i;
|
||||||
pixman_fixed_t fsx, fsy;
|
pixman_fixed_t fsx, fsy;
|
||||||
|
pixman_format_code_t format;
|
||||||
|
|
||||||
fsx = ((pixman_fixed_48_16_t) src_width * 65536) / dest_width;
|
fsx = ((pixman_fixed_48_16_t) src_width * 65536) / dest_width;
|
||||||
fsy = ((pixman_fixed_48_16_t) src_height * 65536) / dest_height;
|
fsy = ((pixman_fixed_48_16_t) src_height * 65536) / dest_height;
|
||||||
|
|
||||||
scaled = pixman_image_create_bits(spice_pixman_image_get_format (src),
|
spice_return_if_fail(spice_pixman_image_get_format(src, &format));
|
||||||
|
scaled = pixman_image_create_bits(format,
|
||||||
dest_width,
|
dest_width,
|
||||||
dest_height,
|
dest_height,
|
||||||
NULL, 0);
|
NULL, 0);
|
||||||
@ -977,9 +991,6 @@ static void colorkey_scale_image_from_surface(SpiceCanvas *spice_canvas,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void canvas_put_image(SpiceCanvas *spice_canvas,
|
static void canvas_put_image(SpiceCanvas *spice_canvas,
|
||||||
#ifdef WIN32
|
|
||||||
HDC dc,
|
|
||||||
#endif
|
|
||||||
const SpiceRect *dest, const uint8_t *src_data,
|
const SpiceRect *dest, const uint8_t *src_data,
|
||||||
uint32_t src_width, uint32_t src_height, int src_stride,
|
uint32_t src_width, uint32_t src_height, int src_stride,
|
||||||
const QRegion *clip)
|
const QRegion *clip)
|
||||||
@ -994,7 +1005,7 @@ static void canvas_put_image(SpiceCanvas *spice_canvas,
|
|||||||
src = pixman_image_create_bits(PIXMAN_x8r8g8b8,
|
src = pixman_image_create_bits(PIXMAN_x8r8g8b8,
|
||||||
src_width,
|
src_width,
|
||||||
src_height,
|
src_height,
|
||||||
(uint32_t*)src_data,
|
SPICE_ALIGNED_CAST(uint32_t*,src_data),
|
||||||
src_stride);
|
src_stride);
|
||||||
|
|
||||||
|
|
||||||
@ -1042,7 +1053,7 @@ static void canvas_draw_text(SpiceCanvas *spice_canvas, SpiceRect *bbox,
|
|||||||
pixman_region32_t dest_region;
|
pixman_region32_t dest_region;
|
||||||
pixman_image_t *str_mask, *brush;
|
pixman_image_t *str_mask, *brush;
|
||||||
SpiceString *str;
|
SpiceString *str;
|
||||||
SpicePoint pos;
|
SpicePoint pos = { 0, 0 };
|
||||||
int depth;
|
int depth;
|
||||||
|
|
||||||
pixman_region32_init_rect(&dest_region,
|
pixman_region32_init_rect(&dest_region,
|
||||||
@ -1064,7 +1075,7 @@ static void canvas_draw_text(SpiceCanvas *spice_canvas, SpiceRect *bbox,
|
|||||||
|
|
||||||
/* Nothing else makes sense for text and we should deprecate it
|
/* Nothing else makes sense for text and we should deprecate it
|
||||||
* and actually it means OVER really */
|
* and actually it means OVER really */
|
||||||
ASSERT(text->fore_mode == SPICE_ROPD_OP_PUT);
|
spice_return_if_fail(text->fore_mode == SPICE_ROPD_OP_PUT);
|
||||||
|
|
||||||
pixman_region32_init_rect(&back_region,
|
pixman_region32_init_rect(&back_region,
|
||||||
text->back_area.left,
|
text->back_area.left,
|
||||||
@ -1087,10 +1098,10 @@ static void canvas_draw_text(SpiceCanvas *spice_canvas, SpiceRect *bbox,
|
|||||||
} else if (str->flags & SPICE_STRING_FLAGS_RASTER_A4) {
|
} else if (str->flags & SPICE_STRING_FLAGS_RASTER_A4) {
|
||||||
depth = 4;
|
depth = 4;
|
||||||
} else if (str->flags & SPICE_STRING_FLAGS_RASTER_A8) {
|
} else if (str->flags & SPICE_STRING_FLAGS_RASTER_A8) {
|
||||||
WARN("untested path A8 glyphs");
|
spice_warning("untested path A8 glyphs");
|
||||||
depth = 8;
|
depth = 8;
|
||||||
} else {
|
} else {
|
||||||
WARN("unsupported path vector glyphs");
|
spice_warning("unsupported path vector glyphs");
|
||||||
pixman_region32_fini (&dest_region);
|
pixman_region32_fini (&dest_region);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1133,7 +1144,7 @@ static void canvas_read_bits(SpiceCanvas *spice_canvas, uint8_t *dest,
|
|||||||
uint8_t *dest_end;
|
uint8_t *dest_end;
|
||||||
int bpp;
|
int bpp;
|
||||||
|
|
||||||
ASSERT(canvas && area);
|
spice_return_if_fail(canvas && area);
|
||||||
|
|
||||||
surface = canvas->image;
|
surface = canvas->image;
|
||||||
|
|
||||||
@ -1170,28 +1181,21 @@ static void canvas_destroy(SpiceCanvas *spice_canvas)
|
|||||||
free(canvas);
|
free(canvas);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int need_init = 1;
|
|
||||||
static SpiceCanvasOps sw_canvas_ops;
|
static SpiceCanvasOps sw_canvas_ops;
|
||||||
|
|
||||||
static SpiceCanvas *canvas_create_common(pixman_image_t *image,
|
static SpiceCanvas *canvas_create_common(pixman_image_t *image,
|
||||||
uint32_t format
|
uint32_t format,
|
||||||
|
SpiceImageCache *bits_cache,
|
||||||
#ifdef SW_CANVAS_CACHE
|
#ifdef SW_CANVAS_CACHE
|
||||||
, SpiceImageCache *bits_cache
|
SpicePaletteCache *palette_cache,
|
||||||
, SpicePaletteCache *palette_cache
|
|
||||||
#elif defined(SW_CANVAS_IMAGE_CACHE)
|
|
||||||
, SpiceImageCache *bits_cache
|
|
||||||
#endif
|
#endif
|
||||||
, SpiceImageSurfaces *surfaces
|
SpiceImageSurfaces *surfaces,
|
||||||
, SpiceGlzDecoder *glz_decoder
|
SpiceGlzDecoder *glz_decoder,
|
||||||
, SpiceJpegDecoder *jpeg_decoder
|
SpiceJpegDecoder *jpeg_decoder,
|
||||||
, SpiceZlibDecoder *zlib_decoder
|
SpiceZlibDecoder *zlib_decoder)
|
||||||
)
|
|
||||||
{
|
{
|
||||||
SwCanvas *canvas;
|
SwCanvas *canvas;
|
||||||
|
|
||||||
if (need_init) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
spice_pixman_image_set_format(image,
|
spice_pixman_image_set_format(image,
|
||||||
spice_surface_format_to_pixman(format));
|
spice_surface_format_to_pixman(format));
|
||||||
|
|
||||||
@ -1199,18 +1203,15 @@ static SpiceCanvas *canvas_create_common(pixman_image_t *image,
|
|||||||
canvas_base_init(&canvas->base, &sw_canvas_ops,
|
canvas_base_init(&canvas->base, &sw_canvas_ops,
|
||||||
pixman_image_get_width(image),
|
pixman_image_get_width(image),
|
||||||
pixman_image_get_height(image),
|
pixman_image_get_height(image),
|
||||||
format
|
format,
|
||||||
|
bits_cache,
|
||||||
#ifdef SW_CANVAS_CACHE
|
#ifdef SW_CANVAS_CACHE
|
||||||
, bits_cache
|
palette_cache,
|
||||||
, palette_cache
|
|
||||||
#elif defined(SW_CANVAS_IMAGE_CACHE)
|
|
||||||
, bits_cache
|
|
||||||
#endif
|
#endif
|
||||||
, surfaces
|
surfaces,
|
||||||
, glz_decoder
|
glz_decoder,
|
||||||
, jpeg_decoder
|
jpeg_decoder,
|
||||||
, zlib_decoder
|
zlib_decoder);
|
||||||
);
|
|
||||||
canvas->private_data = NULL;
|
canvas->private_data = NULL;
|
||||||
canvas->private_data_size = 0;
|
canvas->private_data_size = 0;
|
||||||
|
|
||||||
@ -1219,78 +1220,37 @@ static SpiceCanvas *canvas_create_common(pixman_image_t *image,
|
|||||||
return (SpiceCanvas *)canvas;
|
return (SpiceCanvas *)canvas;
|
||||||
}
|
}
|
||||||
|
|
||||||
SpiceCanvas *canvas_create(int width, int height, uint32_t format
|
|
||||||
#ifdef SW_CANVAS_CACHE
|
|
||||||
, SpiceImageCache *bits_cache
|
|
||||||
, SpicePaletteCache *palette_cache
|
|
||||||
#elif defined(SW_CANVAS_IMAGE_CACHE)
|
|
||||||
, SpiceImageCache *bits_cache
|
|
||||||
#endif
|
|
||||||
, SpiceImageSurfaces *surfaces
|
|
||||||
, SpiceGlzDecoder *glz_decoder
|
|
||||||
, SpiceJpegDecoder *jpeg_decoder
|
|
||||||
, SpiceZlibDecoder *zlib_decoder
|
|
||||||
)
|
|
||||||
{
|
|
||||||
pixman_image_t *image;
|
|
||||||
|
|
||||||
image = pixman_image_create_bits(spice_surface_format_to_pixman (format),
|
|
||||||
width, height, NULL, 0);
|
|
||||||
|
|
||||||
return canvas_create_common(image, format
|
|
||||||
#ifdef SW_CANVAS_CACHE
|
|
||||||
, bits_cache
|
|
||||||
, palette_cache
|
|
||||||
#elif defined(SW_CANVAS_IMAGE_CACHE)
|
|
||||||
, bits_cache
|
|
||||||
#endif
|
|
||||||
, surfaces
|
|
||||||
, glz_decoder
|
|
||||||
, jpeg_decoder
|
|
||||||
, zlib_decoder
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
SpiceCanvas *canvas_create_for_data(int width, int height, uint32_t format,
|
SpiceCanvas *canvas_create_for_data(int width, int height, uint32_t format,
|
||||||
uint8_t *data, int stride
|
uint8_t *data, int stride,
|
||||||
|
SpiceImageCache *bits_cache,
|
||||||
#ifdef SW_CANVAS_CACHE
|
#ifdef SW_CANVAS_CACHE
|
||||||
, SpiceImageCache *bits_cache
|
SpicePaletteCache *palette_cache,
|
||||||
, SpicePaletteCache *palette_cache
|
|
||||||
#elif defined(SW_CANVAS_IMAGE_CACHE)
|
|
||||||
, SpiceImageCache *bits_cache
|
|
||||||
#endif
|
#endif
|
||||||
, SpiceImageSurfaces *surfaces
|
SpiceImageSurfaces *surfaces,
|
||||||
, SpiceGlzDecoder *glz_decoder
|
SpiceGlzDecoder *glz_decoder,
|
||||||
, SpiceJpegDecoder *jpeg_decoder
|
SpiceJpegDecoder *jpeg_decoder,
|
||||||
, SpiceZlibDecoder *zlib_decoder
|
SpiceZlibDecoder *zlib_decoder)
|
||||||
)
|
|
||||||
{
|
{
|
||||||
pixman_image_t *image;
|
pixman_image_t *image;
|
||||||
|
|
||||||
image = pixman_image_create_bits(spice_surface_format_to_pixman(format),
|
image = pixman_image_create_bits(spice_surface_format_to_pixman(format),
|
||||||
width, height, (uint32_t *)data, stride);
|
width, height,
|
||||||
|
SPICE_ALIGNED_CAST(uint32_t *,data),
|
||||||
|
stride);
|
||||||
|
|
||||||
return canvas_create_common(image, format
|
return canvas_create_common(image, format,
|
||||||
|
bits_cache,
|
||||||
#ifdef SW_CANVAS_CACHE
|
#ifdef SW_CANVAS_CACHE
|
||||||
, bits_cache
|
palette_cache,
|
||||||
, palette_cache
|
|
||||||
#elif defined(SW_CANVAS_IMAGE_CACHE)
|
|
||||||
, bits_cache
|
|
||||||
#endif
|
#endif
|
||||||
, surfaces
|
surfaces,
|
||||||
, glz_decoder
|
glz_decoder,
|
||||||
, jpeg_decoder
|
jpeg_decoder,
|
||||||
, zlib_decoder
|
zlib_decoder);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void sw_canvas_init(void) //unsafe global function
|
SPICE_CONSTRUCTOR_FUNC(sw_canvas_global_init) //unsafe global function
|
||||||
{
|
{
|
||||||
if (!need_init) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
need_init = 0;
|
|
||||||
|
|
||||||
canvas_base_init_ops(&sw_canvas_ops);
|
canvas_base_init_ops(&sw_canvas_ops);
|
||||||
sw_canvas_ops.draw_text = canvas_draw_text;
|
sw_canvas_ops.draw_text = canvas_draw_text;
|
||||||
sw_canvas_ops.put_image = canvas_put_image;
|
sw_canvas_ops.put_image = canvas_put_image;
|
||||||
@ -1323,5 +1283,4 @@ void sw_canvas_init(void) //unsafe global function
|
|||||||
sw_canvas_ops.colorkey_scale_image_from_surface = colorkey_scale_image_from_surface;
|
sw_canvas_ops.colorkey_scale_image_from_surface = colorkey_scale_image_from_surface;
|
||||||
sw_canvas_ops.copy_region = copy_region;
|
sw_canvas_ops.copy_region = copy_region;
|
||||||
sw_canvas_ops.get_image = get_image;
|
sw_canvas_ops.get_image = get_image;
|
||||||
rop3_init();
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,43 +16,23 @@
|
|||||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _H__CANVAS
|
#ifndef H_SPICE_COMMON_SW_CANVAS
|
||||||
#define _H__CANVAS
|
#define H_SPICE_COMMON_SW_CANVAS
|
||||||
|
|
||||||
#ifndef SPICE_CANVAS_INTERNAL
|
|
||||||
#error "This header shouldn't be included directly"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <spice/macros.h>
|
||||||
|
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
#include "pixman_utils.h"
|
#include "pixman_utils.h"
|
||||||
#include "canvas_base.h"
|
#include "canvas_base.h"
|
||||||
#include "region.h"
|
#include "region.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
SPICE_BEGIN_DECLS
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
SpiceCanvas *canvas_create(int width, int height, uint32_t format
|
|
||||||
#ifdef SW_CANVAS_CACHE
|
|
||||||
, SpiceImageCache *bits_cache
|
|
||||||
, SpicePaletteCache *palette_cache
|
|
||||||
#elif defined(SW_CANVAS_IMAGE_CACHE)
|
|
||||||
, SpiceImageCache *bits_cache
|
|
||||||
#endif
|
|
||||||
, SpiceImageSurfaces *surfaces
|
|
||||||
, SpiceGlzDecoder *glz_decoder
|
|
||||||
, SpiceJpegDecoder *jpeg_decoder
|
|
||||||
, SpiceZlibDecoder *zlib_decoder
|
|
||||||
);
|
|
||||||
|
|
||||||
SpiceCanvas *canvas_create_for_data(int width, int height, uint32_t format, uint8_t *data, int stride
|
SpiceCanvas *canvas_create_for_data(int width, int height, uint32_t format, uint8_t *data, int stride
|
||||||
|
, SpiceImageCache *bits_cache
|
||||||
#ifdef SW_CANVAS_CACHE
|
#ifdef SW_CANVAS_CACHE
|
||||||
, SpiceImageCache *bits_cache
|
|
||||||
, SpicePaletteCache *palette_cache
|
, SpicePaletteCache *palette_cache
|
||||||
#elif defined(SW_CANVAS_IMAGE_CACHE)
|
|
||||||
, SpiceImageCache *bits_cache
|
|
||||||
#endif
|
#endif
|
||||||
, SpiceImageSurfaces *surfaces
|
, SpiceImageSurfaces *surfaces
|
||||||
, SpiceGlzDecoder *glz_decoder
|
, SpiceGlzDecoder *glz_decoder
|
||||||
@ -61,10 +41,6 @@ SpiceCanvas *canvas_create_for_data(int width, int height, uint32_t format, uint
|
|||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
void sw_canvas_init(void);
|
SPICE_END_DECLS
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
78
common/udev.c
Normal file
78
common/udev.c
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
Copyright (C) 2023 Intel Corporation.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
#include "udev.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_UDEV
|
||||||
|
#include <libudev.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
GpuVendor spice_udev_detect_gpu(int gpu_vendor)
|
||||||
|
{
|
||||||
|
struct udev *udev;
|
||||||
|
struct udev_device *drm_dev, *pci_dev;
|
||||||
|
struct udev_enumerate *udev_enum;
|
||||||
|
struct udev_list_entry *entry, *devices;
|
||||||
|
const char *path, *vendor_id;
|
||||||
|
GpuVendor vendor = VENDOR_GPU_NOTDETECTED;
|
||||||
|
|
||||||
|
udev = udev_new();
|
||||||
|
if (!udev) {
|
||||||
|
return VENDOR_GPU_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
udev_enum = udev_enumerate_new(udev);
|
||||||
|
if (udev_enum) {
|
||||||
|
udev_enumerate_add_match_subsystem(udev_enum, "drm");
|
||||||
|
udev_enumerate_add_match_sysname(udev_enum, "card[0-9]");
|
||||||
|
udev_enumerate_scan_devices(udev_enum);
|
||||||
|
devices = udev_enumerate_get_list_entry(udev_enum);
|
||||||
|
|
||||||
|
udev_list_entry_foreach(entry, devices) {
|
||||||
|
path = udev_list_entry_get_name(entry);
|
||||||
|
drm_dev = udev_device_new_from_syspath(udev, path);
|
||||||
|
if (!drm_dev) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
pci_dev = udev_device_get_parent_with_subsystem_devtype(drm_dev,
|
||||||
|
"pci", NULL);
|
||||||
|
if (pci_dev) {
|
||||||
|
vendor_id = udev_device_get_sysattr_value(pci_dev, "vendor");
|
||||||
|
if (vendor_id && strtol(vendor_id, NULL, 16) == gpu_vendor) {
|
||||||
|
vendor = VENDOR_GPU_DETECTED;
|
||||||
|
udev_device_unref(drm_dev);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
udev_device_unref(drm_dev);
|
||||||
|
}
|
||||||
|
udev_enumerate_unref(udev_enum);
|
||||||
|
}
|
||||||
|
udev_unref(udev);
|
||||||
|
|
||||||
|
return vendor;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
GpuVendor spice_udev_detect_gpu(int gpu_vendor)
|
||||||
|
{
|
||||||
|
return VENDOR_GPU_UNKNOWN;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
33
common/udev.h
Normal file
33
common/udev.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
Copyright (C) 2023 Intel Corporation.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <spice/macros.h>
|
||||||
|
|
||||||
|
#define INTEL_VENDOR_ID 0x8086
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
VENDOR_GPU_UNKNOWN,
|
||||||
|
VENDOR_GPU_DETECTED,
|
||||||
|
VENDOR_GPU_NOTDETECTED,
|
||||||
|
} GpuVendor;
|
||||||
|
|
||||||
|
SPICE_BEGIN_DECLS
|
||||||
|
|
||||||
|
GpuVendor spice_udev_detect_gpu(int gpu_vendor);
|
||||||
|
|
||||||
|
SPICE_END_DECLS
|
||||||
66
common/utils.c
Normal file
66
common/utils.c
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||||
|
/*
|
||||||
|
Copyright (C) 2010, 2011, 2018 Red Hat, Inc.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
/* These 2 functions come from
|
||||||
|
* libvirt-glib/libvirt-gconfig/libvirt-gconfig-helpers.c
|
||||||
|
* Copyright (C) 2010, 2011 Red Hat, Inc.
|
||||||
|
* LGPLv2.1+ licensed */
|
||||||
|
|
||||||
|
const char *
|
||||||
|
spice_genum_get_nick(GType enum_type, gint value)
|
||||||
|
{
|
||||||
|
GEnumClass *enum_class;
|
||||||
|
GEnumValue *enum_value;
|
||||||
|
|
||||||
|
g_return_val_if_fail(G_TYPE_IS_ENUM(enum_type), NULL);
|
||||||
|
|
||||||
|
enum_class = g_type_class_ref(enum_type);
|
||||||
|
enum_value = g_enum_get_value(enum_class, value);
|
||||||
|
g_type_class_unref(enum_class);
|
||||||
|
|
||||||
|
if (enum_value != NULL) {
|
||||||
|
return enum_value->value_nick;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_return_val_if_reached(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
spice_genum_get_value(GType enum_type, const char *nick,
|
||||||
|
gint default_value)
|
||||||
|
{
|
||||||
|
GEnumClass *enum_class;
|
||||||
|
GEnumValue *enum_value;
|
||||||
|
|
||||||
|
g_return_val_if_fail(G_TYPE_IS_ENUM(enum_type), default_value);
|
||||||
|
g_return_val_if_fail(nick != NULL, default_value);
|
||||||
|
|
||||||
|
enum_class = g_type_class_ref(enum_type);
|
||||||
|
enum_value = g_enum_get_value_by_nick(enum_class, nick);
|
||||||
|
g_type_class_unref(enum_class);
|
||||||
|
|
||||||
|
if (enum_value != NULL) {
|
||||||
|
return enum_value->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_return_val_if_reached(default_value);
|
||||||
|
}
|
||||||
57
common/utils.h
Normal file
57
common/utils.h
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||||
|
/*
|
||||||
|
Copyright (C) 2010, 2011, 2018 Red Hat, Inc.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef H_SPICE_COMMON_UTILS
|
||||||
|
#define H_SPICE_COMMON_UTILS
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include <glib-object.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
const char *spice_genum_get_nick(GType enum_type, gint value);
|
||||||
|
int spice_genum_get_value(GType enum_type, const char *nick,
|
||||||
|
gint default_value);
|
||||||
|
|
||||||
|
#define BIT_BYTE(nr) ((nr) / 8)
|
||||||
|
#define BIT_MASK(nr) (1 << ((nr) % 8))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set_bitmap - Set a bit in memory
|
||||||
|
* @nr: the bit to set
|
||||||
|
* @addr: the address to start counting from
|
||||||
|
*/
|
||||||
|
static inline void set_bitmap(uint32_t nr, uint8_t *addr)
|
||||||
|
{
|
||||||
|
addr[BIT_BYTE(nr)] |= BIT_MASK(nr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test_bitmap - Determine whether a bit is set
|
||||||
|
* @nr: bit number to test
|
||||||
|
* @addr: Address to start counting from
|
||||||
|
*/
|
||||||
|
static inline int test_bitmap(uint32_t nr, const uint8_t *addr)
|
||||||
|
{
|
||||||
|
return 1 & (addr[BIT_BYTE(nr)] >> (nr % 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif //H_SPICE_COMMON_UTILS
|
||||||
283
common/verify.h
Normal file
283
common/verify.h
Normal file
@ -0,0 +1,283 @@
|
|||||||
|
/* Compile-time assert-like macros.
|
||||||
|
|
||||||
|
Copyright (C) 2005-2006, 2009-2019 Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2.1 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
/* Written by Paul Eggert, Bruno Haible, and Jim Meyering. */
|
||||||
|
|
||||||
|
#ifndef _GL_VERIFY_H
|
||||||
|
#define _GL_VERIFY_H
|
||||||
|
|
||||||
|
|
||||||
|
/* Define _GL_HAVE__STATIC_ASSERT to 1 if _Static_assert works as per C11.
|
||||||
|
This is supported by GCC 4.6.0 and later, in C mode, and its use
|
||||||
|
here generates easier-to-read diagnostics when verify (R) fails.
|
||||||
|
|
||||||
|
Define _GL_HAVE_STATIC_ASSERT to 1 if static_assert works as per C++11.
|
||||||
|
This is supported by GCC 6.1.0 and later, in C++ mode.
|
||||||
|
|
||||||
|
Use this only with GCC. If we were willing to slow 'configure'
|
||||||
|
down we could also use it with other compilers, but since this
|
||||||
|
affects only the quality of diagnostics, why bother? */
|
||||||
|
#if (4 < __GNUC__ + (6 <= __GNUC_MINOR__) \
|
||||||
|
&& (201112L <= __STDC_VERSION__ || !defined __STRICT_ANSI__) \
|
||||||
|
&& !defined __cplusplus)
|
||||||
|
# define _GL_HAVE__STATIC_ASSERT 1
|
||||||
|
#endif
|
||||||
|
#if (6 <= __GNUC__) && defined __cplusplus
|
||||||
|
# define _GL_HAVE_STATIC_ASSERT 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* FreeBSD 9.1 <sys/cdefs.h>, included by <stddef.h> and lots of other
|
||||||
|
system headers, defines a conflicting _Static_assert that is no
|
||||||
|
better than ours; override it. */
|
||||||
|
#ifndef _GL_HAVE_STATIC_ASSERT
|
||||||
|
# include <stddef.h>
|
||||||
|
# undef _Static_assert
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Each of these macros verifies that its argument R is nonzero. To
|
||||||
|
be portable, R should be an integer constant expression. Unlike
|
||||||
|
assert (R), there is no run-time overhead.
|
||||||
|
|
||||||
|
If _Static_assert works, verify (R) uses it directly. Similarly,
|
||||||
|
_GL_VERIFY_TRUE works by packaging a _Static_assert inside a struct
|
||||||
|
that is an operand of sizeof.
|
||||||
|
|
||||||
|
The code below uses several ideas for C++ compilers, and for C
|
||||||
|
compilers that do not support _Static_assert:
|
||||||
|
|
||||||
|
* The first step is ((R) ? 1 : -1). Given an expression R, of
|
||||||
|
integral or boolean or floating-point type, this yields an
|
||||||
|
expression of integral type, whose value is later verified to be
|
||||||
|
constant and nonnegative.
|
||||||
|
|
||||||
|
* Next this expression W is wrapped in a type
|
||||||
|
struct _gl_verify_type {
|
||||||
|
unsigned int _gl_verify_error_if_negative: W;
|
||||||
|
}.
|
||||||
|
If W is negative, this yields a compile-time error. No compiler can
|
||||||
|
deal with a bit-field of negative size.
|
||||||
|
|
||||||
|
One might think that an array size check would have the same
|
||||||
|
effect, that is, that the type struct { unsigned int dummy[W]; }
|
||||||
|
would work as well. However, inside a function, some compilers
|
||||||
|
(such as C++ compilers and GNU C) allow local parameters and
|
||||||
|
variables inside array size expressions. With these compilers,
|
||||||
|
an array size check would not properly diagnose this misuse of
|
||||||
|
the verify macro:
|
||||||
|
|
||||||
|
void function (int n) { verify (n < 0); }
|
||||||
|
|
||||||
|
* For the verify macro, the struct _gl_verify_type will need to
|
||||||
|
somehow be embedded into a declaration. To be portable, this
|
||||||
|
declaration must declare an object, a constant, a function, or a
|
||||||
|
typedef name. If the declared entity uses the type directly,
|
||||||
|
such as in
|
||||||
|
|
||||||
|
struct dummy {...};
|
||||||
|
typedef struct {...} dummy;
|
||||||
|
extern struct {...} *dummy;
|
||||||
|
extern void dummy (struct {...} *);
|
||||||
|
extern struct {...} *dummy (void);
|
||||||
|
|
||||||
|
two uses of the verify macro would yield colliding declarations
|
||||||
|
if the entity names are not disambiguated. A workaround is to
|
||||||
|
attach the current line number to the entity name:
|
||||||
|
|
||||||
|
#define _GL_CONCAT0(x, y) x##y
|
||||||
|
#define _GL_CONCAT(x, y) _GL_CONCAT0 (x, y)
|
||||||
|
extern struct {...} * _GL_CONCAT (dummy, __LINE__);
|
||||||
|
|
||||||
|
But this has the problem that two invocations of verify from
|
||||||
|
within the same macro would collide, since the __LINE__ value
|
||||||
|
would be the same for both invocations. (The GCC __COUNTER__
|
||||||
|
macro solves this problem, but is not portable.)
|
||||||
|
|
||||||
|
A solution is to use the sizeof operator. It yields a number,
|
||||||
|
getting rid of the identity of the type. Declarations like
|
||||||
|
|
||||||
|
extern int dummy [sizeof (struct {...})];
|
||||||
|
extern void dummy (int [sizeof (struct {...})]);
|
||||||
|
extern int (*dummy (void)) [sizeof (struct {...})];
|
||||||
|
|
||||||
|
can be repeated.
|
||||||
|
|
||||||
|
* Should the implementation use a named struct or an unnamed struct?
|
||||||
|
Which of the following alternatives can be used?
|
||||||
|
|
||||||
|
extern int dummy [sizeof (struct {...})];
|
||||||
|
extern int dummy [sizeof (struct _gl_verify_type {...})];
|
||||||
|
extern void dummy (int [sizeof (struct {...})]);
|
||||||
|
extern void dummy (int [sizeof (struct _gl_verify_type {...})]);
|
||||||
|
extern int (*dummy (void)) [sizeof (struct {...})];
|
||||||
|
extern int (*dummy (void)) [sizeof (struct _gl_verify_type {...})];
|
||||||
|
|
||||||
|
In the second and sixth case, the struct type is exported to the
|
||||||
|
outer scope; two such declarations therefore collide. GCC warns
|
||||||
|
about the first, third, and fourth cases. So the only remaining
|
||||||
|
possibility is the fifth case:
|
||||||
|
|
||||||
|
extern int (*dummy (void)) [sizeof (struct {...})];
|
||||||
|
|
||||||
|
* GCC warns about duplicate declarations of the dummy function if
|
||||||
|
-Wredundant-decls is used. GCC 4.3 and later have a builtin
|
||||||
|
__COUNTER__ macro that can let us generate unique identifiers for
|
||||||
|
each dummy function, to suppress this warning.
|
||||||
|
|
||||||
|
* This implementation exploits the fact that older versions of GCC,
|
||||||
|
which do not support _Static_assert, also do not warn about the
|
||||||
|
last declaration mentioned above.
|
||||||
|
|
||||||
|
* GCC warns if -Wnested-externs is enabled and verify() is used
|
||||||
|
within a function body; but inside a function, you can always
|
||||||
|
arrange to use verify_expr() instead.
|
||||||
|
|
||||||
|
* In C++, any struct definition inside sizeof is invalid.
|
||||||
|
Use a template type to work around the problem. */
|
||||||
|
|
||||||
|
/* Concatenate two preprocessor tokens. */
|
||||||
|
#define _GL_CONCAT(x, y) _GL_CONCAT0 (x, y)
|
||||||
|
#define _GL_CONCAT0(x, y) x##y
|
||||||
|
|
||||||
|
/* _GL_COUNTER is an integer, preferably one that changes each time we
|
||||||
|
use it. Use __COUNTER__ if it works, falling back on __LINE__
|
||||||
|
otherwise. __LINE__ isn't perfect, but it's better than a
|
||||||
|
constant. */
|
||||||
|
#if defined __COUNTER__ && __COUNTER__ != __COUNTER__
|
||||||
|
# define _GL_COUNTER __COUNTER__
|
||||||
|
#else
|
||||||
|
# define _GL_COUNTER __LINE__
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Generate a symbol with the given prefix, making it unique if
|
||||||
|
possible. */
|
||||||
|
#define _GL_GENSYM(prefix) _GL_CONCAT (prefix, _GL_COUNTER)
|
||||||
|
|
||||||
|
/* Verify requirement R at compile-time, as an integer constant expression
|
||||||
|
that returns 1. If R is false, fail at compile-time, preferably
|
||||||
|
with a diagnostic that includes the string-literal DIAGNOSTIC. */
|
||||||
|
|
||||||
|
#define _GL_VERIFY_TRUE(R, DIAGNOSTIC) \
|
||||||
|
(!!sizeof (_GL_VERIFY_TYPE (R, DIAGNOSTIC)))
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
# if !GNULIB_defined_struct__gl_verify_type
|
||||||
|
template <int w>
|
||||||
|
struct _gl_verify_type {
|
||||||
|
unsigned int _gl_verify_error_if_negative: w;
|
||||||
|
};
|
||||||
|
# define GNULIB_defined_struct__gl_verify_type 1
|
||||||
|
# endif
|
||||||
|
# define _GL_VERIFY_TYPE(R, DIAGNOSTIC) \
|
||||||
|
_gl_verify_type<(R) ? 1 : -1>
|
||||||
|
#elif defined _GL_HAVE__STATIC_ASSERT
|
||||||
|
# define _GL_VERIFY_TYPE(R, DIAGNOSTIC) \
|
||||||
|
struct { \
|
||||||
|
_Static_assert (R, DIAGNOSTIC); \
|
||||||
|
int _gl_dummy; \
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
# define _GL_VERIFY_TYPE(R, DIAGNOSTIC) \
|
||||||
|
struct { unsigned int _gl_verify_error_if_negative: (R) ? 1 : -1; }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Verify requirement R at compile-time, as a declaration without a
|
||||||
|
trailing ';'. If R is false, fail at compile-time, preferably
|
||||||
|
with a diagnostic that includes the string-literal DIAGNOSTIC.
|
||||||
|
|
||||||
|
Unfortunately, unlike C11, this implementation must appear as an
|
||||||
|
ordinary declaration, and cannot appear inside struct { ... }. */
|
||||||
|
|
||||||
|
#ifdef _GL_HAVE__STATIC_ASSERT
|
||||||
|
# define _GL_VERIFY _Static_assert
|
||||||
|
#else
|
||||||
|
# define _GL_VERIFY(R, DIAGNOSTIC) \
|
||||||
|
extern int (*_GL_GENSYM (_gl_verify_function) (void)) \
|
||||||
|
[_GL_VERIFY_TRUE (R, DIAGNOSTIC)]
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* _GL_STATIC_ASSERT_H is defined if this code is copied into assert.h. */
|
||||||
|
#ifdef _GL_STATIC_ASSERT_H
|
||||||
|
# if !defined _GL_HAVE__STATIC_ASSERT && !defined _Static_assert
|
||||||
|
# define _Static_assert(R, DIAGNOSTIC) _GL_VERIFY (R, DIAGNOSTIC)
|
||||||
|
# endif
|
||||||
|
# if !defined _GL_HAVE_STATIC_ASSERT && !defined static_assert
|
||||||
|
# define static_assert _Static_assert /* C11 requires this #define. */
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* @assert.h omit start@ */
|
||||||
|
|
||||||
|
/* Each of these macros verifies that its argument R is nonzero. To
|
||||||
|
be portable, R should be an integer constant expression. Unlike
|
||||||
|
assert (R), there is no run-time overhead.
|
||||||
|
|
||||||
|
There are two macros, since no single macro can be used in all
|
||||||
|
contexts in C. verify_true (R) is for scalar contexts, including
|
||||||
|
integer constant expression contexts. verify (R) is for declaration
|
||||||
|
contexts, e.g., the top level. */
|
||||||
|
|
||||||
|
/* Verify requirement R at compile-time, as an integer constant expression.
|
||||||
|
Return 1. This is equivalent to verify_expr (R, 1).
|
||||||
|
|
||||||
|
verify_true is obsolescent; please use verify_expr instead. */
|
||||||
|
|
||||||
|
#define verify_true(R) _GL_VERIFY_TRUE (R, "verify_true (" #R ")")
|
||||||
|
|
||||||
|
/* Verify requirement R at compile-time. Return the value of the
|
||||||
|
expression E. */
|
||||||
|
|
||||||
|
#define verify_expr(R, E) \
|
||||||
|
(_GL_VERIFY_TRUE (R, "verify_expr (" #R ", " #E ")") ? (E) : (E))
|
||||||
|
|
||||||
|
/* Verify requirement R at compile-time, as a declaration without a
|
||||||
|
trailing ';'. */
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
# define verify(R) _GL_VERIFY (R, "verify (" #R ")")
|
||||||
|
#else
|
||||||
|
/* PGI barfs if R is long. Play it safe. */
|
||||||
|
# define verify(R) _GL_VERIFY (R, "verify (...)")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __has_builtin
|
||||||
|
# define __has_builtin(x) 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Assume that R always holds. This lets the compiler optimize
|
||||||
|
accordingly. R should not have side-effects; it may or may not be
|
||||||
|
evaluated. Behavior is undefined if R is false. */
|
||||||
|
|
||||||
|
#if (__has_builtin (__builtin_unreachable) \
|
||||||
|
|| 4 < __GNUC__ + (5 <= __GNUC_MINOR__))
|
||||||
|
# define assume(R) ((R) ? (void) 0 : __builtin_unreachable ())
|
||||||
|
#elif 1200 <= _MSC_VER
|
||||||
|
# define assume(R) __assume (R)
|
||||||
|
#elif ((defined GCC_LINT || defined lint) \
|
||||||
|
&& (__has_builtin (__builtin_trap) \
|
||||||
|
|| 3 < __GNUC__ + (3 < __GNUC_MINOR__ + (4 <= __GNUC_PATCHLEVEL__))))
|
||||||
|
/* Doing it this way helps various packages when configured with
|
||||||
|
--enable-gcc-warnings, which compiles with -Dlint. It's nicer
|
||||||
|
when 'assume' silences warnings even with older GCCs. */
|
||||||
|
# define assume(R) ((R) ? (void) 0 : __builtin_trap ())
|
||||||
|
#else
|
||||||
|
/* Some tools grok NOTREACHED, e.g., Oracle Studio 12.6. */
|
||||||
|
# define assume(R) ((R) ? (void) 0 : /*NOTREACHED*/ (void) 0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* @assert.h omit end@ */
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -1 +0,0 @@
|
|||||||
SUBDIRS = my_getopt-1.5
|
|
||||||
@ -1,22 +0,0 @@
|
|||||||
2006-12-09 Benjamin C. W. Sittler <bsittler@>
|
|
||||||
|
|
||||||
* my_getopt.c: add my_getopt_reset to reset the argument parser
|
|
||||||
|
|
||||||
* README: updated email address, updated for version 1.5
|
|
||||||
|
|
||||||
2002-07-26 Benjamin C. W. Sittler <bsittler@knownow.com>
|
|
||||||
|
|
||||||
* README: updated for version 1.4
|
|
||||||
|
|
||||||
* my_getopt.c: now we include <sys/types.h> explicitly for those
|
|
||||||
systems that narrowly (mis-)interpret ANSI C and POSIX
|
|
||||||
(_my_getopt_internal): added an explicit cast to size_t to make
|
|
||||||
g++ happy
|
|
||||||
|
|
||||||
* getopt.h, my_getopt.h: added extern "C" { ... } for C++
|
|
||||||
compilation (thanks to Jeff Lawson <bovine@ud.com> and others)
|
|
||||||
|
|
||||||
2001-08-20 Benjamin C. W. Sittler <bsittler@knownow.com>
|
|
||||||
|
|
||||||
* getopt.h (getopt_long_only): fixed typo (thanks to Justin Lee
|
|
||||||
<justin_lee@ud.com>)
|
|
||||||
@ -1,22 +0,0 @@
|
|||||||
my_getopt - a command-line argument parser
|
|
||||||
Copyright 1997-2001, Benjamin Sittler
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person
|
|
||||||
obtaining a copy of this software and associated documentation
|
|
||||||
files (the "Software"), to deal in the Software without
|
|
||||||
restriction, including without limitation the rights to use, copy,
|
|
||||||
modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
||||||
of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be
|
|
||||||
included in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
||||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
||||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
||||||
DEALINGS IN THE SOFTWARE.
|
|
||||||
@ -1,14 +0,0 @@
|
|||||||
NULL =
|
|
||||||
|
|
||||||
EXTRA_DIST = \
|
|
||||||
ChangeLog \
|
|
||||||
getopt.3 \
|
|
||||||
getopt.h \
|
|
||||||
getopt.txt \
|
|
||||||
LICENSE \
|
|
||||||
main.c \
|
|
||||||
Makefile \
|
|
||||||
my_getopt.c \
|
|
||||||
my_getopt.h \
|
|
||||||
README \
|
|
||||||
$(NULL)
|
|
||||||
@ -1,26 +0,0 @@
|
|||||||
all: copy
|
|
||||||
|
|
||||||
# Compiler options
|
|
||||||
#CCOPTS = -g -O3 -Wall -Werror
|
|
||||||
CCOPTS =
|
|
||||||
|
|
||||||
# Compiler
|
|
||||||
CC = gcc -Wall -Werror
|
|
||||||
#CC = cc
|
|
||||||
|
|
||||||
# Linker
|
|
||||||
LD = $(CC)
|
|
||||||
|
|
||||||
# Utility to remove a file
|
|
||||||
RM = rm
|
|
||||||
|
|
||||||
OBJS = main.o my_getopt.o
|
|
||||||
|
|
||||||
copy: $(OBJS)
|
|
||||||
$(LD) -o $@ $(OBJS)
|
|
||||||
|
|
||||||
clean:
|
|
||||||
$(RM) -f copy $(OBJS) *~
|
|
||||||
|
|
||||||
%.o: %.c getopt.h my_getopt.h
|
|
||||||
$(CC) $(CCOPTS) -o $@ -c $<
|
|
||||||
@ -1,140 +0,0 @@
|
|||||||
my_getopt - a command-line argument parser
|
|
||||||
Copyright 1997-2006, Benjamin Sittler
|
|
||||||
|
|
||||||
The author can be reached by sending email to <bsittler@gmail.com>.
|
|
||||||
|
|
||||||
The version of my_getopt in this package (1.5) has a BSD-like license;
|
|
||||||
see the file LICENSE for details. Version 1.0 of my_getopt was similar
|
|
||||||
to the GPL'ed version of my_getopt included with SMOKE-16 Version 1,
|
|
||||||
Release 19990717. SMOKE-16 packages are available from:
|
|
||||||
|
|
||||||
http://geocities.com/bsittler/#smoke16
|
|
||||||
|
|
||||||
OVERVIEW OF THE ARGUMENT PARSER
|
|
||||||
===============================
|
|
||||||
|
|
||||||
The getopt(), getopt_long() and getopt_long_only() functions parse
|
|
||||||
command line arguments. The argc and argv parameters passed to these
|
|
||||||
functions correspond to the argument count and argument list passed to
|
|
||||||
your program's main() function at program start-up. Element 0 of the
|
|
||||||
argument list conventionally contains the name of your program. Any
|
|
||||||
remaining arguments starting with "-" (except for "-" or "--" by
|
|
||||||
themselves) are option arguments, some of include option values. This
|
|
||||||
family of getopt() functions allows intermixed option and non-option
|
|
||||||
arguments anywhere in the argument list, except that "--" by itself
|
|
||||||
causes the remaining elements of the argument list to be treated as
|
|
||||||
non-option arguments.
|
|
||||||
|
|
||||||
[ See the parts of this document labeled "DOCUMENTATION" and
|
|
||||||
"WHY RE-INVENT THE WHEEL?" for a more information. ]
|
|
||||||
|
|
||||||
FILES
|
|
||||||
=====
|
|
||||||
|
|
||||||
The following four files constitute the my_getopt package:
|
|
||||||
|
|
||||||
LICENSE - license and warranty information for my_getopt
|
|
||||||
my_getopt.c - implementation of my getopt replacement
|
|
||||||
my_getopt.h - interface for my getopt replacement
|
|
||||||
getopt.h - a header file to make my getopt look like GNU getopt
|
|
||||||
|
|
||||||
USAGE
|
|
||||||
=====
|
|
||||||
|
|
||||||
To use my_getopt in your application, include the following line to
|
|
||||||
your main program source:
|
|
||||||
|
|
||||||
#include "getopt.h"
|
|
||||||
|
|
||||||
This line should appear after your standard system header files to
|
|
||||||
avoid conflicting with your system's built-in getopt.
|
|
||||||
|
|
||||||
Then compile my_getopt.c into my_getopt.o, and link my_getopt.o into
|
|
||||||
your application:
|
|
||||||
|
|
||||||
$ cc -c my_getopt.c
|
|
||||||
$ ld -o app app.o ... my_getopt.o
|
|
||||||
|
|
||||||
To avoid conflicting with standard library functions, the function
|
|
||||||
names and global variables used by my_getopt all begin with `my_'. To
|
|
||||||
ensure compatibility with existing C programs, the `getopt.h' header
|
|
||||||
file uses the C preprocessor to redefine names like getopt, optarg,
|
|
||||||
optind, and so forth to my_getopt, my_optarg, my_optind, etc.
|
|
||||||
|
|
||||||
SAMPLE PROGRAM
|
|
||||||
==============
|
|
||||||
|
|
||||||
There is also a public-domain sample program:
|
|
||||||
|
|
||||||
main.c - main() for a sample program using my_getopt
|
|
||||||
Makefile - build script for the sample program (called `copy')
|
|
||||||
|
|
||||||
To build and test the sample program:
|
|
||||||
|
|
||||||
$ make
|
|
||||||
$ ./copy -help
|
|
||||||
$ ./copy -version
|
|
||||||
|
|
||||||
The sample program bears a slight resemblance to the UNIX `cat'
|
|
||||||
utility, but can be used rot13-encode streams, and can redirect output
|
|
||||||
to a file.
|
|
||||||
|
|
||||||
DOCUMENTATION
|
|
||||||
=============
|
|
||||||
|
|
||||||
There is not yet any real documentation for my_getopt. For the moment,
|
|
||||||
use the Linux manual page for getopt. It has its own copyright and
|
|
||||||
license; view the file `getopt.3' in a text editor for more details.
|
|
||||||
|
|
||||||
getopt.3 - the manual page for GNU getopt
|
|
||||||
getopt.txt - preformatted copy of the manual page for GNU getopt,
|
|
||||||
for your convenience
|
|
||||||
|
|
||||||
WHY RE-INVENT THE WHEEL?
|
|
||||||
========================
|
|
||||||
|
|
||||||
I re-implemented getopt, getopt_long, and getopt_long_only because
|
|
||||||
there were noticable bugs in several versions of the GNU
|
|
||||||
implementations, and because the GNU versions aren't always available
|
|
||||||
on some systems (*BSD, for example.) Other systems don't include any
|
|
||||||
sort of standard argument parser (Win32 with Microsoft tools, for
|
|
||||||
example, has no getopt.)
|
|
||||||
|
|
||||||
These should do all the expected Unix- and GNU-style argument
|
|
||||||
parsing, including permution, bunching, long options with single or
|
|
||||||
double dashes (double dashes are required if you use
|
|
||||||
my_getopt_long,) and optional arguments for both long and short
|
|
||||||
options. A word with double dashes all by themselves halts argument
|
|
||||||
parsing. A required long option argument can be in the same word as
|
|
||||||
the option name, separated by '=', or in the next word. An optional
|
|
||||||
long option argument must be in the same word as the option name,
|
|
||||||
separated by '='.
|
|
||||||
|
|
||||||
As with the GNU versions, a '+' prefix to the short option
|
|
||||||
specification (or the POSIXLY_CORRECT environment variable) disables
|
|
||||||
permution, a '-' prefix to the short option specification returns 1
|
|
||||||
for non-options, ':' after a short option indicates a required
|
|
||||||
argument, and '::' after a short option specification indicates an
|
|
||||||
optional argument (which must appear in the same word.) If you'd like
|
|
||||||
to recieve ':' instead of '?' for missing option arguments, prefix the
|
|
||||||
short option specification with ':'.
|
|
||||||
|
|
||||||
The original intent was to re-implement the documented behavior of
|
|
||||||
the GNU versions, but I have found it necessary to emulate some of
|
|
||||||
the undocumented behavior as well. Some programs depend on it.
|
|
||||||
|
|
||||||
KNOWN BUGS
|
|
||||||
==========
|
|
||||||
|
|
||||||
The GNU versions support POSIX-style -W "name=value" long
|
|
||||||
options. Currently, my_getopt does not support these, because I
|
|
||||||
don't have any documentation on them (other than the fact that they
|
|
||||||
are enabled by "W;" in the short option specification.) As a
|
|
||||||
temporary workaround, my_getopt treats "W;" in the short option
|
|
||||||
string identically to "W:".
|
|
||||||
|
|
||||||
The GNU versions support internationalized/localized
|
|
||||||
messages. Currently, my_getopt does not.
|
|
||||||
|
|
||||||
There should be re-entrant versions of all these functions so that
|
|
||||||
multiple threads can parse arguments simultaneously.
|
|
||||||
@ -1,288 +0,0 @@
|
|||||||
.\" (c) 1993 by Thomas Koenig (ig25@rz.uni-karlsruhe.de)
|
|
||||||
.\"
|
|
||||||
.\" Permission is granted to make and distribute verbatim copies of this
|
|
||||||
.\" manual provided the copyright notice and this permission notice are
|
|
||||||
.\" preserved on all copies.
|
|
||||||
.\"
|
|
||||||
.\" Permission is granted to copy and distribute modified versions of this
|
|
||||||
.\" manual under the conditions for verbatim copying, provided that the
|
|
||||||
.\" entire resulting derived work is distributed under the terms of a
|
|
||||||
.\" permission notice identical to this one
|
|
||||||
.\"
|
|
||||||
.\" Since the Linux kernel and libraries are constantly changing, this
|
|
||||||
.\" manual page may be incorrect or out-of-date. The author(s) assume no
|
|
||||||
.\" responsibility for errors or omissions, or for damages resulting from
|
|
||||||
.\" the use of the information contained herein. The author(s) may not
|
|
||||||
.\" have taken the same level of care in the production of this manual,
|
|
||||||
.\" which is licensed free of charge, as they might when working
|
|
||||||
.\" professionally.
|
|
||||||
.\"
|
|
||||||
.\" Formatted or processed versions of this manual, if unaccompanied by
|
|
||||||
.\" the source, must acknowledge the copyright and authors of this work.
|
|
||||||
.\" License.
|
|
||||||
.\" Modified Sat Jul 24 19:27:50 1993 by Rik Faith (faith@cs.unc.edu)
|
|
||||||
.\" Modified Mon Aug 30 22:02:34 1995 by Jim Van Zandt <jrv@vanzandt.mv.com>
|
|
||||||
.\" longindex is a pointer, has_arg can take 3 values, using consistent
|
|
||||||
.\" names for optstring and longindex, "\n" in formats fixed. Documenting
|
|
||||||
.\" opterr and getopt_long_only. Clarified explanations (borrowing heavily
|
|
||||||
.\" from the source code).
|
|
||||||
.TH GETOPT 3 "Aug 30, 1995" "GNU" "Linux Programmer's Manual"
|
|
||||||
.SH NAME
|
|
||||||
getopt \- Parse command line options
|
|
||||||
.SH SYNOPSIS
|
|
||||||
.nf
|
|
||||||
.B #include <unistd.h>
|
|
||||||
.sp
|
|
||||||
.BI "int getopt(int " argc ", char * const " argv[] ","
|
|
||||||
.BI " const char *" optstring ");"
|
|
||||||
.sp
|
|
||||||
.BI "extern char *" optarg ;
|
|
||||||
.BI "extern int " optind ", " opterr ", " optopt ;
|
|
||||||
.sp
|
|
||||||
.B #include <getopt.h>
|
|
||||||
.sp
|
|
||||||
.BI "int getopt_long(int " argc ", char * const " argv[] ",
|
|
||||||
.BI " const char *" optstring ,
|
|
||||||
.BI " const struct option *" longopts ", int *" longindex ");"
|
|
||||||
.sp
|
|
||||||
.BI "int getopt_long_only(int " argc ", char * const " argv[] ",
|
|
||||||
.BI " const char *" optstring ,
|
|
||||||
.BI " const struct option *" longopts ", int *" longindex ");"
|
|
||||||
.fi
|
|
||||||
.SH DESCRIPTION
|
|
||||||
The
|
|
||||||
.B getopt()
|
|
||||||
function parses the command line arguments. Its arguments
|
|
||||||
.I argc
|
|
||||||
and
|
|
||||||
.I argv
|
|
||||||
are the argument count and array as passed to the
|
|
||||||
.B main()
|
|
||||||
function on program invocation.
|
|
||||||
An element of \fIargv\fP that starts with `-' (and is not exactly "-" or "--")
|
|
||||||
is an option element. The characters of this element
|
|
||||||
(aside from the initial `-') are option characters. If \fBgetopt()\fP
|
|
||||||
is called repeatedly, it returns successively each of the option characters
|
|
||||||
from each of the option elements.
|
|
||||||
.PP
|
|
||||||
If \fBgetopt()\fP finds another option character, it returns that
|
|
||||||
character, updating the external variable \fIoptind\fP and a static
|
|
||||||
variable \fInextchar\fP so that the next call to \fBgetopt()\fP can
|
|
||||||
resume the scan with the following option character or
|
|
||||||
\fIargv\fP-element.
|
|
||||||
.PP
|
|
||||||
If there are no more option characters, \fBgetopt()\fP returns
|
|
||||||
\fBEOF\fP. Then \fIoptind\fP is the index in \fIargv\fP of the first
|
|
||||||
\fIargv\fP-element that is not an option.
|
|
||||||
.PP
|
|
||||||
.I optstring
|
|
||||||
is a string containing the legitimate option characters. If such a
|
|
||||||
character is followed by a colon, the option requires an argument, so
|
|
||||||
\fBgetopt\fP places a pointer to the following text in the same
|
|
||||||
\fIargv\fP-element, or the text of the following \fIargv\fP-element, in
|
|
||||||
.IR optarg .
|
|
||||||
Two colons mean an option takes
|
|
||||||
an optional arg; if there is text in the current \fIargv\fP-element,
|
|
||||||
it is returned in \fIoptarg\fP, otherwise \fIoptarg\fP is set to zero.
|
|
||||||
.PP
|
|
||||||
By default, \fBgetargs()\fP permutes the contents of \fIargv\fP as it
|
|
||||||
scans, so that eventually all the non-options are at the end. Two
|
|
||||||
other modes are also implemented. If the first character of
|
|
||||||
\fIoptstring\fP is `+' or the environment variable POSIXLY_CORRECT is
|
|
||||||
set, then option processing stops as soon as a non-option argument is
|
|
||||||
encountered. If the first character of \fIoptstring\fP is `-', then
|
|
||||||
each non-option \fIargv\fP-element is handled as if it were the argument of
|
|
||||||
an option with character code 1. (This is used by programs that were
|
|
||||||
written to expect options and other \fIargv\fP-elements in any order
|
|
||||||
and that care about the ordering of the two.)
|
|
||||||
The special argument `--' forces an end of option-scanning regardless
|
|
||||||
of the scanning mode.
|
|
||||||
.PP
|
|
||||||
If \fBgetopt()\fP does not recognize an option character, it prints an
|
|
||||||
error message to stderr, stores the character in \fIoptopt\fP, and
|
|
||||||
returns `?'. The calling program may prevent the error message by
|
|
||||||
setting \fIopterr\fP to 0.
|
|
||||||
.PP
|
|
||||||
The
|
|
||||||
.B getopt_long()
|
|
||||||
function works like
|
|
||||||
.B getopt()
|
|
||||||
except that it also accepts long options, started out by two dashes.
|
|
||||||
Long option names may be abbreviated if the abbreviation is
|
|
||||||
unique or is an exact match for some defined option. A long option
|
|
||||||
may take a parameter, of the form
|
|
||||||
.B --arg=param
|
|
||||||
or
|
|
||||||
.BR "--arg param" .
|
|
||||||
.PP
|
|
||||||
.I longopts
|
|
||||||
is a pointer to the first element of an array of
|
|
||||||
.B struct option
|
|
||||||
declared in
|
|
||||||
.B <getopt.h>
|
|
||||||
as
|
|
||||||
.nf
|
|
||||||
.sp
|
|
||||||
.in 10
|
|
||||||
struct option {
|
|
||||||
.in 14
|
|
||||||
const char *name;
|
|
||||||
int has_arg;
|
|
||||||
int *flag;
|
|
||||||
int val;
|
|
||||||
.in 10
|
|
||||||
};
|
|
||||||
.fi
|
|
||||||
.PP
|
|
||||||
The meanings of the different fields are:
|
|
||||||
.TP
|
|
||||||
.I name
|
|
||||||
is the name of the long option.
|
|
||||||
.TP
|
|
||||||
.I has_arg
|
|
||||||
is:
|
|
||||||
\fBno_argument\fP (or 0) if the option does not take an argument,
|
|
||||||
\fBrequired_argument\fP (or 1) if the option requires an argument, or
|
|
||||||
\fBoptional_argument\fP (or 2) if the option takes an optional argument.
|
|
||||||
.TP
|
|
||||||
.I flag
|
|
||||||
specifies how results are returned for a long option. If \fIflag\fP
|
|
||||||
is \fBNULL\fP, then \fBgetopt_long()\fP returns \fIval\fP. (For
|
|
||||||
example, the calling program may set \fIval\fP to the equivalent short
|
|
||||||
option character.) Otherwise, \fBgetopt_long()\fP returns 0, and
|
|
||||||
\fIflag\fP points to a variable which is set to \fIval\fP if the
|
|
||||||
option is found, but left unchanged if the option is not found.
|
|
||||||
.TP
|
|
||||||
\fIval\fP
|
|
||||||
is the value to return, or to load into the variable pointed
|
|
||||||
to by \fIflag\fP.
|
|
||||||
.PP
|
|
||||||
The last element of the array has to be filled with zeroes.
|
|
||||||
.PP
|
|
||||||
If \fIlongindex\fP is not \fBNULL\fP, it
|
|
||||||
points to a variable which is set to the index of the long option relative to
|
|
||||||
.IR longopts .
|
|
||||||
.PP
|
|
||||||
\fBgetopt_long_only()\fP is like \fBgetopt_long()\fP, but `-' as well
|
|
||||||
as `--' can indicate a long option. If an option that starts with `-'
|
|
||||||
(not `--') doesn't match a long option, but does match a short option,
|
|
||||||
it is parsed as a short option instead.
|
|
||||||
.SH "RETURN VALUE"
|
|
||||||
The
|
|
||||||
.B getopt()
|
|
||||||
function returns the option character if the option was found
|
|
||||||
successfully, `:' if there was a missing parameter for one of the
|
|
||||||
options, `?' for an unknown option character, or \fBEOF\fP
|
|
||||||
for the end of the option list.
|
|
||||||
.PP
|
|
||||||
\fBgetopt_long()\fP and \fBgetopt_long_only()\fP also return the option
|
|
||||||
character when a short option is recognized. For a long option, they
|
|
||||||
return \fIval\fP if \fIflag\fP is \fBNULL\fP, and 0 otherwise. Error
|
|
||||||
and EOF returns are the same as for \fBgetopt()\fP, plus `?' for an
|
|
||||||
ambiguous match or an extraneous parameter.
|
|
||||||
.SH "ENVIRONMENT VARIABLES"
|
|
||||||
.TP
|
|
||||||
.SM
|
|
||||||
.B POSIXLY_CORRECT
|
|
||||||
If this is set, then option processing stops as soon as a non-option
|
|
||||||
argument is encountered.
|
|
||||||
.SH "EXAMPLE"
|
|
||||||
The following example program, from the source code, illustrates the
|
|
||||||
use of
|
|
||||||
.BR getopt_long()
|
|
||||||
with most of its features.
|
|
||||||
.nf
|
|
||||||
.sp
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
int
|
|
||||||
main (argc, argv)
|
|
||||||
int argc;
|
|
||||||
char **argv;
|
|
||||||
{
|
|
||||||
int c;
|
|
||||||
int digit_optind = 0;
|
|
||||||
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
int this_option_optind = optind ? optind : 1;
|
|
||||||
int option_index = 0;
|
|
||||||
static struct option long_options[] =
|
|
||||||
{
|
|
||||||
{"add", 1, 0, 0},
|
|
||||||
{"append", 0, 0, 0},
|
|
||||||
{"delete", 1, 0, 0},
|
|
||||||
{"verbose", 0, 0, 0},
|
|
||||||
{"create", 1, 0, 'c'},
|
|
||||||
{"file", 1, 0, 0},
|
|
||||||
{0, 0, 0, 0}
|
|
||||||
};
|
|
||||||
|
|
||||||
c = getopt_long (argc, argv, "abc:d:012",
|
|
||||||
long_options, &option_index);
|
|
||||||
if (c == -1)
|
|
||||||
break;
|
|
||||||
|
|
||||||
switch (c)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
printf ("option %s", long_options[option_index].name);
|
|
||||||
if (optarg)
|
|
||||||
printf (" with arg %s", optarg);
|
|
||||||
printf ("\\n");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '0':
|
|
||||||
case '1':
|
|
||||||
case '2':
|
|
||||||
if (digit_optind != 0 && digit_optind != this_option_optind)
|
|
||||||
printf ("digits occur in two different argv-elements.\\n");
|
|
||||||
digit_optind = this_option_optind;
|
|
||||||
printf ("option %c\\n", c);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'a':
|
|
||||||
printf ("option a\\n");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'b':
|
|
||||||
printf ("option b\\n");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'c':
|
|
||||||
printf ("option c with value `%s'\\n", optarg);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'd':
|
|
||||||
printf ("option d with value `%s'\\n", optarg);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '?':
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
printf ("?? getopt returned character code 0%o ??\\n", c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (optind < argc)
|
|
||||||
{
|
|
||||||
printf ("non-option ARGV-elements: ");
|
|
||||||
while (optind < argc)
|
|
||||||
printf ("%s ", argv[optind++]);
|
|
||||||
printf ("\\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
exit (0);
|
|
||||||
}
|
|
||||||
.fi
|
|
||||||
.SH "BUGS"
|
|
||||||
This manpage is confusing.
|
|
||||||
.SH "CONFORMING TO"
|
|
||||||
.TP
|
|
||||||
\fBgetopt()\fP:
|
|
||||||
POSIX.1, provided the environment variable POSIXLY_CORRECT is set.
|
|
||||||
Otherwise, the elements of \fIargv\fP aren't really const, because we
|
|
||||||
permute them. We pretend they're const in the prototype to be
|
|
||||||
compatible with other systems.
|
|
||||||
|
|
||||||
@ -1,56 +0,0 @@
|
|||||||
/*
|
|
||||||
* getopt.h - cpp wrapper for my_getopt to make it look like getopt.
|
|
||||||
* Copyright 1997, 2000, 2001, 2002, Benjamin Sittler
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person
|
|
||||||
* obtaining a copy of this software and associated documentation
|
|
||||||
* files (the "Software"), to deal in the Software without
|
|
||||||
* restriction, including without limitation the rights to use, copy,
|
|
||||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
||||||
* of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be
|
|
||||||
* included in all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
||||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
||||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
||||||
* DEALINGS IN THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef MY_WRAPPER_GETOPT_H_INCLUDED
|
|
||||||
#define MY_WRAPPER_GETOPT_H_INCLUDED
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "my_getopt.h"
|
|
||||||
|
|
||||||
#undef getopt
|
|
||||||
#define getopt my_getopt
|
|
||||||
#undef getopt_long
|
|
||||||
#define getopt_long my_getopt_long
|
|
||||||
#undef getopt_long_only
|
|
||||||
#define getopt_long_only my_getopt_long_only
|
|
||||||
#undef _getopt_internal
|
|
||||||
#define _getopt_internal _my_getopt_internal
|
|
||||||
#undef opterr
|
|
||||||
#define opterr my_opterr
|
|
||||||
#undef optind
|
|
||||||
#define optind my_optind
|
|
||||||
#undef optopt
|
|
||||||
#define optopt my_optopt
|
|
||||||
#undef optarg
|
|
||||||
#define optarg my_optarg
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* MY_WRAPPER_GETOPT_H_INCLUDED */
|
|
||||||
@ -1,330 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
GETOPT(3) Linux Programmer's Manual GETOPT(3)
|
|
||||||
|
|
||||||
|
|
||||||
NAME
|
|
||||||
getopt - Parse command line options
|
|
||||||
|
|
||||||
SYNOPSIS
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
int getopt(int argc, char * const argv[],
|
|
||||||
const char *optstring);
|
|
||||||
|
|
||||||
extern char *optarg;
|
|
||||||
extern int optind, opterr, optopt;
|
|
||||||
|
|
||||||
#include <getopt.h>
|
|
||||||
|
|
||||||
int getopt_long(int argc, char * const argv[],
|
|
||||||
const char *optstring,
|
|
||||||
const struct option *longopts, int *longindex);
|
|
||||||
|
|
||||||
int getopt_long_only(int argc, char * const argv[],
|
|
||||||
const char *optstring,
|
|
||||||
const struct option *longopts, int *longindex);
|
|
||||||
|
|
||||||
DESCRIPTION
|
|
||||||
The getopt() function parses the command line arguments.
|
|
||||||
Its arguments argc and argv are the argument count and
|
|
||||||
array as passed to the main() function on program invoca-
|
|
||||||
tion. An element of argv that starts with `-' (and is not
|
|
||||||
exactly "-" or "--") is an option element. The characters
|
|
||||||
of this element (aside from the initial `-') are option
|
|
||||||
characters. If getopt() is called repeatedly, it returns
|
|
||||||
successively each of the option characters from each of
|
|
||||||
the option elements.
|
|
||||||
|
|
||||||
If getopt() finds another option character, it returns
|
|
||||||
that character, updating the external variable optind and
|
|
||||||
a static variable nextchar so that the next call to
|
|
||||||
getopt() can resume the scan with the following option
|
|
||||||
character or argv-element.
|
|
||||||
|
|
||||||
If there are no more option characters, getopt() returns
|
|
||||||
EOF. Then optind is the index in argv of the first argv-
|
|
||||||
element that is not an option.
|
|
||||||
|
|
||||||
optstring is a string containing the legitimate option
|
|
||||||
characters. If such a character is followed by a colon,
|
|
||||||
the option requires an argument, so getopt places a
|
|
||||||
pointer to the following text in the same argv-element, or
|
|
||||||
the text of the following argv-element, in optarg. Two
|
|
||||||
colons mean an option takes an optional arg; if there is
|
|
||||||
text in the current argv-element, it is returned in
|
|
||||||
optarg, otherwise optarg is set to zero.
|
|
||||||
|
|
||||||
By default, getargs() permutes the contents of argv as it
|
|
||||||
scans, so that eventually all the non-options are at the
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
GNU Aug 30, 1995 1
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
GETOPT(3) Linux Programmer's Manual GETOPT(3)
|
|
||||||
|
|
||||||
|
|
||||||
end. Two other modes are also implemented. If the first
|
|
||||||
character of optstring is `+' or the environment variable
|
|
||||||
POSIXLY_CORRECT is set, then option processing stops as
|
|
||||||
soon as a non-option argument is encountered. If the
|
|
||||||
first character of optstring is `-', then each non-option
|
|
||||||
argv-element is handled as if it were the argument of an
|
|
||||||
option with character code 1. (This is used by programs
|
|
||||||
that were written to expect options and other argv-ele-
|
|
||||||
ments in any order and that care about the ordering of the
|
|
||||||
two.) The special argument `--' forces an end of option-
|
|
||||||
scanning regardless of the scanning mode.
|
|
||||||
|
|
||||||
If getopt() does not recognize an option character, it
|
|
||||||
prints an error message to stderr, stores the character in
|
|
||||||
optopt, and returns `?'. The calling program may prevent
|
|
||||||
the error message by setting opterr to 0.
|
|
||||||
|
|
||||||
The getopt_long() function works like getopt() except that
|
|
||||||
it also accepts long options, started out by two dashes.
|
|
||||||
Long option names may be abbreviated if the abbreviation
|
|
||||||
is unique or is an exact match for some defined option. A
|
|
||||||
long option may take a parameter, of the form --arg=param
|
|
||||||
or --arg param.
|
|
||||||
|
|
||||||
longopts is a pointer to the first element of an array of
|
|
||||||
struct option declared in <getopt.h> as
|
|
||||||
|
|
||||||
struct option {
|
|
||||||
const char *name;
|
|
||||||
int has_arg;
|
|
||||||
int *flag;
|
|
||||||
int val;
|
|
||||||
};
|
|
||||||
|
|
||||||
The meanings of the different fields are:
|
|
||||||
|
|
||||||
name is the name of the long option.
|
|
||||||
|
|
||||||
has_arg
|
|
||||||
is: no_argument (or 0) if the option does not take
|
|
||||||
an argument, required_argument (or 1) if the option
|
|
||||||
requires an argument, or optional_argument (or 2)
|
|
||||||
if the option takes an optional argument.
|
|
||||||
|
|
||||||
flag specifies how results are returned for a long
|
|
||||||
option. If flag is NULL, then getopt_long()
|
|
||||||
returns val. (For example, the calling program may
|
|
||||||
set val to the equivalent short option character.)
|
|
||||||
Otherwise, getopt_long() returns 0, and flag points
|
|
||||||
to a variable which is set to val if the option is
|
|
||||||
found, but left unchanged if the option is not
|
|
||||||
found.
|
|
||||||
|
|
||||||
val is the value to return, or to load into the
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
GNU Aug 30, 1995 2
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
GETOPT(3) Linux Programmer's Manual GETOPT(3)
|
|
||||||
|
|
||||||
|
|
||||||
variable pointed to by flag.
|
|
||||||
|
|
||||||
The last element of the array has to be filled with
|
|
||||||
zeroes.
|
|
||||||
|
|
||||||
If longindex is not NULL, it points to a variable which is
|
|
||||||
set to the index of the long option relative to longopts.
|
|
||||||
|
|
||||||
getopt_long_only() is like getopt_long(), but `-' as well
|
|
||||||
as `--' can indicate a long option. If an option that
|
|
||||||
starts with `-' (not `--') doesn't match a long option,
|
|
||||||
but does match a short option, it is parsed as a short
|
|
||||||
option instead.
|
|
||||||
|
|
||||||
RETURN VALUE
|
|
||||||
The getopt() function returns the option character if the
|
|
||||||
option was found successfully, `:' if there was a missing
|
|
||||||
parameter for one of the options, `?' for an unknown
|
|
||||||
option character, or EOF for the end of the option list.
|
|
||||||
|
|
||||||
getopt_long() and getopt_long_only() also return the
|
|
||||||
option character when a short option is recognized. For a
|
|
||||||
long option, they return val if flag is NULL, and 0 other-
|
|
||||||
wise. Error and EOF returns are the same as for getopt(),
|
|
||||||
plus `?' for an ambiguous match or an extraneous parame-
|
|
||||||
ter.
|
|
||||||
|
|
||||||
ENVIRONMENT VARIABLES
|
|
||||||
POSIXLY_CORRECT
|
|
||||||
If this is set, then option processing stops as
|
|
||||||
soon as a non-option argument is encountered.
|
|
||||||
|
|
||||||
EXAMPLE
|
|
||||||
The following example program, from the source code,
|
|
||||||
illustrates the use of getopt_long() with most of its fea-
|
|
||||||
tures.
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
int
|
|
||||||
main (argc, argv)
|
|
||||||
int argc;
|
|
||||||
char **argv;
|
|
||||||
{
|
|
||||||
int c;
|
|
||||||
int digit_optind = 0;
|
|
||||||
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
int this_option_optind = optind ? optind : 1;
|
|
||||||
int option_index = 0;
|
|
||||||
static struct option long_options[] =
|
|
||||||
{
|
|
||||||
{"add", 1, 0, 0},
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
GNU Aug 30, 1995 3
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
GETOPT(3) Linux Programmer's Manual GETOPT(3)
|
|
||||||
|
|
||||||
|
|
||||||
{"append", 0, 0, 0},
|
|
||||||
{"delete", 1, 0, 0},
|
|
||||||
{"verbose", 0, 0, 0},
|
|
||||||
{"create", 1, 0, 'c'},
|
|
||||||
{"file", 1, 0, 0},
|
|
||||||
{0, 0, 0, 0}
|
|
||||||
};
|
|
||||||
|
|
||||||
c = getopt_long (argc, argv, "abc:d:012",
|
|
||||||
long_options, &option_index);
|
|
||||||
if (c == -1)
|
|
||||||
break;
|
|
||||||
|
|
||||||
switch (c)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
printf ("option %s", long_options[option_index].name);
|
|
||||||
if (optarg)
|
|
||||||
printf (" with arg %s", optarg);
|
|
||||||
printf ("\n");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '0':
|
|
||||||
case '1':
|
|
||||||
case '2':
|
|
||||||
if (digit_optind != 0 && digit_optind != this_option_optind)
|
|
||||||
printf ("digits occur in two different argv-elements.\n");
|
|
||||||
digit_optind = this_option_optind;
|
|
||||||
printf ("option %c\n", c);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'a':
|
|
||||||
printf ("option a\n");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'b':
|
|
||||||
printf ("option b\n");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'c':
|
|
||||||
printf ("option c with value `%s'\n", optarg);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'd':
|
|
||||||
printf ("option d with value `%s'\n", optarg);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '?':
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
printf ("?? getopt returned character code 0%o ??\n", c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
GNU Aug 30, 1995 4
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
GETOPT(3) Linux Programmer's Manual GETOPT(3)
|
|
||||||
|
|
||||||
|
|
||||||
if (optind < argc)
|
|
||||||
{
|
|
||||||
printf ("non-option ARGV-elements: ");
|
|
||||||
while (optind < argc)
|
|
||||||
printf ("%s ", argv[optind++]);
|
|
||||||
printf ("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
exit (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
BUGS
|
|
||||||
This manpage is confusing.
|
|
||||||
|
|
||||||
CONFORMING TO
|
|
||||||
getopt():
|
|
||||||
POSIX.1, provided the environment variable
|
|
||||||
POSIXLY_CORRECT is set. Otherwise, the elements of
|
|
||||||
argv aren't really const, because we permute them.
|
|
||||||
We pretend they're const in the prototype to be
|
|
||||||
compatible with other systems.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
GNU Aug 30, 1995 5
|
|
||||||
|
|
||||||
|
|
||||||
@ -1,387 +0,0 @@
|
|||||||
/*
|
|
||||||
* copy - test program for my getopt() re-implementation
|
|
||||||
*
|
|
||||||
* This program is in the public domain.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define VERSION \
|
|
||||||
"0.3"
|
|
||||||
|
|
||||||
#define COPYRIGHT \
|
|
||||||
"This program is in the public domain."
|
|
||||||
|
|
||||||
/* for isprint(), printf(), fopen(), perror(), getenv(), strcmp(), etc. */
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
/* for my getopt() re-implementation */
|
|
||||||
#include "getopt.h"
|
|
||||||
|
|
||||||
/* the default verbosity level is 0 (no verbose reporting) */
|
|
||||||
static unsigned verbose = 0;
|
|
||||||
|
|
||||||
/* print version and copyright information */
|
|
||||||
static void
|
|
||||||
version(char *progname)
|
|
||||||
{
|
|
||||||
printf("%s version %s\n"
|
|
||||||
"%s\n",
|
|
||||||
progname,
|
|
||||||
VERSION,
|
|
||||||
COPYRIGHT);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* print a help summary */
|
|
||||||
static void
|
|
||||||
help(char *progname)
|
|
||||||
{
|
|
||||||
printf("Usage: %s [options] [FILE]...\n"
|
|
||||||
"Options:\n"
|
|
||||||
"-h or -help show this message and exit\n"
|
|
||||||
"-append append to the output file\n"
|
|
||||||
"-o FILE or\n"
|
|
||||||
"-output FILE send output to FILE (default is stdout)\n"
|
|
||||||
"-r or --rotate rotate letters 13 positions (rot13)\n"
|
|
||||||
"-rNUM or\n"
|
|
||||||
"--rotate=NUM rotate letters NUM positions\n"
|
|
||||||
"-truncate truncate the output file "
|
|
||||||
"(this is the default)\n"
|
|
||||||
"-v or -verbose increase the level of verbosity by 1"
|
|
||||||
"(the default is 0)\n"
|
|
||||||
"-vNUM or\n"
|
|
||||||
"-verbose=NUM set the level of verbosity to NUM\n"
|
|
||||||
"-V or -version print program version and exit\n"
|
|
||||||
"\n"
|
|
||||||
"This program reads the specified FILEs "
|
|
||||||
"(or stdin if none are given)\n"
|
|
||||||
"and writes their bytes to the specified output FILE "
|
|
||||||
"(or stdout if none is\n"
|
|
||||||
"given.) It can optionally rotate letters.\n",
|
|
||||||
progname);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* print usage information to stderr */
|
|
||||||
static void
|
|
||||||
usage(char *progname)
|
|
||||||
{
|
|
||||||
fprintf(stderr,
|
|
||||||
"Summary: %s [-help] [-version] [options] [FILE]...\n",
|
|
||||||
progname);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* input file handler -- returns nonzero or exit()s on failure */
|
|
||||||
static int
|
|
||||||
handle(char *progname,
|
|
||||||
FILE *infile, char *infilename,
|
|
||||||
FILE *outfile, char *outfilename,
|
|
||||||
int rotate)
|
|
||||||
{
|
|
||||||
int c;
|
|
||||||
unsigned long bytes_copied = 0;
|
|
||||||
|
|
||||||
if (verbose > 2)
|
|
||||||
{
|
|
||||||
fprintf(stderr,
|
|
||||||
"%s: copying from `%s' to `%s'\n",
|
|
||||||
progname,
|
|
||||||
infilename,
|
|
||||||
outfilename);
|
|
||||||
}
|
|
||||||
while ((c = getc(infile)) != EOF)
|
|
||||||
{
|
|
||||||
if (rotate && isalpha(c))
|
|
||||||
{
|
|
||||||
const char *letters = "abcdefghijklmnopqrstuvwxyz";
|
|
||||||
char *match;
|
|
||||||
if ((match = strchr(letters, tolower(c))))
|
|
||||||
{
|
|
||||||
char rc = letters[(match - letters + rotate) % 26];
|
|
||||||
if (isupper(c))
|
|
||||||
rc = toupper(rc);
|
|
||||||
c = rc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (putc(c, outfile) == EOF)
|
|
||||||
{
|
|
||||||
perror(outfilename);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
bytes_copied ++;
|
|
||||||
}
|
|
||||||
if (! feof(infile))
|
|
||||||
{
|
|
||||||
perror(infilename);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (verbose > 2)
|
|
||||||
{
|
|
||||||
fprintf(stderr,
|
|
||||||
"%s: %lu bytes copied from `%s' to `%s'\n",
|
|
||||||
progname,
|
|
||||||
bytes_copied,
|
|
||||||
infilename,
|
|
||||||
outfilename);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* argument parser and dispatcher */
|
|
||||||
int
|
|
||||||
main(int argc, char * argv[])
|
|
||||||
{
|
|
||||||
/* the program name */
|
|
||||||
char *progname = argv[0];
|
|
||||||
/* during argument parsing, opt contains the return value from getopt() */
|
|
||||||
int opt;
|
|
||||||
/* the output filename is initially 0 (a.k.a. stdout) */
|
|
||||||
char *outfilename = 0;
|
|
||||||
/* the default return value is initially 0 (success) */
|
|
||||||
int retval = 0;
|
|
||||||
/* initially we truncate */
|
|
||||||
int append = 0;
|
|
||||||
/* initially we don't rotate letters */
|
|
||||||
int rotate = 0;
|
|
||||||
|
|
||||||
/* short options string */
|
|
||||||
char *shortopts = "Vho:r::v::";
|
|
||||||
/* long options list */
|
|
||||||
struct option longopts[] =
|
|
||||||
{
|
|
||||||
/* name, has_arg, flag, val */ /* longind */
|
|
||||||
{ "append", no_argument, 0, 0 }, /* 0 */
|
|
||||||
{ "truncate", no_argument, 0, 0 }, /* 1 */
|
|
||||||
{ "version", no_argument, 0, 'V' }, /* 3 */
|
|
||||||
{ "help", no_argument, 0, 'h' }, /* 4 */
|
|
||||||
{ "output", required_argument, 0, 'o' }, /* 5 */
|
|
||||||
{ "rotate", optional_argument, 0, 'r' }, /* 6 */
|
|
||||||
{ "verbose", optional_argument, 0, 'v' }, /* 7 */
|
|
||||||
/* end-of-list marker */
|
|
||||||
{ 0, 0, 0, 0 }
|
|
||||||
};
|
|
||||||
/* long option list index */
|
|
||||||
int longind = 0;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* print a warning when the POSIXLY_CORRECT environment variable will
|
|
||||||
* interfere with argument placement
|
|
||||||
*/
|
|
||||||
if (getenv("POSIXLY_CORRECT"))
|
|
||||||
{
|
|
||||||
fprintf(stderr,
|
|
||||||
"%s: "
|
|
||||||
"Warning: implicit argument reordering disallowed by "
|
|
||||||
"POSIXLY_CORRECT\n",
|
|
||||||
progname);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* parse all options from the command line */
|
|
||||||
while ((opt =
|
|
||||||
getopt_long_only(argc, argv, shortopts, longopts, &longind)) != -1)
|
|
||||||
switch (opt)
|
|
||||||
{
|
|
||||||
case 0: /* a long option without an equivalent short option */
|
|
||||||
switch (longind)
|
|
||||||
{
|
|
||||||
case 0: /* -append */
|
|
||||||
append = 1;
|
|
||||||
break;
|
|
||||||
case 1: /* -truncate */
|
|
||||||
append = 0;
|
|
||||||
break;
|
|
||||||
default: /* something unexpected has happened */
|
|
||||||
fprintf(stderr,
|
|
||||||
"%s: "
|
|
||||||
"getopt_long_only unexpectedly returned %d for `--%s'\n",
|
|
||||||
progname,
|
|
||||||
opt,
|
|
||||||
longopts[longind].name);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'V': /* -version */
|
|
||||||
version(progname);
|
|
||||||
return 0;
|
|
||||||
case 'h': /* -help */
|
|
||||||
help(progname);
|
|
||||||
return 0;
|
|
||||||
case 'r': /* -rotate[=NUM] */
|
|
||||||
if (optarg)
|
|
||||||
{
|
|
||||||
/* we use this while trying to parse a numeric argument */
|
|
||||||
char ignored;
|
|
||||||
if (sscanf(optarg,
|
|
||||||
"%d%c",
|
|
||||||
&rotate,
|
|
||||||
&ignored) != 1)
|
|
||||||
{
|
|
||||||
fprintf(stderr,
|
|
||||||
"%s: "
|
|
||||||
"rotation `%s' is not a number\n",
|
|
||||||
progname,
|
|
||||||
optarg);
|
|
||||||
usage(progname);
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
/* normalize rotation */
|
|
||||||
while (rotate < 0)
|
|
||||||
{
|
|
||||||
rotate += 26;
|
|
||||||
}
|
|
||||||
rotate %= 26;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
rotate = 13;
|
|
||||||
break;
|
|
||||||
case 'o': /* -output=FILE */
|
|
||||||
outfilename = optarg;
|
|
||||||
/* we allow "-" as a synonym for stdout here */
|
|
||||||
if (! strcmp(optarg, "-"))
|
|
||||||
{
|
|
||||||
outfilename = 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'v': /* -verbose[=NUM] */
|
|
||||||
if (optarg)
|
|
||||||
{
|
|
||||||
/* we use this while trying to parse a numeric argument */
|
|
||||||
char ignored;
|
|
||||||
if (sscanf(optarg,
|
|
||||||
"%u%c",
|
|
||||||
&verbose,
|
|
||||||
&ignored) != 1)
|
|
||||||
{
|
|
||||||
fprintf(stderr,
|
|
||||||
"%s: "
|
|
||||||
"verbosity level `%s' is not a number\n",
|
|
||||||
progname,
|
|
||||||
optarg);
|
|
||||||
usage(progname);
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
verbose ++;
|
|
||||||
break;
|
|
||||||
case '?': /* getopt_long_only noticed an error */
|
|
||||||
usage(progname);
|
|
||||||
return 2;
|
|
||||||
default: /* something unexpected has happened */
|
|
||||||
fprintf(stderr,
|
|
||||||
"%s: "
|
|
||||||
"getopt_long_only returned an unexpected value (%d)\n",
|
|
||||||
progname,
|
|
||||||
opt);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* re-open stdout to outfilename, if requested */
|
|
||||||
if (outfilename)
|
|
||||||
{
|
|
||||||
if (! freopen(outfilename, (append ? "a" : "w"), stdout))
|
|
||||||
{
|
|
||||||
perror(outfilename);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* make a human-readable version of the output filename "-" */
|
|
||||||
outfilename = "stdout";
|
|
||||||
/* you can't truncate stdout */
|
|
||||||
append = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (verbose)
|
|
||||||
{
|
|
||||||
fprintf(stderr,
|
|
||||||
"%s: verbosity level is %u; %s `%s'; rotation %d\n",
|
|
||||||
progname,
|
|
||||||
verbose,
|
|
||||||
(append ? "appending to" : "truncating"),
|
|
||||||
outfilename,
|
|
||||||
rotate);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (verbose > 1)
|
|
||||||
{
|
|
||||||
fprintf(stderr,
|
|
||||||
"%s: %d input file(s) were given\n",
|
|
||||||
progname,
|
|
||||||
((argc > optind) ? (argc - optind) : 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (verbose > 3)
|
|
||||||
{
|
|
||||||
fprintf(stderr,
|
|
||||||
"\topterr: %d\n\toptind: %d\n\toptopt: %d (%c)\n\toptarg: %s\n",
|
|
||||||
opterr,
|
|
||||||
optind,
|
|
||||||
optopt, optopt,
|
|
||||||
optarg ? optarg : "(null)");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* handle each of the input files (or stdin, if no files were given) */
|
|
||||||
if (optind < argc)
|
|
||||||
{
|
|
||||||
int argindex;
|
|
||||||
|
|
||||||
for (argindex = optind; argindex < argc; argindex ++)
|
|
||||||
{
|
|
||||||
char *infilename = argv[argindex];
|
|
||||||
FILE *infile;
|
|
||||||
|
|
||||||
/* we allow "-" as a synonym for stdin here */
|
|
||||||
if (! strcmp(infilename, "-"))
|
|
||||||
{
|
|
||||||
infile = stdin;
|
|
||||||
infilename = "stdin";
|
|
||||||
}
|
|
||||||
else if (! (infile = fopen(infilename, "r")))
|
|
||||||
{
|
|
||||||
perror(infilename);
|
|
||||||
retval = 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (handle(progname,
|
|
||||||
infile, argv[optind],
|
|
||||||
stdout, outfilename,
|
|
||||||
rotate))
|
|
||||||
{
|
|
||||||
retval = 1;
|
|
||||||
fclose(infile);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if ((infile != stdin) && fclose(infile))
|
|
||||||
{
|
|
||||||
perror(infilename);
|
|
||||||
retval = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
retval =
|
|
||||||
handle(progname,
|
|
||||||
stdin, "stdin",
|
|
||||||
stdout, outfilename,
|
|
||||||
rotate);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* close stdout */
|
|
||||||
if (fclose(stdout))
|
|
||||||
{
|
|
||||||
perror(outfilename);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (verbose > 3)
|
|
||||||
{
|
|
||||||
fprintf(stderr,
|
|
||||||
"%s: normal return, exit code is %d\n",
|
|
||||||
progname,
|
|
||||||
retval);
|
|
||||||
}
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
@ -1,281 +0,0 @@
|
|||||||
/*
|
|
||||||
* my_getopt.c - my re-implementation of getopt.
|
|
||||||
* Copyright 1997, 2000, 2001, 2002, 2006, Benjamin Sittler
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person
|
|
||||||
* obtaining a copy of this software and associated documentation
|
|
||||||
* files (the "Software"), to deal in the Software without
|
|
||||||
* restriction, including without limitation the rights to use, copy,
|
|
||||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
||||||
* of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be
|
|
||||||
* included in all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
||||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
||||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
||||||
* DEALINGS IN THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "my_getopt.h"
|
|
||||||
|
|
||||||
int my_optind=1, my_opterr=1, my_optopt=0;
|
|
||||||
char *my_optarg=0;
|
|
||||||
|
|
||||||
/* reset argument parser to start-up values */
|
|
||||||
int my_getopt_reset(void)
|
|
||||||
{
|
|
||||||
my_optind = 1;
|
|
||||||
my_opterr = 1;
|
|
||||||
my_optopt = 0;
|
|
||||||
my_optarg = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* this is the plain old UNIX getopt, with GNU-style extensions. */
|
|
||||||
/* if you're porting some piece of UNIX software, this is all you need. */
|
|
||||||
/* this supports GNU-style permution and optional arguments */
|
|
||||||
|
|
||||||
int my_getopt(int argc, char * argv[], const char *opts)
|
|
||||||
{
|
|
||||||
static int charind=0;
|
|
||||||
char mode, colon_mode;
|
|
||||||
int off = 0, opt = -1;
|
|
||||||
|
|
||||||
if(getenv("POSIXLY_CORRECT")) colon_mode = mode = '+';
|
|
||||||
else {
|
|
||||||
if((colon_mode = *opts) == ':') off ++;
|
|
||||||
if(((mode = opts[off]) == '+') || (mode == '-')) {
|
|
||||||
off++;
|
|
||||||
if((colon_mode != ':') && ((colon_mode = opts[off]) == ':'))
|
|
||||||
off ++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
my_optarg = 0;
|
|
||||||
if(charind) {
|
|
||||||
const char *s;
|
|
||||||
my_optopt = argv[my_optind][charind];
|
|
||||||
for(s=opts+off; *s; s++) if(my_optopt == *s) {
|
|
||||||
charind++;
|
|
||||||
if((*(++s) == ':') || ((my_optopt == 'W') && (*s == ';'))) {
|
|
||||||
if(argv[my_optind][charind]) {
|
|
||||||
my_optarg = &(argv[my_optind++][charind]);
|
|
||||||
charind = 0;
|
|
||||||
} else if(*(++s) != ':') {
|
|
||||||
charind = 0;
|
|
||||||
if(++my_optind >= argc) {
|
|
||||||
if(my_opterr) fprintf(stderr,
|
|
||||||
"%s: option requires an argument -- %c\n",
|
|
||||||
argv[0], my_optopt);
|
|
||||||
opt = (colon_mode == ':') ? ':' : '?';
|
|
||||||
goto my_getopt_ok;
|
|
||||||
}
|
|
||||||
my_optarg = argv[my_optind++];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
opt = my_optopt;
|
|
||||||
goto my_getopt_ok;
|
|
||||||
}
|
|
||||||
if(my_opterr) fprintf(stderr,
|
|
||||||
"%s: illegal option -- %c\n",
|
|
||||||
argv[0], my_optopt);
|
|
||||||
opt = '?';
|
|
||||||
if(argv[my_optind][++charind] == '\0') {
|
|
||||||
my_optind++;
|
|
||||||
charind = 0;
|
|
||||||
}
|
|
||||||
my_getopt_ok:
|
|
||||||
if(charind && ! argv[my_optind][charind]) {
|
|
||||||
my_optind++;
|
|
||||||
charind = 0;
|
|
||||||
}
|
|
||||||
} else if((my_optind >= argc) ||
|
|
||||||
((argv[my_optind][0] == '-') &&
|
|
||||||
(argv[my_optind][1] == '-') &&
|
|
||||||
(argv[my_optind][2] == '\0'))) {
|
|
||||||
my_optind++;
|
|
||||||
opt = -1;
|
|
||||||
} else if((argv[my_optind][0] != '-') ||
|
|
||||||
(argv[my_optind][1] == '\0')) {
|
|
||||||
char *tmp;
|
|
||||||
int i, j, k;
|
|
||||||
|
|
||||||
if(mode == '+') opt = -1;
|
|
||||||
else if(mode == '-') {
|
|
||||||
my_optarg = argv[my_optind++];
|
|
||||||
charind = 0;
|
|
||||||
opt = 1;
|
|
||||||
} else {
|
|
||||||
for(i=j=my_optind; i<argc; i++) if((argv[i][0] == '-') &&
|
|
||||||
(argv[i][1] != '\0')) {
|
|
||||||
my_optind=i;
|
|
||||||
opt=my_getopt(argc, argv, opts);
|
|
||||||
while(i > j) {
|
|
||||||
tmp=argv[--i];
|
|
||||||
for(k=i; k+1<my_optind; k++) argv[k]=argv[k+1];
|
|
||||||
argv[--my_optind]=tmp;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(i == argc) opt = -1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
charind++;
|
|
||||||
opt = my_getopt(argc, argv, opts);
|
|
||||||
}
|
|
||||||
if (my_optind > argc) my_optind = argc;
|
|
||||||
return opt;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* this is the extended getopt_long{,_only}, with some GNU-like
|
|
||||||
* extensions. Implements _getopt_internal in case any programs
|
|
||||||
* expecting GNU libc getopt call it.
|
|
||||||
*/
|
|
||||||
|
|
||||||
int _my_getopt_internal(int argc, char * argv[], const char *shortopts,
|
|
||||||
const struct option *longopts, int *longind,
|
|
||||||
int long_only)
|
|
||||||
{
|
|
||||||
char mode, colon_mode = *shortopts;
|
|
||||||
int shortoff = 0, opt = -1;
|
|
||||||
|
|
||||||
if(getenv("POSIXLY_CORRECT")) colon_mode = mode = '+';
|
|
||||||
else {
|
|
||||||
if((colon_mode = *shortopts) == ':') shortoff ++;
|
|
||||||
if(((mode = shortopts[shortoff]) == '+') || (mode == '-')) {
|
|
||||||
shortoff++;
|
|
||||||
if((colon_mode != ':') && ((colon_mode = shortopts[shortoff]) == ':'))
|
|
||||||
shortoff ++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
my_optarg = 0;
|
|
||||||
if((my_optind >= argc) ||
|
|
||||||
((argv[my_optind][0] == '-') &&
|
|
||||||
(argv[my_optind][1] == '-') &&
|
|
||||||
(argv[my_optind][2] == '\0'))) {
|
|
||||||
my_optind++;
|
|
||||||
opt = -1;
|
|
||||||
} else if((argv[my_optind][0] != '-') ||
|
|
||||||
(argv[my_optind][1] == '\0')) {
|
|
||||||
char *tmp;
|
|
||||||
int i, j, k;
|
|
||||||
|
|
||||||
opt = -1;
|
|
||||||
if(mode == '+') return -1;
|
|
||||||
else if(mode == '-') {
|
|
||||||
my_optarg = argv[my_optind++];
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
for(i=j=my_optind; i<argc; i++) if((argv[i][0] == '-') &&
|
|
||||||
(argv[i][1] != '\0')) {
|
|
||||||
my_optind=i;
|
|
||||||
opt=_my_getopt_internal(argc, argv, shortopts,
|
|
||||||
longopts, longind,
|
|
||||||
long_only);
|
|
||||||
while(i > j) {
|
|
||||||
tmp=argv[--i];
|
|
||||||
for(k=i; k+1<my_optind; k++)
|
|
||||||
argv[k]=argv[k+1];
|
|
||||||
argv[--my_optind]=tmp;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else if((!long_only) && (argv[my_optind][1] != '-'))
|
|
||||||
opt = my_getopt(argc, argv, shortopts);
|
|
||||||
else {
|
|
||||||
int charind, offset;
|
|
||||||
int found = 0, ind, hits = 0;
|
|
||||||
|
|
||||||
if(((my_optopt = argv[my_optind][1]) != '-') && ! argv[my_optind][2]) {
|
|
||||||
int c;
|
|
||||||
|
|
||||||
ind = shortoff;
|
|
||||||
while((c = shortopts[ind++])) {
|
|
||||||
if(((shortopts[ind] == ':') ||
|
|
||||||
((c == 'W') && (shortopts[ind] == ';'))) &&
|
|
||||||
(shortopts[++ind] == ':'))
|
|
||||||
ind ++;
|
|
||||||
if(my_optopt == c) return my_getopt(argc, argv, shortopts);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
offset = 2 - (argv[my_optind][1] != '-');
|
|
||||||
for(charind = offset;
|
|
||||||
(argv[my_optind][charind] != '\0') &&
|
|
||||||
(argv[my_optind][charind] != '=');
|
|
||||||
charind++);
|
|
||||||
for(ind = 0; longopts[ind].name && !hits; ind++)
|
|
||||||
if((strlen(longopts[ind].name) == (size_t) (charind - offset)) &&
|
|
||||||
(strncmp(longopts[ind].name,
|
|
||||||
argv[my_optind] + offset, charind - offset) == 0))
|
|
||||||
found = ind, hits++;
|
|
||||||
if(!hits) for(ind = 0; longopts[ind].name; ind++)
|
|
||||||
if(strncmp(longopts[ind].name,
|
|
||||||
argv[my_optind] + offset, charind - offset) == 0)
|
|
||||||
found = ind, hits++;
|
|
||||||
if(hits == 1) {
|
|
||||||
opt = 0;
|
|
||||||
|
|
||||||
if(argv[my_optind][charind] == '=') {
|
|
||||||
if(longopts[found].has_arg == 0) {
|
|
||||||
opt = '?';
|
|
||||||
if(my_opterr) fprintf(stderr,
|
|
||||||
"%s: option `--%s' doesn't allow an argument\n",
|
|
||||||
argv[0], longopts[found].name);
|
|
||||||
} else {
|
|
||||||
my_optarg = argv[my_optind] + ++charind;
|
|
||||||
charind = 0;
|
|
||||||
}
|
|
||||||
} else if(longopts[found].has_arg == 1) {
|
|
||||||
if(++my_optind >= argc) {
|
|
||||||
opt = (colon_mode == ':') ? ':' : '?';
|
|
||||||
if(my_opterr) fprintf(stderr,
|
|
||||||
"%s: option `--%s' requires an argument\n",
|
|
||||||
argv[0], longopts[found].name);
|
|
||||||
} else my_optarg = argv[my_optind];
|
|
||||||
}
|
|
||||||
if(!opt) {
|
|
||||||
if (longind) *longind = found;
|
|
||||||
if(!longopts[found].flag) opt = longopts[found].val;
|
|
||||||
else *(longopts[found].flag) = longopts[found].val;
|
|
||||||
}
|
|
||||||
my_optind++;
|
|
||||||
} else if(!hits) {
|
|
||||||
if(offset == 1) opt = my_getopt(argc, argv, shortopts);
|
|
||||||
else {
|
|
||||||
opt = '?';
|
|
||||||
if(my_opterr) fprintf(stderr,
|
|
||||||
"%s: unrecognized option `%s'\n",
|
|
||||||
argv[0], argv[my_optind++]);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
opt = '?';
|
|
||||||
if(my_opterr) fprintf(stderr,
|
|
||||||
"%s: option `%s' is ambiguous\n",
|
|
||||||
argv[0], argv[my_optind++]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (my_optind > argc) my_optind = argc;
|
|
||||||
return opt;
|
|
||||||
}
|
|
||||||
|
|
||||||
int my_getopt_long(int argc, char * argv[], const char *shortopts,
|
|
||||||
const struct option *longopts, int *longind)
|
|
||||||
{
|
|
||||||
return _my_getopt_internal(argc, argv, shortopts, longopts, longind, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int my_getopt_long_only(int argc, char * argv[], const char *shortopts,
|
|
||||||
const struct option *longopts, int *longind)
|
|
||||||
{
|
|
||||||
return _my_getopt_internal(argc, argv, shortopts, longopts, longind, 1);
|
|
||||||
}
|
|
||||||
@ -1,72 +0,0 @@
|
|||||||
/*
|
|
||||||
* my_getopt.h - interface to my re-implementation of getopt.
|
|
||||||
* Copyright 1997, 2000, 2001, 2002, 2006, Benjamin Sittler
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person
|
|
||||||
* obtaining a copy of this software and associated documentation
|
|
||||||
* files (the "Software"), to deal in the Software without
|
|
||||||
* restriction, including without limitation the rights to use, copy,
|
|
||||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
||||||
* of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be
|
|
||||||
* included in all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
||||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
||||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
||||||
* DEALINGS IN THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef MY_GETOPT_H_INCLUDED
|
|
||||||
#define MY_GETOPT_H_INCLUDED
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* reset argument parser to start-up values */
|
|
||||||
extern int my_getopt_reset(void);
|
|
||||||
|
|
||||||
/* UNIX-style short-argument parser */
|
|
||||||
extern int my_getopt(int argc, char * argv[], const char *opts);
|
|
||||||
|
|
||||||
extern int my_optind, my_opterr, my_optopt;
|
|
||||||
extern char *my_optarg;
|
|
||||||
|
|
||||||
struct option {
|
|
||||||
const char *name;
|
|
||||||
int has_arg;
|
|
||||||
int *flag;
|
|
||||||
int val;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* human-readable values for has_arg */
|
|
||||||
#undef no_argument
|
|
||||||
#define no_argument 0
|
|
||||||
#undef required_argument
|
|
||||||
#define required_argument 1
|
|
||||||
#undef optional_argument
|
|
||||||
#define optional_argument 2
|
|
||||||
|
|
||||||
/* GNU-style long-argument parsers */
|
|
||||||
extern int my_getopt_long(int argc, char * argv[], const char *shortopts,
|
|
||||||
const struct option *longopts, int *longind);
|
|
||||||
|
|
||||||
extern int my_getopt_long_only(int argc, char * argv[], const char *shortopts,
|
|
||||||
const struct option *longopts, int *longind);
|
|
||||||
|
|
||||||
extern int _my_getopt_internal(int argc, char * argv[], const char *shortopts,
|
|
||||||
const struct option *longopts, int *longind,
|
|
||||||
int long_only);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* MY_GETOPT_H_INCLUDED */
|
|
||||||
81
configure.ac
Normal file
81
configure.ac
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
AC_PREREQ([2.63])
|
||||||
|
|
||||||
|
AC_INIT([spice-common],
|
||||||
|
[noversion],
|
||||||
|
[spice-devel@lists.freedesktop.org])
|
||||||
|
|
||||||
|
AC_CONFIG_SRCDIR([common/log.h])
|
||||||
|
AC_CONFIG_MACRO_DIR([m4])
|
||||||
|
AM_CONFIG_HEADER([config.h])
|
||||||
|
AC_CONFIG_AUX_DIR([build-aux])
|
||||||
|
|
||||||
|
# For automake >= 1.12
|
||||||
|
m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
|
||||||
|
|
||||||
|
# Checks for programs
|
||||||
|
AM_INIT_AUTOMAKE([1.11 dist-xz no-dist-gzip tar-ustar foreign subdir-objects -Wall -Werror])
|
||||||
|
AM_MAINTAINER_MODE
|
||||||
|
AM_SILENT_RULES([yes])
|
||||||
|
LT_INIT
|
||||||
|
SPICE_MANUAL
|
||||||
|
|
||||||
|
AC_PROG_CC
|
||||||
|
AC_PROG_CC_C99
|
||||||
|
if test "x$ac_cv_prog_cc_c99" = xno; then
|
||||||
|
AC_MSG_ERROR([C99 compiler is required.])
|
||||||
|
fi
|
||||||
|
AM_PROG_CC_C_O
|
||||||
|
|
||||||
|
AC_CHECK_HEADERS([sys/mman.h regex.h])
|
||||||
|
AC_CHECK_FUNCS([sigaction drand48 setlinebuf])
|
||||||
|
AC_SEARCH_LIBS(regcomp, [regex rx])
|
||||||
|
|
||||||
|
SPICE_CHECK_SYSDEPS
|
||||||
|
SPICE_EXTRA_CHECKS
|
||||||
|
|
||||||
|
AC_ARG_ENABLE([tests],
|
||||||
|
AS_HELP_STRING([--enable-tests],
|
||||||
|
[Enable tests @<:@default=yes@:>@]),
|
||||||
|
[],
|
||||||
|
enable_tests="yes")
|
||||||
|
AM_CONDITIONAL(ENABLE_TESTS, test "x$enable_tests" = "xyes")
|
||||||
|
|
||||||
|
AC_ARG_ENABLE([alignment-checks],
|
||||||
|
AS_HELP_STRING([--enable-alignment-checks],
|
||||||
|
[Enable runtime checks for cast alignment @<:@default=no@:>@]),
|
||||||
|
[],
|
||||||
|
enable_alignment_checks="no")
|
||||||
|
AS_IF([test "x$enable_alignment_checks" = "xyes"],
|
||||||
|
[AC_DEFINE([SPICE_DEBUG_ALIGNMENT], 1, [Enable runtime checks for cast alignment])])
|
||||||
|
|
||||||
|
SPICE_CHECK_INSTRUMENTATION
|
||||||
|
|
||||||
|
# Checks for libraries
|
||||||
|
PKG_CHECK_MODULES([PROTOCOL], [spice-protocol >= 0.14.2])
|
||||||
|
|
||||||
|
SPICE_CHECK_PYTHON_MODULES()
|
||||||
|
|
||||||
|
SPICE_CHECK_PIXMAN
|
||||||
|
SPICE_CHECK_SMARTCARD
|
||||||
|
SPICE_CHECK_GLIB2
|
||||||
|
SPICE_CHECK_OPUS
|
||||||
|
SPICE_CHECK_OPENSSL
|
||||||
|
SPICE_CHECK_GDK_PIXBUF
|
||||||
|
SPICE_CHECK_UDEV
|
||||||
|
|
||||||
|
SPICE_COMMON_CFLAGS='$(PIXMAN_CFLAGS) $(SMARTCARD_CFLAGS) $(GLIB2_CFLAGS) $(OPUS_CFLAGS) $(OPENSSL_CFLAGS)'
|
||||||
|
SPICE_COMMON_CFLAGS="$SPICE_COMMON_CFLAGS -DG_LOG_DOMAIN=\\\"Spice\\\""
|
||||||
|
SPICE_COMMON_LIBS='$(PIXMAN_LIBS) $(GLIB2_LIBS) $(OPUS_LIBS) $(OPENSSL_LIBS)'
|
||||||
|
AC_SUBST(SPICE_COMMON_CFLAGS)
|
||||||
|
AC_SUBST(SPICE_COMMON_LIBS)
|
||||||
|
|
||||||
|
# The End!
|
||||||
|
AC_CONFIG_FILES([
|
||||||
|
Makefile
|
||||||
|
common/Makefile
|
||||||
|
python_modules/Makefile
|
||||||
|
tests/Makefile
|
||||||
|
docs/Makefile
|
||||||
|
])
|
||||||
|
|
||||||
|
AC_OUTPUT
|
||||||
27
docs/Makefile.am
Normal file
27
docs/Makefile.am
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
NULL =
|
||||||
|
CLEANFILES =
|
||||||
|
|
||||||
|
ASCIIDOC_FILES = \
|
||||||
|
spice_protocol.txt \
|
||||||
|
spice_uri_scheme.txt \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
ASCIIDOC_FLAGS = -n -a icons -a toc
|
||||||
|
|
||||||
|
EXTRA_DIST = \
|
||||||
|
$(ASCIIDOC_FILES) \
|
||||||
|
meson.build \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
if BUILD_HTML_MANUAL
|
||||||
|
ASCIIDOC_HTML = $(ASCIIDOC_FILES:.txt=.html)
|
||||||
|
|
||||||
|
CLEANFILES += $(ASCIIDOC_HTML)
|
||||||
|
|
||||||
|
all-local: $(ASCIIDOC_HTML)
|
||||||
|
|
||||||
|
.txt.html:
|
||||||
|
$(AM_V_GEN)$(ASCIIDOC) $(ASCIIDOC_FLAGS) -o $@ $<
|
||||||
|
endif
|
||||||
|
|
||||||
|
-include $(top_srcdir)/git.mk
|
||||||
12
docs/meson.build
Normal file
12
docs/meson.build
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
if get_option('manual')
|
||||||
|
asciidoc = find_program('asciidoc', required : false)
|
||||||
|
if asciidoc.found()
|
||||||
|
foreach f: ['spice_protocol.txt', 'spice_uri_scheme.txt']
|
||||||
|
custom_target('HTML for @0@'.format(f),
|
||||||
|
input : f,
|
||||||
|
output : '@BASENAME@.html',
|
||||||
|
build_by_default : true,
|
||||||
|
command : [asciidoc, '-n', '-a', 'icons', '-a', 'toc', '-o', '@OUTPUT@', '@INPUT@'])
|
||||||
|
endforeach
|
||||||
|
endif
|
||||||
|
endif
|
||||||
477
docs/spice_protocol.txt
Normal file
477
docs/spice_protocol.txt
Normal file
@ -0,0 +1,477 @@
|
|||||||
|
Spice protocol format file
|
||||||
|
==========================
|
||||||
|
|
||||||
|
Copyright (C) 2016 Red Hat, Inc.
|
||||||
|
Licensed under a Creative Commons Attribution-Share Alike 3.0
|
||||||
|
United States License (see http://creativecommons.org/licenses/by-sa/3.0/us/legalcode).
|
||||||
|
|
||||||
|
Basic
|
||||||
|
-----
|
||||||
|
The spice protocol format file defines the network protocol used by spice.
|
||||||
|
It resemble the C format.
|
||||||
|
|
||||||
|
file ::= <definitions> <protocol> ;
|
||||||
|
definitions ::= <definition>|<definitions><definition> ;
|
||||||
|
definition ::= <typedef>|<structure>|<enum>|<flag>|<message>|<channel> ;
|
||||||
|
protocol ::= "protocol" <identifier> "{" <protocol_channels> "}" ";" ;
|
||||||
|
protocol_channels ::= <protocol_channel>|<protocol_channels><protocol_channel> ;
|
||||||
|
protocol_channel ::= <identifier> <identifier> [ "=" <integer> ] ";" ;
|
||||||
|
integer ::= <hex>|<dec> ;
|
||||||
|
dec ::= [+-][0-9]+ ;
|
||||||
|
hex ::= "0x" [0-9a-f]+ ;
|
||||||
|
identifier ::= [a-z][a-z0-9_]* ;
|
||||||
|
|
||||||
|
(here BNF with some regular expression is used).
|
||||||
|
|
||||||
|
It's used to generate automatically code to marshal/demarshal the network data.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
channel ExampleChannel {
|
||||||
|
message {
|
||||||
|
uint32 dummy;
|
||||||
|
} Dummy;
|
||||||
|
};
|
||||||
|
|
||||||
|
protocol Example {
|
||||||
|
ExampleChannel first = 1001;
|
||||||
|
};
|
||||||
|
|
||||||
|
As you can see brackets like C are used and structures looks like C but you
|
||||||
|
can also see that keywords like `channel`, `protocol`, `message` or some
|
||||||
|
predefined types like `uint32` are proper of the protocol.
|
||||||
|
|
||||||
|
Comments
|
||||||
|
--------
|
||||||
|
Both C and C++ style comments are supported
|
||||||
|
|
||||||
|
// this is a comment
|
||||||
|
/* this is a comment too
|
||||||
|
but can be split in multiple lines */
|
||||||
|
|
||||||
|
Base types
|
||||||
|
----------
|
||||||
|
|
||||||
|
All int from 8 to 64 bit (8, 16, 32 and 64) are supported either signed or unsigned.
|
||||||
|
Also you can pass one unix descriptor.
|
||||||
|
|
||||||
|
base_type ::= "int8"|"uint8"|"int16"|"uint16"|"int32"|"uint32"|"int64"|"uint64"|"unix_fd" ;
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
int16 x;
|
||||||
|
|
||||||
|
Enumerations and flags
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
It's possible to specify enumerations and flags. The difference is that flags are defined as 2 power
|
||||||
|
values and can be combined. Enumerations and flags must have a size (`8`, `16` or `32`) specified.
|
||||||
|
|
||||||
|
enum ::= <enum_type> "{" [ <enumflag_items> ] "}" <attributes> ";" ;
|
||||||
|
flag ::= <flag_type> "{" [ <enumflag_items> ] "}" <attributes> ";" ;
|
||||||
|
enum_type ::= "enum8"|"enum16"|"enum32" ;
|
||||||
|
flag_type ::= "flag8"|"flag16"|"flag32" ;
|
||||||
|
enumflag_items ::= <enumflag_item>|<enumflag_items><enumflag_item>
|
||||||
|
enumflag_item ::= <enum_name> [ "=" <integer> ] [ "," ] ;
|
||||||
|
enum_name ::= [a-z0-9_]* ;
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
enum16 Level {
|
||||||
|
LOW = 0x100,
|
||||||
|
MEDIUM,
|
||||||
|
HIGH = 0x1000
|
||||||
|
};
|
||||||
|
|
||||||
|
Variables
|
||||||
|
---------
|
||||||
|
|
||||||
|
As you should already have noted variables are similar to C syntax but there are
|
||||||
|
some differences.
|
||||||
|
|
||||||
|
variable ::= <type> [ "*" ] <identifier> [ "[" <array_size> "]" ] <attributes>;
|
||||||
|
|
||||||
|
The `*` specify a pointer. This is quite different from C. For the protocol it
|
||||||
|
specifies that in the protocol stream a relative offset is put that points to that
|
||||||
|
variable usually after all defined fields. This happens even on arrays, so for instance
|
||||||
|
|
||||||
|
int32 *n;
|
||||||
|
|
||||||
|
containing a 0x12345678 `n` value could ended up coded as
|
||||||
|
|
||||||
|
04 00 00 00 // 4 as offset
|
||||||
|
78 56 34 12 // `n`
|
||||||
|
|
||||||
|
(little endian). While an array of 2 items defined as
|
||||||
|
|
||||||
|
int32 *n[2];
|
||||||
|
|
||||||
|
and containing 0x12345678 and 0x9abcdef could end up with
|
||||||
|
|
||||||
|
04 00 00 00 // 4 as offset
|
||||||
|
78 56 34 12 // `n`[0]
|
||||||
|
ef cd ab 09 // `n`[1]
|
||||||
|
|
||||||
|
note that `int32 *n[2]` defined a pointer to an array of 2 items and not
|
||||||
|
an array of pointers as C.
|
||||||
|
|
||||||
|
*WARNING*: You should avoid using pointers on protocol if not necessary as they are complicated
|
||||||
|
to handle not using autogenerated code and also use more space on the network.
|
||||||
|
|
||||||
|
Arrays
|
||||||
|
------
|
||||||
|
|
||||||
|
As seen above the easiest way to define an array size is specifying a constant value.
|
||||||
|
However there are multiple way to specify the size
|
||||||
|
|
||||||
|
array_size ::= <integer>|<identifier>|""|<array_size_image>|<array_size_cstring> ;
|
||||||
|
array_size_image ::= "image_size" "(" <integer> "," <identifier> ")" ;
|
||||||
|
array_size_cstring ::= "cstring()" ;
|
||||||
|
|
||||||
|
We already seen integer.
|
||||||
|
Specifying an identifier name instead (should be variable) indicate that the length is specified
|
||||||
|
in another field, for instance
|
||||||
|
|
||||||
|
uint8 name_len;
|
||||||
|
int8 name[name_len];
|
||||||
|
|
||||||
|
allows to put a name of `name_len` len.
|
||||||
|
The empty value tells that the array will end when the containing message end so if we have
|
||||||
|
|
||||||
|
int8 name[];
|
||||||
|
|
||||||
|
and the message is
|
||||||
|
|
||||||
|
66 6f 6f
|
||||||
|
|
||||||
|
possibly the name we want is `foo` (66 6f 6f is the ASCII encoding for `foo`).
|
||||||
|
|
||||||
|
TODO: what happen with two [] in the structure ??
|
||||||
|
TODO: can a [] array not be the last and what happens ??
|
||||||
|
|
||||||
|
`image_size` allow to specify an array holding an image, for instance
|
||||||
|
|
||||||
|
uint16 width;
|
||||||
|
uint16 height;
|
||||||
|
uint8 raw_image[image_size(8, width, height)];
|
||||||
|
|
||||||
|
could contain row data in raw_image. The constant `8` is the bit size of the image.
|
||||||
|
|
||||||
|
`cstring` allows to specify NUL-terminated sequence so having
|
||||||
|
|
||||||
|
int8 name[cstring()];
|
||||||
|
|
||||||
|
and the message as
|
||||||
|
|
||||||
|
66 6f 6f 00
|
||||||
|
|
||||||
|
we'll have the `foo` name. Note that the field does not need to end the message as in `int8 name[]` example.
|
||||||
|
|
||||||
|
Structures
|
||||||
|
----------
|
||||||
|
|
||||||
|
The simplest compound type is the structure. As in C is defined as a list of fields (any variable or switch).
|
||||||
|
But as a protocol definition there are no alignment or padding and every field (beside pointer values) follow each other.
|
||||||
|
|
||||||
|
struct ::= "struct" <identifier> "{" [ <fields> ] "}" <attributes> ";" ;
|
||||||
|
fields ::= <field>|<fields><field> ;
|
||||||
|
field ::= <variable>|<switch>
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
struct Point {
|
||||||
|
int32 x;
|
||||||
|
int32 y;
|
||||||
|
};
|
||||||
|
|
||||||
|
Messages
|
||||||
|
--------
|
||||||
|
|
||||||
|
Messages have the same syntax of structure (beside `message`) with the difference that they can
|
||||||
|
be used directly inside channels.
|
||||||
|
|
||||||
|
message ::= "message" <identifier> "{" [ <fields> ] "}" <attributes> ";" ;
|
||||||
|
|
||||||
|
Switches
|
||||||
|
--------
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
|
Type definitions
|
||||||
|
----------------
|
||||||
|
|
||||||
|
Like C type definition allow to short types defining new ones.
|
||||||
|
|
||||||
|
typedef ::= "typedef" <identifier> <type> <attributes> ;
|
||||||
|
|
||||||
|
note that unlike C name came before the type.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
typedef XCoord int32;
|
||||||
|
|
||||||
|
Channels
|
||||||
|
--------
|
||||||
|
|
||||||
|
channel ::= "channel" <identifier> [ ":" <identifier> ] "{" <channel_messages> "}" <attributes> ";" ;
|
||||||
|
channel_messages ::= <channel_message>|<channel_messages><channel_message> ;
|
||||||
|
channel_message ::= "server:" | "client:" | "message" <identifier> [ "=" <integer> ] ;
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
channel ExampleChannel {
|
||||||
|
server:
|
||||||
|
message {
|
||||||
|
uint32 dummy;
|
||||||
|
} Dummy;
|
||||||
|
};
|
||||||
|
|
||||||
|
Note that every message is associated with a number which is used in the protocol.
|
||||||
|
The assignment work in a similar way to enumeration in C beside first message is
|
||||||
|
assigned 1 value and not 0. So first message (if no integer is specified) is assigned
|
||||||
|
1, second 2 and so on.
|
||||||
|
|
||||||
|
`server:` or `client:` specify the direction of messages following, `server` specify
|
||||||
|
messages from server while `client` from client. If not specified is assumed from
|
||||||
|
server.
|
||||||
|
|
||||||
|
For each channel you can specify a parent channel. Derived channel inherits all
|
||||||
|
messages specified in the parent.
|
||||||
|
Note that messages from parent can be overridden by derived channels.
|
||||||
|
|
||||||
|
Protocol
|
||||||
|
--------
|
||||||
|
|
||||||
|
protocol ::= "protocol" <identifier> "{" <protocol_channels> "}" ";" ;
|
||||||
|
protocol_channels ::= <protocol_channel>|<protocol_channels><protocol_channel> ;
|
||||||
|
protocol_channel ::= <identifier> <identifier> [ "=" <integer> ] ";" ;
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
protocol Example {
|
||||||
|
ExampleChannel first = 1001;
|
||||||
|
};
|
||||||
|
|
||||||
|
Protocol specify the list of channel supported. Channel have an associated number
|
||||||
|
assigned in a similar way of channels (incremented from one to the next with
|
||||||
|
first starting from 0 if not specified).
|
||||||
|
|
||||||
|
*NOTE*: Due to the way currently code is generate you should use
|
||||||
|
small numbers.
|
||||||
|
|
||||||
|
Attributes
|
||||||
|
----------
|
||||||
|
|
||||||
|
As you probably noted attributed can be specified for lot of definitions.
|
||||||
|
They allow to change code generated or specific constraints of the protocol.
|
||||||
|
|
||||||
|
attributes ::= ""|<attributes><attribute>|<attribute> ;
|
||||||
|
attribute ::= <attribute_name> [ "(" <attribute_values> ")" ] ;
|
||||||
|
attribute_values ::= <attribute_values> "," <attribute_value> | <attribute_value>
|
||||||
|
attribute_value ::= <integer> | <identifier>
|
||||||
|
attribute_name ::= @[a-z][a-z0-9_]* ;
|
||||||
|
|
||||||
|
Mostly of the attributes have no arguments, other currently have only one
|
||||||
|
argument.
|
||||||
|
|
||||||
|
*NOTE*: Some comments are also written in `spice-common` `python_modules/ptypes.py`
|
||||||
|
source file.
|
||||||
|
|
||||||
|
ctype
|
||||||
|
~~~~~
|
||||||
|
|
||||||
|
Specify the structure type name that the generated marshaller/demarshaller code
|
||||||
|
will use. By default the name will be converted to CamelCase and prefixed by
|
||||||
|
`Spice` so for example a structure like
|
||||||
|
|
||||||
|
struct Point {
|
||||||
|
int32 x;
|
||||||
|
int32 y;
|
||||||
|
} @ctype(MyPoint);
|
||||||
|
|
||||||
|
will be marshalled into a C structure like
|
||||||
|
|
||||||
|
struct MyPoint {
|
||||||
|
int32_t x;
|
||||||
|
int32_t y;
|
||||||
|
};
|
||||||
|
|
||||||
|
prefix
|
||||||
|
~~~~~~
|
||||||
|
|
||||||
|
This attribute allows to specify the prefix used for generated enumerations (both
|
||||||
|
protocol enumerations and flags generate C enumerations). By default the enumeration
|
||||||
|
will use upper case of the enum/flag name prefixed with `SPICE_` and followed by item so
|
||||||
|
|
||||||
|
enum32 level {
|
||||||
|
LOW,
|
||||||
|
HIGH,
|
||||||
|
};
|
||||||
|
|
||||||
|
will generate
|
||||||
|
|
||||||
|
typedef enum SpiceLevel {
|
||||||
|
SPICE_LEVEL_LOW,
|
||||||
|
SPICE_LEVEL_HIGH,
|
||||||
|
SPICE_LEVEL_ENUM_END
|
||||||
|
} SpiceLevel;
|
||||||
|
|
||||||
|
while
|
||||||
|
|
||||||
|
enum32 level {
|
||||||
|
LOW,
|
||||||
|
HIGH,
|
||||||
|
} @prefix(LVL_);
|
||||||
|
|
||||||
|
will generate
|
||||||
|
|
||||||
|
typedef enum SpiceLevel {
|
||||||
|
LVL_LOW,
|
||||||
|
LVL_HIGH,
|
||||||
|
SPICE_LEVEL_ENUM_END
|
||||||
|
} SpiceLevel;
|
||||||
|
|
||||||
|
(note that an automatic `END` enumeration is generated and name is not affected).
|
||||||
|
|
||||||
|
end
|
||||||
|
~~~
|
||||||
|
|
||||||
|
This attribute specifies that the data will be appended/embedded in the final C structure.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
struct test {
|
||||||
|
uint16 len;
|
||||||
|
uint16 array[len] @end;
|
||||||
|
};
|
||||||
|
|
||||||
|
Output C structure:
|
||||||
|
|
||||||
|
struct test {
|
||||||
|
uint16_t len;
|
||||||
|
uint16_t array[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
The generated code will allocate the C structure to allow space for extracted array.
|
||||||
|
|
||||||
|
*WARNING*: This option is usually confused with with empty size protocol. The
|
||||||
|
empty protocol array size specify array that extend on the network data while
|
||||||
|
the `@end` attribute specify to extend the C structure (for instance in the example
|
||||||
|
the attribute was attached to a `len`-sized array).
|
||||||
|
|
||||||
|
to_ptr
|
||||||
|
~~~~~~
|
||||||
|
|
||||||
|
This specifies that the corresponding C structure field contains a pointer to
|
||||||
|
the data. On marshalling the pointer is used, on demarshalling the data is
|
||||||
|
allocated in the memory block that holds the returned structure.
|
||||||
|
The type of this field must be a structure.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
struct test {
|
||||||
|
uint16 num;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct msg {
|
||||||
|
test ptr @to_ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
Output C structure:
|
||||||
|
|
||||||
|
struct test {
|
||||||
|
uint16_t num;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct msg {
|
||||||
|
struct test *ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
nocopy
|
||||||
|
~~~~~~
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
|
as_ptr
|
||||||
|
~~~~~~
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
|
nomarshal
|
||||||
|
~~~~~~~~~
|
||||||
|
|
||||||
|
Do not generate code for marshalling this variable.
|
||||||
|
Usually used on last array element to make possible to manually feed data.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
struct Data {
|
||||||
|
uint32 data_size;
|
||||||
|
uint8 data[data_size] @nomarshal;
|
||||||
|
};
|
||||||
|
|
||||||
|
zero_terminated
|
||||||
|
~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The field should terminated by zero.
|
||||||
|
Actually it's not used by python code so it's not enforced and no
|
||||||
|
code is generated.
|
||||||
|
|
||||||
|
marshall
|
||||||
|
~~~~~~~~
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
|
nonnull
|
||||||
|
~~~~~~~
|
||||||
|
|
||||||
|
This pointer field cannot be NULL. This means that marshaller assume C structure
|
||||||
|
contain not NULL pointer and demarshaller will fail to demarshall message if offset
|
||||||
|
is 0.
|
||||||
|
|
||||||
|
unique_flag
|
||||||
|
~~~~~~~~~~~
|
||||||
|
|
||||||
|
This flag field should contain just a single flag.
|
||||||
|
Actually it's not used by python code so it's not enforced and no
|
||||||
|
code is generated.
|
||||||
|
|
||||||
|
deprecated
|
||||||
|
~~~~~~~~~~
|
||||||
|
|
||||||
|
This flag currently apply only to enumerations and flags types and will set
|
||||||
|
generated C enumeration constant to deprecated
|
||||||
|
|
||||||
|
ptr_array
|
||||||
|
~~~~~~~~~
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
|
outvar
|
||||||
|
~~~~~~
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
|
anon
|
||||||
|
~~~~
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
|
chunk
|
||||||
|
~~~~~
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
|
ifdef
|
||||||
|
~~~~~
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
|
zero
|
||||||
|
~~~~
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
|
virtual
|
||||||
|
~~~~~~~
|
||||||
|
|
||||||
|
TODO
|
||||||
131
docs/spice_uri_scheme.txt
Normal file
131
docs/spice_uri_scheme.txt
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
The "spice" URI scheme
|
||||||
|
======================
|
||||||
|
|
||||||
|
This document is inspired by 'The "vnc" URI Scheme' (rfc7869) and
|
||||||
|
attempts to document a standard Spice URI scheme.
|
||||||
|
|
||||||
|
The normative syntax of the Spice URI is defined in the <spice-uri>
|
||||||
|
rule in the following syntax specification. This specification
|
||||||
|
uses the Augmented Backus-Naur Form (ABNF) as described in
|
||||||
|
[RFC5234]. The Spice URI conforms to the generic URI syntax
|
||||||
|
specified in [RFC3986]. The <userinfo>, <host>, <port>,
|
||||||
|
<unreserved>, and <pct-encoded> rules are defined in [RFC3986].
|
||||||
|
|
||||||
|
spice-uri = spice-scheme "://" [ userinfo "@" ] [ host [ ":" port ] ]
|
||||||
|
[ "?" [ spice-params ] ]
|
||||||
|
|
||||||
|
spice-scheme = "spice" / "spice+unix" / "spice+tls"
|
||||||
|
|
||||||
|
spice-params = param "=" value *("&" param "=" value) ["&"]
|
||||||
|
|
||||||
|
param = 1*( param-char )
|
||||||
|
|
||||||
|
value = *( param-char )
|
||||||
|
|
||||||
|
param-char = unreserved / pct-encoded / unreserved-symbols
|
||||||
|
|
||||||
|
unreserved-symbols = ":" / "/" / "@" / "!" / "$" / "'"
|
||||||
|
/ "(" / ")" / "*" / "," / ";"
|
||||||
|
|
||||||
|
The "?", "=", and "&" characters are used to delimit Spice parameters
|
||||||
|
and must be percent-encoded when representing a data octet as
|
||||||
|
specified in [RFC3986]. Within the <spice-params> portion of a Spice
|
||||||
|
URI, the <unreserved-symbols> do not have special meaning and need not
|
||||||
|
be percent-encoded when representing a data octet.
|
||||||
|
|
||||||
|
A Spice URI has the general form:
|
||||||
|
|
||||||
|
spice-scheme://host:port?param1=value1¶m2=value2...
|
||||||
|
|
||||||
|
The host information and each parameter value specify information
|
||||||
|
used in establishing or operating the remote desktop session as
|
||||||
|
specified in Section "URI Parameters".
|
||||||
|
|
||||||
|
URI Parameters
|
||||||
|
--------------
|
||||||
|
|
||||||
|
A description of host information and URI parameters is provided in
|
||||||
|
this section. Information on the constraints of various data types is
|
||||||
|
provided in Section "Data Types". All parameters are considered optional;
|
||||||
|
however, a client will not be able to connect without sufficient
|
||||||
|
information.
|
||||||
|
|
||||||
|
A parameter without a specified default value indicates that no
|
||||||
|
default value is implied by this URI scheme; however, Spice clients
|
||||||
|
can apply implementation-dependent default behaviors otherwise
|
||||||
|
consistent with this document.
|
||||||
|
|
||||||
|
The <host> and <port> values in the "spice://" and "spice+tls://" URIs
|
||||||
|
specify the address of the Spice server on the remote host:
|
||||||
|
|
||||||
|
[options="header"]
|
||||||
|
|=======================================================================
|
||||||
|
| Name | Type | Description | Default
|
||||||
|
| host | string | Spice server hostname or IP | none
|
||||||
|
| port | ushort | Spice server port | none
|
||||||
|
|=======================================================================
|
||||||
|
|
||||||
|
The <host> value in the "spice+unix://" URI specify the UNIX domain
|
||||||
|
socket path of the Spice server on the local host:
|
||||||
|
|
||||||
|
[options="header"]
|
||||||
|
|=======================================================================
|
||||||
|
| Name | Type | Description | Default
|
||||||
|
| host | string | UNIX domain socket path | none
|
||||||
|
|=======================================================================
|
||||||
|
|
||||||
|
The Spice URI parameter values specify remote desktop connection or
|
||||||
|
session properties, including aspects of client operation, usability,
|
||||||
|
and security as specified in the table below:
|
||||||
|
|
||||||
|
[options="header"]
|
||||||
|
|=======================================================================
|
||||||
|
| Name | Type | Description | Default
|
||||||
|
| port | ushort | Spice server port (legacy) | none
|
||||||
|
| tls-port | ushort | Spice server TLS port (legacy) | none
|
||||||
|
| password | string | Spice server password (legacy) | none
|
||||||
|
| ... | | |
|
||||||
|
|=======================================================================
|
||||||
|
|
||||||
|
Parameter names SHOULD be provided in the case specified in this
|
||||||
|
document; however, for compatibility, clients SHOULD accept
|
||||||
|
parameters in a case-insensitive manner. Values SHALL be interpreted
|
||||||
|
in a case-sensitive manner, unless otherwise noted.
|
||||||
|
|
||||||
|
Additional parameters likely to be useful with multiple Spice clients
|
||||||
|
can be added to the "URI Parameters" registry (at the moment,
|
||||||
|
discussed and approved on the Spice mailing list). Individual clients
|
||||||
|
MAY support parameters specific to that client. Spice clients
|
||||||
|
supporting application-specific parameters SHOULD include a
|
||||||
|
distinguishing prefix within the parameter name, such as the name of
|
||||||
|
the application package specified in source code except when precluded
|
||||||
|
by compatibility constraints. For example:
|
||||||
|
|
||||||
|
spice://?com.redhat.spiceclient.MonitorMapping=2&
|
||||||
|
|
||||||
|
It can also be expected that clients will maintain backward
|
||||||
|
compatibility with legacy URI formats and parameters.
|
||||||
|
|
||||||
|
Legacy software applications respond to "spice" URIs in different ways
|
||||||
|
and may fail to behave as expected. It is advisable to test "spice"
|
||||||
|
URIs with specific applications or consult application-specific
|
||||||
|
documentation.
|
||||||
|
|
||||||
|
Data Types
|
||||||
|
----------
|
||||||
|
|
||||||
|
Spice URIs can be percent-encoded as specified in [RFC3986] and MUST
|
||||||
|
be decoded. After decoding, the following type constraints and
|
||||||
|
semantics apply:
|
||||||
|
|
||||||
|
string
|
||||||
|
~~~~~~
|
||||||
|
|
||||||
|
Values of "string" type are UTF8-encoded strings as specified in
|
||||||
|
[RFC3629].
|
||||||
|
|
||||||
|
ushort
|
||||||
|
~~~~~~
|
||||||
|
|
||||||
|
The "ushort" values represent unsigned 16-bit integers expressed
|
||||||
|
in decimal digits with value between 0-65535 inclusive.
|
||||||
400
git.mk
Normal file
400
git.mk
Normal file
@ -0,0 +1,400 @@
|
|||||||
|
# git.mk, a small Makefile to autogenerate .gitignore files
|
||||||
|
# for autotools-based projects.
|
||||||
|
#
|
||||||
|
# Copyright 2009, Red Hat, Inc.
|
||||||
|
# Copyright 2010,2011,2012,2013 Behdad Esfahbod
|
||||||
|
# Written by Behdad Esfahbod
|
||||||
|
#
|
||||||
|
# Copying and distribution of this file, with or without modification,
|
||||||
|
# is permitted in any medium without royalty provided the copyright
|
||||||
|
# notice and this notice are preserved.
|
||||||
|
#
|
||||||
|
# The latest version of this file can be downloaded from:
|
||||||
|
GIT_MK_URL = https://raw.githubusercontent.com/behdad/git.mk/master/git.mk
|
||||||
|
#
|
||||||
|
# Bugs, etc, should be reported upstream at:
|
||||||
|
# https://github.com/behdad/git.mk
|
||||||
|
#
|
||||||
|
# To use in your project, import this file in your git repo's toplevel,
|
||||||
|
# then do "make -f git.mk". This modifies all Makefile.am files in
|
||||||
|
# your project to -include git.mk. Remember to add that line to new
|
||||||
|
# Makefile.am files you create in your project, or just rerun the
|
||||||
|
# "make -f git.mk".
|
||||||
|
#
|
||||||
|
# This enables automatic .gitignore generation. If you need to ignore
|
||||||
|
# more files, add them to the GITIGNOREFILES variable in your Makefile.am.
|
||||||
|
# But think twice before doing that. If a file has to be in .gitignore,
|
||||||
|
# chances are very high that it's a generated file and should be in one
|
||||||
|
# of MOSTLYCLEANFILES, CLEANFILES, DISTCLEANFILES, or MAINTAINERCLEANFILES.
|
||||||
|
#
|
||||||
|
# The only case that you need to manually add a file to GITIGNOREFILES is
|
||||||
|
# when remove files in one of mostlyclean-local, clean-local, distclean-local,
|
||||||
|
# or maintainer-clean-local make targets.
|
||||||
|
#
|
||||||
|
# Note that for files like editor backup, etc, there are better places to
|
||||||
|
# ignore them. See "man gitignore".
|
||||||
|
#
|
||||||
|
# If "make maintainer-clean" removes the files but they are not recognized
|
||||||
|
# by this script (that is, if "git status" shows untracked files still), send
|
||||||
|
# me the output of "git status" as well as your Makefile.am and Makefile for
|
||||||
|
# the directories involved and I'll diagnose.
|
||||||
|
#
|
||||||
|
# For a list of toplevel files that should be in MAINTAINERCLEANFILES, see
|
||||||
|
# Makefile.am.sample in the git.mk git repo.
|
||||||
|
#
|
||||||
|
# Don't EXTRA_DIST this file. It is supposed to only live in git clones,
|
||||||
|
# not tarballs. It serves no useful purpose in tarballs and clutters the
|
||||||
|
# build dir.
|
||||||
|
#
|
||||||
|
# This file knows how to handle autoconf, automake, libtool, gtk-doc,
|
||||||
|
# gnome-doc-utils, yelp.m4, mallard, intltool, gsettings, dejagnu, appdata,
|
||||||
|
# appstream, hotdoc.
|
||||||
|
#
|
||||||
|
# This makefile provides the following targets:
|
||||||
|
#
|
||||||
|
# - all: "make all" will build all gitignore files.
|
||||||
|
# - gitignore: makes all gitignore files in the current dir and subdirs.
|
||||||
|
# - .gitignore: make gitignore file for the current dir.
|
||||||
|
# - gitignore-recurse: makes all gitignore files in the subdirs.
|
||||||
|
#
|
||||||
|
# KNOWN ISSUES:
|
||||||
|
#
|
||||||
|
# - Recursive configure doesn't work as $(top_srcdir)/git.mk inside the
|
||||||
|
# submodule doesn't find us. If you have configure.{in,ac} files in
|
||||||
|
# subdirs, add a proxy git.mk file in those dirs that simply does:
|
||||||
|
# "include $(top_srcdir)/../git.mk". Add more ..'s to your taste.
|
||||||
|
# And add those files to git. See vte/gnome-pty-helper/git.mk for
|
||||||
|
# example.
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Variables user modules may want to add to toplevel MAINTAINERCLEANFILES:
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
#
|
||||||
|
# Most autotools-using modules should be fine including this variable in their
|
||||||
|
# toplevel MAINTAINERCLEANFILES:
|
||||||
|
GITIGNORE_MAINTAINERCLEANFILES_TOPLEVEL = \
|
||||||
|
$(srcdir)/aclocal.m4 \
|
||||||
|
$(srcdir)/autoscan.log \
|
||||||
|
$(srcdir)/configure.scan \
|
||||||
|
`AUX_DIR=$(srcdir)/$$(cd $(top_srcdir); $(AUTOCONF) --trace 'AC_CONFIG_AUX_DIR:$$1' ./configure.ac); \
|
||||||
|
test "x$$AUX_DIR" = "x$(srcdir)/" && AUX_DIR=$(srcdir); \
|
||||||
|
for x in \
|
||||||
|
ar-lib \
|
||||||
|
compile \
|
||||||
|
config.guess \
|
||||||
|
config.rpath \
|
||||||
|
config.sub \
|
||||||
|
depcomp \
|
||||||
|
install-sh \
|
||||||
|
ltmain.sh \
|
||||||
|
missing \
|
||||||
|
mkinstalldirs \
|
||||||
|
test-driver \
|
||||||
|
ylwrap \
|
||||||
|
; do echo "$$AUX_DIR/$$x"; done` \
|
||||||
|
`cd $(top_srcdir); $(AUTOCONF) --trace 'AC_CONFIG_HEADERS:$$1' ./configure.ac | \
|
||||||
|
head -n 1 | while read f; do echo "$(srcdir)/$$f.in"; done`
|
||||||
|
#
|
||||||
|
# All modules should also be fine including the following variable, which
|
||||||
|
# removes automake-generated Makefile.in files:
|
||||||
|
GITIGNORE_MAINTAINERCLEANFILES_MAKEFILE_IN = \
|
||||||
|
`cd $(top_srcdir); $(AUTOCONF) --trace 'AC_CONFIG_FILES:$$1' ./configure.ac | \
|
||||||
|
while read f; do \
|
||||||
|
case $$f in Makefile|*/Makefile) \
|
||||||
|
test -f "$(srcdir)/$$f.am" && echo "$(srcdir)/$$f.in";; esac; \
|
||||||
|
done`
|
||||||
|
#
|
||||||
|
# Modules that use libtool and use AC_CONFIG_MACRO_DIR() may also include this,
|
||||||
|
# though it's harmless to include regardless.
|
||||||
|
GITIGNORE_MAINTAINERCLEANFILES_M4_LIBTOOL = \
|
||||||
|
`MACRO_DIR=$(srcdir)/$$(cd $(top_srcdir); $(AUTOCONF) --trace 'AC_CONFIG_MACRO_DIR:$$1' ./configure.ac); \
|
||||||
|
if test "x$$MACRO_DIR" != "x$(srcdir)/"; then \
|
||||||
|
for x in \
|
||||||
|
libtool.m4 \
|
||||||
|
ltoptions.m4 \
|
||||||
|
ltsugar.m4 \
|
||||||
|
ltversion.m4 \
|
||||||
|
lt~obsolete.m4 \
|
||||||
|
; do echo "$$MACRO_DIR/$$x"; done; \
|
||||||
|
fi`
|
||||||
|
#
|
||||||
|
# Modules that use gettext and use AC_CONFIG_MACRO_DIR() may also include this,
|
||||||
|
# though it's harmless to include regardless.
|
||||||
|
GITIGNORE_MAINTAINERCLEANFILES_M4_GETTEXT = \
|
||||||
|
`MACRO_DIR=$(srcdir)/$$(cd $(top_srcdir); $(AUTOCONF) --trace 'AC_CONFIG_MACRO_DIR:$$1' ./configure.ac); \
|
||||||
|
if test "x$$MACRO_DIR" != "x$(srcdir)/"; then \
|
||||||
|
for x in \
|
||||||
|
codeset.m4 \
|
||||||
|
extern-inline.m4 \
|
||||||
|
fcntl-o.m4 \
|
||||||
|
gettext.m4 \
|
||||||
|
glibc2.m4 \
|
||||||
|
glibc21.m4 \
|
||||||
|
iconv.m4 \
|
||||||
|
intdiv0.m4 \
|
||||||
|
intl.m4 \
|
||||||
|
intldir.m4 \
|
||||||
|
intlmacosx.m4 \
|
||||||
|
intmax.m4 \
|
||||||
|
inttypes-pri.m4 \
|
||||||
|
inttypes_h.m4 \
|
||||||
|
lcmessage.m4 \
|
||||||
|
lib-ld.m4 \
|
||||||
|
lib-link.m4 \
|
||||||
|
lib-prefix.m4 \
|
||||||
|
lock.m4 \
|
||||||
|
longlong.m4 \
|
||||||
|
nls.m4 \
|
||||||
|
po.m4 \
|
||||||
|
printf-posix.m4 \
|
||||||
|
progtest.m4 \
|
||||||
|
size_max.m4 \
|
||||||
|
stdint_h.m4 \
|
||||||
|
threadlib.m4 \
|
||||||
|
uintmax_t.m4 \
|
||||||
|
visibility.m4 \
|
||||||
|
wchar_t.m4 \
|
||||||
|
wint_t.m4 \
|
||||||
|
xsize.m4 \
|
||||||
|
; do echo "$$MACRO_DIR/$$x"; done; \
|
||||||
|
fi`
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Default rule is to install ourselves in all Makefile.am files:
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
git-all: git-mk-install
|
||||||
|
|
||||||
|
git-mk-install:
|
||||||
|
@echo "Installing git makefile"
|
||||||
|
@any_failed=; \
|
||||||
|
find "`test -z "$(top_srcdir)" && echo . || echo "$(top_srcdir)"`" -name Makefile.am | while read x; do \
|
||||||
|
if grep 'include .*/git.mk' $$x >/dev/null; then \
|
||||||
|
echo "$$x already includes git.mk"; \
|
||||||
|
else \
|
||||||
|
failed=; \
|
||||||
|
echo "Updating $$x"; \
|
||||||
|
{ cat $$x; \
|
||||||
|
echo ''; \
|
||||||
|
echo '-include $$(top_srcdir)/git.mk'; \
|
||||||
|
} > $$x.tmp || failed=1; \
|
||||||
|
if test x$$failed = x; then \
|
||||||
|
mv $$x.tmp $$x || failed=1; \
|
||||||
|
fi; \
|
||||||
|
if test x$$failed = x; then : else \
|
||||||
|
echo "Failed updating $$x"; >&2 \
|
||||||
|
any_failed=1; \
|
||||||
|
fi; \
|
||||||
|
fi; done; test -z "$$any_failed"
|
||||||
|
|
||||||
|
git-mk-update:
|
||||||
|
wget $(GIT_MK_URL) -O $(top_srcdir)/git.mk
|
||||||
|
|
||||||
|
.PHONY: git-all git-mk-install git-mk-update
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Actual .gitignore generation:
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
$(srcdir)/.gitignore: Makefile.am $(top_srcdir)/git.mk $(top_srcdir)/configure.ac
|
||||||
|
@echo "git.mk: Generating $@"
|
||||||
|
@{ \
|
||||||
|
if test "x$(DOC_MODULE)" = x -o "x$(DOC_MAIN_SGML_FILE)" = x; then :; else \
|
||||||
|
for x in \
|
||||||
|
$(DOC_MODULE)-decl-list.txt \
|
||||||
|
$(DOC_MODULE)-decl.txt \
|
||||||
|
tmpl/$(DOC_MODULE)-unused.sgml \
|
||||||
|
"tmpl/*.bak" \
|
||||||
|
$(REPORT_FILES) \
|
||||||
|
$(DOC_MODULE).pdf \
|
||||||
|
xml html \
|
||||||
|
; do echo "/$$x"; done; \
|
||||||
|
FLAVOR=$$(cd $(top_srcdir); $(AUTOCONF) --trace 'GTK_DOC_CHECK:$$2' ./configure.ac); \
|
||||||
|
case $$FLAVOR in *no-tmpl*) echo /tmpl;; esac; \
|
||||||
|
if echo "$(SCAN_OPTIONS)" | grep -q "\-\-rebuild-types"; then \
|
||||||
|
echo "/$(DOC_MODULE).types"; \
|
||||||
|
fi; \
|
||||||
|
if echo "$(SCAN_OPTIONS)" | grep -q "\-\-rebuild-sections"; then \
|
||||||
|
echo "/$(DOC_MODULE)-sections.txt"; \
|
||||||
|
fi; \
|
||||||
|
if test "$(abs_srcdir)" != "$(abs_builddir)" ; then \
|
||||||
|
for x in \
|
||||||
|
$(SETUP_FILES) \
|
||||||
|
$(DOC_MODULE).types \
|
||||||
|
; do echo "/$$x"; done; \
|
||||||
|
fi; \
|
||||||
|
fi; \
|
||||||
|
if test "x$(DOC_MODULE)$(DOC_ID)" = x -o "x$(DOC_LINGUAS)" = x; then :; else \
|
||||||
|
for lc in $(DOC_LINGUAS); do \
|
||||||
|
for x in \
|
||||||
|
$(if $(DOC_MODULE),$(DOC_MODULE).xml) \
|
||||||
|
$(DOC_PAGES) \
|
||||||
|
$(DOC_INCLUDES) \
|
||||||
|
; do echo "/$$lc/$$x"; done; \
|
||||||
|
done; \
|
||||||
|
for x in \
|
||||||
|
$(_DOC_OMF_ALL) \
|
||||||
|
$(_DOC_DSK_ALL) \
|
||||||
|
$(_DOC_HTML_ALL) \
|
||||||
|
$(_DOC_MOFILES) \
|
||||||
|
$(DOC_H_FILE) \
|
||||||
|
"*/.xml2po.mo" \
|
||||||
|
"*/*.omf.out" \
|
||||||
|
; do echo /$$x; done; \
|
||||||
|
fi; \
|
||||||
|
if test "x$(HOTDOC)" = x; then :; else \
|
||||||
|
$(foreach project, $(HOTDOC_PROJECTS),echo "/$(call HOTDOC_TARGET,$(project))"; \
|
||||||
|
echo "/$(shell $(call HOTDOC_PROJECT_COMMAND,$(project)) --get-conf-path output)" ; \
|
||||||
|
echo "/$(shell $(call HOTDOC_PROJECT_COMMAND,$(project)) --get-private-folder)" ; \
|
||||||
|
) \
|
||||||
|
for x in \
|
||||||
|
.hotdoc.d \
|
||||||
|
; do echo "/$$x"; done; \
|
||||||
|
fi; \
|
||||||
|
if test "x$(HELP_ID)" = x -o "x$(HELP_LINGUAS)" = x; then :; else \
|
||||||
|
for lc in $(HELP_LINGUAS); do \
|
||||||
|
for x in \
|
||||||
|
$(HELP_FILES) \
|
||||||
|
"$$lc.stamp" \
|
||||||
|
"$$lc.mo" \
|
||||||
|
; do echo "/$$lc/$$x"; done; \
|
||||||
|
done; \
|
||||||
|
fi; \
|
||||||
|
if test "x$(gsettings_SCHEMAS)" = x; then :; else \
|
||||||
|
for x in \
|
||||||
|
$(gsettings_SCHEMAS:.xml=.valid) \
|
||||||
|
$(gsettings__enum_file) \
|
||||||
|
; do echo "/$$x"; done; \
|
||||||
|
fi; \
|
||||||
|
if test "x$(appdata_XML)" = x; then :; else \
|
||||||
|
for x in \
|
||||||
|
$(appdata_XML:.xml=.valid) \
|
||||||
|
; do echo "/$$x"; done; \
|
||||||
|
fi; \
|
||||||
|
if test "x$(appstream_XML)" = x; then :; else \
|
||||||
|
for x in \
|
||||||
|
$(appstream_XML:.xml=.valid) \
|
||||||
|
; do echo "/$$x"; done; \
|
||||||
|
fi; \
|
||||||
|
if test -f $(srcdir)/po/Makefile.in.in; then \
|
||||||
|
for x in \
|
||||||
|
ABOUT-NLS \
|
||||||
|
po/Makefile.in.in \
|
||||||
|
po/Makefile.in.in~ \
|
||||||
|
po/Makefile.in \
|
||||||
|
po/Makefile \
|
||||||
|
po/Makevars.template \
|
||||||
|
po/POTFILES \
|
||||||
|
po/Rules-quot \
|
||||||
|
po/stamp-it \
|
||||||
|
po/stamp-po \
|
||||||
|
po/.intltool-merge-cache \
|
||||||
|
"po/*.gmo" \
|
||||||
|
"po/*.header" \
|
||||||
|
"po/*.mo" \
|
||||||
|
"po/*.sed" \
|
||||||
|
"po/*.sin" \
|
||||||
|
po/$(GETTEXT_PACKAGE).pot \
|
||||||
|
intltool-extract.in \
|
||||||
|
intltool-merge.in \
|
||||||
|
intltool-update.in \
|
||||||
|
; do echo "/$$x"; done; \
|
||||||
|
fi; \
|
||||||
|
if test -f $(srcdir)/configure; then \
|
||||||
|
for x in \
|
||||||
|
autom4te.cache \
|
||||||
|
configure \
|
||||||
|
config.h \
|
||||||
|
stamp-h1 \
|
||||||
|
libtool \
|
||||||
|
config.lt \
|
||||||
|
; do echo "/$$x"; done; \
|
||||||
|
fi; \
|
||||||
|
if test "x$(DEJATOOL)" = x; then :; else \
|
||||||
|
for x in \
|
||||||
|
$(DEJATOOL) \
|
||||||
|
; do echo "/$$x.sum"; echo "/$$x.log"; done; \
|
||||||
|
echo /site.exp; \
|
||||||
|
fi; \
|
||||||
|
if test "x$(am__dirstamp)" = x; then :; else \
|
||||||
|
echo "$(am__dirstamp)"; \
|
||||||
|
fi; \
|
||||||
|
if test "x$(findstring libtool,$(LTCOMPILE))" = x -a "x$(findstring libtool,$(LTCXXCOMPILE))" = x -a "x$(GTKDOC_RUN)" = x; then :; else \
|
||||||
|
for x in \
|
||||||
|
"*.lo" \
|
||||||
|
".libs" "_libs" \
|
||||||
|
; do echo "$$x"; done; \
|
||||||
|
fi; \
|
||||||
|
for x in \
|
||||||
|
.gitignore \
|
||||||
|
$(GITIGNOREFILES) \
|
||||||
|
$(CLEANFILES) \
|
||||||
|
$(PROGRAMS) $(check_PROGRAMS) $(EXTRA_PROGRAMS) \
|
||||||
|
$(LIBRARIES) $(check_LIBRARIES) $(EXTRA_LIBRARIES) \
|
||||||
|
$(LTLIBRARIES) $(check_LTLIBRARIES) $(EXTRA_LTLIBRARIES) \
|
||||||
|
so_locations \
|
||||||
|
$(MOSTLYCLEANFILES) \
|
||||||
|
$(TEST_LOGS) \
|
||||||
|
$(TEST_LOGS:.log=.trs) \
|
||||||
|
$(TEST_SUITE_LOG) \
|
||||||
|
$(TESTS:=.test) \
|
||||||
|
"*.gcda" \
|
||||||
|
"*.gcno" \
|
||||||
|
$(DISTCLEANFILES) \
|
||||||
|
$(am__CONFIG_DISTCLEAN_FILES) \
|
||||||
|
$(CONFIG_CLEAN_FILES) \
|
||||||
|
TAGS ID GTAGS GRTAGS GSYMS GPATH tags \
|
||||||
|
"*.tab.c" \
|
||||||
|
$(MAINTAINERCLEANFILES) \
|
||||||
|
$(BUILT_SOURCES) \
|
||||||
|
$(patsubst %.vala,%.c,$(filter %.vala,$(SOURCES))) \
|
||||||
|
$(filter %_vala.stamp,$(DIST_COMMON)) \
|
||||||
|
$(filter %.vapi,$(DIST_COMMON)) \
|
||||||
|
$(filter $(addprefix %,$(notdir $(patsubst %.vapi,%.h,$(filter %.vapi,$(DIST_COMMON))))),$(DIST_COMMON)) \
|
||||||
|
Makefile \
|
||||||
|
Makefile.in \
|
||||||
|
"*.orig" \
|
||||||
|
"*.rej" \
|
||||||
|
"*.bak" \
|
||||||
|
"*~" \
|
||||||
|
".*.sw[nop]" \
|
||||||
|
".dirstamp" \
|
||||||
|
; do echo "/$$x"; done; \
|
||||||
|
for x in \
|
||||||
|
"*.$(OBJEXT)" \
|
||||||
|
$(DEPDIR) \
|
||||||
|
; do echo "$$x"; done; \
|
||||||
|
} | \
|
||||||
|
sed "s@^/`echo "$(srcdir)" | sed 's/\(.\)/[\1]/g'`/@/@" | \
|
||||||
|
sed 's@/[.]/@/@g' | \
|
||||||
|
LC_ALL=C sort | uniq > $@.tmp && \
|
||||||
|
mv $@.tmp $@;
|
||||||
|
|
||||||
|
all: $(srcdir)/.gitignore gitignore-recurse-maybe
|
||||||
|
gitignore: $(srcdir)/.gitignore gitignore-recurse
|
||||||
|
|
||||||
|
gitignore-recurse-maybe:
|
||||||
|
@for subdir in $(DIST_SUBDIRS); do \
|
||||||
|
case " $(SUBDIRS) " in \
|
||||||
|
*" $$subdir "*) :;; \
|
||||||
|
*) test "$$subdir" = . -o -e "$$subdir/.git" || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) gitignore || echo "Skipping $$subdir");; \
|
||||||
|
esac; \
|
||||||
|
done
|
||||||
|
gitignore-recurse:
|
||||||
|
@for subdir in $(DIST_SUBDIRS); do \
|
||||||
|
test "$$subdir" = . -o -e "$$subdir/.git" || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) gitignore || echo "Skipping $$subdir"); \
|
||||||
|
done
|
||||||
|
|
||||||
|
maintainer-clean: gitignore-clean
|
||||||
|
gitignore-clean:
|
||||||
|
-rm -f $(srcdir)/.gitignore
|
||||||
|
|
||||||
|
.PHONY: gitignore-clean gitignore gitignore-recurse gitignore-recurse-maybe
|
||||||
0
m4/.gitignore
vendored
Normal file
0
m4/.gitignore
vendored
Normal file
49
m4/ax_python_module.m4
Normal file
49
m4/ax_python_module.m4
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
# ===========================================================================
|
||||||
|
# http://www.gnu.org/software/autoconf-archive/ax_python_module.html
|
||||||
|
# ===========================================================================
|
||||||
|
#
|
||||||
|
# SYNOPSIS
|
||||||
|
#
|
||||||
|
# AX_PYTHON_MODULE(modname[, fatal])
|
||||||
|
#
|
||||||
|
# DESCRIPTION
|
||||||
|
#
|
||||||
|
# Checks for Python module.
|
||||||
|
#
|
||||||
|
# If fatal is non-empty then absence of a module will trigger an error.
|
||||||
|
#
|
||||||
|
# LICENSE
|
||||||
|
#
|
||||||
|
# Copyright (c) 2008 Andrew Collier
|
||||||
|
#
|
||||||
|
# Copying and distribution of this file, with or without modification, are
|
||||||
|
# permitted in any medium without royalty provided the copyright notice
|
||||||
|
# and this notice are preserved. This file is offered as-is, without any
|
||||||
|
# warranty.
|
||||||
|
|
||||||
|
#serial 6
|
||||||
|
|
||||||
|
AU_ALIAS([AC_PYTHON_MODULE], [AX_PYTHON_MODULE])
|
||||||
|
AC_DEFUN([AX_PYTHON_MODULE],[
|
||||||
|
if test -z $PYTHON;
|
||||||
|
then
|
||||||
|
PYTHON="python"
|
||||||
|
fi
|
||||||
|
PYTHON_NAME=`basename $PYTHON`
|
||||||
|
AC_MSG_CHECKING($PYTHON_NAME module: $1)
|
||||||
|
$PYTHON -c "import $1" 2>/dev/null
|
||||||
|
if test $? -eq 0;
|
||||||
|
then
|
||||||
|
AC_MSG_RESULT(yes)
|
||||||
|
eval AS_TR_CPP(HAVE_PYMOD_$1)=yes
|
||||||
|
else
|
||||||
|
AC_MSG_RESULT(no)
|
||||||
|
eval AS_TR_CPP(HAVE_PYMOD_$1)=no
|
||||||
|
#
|
||||||
|
if test -n "$2"
|
||||||
|
then
|
||||||
|
AC_MSG_ERROR(failed to find required module $1)
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
])
|
||||||
6
m4/common.m4
Normal file
6
m4/common.m4
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
dnl This file should be included by spice-common user from
|
||||||
|
dnl configure.ac to have all required checks in order to use spice-common
|
||||||
|
m4_define(spice_common_dir,m4_bpatsubst(__file__,[/m4/common\.m4],[]))dnl
|
||||||
|
dnl Automatically include m4 files in m4 directory
|
||||||
|
AC_CONFIG_MACRO_DIRS(spice_common_dir[/m4])dnl
|
||||||
|
SPICE_COMMON(spice_common_dir)
|
||||||
368
m4/spice-deps.m4
Normal file
368
m4/spice-deps.m4
Normal file
@ -0,0 +1,368 @@
|
|||||||
|
# SPICE_WARNING(warning)
|
||||||
|
# SPICE_PRINT_MESSAGES
|
||||||
|
# ----------------------
|
||||||
|
# Collect warnings and print them at the end so they are clearly visible.
|
||||||
|
# ---------------------
|
||||||
|
AC_DEFUN([SPICE_WARNING],[AS_VAR_APPEND([spice_warnings],["|$1"])])
|
||||||
|
AC_DEFUN([SPICE_PRINT_MESSAGES],[
|
||||||
|
ac_save_IFS="$IFS"
|
||||||
|
IFS="|"
|
||||||
|
for msg in $spice_warnings; do
|
||||||
|
IFS="$ac_save_IFS"
|
||||||
|
AS_VAR_IF([msg],[],,[AC_MSG_WARN([$msg]); echo >&2])
|
||||||
|
done
|
||||||
|
IFS="$ac_save_IFS"
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
# SPICE_EXTRA_CHECKS()
|
||||||
|
# --------------------
|
||||||
|
# Check for --enable-extra-checks option
|
||||||
|
# --------------------
|
||||||
|
AC_DEFUN([SPICE_EXTRA_CHECKS],[
|
||||||
|
AC_ARG_ENABLE([extra-checks],
|
||||||
|
AS_HELP_STRING([--enable-extra-checks=@<:@yes/no@:>@],
|
||||||
|
[Enable expensive checks @<:@default=no@:>@]))
|
||||||
|
AM_CONDITIONAL(ENABLE_EXTRA_CHECKS, test "x$enable_extra_checks" = "xyes")
|
||||||
|
AM_COND_IF([ENABLE_EXTRA_CHECKS], AC_DEFINE([ENABLE_EXTRA_CHECKS], 1, [Enable extra checks on code]))
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
# SPICE_CHECK_SYSDEPS()
|
||||||
|
# ---------------------
|
||||||
|
# Checks for header files and library functions needed by spice-common.
|
||||||
|
# ---------------------
|
||||||
|
AC_DEFUN([SPICE_CHECK_SYSDEPS], [
|
||||||
|
AC_C_BIGENDIAN
|
||||||
|
AC_FUNC_ALLOCA
|
||||||
|
AC_CHECK_HEADERS([arpa/inet.h netinet/in.h stdlib.h sys/socket.h unistd.h])
|
||||||
|
|
||||||
|
# Checks for typedefs, structures, and compiler characteristics
|
||||||
|
AC_C_INLINE
|
||||||
|
|
||||||
|
# Checks for library functions
|
||||||
|
# do not check malloc or realloc, since that cannot be cross-compiled checked
|
||||||
|
AC_CHECK_FUNCS([floor])
|
||||||
|
AC_SEARCH_LIBS([hypot], [m], [], [
|
||||||
|
AC_MSG_ERROR([unable to find the hypot() function])
|
||||||
|
])
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
# SPICE_CHECK_SMARTCARD
|
||||||
|
# ---------------------
|
||||||
|
# Adds a --enable-smartcard switch in order to enable/disable smartcard
|
||||||
|
# support, and checks if the needed libraries are available. If found, it will
|
||||||
|
# return the flags to use in the SMARTCARD_CFLAGS and SMARTCARD_LIBS variables, and
|
||||||
|
# it will define a USE_SMARTCARD preprocessor symbol as well as a HAVE_SMARTCARD
|
||||||
|
# Makefile conditional.
|
||||||
|
#----------------------
|
||||||
|
AC_DEFUN([SPICE_CHECK_SMARTCARD], [
|
||||||
|
AC_ARG_ENABLE([smartcard],
|
||||||
|
AS_HELP_STRING([--enable-smartcard=@<:@yes/no/auto@:>@],
|
||||||
|
[Enable smartcard support @<:@default=auto@:>@]),
|
||||||
|
[],
|
||||||
|
[enable_smartcard="auto"])
|
||||||
|
|
||||||
|
have_smartcard=no
|
||||||
|
if test "x$enable_smartcard" != "xno"; then
|
||||||
|
PKG_CHECK_MODULES([SMARTCARD], [libcacard >= 2.5.1], [have_smartcard=yes], [have_smartcard=no])
|
||||||
|
if test "x$enable_smartcard" = "xyes" && test "x$have_smartcard" = "xno"; then
|
||||||
|
AC_MSG_ERROR([smarcard support explicitly requested, but some required packages are not available])
|
||||||
|
fi
|
||||||
|
if test "x$have_smartcard" = "xyes"; then
|
||||||
|
AC_DEFINE(USE_SMARTCARD, [1], [Define if supporting smartcard proxying])
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
AM_CONDITIONAL(HAVE_SMARTCARD, test "x$have_smartcard" = "xyes")
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
# SPICE_CHECK_OPUS
|
||||||
|
# ----------------
|
||||||
|
# Check for the availability of Opus. If found, it will return the flags to use
|
||||||
|
# in the OPUS_CFLAGS and OPUS_LIBS variables, and it will define a
|
||||||
|
# HAVE_OPUS preprocessor symbol as well as a HAVE_OPUS Makefile conditional.
|
||||||
|
# ----------------
|
||||||
|
AC_DEFUN([SPICE_CHECK_OPUS], [
|
||||||
|
AC_ARG_ENABLE([opus],
|
||||||
|
[ --disable-opus Disable Opus audio codec (enabled by default)],,
|
||||||
|
[enable_opus="auto"])
|
||||||
|
if test "x$enable_opus" != "xno"; then
|
||||||
|
PKG_CHECK_MODULES([OPUS], [opus >= 0.9.14], [have_opus=yes], [have_opus=no])
|
||||||
|
if test "x$enable_opus" = "xauto" && test "x$have_opus" = "xno"; then
|
||||||
|
AC_MSG_ERROR([Opus could not be detected, explicitly use --disable-opus if that's intentional])
|
||||||
|
fi
|
||||||
|
if test "x$enable_opus" = "xyes" && test "x$have_opus" != "xyes"; then
|
||||||
|
AC_MSG_ERROR([--enable-opus has been specified, but Opus is missing])
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
AM_CONDITIONAL([HAVE_OPUS], [test "x$have_opus" = "xyes"])
|
||||||
|
AM_COND_IF([HAVE_OPUS], AC_DEFINE([HAVE_OPUS], [1], [Define if we have OPUS]))
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
# SPICE_CHECK_PIXMAN
|
||||||
|
# ------------------
|
||||||
|
# Check for the availability of pixman. If found, it will return the flags to
|
||||||
|
# use in the PIXMAN_CFLAGS and PIXMAN_LIBS variables.
|
||||||
|
#-------------------
|
||||||
|
AC_DEFUN([SPICE_CHECK_PIXMAN], [
|
||||||
|
PKG_CHECK_MODULES(PIXMAN, pixman-1 >= 0.17.7)
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
# SPICE_CHECK_GLIB2
|
||||||
|
# -----------------
|
||||||
|
# Check for the availability of glib2. If found, it will return the flags to
|
||||||
|
# use in the GLIB2_CFLAGS and GLIB2_LIBS variables.
|
||||||
|
#------------------
|
||||||
|
AC_DEFUN([SPICE_CHECK_GLIB2], [
|
||||||
|
PKG_CHECK_MODULES(GLIB2, glib-2.0 >= 2.38)
|
||||||
|
PKG_CHECK_MODULES(GIO2, gio-2.0 >= 2.38)
|
||||||
|
GLIB2_CFLAGS="$GLIB2_CFLAGS -DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_38 -DGLIB_VERSION_MAX_ALLOWED=GLIB_VERSION_2_38"
|
||||||
|
])
|
||||||
|
|
||||||
|
# SPICE_CHECK_GDK_PIXBUF
|
||||||
|
# ----------------------
|
||||||
|
# Check for the availability of gdk-pixbuf. If found, it will return the flags to use
|
||||||
|
# in the GDK_PIXBUF_CFLAGS and GDK_PIXBUF_LIBS variables, and it will define a
|
||||||
|
# HAVE_GDK_PIXBUF preprocessor symbol as well as a HAVE_GDK_PIXBUF Makefile conditional.
|
||||||
|
# ----------------
|
||||||
|
AC_DEFUN([SPICE_CHECK_GDK_PIXBUF], [
|
||||||
|
PKG_CHECK_MODULES([GDK_PIXBUF], [gdk-pixbuf-2.0 >= 2.26], [have_gdk_pixbuf=yes], [have_gdk_pixbuf=no])
|
||||||
|
|
||||||
|
AM_CONDITIONAL([HAVE_GDK_PIXBUF], [test "x$have_gdk_pixbuf" = "xyes"])
|
||||||
|
AM_COND_IF([HAVE_GDK_PIXBUF], AC_DEFINE([HAVE_GDK_PIXBUF], [1], [Define if gdk-pixbuf was found]))
|
||||||
|
])
|
||||||
|
|
||||||
|
# SPICE_CHECK_PYTHON_MODULES()
|
||||||
|
# --------------------------
|
||||||
|
# Adds a --enable-python-checks configure flags as well as checks for the
|
||||||
|
# availability of the python modules needed by the python scripts generating
|
||||||
|
# C code from spice.proto. These checks are not needed when building from
|
||||||
|
# tarballs so they are disabled by default.
|
||||||
|
#---------------------------
|
||||||
|
AC_DEFUN([SPICE_CHECK_PYTHON_MODULES], [
|
||||||
|
AC_ARG_ENABLE([python-checks],
|
||||||
|
AS_HELP_STRING([--enable-python-checks=@<:@yes/no@:>@],
|
||||||
|
[Enable checks for Python modules needed to build from git @<:@default=no@:>@]),
|
||||||
|
[],
|
||||||
|
[enable_python_checks="no"])
|
||||||
|
if test "x$enable_python_checks" != "xno"; then
|
||||||
|
AS_IF([test -n "$PYTHON"], # already set required PYTHON version
|
||||||
|
[AM_PATH_PYTHON
|
||||||
|
AX_PYTHON_MODULE([pyparsing], [1])],
|
||||||
|
[PYTHON=python3
|
||||||
|
AX_PYTHON_MODULE([pyparsing])
|
||||||
|
test "$HAVE_PYMOD_PYPARSING" = "yes"],
|
||||||
|
[AM_PATH_PYTHON([3])],
|
||||||
|
[AC_MSG_ERROR([Python module pyparsing is required])])
|
||||||
|
else
|
||||||
|
AM_PATH_PYTHON
|
||||||
|
fi
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
# SPICE_CHECK_LZ4
|
||||||
|
# ---------------
|
||||||
|
# Adds a --enable-lz4 switch in order to enable/disable LZ4 compression
|
||||||
|
# support, and checks if the needed libraries are available. If found, it will
|
||||||
|
# return the flags to use in the LZ4_CFLAGS and LZ4_LIBS variables, and
|
||||||
|
# it will define a USE_LZ4 preprocessor symbol and a HAVE_LZ4 conditional.
|
||||||
|
# ---------------
|
||||||
|
AC_DEFUN([SPICE_CHECK_LZ4], [
|
||||||
|
AC_ARG_ENABLE([lz4],
|
||||||
|
AS_HELP_STRING([--enable-lz4=@<:@yes/no/auto@:>@],
|
||||||
|
[Enable LZ4 compression support @<:@default=auto@:>@]),
|
||||||
|
[],
|
||||||
|
[enable_lz4="auto"])
|
||||||
|
|
||||||
|
have_lz4="no"
|
||||||
|
if test "x$enable_lz4" != "xno"; then
|
||||||
|
# LZ4_compress_default is available in liblz4 >= 129, however liblz has changed
|
||||||
|
# versioning scheme making the check failing. Rather check for function definition
|
||||||
|
PKG_CHECK_MODULES([LZ4], [liblz4], [have_lz4="yes"], [have_lz4="no"])
|
||||||
|
|
||||||
|
if test "x$have_lz4" = "xyes"; then
|
||||||
|
# It is necessary to set LIBS and CFLAGS before AC_CHECK_FUNC
|
||||||
|
old_LIBS="$LIBS"
|
||||||
|
old_CFLAGS="$CFLAGS"
|
||||||
|
CFLAGS="$CFLAGS $LZ4_CFLAGS"
|
||||||
|
LIBS="$LIBS $LZ4_LIBS"
|
||||||
|
|
||||||
|
AC_CHECK_FUNC([LZ4_compress_default], [
|
||||||
|
AC_DEFINE(USE_LZ4, [1], [Define to build with lz4 support])],
|
||||||
|
[have_lz4="no"])
|
||||||
|
AC_CHECK_FUNCS([LZ4_compress_fast_continue])
|
||||||
|
|
||||||
|
LIBS="$old_LIBS"
|
||||||
|
CFLAGS="$old_CFLAGS"
|
||||||
|
fi
|
||||||
|
if test "x$enable_lz4" = "xyes" && test "x$have_lz4" = "xno"; then
|
||||||
|
AC_MSG_ERROR([lz4 support requested but liblz4 >= 129 could not be found])
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
AM_CONDITIONAL(HAVE_LZ4, test "x$have_lz4" = "xyes")
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
# SPICE_CHECK_GSTREAMER(VAR, version, packages-to-check-for, [action-if-found, [action-if-not-found]])
|
||||||
|
# ---------------------
|
||||||
|
# Checks whether the specified GStreamer modules are present and sets the
|
||||||
|
# corresponding autoconf variables and preprocessor definitions.
|
||||||
|
# ---------------------
|
||||||
|
AC_DEFUN([SPICE_CHECK_GSTREAMER], [
|
||||||
|
AS_VAR_PUSHDEF([have_gst],[have_]m4_tolower([$1]))dnl
|
||||||
|
AS_VAR_PUSHDEF([gst_inspect],[GST_INSPECT_$2])dnl
|
||||||
|
PKG_CHECK_MODULES([$1], [$3],
|
||||||
|
[have_gst="yes"
|
||||||
|
AC_SUBST(AS_TR_SH([[$1]_CFLAGS]))
|
||||||
|
AC_SUBST(AS_TR_SH([[$1]_LIBS]))
|
||||||
|
AS_VAR_APPEND([SPICE_REQUIRES], [" $3"])
|
||||||
|
AC_DEFINE(AS_TR_SH([HAVE_$1]), [1], [Define if supporting GStreamer $2])
|
||||||
|
AC_PATH_PROG(gst_inspect, gst-inspect-$2)
|
||||||
|
AS_IF([test "x$gst_inspect" = x],
|
||||||
|
SPICE_WARNING([Cannot verify that the required runtime GStreamer $2 elements are present because gst-inspect-$2 is missing]))
|
||||||
|
$4],
|
||||||
|
[have_gst="no"
|
||||||
|
$5])
|
||||||
|
AS_VAR_POPDEF([gst_inspect])dnl
|
||||||
|
AS_VAR_POPDEF([have_gst])dnl
|
||||||
|
])
|
||||||
|
|
||||||
|
# SPICE_CHECK_GSTREAMER_ELEMENTS(gst-inspect, package, elements-to-check-for)
|
||||||
|
# ---------------------
|
||||||
|
# Checks that the specified GStreamer elements are installed. If not it
|
||||||
|
# issues a warning and sets missing_gstreamer_elements.
|
||||||
|
# ---------------------
|
||||||
|
AC_DEFUN([SPICE_CHECK_GSTREAMER_ELEMENTS], [
|
||||||
|
AS_IF([test "x$1" != x],
|
||||||
|
[missing=""
|
||||||
|
for element in $3
|
||||||
|
do
|
||||||
|
AS_VAR_PUSHDEF([cache_var],[spice_cv_prog_${1}_${element}])dnl
|
||||||
|
AC_CACHE_CHECK([for the $element GStreamer element], cache_var,
|
||||||
|
[found=no
|
||||||
|
"$1" $element >/dev/null 2>/dev/null && found=yes
|
||||||
|
eval "cache_var=$found"])
|
||||||
|
AS_VAR_COPY(res, cache_var)
|
||||||
|
AS_IF([test "x$res" = "xno"], [missing="$missing $element"])
|
||||||
|
AS_VAR_POPDEF([cache_var])dnl
|
||||||
|
done
|
||||||
|
AS_IF([test "x$missing" != x],
|
||||||
|
[SPICE_WARNING([The$missing GStreamer element(s) are missing. You should be able to find them in the $2 package.])
|
||||||
|
missing_gstreamer_elements="yes"],
|
||||||
|
[test "x$missing_gstreamer_elements" = x],
|
||||||
|
[missing_gstreamer_elements="no"])
|
||||||
|
])
|
||||||
|
])
|
||||||
|
|
||||||
|
# SPICE_CHECK_SASL
|
||||||
|
# ----------------
|
||||||
|
# Adds a --with-sasl switch to allow using SASL for authentication.
|
||||||
|
# Checks whether the required library is available. If it is present,
|
||||||
|
# it will return the flags to use in SASL_CFLAGS and SASL_LIBS variables,
|
||||||
|
# and it will define a have_sasl configure variable and a HAVE_SASL preprocessor
|
||||||
|
# symbol.
|
||||||
|
# ----------------
|
||||||
|
AC_DEFUN([SPICE_CHECK_SASL], [
|
||||||
|
AC_ARG_WITH([sasl],
|
||||||
|
[AS_HELP_STRING([--with-sasl=@<:@yes/no/auto@:>@],
|
||||||
|
[use cyrus SASL for authentication @<:@default=auto@:>@])],
|
||||||
|
[],
|
||||||
|
[with_sasl="auto"])
|
||||||
|
|
||||||
|
have_sasl=no
|
||||||
|
if test "x$with_sasl" != "xno"; then
|
||||||
|
PKG_CHECK_MODULES([SASL], [libsasl2], [have_sasl=yes],[have_sasl=no])
|
||||||
|
if test "x$have_sasl" = "xno" && test "x$with_sasl" = "xyes"; then
|
||||||
|
AC_MSG_ERROR([Cyrus SASL support requested but libsasl2 could not be found])
|
||||||
|
fi
|
||||||
|
if test "x$have_sasl" = "xyes"; then
|
||||||
|
AC_DEFINE([HAVE_SASL], 1, [whether Cyrus SASL is available for authentication])
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
])
|
||||||
|
|
||||||
|
# SPICE_CHECK_OPENSSL
|
||||||
|
# -----------------
|
||||||
|
# Check for the availability of openssl. If found, it will return the flags to
|
||||||
|
# use in the OPENSSL_CFLAGS and OPENSSL_LIBS variables.
|
||||||
|
#------------------
|
||||||
|
AC_DEFUN([SPICE_CHECK_OPENSSL], [
|
||||||
|
PKG_CHECK_MODULES(OPENSSL, openssl)
|
||||||
|
])
|
||||||
|
|
||||||
|
# SPICE_CHECK_UDEV
|
||||||
|
# -----------------
|
||||||
|
# Check for the availability of libudev. If found, it will help to determine
|
||||||
|
# if a given vendor GPU is available or not.
|
||||||
|
#------------------
|
||||||
|
AC_DEFUN([SPICE_CHECK_UDEV], [
|
||||||
|
PKG_CHECK_MODULES([UDEV], [libudev], [have_udev=yes],[have_udev=no])
|
||||||
|
if test "x$have_udev" = "xyes"; then
|
||||||
|
AC_DEFINE([HAVE_UDEV], 1, [whether libudev is available to identify GPU])
|
||||||
|
fi
|
||||||
|
])
|
||||||
|
|
||||||
|
# SPICE_CHECK_INSTRUMENTATION
|
||||||
|
# -----------------
|
||||||
|
# Check for the availability of an instrumentation library.
|
||||||
|
#------------------
|
||||||
|
AC_DEFUN([SPICE_CHECK_INSTRUMENTATION], [
|
||||||
|
AC_ARG_ENABLE([instrumentation],
|
||||||
|
AS_HELP_STRING([--enable-instrumentation=@<:@recorder/agent/no@:>@],
|
||||||
|
[Enable instrumentation @<:@default=no@:>@]),
|
||||||
|
[],
|
||||||
|
enable_instrumentation="no")
|
||||||
|
AS_IF([test "$enable_instrumentation" = "recorder"],
|
||||||
|
AC_DEFINE([ENABLE_RECORDER], [1], [Define if the recorder instrumentation is enabled]))
|
||||||
|
AS_IF([test "$enable_instrumentation" = "agent"],
|
||||||
|
AC_DEFINE([ENABLE_AGENT_INTERFACE], [1], [Define if the agent-interface instrumentation is enabled]))
|
||||||
|
AM_CONDITIONAL([ENABLE_RECORDER],[test "$enable_instrumentation" = "recorder"])
|
||||||
|
AM_CONDITIONAL([ENABLE_AGENT_INTERFACE],[test "$enable_instrumentation" = "agent"])
|
||||||
|
])
|
||||||
|
|
||||||
|
# SPICE_COMMON
|
||||||
|
# -----------------
|
||||||
|
# Define variables in order to use spice-common
|
||||||
|
# SPICE_COMMON_DIR directory for output libraries
|
||||||
|
# SPICE_COMMON_CFLAGS CFLAGS to add to use the library
|
||||||
|
#
|
||||||
|
# SPICE_PROTOCOL_MIN_VER input (m4) and output (autoconf) SPICE protocol version
|
||||||
|
# SPICE_PROTOCOL_CFLAGS CFLAGS for SPICE protocol, already automatically included
|
||||||
|
#
|
||||||
|
# GLIB2_MIN_VER input (m4) and output (shell) GLib2 minimum version
|
||||||
|
# GLIB2_MIN_VERSION output (shell) variable like "GLIB_VERSION_1_2" from GLIB2_MIN_VER
|
||||||
|
#------------------
|
||||||
|
AC_DEFUN([SPICE_COMMON], [dnl
|
||||||
|
dnl These add some flags and checks to component using spice-common
|
||||||
|
dnl The flags are necessary in order to make included header working
|
||||||
|
AC_REQUIRE([SPICE_EXTRA_CHECKS])dnl
|
||||||
|
AC_REQUIRE([SPICE_CHECK_INSTRUMENTATION])dnl
|
||||||
|
dnl Get the required spice protocol version
|
||||||
|
m4_define([SPICE_PROTOCOL_MIN_VER],m4_ifdef([SPICE_PROTOCOL_MIN_VER],SPICE_PROTOCOL_MIN_VER,[0.14.2]))dnl
|
||||||
|
m4_define([SPICE_PROTOCOL_MIN_VER],m4_if(m4_version_compare(SPICE_PROTOCOL_MIN_VER,[0.14.2]),[1],SPICE_PROTOCOL_MIN_VER,[0.14.2]))dnl
|
||||||
|
[SPICE_PROTOCOL_MIN_VER]=SPICE_PROTOCOL_MIN_VER
|
||||||
|
m4_undefine([SPICE_PROTOCOL_MIN_VER])dnl
|
||||||
|
PKG_CHECK_MODULES([SPICE_PROTOCOL], [spice-protocol >= $SPICE_PROTOCOL_MIN_VER])
|
||||||
|
AC_SUBST([SPICE_PROTOCOL_MIN_VER])dnl
|
||||||
|
dnl Get the required GLib2 version
|
||||||
|
m4_define([GLIB2_MIN_VER],m4_ifdef([GLIB2_MIN_VER],GLIB2_MIN_VER,[2.38]))dnl
|
||||||
|
m4_define([GLIB2_MIN_VER],m4_if(m4_version_compare(GLIB2_MIN_VER,[2.38]),[1],GLIB2_MIN_VER,[2.38]))dnl
|
||||||
|
m4_define([GLIB2_MIN_VERSION],[GLIB_VERSION_]m4_translit(GLIB2_MIN_VER,[.],[_]))dnl
|
||||||
|
[GLIB2_MIN_VER]=GLIB2_MIN_VER
|
||||||
|
[GLIB2_MIN_VERSION]=GLIB2_MIN_VERSION
|
||||||
|
m4_undefine([GLIB2_MIN_VER])dnl
|
||||||
|
m4_undefine([GLIB2_MIN_VERSION])dnl
|
||||||
|
PKG_CHECK_MODULES([GLIB2], [glib-2.0 >= $GLIB2_MIN_VER gio-2.0 >= $GLIB2_MIN_VER])
|
||||||
|
dnl Configuration variables
|
||||||
|
AC_CONFIG_SUBDIRS([$1])dnl
|
||||||
|
SPICE_COMMON_CFLAGS='-I${top_srcdir}/$1 -I${top_builddir}/$1 -DG_LOG_DOMAIN=\"Spice\" $(SPICE_PROTOCOL_CFLAGS) $(GLIB2_CFLAGS)'
|
||||||
|
AC_SUBST([SPICE_COMMON_CFLAGS])dnl
|
||||||
|
|
||||||
|
SPICE_COMMON_DIR='${top_builddir}/$1'
|
||||||
|
AC_SUBST([SPICE_COMMON_DIR])dnl
|
||||||
|
])
|
||||||
32
m4/spice_manual.m4
Normal file
32
m4/spice_manual.m4
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
dnl SPICE_MANUAL
|
||||||
|
dnl ------------
|
||||||
|
dnl Check if user wants manuals to be compiled and
|
||||||
|
dnl if all programs (asciidoc and a2x) are available
|
||||||
|
dnl ------------
|
||||||
|
dnl Shell defines:
|
||||||
|
dnl - have_asciidoc yes or not is asciidoc program is available
|
||||||
|
dnl Automake macros:
|
||||||
|
dnl - A2X a2x program or empty
|
||||||
|
dnl - ASCIIDOC asciidoc program or emtpy
|
||||||
|
dnl - BUILD_MANUAL if asciidoc and a2x are available
|
||||||
|
dnl - BUILD_HTML_MANUAL if asciidoc is available (html can be produced)
|
||||||
|
dnl - BUILD_CHUNKED_MANUAL if a2x is available
|
||||||
|
AC_DEFUN([SPICE_MANUAL],[
|
||||||
|
AC_ARG_ENABLE([manual],
|
||||||
|
AS_HELP_STRING([--enable-manual=@<:@auto/yes/no@:>@],
|
||||||
|
[Build SPICE manual]),
|
||||||
|
[],
|
||||||
|
[enable_manual="auto"])
|
||||||
|
if test "x$enable_manual" != "xno"; then
|
||||||
|
AC_PATH_PROG([ASCIIDOC], [asciidoc])
|
||||||
|
AS_IF([test -z "$ASCIIDOC" && test "x$enable_manual" = "xyes"],
|
||||||
|
[AC_MSG_ERROR([asciidoc is missing and build of manual was requested])])
|
||||||
|
AC_PATH_PROG([A2X], [a2x])
|
||||||
|
AS_IF([test -z "$A2X" && test "x$enable_manual" = "xyes"],
|
||||||
|
[AC_MSG_ERROR([a2x is missing and build of manual was requested])])
|
||||||
|
fi
|
||||||
|
AS_IF([test -n "$ASCIIDOC"], [have_asciidoc=yes], [have_asciidoc=no])
|
||||||
|
AM_CONDITIONAL([BUILD_MANUAL], [test -n "$ASCIIDOC" || test -n "$A2X"])
|
||||||
|
AM_CONDITIONAL([BUILD_HTML_MANUAL], [test -n "$ASCIIDOC"])
|
||||||
|
AM_CONDITIONAL([BUILD_CHUNKED_MANUAL], [test -n "$A2X"])
|
||||||
|
])
|
||||||
181
meson.build
Normal file
181
meson.build
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
#
|
||||||
|
# project definition
|
||||||
|
#
|
||||||
|
project('spice-common', 'c',
|
||||||
|
meson_version : '>= 0.49.0',
|
||||||
|
license : 'LGPLv2.1',
|
||||||
|
default_options : ['warning_level=2'])
|
||||||
|
|
||||||
|
if not meson.is_subproject()
|
||||||
|
warning('This project is only intended to be used as a subproject!')
|
||||||
|
endif
|
||||||
|
|
||||||
|
# some global vars
|
||||||
|
spice_common_global_cflags = ['-DG_LOG_DOMAIN="Spice"',
|
||||||
|
'-Wno-unused-parameter']
|
||||||
|
|
||||||
|
if get_option('alignment-checks')
|
||||||
|
spice_common_global_cflags += ['-DSPICE_DEBUG_ALIGNMENT']
|
||||||
|
endif
|
||||||
|
|
||||||
|
spice_common_deps = []
|
||||||
|
spice_common_include = include_directories('.')
|
||||||
|
|
||||||
|
spice_proto = files('spice.proto')
|
||||||
|
spice_codegen = files('spice_codegen.py')
|
||||||
|
spice_codegen_files = [spice_codegen]
|
||||||
|
|
||||||
|
compiler = meson.get_compiler('c')
|
||||||
|
spice_common_config_data = configuration_data()
|
||||||
|
if get_option('extra-checks')
|
||||||
|
spice_common_config_data.set('ENABLE_EXTRA_CHECKS', '1')
|
||||||
|
endif
|
||||||
|
if host_machine.endian() == 'big'
|
||||||
|
spice_common_config_data.set('WORDS_BIGENDIAN', '1')
|
||||||
|
endif
|
||||||
|
|
||||||
|
if get_option('instrumentation') == 'recorder'
|
||||||
|
spice_common_config_data.set('ENABLE_RECORDER', '1')
|
||||||
|
endif
|
||||||
|
if get_option('instrumentation') == 'agent'
|
||||||
|
spice_common_config_data.set('ENABLE_AGENT_INTERFACE', '1')
|
||||||
|
endif
|
||||||
|
|
||||||
|
spice_common_generate_code = get_option('generate-code')
|
||||||
|
spice_common_generate_client_code = spice_common_generate_code == 'all' or spice_common_generate_code == 'client'
|
||||||
|
spice_common_generate_server_code = spice_common_generate_code == 'all' or spice_common_generate_code == 'server'
|
||||||
|
|
||||||
|
#
|
||||||
|
# check for system headers
|
||||||
|
#
|
||||||
|
headers = ['alloca.h',
|
||||||
|
'arpa/inet.h',
|
||||||
|
'dlfcn.h',
|
||||||
|
'inttypes.h',
|
||||||
|
'netinet/in.h',
|
||||||
|
'stdlib.h',
|
||||||
|
'sys/socket.h',
|
||||||
|
'sys/stat.h',
|
||||||
|
'sys/types.h',
|
||||||
|
'unistd.h',
|
||||||
|
'regex.h',
|
||||||
|
'sys/mman.h']
|
||||||
|
|
||||||
|
foreach header : headers
|
||||||
|
if compiler.has_header(header)
|
||||||
|
spice_common_config_data.set('HAVE_@0@'.format(header.underscorify().to_upper()), '1')
|
||||||
|
endif
|
||||||
|
endforeach
|
||||||
|
|
||||||
|
#
|
||||||
|
# check for system functions
|
||||||
|
#
|
||||||
|
functions = ['alloca',
|
||||||
|
'sigaction',
|
||||||
|
'drand48',
|
||||||
|
'setlinebuf']
|
||||||
|
|
||||||
|
foreach func : functions
|
||||||
|
if compiler.has_function(func)
|
||||||
|
spice_common_config_data.set('HAVE_@0@'.format(func.underscorify().to_upper()), '1')
|
||||||
|
endif
|
||||||
|
endforeach
|
||||||
|
|
||||||
|
# FIXME
|
||||||
|
# check for libm, as workaround for https://github.com/mesonbuild/meson/issues/3740
|
||||||
|
libm = compiler.find_library('m', required : false)
|
||||||
|
if libm.found()
|
||||||
|
spice_common_deps += libm
|
||||||
|
endif
|
||||||
|
|
||||||
|
#
|
||||||
|
# check for mandatory dependencies
|
||||||
|
#
|
||||||
|
glib_version = '2.38'
|
||||||
|
glib_version_info = '>= @0@'.format(glib_version)
|
||||||
|
|
||||||
|
spice_protocol_version = '0.14.2'
|
||||||
|
|
||||||
|
spice_protocol_version_req = get_option('spice-protocol-version')
|
||||||
|
if spice_protocol_version_req.version_compare('> @0@'.format(spice_protocol_version))
|
||||||
|
spice_protocol_version = spice_protocol_version_req
|
||||||
|
endif
|
||||||
|
|
||||||
|
deps = {'spice-protocol' : '>= @0@'.format(spice_protocol_version),
|
||||||
|
'glib-2.0' : glib_version_info,
|
||||||
|
'pixman-1' : '>= 0.17.7',
|
||||||
|
'openssl' : '>= 1.0.0'}
|
||||||
|
|
||||||
|
foreach dep, version : deps
|
||||||
|
spice_common_deps += dependency(dep, version : version)
|
||||||
|
endforeach
|
||||||
|
|
||||||
|
gio2_deps = dependency('gio-2.0', version : glib_version_info)
|
||||||
|
|
||||||
|
#
|
||||||
|
# Non-mandatory/optional dependencies
|
||||||
|
#
|
||||||
|
optional_deps = {'opus' : '>= 0.9.14'}
|
||||||
|
foreach dep, version : optional_deps
|
||||||
|
d = dependency(dep, required : get_option(dep), version : version)
|
||||||
|
if d.found()
|
||||||
|
spice_common_deps += d
|
||||||
|
spice_common_config_data.set('HAVE_@0@'.format(dep.underscorify().to_upper()), '1')
|
||||||
|
endif
|
||||||
|
endforeach
|
||||||
|
|
||||||
|
# Python
|
||||||
|
if spice_common_generate_client_code or spice_common_generate_server_code
|
||||||
|
py_module = import('python')
|
||||||
|
python = py_module.find_installation('python3')
|
||||||
|
|
||||||
|
if get_option('python-checks')
|
||||||
|
foreach module : ['pyparsing']
|
||||||
|
message('Checking for python module @0@'.format(module))
|
||||||
|
cmd = run_command(python, '-c', 'import @0@'.format(module), check : false)
|
||||||
|
if cmd.returncode() != 0
|
||||||
|
error('Python module @0@ not found'.format(module))
|
||||||
|
endif
|
||||||
|
endforeach
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
# smartcard check
|
||||||
|
smartcard_dep = dependency('libcacard', required : get_option('smartcard'), version : '>= 2.5.1')
|
||||||
|
if smartcard_dep.found()
|
||||||
|
spice_common_deps += smartcard_dep
|
||||||
|
spice_common_config_data.set('USE_SMARTCARD', '1')
|
||||||
|
endif
|
||||||
|
|
||||||
|
# udev check
|
||||||
|
udev_dep = dependency('libudev', required : false)
|
||||||
|
if udev_dep.found()
|
||||||
|
spice_common_deps += udev_dep
|
||||||
|
spice_common_config_data.set('HAVE_UDEV', '1')
|
||||||
|
endif
|
||||||
|
|
||||||
|
#
|
||||||
|
# global C defines
|
||||||
|
#
|
||||||
|
glib_encoded_version = 'GLIB_VERSION_@0@'.format(glib_version.underscorify())
|
||||||
|
spice_common_global_cflags += ['-DGLIB_VERSION_MIN_REQUIRED=@0@'.format(glib_encoded_version),
|
||||||
|
'-DGLIB_VERSION_MAX_ALLOWED=@0@'.format(glib_encoded_version)]
|
||||||
|
|
||||||
|
add_project_arguments(compiler.get_supported_arguments(spice_common_global_cflags),
|
||||||
|
language : 'c')
|
||||||
|
|
||||||
|
#
|
||||||
|
# Subdirectories
|
||||||
|
#
|
||||||
|
subdir('python_modules')
|
||||||
|
subdir('common')
|
||||||
|
if get_option('tests')
|
||||||
|
subdir('tests')
|
||||||
|
endif
|
||||||
|
subdir('docs')
|
||||||
|
|
||||||
|
#
|
||||||
|
# write config.h
|
||||||
|
#
|
||||||
|
configure_file(output : 'config.h',
|
||||||
|
configuration : spice_common_config_data)
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user