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 =
|
||||
|
||||
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 = \
|
||||
bitops.h \
|
||||
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 \
|
||||
mutex.h \
|
||||
pixman_utils.c \
|
||||
pixman_utils.h \
|
||||
quic.c \
|
||||
@ -33,44 +50,112 @@ libspice_common_la_SOURCES = \
|
||||
ring.h \
|
||||
rop3.c \
|
||||
rop3.h \
|
||||
spice_common.h \
|
||||
ssl_verify.c \
|
||||
ssl_verify.h \
|
||||
backtrace.c \
|
||||
backtrace.h \
|
||||
snd_codec.c \
|
||||
snd_codec.h \
|
||||
udev.c \
|
||||
udev.h \
|
||||
utils.c \
|
||||
utils.h \
|
||||
verify.h \
|
||||
recorder.h \
|
||||
$(NULL)
|
||||
|
||||
if SUPPORT_GL
|
||||
libspice_common_la_SOURCES += \
|
||||
gl_utils.h \
|
||||
glc.h \
|
||||
glc.c \
|
||||
ogl_ctx.h \
|
||||
ogl_ctx.c \
|
||||
if ENABLE_RECORDER
|
||||
libspice_common_la_SOURCES += \
|
||||
recorder/recorder.c \
|
||||
recorder/recorder.h \
|
||||
recorder/recorder_ring.c \
|
||||
recorder/recorder_ring.h \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
INCLUDES = \
|
||||
$(GL_CFLAGS) \
|
||||
$(PIXMAN_CFLAGS) \
|
||||
$(PROTOCOL_CFLAGS) \
|
||||
$(VISIBILITY_HIDDEN_CFLAGS) \
|
||||
$(WARN_CFLAGS) \
|
||||
-std=gnu99 \
|
||||
if ENABLE_AGENT_INTERFACE
|
||||
libspice_common_la_SOURCES += \
|
||||
agent_interface.c \
|
||||
agent_interface.h \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
EXTRA_DIST = \
|
||||
canvas_base.c \
|
||||
canvas_base.h \
|
||||
gdi_canvas.c \
|
||||
gdi_canvas.h \
|
||||
gl_canvas.c \
|
||||
gl_canvas.h \
|
||||
# These 2 files are not build as part of spice-common
|
||||
# build system, but modules using spice-common will build
|
||||
# them with the appropriate options. We need to let automake
|
||||
# know that these are source files so that it can properly
|
||||
# track these files dependencies
|
||||
EXTRA_libspice_common_la_SOURCES = \
|
||||
sw_canvas.c \
|
||||
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_decompress_tmpl.c \
|
||||
quic_family_tmpl.c \
|
||||
quic_rgb_tmpl.c \
|
||||
quic_tmpl.c \
|
||||
$(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 <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#if !defined(WIN32) || defined(__MINGW32__)
|
||||
|
||||
#include "backtrace.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#ifndef __MINGW32__
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
#include "spice_common.h"
|
||||
|
||||
#define GSTACK_PATH "/usr/bin/gstack"
|
||||
|
||||
#if HAVE_EXECINFO_H
|
||||
@ -75,7 +77,6 @@ static int spice_backtrace_gstack(void)
|
||||
/* CHILD */
|
||||
char parent[16];
|
||||
|
||||
seteuid(0);
|
||||
close(STDIN_FILENO);
|
||||
close(STDOUT_FILENO);
|
||||
dup2(pipefd[1],STDOUT_FILENO);
|
||||
@ -131,3 +132,4 @@ void spice_backtrace(void)
|
||||
spice_backtrace_backtrace();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -16,8 +16,8 @@
|
||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef BACKTRACE_H
|
||||
#define BACKTRACE_H
|
||||
#ifndef H_SPICE_COMMON_BACKTRACE
|
||||
#define H_SPICE_COMMON_BACKTRACE
|
||||
|
||||
#include <spice/macros.h>
|
||||
|
||||
@ -31,4 +31,4 @@ void spice_backtrace(void);
|
||||
|
||||
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
|
||||
1122
common/canvas_base.c
1122
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/>.
|
||||
*/
|
||||
|
||||
#ifndef _H_CANVAS_BASE
|
||||
#define _H_CANVAS_BASE
|
||||
#ifndef H_SPICE_COMMON_CANVAS_BASE
|
||||
#define H_SPICE_COMMON_CANVAS_BASE
|
||||
|
||||
#ifndef SPICE_CANVAS_INTERNAL
|
||||
#error "This header shouldn't be included directly"
|
||||
#endif
|
||||
#include <spice/macros.h>
|
||||
|
||||
#include "pixman_utils.h"
|
||||
#include "lz.h"
|
||||
#include "region.h"
|
||||
#include "draw.h"
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
SPICE_BEGIN_DECLS
|
||||
|
||||
typedef void (*spice_destroy_fn_t)(void *data);
|
||||
|
||||
@ -64,7 +57,7 @@ typedef struct {
|
||||
} SpiceImageCacheOps;
|
||||
|
||||
struct _SpiceImageCache {
|
||||
SpiceImageCacheOps *ops;
|
||||
const SpiceImageCacheOps *ops;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
@ -73,7 +66,7 @@ typedef struct {
|
||||
} SpiceImageSurfacesOps;
|
||||
|
||||
struct _SpiceImageSurfaces {
|
||||
SpiceImageSurfacesOps *ops;
|
||||
const SpiceImageSurfacesOps *ops;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
@ -137,6 +130,7 @@ typedef struct {
|
||||
void (*draw_text)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceText *text);
|
||||
void (*draw_stroke)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceStroke *stroke);
|
||||
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_blackness)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceBlackness *blackness);
|
||||
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_alpha_blend)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceAlphaBlend* alpha_blend);
|
||||
void (*put_image)(SpiceCanvas *canvas,
|
||||
#ifdef WIN32
|
||||
HDC dc,
|
||||
#endif
|
||||
const SpiceRect *dest, const uint8_t *src_data,
|
||||
uint32_t src_width, uint32_t src_height, int src_stride,
|
||||
const QRegion *clip);
|
||||
@ -310,18 +301,13 @@ typedef struct {
|
||||
void (*copy_region)(SpiceCanvas *canvas,
|
||||
pixman_region32_t *dest_region,
|
||||
int dx, int dy);
|
||||
pixman_image_t *(*get_image)(SpiceCanvas *canvas);
|
||||
pixman_image_t *(*get_image)(SpiceCanvas *canvas, int force_opaque);
|
||||
} 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 {
|
||||
SpiceCanvasOps *ops;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
SPICE_END_DECLS
|
||||
|
||||
#endif
|
||||
|
||||
@ -15,42 +15,21 @@
|
||||
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 "canvas_utils.h"
|
||||
|
||||
#include <spice/macros.h>
|
||||
|
||||
#ifdef __GNUC__
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#include "mem.h"
|
||||
|
||||
#ifdef WIN32
|
||||
static int gdi_handlers = 0;
|
||||
#endif
|
||||
typedef struct PixmanData {
|
||||
uint8_t *data;
|
||||
pixman_format_code_t format;
|
||||
} PixmanData;
|
||||
|
||||
#ifndef CANVAS_ERROR
|
||||
#define CANVAS_ERROR(format, ...) { \
|
||||
printf("%s: " format "\n", __FUNCTION__, ## __VA_ARGS__); \
|
||||
abort(); \
|
||||
}
|
||||
#endif
|
||||
|
||||
static void release_data(pixman_image_t *image, void *release_data)
|
||||
static void release_data(SPICE_GNUC_UNUSED pixman_image_t *image,
|
||||
void *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);
|
||||
@ -65,7 +44,7 @@ pixman_image_add_data(pixman_image_t *image)
|
||||
if (data == NULL) {
|
||||
data = (PixmanData *)calloc(1, sizeof(PixmanData));
|
||||
if (data == NULL) {
|
||||
CANVAS_ERROR("out of memory");
|
||||
spice_error("out of memory");
|
||||
}
|
||||
pixman_image_set_destroy_function(image,
|
||||
release_data,
|
||||
@ -85,21 +64,25 @@ spice_pixman_image_set_format(pixman_image_t *image,
|
||||
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;
|
||||
|
||||
data = (PixmanData *)pixman_image_get_destroy_data(image);
|
||||
if (data != NULL &&
|
||||
data->format != 0)
|
||||
return data->format;
|
||||
spice_return_val_if_fail(format != NULL, 0);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
spice_warn_if_reached();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static INLINE pixman_image_t *__surface_create_stride(pixman_format_code_t format, int width, int height,
|
||||
int stride)
|
||||
pixman_image_t *surface_create_stride(pixman_format_code_t format, int width, int height,
|
||||
int stride)
|
||||
{
|
||||
uint8_t *data;
|
||||
uint8_t *stride_data;
|
||||
@ -117,7 +100,8 @@ static INLINE pixman_image_t *__surface_create_stride(pixman_format_code_t forma
|
||||
|
||||
if (surface == NULL) {
|
||||
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);
|
||||
@ -127,98 +111,8 @@ static INLINE pixman_image_t *__surface_create_stride(pixman_format_code_t forma
|
||||
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)
|
||||
#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) {
|
||||
pixman_image_t *surface;
|
||||
PixmanData *data;
|
||||
@ -233,8 +127,19 @@ pixman_image_t * surface_create(pixman_format_code_t format, int width, int heig
|
||||
switch (format) {
|
||||
case PIXMAN_a8r8g8b8:
|
||||
case PIXMAN_x8r8g8b8:
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
case PIXMAN_b8g8r8a8:
|
||||
case PIXMAN_b8g8r8x8:
|
||||
#endif
|
||||
stride = width * 4;
|
||||
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_r5g6b5:
|
||||
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;
|
||||
break;
|
||||
default:
|
||||
CANVAS_ERROR("invalid format");
|
||||
spice_error("invalid format");
|
||||
}
|
||||
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,
|
||||
@ -285,15 +167,14 @@ pixman_image_t *alloc_lz_image_surface(LzDecodeUsrData *canvas_data,
|
||||
|
||||
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) {
|
||||
stride = -stride;
|
||||
}
|
||||
|
||||
surface = surface_create_stride(
|
||||
#ifdef WIN32
|
||||
canvas_data->dc,
|
||||
#endif
|
||||
pixman_format, width, height, stride);
|
||||
surface = surface_create_stride(pixman_format, width, height, stride);
|
||||
canvas_data->out_surface = surface;
|
||||
return surface;
|
||||
}
|
||||
|
||||
@ -16,56 +16,29 @@
|
||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _H_CANVAS_UTILS
|
||||
#define _H_CANVAS_UTILS
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#ifndef H_SPICE_COMMON_CANVAS_UTILS
|
||||
#define H_SPICE_COMMON_CANVAS_UTILS
|
||||
|
||||
#include <spice/types.h>
|
||||
#include <spice/macros.h>
|
||||
|
||||
#include "pixman_utils.h"
|
||||
#include "lz.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct PixmanData {
|
||||
#ifdef WIN32
|
||||
HBITMAP bitmap;
|
||||
HANDLE mutex;
|
||||
#endif
|
||||
uint8_t *data;
|
||||
pixman_format_code_t format;
|
||||
} PixmanData;
|
||||
SPICE_BEGIN_DECLS
|
||||
|
||||
void spice_pixman_image_set_format(pixman_image_t *image,
|
||||
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);
|
||||
#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
|
||||
|
||||
|
||||
typedef struct LzDecodeUsrData {
|
||||
#ifdef WIN32
|
||||
HDC dc;
|
||||
#endif
|
||||
pixman_image_t *out_surface;
|
||||
} LzDecodeUsrData;
|
||||
|
||||
@ -73,8 +46,7 @@ typedef struct LzDecodeUsrData {
|
||||
pixman_image_t *alloc_lz_image_surface(LzDecodeUsrData *canvas_data,
|
||||
pixman_format_code_t pixman_format, int width,
|
||||
int height, int gross_pixels, int top_down);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
SPICE_END_DECLS
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* -*- 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
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#ifndef _H_GLCTX
|
||||
#define _H_GLCTX
|
||||
#ifndef H_SPICE_COMMON_CLIENT_MARSHALLERS
|
||||
#define H_SPICE_COMMON_CLIENT_MARSHALLERS
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#include <spice/protocol.h>
|
||||
|
||||
typedef struct OGLCtx OGLCtx;
|
||||
#include "messages.h"
|
||||
#include "common/generated_client_marshallers.h"
|
||||
#include "marshaller.h"
|
||||
|
||||
const char *oglctx_type_str(OGLCtx *ctx);
|
||||
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);
|
||||
SPICE_BEGIN_DECLS
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
SpiceMessageMarshallers *spice_message_marshallers_get(void);
|
||||
|
||||
SPICE_END_DECLS
|
||||
|
||||
#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.
|
||||
*/
|
||||
|
||||
#ifndef _H_SPICE_DRAW
|
||||
#define _H_SPICE_DRAW
|
||||
#ifndef H_SPICE_COMMON_DRAW
|
||||
#define H_SPICE_COMMON_DRAW
|
||||
|
||||
#include <spice/macros.h>
|
||||
#include <spice/types.h>
|
||||
#include <spice/enums.h>
|
||||
#include "mem.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
SPICE_BEGIN_DECLS
|
||||
|
||||
#define SPICE_GET_ADDRESS(addr) ((void *)(uintptr_t)(addr))
|
||||
#define SPICE_SET_ADDRESS(addr, val) ((addr) = (uintptr_t)(val))
|
||||
@ -83,7 +82,7 @@ typedef struct SpiceClipRects {
|
||||
} SpiceClipRects;
|
||||
|
||||
typedef struct SpiceClip {
|
||||
uint32_t type;
|
||||
uint8_t type;
|
||||
SpiceClipRects *rects;
|
||||
} SpiceClip;
|
||||
|
||||
@ -121,7 +120,7 @@ typedef struct SpiceSurface {
|
||||
typedef struct SpiceQUICData {
|
||||
uint32_t data_size;
|
||||
SpiceChunks *data;
|
||||
} SpiceQUICData, SpiceLZRGBData, SpiceJPEGData;
|
||||
} SpiceQUICData, SpiceLZRGBData, SpiceJPEGData, SpiceLZ4Data;
|
||||
|
||||
typedef struct SpiceLZPLTData {
|
||||
uint8_t flags;
|
||||
@ -154,6 +153,7 @@ typedef struct SpiceImage {
|
||||
SpiceLZRGBData lz_rgb;
|
||||
SpiceLZPLTData lz_plt;
|
||||
SpiceJPEGData jpeg;
|
||||
SpiceLZ4Data lz4;
|
||||
SpiceZlibGlzRGBData zlib_glz;
|
||||
SpiceJPEGAlphaData jpeg_alpha;
|
||||
} u;
|
||||
@ -224,6 +224,26 @@ typedef struct SpiceRop3 {
|
||||
SpiceQMask mask;
|
||||
} 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 {
|
||||
SpiceQMask mask;
|
||||
} SpiceBlackness, SpiceInvers, SpiceWhiteness;
|
||||
@ -274,8 +294,12 @@ typedef struct SpiceCursorHeader {
|
||||
uint16_t hot_spot_y;
|
||||
} 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.
|
||||
|
||||
******************************************************************/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <spice/macros.h>
|
||||
@ -84,7 +82,7 @@ typedef struct lineGC *GCPtr;
|
||||
#define miWideDash spice_canvas_wide_dash_line
|
||||
#define miWideLine spice_canvas_wide_line
|
||||
|
||||
static INLINE int ICEIL (double x)
|
||||
static inline int ICEIL (double x)
|
||||
{
|
||||
int _cTmp = (int)x;
|
||||
return ((x == _cTmp) || (x < 0.0)) ? _cTmp : _cTmp + 1;
|
||||
@ -412,7 +410,7 @@ miStepDash (int dist, /* distance to step */
|
||||
totallen = 0;
|
||||
for (i = 0; i < numInDashList; i++)
|
||||
totallen += pDash[i];
|
||||
if (totallen <= dist)
|
||||
if (totallen > 0 && totallen <= dist)
|
||||
dist = dist % totallen;
|
||||
while (dist >= pDash[dashIndex]) {
|
||||
dist -= pDash[dashIndex];
|
||||
@ -806,14 +804,14 @@ miFillUniqueSpanGroup (GCPtr pGC, SpanGroup * spanGroup, Boolean foreground)
|
||||
newwidths = xrealloc (newspans->widths,
|
||||
ysizes[index] * sizeof (int));
|
||||
if (!newpoints || !newwidths) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ylength; i++) {
|
||||
xfree (yspans[i].points);
|
||||
xfree (yspans[i].widths);
|
||||
}
|
||||
xfree (yspans);
|
||||
xfree (ysizes);
|
||||
xfree (newpoints);
|
||||
xfree (newwidths);
|
||||
miDisposeSpanGroup (spanGroup);
|
||||
return;
|
||||
}
|
||||
@ -836,8 +834,6 @@ miFillUniqueSpanGroup (GCPtr pGC, SpanGroup * spanGroup, Boolean foreground)
|
||||
points = (DDXPointRec*)xalloc (count * sizeof (DDXPointRec));
|
||||
widths = (int *)xalloc (count * sizeof (int));
|
||||
if (!points || !widths) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ylength; i++) {
|
||||
xfree (yspans[i].points);
|
||||
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
|
||||
the Y steps as (dy - N), we will actually want to solve for the
|
||||
smallest N in that equation.
|
||||
|
||||
|
||||
Case 1: X major, starting X coordinate moved by M steps
|
||||
|
||||
-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) / 2dx)
|
||||
= floor((2Mdy + dx + B - 1) / 2dx)
|
||||
|
||||
|
||||
Case 3: Y major, starting X coordinate moved by M steps
|
||||
|
||||
-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:
|
||||
|
||||
N = floor((2Mdy + dy - B) / 2dx)
|
||||
|
||||
|
||||
Now let's try the Y coordinates, we have the same 4 cases.
|
||||
|
||||
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:
|
||||
|
||||
M = floor((2Ndx + dx - B) / 2dy)
|
||||
|
||||
|
||||
Case 7: Y major, starting Y coordinate moved by N steps
|
||||
|
||||
-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) / 2dy)
|
||||
= floor((2Ndx + dy + B - 1) / 2dy)
|
||||
|
||||
|
||||
So, our equations are:
|
||||
|
||||
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
|
||||
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 x, y, e;
|
||||
@ -1837,15 +1833,6 @@ miPolyBuildEdge (double x0, double y0, double k, /* x0 * dy - y0 * dx */
|
||||
dx = -dx;
|
||||
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);
|
||||
xady = ICEIL (k) + y * dx;
|
||||
|
||||
@ -1970,7 +1957,11 @@ miPolyBuildPoly (PolyVertexPtr vertices,
|
||||
}
|
||||
|
||||
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;
|
||||
int wid;
|
||||
@ -2430,7 +2421,7 @@ miLineArc (GCPtr pGC,
|
||||
int xorgi = 0, yorgi = 0;
|
||||
Spans spanRec;
|
||||
int n;
|
||||
PolyEdgeRec edge1, edge2;
|
||||
PolyEdgeRec edge1 = { 0 }, edge2 = { 0 };
|
||||
int edgey1, edgey2;
|
||||
Boolean edgeleft1, edgeleft2;
|
||||
|
||||
@ -2501,13 +2492,18 @@ miLineArc (GCPtr pGC,
|
||||
}
|
||||
|
||||
static void
|
||||
miLineProjectingCap (GCPtr pGC, Boolean foreground,
|
||||
SpanDataPtr spanData, LineFacePtr face, Boolean isLeft,
|
||||
double xorg, double yorg, Boolean isInt)
|
||||
miLineProjectingCap (GCPtr pGC,
|
||||
Boolean foreground,
|
||||
SpanDataPtr spanData,
|
||||
LineFacePtr face,
|
||||
Boolean isLeft,
|
||||
SPICE_GNUC_UNUSED double xorg,
|
||||
SPICE_GNUC_UNUSED double yorg,
|
||||
Boolean isInt)
|
||||
{
|
||||
int xorgi = 0, yorgi = 0;
|
||||
int lw;
|
||||
PolyEdgeRec lefts[2], rights[2];
|
||||
PolyEdgeRec lefts[4], rights[4];
|
||||
int lefty, righty, topy, bottomy;
|
||||
PolyEdgePtr left, right;
|
||||
PolyEdgePtr top, bottom;
|
||||
@ -2665,7 +2661,7 @@ miWideSegment (GCPtr pGC,
|
||||
PolyEdgePtr top, bottom;
|
||||
int lefty, righty, topy, bottomy;
|
||||
int signdx;
|
||||
PolyEdgeRec lefts[2], rights[2];
|
||||
PolyEdgeRec lefts[4], rights[4];
|
||||
LineFacePtr tface;
|
||||
int lw = pGC->lineWidth;
|
||||
|
||||
@ -2980,9 +2976,9 @@ miWideDashSegment (GCPtr pGC,
|
||||
double L, l;
|
||||
double k;
|
||||
PolyVertexRec vertices[4];
|
||||
PolyVertexRec saveRight = { 0 }, saveBottom;
|
||||
PolyVertexRec saveRight = { 0, 0 }, saveBottom;
|
||||
PolySlopeRec slopes[4];
|
||||
PolyEdgeRec left[2], right[2];
|
||||
PolyEdgeRec left[4], right[4];
|
||||
LineFaceRec lcapFace, rcapFace;
|
||||
int nleft, nright;
|
||||
int h;
|
||||
|
||||
@ -46,17 +46,17 @@ SOFTWARE.
|
||||
|
||||
******************************************************************/
|
||||
|
||||
#ifndef LINES_H
|
||||
#define LINES_H
|
||||
#ifndef H_SPICE_COMMON_LINES
|
||||
#define H_SPICE_COMMON_LINES
|
||||
|
||||
#include <pixman_utils.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <spice/macros.h>
|
||||
|
||||
#include "pixman_utils.h"
|
||||
#include "draw.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
SPICE_BEGIN_DECLS
|
||||
|
||||
typedef struct lineGC lineGC;
|
||||
|
||||
@ -131,8 +131,6 @@ extern int spice_canvas_clip_spans(pixman_region32_t *clip_region,
|
||||
int *new_widths,
|
||||
int sorted);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
SPICE_END_DECLS
|
||||
|
||||
#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.
|
||||
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#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_SIZE (1 << HASH_LOG)
|
||||
#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;
|
||||
struct LzImageSegment {
|
||||
@ -102,7 +89,6 @@ typedef struct Encoder {
|
||||
// (2) a pointer to the first byte in the segment that matches the word
|
||||
HashEntry htab[HASH_SIZE];
|
||||
|
||||
uint8_t *io_start;
|
||||
uint8_t *io_now;
|
||||
uint8_t *io_end;
|
||||
size_t io_bytes_count;
|
||||
@ -113,7 +99,7 @@ typedef struct Encoder {
|
||||
/****************************************************/
|
||||
/* 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 int lz_read_image_segments(Encoder *encoder, uint8_t *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
|
||||
// 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;
|
||||
|
||||
@ -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)
|
||||
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;
|
||||
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;
|
||||
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);
|
||||
if (!image_seg) {
|
||||
@ -224,7 +210,7 @@ error_1:
|
||||
/**************************************************************************
|
||||
* 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;
|
||||
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;
|
||||
}
|
||||
|
||||
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 (more_io_bytes(encoder) <= 0) {
|
||||
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;
|
||||
}
|
||||
|
||||
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 >> 16) & 0x0000ff);
|
||||
@ -255,37 +241,32 @@ static INLINE void encode_32(Encoder *encoder, unsigned int word)
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
static INLINE void encode_level(Encoder *encoder, uint8_t level_code)
|
||||
{
|
||||
*(encoder->io_start) |= level_code;
|
||||
}
|
||||
|
||||
// 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
|
||||
encoder->io_now--;
|
||||
// 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)
|
||||
{
|
||||
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_start = io_ptr;
|
||||
encoder->io_now = io_ptr;
|
||||
encoder->io_end = io_ptr_end;
|
||||
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;
|
||||
}
|
||||
|
||||
static INLINE uint8_t decode(Encoder *encoder)
|
||||
static inline uint8_t decode(Encoder *encoder)
|
||||
{
|
||||
if (encoder->io_now == encoder->io_end) {
|
||||
int num_io_bytes = more_io_bytes(encoder);
|
||||
if (num_io_bytes <= 0) {
|
||||
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++);
|
||||
}
|
||||
|
||||
static INLINE uint32_t decode_32(Encoder *encoder)
|
||||
static inline uint32_t decode_32(Encoder *encoder)
|
||||
{
|
||||
uint32_t word = 0;
|
||||
word |= decode(encoder);
|
||||
@ -319,7 +300,7 @@ static INLINE uint32_t decode_32(Encoder *encoder)
|
||||
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) {
|
||||
return FALSE;
|
||||
@ -393,30 +374,23 @@ void lz_destroy(LzContext *lz)
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define ATTR_PACKED __attribute__ ((__packed__))
|
||||
#else
|
||||
#define ATTR_PACKED
|
||||
#pragma pack(push)
|
||||
#pragma pack(1)
|
||||
#endif
|
||||
|
||||
#include <spice/start-packed.h>
|
||||
|
||||
/* the palette images will be treated as one byte pixels. Their width should be transformed
|
||||
accordingly.
|
||||
*/
|
||||
typedef struct ATTR_PACKED one_byte_pixel_t {
|
||||
typedef struct SPICE_ATTR_PACKED one_byte_pixel_t {
|
||||
uint8_t a;
|
||||
} one_byte_pixel_t;
|
||||
|
||||
typedef struct ATTR_PACKED rgb32_pixel_t {
|
||||
typedef struct SPICE_ATTR_PACKED rgb32_pixel_t {
|
||||
uint8_t b;
|
||||
uint8_t g;
|
||||
uint8_t r;
|
||||
uint8_t pad;
|
||||
} rgb32_pixel_t;
|
||||
|
||||
typedef struct ATTR_PACKED rgb24_pixel_t {
|
||||
typedef struct SPICE_ATTR_PACKED rgb24_pixel_t {
|
||||
uint8_t b;
|
||||
uint8_t g;
|
||||
uint8_t r;
|
||||
@ -424,11 +398,7 @@ typedef struct ATTR_PACKED rgb24_pixel_t {
|
||||
|
||||
typedef uint16_t rgb16_pixel_t;
|
||||
|
||||
#ifndef __GNUC__
|
||||
#pragma pack(pop)
|
||||
#endif
|
||||
|
||||
#undef ATTR_PACKED
|
||||
#include <spice/end-packed.h>
|
||||
|
||||
|
||||
#define MAX_COPY 32
|
||||
@ -476,6 +446,13 @@ typedef uint16_t rgb16_pixel_t;
|
||||
#define TO_RGB32
|
||||
#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
|
||||
#include "lz_compress_tmpl.c"
|
||||
@ -504,6 +481,44 @@ typedef uint16_t rgb16_pixel_t;
|
||||
#undef LZ_UNEXPECT_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,
|
||||
uint8_t *lines, unsigned int num_lines, int stride,
|
||||
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;
|
||||
uint8_t *io_ptr_end = io_ptr + num_io_bytes;
|
||||
|
||||
encoder->type = type;
|
||||
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");
|
||||
}
|
||||
}
|
||||
lz_set_sizes(encoder, type, width, height, stride);
|
||||
|
||||
// assign the output buffer
|
||||
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:
|
||||
lz_rgb_alpha_compress(encoder);
|
||||
break;
|
||||
case LZ_IMAGE_TYPE_A8:
|
||||
lz_a8_compress(encoder);
|
||||
break;
|
||||
case LZ_IMAGE_TYPE_INVALID:
|
||||
default:
|
||||
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->type = (LzImageType)decode_32(encoder);
|
||||
encoder->width = decode_32(encoder);
|
||||
encoder->height = decode_32(encoder);
|
||||
encoder->stride = decode_32(encoder);
|
||||
int type = decode_32(encoder);
|
||||
if (type <= LZ_IMAGE_TYPE_INVALID || type > LZ_IMAGE_TYPE_A8) {
|
||||
encoder->usr->error(encoder->usr, "invalid lz type %d\n", type);
|
||||
}
|
||||
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_width = encoder->width;
|
||||
@ -646,6 +653,7 @@ void lz_decode(LzContext *lz, LzImageType to_type, uint8_t *buf)
|
||||
if (!encoder->palette) {
|
||||
encoder->usr->error(encoder->usr,
|
||||
"a palette is missing (for bpp to rgb decoding)\n");
|
||||
return;
|
||||
}
|
||||
switch (encoder->type) {
|
||||
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) {
|
||||
out_size = lz_rgb32_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 {
|
||||
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");
|
||||
}
|
||||
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_BE:
|
||||
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));
|
||||
ASSERT(encoder->usr, out_size == size);
|
||||
spice_assert(is_io_to_decode_end(encoder));
|
||||
spice_assert(out_size == size);
|
||||
|
||||
if (out_size != size) {
|
||||
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/)
|
||||
(Distributed under MIT license).
|
||||
*/
|
||||
#ifndef __LZ_H
|
||||
#define __LZ_H
|
||||
#ifndef H_SPICE_COMMON_LZ
|
||||
#define H_SPICE_COMMON_LZ
|
||||
|
||||
#include <spice/macros.h>
|
||||
|
||||
#include "lz_common.h"
|
||||
#include "lz_config.h"
|
||||
#include "draw.h"
|
||||
#include "macros.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
SPICE_BEGIN_DECLS
|
||||
|
||||
typedef void *LzContext;
|
||||
|
||||
typedef struct LzUsrContext LzUsrContext;
|
||||
struct LzUsrContext {
|
||||
void (*error)(LzUsrContext *usr, const char *fmt, ...);
|
||||
void (*warn)(LzUsrContext *usr, const char *fmt, ...);
|
||||
void (*info)(LzUsrContext *usr, const char *fmt, ...);
|
||||
SPICE_GNUC_NORETURN
|
||||
SPICE_GNUC_PRINTF(2, 3) void (*error)(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 (*free)(LzUsrContext *usr, void *ptr);
|
||||
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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
SPICE_END_DECLS
|
||||
|
||||
#endif // __LZ_H
|
||||
#endif // H_SPICE_COMMON_LZ
|
||||
|
||||
@ -20,14 +20,13 @@
|
||||
|
||||
/*common header for encoder and decoder*/
|
||||
|
||||
#ifndef _LZ_COMMON_H
|
||||
#define _LZ_COMMON_H
|
||||
#ifndef H_SPICE_COMMON_LZ_COMMON
|
||||
#define H_SPICE_COMMON_LZ_COMMON
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#include <spice/macros.h>
|
||||
#include "verify.h"
|
||||
|
||||
//#define DEBUG
|
||||
SPICE_BEGIN_DECLS
|
||||
|
||||
/* change the max window size will require change in the encoding format*/
|
||||
#define LZ_MAX_WINDOW_SIZE (1 << 25)
|
||||
@ -44,26 +43,30 @@ typedef enum {
|
||||
LZ_IMAGE_TYPE_RGB24,
|
||||
LZ_IMAGE_TYPE_RGB32,
|
||||
LZ_IMAGE_TYPE_RGBA,
|
||||
LZ_IMAGE_TYPE_XXXA
|
||||
LZ_IMAGE_TYPE_XXXA,
|
||||
LZ_IMAGE_TYPE_A8
|
||||
} LzImageType;
|
||||
|
||||
#define LZ_IMAGE_TYPE_MASK 0x0f
|
||||
#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 */
|
||||
static const int IS_IMAGE_TYPE_PLT[] = {0, 1, 1, 1, 1, 1, 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_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, 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_MINOR 1U
|
||||
#define LZ_VERSION ((LZ_VERSION_MAJOR << 16) | (LZ_VERSION_MINOR & 0xffff))
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
SPICE_END_DECLS
|
||||
|
||||
#endif // _LZ_COMMON_H
|
||||
#endif // H_SPICE_COMMON_LZ_COMMON
|
||||
|
||||
@ -40,11 +40,9 @@
|
||||
SOFTWARE.
|
||||
|
||||
*/
|
||||
#ifdef HAVE_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;}
|
||||
|
||||
/*
|
||||
@ -71,6 +69,21 @@
|
||||
}
|
||||
#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
|
||||
//#undef LZ_RGB_ALPHA
|
||||
#define PIXEL rgb32_pixel_t
|
||||
@ -90,9 +103,8 @@
|
||||
#ifdef LZ_RGB16
|
||||
#define PIXEL rgb16_pixel_t
|
||||
#define FNAME(name) lz_rgb16_##name
|
||||
#define GET_r(pix) (((pix) >> 10) & 0x1f)
|
||||
#define GET_g(pix) (((pix) >> 5) & 0x1f)
|
||||
#define GET_b(pix) ((pix) & 0x1f)
|
||||
#define GET_rgb(pix) ((pix) & 0x7fffu)
|
||||
#define SAME_PIXEL(p1, p2) (GET_rgb(p1) == GET_rgb(p2))
|
||||
#define ENCODE_PIXEL(e, pix) {encode(e, (pix) >> 8); encode(e, (pix) & 0xff);}
|
||||
|
||||
#define HASH_FUNC(v, p) { \
|
||||
@ -110,20 +122,17 @@
|
||||
#ifdef LZ_RGB24
|
||||
#define PIXEL rgb24_pixel_t
|
||||
#define FNAME(name) lz_rgb24_##name
|
||||
#define ENCODE_PIXEL(e, pix) {encode(e, (pix).b); encode(e, (pix).g); encode(e, (pix).r);}
|
||||
#endif
|
||||
|
||||
#ifdef LZ_RGB32
|
||||
#define PIXEL rgb32_pixel_t
|
||||
#define FNAME(name) lz_rgb32_##name
|
||||
#define ENCODE_PIXEL(e, pix) {encode(e, (pix).b); encode(e, (pix).g); encode(e, (pix).r);}
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(LZ_RGB24) || defined(LZ_RGB32)
|
||||
#define GET_r(pix) ((pix).r)
|
||||
#define GET_g(pix) ((pix).g)
|
||||
#define GET_b(pix) ((pix).b)
|
||||
#define ENCODE_PIXEL(e, pix) {encode(e, (pix).b); encode(e, (pix).g); encode(e, (pix).r);}
|
||||
#define SAME_PIXEL(p1, p2) ((p1).r == (p2).r && (p1).g == (p2).g && (p1).b == (p2).b)
|
||||
#define HASH_FUNC(v, p) { \
|
||||
v = DJB2_START; \
|
||||
DJB2_HASH(v, p[0].r); \
|
||||
@ -139,12 +148,6 @@
|
||||
}
|
||||
#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)
|
||||
|
||||
// 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;
|
||||
|
||||
/* 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;
|
||||
#elif defined(LZ_RGB16)
|
||||
size_t len = 2;
|
||||
@ -199,9 +202,7 @@ static void FNAME(compress_seg)(Encoder *encoder, LzImageSegment *seg, PIXEL *fr
|
||||
ip += 3;
|
||||
ref = anchor + 2;
|
||||
ref_limit = (PIXEL *)(seg->lines_end);
|
||||
#if defined(LZ_RGB16) || defined(LZ_RGB24) || defined(LZ_RGB32)
|
||||
len = 3;
|
||||
#endif
|
||||
|
||||
goto match;
|
||||
}
|
||||
}
|
||||
@ -234,7 +235,7 @@ static void FNAME(compress_seg)(Encoder *encoder, LzImageSegment *seg, PIXEL *fr
|
||||
ip++;
|
||||
|
||||
/* 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)) {
|
||||
ref++;
|
||||
ip++;
|
||||
@ -244,7 +245,7 @@ static void FNAME(compress_seg)(Encoder *encoder, LzImageSegment *seg, PIXEL *fr
|
||||
ip++;
|
||||
#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)) {
|
||||
ref++;
|
||||
ip++;
|
||||
@ -255,7 +256,7 @@ static void FNAME(compress_seg)(Encoder *encoder, LzImageSegment *seg, PIXEL *fr
|
||||
#endif
|
||||
/* far, needs at least 5-byte match */
|
||||
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)) {
|
||||
goto literal;
|
||||
}
|
||||
@ -272,7 +273,7 @@ static void FNAME(compress_seg)(Encoder *encoder, LzImageSegment *seg, PIXEL *fr
|
||||
ref++;
|
||||
ip++;
|
||||
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)) {
|
||||
ref++;
|
||||
ip++;
|
||||
@ -310,18 +311,15 @@ 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
|
||||
// to spare ref < ref_limit and that way we can also perform 8 calls of
|
||||
// (ref++ != ip++) outside a loop
|
||||
for (;;) {
|
||||
while ((ip < ip_bound) && (ref < ref_limit)) {
|
||||
if (!SAME_PIXEL(*ref, *ip)) {
|
||||
ref++;
|
||||
ip++;
|
||||
break;
|
||||
} else {
|
||||
ref++;
|
||||
ip++;
|
||||
}
|
||||
while ((ip < ip_bound) && (ref < ref_limit)) {
|
||||
if (!SAME_PIXEL(*ref, *ip)) {
|
||||
ref++;
|
||||
ip++;
|
||||
break;
|
||||
} else {
|
||||
ref++;
|
||||
ip++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -393,27 +391,23 @@ match: // RLE or dictionary (both are encoded by distance from ref (-1) a
|
||||
|
||||
/* update the hash at match boundary */
|
||||
#if defined(LZ_RGB16) || defined(LZ_RGB24) || defined(LZ_RGB32)
|
||||
if (ip > anchor) {
|
||||
if (ip > anchor)
|
||||
#endif
|
||||
HASH_FUNC(hval, ip);
|
||||
encoder->htab[hval].ref = (uint8_t *)ip;
|
||||
{
|
||||
HASH_FUNC(hval, ip);
|
||||
encoder->htab[hval].ref = (uint8_t *)ip;
|
||||
encoder->htab[hval].image_seg = seg;
|
||||
}
|
||||
ip++;
|
||||
encoder->htab[hval].image_seg = seg;
|
||||
#if defined(LZ_RGB16) || defined(LZ_RGB24) || defined(LZ_RGB32)
|
||||
} else {ip++;
|
||||
}
|
||||
#endif
|
||||
#if defined(LZ_RGB24) || defined(LZ_RGB32)
|
||||
if (ip > anchor) {
|
||||
if (ip > anchor)
|
||||
#endif
|
||||
HASH_FUNC(hval, ip);
|
||||
encoder->htab[hval].ref = (uint8_t *)ip;
|
||||
{
|
||||
HASH_FUNC(hval, ip);
|
||||
encoder->htab[hval].ref = (uint8_t *)ip;
|
||||
encoder->htab[hval].image_seg = seg;
|
||||
}
|
||||
ip++;
|
||||
encoder->htab[hval].image_seg = seg;
|
||||
#if defined(LZ_RGB24) || defined(LZ_RGB32)
|
||||
} else {ip++;
|
||||
}
|
||||
#endif
|
||||
/* assuming literal copy */
|
||||
encode_copy_count(encoder, MAX_COPY - 1);
|
||||
continue;
|
||||
@ -513,17 +507,11 @@ static void FNAME(compress)(Encoder *encoder)
|
||||
#undef PIXEL
|
||||
#undef ENCODE_PIXEL
|
||||
#undef SAME_PIXEL
|
||||
#undef LZ_READU16
|
||||
#undef HASH_FUNC
|
||||
#undef BYTES_TO_16
|
||||
#undef HASH_FUNC_16
|
||||
#undef GET_r
|
||||
#undef GET_g
|
||||
#undef GET_b
|
||||
#undef GET_CODE
|
||||
#undef GET_rgb
|
||||
#undef LZ_PLT
|
||||
#undef LZ_RGB_ALPHA
|
||||
#undef LZ_RGB16
|
||||
#undef LZ_RGB24
|
||||
#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
|
||||
*/
|
||||
|
||||
#ifndef __LZ_CONFIG_H
|
||||
#define __LZ_CONFIG_H
|
||||
#ifndef H_SPICE_COMMON_LZ_CONFIG
|
||||
#define H_SPICE_COMMON_LZ_CONFIG
|
||||
|
||||
#include <spice/types.h>
|
||||
#include <spice/macros.h>
|
||||
@ -36,4 +36,4 @@
|
||||
#endif // QXLDD
|
||||
#endif //__GNUC__
|
||||
|
||||
#endif //__LZ_CONFIG_H
|
||||
#endif // H_SPICE_COMMON_LZ_CONFIG
|
||||
|
||||
@ -50,18 +50,16 @@
|
||||
|
||||
/*
|
||||
For each output pixel type the following macros are defined:
|
||||
OUT_PIXEL - the output pixel type
|
||||
COPY_PIXEL(p, out) - assigns the pixel to the place pointed by out and increases
|
||||
out. Used in RLE. Need special handling because in alpha we
|
||||
copy only the pad byte.
|
||||
OUT_PIXEL - the output pixel type
|
||||
COPY_PIXEL(p, out) - assigns the pixel to the place pointed by out and increases
|
||||
out. Used in RLE. Need special handling because in alpha we
|
||||
copy only the pad byte.
|
||||
COPY_REF_PIXEL(ref, out) - copies the pixel pointed by ref to the pixel pointed by out.
|
||||
Increases ref and out.
|
||||
COPY_COMP_PIXEL(encoder, out) - copies pixel from the compressed buffer to the decompressed
|
||||
buffer. Increases out.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#if !defined(LZ_RGB_ALPHA)
|
||||
#define COPY_PIXEL(p, out) (*out++ = p)
|
||||
@ -153,6 +151,26 @@
|
||||
#endif // TO_RGB32
|
||||
#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
|
||||
#ifndef TO_RGB32
|
||||
#define OUT_PIXEL rgb16_pixel_t
|
||||
@ -204,18 +222,18 @@
|
||||
static size_t FNAME(decompress)(Encoder *encoder, OUT_PIXEL *out_buf, int size)
|
||||
{
|
||||
OUT_PIXEL *op = out_buf;
|
||||
OUT_PIXEL *op_limit = out_buf + size;
|
||||
uint32_t ctrl = decode(encoder);
|
||||
int loop = TRUE;
|
||||
OUT_PIXEL *const op_limit = out_buf + size;
|
||||
|
||||
do {
|
||||
const OUT_PIXEL *ref = op;
|
||||
uint32_t len = ctrl >> 5;
|
||||
uint32_t ofs = (ctrl & 31) << 8; // 5 MSb of distance
|
||||
for (;;) {
|
||||
uint32_t ctrl = decode(encoder);
|
||||
|
||||
if (ctrl >= MAX_COPY) { // reference (dictionary/RLE)
|
||||
/* 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;
|
||||
len--;
|
||||
//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)
|
||||
#elif defined(LZ_RGB16)
|
||||
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
|
||||
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);
|
||||
len = CAST_PLT_DISTANCE(len);
|
||||
#endif
|
||||
#endif
|
||||
ref -= ofs;
|
||||
|
||||
ASSERT(encoder->usr, op + len <= op_limit);
|
||||
ASSERT(encoder->usr, ref + len <= op_limit);
|
||||
ASSERT(encoder->usr, ref >= out_buf);
|
||||
spice_assert(op + len <= op_limit);
|
||||
spice_assert(ref + len <= op_limit);
|
||||
spice_assert(ref >= out_buf);
|
||||
|
||||
// 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
|
||||
@ -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
|
||||
// then one...
|
||||
/* optimize copy for a run */
|
||||
OUT_PIXEL b = *ref;
|
||||
const OUT_PIXEL b = *ref;
|
||||
for (; len; --len) {
|
||||
COPY_PIXEL(b, op);
|
||||
ASSERT(encoder->usr, op <= op_limit);
|
||||
spice_extra_assert(op <= op_limit);
|
||||
}
|
||||
} else {
|
||||
for (; len; --len) {
|
||||
COPY_REF_PIXEL(ref, op);
|
||||
ASSERT(encoder->usr, op <= op_limit);
|
||||
spice_extra_assert(op <= op_limit);
|
||||
}
|
||||
}
|
||||
} else { // copy
|
||||
ctrl++; // copy count is biased by 1
|
||||
#if defined(TO_RGB32) && (defined(PLT4_BE) || defined(PLT4_LE) || defined(PLT1_BE) || \
|
||||
defined(PLT1_LE))
|
||||
ASSERT(encoder->usr, op + CAST_PLT_DISTANCE(ctrl) <= op_limit);
|
||||
#else
|
||||
ASSERT(encoder->usr, op + ctrl <= op_limit);
|
||||
#endif
|
||||
COPY_COMP_PIXEL(encoder, op);
|
||||
spice_assert(op + CAST_PLT_DISTANCE(ctrl) <= op_limit);
|
||||
|
||||
ASSERT(encoder->usr, op <= op_limit);
|
||||
|
||||
for (--ctrl; ctrl; ctrl--) {
|
||||
do {
|
||||
COPY_COMP_PIXEL(encoder, op);
|
||||
ASSERT(encoder->usr, op <= op_limit);
|
||||
}
|
||||
spice_extra_assert(op <= op_limit);
|
||||
} while(--ctrl);
|
||||
}
|
||||
|
||||
if (LZ_EXPECT_CONDITIONAL(op < op_limit)) {
|
||||
ctrl = decode(encoder);
|
||||
} else {
|
||||
loop = FALSE;
|
||||
if (LZ_UNEXPECT_CONDITIONAL(op >= op_limit)) {
|
||||
break;
|
||||
}
|
||||
} while (LZ_EXPECT_CONDITIONAL(loop));
|
||||
}
|
||||
|
||||
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_RGB24
|
||||
#undef LZ_RGB32
|
||||
#undef LZ_A8
|
||||
#undef LZ_RGB_ALPHA
|
||||
#undef TO_RGB32
|
||||
#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
|
||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include "log.h"
|
||||
#include "marshaller.h"
|
||||
#include "mem.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.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
|
||||
#define write_int8(ptr,v) (*((int8_t *)(ptr)) = v)
|
||||
#define write_uint8(ptr,v) (*((uint8_t *)(ptr)) = v)
|
||||
#define write_int16(ptr,v) (*((int16_t *)(ptr)) = SPICE_BYTESWAP16((uint16_t)(v)))
|
||||
#define write_uint16(ptr,v) (*((uint16_t *)(ptr)) = SPICE_BYTESWAP16((uint16_t)(v)))
|
||||
#define write_int32(ptr,v) (*((int32_t *)(ptr)) = SPICE_BYTESWAP32((uint32_t)(v)))
|
||||
#define write_uint32(ptr,v) (*((uint32_t *)(ptr)) = SPICE_BYTESWAP32((uint32_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)))
|
||||
#define write_int16(ptr,v) (((uint16_unaligned_t *)(ptr))->val = SPICE_BYTESWAP16((uint16_t)(v)))
|
||||
#define write_uint16(ptr,v) (((uint16_unaligned_t *)(ptr))->val = SPICE_BYTESWAP16((uint16_t)(v)))
|
||||
#define write_int32(ptr,v) (((uint32_unaligned_t *)(ptr))->val = SPICE_BYTESWAP32((uint32_t)(v)))
|
||||
#define write_uint32(ptr,v) (((uint32_unaligned_t *)(ptr))->val = SPICE_BYTESWAP32((uint32_t)(v)))
|
||||
#define write_int64(ptr,v) (((uint64_unaligned_t *)(ptr))->val = SPICE_BYTESWAP64((uint64_t)(v)))
|
||||
#define write_uint64(ptr,v) (((uint64_unaligned_t *)(ptr))->val = SPICE_BYTESWAP64((uint64_t)(v)))
|
||||
#else
|
||||
#define write_int8(ptr,v) (*((int8_t *)(ptr)) = v)
|
||||
#define write_uint8(ptr,v) (*((uint8_t *)(ptr)) = v)
|
||||
#define write_int16(ptr,v) (*((int16_t *)(ptr)) = v)
|
||||
#define write_uint16(ptr,v) (*((uint16_t *)(ptr)) = v)
|
||||
#define write_int32(ptr,v) (*((int32_t *)(ptr)) = v)
|
||||
#define write_uint32(ptr,v) (*((uint32_t *)(ptr)) = v)
|
||||
#define write_int64(ptr,v) (*((int64_t *)(ptr)) = v)
|
||||
#define write_uint64(ptr,v) (*((uint64_t *)(ptr)) = v)
|
||||
#define write_int16(ptr,v) (((int16_unaligned_t *)(ptr))->val = v)
|
||||
#define write_uint16(ptr,v) (((uint16_unaligned_t *)(ptr))->val = v)
|
||||
#define write_int32(ptr,v) (((int32_unaligned_t *)(ptr))->val = v)
|
||||
#define write_uint32(ptr,v) (((uint32_unaligned_t *)(ptr))->val = v)
|
||||
#define write_int64(ptr,v) (((int64_unaligned_t *)(ptr))->val = v)
|
||||
#define write_uint64(ptr,v) (((uint64_unaligned_t *)(ptr))->val = v)
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
@ -68,7 +94,6 @@ typedef struct SpiceMarshallerData SpiceMarshallerData;
|
||||
typedef struct {
|
||||
SpiceMarshaller *marshaller;
|
||||
int item_nr;
|
||||
int is_64bit;
|
||||
size_t offset;
|
||||
} MarshallerRef;
|
||||
|
||||
@ -80,25 +105,26 @@ struct SpiceMarshaller {
|
||||
MarshallerRef pointer_ref;
|
||||
|
||||
int n_items;
|
||||
int items_size; /* number of items availible in items */
|
||||
int items_size; /* number of items available in items */
|
||||
MarshallerItem *items;
|
||||
|
||||
MarshallerItem static_items[N_STATIC_ITEMS];
|
||||
int num_fd;
|
||||
int fd[4];
|
||||
};
|
||||
|
||||
struct SpiceMarshallerData {
|
||||
size_t total_size;
|
||||
size_t base;
|
||||
SpiceMarshaller *marshallers;
|
||||
SpiceMarshaller *last_marshaller;
|
||||
|
||||
size_t current_buffer_position;
|
||||
MarshallerBuffer *current_buffer;
|
||||
MarshallerItem *current_buffer_item;
|
||||
MarshallerBuffer *buffers;
|
||||
|
||||
SpiceMarshaller static_marshaller;
|
||||
MarshallerBuffer static_buffer;
|
||||
// first marshaller and buffer are statically allocated here
|
||||
SpiceMarshaller marshallers[1];
|
||||
MarshallerBuffer buffers[1];
|
||||
};
|
||||
|
||||
static void spice_marshaller_init(SpiceMarshaller *m,
|
||||
@ -111,6 +137,8 @@ static void spice_marshaller_init(SpiceMarshaller *m,
|
||||
m->n_items = 0;
|
||||
m->items_size = N_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)
|
||||
@ -120,16 +148,15 @@ SpiceMarshaller *spice_marshaller_new(void)
|
||||
|
||||
d = spice_new(SpiceMarshallerData, 1);
|
||||
|
||||
d->last_marshaller = d->marshallers = &d->static_marshaller;
|
||||
d->last_marshaller = d->marshallers;
|
||||
d->total_size = 0;
|
||||
d->base = 0;
|
||||
d->buffers = &d->static_buffer;
|
||||
d->buffers->next = NULL;
|
||||
d->current_buffer = d->buffers;
|
||||
d->current_buffer_position = 0;
|
||||
d->current_buffer_item = NULL;
|
||||
|
||||
m = &d->static_marshaller;
|
||||
m = d->marshallers;
|
||||
spice_marshaller_init(m, d);
|
||||
|
||||
return m;
|
||||
@ -160,6 +187,7 @@ void spice_marshaller_reset(SpiceMarshaller *m)
|
||||
{
|
||||
SpiceMarshaller *m2, *next;
|
||||
SpiceMarshallerData *d;
|
||||
int i;
|
||||
|
||||
/* Only supported for root marshaller */
|
||||
assert(m->data->marshallers == m);
|
||||
@ -179,6 +207,14 @@ void spice_marshaller_reset(SpiceMarshaller *m)
|
||||
m->n_items = 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->last_marshaller = d->marshallers;
|
||||
d->total_size = 0;
|
||||
@ -238,6 +274,11 @@ static size_t remaining_buffer_size(SpiceMarshallerData *d)
|
||||
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)
|
||||
{
|
||||
MarshallerItem *item;
|
||||
@ -276,7 +317,7 @@ uint8_t *spice_marshaller_reserve_space(SpiceMarshaller *m, size_t size)
|
||||
/* Large item, allocate by itself */
|
||||
item->data = (uint8_t *)spice_malloc(size);
|
||||
item->len = size;
|
||||
item->free_data = (spice_marshaller_item_free_func)free;
|
||||
item->free_data = reserve_space_free_data;
|
||||
item->opaque = NULL;
|
||||
} else {
|
||||
/* Use next buffer */
|
||||
@ -310,8 +351,8 @@ void spice_marshaller_unreserve_space(SpiceMarshaller *m, size_t size)
|
||||
item->len -= size;
|
||||
}
|
||||
|
||||
uint8_t *spice_marshaller_add_ref_full(SpiceMarshaller *m, uint8_t *data, size_t size,
|
||||
spice_marshaller_item_free_func free_data, void *opaque)
|
||||
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)
|
||||
{
|
||||
MarshallerItem *item;
|
||||
SpiceMarshallerData *d;
|
||||
@ -333,7 +374,7 @@ uint8_t *spice_marshaller_add_ref_full(SpiceMarshaller *m, uint8_t *data, size_t
|
||||
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;
|
||||
|
||||
@ -342,18 +383,21 @@ uint8_t *spice_marshaller_add(SpiceMarshaller *m, uint8_t *data, size_t size)
|
||||
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;
|
||||
|
||||
for (i = 0; i < chunks->num_chunks; i++) {
|
||||
spice_marshaller_add_ref(m, chunks->chunk[i].data,
|
||||
chunks->chunk[i].len);
|
||||
spice_marshaller_add_by_ref(m, chunks->chunk[i].data,
|
||||
chunks->chunk[i].len);
|
||||
}
|
||||
}
|
||||
|
||||
@ -373,13 +417,13 @@ SpiceMarshaller *spice_marshaller_get_submarshaller(SpiceMarshaller *m)
|
||||
return m2;
|
||||
}
|
||||
|
||||
SpiceMarshaller *spice_marshaller_get_ptr_submarshaller(SpiceMarshaller *m, int is_64bit)
|
||||
SpiceMarshaller *spice_marshaller_get_ptr_submarshaller(SpiceMarshaller *m)
|
||||
{
|
||||
SpiceMarshaller *m2;
|
||||
uint8_t *p;
|
||||
int size;
|
||||
|
||||
size = is_64bit ? 8 : 4;
|
||||
size = 4;
|
||||
|
||||
p = spice_marshaller_reserve_space(m, 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.item_nr = m->n_items - 1;
|
||||
m2->pointer_ref.offset = m->items[m->n_items - 1].len - size;
|
||||
m2->pointer_ref.is_64bit = is_64bit;
|
||||
|
||||
return m2;
|
||||
}
|
||||
|
||||
uint8_t *lookup_ref(MarshallerRef *ref)
|
||||
static uint8_t *lookup_ref(MarshallerRef *ref)
|
||||
{
|
||||
MarshallerItem *item;
|
||||
|
||||
@ -419,7 +462,7 @@ uint8_t *spice_marshaller_linearize(SpiceMarshaller *m, size_t skip_bytes,
|
||||
/* Only supported for root marshaller */
|
||||
assert(m->data->marshallers == m);
|
||||
|
||||
if (m->n_items == 1) {
|
||||
if (m->n_items == 1 && m->next == NULL) {
|
||||
*free_res = FALSE;
|
||||
if (m->items[0].len <= skip_bytes) {
|
||||
*len = 0;
|
||||
@ -492,18 +535,19 @@ void spice_marshaller_flush(SpiceMarshaller *m)
|
||||
for (m2 = m; m2 != NULL; m2 = m2->next) {
|
||||
if (m2->pointer_ref.marshaller != NULL && m2->total_size > 0) {
|
||||
ptr_pos = lookup_ref(&m2->pointer_ref);
|
||||
if (m2->pointer_ref.is_64bit) {
|
||||
write_uint64(ptr_pos,
|
||||
spice_marshaller_get_offset(m2));
|
||||
} else {
|
||||
write_uint32(ptr_pos,
|
||||
spice_marshaller_get_offset(m2));
|
||||
}
|
||||
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 n_vec, size_t skip_bytes)
|
||||
{
|
||||
@ -525,7 +569,7 @@ int spice_marshaller_fill_iovec(SpiceMarshaller *m, struct iovec *vec,
|
||||
if (v == n_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;
|
||||
skip_bytes = 0;
|
||||
v++;
|
||||
@ -535,7 +579,6 @@ int spice_marshaller_fill_iovec(SpiceMarshaller *m, struct iovec *vec,
|
||||
|
||||
return v;
|
||||
}
|
||||
#endif
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
@ -613,3 +656,26 @@ void *spice_marshaller_add_int8(SpiceMarshaller *m, int8_t v)
|
||||
write_int8(ptr, v);
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#ifndef _H_MARSHALLER
|
||||
#define _H_MARSHALLER
|
||||
#ifndef H_SPICE_COMMON_MARSHALLER
|
||||
#define H_SPICE_COMMON_MARSHALLER
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <spice/macros.h>
|
||||
#include <spice/types.h>
|
||||
#include "mem.h"
|
||||
#ifndef WIN32
|
||||
#include <sys/uio.h>
|
||||
#else
|
||||
struct iovec;
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
SPICE_BEGIN_DECLS
|
||||
|
||||
typedef struct SpiceMarshaller SpiceMarshaller;
|
||||
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);
|
||||
uint8_t *spice_marshaller_reserve_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_ref(SpiceMarshaller *m, uint8_t *data, size_t size);
|
||||
uint8_t *spice_marshaller_add_ref_full(SpiceMarshaller *m, uint8_t *data, size_t size,
|
||||
spice_marshaller_item_free_func free_data, void *opaque);
|
||||
void spice_marshaller_add_ref_chunks(SpiceMarshaller *m, SpiceChunks *chunks);
|
||||
uint8_t *spice_marshaller_add(SpiceMarshaller *m, const 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_by_ref_full(SpiceMarshaller *m, uint8_t *data, size_t size,
|
||||
spice_marshaller_item_free_func free_data, void *opaque);
|
||||
void spice_marshaller_add_chunks_by_ref(SpiceMarshaller *m, SpiceChunks *chunks);
|
||||
void spice_marshaller_flush(SpiceMarshaller *m);
|
||||
void spice_marshaller_set_base(SpiceMarshaller *m, size_t base);
|
||||
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_total_size(SpiceMarshaller *m);
|
||||
SpiceMarshaller *spice_marshaller_get_submarshaller(SpiceMarshaller *m);
|
||||
SpiceMarshaller *spice_marshaller_get_ptr_submarshaller(SpiceMarshaller *m, int is_64bit);
|
||||
#ifndef WIN32
|
||||
SpiceMarshaller *spice_marshaller_get_ptr_submarshaller(SpiceMarshaller *m);
|
||||
int spice_marshaller_fill_iovec(SpiceMarshaller *m, struct iovec *vec,
|
||||
int n_vec, size_t skip_bytes);
|
||||
#endif
|
||||
void *spice_marshaller_add_uint64(SpiceMarshaller *m, uint64_t v);
|
||||
void *spice_marshaller_add_int64(SpiceMarshaller *m, int64_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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
void spice_marshaller_add_fd(SpiceMarshaller *m, int fd);
|
||||
int spice_marshaller_get_fds(SpiceMarshaller *m, int fd[4]);
|
||||
|
||||
SPICE_END_DECLS
|
||||
|
||||
#endif
|
||||
|
||||
54
common/mem.c
54
common/mem.c
@ -15,20 +15,17 @@
|
||||
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 "mem.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#ifndef MALLOC_ERROR
|
||||
#define MALLOC_ERROR(format, ...) { \
|
||||
printf(format "\n", ## __VA_ARGS__); \
|
||||
abort(); \
|
||||
}
|
||||
#define MALLOC_ERROR(...) SPICE_STMT_START { \
|
||||
spice_error(__VA_ARGS__); \
|
||||
abort(); \
|
||||
} SPICE_STMT_END
|
||||
#endif
|
||||
|
||||
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 *copy;
|
||||
size_t len;
|
||||
|
||||
if (str == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
copy = (char *)spice_malloc(strlen(str) + 1);
|
||||
strcpy(copy, str);
|
||||
len = strlen(str) + 1;
|
||||
copy = (char *)spice_malloc(len);
|
||||
memcpy(copy, str, len);
|
||||
return copy;
|
||||
}
|
||||
|
||||
@ -94,8 +93,7 @@ void *spice_malloc(size_t n_bytes)
|
||||
return mem;
|
||||
}
|
||||
|
||||
MALLOC_ERROR("spice_malloc: panic: unable to allocate %lu bytes\n",
|
||||
(unsigned long)n_bytes);
|
||||
MALLOC_ERROR("unable to allocate %lu bytes", (unsigned long)n_bytes);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@ -111,8 +109,7 @@ void *spice_malloc0(size_t n_bytes)
|
||||
return mem;
|
||||
}
|
||||
|
||||
MALLOC_ERROR("spice_malloc0: panic: unable to allocate %lu bytes\n",
|
||||
(unsigned long)n_bytes);
|
||||
MALLOC_ERROR("unable to allocate %lu bytes", (unsigned long)n_bytes);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@ -126,8 +123,7 @@ void *spice_realloc(void *mem, size_t n_bytes)
|
||||
return mem;
|
||||
}
|
||||
|
||||
MALLOC_ERROR("spice_realloc: panic: unable to allocate %lu bytes\n",
|
||||
(unsigned long)n_bytes);
|
||||
MALLOC_ERROR("unable to allocate %lu bytes", (unsigned long)n_bytes);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
@ -179,7 +175,7 @@ void *spice_realloc_n(void *mem, size_t n_blocks, size_t n_block_bytes)
|
||||
if (SIZE_OVERFLOWS (n_blocks, n_block_bytes)) {
|
||||
MALLOC_ERROR("spice_realloc_n: overflow allocating %lu*%lu bytes",
|
||||
(unsigned long)n_blocks, (unsigned long)n_block_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
return spice_realloc(mem, n_blocks * n_block_bytes);
|
||||
}
|
||||
@ -295,3 +291,25 @@ size_t spice_buffer_remove(SpiceBuffer *buffer, size_t len)
|
||||
buffer->offset -= 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
|
||||
|
||||
61
common/mem.h
61
common/mem.h
@ -16,19 +16,14 @@
|
||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _H_MEM
|
||||
#define _H_MEM
|
||||
#ifndef H_SPICE_COMMON_MEM
|
||||
#define H_SPICE_COMMON_MEM
|
||||
|
||||
#include "log.h"
|
||||
#include <stdlib.h>
|
||||
#include <spice/macros.h>
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
SPICE_BEGIN_DECLS
|
||||
|
||||
#ifdef STDC_HEADERS
|
||||
# include <stdlib.h>
|
||||
@ -118,7 +113,7 @@ size_t spice_strnlen(const char *str, size_t max_len);
|
||||
__p; \
|
||||
}))
|
||||
# define _SPICE_RENEW(struct_type, mem, n_structs, func) \
|
||||
(struct_type *) (__extension__ ({ \
|
||||
(struct_type *) (__extension__ ({ \
|
||||
size_t __n = (size_t) (n_structs); \
|
||||
size_t __s = sizeof (struct_type); \
|
||||
void *__p = (void *) (mem); \
|
||||
@ -134,7 +129,6 @@ size_t spice_strnlen(const char *str, size_t max_len);
|
||||
#else
|
||||
|
||||
/* Unoptimized version: always call the _n() function. */
|
||||
|
||||
#define _SPICE_NEW(struct_type, n_structs, func) \
|
||||
((struct_type *) spice_##func##_n ((n_structs), sizeof (struct_type)))
|
||||
#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
|
||||
|
||||
/* 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_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)
|
||||
@ -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_remove(SpiceBuffer *buffer, size_t len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
SPICE_END_DECLS
|
||||
|
||||
#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.
|
||||
*/
|
||||
|
||||
#ifndef _H_MESSAGES
|
||||
#define _H_MESSAGES
|
||||
#ifndef H_SPICE_COMMON_MESSAGES
|
||||
#define H_SPICE_COMMON_MESSAGES
|
||||
|
||||
#include <spice/protocol.h>
|
||||
#include "draw.h"
|
||||
#include <spice/macros.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#ifdef USE_SMARTCARD
|
||||
#include <libcacard.h>
|
||||
#endif
|
||||
|
||||
typedef struct SpiceMsgData {
|
||||
uint32_t data_size;
|
||||
uint8_t data[0];
|
||||
} SpiceMsgData;
|
||||
#include "draw.h"
|
||||
|
||||
typedef struct SpiceMsgEmpty {
|
||||
} SpiceMsgEmpty;
|
||||
SPICE_BEGIN_DECLS
|
||||
|
||||
typedef struct SpiceMsgInputsInit {
|
||||
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 {
|
||||
typedef struct SpiceMsgCompressedData {
|
||||
uint8_t type;
|
||||
uint64_t id;
|
||||
} SpiceResourceID;
|
||||
|
||||
typedef struct SpiceResourceList {
|
||||
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;
|
||||
uint32_t uncompressed_size;
|
||||
uint32_t compressed_size;
|
||||
uint8_t *compressed_data;
|
||||
} SpiceMsgCompressedData;
|
||||
|
||||
#define SPICE_AGENT_MAX_DATA_SIZE 2048
|
||||
|
||||
typedef struct SpiceMsgMainAgentTokens {
|
||||
uint32_t num_tokens;
|
||||
} SpiceMsgMainAgentTokens, SpiceMsgcMainAgentTokens, SpiceMsgcMainAgentStart;
|
||||
|
||||
typedef struct SpiceMsgcClientInfo {
|
||||
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;
|
||||
#ifdef USE_SMARTCARD
|
||||
typedef struct SpiceMsgSmartcard {
|
||||
VSCMsgType type;
|
||||
uint32_t length;
|
||||
uint32_t reader_id;
|
||||
uint8_t data[0];
|
||||
} SpiceMsgDisplayStreamData;
|
||||
|
||||
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
|
||||
}
|
||||
} SpiceMsgSmartcard;
|
||||
#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
|
||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include "pixman_utils.h"
|
||||
#include "spice_common.h"
|
||||
#include <spice/macros.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.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) \
|
||||
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--) { \
|
||||
_type dst = *ptr; \
|
||||
@ -206,12 +210,12 @@ void spice_pixman_fill_rect(pixman_image_t *dest,
|
||||
depth = spice_pixman_image_get_bpp(dest);
|
||||
/* stride is in bytes, depth in bits */
|
||||
|
||||
ASSERT(x >= 0);
|
||||
ASSERT(y >= 0);
|
||||
ASSERT(width > 0);
|
||||
ASSERT(height > 0);
|
||||
ASSERT(x + width <= pixman_image_get_width(dest));
|
||||
ASSERT(y + height <= pixman_image_get_height(dest));
|
||||
spice_assert(x >= 0);
|
||||
spice_assert(y >= 0);
|
||||
spice_assert(width > 0);
|
||||
spice_assert(height > 0);
|
||||
spice_assert(x + width <= pixman_image_get_width(dest));
|
||||
spice_assert(y + height <= pixman_image_get_height(dest));
|
||||
|
||||
if (pixman_fill(bits,
|
||||
stride / 4,
|
||||
@ -231,7 +235,7 @@ void spice_pixman_fill_rect(pixman_image_t *dest,
|
||||
byte_width = 2 * width;
|
||||
value = (value & 0xffff) * 0x00010001;
|
||||
} else {
|
||||
ASSERT (depth == 32)
|
||||
spice_assert (depth == 32);
|
||||
byte_line = ((uint8_t *)bits) + stride * y + x * 4;
|
||||
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);
|
||||
/* stride is in bytes, depth in bits */
|
||||
|
||||
ASSERT(x >= 0);
|
||||
ASSERT(y >= 0);
|
||||
ASSERT(width > 0);
|
||||
ASSERT(height > 0);
|
||||
ASSERT(x + width <= pixman_image_get_width(dest));
|
||||
ASSERT(y + height <= pixman_image_get_height(dest));
|
||||
ASSERT(rop >= 0 && rop < 16);
|
||||
spice_assert(x >= 0);
|
||||
spice_assert(y >= 0);
|
||||
spice_assert(width > 0);
|
||||
spice_assert(height > 0);
|
||||
spice_assert(x + width <= pixman_image_get_width(dest));
|
||||
spice_assert(y + height <= pixman_image_get_height(dest));
|
||||
spice_assert(rop < 16);
|
||||
|
||||
if (depth == 8) {
|
||||
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_height = pixman_image_get_height(tile);
|
||||
|
||||
ASSERT(x >= 0);
|
||||
ASSERT(y >= 0);
|
||||
ASSERT(width > 0);
|
||||
ASSERT(height > 0);
|
||||
ASSERT(x + width <= pixman_image_get_width(dest));
|
||||
ASSERT(y + height <= pixman_image_get_height(dest));
|
||||
ASSERT(depth == spice_pixman_image_get_bpp(tile));
|
||||
spice_assert(x >= 0);
|
||||
spice_assert(y >= 0);
|
||||
spice_assert(width > 0);
|
||||
spice_assert(height > 0);
|
||||
spice_assert(x + width <= pixman_image_get_width(dest));
|
||||
spice_assert(y + height <= pixman_image_get_height(dest));
|
||||
spice_assert(depth == spice_pixman_image_get_bpp(tile));
|
||||
|
||||
tile_start_x = (x - offset_x) % tile_width;
|
||||
if (tile_start_x < 0) {
|
||||
@ -406,7 +410,7 @@ void spice_pixman_tile_rect(pixman_image_t *dest,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ASSERT (depth == 32);
|
||||
spice_assert (depth == 32);
|
||||
|
||||
byte_line = ((uint8_t *)bits) + stride * y + 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_height = pixman_image_get_height(tile);
|
||||
|
||||
ASSERT(x >= 0);
|
||||
ASSERT(y >= 0);
|
||||
ASSERT(width > 0);
|
||||
ASSERT(height > 0);
|
||||
ASSERT(x + width <= pixman_image_get_width(dest));
|
||||
ASSERT(y + height <= pixman_image_get_height(dest));
|
||||
ASSERT(rop >= 0 && rop < 16);
|
||||
ASSERT(depth == spice_pixman_image_get_bpp(tile));
|
||||
spice_assert(x >= 0);
|
||||
spice_assert(y >= 0);
|
||||
spice_assert(width > 0);
|
||||
spice_assert(height > 0);
|
||||
spice_assert(x + width <= pixman_image_get_width(dest));
|
||||
spice_assert(y + height <= pixman_image_get_height(dest));
|
||||
spice_assert(rop < 16);
|
||||
spice_assert(depth == spice_pixman_image_get_bpp(tile));
|
||||
|
||||
tile_start_x = (x - offset_x) % tile_width;
|
||||
if (tile_start_x < 0) {
|
||||
@ -504,7 +508,7 @@ void spice_pixman_tile_rect_rop(pixman_image_t *dest,
|
||||
} else {
|
||||
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;
|
||||
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;
|
||||
int byte_width;
|
||||
|
||||
if (!src) {
|
||||
fprintf(stderr, "missing src!");
|
||||
return;
|
||||
}
|
||||
|
||||
bits = pixman_image_get_data(dest);
|
||||
stride = pixman_image_get_stride(dest);
|
||||
depth = spice_pixman_image_get_bpp(dest);
|
||||
@ -569,17 +578,17 @@ void spice_pixman_blit(pixman_image_t *dest,
|
||||
return;
|
||||
}
|
||||
|
||||
ASSERT(src_x >= 0);
|
||||
ASSERT(src_y >= 0);
|
||||
ASSERT(dest_x >= 0);
|
||||
ASSERT(dest_y >= 0);
|
||||
ASSERT(width > 0);
|
||||
ASSERT(height > 0);
|
||||
ASSERT(dest_x + width <= pixman_image_get_width(dest));
|
||||
ASSERT(dest_y + height <= pixman_image_get_height(dest));
|
||||
ASSERT(src_x + width <= pixman_image_get_width(src));
|
||||
ASSERT(src_y + height <= pixman_image_get_height(src));
|
||||
ASSERT(depth == src_depth);
|
||||
spice_assert(src_x >= 0);
|
||||
spice_assert(src_y >= 0);
|
||||
spice_assert(dest_x >= 0);
|
||||
spice_assert(dest_y >= 0);
|
||||
spice_assert(width > 0);
|
||||
spice_assert(height > 0);
|
||||
spice_assert(dest_x + width <= pixman_image_get_width(dest));
|
||||
spice_assert(dest_y + height <= pixman_image_get_height(dest));
|
||||
spice_assert(src_x + width <= pixman_image_get_width(src));
|
||||
spice_assert(src_y + height <= pixman_image_get_height(src));
|
||||
spice_assert(depth == src_depth);
|
||||
|
||||
if (pixman_blt(src_bits,
|
||||
bits,
|
||||
@ -601,7 +610,7 @@ void spice_pixman_blit(pixman_image_t *dest,
|
||||
byte_width = width * 2;
|
||||
src_line = ((uint8_t *)src_bits) + src_stride * src_y + src_x * 2;
|
||||
} else {
|
||||
ASSERT (depth == 32);
|
||||
spice_assert (depth == 32);
|
||||
byte_line = ((uint8_t *)bits) + stride * dest_y + dest_x * 4;
|
||||
byte_width = width * 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;
|
||||
}
|
||||
|
||||
ASSERT(src_x >= 0);
|
||||
ASSERT(src_y >= 0);
|
||||
ASSERT(dest_x >= 0);
|
||||
ASSERT(dest_y >= 0);
|
||||
ASSERT(width > 0);
|
||||
ASSERT(height > 0);
|
||||
ASSERT(dest_x + width <= pixman_image_get_width(dest));
|
||||
ASSERT(dest_y + height <= pixman_image_get_height(dest));
|
||||
ASSERT(src_x + width <= pixman_image_get_width(src));
|
||||
ASSERT(src_y + height <= pixman_image_get_height(src));
|
||||
ASSERT(depth == src_depth);
|
||||
spice_assert(src_x >= 0);
|
||||
spice_assert(src_y >= 0);
|
||||
spice_assert(dest_x >= 0);
|
||||
spice_assert(dest_y >= 0);
|
||||
spice_assert(width > 0);
|
||||
spice_assert(height > 0);
|
||||
spice_assert(dest_x + width <= pixman_image_get_width(dest));
|
||||
spice_assert(dest_y + height <= pixman_image_get_height(dest));
|
||||
spice_assert(src_x + width <= pixman_image_get_width(src));
|
||||
spice_assert(src_y + height <= pixman_image_get_height(src));
|
||||
spice_assert(depth == src_depth);
|
||||
|
||||
if (depth == 8) {
|
||||
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 {
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
ASSERT(src_x >= 0);
|
||||
ASSERT(src_y >= 0);
|
||||
ASSERT(dest_x >= 0);
|
||||
ASSERT(dest_y >= 0);
|
||||
ASSERT(width > 0);
|
||||
ASSERT(height > 0);
|
||||
ASSERT(dest_x + width <= pixman_image_get_width(dest));
|
||||
ASSERT(dest_y + height <= pixman_image_get_height(dest));
|
||||
ASSERT(src_x + width <= pixman_image_get_width(src));
|
||||
ASSERT(src_y + height <= pixman_image_get_height(src));
|
||||
ASSERT(depth == spice_pixman_image_get_bpp(src));
|
||||
spice_assert(src_x >= 0);
|
||||
spice_assert(src_y >= 0);
|
||||
spice_assert(dest_x >= 0);
|
||||
spice_assert(dest_y >= 0);
|
||||
spice_assert(width > 0);
|
||||
spice_assert(height > 0);
|
||||
spice_assert(dest_x + width <= pixman_image_get_width(dest));
|
||||
spice_assert(dest_y + height <= pixman_image_get_height(dest));
|
||||
spice_assert(src_x + width <= pixman_image_get_width(src));
|
||||
spice_assert(src_y + height <= pixman_image_get_height(src));
|
||||
spice_assert(depth == spice_pixman_image_get_bpp(src));
|
||||
|
||||
if (depth == 8) {
|
||||
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;
|
||||
}
|
||||
} else {
|
||||
ASSERT (depth == 32);
|
||||
spice_assert (depth == 32);
|
||||
byte_line = ((uint8_t *)bits) + stride * dest_y + dest_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:
|
||||
return PIXMAN_a8r8g8b8;
|
||||
default:
|
||||
printf("Unknown surface format %d\n", surface_format);
|
||||
abort();
|
||||
g_error("Unknown surface format %d\n", surface_format);
|
||||
break;
|
||||
}
|
||||
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:
|
||||
return PIXMAN_a8r8g8b8;
|
||||
|
||||
case SPICE_BITMAP_FMT_8BIT_A:
|
||||
return PIXMAN_a8;
|
||||
|
||||
case SPICE_BITMAP_FMT_INVALID:
|
||||
default:
|
||||
printf("Unknown bitmap format %d\n", bitmap_format);
|
||||
abort();
|
||||
g_error("Unknown bitmap format %d\n", bitmap_format);
|
||||
return PIXMAN_a8r8g8b8;
|
||||
}
|
||||
}
|
||||
@ -985,25 +995,13 @@ pixman_image_t *spice_bitmap_try_as_pixman(int src_format,
|
||||
|
||||
switch (src_format) {
|
||||
case SPICE_BITMAP_FMT_32BIT:
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
pixman_format = PIXMAN_b8g8r8x8;
|
||||
#else
|
||||
pixman_format = PIXMAN_x8r8g8b8;
|
||||
#endif
|
||||
pixman_format = PIXMAN_LE_x8r8g8b8;
|
||||
break;
|
||||
case SPICE_BITMAP_FMT_RGBA:
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
pixman_format = PIXMAN_b8g8r8a8;
|
||||
#else
|
||||
pixman_format = PIXMAN_a8r8g8b8;
|
||||
#endif
|
||||
pixman_format = PIXMAN_LE_a8r8g8b8;
|
||||
break;
|
||||
case SPICE_BITMAP_FMT_24BIT:
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
pixman_format = PIXMAN_b8g8r8;
|
||||
#else
|
||||
pixman_format = PIXMAN_r8g8b8;
|
||||
#endif
|
||||
pixman_format = PIXMAN_LE_r8g8b8;
|
||||
break;
|
||||
case SPICE_BITMAP_FMT_16BIT:
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
@ -1037,26 +1035,6 @@ pixman_image_t *spice_bitmap_try_as_pixman(int src_format,
|
||||
#define UINT32_FROM_LE(x) (x)
|
||||
#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,
|
||||
uint8_t* src, int src_stride,
|
||||
int width, uint8_t* end)
|
||||
@ -1078,6 +1056,15 @@ static void bitmap_32_to_32(uint8_t* dest, int dest_stride,
|
||||
#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,
|
||||
uint8_t* src, int src_stride,
|
||||
int width, uint8_t* end)
|
||||
@ -1131,7 +1118,7 @@ static void bitmap_8_32_to_32(uint8_t *dest, int dest_stride,
|
||||
#endif
|
||||
|
||||
if (!palette) {
|
||||
PANIC("No palette");
|
||||
spice_error("No palette");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1177,7 +1164,7 @@ static void bitmap_8_16_to_16_555(uint8_t *dest, int dest_stride,
|
||||
#endif
|
||||
|
||||
if (!palette) {
|
||||
PANIC("No palette");
|
||||
spice_error("No palette");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1223,7 +1210,7 @@ static void bitmap_4be_32_to_32(uint8_t* dest, int dest_stride,
|
||||
#endif
|
||||
|
||||
if (!palette) {
|
||||
PANIC("No palette");
|
||||
spice_error("No palette");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1273,7 +1260,7 @@ static void bitmap_4be_16_to_16_555(uint8_t* dest, int dest_stride,
|
||||
#endif
|
||||
|
||||
if (!palette) {
|
||||
PANIC("No palette");
|
||||
spice_error("No palette");
|
||||
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)));
|
||||
}
|
||||
@ -1323,7 +1310,7 @@ static void bitmap_1be_32_to_32(uint8_t* dest, int dest_stride,
|
||||
uint32_t fore_color;
|
||||
uint32_t back_color;
|
||||
|
||||
ASSERT(palette != NULL);
|
||||
spice_assert(palette != NULL);
|
||||
|
||||
if (!palette) {
|
||||
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 back_color;
|
||||
|
||||
ASSERT(palette != NULL);
|
||||
spice_assert(palette != NULL);
|
||||
|
||||
if (!palette) {
|
||||
return;
|
||||
@ -1380,6 +1367,25 @@ static void bitmap_1be_16_to_16_555(uint8_t* dest, int dest_stride,
|
||||
|
||||
#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,
|
||||
uint8_t* src, int src_stride,
|
||||
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_stride = pixman_image_get_stride(dest_image);
|
||||
if (!(flags & SPICE_BITMAP_FLAGS_TOP_DOWN)) {
|
||||
ASSERT(height > 0);
|
||||
spice_assert(height > 0);
|
||||
dest += dest_stride * (height - 1);
|
||||
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:
|
||||
bitmap_32_to_32(dest, dest_stride, src, src_stride, width, end);
|
||||
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:
|
||||
bitmap_24_to_32(dest, dest_stride, src, src_stride, width, end);
|
||||
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) {
|
||||
bitmap_8_16_to_16_555(dest, dest_stride, src, src_stride, width, end, palette);
|
||||
} else {
|
||||
PANIC("Unsupported palette format");
|
||||
spice_error("Unsupported palette format");
|
||||
}
|
||||
break;
|
||||
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) {
|
||||
bitmap_4be_16_to_16_555(dest, dest_stride, src, src_stride, width, end, palette);
|
||||
} else {
|
||||
PANIC("Unsupported palette format");
|
||||
spice_error("Unsupported palette format");
|
||||
}
|
||||
break;
|
||||
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) {
|
||||
bitmap_1be_16_to_16_555(dest, dest_stride, src, src_stride, width, end, palette);
|
||||
} else {
|
||||
PANIC("Unsupported palette format");
|
||||
spice_error("Unsupported palette format");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
PANIC("Unsupported bitmap format");
|
||||
spice_error("Unsupported bitmap format");
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@ -16,20 +16,29 @@
|
||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _H__PIXMAN_UTILS
|
||||
#define _H__PIXMAN_UTILS
|
||||
#ifndef H_SPICE_COMMON_PIXMAN_UTILS
|
||||
#define H_SPICE_COMMON_PIXMAN_UTILS
|
||||
|
||||
#include <spice/types.h>
|
||||
#include <spice/macros.h>
|
||||
#include <stdlib.h>
|
||||
#define PIXMAN_DONT_DEFINE_STDINT
|
||||
#include <pixman.h>
|
||||
|
||||
#include "draw.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
# 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
|
||||
|
||||
SPICE_BEGIN_DECLS
|
||||
|
||||
/* This lists all possible 2 argument binary raster ops.
|
||||
* This enum has the same values as the X11 GXcopy type
|
||||
* 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 dest_x, int dest_y);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
SPICE_END_DECLS
|
||||
|
||||
#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/>.
|
||||
*/
|
||||
|
||||
#ifndef __QUIC_H
|
||||
#define __QUIC_H
|
||||
#ifndef H_SPICE_COMMON_QUIC
|
||||
#define H_SPICE_COMMON_QUIC
|
||||
|
||||
#include "quic_config.h"
|
||||
#include <spice/macros.h>
|
||||
#include "macros.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
SPICE_BEGIN_DECLS
|
||||
|
||||
typedef enum {
|
||||
QUIC_IMAGE_TYPE_INVALID,
|
||||
@ -41,9 +40,10 @@ typedef void *QuicContext;
|
||||
|
||||
typedef struct QuicUsrContext QuicUsrContext;
|
||||
struct QuicUsrContext {
|
||||
void (*error)(QuicUsrContext *usr, const char *fmt, ...);
|
||||
void (*warn)(QuicUsrContext *usr, const char *fmt, ...);
|
||||
void (*info)(QuicUsrContext *usr, const char *fmt, ...);
|
||||
SPICE_GNUC_NORETURN
|
||||
SPICE_GNUC_PRINTF(2, 3) void (*error)(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 (*free)(QuicUsrContext *usr, void *ptr);
|
||||
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);
|
||||
void quic_destroy(QuicContext *quic);
|
||||
|
||||
void quic_init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
SPICE_END_DECLS
|
||||
|
||||
#endif
|
||||
|
||||
@ -16,15 +16,13 @@
|
||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __QUIC_CONFIG_H
|
||||
#define __QUIC_CONFIG_H
|
||||
#ifndef H_SPICE_COMMON_QUIC_CONFIG
|
||||
#define H_SPICE_COMMON_QUIC_CONFIG
|
||||
|
||||
#include <spice/types.h>
|
||||
#include <spice/macros.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
SPICE_BEGIN_DECLS
|
||||
|
||||
#ifdef __GNUC__
|
||||
#include <string.h>
|
||||
@ -41,8 +39,6 @@ extern "C" {
|
||||
#endif // QXLDD
|
||||
#endif //__GNUC__
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
SPICE_END_DECLS
|
||||
|
||||
#endif
|
||||
|
||||
@ -15,9 +15,7 @@
|
||||
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_FAMILY_8BPC
|
||||
#undef QUIC_FAMILY_8BPC
|
||||
@ -34,26 +32,19 @@
|
||||
#define BPC 5
|
||||
#endif
|
||||
|
||||
|
||||
static unsigned int FNAME(golomb_code_len)(const BYTE n, const unsigned int l)
|
||||
static inline unsigned int FNAME(golomb_code)(const BYTE n, const unsigned int l)
|
||||
{
|
||||
if (n < VNAME(family).nGRcodewords[l]) {
|
||||
return (n >> l) + 1 + l;
|
||||
} else {
|
||||
return VNAME(family).notGRcwlen[l];
|
||||
}
|
||||
return VNAME(family).golomb_code[n][l];
|
||||
}
|
||||
|
||||
static void FNAME(golomb_coding)(const BYTE n, const unsigned int l, unsigned int * const codeword,
|
||||
unsigned int * const codewordlen)
|
||||
static inline unsigned int FNAME(golomb_code_len)(const BYTE n, const unsigned int l)
|
||||
{
|
||||
if (n < VNAME(family).nGRcodewords[l]) {
|
||||
(*codeword) = bitat[l] | (n & bppmask[l]);
|
||||
(*codewordlen) = (n >> l) + l + 1;
|
||||
} else {
|
||||
(*codeword) = n - VNAME(family).nGRcodewords[l];
|
||||
(*codewordlen) = VNAME(family).notGRcwlen[l];
|
||||
}
|
||||
return VNAME(family).golomb_code_len[n][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,
|
||||
@ -74,13 +65,16 @@ static unsigned int FNAME(golomb_decoding)(const unsigned int l, const unsigned
|
||||
|
||||
/* update the bucket using just encoded curval */
|
||||
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;
|
||||
unsigned int i;
|
||||
unsigned int bestcode;
|
||||
unsigned int bestcodelen;
|
||||
//unsigned int bpp = encoder->bpp;
|
||||
|
||||
/* 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)
|
||||
{
|
||||
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
|
||||
|
||||
@ -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/>.
|
||||
*/
|
||||
|
||||
#ifndef _H_RECT
|
||||
#define _H_RECT
|
||||
#ifndef H_SPICE_COMMON_RECT
|
||||
#define H_SPICE_COMMON_RECT
|
||||
|
||||
#include "draw.h"
|
||||
#include <spice/macros.h>
|
||||
#include "draw.h"
|
||||
#include "log.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
SPICE_BEGIN_DECLS
|
||||
|
||||
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->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);
|
||||
}
|
||||
|
||||
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->right += dx;
|
||||
@ -45,24 +44,24 @@ static INLINE void rect_offset(SpiceRect* r, int dx, int 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;
|
||||
}
|
||||
|
||||
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 &&
|
||||
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 &&
|
||||
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->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);
|
||||
}
|
||||
|
||||
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 &&
|
||||
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
|
||||
|
||||
@ -117,6 +130,21 @@ static inline int rect_is_same_size(const SpiceRect& r1, const SpiceRect& 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
|
||||
|
||||
394
common/region.c
394
common/region.c
@ -15,9 +15,7 @@
|
||||
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 <stdio.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)
|
||||
{
|
||||
@ -409,7 +418,7 @@ int region_bounds_intersects(const QRegion *rgn1, const QRegion *rgn2)
|
||||
pixman_box32_t *extents1, *extents2;
|
||||
|
||||
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);
|
||||
}
|
||||
@ -441,6 +450,7 @@ void region_xor(QRegion *rgn, const QRegion *other_rgn)
|
||||
{
|
||||
pixman_region32_t intersection;
|
||||
|
||||
pixman_region32_init(&intersection);
|
||||
pixman_region32_copy(&intersection, rgn);
|
||||
pixman_region32_intersect(&intersection,
|
||||
&intersection,
|
||||
@ -510,381 +520,3 @@ void region_dump(const QRegion *rgn, const char *prefix)
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#ifndef _H_REGION
|
||||
#define _H_REGION
|
||||
#ifndef H_SPICE_COMMON_REGION
|
||||
#define H_SPICE_COMMON_REGION
|
||||
|
||||
#include <stdint.h>
|
||||
#include "draw.h"
|
||||
#include <pixman_utils.h>
|
||||
#include <spice/macros.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#include "draw.h"
|
||||
#include "pixman_utils.h"
|
||||
|
||||
SPICE_BEGIN_DECLS
|
||||
|
||||
typedef pixman_region32_t QRegion;
|
||||
|
||||
/* the left region is not contained entirely within the right region */
|
||||
#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)
|
||||
/* the regions overlap */
|
||||
#define REGION_TEST_SHARED (1 << 2)
|
||||
#define REGION_TEST_ALL \
|
||||
(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);
|
||||
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_extents(const QRegion *rgn, SpiceRect *r);
|
||||
|
||||
int region_test(const QRegion *rgn, const QRegion *other_rgn, int query);
|
||||
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_dump(const QRegion *rgn, const char *prefix);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
SPICE_END_DECLS
|
||||
|
||||
#endif
|
||||
|
||||
@ -16,14 +16,12 @@
|
||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _H_RING2
|
||||
#define _H_RING2
|
||||
#ifndef H_SPICE_COMMON_RING
|
||||
#define H_SPICE_COMMON_RING
|
||||
|
||||
#include "spice_common.h"
|
||||
#include "log.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
SPICE_BEGIN_DECLS
|
||||
|
||||
typedef struct Ring RingItem;
|
||||
typedef struct Ring {
|
||||
@ -48,14 +46,14 @@ static inline int ring_item_is_linked(RingItem *item)
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static inline void ring_add(Ring *ring, RingItem *item)
|
||||
{
|
||||
ASSERT(ring->next != NULL && ring->prev != NULL);
|
||||
ASSERT(item->next == NULL && item->prev == NULL);
|
||||
spice_assert(ring->next != NULL && ring->prev != NULL);
|
||||
spice_assert(item->next == NULL && item->prev == NULL);
|
||||
|
||||
item->next = ring->next;
|
||||
item->prev = ring;
|
||||
@ -72,54 +70,43 @@ static inline void ring_add_before(RingItem *item, RingItem *pos)
|
||||
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)
|
||||
{
|
||||
ASSERT(item->next != NULL && item->prev != NULL);
|
||||
ASSERT(item->next != item);
|
||||
spice_assert(item->next != NULL && item->prev != NULL);
|
||||
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)
|
||||
{
|
||||
RingItem *ret;
|
||||
|
||||
ASSERT(ring->next != NULL && ring->prev != NULL);
|
||||
spice_assert(ring->next != NULL && ring->prev != NULL);
|
||||
|
||||
if (ring_is_empty(ring)) {
|
||||
return NULL;
|
||||
}
|
||||
ret = ring->next;
|
||||
return ret;
|
||||
return ring->next;
|
||||
}
|
||||
|
||||
static inline RingItem *ring_get_tail(Ring *ring)
|
||||
{
|
||||
RingItem *ret;
|
||||
|
||||
ASSERT(ring->next != NULL && ring->prev != NULL);
|
||||
spice_assert(ring->next != NULL && ring->prev != NULL);
|
||||
|
||||
if (ring_is_empty(ring)) {
|
||||
return NULL;
|
||||
}
|
||||
ret = ring->prev;
|
||||
return ret;
|
||||
return ring->prev;
|
||||
}
|
||||
|
||||
static inline RingItem *ring_next(Ring *ring, RingItem *pos)
|
||||
{
|
||||
RingItem *ret;
|
||||
|
||||
ASSERT(ring->next != NULL && ring->prev != NULL);
|
||||
ASSERT(pos);
|
||||
ASSERT(pos->next != NULL && pos->prev != NULL);
|
||||
spice_assert(ring->next != NULL && ring->prev != NULL);
|
||||
spice_assert(pos);
|
||||
spice_assert(pos->next != NULL && pos->prev != NULL);
|
||||
ret = pos->next;
|
||||
return (ret == ring) ? NULL : ret;
|
||||
}
|
||||
@ -128,9 +115,9 @@ static inline RingItem *ring_prev(Ring *ring, RingItem *pos)
|
||||
{
|
||||
RingItem *ret;
|
||||
|
||||
ASSERT(ring->next != NULL && ring->prev != NULL);
|
||||
ASSERT(pos);
|
||||
ASSERT(pos->next != NULL && pos->prev != NULL);
|
||||
spice_assert(ring->next != NULL && ring->prev != NULL);
|
||||
spice_assert(pos);
|
||||
spice_assert(pos->next != NULL && pos->prev != NULL);
|
||||
ret = pos->prev;
|
||||
return (ret == ring) ? NULL : ret;
|
||||
}
|
||||
@ -157,16 +144,12 @@ static inline unsigned int ring_get_length(Ring *ring)
|
||||
RingItem *i;
|
||||
unsigned int ret = 0;
|
||||
|
||||
for (i = ring_get_head(ring);
|
||||
i != NULL;
|
||||
i = ring_next(ring, i))
|
||||
RING_FOREACH(i, ring)
|
||||
ret++;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
SPICE_END_DECLS
|
||||
|
||||
#endif
|
||||
|
||||
@ -15,14 +15,9 @@
|
||||
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 <stdio.h>
|
||||
|
||||
#include "rop3.h"
|
||||
#include "spice_common.h"
|
||||
|
||||
typedef void (*rop3_with_pattern_handler_t)(pixman_image_t *d, pixman_image_t *s,
|
||||
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 void default_rop3_with_pattern_handler(pixman_image_t *d, pixman_image_t *s,
|
||||
SpicePoint *src_pos, pixman_image_t *p,
|
||||
SpicePoint *pat_pos)
|
||||
static void default_rop3_with_pattern_handler(SPICE_GNUC_UNUSED pixman_image_t *d,
|
||||
SPICE_GNUC_UNUSED pixman_image_t *s,
|
||||
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,
|
||||
uint32_t rgb)
|
||||
static void default_rop3_withe_color_handler(SPICE_GNUC_UNUSED pixman_image_t *d,
|
||||
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)
|
||||
@ -374,16 +373,10 @@ ROP3_HANDLERS(DPSoo, *src | *pat | *dest, 0xfe);
|
||||
rop3_test_handlers_32[index] = rop3_test32_##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;
|
||||
|
||||
if (!need_init) {
|
||||
return;
|
||||
}
|
||||
need_init = 0;
|
||||
|
||||
for (i = 0; i < ROP3_NUM_OPS; i++) {
|
||||
rop3_with_pattern_handlers_32[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;
|
||||
|
||||
bpp = spice_pixman_image_get_bpp(d);
|
||||
ASSERT (bpp == spice_pixman_image_get_bpp(s));
|
||||
ASSERT (bpp == spice_pixman_image_get_bpp(p));
|
||||
spice_assert(bpp == spice_pixman_image_get_bpp(s));
|
||||
spice_assert(bpp == spice_pixman_image_get_bpp(p));
|
||||
|
||||
if (bpp == 32) {
|
||||
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;
|
||||
|
||||
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) {
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#ifndef _H_ROP3
|
||||
#define _H_ROP3
|
||||
#ifndef H_SPICE_COMMON_ROP3
|
||||
#define H_SPICE_COMMON_ROP3
|
||||
|
||||
#include <stdint.h>
|
||||
#include <spice/macros.h>
|
||||
|
||||
#include "draw.h"
|
||||
#include "pixman_utils.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
SPICE_BEGIN_DECLS
|
||||
|
||||
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);
|
||||
void do_rop3_with_color(uint8_t rop3, pixman_image_t *d, pixman_image_t *s, SpicePoint *src_pos,
|
||||
uint32_t rgb);
|
||||
|
||||
void rop3_init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
SPICE_END_DECLS
|
||||
|
||||
#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/>.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include "mem.h"
|
||||
#include "ssl_verify.h"
|
||||
#include "log.h"
|
||||
|
||||
#ifndef WIN32
|
||||
#include <sys/socket.h>
|
||||
@ -29,21 +28,14 @@
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <gio/gio.h>
|
||||
|
||||
#ifndef SPICE_DEBUG
|
||||
# define SPICE_DEBUG(format, ...)
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
static int inet_aton(const char* ip, struct in_addr* in_addr)
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000 || \
|
||||
(defined (LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000)
|
||||
static const unsigned char *ASN1_STRING_get0_data(const ASN1_STRING *asn1)
|
||||
{
|
||||
unsigned long addr = inet_addr(ip);
|
||||
|
||||
if (addr == INADDR_NONE) {
|
||||
return 0;
|
||||
}
|
||||
in_addr->S_un.S_addr = addr;
|
||||
return 1;
|
||||
return M_ASN1_STRING_data(asn1);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -58,36 +50,41 @@ static int verify_pubkey(X509* cert, const char *key, size_t key_size)
|
||||
return 0;
|
||||
|
||||
if (!cert) {
|
||||
SPICE_DEBUG("warning: no cert!");
|
||||
spice_debug("warning: no cert!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
cert_pubkey = X509_get_pubkey(cert);
|
||||
if (!cert_pubkey) {
|
||||
SPICE_DEBUG("warning: reading public key from certificate failed");
|
||||
spice_debug("warning: reading public key from certificate failed");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
bio = BIO_new_mem_buf((void*)key, key_size);
|
||||
if (!bio) {
|
||||
SPICE_DEBUG("creating BIO failed");
|
||||
spice_debug("creating BIO failed");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
orig_pubkey = d2i_PUBKEY_bio(bio, NULL);
|
||||
if (!orig_pubkey) {
|
||||
SPICE_DEBUG("reading pubkey from bio failed");
|
||||
spice_debug("reading pubkey from bio failed");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000
|
||||
ret = EVP_PKEY_eq(orig_pubkey, cert_pubkey);
|
||||
#else
|
||||
ret = EVP_PKEY_cmp(orig_pubkey, cert_pubkey);
|
||||
#endif
|
||||
|
||||
if (ret == 1)
|
||||
SPICE_DEBUG("public keys match");
|
||||
else if (ret == 0)
|
||||
SPICE_DEBUG("public keys mismatch");
|
||||
else
|
||||
SPICE_DEBUG("public keys types mismatch");
|
||||
if (ret == 1) {
|
||||
spice_debug("public keys match");
|
||||
} else if (ret == 0) {
|
||||
spice_debug("public keys mismatch");
|
||||
} else {
|
||||
spice_debug("public keys types mismatch");
|
||||
}
|
||||
|
||||
finish:
|
||||
if (bio)
|
||||
@ -162,19 +159,14 @@ static int verify_hostname(X509* cert, const char *hostname)
|
||||
{
|
||||
GENERAL_NAMES* subject_alt_names;
|
||||
int found_dns_name = 0;
|
||||
struct in_addr addr;
|
||||
int addr_len = 0;
|
||||
int cn_match = 0;
|
||||
X509_NAME* subject;
|
||||
|
||||
if (!cert) {
|
||||
SPICE_DEBUG("warning: no cert!");
|
||||
return 0;
|
||||
}
|
||||
spice_return_val_if_fail(hostname != NULL, 0);
|
||||
|
||||
// only IpV4 supported
|
||||
if (inet_aton(hostname, &addr)) {
|
||||
addr_len = sizeof(struct in_addr);
|
||||
if (!cert) {
|
||||
spice_debug("warning: no cert!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
if (name->type == GEN_DNS) {
|
||||
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),
|
||||
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);
|
||||
return 1;
|
||||
}
|
||||
} 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;
|
||||
if ((addr_len == alt_ip_len)&&
|
||||
!memcmp(ASN1_STRING_data(name->d.iPAddress), &addr, addr_len)) {
|
||||
SPICE_DEBUG("alt name IP match=%s",
|
||||
inet_ntoa(*((struct in_addr*)ASN1_STRING_data(name->d.dNSName))));
|
||||
|
||||
ip = g_inet_address_new_from_string(hostname);
|
||||
if (ip == NULL) {
|
||||
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);
|
||||
return 1;
|
||||
}
|
||||
g_object_unref(ip);
|
||||
}
|
||||
}
|
||||
GENERAL_NAMES_free(subject_alt_names);
|
||||
}
|
||||
|
||||
if (found_dns_name) {
|
||||
SPICE_DEBUG("warning: SubjectAltName mismatch");
|
||||
spice_debug("warning: SubjectAltName mismatch");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -244,38 +262,41 @@ static int verify_hostname(X509* cert, const char *hostname)
|
||||
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),
|
||||
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;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!cn_match)
|
||||
SPICE_DEBUG("warning: common name mismatch");
|
||||
if (!cn_match) {
|
||||
spice_debug("warning: common name mismatch");
|
||||
}
|
||||
|
||||
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;
|
||||
const char *p;
|
||||
char *key, *val, *k, *v = NULL;
|
||||
char *key, *val = NULL, *k, *v = NULL;
|
||||
enum {
|
||||
KEY,
|
||||
VALUE
|
||||
} state;
|
||||
|
||||
key = (char*)alloca(strlen(subject));
|
||||
val = (char*)alloca(strlen(subject));
|
||||
spice_return_val_if_fail(subject != NULL, NULL);
|
||||
spice_return_val_if_fail(nentries != NULL, NULL);
|
||||
|
||||
key = (char*)alloca(strlen(subject)+1);
|
||||
in_subject = X509_NAME_new();
|
||||
|
||||
if (!in_subject || !key || !val) {
|
||||
SPICE_DEBUG("failed to allocate");
|
||||
if (!in_subject || !key) {
|
||||
spice_debug("failed to allocate");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -288,7 +309,7 @@ X509_NAME* subject_to_x509_name(const char *subject, int *nentries)
|
||||
if (*p == '\\') {
|
||||
++p;
|
||||
if (*p != '\\' && *p != ',') {
|
||||
SPICE_DEBUG("Invalid character after \\");
|
||||
spice_debug("Invalid character after \\");
|
||||
goto fail;
|
||||
}
|
||||
escape = 1;
|
||||
@ -307,6 +328,7 @@ X509_NAME* subject_to_x509_name(const char *subject, int *nentries)
|
||||
} else if (*p == '=' && !escape) {
|
||||
state = VALUE;
|
||||
*k = 0;
|
||||
val = k + 1;
|
||||
v = val;
|
||||
} else
|
||||
*k++ = *p;
|
||||
@ -322,7 +344,7 @@ X509_NAME* subject_to_x509_name(const char *subject, int *nentries)
|
||||
MBSTRING_UTF8,
|
||||
(const unsigned char*)val,
|
||||
-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);
|
||||
goto fail;
|
||||
}
|
||||
@ -349,89 +371,145 @@ fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int verify_subject(X509* cert, SpiceOpenSSLVerify* verify)
|
||||
static int verify_subject(X509* cert, SpiceOpenSSLVerify* verify)
|
||||
{
|
||||
X509_NAME *cert_subject = NULL;
|
||||
X509_NAME* in_subject;
|
||||
int ret;
|
||||
int in_entries;
|
||||
|
||||
if (!cert) {
|
||||
SPICE_DEBUG("warning: no cert!");
|
||||
spice_debug("warning: no cert!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
cert_subject = X509_get_subject_name(cert);
|
||||
if (!cert_subject) {
|
||||
SPICE_DEBUG("warning: reading certificate subject failed");
|
||||
spice_debug("warning: reading certificate subject failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!verify->in_subject) {
|
||||
verify->in_subject = subject_to_x509_name(verify->subject, &in_entries);
|
||||
if (!verify->in_subject) {
|
||||
SPICE_DEBUG("warning: no in_subject!");
|
||||
return 0;
|
||||
}
|
||||
in_subject = subject_to_x509_name(verify->subject, &in_entries);
|
||||
if (!in_subject) {
|
||||
spice_debug("warning: no in_subject!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Note: this check is redundant with the pre-condition in X509_NAME_cmp */
|
||||
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_free(in_subject);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = X509_NAME_cmp(cert_subject, verify->in_subject);
|
||||
ret = X509_NAME_cmp(cert_subject, in_subject);
|
||||
|
||||
if (ret == 0)
|
||||
SPICE_DEBUG("subjects match");
|
||||
else
|
||||
SPICE_DEBUG("subjects mismatch");
|
||||
if (ret == 0) {
|
||||
spice_debug("subjects match");
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
|
||||
static int openssl_verify(int preverify_ok, X509_STORE_CTX *ctx)
|
||||
{
|
||||
int depth;
|
||||
int depth, err;
|
||||
SpiceOpenSSLVerify *v;
|
||||
SSL *ssl;
|
||||
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());
|
||||
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);
|
||||
err = X509_STORE_CTX_get_error(ctx);
|
||||
if (depth > 0) {
|
||||
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;
|
||||
|
||||
/* 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;
|
||||
} else
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* depth == 0 */
|
||||
cert = X509_STORE_CTX_get_current_cert(ctx);
|
||||
if (!cert) {
|
||||
SPICE_DEBUG("failed to get server certificate");
|
||||
spice_debug("failed to get server certificate");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (v->verifyop & SPICE_SSL_VERIFY_OP_PUBKEY &&
|
||||
verify_pubkey(cert, v->pubkey, v->pubkey_size))
|
||||
return 1;
|
||||
failed_verifications = 0;
|
||||
if (v->verifyop & SPICE_SSL_VERIFY_OP_PUBKEY) {
|
||||
if (verify_pubkey(cert, v->pubkey, v->pubkey_size))
|
||||
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;
|
||||
}
|
||||
if (!v->all_preverify_ok) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (v->verifyop & SPICE_SSL_VERIFY_OP_HOSTNAME &&
|
||||
verify_hostname(cert, v->hostname))
|
||||
return 1;
|
||||
if (v->verifyop & SPICE_SSL_VERIFY_OP_SUBJECT) {
|
||||
if (verify_subject(cert, v))
|
||||
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 &&
|
||||
verify_subject(cert, v))
|
||||
return 1;
|
||||
/* If we reach this code, this means all the tests failed, thus
|
||||
* verification failed
|
||||
*/
|
||||
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;
|
||||
}
|
||||
@ -473,9 +551,6 @@ void spice_openssl_verify_free(SpiceOpenSSLVerify* verify)
|
||||
free(verify->subject);
|
||||
free(verify->hostname);
|
||||
|
||||
if (verify->in_subject)
|
||||
X509_NAME_free(verify->in_subject);
|
||||
|
||||
if (verify->ssl)
|
||||
SSL_set_app_data(verify->ssl, NULL);
|
||||
free(verify);
|
||||
|
||||
@ -16,12 +16,16 @@
|
||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SSL_VERIFY_H
|
||||
#define SSL_VERIFY_H
|
||||
#ifndef H_SPICE_COMMON_SSL_VERIFY
|
||||
#define H_SPICE_COMMON_SSL_VERIFY
|
||||
|
||||
#if defined(WIN32) && !defined(__MINGW32__)
|
||||
#if defined(WIN32)
|
||||
#include <windows.h>
|
||||
#include <wincrypt.h>
|
||||
#ifdef X509_NAME
|
||||
/* wincrypt.h has already a different define... */
|
||||
#undef X509_NAME
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <openssl/rsa.h>
|
||||
@ -29,12 +33,11 @@
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
#undef X509_NAME
|
||||
#include <openssl/x509v3.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#include <spice/macros.h>
|
||||
|
||||
SPICE_BEGIN_DECLS
|
||||
|
||||
typedef enum {
|
||||
SPICE_SSL_VERIFY_OP_NONE = 0,
|
||||
@ -51,7 +54,6 @@ typedef struct {
|
||||
char *pubkey;
|
||||
size_t pubkey_size;
|
||||
char *subject;
|
||||
X509_NAME *in_subject;
|
||||
} SpiceOpenSSLVerify;
|
||||
|
||||
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);
|
||||
void spice_openssl_verify_free(SpiceOpenSSLVerify* verify);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
#endif // SSL_VERIFY_H
|
||||
SPICE_END_DECLS
|
||||
|
||||
#endif // H_SPICE_COMMON_SSL_VERIFY
|
||||
|
||||
@ -15,21 +15,13 @@
|
||||
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
|
||||
#ifdef __MINGW32__
|
||||
#undef HAVE_STDLIB_H
|
||||
#endif
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifndef SPICE_CANVAS_INTERNAL
|
||||
#error "This file shouldn't be compiled directly"
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
#include "sw_canvas.h"
|
||||
#define CANVAS_USE_PIXMAN
|
||||
#define CANVAS_SINGLE_INSTANCE
|
||||
#include "canvas_base.c"
|
||||
#include "rect.h"
|
||||
#include "region.h"
|
||||
@ -83,15 +75,33 @@ static pixman_image_t *canvas_get_pixman_brush(SwCanvas *canvas,
|
||||
case SPICE_BRUSH_TYPE_NONE:
|
||||
return NULL;
|
||||
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;
|
||||
pixman_format_code_t format;
|
||||
|
||||
pixman_image_ref(sw_canvas->image);
|
||||
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);
|
||||
}
|
||||
|
||||
return sw_canvas->image;
|
||||
}
|
||||
@ -343,8 +353,8 @@ static void clear_dest_alpha(pixman_image_t *dest,
|
||||
}
|
||||
|
||||
stride = pixman_image_get_stride(dest);
|
||||
data = (uint32_t *) (
|
||||
(uint8_t *)pixman_image_get_data(dest) + y * stride + 4 * x);
|
||||
data = SPICE_ALIGNED_CAST(uint32_t *,
|
||||
(uint8_t *)pixman_image_get_data(dest) + y * stride + 4 * x);
|
||||
|
||||
if ((*data & 0xff000000U) == 0xff000000U) {
|
||||
spice_pixman_fill_rect_rop(dest,
|
||||
@ -472,13 +482,13 @@ static void __scale_image(SpiceCanvas *spice_canvas,
|
||||
|
||||
pixman_transform_init_scale(&transform, fsx, fsy);
|
||||
pixman_transform_translate(&transform, NULL,
|
||||
pixman_int_to_fixed (src_x),
|
||||
pixman_int_to_fixed (src_y));
|
||||
pixman_int_to_fixed(src_x),
|
||||
pixman_int_to_fixed(src_y));
|
||||
|
||||
pixman_image_set_transform(src, &transform);
|
||||
pixman_image_set_repeat(src, PIXMAN_REPEAT_NONE);
|
||||
ASSERT(scale_mode == SPICE_IMAGE_SCALE_MODE_INTERPOLATE ||
|
||||
scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST);
|
||||
spice_return_if_fail(scale_mode == SPICE_IMAGE_SCALE_MODE_INTERPOLATE ||
|
||||
scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST);
|
||||
pixman_image_set_filter(src,
|
||||
(scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST) ?
|
||||
PIXMAN_FILTER_NEAREST : PIXMAN_FILTER_GOOD,
|
||||
@ -539,11 +549,13 @@ static void __scale_image_rop(SpiceCanvas *spice_canvas,
|
||||
pixman_box32_t *rects;
|
||||
int n_rects, i;
|
||||
pixman_fixed_t fsx, fsy;
|
||||
pixman_format_code_t format;
|
||||
|
||||
fsx = ((pixman_fixed_48_16_t) src_width * 65536) / dest_width;
|
||||
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_height,
|
||||
NULL, 0);
|
||||
@ -553,13 +565,13 @@ static void __scale_image_rop(SpiceCanvas *spice_canvas,
|
||||
|
||||
pixman_transform_init_scale(&transform, fsx, fsy);
|
||||
pixman_transform_translate(&transform, NULL,
|
||||
pixman_int_to_fixed (src_x),
|
||||
pixman_int_to_fixed (src_y));
|
||||
pixman_int_to_fixed(src_x),
|
||||
pixman_int_to_fixed(src_y));
|
||||
|
||||
pixman_image_set_transform(src, &transform);
|
||||
pixman_image_set_repeat(src, PIXMAN_REPEAT_NONE);
|
||||
ASSERT(scale_mode == SPICE_IMAGE_SCALE_MODE_INTERPOLATE ||
|
||||
scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST);
|
||||
spice_return_if_fail(scale_mode == SPICE_IMAGE_SCALE_MODE_INTERPOLATE ||
|
||||
scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST);
|
||||
pixman_image_set_filter(src,
|
||||
(scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST) ?
|
||||
PIXMAN_FILTER_NEAREST : PIXMAN_FILTER_GOOD,
|
||||
@ -659,7 +671,7 @@ static void __blend_image(SpiceCanvas *spice_canvas,
|
||||
|
||||
mask = NULL;
|
||||
if (overall_alpha != 0xff) {
|
||||
pixman_color_t color = { 0 };
|
||||
pixman_color_t color = { 0, 0, 0, 0 };
|
||||
color.alpha = overall_alpha * 0x101;
|
||||
mask = pixman_image_create_solid_fill(&color);
|
||||
}
|
||||
@ -747,20 +759,20 @@ static void __blend_scale_image(SpiceCanvas *spice_canvas,
|
||||
|
||||
pixman_transform_init_scale(&transform, fsx, fsy);
|
||||
pixman_transform_translate(&transform, NULL,
|
||||
pixman_int_to_fixed (src_x),
|
||||
pixman_int_to_fixed (src_y));
|
||||
pixman_int_to_fixed(src_x),
|
||||
pixman_int_to_fixed(src_y));
|
||||
|
||||
mask = NULL;
|
||||
if (overall_alpha != 0xff) {
|
||||
pixman_color_t color = { 0 };
|
||||
pixman_color_t color = { 0, 0, 0, 0 };
|
||||
color.alpha = overall_alpha * 0x101;
|
||||
mask = pixman_image_create_solid_fill(&color);
|
||||
}
|
||||
|
||||
pixman_image_set_transform(src, &transform);
|
||||
pixman_image_set_repeat(src, PIXMAN_REPEAT_NONE);
|
||||
ASSERT(scale_mode == SPICE_IMAGE_SCALE_MODE_INTERPOLATE ||
|
||||
scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST);
|
||||
spice_return_if_fail(scale_mode == SPICE_IMAGE_SCALE_MODE_INTERPOLATE ||
|
||||
scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST);
|
||||
pixman_image_set_filter(src,
|
||||
(scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST) ?
|
||||
PIXMAN_FILTER_NEAREST : PIXMAN_FILTER_GOOD,
|
||||
@ -895,11 +907,13 @@ static void __colorkey_scale_image(SpiceCanvas *spice_canvas,
|
||||
pixman_box32_t *rects;
|
||||
int n_rects, i;
|
||||
pixman_fixed_t fsx, fsy;
|
||||
pixman_format_code_t format;
|
||||
|
||||
fsx = ((pixman_fixed_48_16_t) src_width * 65536) / dest_width;
|
||||
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_height,
|
||||
NULL, 0);
|
||||
@ -909,8 +923,8 @@ static void __colorkey_scale_image(SpiceCanvas *spice_canvas,
|
||||
|
||||
pixman_transform_init_scale(&transform, fsx, fsy);
|
||||
pixman_transform_translate(&transform, NULL,
|
||||
pixman_int_to_fixed (src_x),
|
||||
pixman_int_to_fixed (src_y));
|
||||
pixman_int_to_fixed(src_x),
|
||||
pixman_int_to_fixed(src_y));
|
||||
|
||||
pixman_image_set_transform(src, &transform);
|
||||
pixman_image_set_repeat(src, PIXMAN_REPEAT_NONE);
|
||||
@ -977,9 +991,6 @@ static void colorkey_scale_image_from_surface(SpiceCanvas *spice_canvas,
|
||||
}
|
||||
|
||||
static void canvas_put_image(SpiceCanvas *spice_canvas,
|
||||
#ifdef WIN32
|
||||
HDC dc,
|
||||
#endif
|
||||
const SpiceRect *dest, const uint8_t *src_data,
|
||||
uint32_t src_width, uint32_t src_height, int src_stride,
|
||||
const QRegion *clip)
|
||||
@ -994,7 +1005,7 @@ static void canvas_put_image(SpiceCanvas *spice_canvas,
|
||||
src = pixman_image_create_bits(PIXMAN_x8r8g8b8,
|
||||
src_width,
|
||||
src_height,
|
||||
(uint32_t*)src_data,
|
||||
SPICE_ALIGNED_CAST(uint32_t*,src_data),
|
||||
src_stride);
|
||||
|
||||
|
||||
@ -1042,7 +1053,7 @@ static void canvas_draw_text(SpiceCanvas *spice_canvas, SpiceRect *bbox,
|
||||
pixman_region32_t dest_region;
|
||||
pixman_image_t *str_mask, *brush;
|
||||
SpiceString *str;
|
||||
SpicePoint pos;
|
||||
SpicePoint pos = { 0, 0 };
|
||||
int depth;
|
||||
|
||||
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
|
||||
* 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,
|
||||
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) {
|
||||
depth = 4;
|
||||
} else if (str->flags & SPICE_STRING_FLAGS_RASTER_A8) {
|
||||
WARN("untested path A8 glyphs");
|
||||
spice_warning("untested path A8 glyphs");
|
||||
depth = 8;
|
||||
} else {
|
||||
WARN("unsupported path vector glyphs");
|
||||
spice_warning("unsupported path vector glyphs");
|
||||
pixman_region32_fini (&dest_region);
|
||||
return;
|
||||
}
|
||||
@ -1133,7 +1144,7 @@ static void canvas_read_bits(SpiceCanvas *spice_canvas, uint8_t *dest,
|
||||
uint8_t *dest_end;
|
||||
int bpp;
|
||||
|
||||
ASSERT(canvas && area);
|
||||
spice_return_if_fail(canvas && area);
|
||||
|
||||
surface = canvas->image;
|
||||
|
||||
@ -1170,47 +1181,37 @@ static void canvas_destroy(SpiceCanvas *spice_canvas)
|
||||
free(canvas);
|
||||
}
|
||||
|
||||
static int need_init = 1;
|
||||
static SpiceCanvasOps sw_canvas_ops;
|
||||
|
||||
static SpiceCanvas *canvas_create_common(pixman_image_t *image,
|
||||
uint32_t format
|
||||
uint32_t format,
|
||||
SpiceImageCache *bits_cache,
|
||||
#ifdef SW_CANVAS_CACHE
|
||||
, SpiceImageCache *bits_cache
|
||||
, SpicePaletteCache *palette_cache
|
||||
#elif defined(SW_CANVAS_IMAGE_CACHE)
|
||||
, SpiceImageCache *bits_cache
|
||||
SpicePaletteCache *palette_cache,
|
||||
#endif
|
||||
, SpiceImageSurfaces *surfaces
|
||||
, SpiceGlzDecoder *glz_decoder
|
||||
, SpiceJpegDecoder *jpeg_decoder
|
||||
, SpiceZlibDecoder *zlib_decoder
|
||||
)
|
||||
SpiceImageSurfaces *surfaces,
|
||||
SpiceGlzDecoder *glz_decoder,
|
||||
SpiceJpegDecoder *jpeg_decoder,
|
||||
SpiceZlibDecoder *zlib_decoder)
|
||||
{
|
||||
SwCanvas *canvas;
|
||||
|
||||
if (need_init) {
|
||||
return NULL;
|
||||
}
|
||||
spice_pixman_image_set_format(image,
|
||||
spice_surface_format_to_pixman (format));
|
||||
spice_surface_format_to_pixman(format));
|
||||
|
||||
canvas = spice_new0(SwCanvas, 1);
|
||||
canvas_base_init(&canvas->base, &sw_canvas_ops,
|
||||
pixman_image_get_width (image),
|
||||
pixman_image_get_height (image),
|
||||
format
|
||||
pixman_image_get_width(image),
|
||||
pixman_image_get_height(image),
|
||||
format,
|
||||
bits_cache,
|
||||
#ifdef SW_CANVAS_CACHE
|
||||
, bits_cache
|
||||
, palette_cache
|
||||
#elif defined(SW_CANVAS_IMAGE_CACHE)
|
||||
, bits_cache
|
||||
palette_cache,
|
||||
#endif
|
||||
, surfaces
|
||||
, glz_decoder
|
||||
, jpeg_decoder
|
||||
, zlib_decoder
|
||||
);
|
||||
surfaces,
|
||||
glz_decoder,
|
||||
jpeg_decoder,
|
||||
zlib_decoder);
|
||||
canvas->private_data = NULL;
|
||||
canvas->private_data_size = 0;
|
||||
|
||||
@ -1219,78 +1220,37 @@ static SpiceCanvas *canvas_create_common(pixman_image_t *image,
|
||||
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,
|
||||
uint8_t *data, int stride
|
||||
uint8_t *data, int stride,
|
||||
SpiceImageCache *bits_cache,
|
||||
#ifdef SW_CANVAS_CACHE
|
||||
, SpiceImageCache *bits_cache
|
||||
, SpicePaletteCache *palette_cache
|
||||
#elif defined(SW_CANVAS_IMAGE_CACHE)
|
||||
, SpiceImageCache *bits_cache
|
||||
SpicePaletteCache *palette_cache,
|
||||
#endif
|
||||
, SpiceImageSurfaces *surfaces
|
||||
, SpiceGlzDecoder *glz_decoder
|
||||
, SpiceJpegDecoder *jpeg_decoder
|
||||
, SpiceZlibDecoder *zlib_decoder
|
||||
)
|
||||
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, (uint32_t *)data, stride);
|
||||
image = pixman_image_create_bits(spice_surface_format_to_pixman(format),
|
||||
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
|
||||
, bits_cache
|
||||
, palette_cache
|
||||
#elif defined(SW_CANVAS_IMAGE_CACHE)
|
||||
, bits_cache
|
||||
palette_cache,
|
||||
#endif
|
||||
, surfaces
|
||||
, glz_decoder
|
||||
, jpeg_decoder
|
||||
, zlib_decoder
|
||||
);
|
||||
surfaces,
|
||||
glz_decoder,
|
||||
jpeg_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);
|
||||
sw_canvas_ops.draw_text = canvas_draw_text;
|
||||
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.copy_region = copy_region;
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#ifndef _H__CANVAS
|
||||
#define _H__CANVAS
|
||||
|
||||
#ifndef SPICE_CANVAS_INTERNAL
|
||||
#error "This header shouldn't be included directly"
|
||||
#endif
|
||||
#ifndef H_SPICE_COMMON_SW_CANVAS
|
||||
#define H_SPICE_COMMON_SW_CANVAS
|
||||
|
||||
#include <stdint.h>
|
||||
#include <spice/macros.h>
|
||||
|
||||
#include "draw.h"
|
||||
#include "pixman_utils.h"
|
||||
#include "canvas_base.h"
|
||||
#include "region.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
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
|
||||
);
|
||||
SPICE_BEGIN_DECLS
|
||||
|
||||
SpiceCanvas *canvas_create_for_data(int width, int height, uint32_t format, uint8_t *data, int stride
|
||||
, SpiceImageCache *bits_cache
|
||||
#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
|
||||
@ -61,10 +41,6 @@ SpiceCanvas *canvas_create_for_data(int width, int height, uint32_t format, uint
|
||||
);
|
||||
|
||||
|
||||
void sw_canvas_init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
SPICE_END_DECLS
|
||||
|
||||
#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