Compare commits
3658 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3b72a12540 | ||
|
|
38a1b7765a | ||
|
|
02f2b8b6f0 | ||
|
|
7bfa75102c | ||
|
|
b0f3e7351c | ||
|
|
b5fa401db9 | ||
|
|
41f2710dea | ||
|
|
f19dda57f0 | ||
|
|
cc4a99ad80 | ||
|
|
1c1a3fc417 | ||
|
|
e97be5850b | ||
|
|
2c302654b7 | ||
|
|
3ee4dc77b2 | ||
|
|
db55f314c9 | ||
|
|
0b536b287f | ||
|
|
6f298a9917 | ||
|
|
70f829a2e5 | ||
|
|
1dfe07003f | ||
|
|
286b908062 | ||
|
|
4ec028e736 | ||
|
|
35a6d1437a | ||
|
|
7e3cb3de89 | ||
|
|
bd945039f1 | ||
|
|
46743c8f15 | ||
|
|
9b75284447 | ||
|
|
dca3b0052a | ||
|
|
6d05bb2de5 | ||
|
|
8b2e8d3804 | ||
|
|
1a2ab19ab4 | ||
|
|
04f010aa7b | ||
|
|
25323b4a3a | ||
|
|
f353c022f6 | ||
|
|
9d8b3d3428 | ||
|
|
e4b06772c0 | ||
|
|
a2b5c3ea08 | ||
|
|
f632e95600 | ||
|
|
4b5da8c6d4 | ||
|
|
77d7ffd10a | ||
|
|
d2f720011a | ||
|
|
6329a7711d | ||
|
|
fd14d044e3 | ||
|
|
6368d507e1 | ||
|
|
205b7f2401 | ||
|
|
f7d10f9530 | ||
|
|
66154bb51e | ||
|
|
fac4ad5313 | ||
|
|
fee63891ac | ||
|
|
efa979ee03 | ||
|
|
c756346357 | ||
|
|
cc95db25cc | ||
|
|
44970c3321 | ||
|
|
43c7934af7 | ||
|
|
3e7b51163c | ||
|
|
4d5f8a53f0 | ||
|
|
0b73ca8318 | ||
|
|
754cfc3bfd | ||
|
|
2ed1a5c06a | ||
|
|
b2073df3c3 | ||
|
|
6267edaa81 | ||
|
|
292f2de3e6 | ||
|
|
7803dc8be3 | ||
|
|
2a1260b79e | ||
|
|
f9ec438b7f | ||
|
|
de544c4856 | ||
|
|
55e04dd520 | ||
|
|
b2d06f900b | ||
|
|
b92ec71810 | ||
|
|
3a4199240e | ||
|
|
157de12bdf | ||
|
|
7c0c9fccdb | ||
|
|
2cb29d06b3 | ||
|
|
1fdeb50d93 | ||
|
|
f59632ae59 | ||
|
|
67b503da44 | ||
|
|
a351de6904 | ||
|
|
f94742abd5 | ||
|
|
891182637e | ||
|
|
086681c915 | ||
|
|
3970d2d02b | ||
|
|
2b3fddd015 | ||
|
|
30fa0480a3 | ||
|
|
320a81ce69 | ||
|
|
950411ef56 | ||
|
|
cb9cf084c0 | ||
|
|
bb18af09ae | ||
|
|
049bf0c7f9 | ||
|
|
ebc73ef775 | ||
|
|
1bd6f59355 | ||
|
|
c16396a690 | ||
|
|
32a9fe3e9c | ||
|
|
f48d133bc6 | ||
|
|
0678526d7d | ||
|
|
26d3e8371f | ||
|
|
6768f614c7 | ||
|
|
171dc84df1 | ||
|
|
5ca6513c04 | ||
|
|
41aeb0ac80 | ||
|
|
f871c4adef | ||
|
|
ad4d0e89b1 | ||
|
|
0d0c49caa1 | ||
|
|
7cbc7bdcfb | ||
|
|
6b46c8ed4a | ||
|
|
e33ffd1c8a | ||
|
|
8dce9cc938 | ||
|
|
f06218f8e3 | ||
|
|
5711eef2be | ||
|
|
db6aac603c | ||
|
|
f10e928106 | ||
|
|
99d963b99c | ||
|
|
5d35c22238 | ||
|
|
54fc11a235 | ||
|
|
ec99df3144 | ||
|
|
d722035883 | ||
|
|
52139fbaa0 | ||
|
|
88854eb558 | ||
|
|
c82bba01ee | ||
|
|
eaa33a03d7 | ||
|
|
89e8518f31 | ||
|
|
c7bf2e1da8 | ||
|
|
bf904a6afa | ||
|
|
43c14ae71b | ||
|
|
4abb8ef3c9 | ||
|
|
e46b92dd7d | ||
|
|
1a25faa5b9 | ||
|
|
3f4bf5f512 | ||
|
|
ae7dbf15ed | ||
|
|
b22320c48f | ||
|
|
61204e8d35 | ||
|
|
b0704c654c | ||
|
|
f40f8a8873 | ||
|
|
560a7db506 | ||
|
|
15baa8f70e | ||
|
|
97a7637294 | ||
|
|
3454656207 | ||
|
|
7dff6f26bc | ||
|
|
9e835a23fd | ||
|
|
c0259fb6ce | ||
|
|
acf106220b | ||
|
|
5d4dc9c907 | ||
|
|
2b9a56af7f | ||
|
|
f1e3ac65ac | ||
|
|
143f72cf6b | ||
|
|
5c8e49296c | ||
|
|
b2558b703c | ||
|
|
bf9d87106e | ||
|
|
5b7f507d9b | ||
|
|
59a7835ace | ||
|
|
2495838fe3 | ||
|
|
bab687bedf | ||
|
|
6467c3c8ee | ||
|
|
66c2b7aaa6 | ||
|
|
ab72c52661 | ||
|
|
f0bf1b8a54 | ||
|
|
119251719f | ||
|
|
0348400132 | ||
|
|
813473805b | ||
|
|
fe6368561b | ||
|
|
7ff06f424d | ||
|
|
31958592c7 | ||
|
|
adc21f4f75 | ||
|
|
9cecd89d6f | ||
|
|
d866b9b4d4 | ||
|
|
93f12baf51 | ||
|
|
78d6fd634b | ||
|
|
b5fc19f08a | ||
|
|
2dae6a6546 | ||
|
|
b6bba46391 | ||
|
|
b791d97116 | ||
|
|
6aa8255f34 | ||
|
|
98e2140761 | ||
|
|
a59e064778 | ||
|
|
655c4c66a7 | ||
|
|
407c128f65 | ||
|
|
59a261a5be | ||
|
|
ba4e1afefe | ||
|
|
98b53b81d8 | ||
|
|
8270cc0aa2 | ||
|
|
74207b1a87 | ||
|
|
77983445ce | ||
|
|
162190bcb8 | ||
|
|
86b92b20b7 | ||
|
|
2f5b60d548 | ||
|
|
c19661c977 | ||
|
|
82d101ca27 | ||
|
|
32f9c4e670 | ||
|
|
34c7225ab7 | ||
|
|
b02eb502e4 | ||
|
|
7d6b3dfd20 | ||
|
|
3ac39968d2 | ||
|
|
2b24ac54a0 | ||
|
|
6da6b794c7 | ||
|
|
ed689e27c9 | ||
|
|
186f9c3f18 | ||
|
|
42cdde3203 | ||
|
|
b9091702e9 | ||
|
|
d42ecbe74e | ||
|
|
e6c5446d63 | ||
|
|
cc277211b3 | ||
|
|
6703c15c52 | ||
|
|
4ecdaf573e | ||
|
|
71ec3e61be | ||
|
|
216fdb2393 | ||
|
|
c39acc6e3c | ||
|
|
d97b0478a7 | ||
|
|
d15d64eb67 | ||
|
|
3acd2656ee | ||
|
|
a4b003534a | ||
|
|
8752538a02 | ||
|
|
bde435753a | ||
|
|
d347e6fc5f | ||
|
|
27b01d3642 | ||
|
|
b78677e285 | ||
|
|
f8f6c74bcb | ||
|
|
7ce123939b | ||
|
|
e7b02cfb15 | ||
|
|
5931077b08 | ||
|
|
a521bdc0e3 | ||
|
|
80da565609 | ||
|
|
6bc46e4598 | ||
|
|
6562258db5 | ||
|
|
c219995218 | ||
|
|
62035431ed | ||
|
|
fa1fbca7dc | ||
|
|
391b7476b3 | ||
|
|
9c04ce665f | ||
|
|
dd87268197 | ||
|
|
8d9af59db2 | ||
|
|
1b754a35ff | ||
|
|
7230f91f61 | ||
|
|
93edfc315c | ||
|
|
74c8269531 | ||
|
|
acb6c0fc83 | ||
|
|
553d4cce93 | ||
|
|
ca81f144e6 | ||
|
|
ec84960347 | ||
|
|
38db0764af | ||
|
|
a647f63bb0 | ||
|
|
5b7087cc9e | ||
|
|
1a6fcd5da6 | ||
|
|
e31dd9f553 | ||
|
|
22844716d1 | ||
|
|
6abed76f70 | ||
|
|
72ff502e0f | ||
|
|
2b781df32b | ||
|
|
bf601c3906 | ||
|
|
b753e0ebb0 | ||
|
|
564211aceb | ||
|
|
538c759fef | ||
|
|
95edc34100 | ||
|
|
98682a2da9 | ||
|
|
33581fa61d | ||
|
|
b02e0aae98 | ||
|
|
6fa4e1cb6d | ||
|
|
9f2ec22e95 | ||
|
|
65b2e506b1 | ||
|
|
8bc07b5286 | ||
|
|
fe0af63795 | ||
|
|
44ce7f4c67 | ||
|
|
252936134b | ||
|
|
e255b06945 | ||
|
|
d726568a23 | ||
|
|
66880a6de7 | ||
|
|
fda622a0c0 | ||
|
|
efa7d10f40 | ||
|
|
348a3fabab | ||
|
|
1bbaee605c | ||
|
|
22edf7a2b3 | ||
|
|
3ffcc29249 | ||
|
|
21f1fe52c0 | ||
|
|
99840c9e4f | ||
|
|
3194fe7d8e | ||
|
|
81df72b0cb | ||
|
|
57b056ac43 | ||
|
|
c5876d0d48 | ||
|
|
b5e65401b6 | ||
|
|
ebea5b48ea | ||
|
|
7d081e581a | ||
|
|
5e819cf04b | ||
|
|
fd9ab43681 | ||
|
|
4935cdc722 | ||
|
|
26a3c7ad6a | ||
|
|
c358216ad9 | ||
|
|
bb9302143c | ||
|
|
3a73553aac | ||
|
|
6447a17e3e | ||
|
|
4bd5c8ffb3 | ||
|
|
89f137b211 | ||
|
|
3425572c66 | ||
|
|
ad50875f9c | ||
|
|
34e5645dab | ||
|
|
e8ae91c230 | ||
|
|
44b83994fa | ||
|
|
201f585350 | ||
|
|
e4d2f1925e | ||
|
|
658c116eac | ||
|
|
dbbedee77f | ||
|
|
16ac9ea061 | ||
|
|
6afbc71b4a | ||
|
|
71263863ad | ||
|
|
05232065f8 | ||
|
|
f289ae4143 | ||
|
|
91703ecec4 | ||
|
|
6fb0858b87 | ||
|
|
f1c6620df9 | ||
|
|
08fed9a5ee | ||
|
|
eb28b3b05b | ||
|
|
f0c354b0c9 | ||
|
|
07d88e86a2 | ||
|
|
f41a3b9bb2 | ||
|
|
bfd9e76f40 | ||
|
|
38ce208a43 | ||
|
|
fcd148b8d5 | ||
|
|
fc6c3774b0 | ||
|
|
18023d2e18 | ||
|
|
467e834ad6 | ||
|
|
629d9e7ae0 | ||
|
|
4487d292e8 | ||
|
|
76711b9a66 | ||
|
|
b54c749e43 | ||
|
|
d82fd421ed | ||
|
|
abdcadb5fa | ||
|
|
fa3891e383 | ||
|
|
f1dc0f95c8 | ||
|
|
5c721d243a | ||
|
|
2770384f1f | ||
|
|
f4e5b83039 | ||
|
|
124681605b | ||
|
|
a217faae7c | ||
|
|
184c39bbb7 | ||
|
|
508e2a70bb | ||
|
|
5aac56fe96 | ||
|
|
dab7dad966 | ||
|
|
25e48d6cae | ||
|
|
9b743e55d1 | ||
|
|
dc1f9edfaf | ||
|
|
b6b68edf1e | ||
|
|
a2320b99ae | ||
|
|
be01e28068 | ||
|
|
d6084083a5 | ||
|
|
019bf5102c | ||
|
|
a1633224d1 | ||
|
|
e62bd26cb9 | ||
|
|
c29f517292 | ||
|
|
d80144f80c | ||
|
|
4733c84a86 | ||
|
|
23f3d2095b | ||
|
|
4f1f2b6fc6 | ||
|
|
1ea70b085f | ||
|
|
6c0b395f4a | ||
|
|
0ee67f186f | ||
|
|
d133addbaa | ||
|
|
683991b1c9 | ||
|
|
32ac02007b | ||
|
|
d716617ae0 | ||
|
|
26e1f015d2 | ||
|
|
1c94093a4b | ||
|
|
27eccd456a | ||
|
|
eed4447560 | ||
|
|
3c8d0ebd52 | ||
|
|
7ec0d2f2cc | ||
|
|
35da91a997 | ||
|
|
788747c071 | ||
|
|
36eb131289 | ||
|
|
f231f28818 | ||
|
|
aebdc89f77 | ||
|
|
4a3a379871 | ||
|
|
a7f27add2d | ||
|
|
cd1d4247cf | ||
|
|
6d618c4b78 | ||
|
|
ad469531ff | ||
|
|
cf9b4b1246 | ||
|
|
18a2692dc1 | ||
|
|
a2dad982f8 | ||
|
|
8f27b6a4c9 | ||
|
|
21c4022fca | ||
|
|
237933855a | ||
|
|
dff7068a03 | ||
|
|
8f28a85a6d | ||
|
|
2414eb2598 | ||
|
|
4851f6bffd | ||
|
|
948be36d3c | ||
|
|
edd088927d | ||
|
|
4cfe8dd95e | ||
|
|
e1ce81c5bf | ||
|
|
0f40b5f022 | ||
|
|
94c5ffa92e | ||
|
|
3c9bf56767 | ||
|
|
9024acb16e | ||
|
|
7732402122 | ||
|
|
2059bce6a7 | ||
|
|
499c86a8b8 | ||
|
|
ef084eb145 | ||
|
|
3f3ae7c38f | ||
|
|
83d762287f | ||
|
|
5af0acf147 | ||
|
|
907dfee6f7 | ||
|
|
d587d24603 | ||
|
|
c246b8f164 | ||
|
|
deecafa053 | ||
|
|
f8810106a2 | ||
|
|
8e35fbe532 | ||
|
|
b1fdccde6e | ||
|
|
6741f100a1 | ||
|
|
e05e9ea1b2 | ||
|
|
197341de5e | ||
|
|
2933482be3 | ||
|
|
c7ce23239f | ||
|
|
79115f7439 | ||
|
|
4457103672 | ||
|
|
d204875f72 | ||
|
|
c690e73b1a | ||
|
|
b5d39c5f21 | ||
|
|
7f8834cb04 | ||
|
|
0dab7e293c | ||
|
|
8f016880af | ||
|
|
f471462a84 | ||
|
|
58eec8df1e | ||
|
|
2655b8b43a | ||
|
|
ea86c043a4 | ||
|
|
c1faa616bc | ||
|
|
a68bf5a30d | ||
|
|
9568b8e0e5 | ||
|
|
b34321ef87 | ||
|
|
4971f1c5bf | ||
|
|
962b52bd5b | ||
|
|
9449bfa414 | ||
|
|
5b8e9066c6 | ||
|
|
8690be7fd2 | ||
|
|
497267016b | ||
|
|
0468f850c2 | ||
|
|
b9e7d4e30c | ||
|
|
0e7734b555 | ||
|
|
e81dcce5b3 | ||
|
|
38bd1f7e1c | ||
|
|
36ad9704a2 | ||
|
|
a6c05df362 | ||
|
|
f6b70fda71 | ||
|
|
8cb4e75f70 | ||
|
|
da1815ac2b | ||
|
|
f7357f2d10 | ||
|
|
d9c92c5ddd | ||
|
|
c82bdb6405 | ||
|
|
eec8ee5830 | ||
|
|
e67eb3c0d8 | ||
|
|
9c101759f6 | ||
|
|
a55ee92590 | ||
|
|
5ccfc97dab | ||
|
|
d6dd88ec3d | ||
|
|
8557d83599 | ||
|
|
94cf1f8698 | ||
|
|
9ada35c3a3 | ||
|
|
79b0c906fa | ||
|
|
a0688f1dba | ||
|
|
f91e8fecee | ||
|
|
1b363babe2 | ||
|
|
73843cb54d | ||
|
|
a2ccfc2116 | ||
|
|
fe104e2bad | ||
|
|
35e3e9f4ff | ||
|
|
b2a1cd9716 | ||
|
|
14f58eae4b | ||
|
|
5cec000618 | ||
|
|
4805a5287d | ||
|
|
4789dc5b30 | ||
|
|
5a35099043 | ||
|
|
4cd0128919 | ||
|
|
61e9b80f67 | ||
|
|
dcd881ba6c | ||
|
|
d40a67ce68 | ||
|
|
1c1e7ca62a | ||
|
|
d3831d511b | ||
|
|
0942e93144 | ||
|
|
98d3eba8e8 | ||
|
|
ff3db03696 | ||
|
|
3608c31d22 | ||
|
|
8d504d9cee | ||
|
|
782921f6e0 | ||
|
|
0694aabb45 | ||
|
|
604b35dfde | ||
|
|
4c308bf5d0 | ||
|
|
7a53ca7f8e | ||
|
|
7c51f04140 | ||
|
|
488b326e0f | ||
|
|
1e0c0a35ba | ||
|
|
bf044c1ccc | ||
|
|
c9caa7f034 | ||
|
|
1b8966b3a4 | ||
|
|
01d4d404c0 | ||
|
|
354bbf820f | ||
|
|
7620f9ebbe | ||
|
|
9c2c668a04 | ||
|
|
b6f5a5712b | ||
|
|
9e9df6eb16 | ||
|
|
f510c993a6 | ||
|
|
8ddcbaac27 | ||
|
|
3fcab72900 | ||
|
|
70aa2233e2 | ||
|
|
8123a2924d | ||
|
|
dd3c308b09 | ||
|
|
e56ca2ffd6 | ||
|
|
57c98c363c | ||
|
|
2211508061 | ||
|
|
848e41919d | ||
|
|
dac613a8bb | ||
|
|
a1735278df | ||
|
|
3730bd04a4 | ||
|
|
eee3445d2f | ||
|
|
8bf473dc3a | ||
|
|
e106dda794 | ||
|
|
fc35d2a35c | ||
|
|
aef9ff0d38 | ||
|
|
192fb46d1d | ||
|
|
1dd4eb05f2 | ||
|
|
79f0c494fa | ||
|
|
7caeb47637 | ||
|
|
ffef339ebd | ||
|
|
817153b20b | ||
|
|
686eb2e786 | ||
|
|
53d5192477 | ||
|
|
a172f5fe85 | ||
|
|
288408795b | ||
|
|
4b5a811b08 | ||
|
|
c1259d8b6e | ||
|
|
3acbe431f7 | ||
|
|
40f381257d | ||
|
|
beec983f21 | ||
|
|
d20750012e | ||
|
|
e31c9d74fa | ||
|
|
78adc388df | ||
|
|
609413cda4 | ||
|
|
63e5d6a94a | ||
|
|
fd5970b647 | ||
|
|
af38b8f92b | ||
|
|
e676e65f9e | ||
|
|
4c479301ff | ||
|
|
98178947ae | ||
|
|
0dbf3b462b | ||
|
|
cd9f8b569b | ||
|
|
6b23728efa | ||
|
|
ff0f7ee483 | ||
|
|
74498c3ac9 | ||
|
|
7a61e740e8 | ||
|
|
81e6b55c39 | ||
|
|
e439ac0e0e | ||
|
|
7b9d784a64 | ||
|
|
56b2630a1c | ||
|
|
6d5597a732 | ||
|
|
c0a9345358 | ||
|
|
2e4ad81fff | ||
|
|
1aad85a4f9 | ||
|
|
fbd2993239 | ||
|
|
203228bd05 | ||
|
|
da7edebe90 | ||
|
|
c7444a189e | ||
|
|
29235c5fa6 | ||
|
|
bf8374ff9f | ||
|
|
ba05e85e48 | ||
|
|
a9aab0702c | ||
|
|
b5cf83d501 | ||
|
|
1cc2e6303a | ||
|
|
4509a07fff | ||
|
|
ea419f6d40 | ||
|
|
c9b6707468 | ||
|
|
cf512a35a7 | ||
|
|
bdd3e5343d | ||
|
|
80fd8cd338 | ||
|
|
eb48592083 | ||
|
|
a45cb25002 | ||
|
|
21ec116769 | ||
|
|
1d4775a94b | ||
|
|
4cde9a7e9e | ||
|
|
709ba72777 | ||
|
|
0e56b8c575 | ||
|
|
558a087e37 | ||
|
|
7d96fe8b65 | ||
|
|
2f3e8986ab | ||
|
|
df359ba0fa | ||
|
|
31fa60884f | ||
|
|
15be227920 | ||
|
|
fdedfd54c7 | ||
|
|
7d55eb4b44 | ||
|
|
61ac7ae31e | ||
|
|
353e141036 | ||
|
|
cb4332842f | ||
|
|
004d219c97 | ||
|
|
94561e6815 | ||
|
|
ce3af4961b | ||
|
|
bbd81e7d9c | ||
|
|
8b1d198efd | ||
|
|
7a3bafc961 | ||
|
|
512eed9b04 | ||
|
|
38adf640e9 | ||
|
|
f4d8d73970 | ||
|
|
5a50285dee | ||
|
|
ca4ea0719f | ||
|
|
4c6251bf28 | ||
|
|
22c12c7366 | ||
|
|
8f49d1591f | ||
|
|
a97dbab2ae | ||
|
|
4cb8261d3b | ||
|
|
059e2d740f | ||
|
|
587d1c9d74 | ||
|
|
ab56c96170 | ||
|
|
efa4270429 | ||
|
|
0fbe5d888a | ||
|
|
b68f81179e | ||
|
|
6a8c1af5f9 | ||
|
|
98f287559b | ||
|
|
1a53d85f6a | ||
|
|
05b168aa04 | ||
|
|
a68d856074 | ||
|
|
d5dac9c6cc | ||
|
|
e9f7f42c03 | ||
|
|
7b8265d4a3 | ||
|
|
5715f4c2cb | ||
|
|
350debb66c | ||
|
|
267cd3660b | ||
|
|
bc1c0c3c6d | ||
|
|
c420f69da8 | ||
|
|
2151d96303 | ||
|
|
c48c65d0ce | ||
|
|
1c0b706b94 | ||
|
|
2dca3d6f5a | ||
|
|
0992636f8c | ||
|
|
86d3f2b4ed | ||
|
|
b78b4038f6 | ||
|
|
84c14349dc | ||
|
|
9916e34006 | ||
|
|
a729b42e5d | ||
|
|
01f8129ed0 | ||
|
|
fd85763fb4 | ||
|
|
c278ffe2cb | ||
|
|
902c76a781 | ||
|
|
4daed0070a | ||
|
|
a4d055b3ac | ||
|
|
e6ae6c6f04 | ||
|
|
de54ceeb40 | ||
|
|
77fe00df30 | ||
|
|
4ae3e63dea | ||
|
|
3329839dbe | ||
|
|
ca10920bb5 | ||
|
|
b41957ce5c | ||
|
|
3db6699018 | ||
|
|
5284ca90ef | ||
|
|
628cdff4fa | ||
|
|
af0c6f9233 | ||
|
|
7697bbfa4e | ||
|
|
642a455a9c | ||
|
|
6abfa2859b | ||
|
|
20c2225d8f | ||
|
|
5e7759b697 | ||
|
|
1ce8d2b31d | ||
|
|
9fbecb5af6 | ||
|
|
1223469be9 | ||
|
|
5eae3ddd8a | ||
|
|
3d0b6e6ea1 | ||
|
|
c6c53548ac | ||
|
|
3efe2d1e05 | ||
|
|
7c87b53517 | ||
|
|
a461c97bcf | ||
|
|
67a6d6c1e3 | ||
|
|
8b8e427a2b | ||
|
|
7d5c263ab2 | ||
|
|
79ac53b2d9 | ||
|
|
a704412dee | ||
|
|
24e2338769 | ||
|
|
bc240f82ef | ||
|
|
a2ad68406d | ||
|
|
3d807d2331 | ||
|
|
e6a7b484ba | ||
|
|
a62371829f | ||
|
|
fb98336713 | ||
|
|
ebadb4db0a | ||
|
|
9a480eb710 | ||
|
|
03ecde8b83 | ||
|
|
0291b78bfa | ||
|
|
377e6fad25 | ||
|
|
e75c955a68 | ||
|
|
6df356327d | ||
|
|
7a57586f90 | ||
|
|
1e2bad270d | ||
|
|
688d983b25 | ||
|
|
fa834a76ef | ||
|
|
5cb88efc38 | ||
|
|
6b64c43851 | ||
|
|
704e6c5448 | ||
|
|
072d7379df | ||
|
|
df1b756a43 | ||
|
|
30269d9d95 | ||
|
|
d29a1de980 | ||
|
|
57f5ccff81 | ||
|
|
69374bfa11 | ||
|
|
d9fd330216 | ||
|
|
312f62d98f | ||
|
|
0d408055b2 | ||
|
|
496ae42d72 | ||
|
|
3ab86543ad | ||
|
|
ce7926cfa4 | ||
|
|
48c81b188c | ||
|
|
21b241bbbe | ||
|
|
934d6fc267 | ||
|
|
a0ce2daa2e | ||
|
|
006d77239b | ||
|
|
303d31bde7 | ||
|
|
737fbeccde | ||
|
|
ec17dc9830 | ||
|
|
0f710ea3be | ||
|
|
bd4eec4527 | ||
|
|
c78252e0d5 | ||
|
|
b1f70982bf | ||
|
|
6128fb4f19 | ||
|
|
ee915254e7 | ||
|
|
d835d4aae6 | ||
|
|
5945d0ebee | ||
|
|
3d3aacdcb1 | ||
|
|
c3ce6cff72 | ||
|
|
6d7a01fb4e | ||
|
|
8582e09e73 | ||
|
|
90744f2965 | ||
|
|
03d0776fdc | ||
|
|
9d18f40c5f | ||
|
|
47e771ee37 | ||
|
|
20760dcf0e | ||
|
|
2edf12e4cd | ||
|
|
c946c1d1c4 | ||
|
|
bb5fe5a6d1 | ||
|
|
814d2fa9fc | ||
|
|
10d89cb6a6 | ||
|
|
a6569d09ac | ||
|
|
b38ad81928 | ||
|
|
637772f8f0 | ||
|
|
0093eb6c2c | ||
|
|
f3b70d1cb2 | ||
|
|
5152f57f6e | ||
|
|
e6112a311d | ||
|
|
e069d069d2 | ||
|
|
fd74bbc868 | ||
|
|
3b37aea3da | ||
|
|
2fd4bbbd49 | ||
|
|
17226b524b | ||
|
|
f38b33ee50 | ||
|
|
0da0e0a6db | ||
|
|
de2b6d1dee | ||
|
|
c9a501ddc8 | ||
|
|
c5babbbb22 | ||
|
|
1fd0d1a330 | ||
|
|
84d9b30fec | ||
|
|
d0f1522f0d | ||
|
|
6b2e25122d | ||
|
|
ce3026f91c | ||
|
|
4b384b3b59 | ||
|
|
da7605a234 | ||
|
|
3abdec1b91 | ||
|
|
ef34199887 | ||
|
|
08eca88e2f | ||
|
|
4636cc74dc | ||
|
|
4cc54a2f05 | ||
|
|
9bd728889b | ||
|
|
d870115467 | ||
|
|
2b445fb563 | ||
|
|
44a3bad278 | ||
|
|
8d2615547d | ||
|
|
3292db8b77 | ||
|
|
8c6ad52437 | ||
|
|
62e53b53f0 | ||
|
|
35db157617 | ||
|
|
cfb137a94b | ||
|
|
9b4a33a612 | ||
|
|
918b7c1e03 | ||
|
|
8fb354705c | ||
|
|
b3826064b7 | ||
|
|
acba68dab9 | ||
|
|
32ea709350 | ||
|
|
c15dfc7c5d | ||
|
|
92f6a0c6c8 | ||
|
|
0235be538b | ||
|
|
abf19e7a27 | ||
|
|
1d3540dca6 | ||
|
|
ddfc9d911b | ||
|
|
b952256988 | ||
|
|
71868936d1 | ||
|
|
23ef4fb132 | ||
|
|
f74f2ca3ef | ||
|
|
f4f005cdd6 | ||
|
|
3137652280 | ||
|
|
88c6f0340a | ||
|
|
86146c7292 | ||
|
|
fad39b6d67 | ||
|
|
09a9330f3e | ||
|
|
d2d7f32c45 | ||
|
|
120b18b399 | ||
|
|
32b9e6b73d | ||
|
|
8d6e5272b9 | ||
|
|
b6f90a9715 | ||
|
|
e3d0b777fc | ||
|
|
79a8450462 | ||
|
|
1a967597e8 | ||
|
|
d5b0794b00 | ||
|
|
d78ee3d62b | ||
|
|
03037a9a6b | ||
|
|
0637b65846 | ||
|
|
e77e914f44 | ||
|
|
68c44daef2 | ||
|
|
8ca0b54b18 | ||
|
|
b77d01baca | ||
|
|
cd509bbbdc | ||
|
|
24a3ac9811 | ||
|
|
d35d3aabc3 | ||
|
|
9e624a6c0d | ||
|
|
9823cd25d2 | ||
|
|
416a8c8f5d | ||
|
|
c55bdd423e | ||
|
|
e45e202c5e | ||
|
|
2280a30ba9 | ||
|
|
9ac7518156 | ||
|
|
0e6dbaf71a | ||
|
|
fe018ff8f7 | ||
|
|
9b01e09302 | ||
|
|
3127474fd7 | ||
|
|
b849edfcca | ||
|
|
20a23c2868 | ||
|
|
49d9ded684 | ||
|
|
fc57b437c2 | ||
|
|
1ba20561ed | ||
|
|
2c8b26e091 | ||
|
|
62d2a97f38 | ||
|
|
44aa292bb5 | ||
|
|
5273b52c31 | ||
|
|
f143efb810 | ||
|
|
978fb06349 | ||
|
|
e274e8070d | ||
|
|
46bd5b42fa | ||
|
|
0b15e29324 | ||
|
|
75b6669371 | ||
|
|
c1c34017e4 | ||
|
|
ed08818b6f | ||
|
|
71adfc0a74 | ||
|
|
49ccbddb17 | ||
|
|
be3c7eef60 | ||
|
|
336c6cdd9d | ||
|
|
709a706853 | ||
|
|
dad62faf88 | ||
|
|
6e0a5fb5c6 | ||
|
|
4b9551d27f | ||
|
|
2a67bc9926 | ||
|
|
d02241d32c | ||
|
|
55e038d345 | ||
|
|
ea2bfbda44 | ||
|
|
ed7794f396 | ||
|
|
086646f311 | ||
|
|
ad169ca5a5 | ||
|
|
671e636aef | ||
|
|
72d381e9ed | ||
|
|
c076933b52 | ||
|
|
fdb5c813ad | ||
|
|
1bda6633b1 | ||
|
|
249a5bf3b7 | ||
|
|
679b468618 | ||
|
|
cf2a0af3d9 | ||
|
|
82be53224d | ||
|
|
9cc995cb52 | ||
|
|
42d414797a | ||
|
|
b071a4df70 | ||
|
|
46d927291c | ||
|
|
50ab01d9c9 | ||
|
|
dc8fe63acf | ||
|
|
4fc5863888 | ||
|
|
e2d8149dcf | ||
|
|
5f156d6bab | ||
|
|
816cdcf4bf | ||
|
|
75c94ae092 | ||
|
|
ecf2c50a26 | ||
|
|
cecb9293f6 | ||
|
|
1ebfa0ad7e | ||
|
|
35c7b57308 | ||
|
|
36bfeffbcc | ||
|
|
e6858719c9 | ||
|
|
f2d52f83fe | ||
|
|
f1d3cadb3b | ||
|
|
7d61d8e646 | ||
|
|
6ede400f3a | ||
|
|
78de45fee2 | ||
|
|
4559e33331 | ||
|
|
43875dd3fe | ||
|
|
fa10384a92 | ||
|
|
7e144da6b9 | ||
|
|
54af17e7bf | ||
|
|
d4a9f5bb2e | ||
|
|
8040813da8 | ||
|
|
871e40c5c0 | ||
|
|
7ce922b084 | ||
|
|
0c9989695a | ||
|
|
88d7cb3ed5 | ||
|
|
5b7fc80f26 | ||
|
|
553e8baa8b | ||
|
|
62a5031ccf | ||
|
|
4abac65316 | ||
|
|
c6e42e1032 | ||
|
|
a353631892 | ||
|
|
f144c982e3 | ||
|
|
16625b1dc7 | ||
|
|
78ccce7d1a | ||
|
|
ffba5f7d31 | ||
|
|
2cb8fa62df | ||
|
|
853b936cdd | ||
|
|
4f0fdbab62 | ||
|
|
190b23b702 | ||
|
|
e0bb79b2c4 | ||
|
|
2eab763d74 | ||
|
|
f64c1dd9e5 | ||
|
|
fab1d94d34 | ||
|
|
facf49b2b7 | ||
|
|
da86b86776 | ||
|
|
a79d9d4e77 | ||
|
|
d9e378211a | ||
|
|
99fbbf70de | ||
|
|
50a616457d | ||
|
|
2ad30ebe88 | ||
|
|
68dbc29f2c | ||
|
|
a87863229f | ||
|
|
f39ffcb997 | ||
|
|
f20bb388be | ||
|
|
fc45015b13 | ||
|
|
7a5f047f8e | ||
|
|
4251bee3ca | ||
|
|
f02741284c | ||
|
|
fec7419fcc | ||
|
|
e8694531f6 | ||
|
|
461491f742 | ||
|
|
af29acf462 | ||
|
|
b47f29e87c | ||
|
|
fc8ec6d7fa | ||
|
|
1d4c736cfa | ||
|
|
600450082a | ||
|
|
c6da0864f2 | ||
|
|
10fc6b4562 | ||
|
|
e48b7d83a3 | ||
|
|
a6742d401c | ||
|
|
87b9a8c4c8 | ||
|
|
134dc55891 | ||
|
|
295cf98e70 | ||
|
|
7333155b8c | ||
|
|
3960c7d8e6 | ||
|
|
b053f99690 | ||
|
|
5700c3f72e | ||
|
|
cdb3729a88 | ||
|
|
c33f2a1d27 | ||
|
|
9b9a32b053 | ||
|
|
95eec369b5 | ||
|
|
5d5860683b | ||
|
|
434b31b932 | ||
|
|
f69e42e520 | ||
|
|
c5cadfe0c6 | ||
|
|
f21be30004 | ||
|
|
b8b21d53e1 | ||
|
|
09ec39c87a | ||
|
|
dbf18db3a3 | ||
|
|
d8f0ae0980 | ||
|
|
09bbf1f4d7 | ||
|
|
d07aff9872 | ||
|
|
4cb3f9d177 | ||
|
|
c1a815778b | ||
|
|
5b003b09ac | ||
|
|
22d0697c77 | ||
|
|
432b0f3e54 | ||
|
|
2bee41e90e | ||
|
|
2a7312f2b4 | ||
|
|
f5091339ad | ||
|
|
3d06d68196 | ||
|
|
1a643bfa8c | ||
|
|
cd82b0a669 | ||
|
|
57312e29e2 | ||
|
|
592df4819b | ||
|
|
f36997c7c5 | ||
|
|
b1640d3626 | ||
|
|
825c62c62b | ||
|
|
a4b0c6f37d | ||
|
|
239b88aa3b | ||
|
|
88819611f4 | ||
|
|
e6ff8368a9 | ||
|
|
8315f572ea | ||
|
|
89e2070419 | ||
|
|
b5f4df0912 | ||
|
|
b9f3f80d50 | ||
|
|
0e8ae1a206 | ||
|
|
32729174bb | ||
|
|
2cf6fe8da7 | ||
|
|
929b031f09 | ||
|
|
57a36491ee | ||
|
|
f3a8dde5f0 | ||
|
|
ffa2489998 | ||
|
|
6cd7bcdae6 | ||
|
|
e4f684f411 | ||
|
|
fdc9a71f9e | ||
|
|
bb134ee7ac | ||
|
|
18dc6f3c88 | ||
|
|
9327fd3aa1 | ||
|
|
aa859b9002 | ||
|
|
20a15ecd35 | ||
|
|
062c59b321 | ||
|
|
9ace66edb7 | ||
|
|
a97d784f26 | ||
|
|
a2e7173983 | ||
|
|
0869651dc3 | ||
|
|
ca42286354 | ||
|
|
174bfcc597 | ||
|
|
244d25ce53 | ||
|
|
8287efd51f | ||
|
|
df31b5d59f | ||
|
|
53cc47a8b1 | ||
|
|
55f8294a38 | ||
|
|
67a5e3f37e | ||
|
|
06cd2f3a57 | ||
|
|
d614a94203 | ||
|
|
f66aca2164 | ||
|
|
b071ecb45e | ||
|
|
83a70fecca | ||
|
|
dbc7c224c1 | ||
|
|
7876f9a8a5 | ||
|
|
215057ce6f | ||
|
|
6d8b0b3ab6 | ||
|
|
e5c85ddd32 | ||
|
|
6bf3c34fe5 | ||
|
|
584f5e5935 | ||
|
|
58a5367015 | ||
|
|
8c2b907ff5 | ||
|
|
e3ab0c0192 | ||
|
|
8572e3eabb | ||
|
|
d4f10c61ef | ||
|
|
59e11d6caa | ||
|
|
67778198de | ||
|
|
ebfd8cd6f7 | ||
|
|
83b54f2ae6 | ||
|
|
7ea60ed178 | ||
|
|
c61d1ce6b4 | ||
|
|
6a7959547e | ||
|
|
af3834672e | ||
|
|
f95ff6cb89 | ||
|
|
e85c13b3fe | ||
|
|
ed09627fdb | ||
|
|
99ba2c2e8b | ||
|
|
589bdf5dcd | ||
|
|
1abbd5ecbc | ||
|
|
7619e8427a | ||
|
|
069e24d713 | ||
|
|
8e9b45f80f | ||
|
|
2d604a80c9 | ||
|
|
1f59a1b952 | ||
|
|
6e5ff01db5 | ||
|
|
50be44adf8 | ||
|
|
e1bf4347ab | ||
|
|
3a3305c020 | ||
|
|
a83f174e1a | ||
|
|
1295033fae | ||
|
|
755abec636 | ||
|
|
310995fb87 | ||
|
|
bee30e572f | ||
|
|
cd37a40bab | ||
|
|
8699790e78 | ||
|
|
d2d3f58a14 | ||
|
|
081df59ed7 | ||
|
|
ec3bcdcb26 | ||
|
|
8265cf8a6a | ||
|
|
dfb53fb3dd | ||
|
|
705fc920e5 | ||
|
|
99764741e4 | ||
|
|
35b3bc4522 | ||
|
|
91eee99bab | ||
|
|
e56defdc50 | ||
|
|
fbe4d3ce9f | ||
|
|
8cf5707575 | ||
|
|
f786a17014 | ||
|
|
427b9c1ebc | ||
|
|
141957e4b5 | ||
|
|
b911f4f34e | ||
|
|
0caf76dfae | ||
|
|
00f09168d7 | ||
|
|
d636359c10 | ||
|
|
8fd32aba4f | ||
|
|
9db59d5deb | ||
|
|
d98321c703 | ||
|
|
a6424c005f | ||
|
|
80d127c277 | ||
|
|
3ca0c828c6 | ||
|
|
d3a8e03b2c | ||
|
|
6e75de0dcb | ||
|
|
a7bed9741a | ||
|
|
f70e52a7a5 | ||
|
|
95d7de0654 | ||
|
|
3398d25b35 | ||
|
|
80a4a43680 | ||
|
|
01ac61f38c | ||
|
|
a98be36684 | ||
|
|
7f085c4012 | ||
|
|
5f008d1560 | ||
|
|
0782b579d5 | ||
|
|
f8ed2afef1 | ||
|
|
a883508eca | ||
|
|
a4a20ec220 | ||
|
|
faed63712f | ||
|
|
0032ec5036 | ||
|
|
9df24a841f | ||
|
|
d2aa4ff2bd | ||
|
|
171db01401 | ||
|
|
0112f1e11d | ||
|
|
8f7b09b58e | ||
|
|
479c2b6cec | ||
|
|
e6f50e6637 | ||
|
|
548f8bf23e | ||
|
|
b6bfe81f9a | ||
|
|
ab95bcc028 | ||
|
|
8b7b3df0a3 | ||
|
|
69a6416146 | ||
|
|
1ced4e277b | ||
|
|
0c5236ebcb | ||
|
|
66c55c5007 | ||
|
|
7f5a0f1b0c | ||
|
|
0c766938f1 | ||
|
|
1455e87aef | ||
|
|
7c50eef8ad | ||
|
|
aa9f972ccf | ||
|
|
45df99bb56 | ||
|
|
a2968e57cf | ||
|
|
67f831beba | ||
|
|
264d47caf4 | ||
|
|
ef72b3273e | ||
|
|
7d3ade7ae1 | ||
|
|
59897fdf55 | ||
|
|
0b4ea04c91 | ||
|
|
094b3b4636 | ||
|
|
0298beeb06 | ||
|
|
971542d6bc | ||
|
|
5bdbc9f40d | ||
|
|
efcd35d4a1 | ||
|
|
a01541d7ca | ||
|
|
7d96d7c066 | ||
|
|
639ea35921 | ||
|
|
dee1905e16 | ||
|
|
1803705749 | ||
|
|
5d96ee5492 | ||
|
|
4a0a1a32a4 | ||
|
|
c2108a35d0 | ||
|
|
31ecdbae18 | ||
|
|
e9c733e78f | ||
|
|
2320c5e04c | ||
|
|
fb7b3b0295 | ||
|
|
316a3d51ee | ||
|
|
240dcf2e5c | ||
|
|
5fbdbffa23 | ||
|
|
932c8b65fb | ||
|
|
e18e174947 | ||
|
|
f2c7df3a3b | ||
|
|
2b15dae806 | ||
|
|
2625d72818 | ||
|
|
a8b4d72421 | ||
|
|
88562890ae | ||
|
|
86c267eb89 | ||
|
|
3d1928cca9 | ||
|
|
8c64d3b55c | ||
|
|
41b238e87b | ||
|
|
da83025fb0 | ||
|
|
84d3b190c8 | ||
|
|
272fc5a72d | ||
|
|
0f709059e3 | ||
|
|
0f91bb28a9 | ||
|
|
63d75a8e17 | ||
|
|
be95d8409b | ||
|
|
9d3000498b | ||
|
|
48f8468e65 | ||
|
|
9b60559855 | ||
|
|
e97acf7938 | ||
|
|
1cfb92e75c | ||
|
|
4c617ccd49 | ||
|
|
494517e767 | ||
|
|
655c872ac9 | ||
|
|
cb0f2b48fd | ||
|
|
20a84bdefc | ||
|
|
83ad7d4935 | ||
|
|
ae2ca175d3 | ||
|
|
c855108b94 | ||
|
|
5e80b694c2 | ||
|
|
99640aa2ad | ||
|
|
4c0f7c3dd4 | ||
|
|
2a8490ef31 | ||
|
|
43dc694963 | ||
|
|
e03ee00554 | ||
|
|
01a07ec0e8 | ||
|
|
74b7738a9d | ||
|
|
10aaaebc38 | ||
|
|
a8d072150d | ||
|
|
7877bb7956 | ||
|
|
bd31e3df89 | ||
|
|
531e97b499 | ||
|
|
43876e967a | ||
|
|
efaf917939 | ||
|
|
7d3ceb7d8c | ||
|
|
201ac47943 | ||
|
|
5a70285c10 | ||
|
|
e13c27d32c | ||
|
|
9c9b673eeb | ||
|
|
7323fe0000 | ||
|
|
460d045cbe | ||
|
|
4983c1cfc9 | ||
|
|
c7bc9d471a | ||
|
|
a36b91ffe8 | ||
|
|
88da0db0f7 | ||
|
|
816c2b0ca8 | ||
|
|
d6ff68339b | ||
|
|
fdf483c98b | ||
|
|
eb020c1cb8 | ||
|
|
6fa331ad06 | ||
|
|
5a58ac2845 | ||
|
|
0c4edc4d17 | ||
|
|
b5cea4c27e | ||
|
|
b7de5d6df3 | ||
|
|
d7310ba307 | ||
|
|
cabb94b856 | ||
|
|
82b649f67d | ||
|
|
8753782a0c | ||
|
|
566a139edc | ||
|
|
39dda0f16b | ||
|
|
bddb371e31 | ||
|
|
128223a28a | ||
|
|
45b9d0553f | ||
|
|
a87f0e0475 | ||
|
|
beacea0482 | ||
|
|
85b59e79d3 | ||
|
|
9a947c5544 | ||
|
|
e4cebf4cbe | ||
|
|
f63e05b7d4 | ||
|
|
84b7fa02bb | ||
|
|
36e597a045 | ||
|
|
f760b3f271 | ||
|
|
d4c8fa6a24 | ||
|
|
c6604734c9 | ||
|
|
91ab8e22b7 | ||
|
|
14fb647647 | ||
|
|
8a39a43ad5 | ||
|
|
a3d23a6f57 | ||
|
|
ae5da12afb | ||
|
|
a3042b8f79 | ||
|
|
29cbfe7c1a | ||
|
|
1ddc3292cc | ||
|
|
658e1d122e | ||
|
|
d936a080db | ||
|
|
2a92af1e09 | ||
|
|
9cde537066 | ||
|
|
ffc5446914 | ||
|
|
5f70b32795 | ||
|
|
6b6117653a | ||
|
|
59bffed47f | ||
|
|
f91a679cdf | ||
|
|
66b8d27d66 | ||
|
|
1219f504ea | ||
|
|
ee5a191e39 | ||
|
|
f577aa8d4f | ||
|
|
2436c87372 | ||
|
|
e90b5e63e5 | ||
|
|
78588d8cdf | ||
|
|
20c1c1d4be | ||
|
|
329dfb21b9 | ||
|
|
02c30211a7 | ||
|
|
645da2713d | ||
|
|
20c5a79efa | ||
|
|
b224aeb0d8 | ||
|
|
73eebd6162 | ||
|
|
99a1851f4d | ||
|
|
d9d89d0927 | ||
|
|
54f2aa5f77 | ||
|
|
d022e9dd00 | ||
|
|
17cf8ec1c6 | ||
|
|
c4a6d81cda | ||
|
|
66ed485803 | ||
|
|
6de585d1c8 | ||
|
|
9498638988 | ||
|
|
87dad82210 | ||
|
|
e37aec16ac | ||
|
|
6fb48af598 | ||
|
|
8193be36e5 | ||
|
|
a7df2bc4fb | ||
|
|
5eda028af3 | ||
|
|
f77475dbfe | ||
|
|
96c1a35c8e | ||
|
|
0ef26be03f | ||
|
|
f5bb15f72e | ||
|
|
d84aebd8f4 | ||
|
|
7d8d9f4c4d | ||
|
|
61b201810d | ||
|
|
c75db8dc60 | ||
|
|
e0bf4091dd | ||
|
|
1d89c46638 | ||
|
|
88797424f1 | ||
|
|
e0c57e77a9 | ||
|
|
e15a99f39f | ||
|
|
9723c3606a | ||
|
|
d2385d9287 | ||
|
|
2695169514 | ||
|
|
efcdfdf612 | ||
|
|
f77e7334c5 | ||
|
|
9079a7988c | ||
|
|
5256d795b1 | ||
|
|
24a765814a | ||
|
|
ef18a00362 | ||
|
|
1823786344 | ||
|
|
548a1f30ca | ||
|
|
e63859442a | ||
|
|
69032db3c3 | ||
|
|
d3e5b1b4e0 | ||
|
|
e2cd68e3e8 | ||
|
|
3e6029d33c | ||
|
|
89f1f8e6dc | ||
|
|
cff25374b5 | ||
|
|
04bbff338d | ||
|
|
bbcd6a3261 | ||
|
|
e587e8cfc8 | ||
|
|
869f8cf380 | ||
|
|
1ff6ba9480 | ||
|
|
5807bee23b | ||
|
|
b5bafbf23a | ||
|
|
3954ccab8a | ||
|
|
24eb9d9e14 | ||
|
|
57207a72ea | ||
|
|
8771911931 | ||
|
|
7b2411eec5 | ||
|
|
49a0b0bff2 | ||
|
|
3cea7ee1b9 | ||
|
|
d366c1ac64 | ||
|
|
315858e410 | ||
|
|
a53965b824 | ||
|
|
cf973c3f25 | ||
|
|
db09144624 | ||
|
|
32b94555c3 | ||
|
|
f507fef40d | ||
|
|
d5caff58c7 | ||
|
|
ab4c725217 | ||
|
|
901ba9cf13 | ||
|
|
19b1bc6b3e | ||
|
|
c623ea7c2a | ||
|
|
72e61106a9 | ||
|
|
e15e7f0942 | ||
|
|
133f094d72 | ||
|
|
e4c89c1aed | ||
|
|
193cf1c750 | ||
|
|
75c2a630f6 | ||
|
|
3a7cecac31 | ||
|
|
0ab214fd5d | ||
|
|
eb603e942f | ||
|
|
b1e1c704b1 | ||
|
|
f908336ec6 | ||
|
|
3ff97e43e1 | ||
|
|
622434b457 | ||
|
|
877319a8e5 | ||
|
|
295db43bca | ||
|
|
4285f43316 | ||
|
|
29e8316527 | ||
|
|
2b988b8ab1 | ||
|
|
0abf991b05 | ||
|
|
7fc5b70553 | ||
|
|
b3681002a7 | ||
|
|
1f9af7a1e4 | ||
|
|
9ed184edbf | ||
|
|
89572b07fb | ||
|
|
443578e0ee | ||
|
|
0f96daec9a | ||
|
|
59412c54de | ||
|
|
16ca55e4ec | ||
|
|
03959a68d5 | ||
|
|
59b48ceb4a | ||
|
|
d499bfab8a | ||
|
|
b7b2b5089f | ||
|
|
fcb417af17 | ||
|
|
28c130a910 | ||
|
|
57a5eabd8f | ||
|
|
88874f0dcd | ||
|
|
98d5e27a8c | ||
|
|
576956fa1d | ||
|
|
be051a4bb1 | ||
|
|
cc6c7430d4 | ||
|
|
477ee14b6d | ||
|
|
2539b2333c | ||
|
|
ebf6ba9ca1 | ||
|
|
60528525e0 | ||
|
|
cb5a7f8c9d | ||
|
|
fd9c6d460a | ||
|
|
fa5b135439 | ||
|
|
9f5249e5b8 | ||
|
|
819800d3a4 | ||
|
|
8ac5b55b3a | ||
|
|
abe1079328 | ||
|
|
775c62fbb4 | ||
|
|
daff2c1f84 | ||
|
|
1ea8b064cc | ||
|
|
a0e030a6ee | ||
|
|
690eb343ea | ||
|
|
ad5e476920 | ||
|
|
2a92ce867a | ||
|
|
bf7c8df353 | ||
|
|
d57f6303f4 | ||
|
|
9c6c26f424 | ||
|
|
00a98f6e30 | ||
|
|
50d83dc070 | ||
|
|
010a0cc2a7 | ||
|
|
71728bb3fe | ||
|
|
fc1537fde8 | ||
|
|
6e40f639b7 | ||
|
|
21c5a97d15 | ||
|
|
8a4d78ae4d | ||
|
|
001964f2f4 | ||
|
|
a6a29d5c5a | ||
|
|
706308cefd | ||
|
|
72b194cd7e | ||
|
|
b85819ed9d | ||
|
|
c5cd648b5d | ||
|
|
3743408543 | ||
|
|
fd251c6e61 | ||
|
|
b7ab6c5c3e | ||
|
|
5659fd5839 | ||
|
|
4dcd3e95df | ||
|
|
57709413e1 | ||
|
|
fb634bc2d4 | ||
|
|
18a67e1f20 | ||
|
|
b4c2ae251b | ||
|
|
bfaabafbfa | ||
|
|
c213d5b8d9 | ||
|
|
50beda6621 | ||
|
|
8ea359ec8a | ||
|
|
c983c8e447 | ||
|
|
af96ce3e82 | ||
|
|
6a5928863c | ||
|
|
514becc53a | ||
|
|
1b140535a8 | ||
|
|
cb5222e4d6 | ||
|
|
b6a9e1a996 | ||
|
|
b58a7c32c2 | ||
|
|
fa0fd6b7d0 | ||
|
|
057ec49a3e | ||
|
|
3ae9092226 | ||
|
|
351999a01b | ||
|
|
e407080057 | ||
|
|
fa0bd8d31a | ||
|
|
9b5fdb1345 | ||
|
|
47fd30c23f | ||
|
|
ad469e4f61 | ||
|
|
eaed953614 | ||
|
|
977ac16a1e | ||
|
|
c7986e4277 | ||
|
|
aff8fa1968 | ||
|
|
0af767fff0 | ||
|
|
a928aa61ca | ||
|
|
30cb0b1cae | ||
|
|
32ae3cd567 | ||
|
|
91b9602e12 | ||
|
|
124eba6800 | ||
|
|
a5ab8ddf8b | ||
|
|
1444a1578a | ||
|
|
5b8894b0ff | ||
|
|
a4329dd9a0 | ||
|
|
1cab25aa7d | ||
|
|
d3faf18251 | ||
|
|
ddcc296af4 | ||
|
|
ee765bc210 | ||
|
|
630c67f7d0 | ||
|
|
e78bb1b29c | ||
|
|
db312a7380 | ||
|
|
48b4cbe1b9 | ||
|
|
edb1d4c747 | ||
|
|
128935b55e | ||
|
|
d5a0d67c7b | ||
|
|
a86640fdee | ||
|
|
03291b27d1 | ||
|
|
acf81f116f | ||
|
|
6564c405c1 | ||
|
|
1bd586268c | ||
|
|
497952611d | ||
|
|
9149d1baa3 | ||
|
|
66c60ac5c7 | ||
|
|
971fad4560 | ||
|
|
8ed1ce4103 | ||
|
|
3112c34d11 | ||
|
|
7ebf3cecc6 | ||
|
|
660fa99f9c | ||
|
|
a997e53d8b | ||
|
|
1d1dd583e2 | ||
|
|
d490b29265 | ||
|
|
e8ca64f16b | ||
|
|
380aa7d884 | ||
|
|
0a31a94ee8 | ||
|
|
e1d50ce28f | ||
|
|
38cc39f23d | ||
|
|
8110035d71 | ||
|
|
9af409d6d6 | ||
|
|
8646829853 | ||
|
|
b9e87813b1 | ||
|
|
138e032746 | ||
|
|
d94c6b5aba | ||
|
|
7c03a39316 | ||
|
|
c482e264f4 | ||
|
|
3a9a1f0a94 | ||
|
|
5b5f728f49 | ||
|
|
179aac6b35 | ||
|
|
25de9126ca | ||
|
|
87be5662ad | ||
|
|
053a59e3f4 | ||
|
|
250857b3d4 | ||
|
|
dc288c584c | ||
|
|
fc02543f15 | ||
|
|
0808db706f | ||
|
|
1e649fc565 | ||
|
|
c523e959d7 | ||
|
|
1422f988c1 | ||
|
|
e86252b934 | ||
|
|
e9c59b5c31 | ||
|
|
f7bddee0ce | ||
|
|
d56b76c9e3 | ||
|
|
a41353ed03 | ||
|
|
7ea12cf2f9 | ||
|
|
5bc5170112 | ||
|
|
946ed0c0b5 | ||
|
|
fcd4e5aca2 | ||
|
|
6ab6e6d3a8 | ||
|
|
0893d01b4a | ||
|
|
bf04c45ebf | ||
|
|
2786a1a97e | ||
|
|
cd9a4f1aa9 | ||
|
|
91e5cafe76 | ||
|
|
47754951f0 | ||
|
|
fbef8ef32e | ||
|
|
abd5bf3158 | ||
|
|
fd024368a3 | ||
|
|
cf4856a0c9 | ||
|
|
1b791c82fc | ||
|
|
3a27a3e868 | ||
|
|
7e6c16b287 | ||
|
|
f877639ed7 | ||
|
|
846309d4dd | ||
|
|
f2239ddfdf | ||
|
|
742d455b0e | ||
|
|
20b08a78e7 | ||
|
|
042da74955 | ||
|
|
4dcae4ce21 | ||
|
|
fa0f07f553 | ||
|
|
39792d76cf | ||
|
|
d181ee9101 | ||
|
|
335ba1a5b0 | ||
|
|
4934a360f1 | ||
|
|
0559a4c6f2 | ||
|
|
fc07919a75 | ||
|
|
d7661edf67 | ||
|
|
1c91693294 | ||
|
|
3fc3cbc6d5 | ||
|
|
11b5895e69 | ||
|
|
b4c614edbf | ||
|
|
deddaed04a | ||
|
|
a155e503f4 | ||
|
|
c0663bc19f | ||
|
|
7ffa51b83d | ||
|
|
6d397b9988 | ||
|
|
571a7fa26b | ||
|
|
b3b5a38c3a | ||
|
|
a4b115f89b | ||
|
|
3d672bb145 | ||
|
|
15b656b753 | ||
|
|
f5785db163 | ||
|
|
1ff1bf3292 | ||
|
|
b062febea0 | ||
|
|
35301dc79e | ||
|
|
30c336726b | ||
|
|
3821680817 | ||
|
|
74242ea24f | ||
|
|
73c7024e11 | ||
|
|
bbdec92dc6 | ||
|
|
b4c289101c | ||
|
|
722d0797f6 | ||
|
|
deb27d5b55 | ||
|
|
9cc4ffdf6e | ||
|
|
c76d63d1d9 | ||
|
|
21bb4f33ad | ||
|
|
2897b881d6 | ||
|
|
e9b89d0929 | ||
|
|
e801254b2e | ||
|
|
6f49918ee9 | ||
|
|
0ae7c18f1f | ||
|
|
c9c3fb396a | ||
|
|
91db4f1934 | ||
|
|
9bbed6e95c | ||
|
|
748bc27b25 | ||
|
|
f42708e8bc | ||
|
|
160e4570a2 | ||
|
|
6272965143 | ||
|
|
1e9613bf7f | ||
|
|
a061dac298 | ||
|
|
914dee8571 | ||
|
|
47e2905edf | ||
|
|
ee6675aee0 | ||
|
|
62e0d9fe64 | ||
|
|
a174c142c1 | ||
|
|
95afc5fdec | ||
|
|
04d69f66c0 | ||
|
|
0347141edd | ||
|
|
1d6baae6e0 | ||
|
|
fb0f48f08a | ||
|
|
76e5e03d31 | ||
|
|
4cab743634 | ||
|
|
7c10ec97b7 | ||
|
|
8718a16889 | ||
|
|
75a0b924c3 | ||
|
|
83a90e0c05 | ||
|
|
e5eadd1315 | ||
|
|
f0142d90d4 | ||
|
|
cabd6e6e9d | ||
|
|
4804a05736 | ||
|
|
c258e5a3af | ||
|
|
e8492940a5 | ||
|
|
4bccb1ab47 | ||
|
|
b6d219e232 | ||
|
|
23ee17594d | ||
|
|
d9d39d8e25 | ||
|
|
224d5d46c1 | ||
|
|
09e0059930 | ||
|
|
0ddff2b087 | ||
|
|
2e6a29eacc | ||
|
|
ad2fb82aa9 | ||
|
|
a3f91c11e8 | ||
|
|
a50c978ce3 | ||
|
|
27d6f881cd | ||
|
|
944cd020af | ||
|
|
bbe5d64b99 | ||
|
|
f7b36ac4c7 | ||
|
|
1d555ca17e | ||
|
|
f91b6c3468 | ||
|
|
abe6eeb350 | ||
|
|
64f90a7912 | ||
|
|
5733966843 | ||
|
|
eb1344fcec | ||
|
|
c5fb29f00e | ||
|
|
63135b9c54 | ||
|
|
f7c666584e | ||
|
|
6834324de2 | ||
|
|
3a0d59e66f | ||
|
|
ffd2e2188a | ||
|
|
0e8d5bdc5d | ||
|
|
14806f6614 | ||
|
|
00ece83b9d | ||
|
|
8197ae2a2d | ||
|
|
5fe658bb16 | ||
|
|
617179f0c6 | ||
|
|
95ac85f642 | ||
|
|
ca8877ad47 | ||
|
|
6d8f31048c | ||
|
|
ac859eb576 | ||
|
|
2dfa171b6a | ||
|
|
6f72e3e2ea | ||
|
|
c2b73ae963 | ||
|
|
6c50077409 | ||
|
|
06746449a1 | ||
|
|
da7b8edf51 | ||
|
|
6e29b41f23 | ||
|
|
912bb069af | ||
|
|
6b2d7a67d8 | ||
|
|
dbb8ec0290 | ||
|
|
60b32760f2 | ||
|
|
73a40bcb49 | ||
|
|
0e258a5a32 | ||
|
|
7ca65c81d8 | ||
|
|
2ad1a60e59 | ||
|
|
cf17ff4478 | ||
|
|
fffc3aac68 | ||
|
|
295ac3c458 | ||
|
|
b6693a71f9 | ||
|
|
5b21118a8c | ||
|
|
0235b19801 | ||
|
|
7426399aa2 | ||
|
|
6861b0d668 | ||
|
|
c30fb0d38c | ||
|
|
e45521c6c0 | ||
|
|
d11fe8d4fc | ||
|
|
8e83e63e3d | ||
|
|
c8fd0ac4b3 | ||
|
|
d78419eb33 | ||
|
|
e44a3d013d | ||
|
|
aeb0d05017 | ||
|
|
62702e4b3d | ||
|
|
5146cdfa2f | ||
|
|
246e7018c3 | ||
|
|
24286dbe9d | ||
|
|
2f442dfbe1 | ||
|
|
b2fb01ee9c | ||
|
|
45e0a9a4ef | ||
|
|
675b7b4bf4 | ||
|
|
be7a35443e | ||
|
|
9918615fcd | ||
|
|
4b72ef77c1 | ||
|
|
e427c61fbb | ||
|
|
c78e8937d5 | ||
|
|
5d63f7a93d | ||
|
|
46551ada7f | ||
|
|
83f17a37b1 | ||
|
|
9e23e0a623 | ||
|
|
4a53d4f043 | ||
|
|
0fd61945c7 | ||
|
|
e3624eed30 | ||
|
|
1923c8be0c | ||
|
|
a3e37fbfe2 | ||
|
|
318c3bb422 | ||
|
|
db96e24028 | ||
|
|
cc2cce66df | ||
|
|
7afeabd288 | ||
|
|
eb43a812d6 | ||
|
|
12cbcdb6f4 | ||
|
|
a2e35e30dc | ||
|
|
b6ff7e6b47 | ||
|
|
6dba40c6bb | ||
|
|
896da46422 | ||
|
|
7c07f5eb2a | ||
|
|
298cff37de | ||
|
|
8add802fe9 | ||
|
|
6d080a0d59 | ||
|
|
f0ae1051ee | ||
|
|
1ad0ffeaa6 | ||
|
|
45b44d012d | ||
|
|
cb6cbb9ee5 | ||
|
|
013a0d9cb0 | ||
|
|
8abb3ea225 | ||
|
|
74a5233b5d | ||
|
|
cd695a4522 | ||
|
|
eec4b2cc0e | ||
|
|
616875d0d2 | ||
|
|
eb749bd76f | ||
|
|
7d1e404efd | ||
|
|
4a01a578d1 | ||
|
|
393a2e0ea0 | ||
|
|
8e21decb8d | ||
|
|
22bfbab832 | ||
|
|
28d0cc8795 | ||
|
|
51f2383a07 | ||
|
|
a6426c6eba | ||
|
|
0631da6c8e | ||
|
|
3960239cfe | ||
|
|
b16e48af6f | ||
|
|
4d3950565a | ||
|
|
8d24bc50c9 | ||
|
|
458efe9168 | ||
|
|
ae940a8681 | ||
|
|
d76b223b7c | ||
|
|
7243d5f7cb | ||
|
|
387f74f66a | ||
|
|
61ffb7d97a | ||
|
|
a553693f34 | ||
|
|
cdcfd64ec4 | ||
|
|
7f4302ba20 | ||
|
|
0d94f2d376 | ||
|
|
c1eb20a20b | ||
|
|
634db67685 | ||
|
|
86648258a3 | ||
|
|
287f0a3739 | ||
|
|
8f42df209a | ||
|
|
390fd64a74 | ||
|
|
48ee471def | ||
|
|
e862afcb78 | ||
|
|
872da05ff6 | ||
|
|
d09e2daf00 | ||
|
|
e2d5b44b0a | ||
|
|
52d42ef2a8 | ||
|
|
b6abc34461 | ||
|
|
ae6a50626d | ||
|
|
8f9dbfee2c | ||
|
|
c71ccda967 | ||
|
|
0f284f2e1d | ||
|
|
45ac80dd8c | ||
|
|
09cdba4b3d | ||
|
|
d94ee8863c | ||
|
|
cc8ced6430 | ||
|
|
cdb144e6a6 | ||
|
|
58fb8643c6 | ||
|
|
b81cfa8acb | ||
|
|
938ee20f1f | ||
|
|
d02dc54c1b | ||
|
|
8680a54ae4 | ||
|
|
30001be0ee | ||
|
|
4614cb5ec1 | ||
|
|
e390f3a399 | ||
|
|
e22d463d11 | ||
|
|
5877aa822c | ||
|
|
a2915913bb | ||
|
|
a8b40747b2 | ||
|
|
b63030d302 | ||
|
|
4457e416db | ||
|
|
c7c1a8ede1 | ||
|
|
fd1e9d7fb0 | ||
|
|
59a6d2317b | ||
|
|
531c171542 | ||
|
|
0c743452b0 | ||
|
|
4893d3da1f | ||
|
|
5cdc24bfb0 | ||
|
|
523cdca449 | ||
|
|
09537d73da | ||
|
|
99c0c0b3b1 | ||
|
|
45bc353341 | ||
|
|
b2fc41a911 | ||
|
|
ebefe8b6d2 | ||
|
|
9e3508134b | ||
|
|
3166ca2127 | ||
|
|
204508478f | ||
|
|
51ce674c97 | ||
|
|
6fcde9fe5f | ||
|
|
c688e3431d | ||
|
|
230376c7f3 | ||
|
|
91d0a2cd0c | ||
|
|
1ffd010e4a | ||
|
|
ae366e141f | ||
|
|
eb869c6e97 | ||
|
|
b559f7cd16 | ||
|
|
375d32f08e | ||
|
|
89d6b7cec0 | ||
|
|
fdf96e8342 | ||
|
|
c5d73d7b09 | ||
|
|
34b4cc2d9e | ||
|
|
40ed17e609 | ||
|
|
673d76af45 | ||
|
|
c13fb6f9d5 | ||
|
|
424b1e7d1f | ||
|
|
e80c9c4101 | ||
|
|
f75c3633e9 | ||
|
|
d535cd8276 | ||
|
|
c13f6ab2af | ||
|
|
d2a30bfb78 | ||
|
|
e5b17092b4 | ||
|
|
466cb4c78b | ||
|
|
9722e1ddc4 | ||
|
|
e3a9b0b943 | ||
|
|
d668a8aee2 | ||
|
|
75dc0aafcf | ||
|
|
41b94233c6 | ||
|
|
52cff01b9c | ||
|
|
372fc6603d | ||
|
|
9221797c9d | ||
|
|
7501131558 | ||
|
|
bba7be99a3 | ||
|
|
abb95534d0 | ||
|
|
0b7b4c12e4 | ||
|
|
4056f00169 | ||
|
|
10303cb9c0 | ||
|
|
e3587d369e | ||
|
|
2a048502cc | ||
|
|
cac01fbde9 | ||
|
|
2d2ce191ec | ||
|
|
6380cb8458 | ||
|
|
48e0e6af71 | ||
|
|
b756bccc7a | ||
|
|
ae8eed7a67 | ||
|
|
ae4882bec3 | ||
|
|
1379741859 | ||
|
|
b45c7ace78 | ||
|
|
3843d9f55b | ||
|
|
f3422cb2fe | ||
|
|
73692797dc | ||
|
|
31dd910289 | ||
|
|
da51580299 | ||
|
|
9db148b1ec | ||
|
|
091b1b8209 | ||
|
|
900a4071ed | ||
|
|
df4b2f7938 | ||
|
|
803f44d9bc | ||
|
|
4b67aee020 | ||
|
|
71dc47d6c9 | ||
|
|
9cb305fb0d | ||
|
|
1672130486 | ||
|
|
8e135e3e79 | ||
|
|
aa1a4f6ea5 | ||
|
|
ba34cf5258 | ||
|
|
647089d2a8 | ||
|
|
5211508eb4 | ||
|
|
e6f05ae465 | ||
|
|
a9193f9b76 | ||
|
|
e373a17cd3 | ||
|
|
ebab9b7e4a | ||
|
|
6de0399807 | ||
|
|
5cc7bb80f6 | ||
|
|
6e0bd9b3f8 | ||
|
|
d1943f72d3 | ||
|
|
81709873bd | ||
|
|
f6bb7cd8ed | ||
|
|
d1c19e431c | ||
|
|
9ab2dde8ab | ||
|
|
71559bb125 | ||
|
|
ae4c95262c | ||
|
|
dbbf07c9c1 | ||
|
|
ab8cd619d5 | ||
|
|
c30ad2819d | ||
|
|
311e91797a | ||
|
|
52be4df355 | ||
|
|
0364e81050 | ||
|
|
2d49b71bc9 | ||
|
|
a18a4bdf31 | ||
|
|
d3acbe8288 | ||
|
|
22afcbcbb6 | ||
|
|
495c6bc21c | ||
|
|
cfd1fe59f3 | ||
|
|
c46cf5bc84 | ||
|
|
a8742557bd | ||
|
|
3bea58cf56 | ||
|
|
5aaa5231b8 | ||
|
|
82d10dd7cb | ||
|
|
841065fb91 | ||
|
|
c7146ef138 | ||
|
|
08f32d1de6 | ||
|
|
4c3f86aa4d | ||
|
|
445cf22333 | ||
|
|
4919de647a | ||
|
|
77fae99528 | ||
|
|
10bd4b40b9 | ||
|
|
9d8e6bb253 | ||
|
|
49c71ecfad | ||
|
|
d18834b415 | ||
|
|
e52cda193e | ||
|
|
0d5edd35ea | ||
|
|
f3f51c3d9d | ||
|
|
1431916183 | ||
|
|
ae48008803 | ||
|
|
5664813931 | ||
|
|
3948af80b8 | ||
|
|
343d6f9aff | ||
|
|
51b379502f | ||
|
|
82142751de | ||
|
|
4e5755f218 | ||
|
|
2f4f29517e | ||
|
|
e8a073651f | ||
|
|
d23da7a612 | ||
|
|
1ae4938da3 | ||
|
|
b5e27d4d69 | ||
|
|
d74fc8d1ce | ||
|
|
c5d9a41967 | ||
|
|
7e3042c4f4 | ||
|
|
1291dadbd6 | ||
|
|
f645099a39 | ||
|
|
8f32038891 | ||
|
|
a6fb1dcdf9 | ||
|
|
f01b469f3f | ||
|
|
47884919c8 | ||
|
|
653a35496d | ||
|
|
9b14df6b27 | ||
|
|
09813f3c5a | ||
|
|
7d76b7e4c2 | ||
|
|
47b5dea95c | ||
|
|
b0df63f1e8 | ||
|
|
3c4209b676 | ||
|
|
d51b9a8e0e | ||
|
|
3b56125bd2 | ||
|
|
6e69e39007 | ||
|
|
97208cb329 | ||
|
|
414a4a97fb | ||
|
|
2a809f96c4 | ||
|
|
17799b03f3 | ||
|
|
efc55fc648 | ||
|
|
22bd41211a | ||
|
|
4cb0171bd0 | ||
|
|
ce6c5af72c | ||
|
|
171575256c | ||
|
|
d3664dcf78 | ||
|
|
0788981783 | ||
|
|
aeee7c02d5 | ||
|
|
6e49a50461 | ||
|
|
fbc99827ab | ||
|
|
3b134320c4 | ||
|
|
c315e5016d | ||
|
|
7aebd6ed57 | ||
|
|
1a8ca06495 | ||
|
|
a27ae7e4a6 | ||
|
|
dd0ab897aa | ||
|
|
00ad92fb6d | ||
|
|
f84128ecbd | ||
|
|
ba89e0f4e3 | ||
|
|
832d36a4d4 | ||
|
|
0b437b3bfb | ||
|
|
7b50ec4630 | ||
|
|
4ddb13abac | ||
|
|
d2ac081177 | ||
|
|
9692fbf15b | ||
|
|
be966488e8 | ||
|
|
0ce613264f | ||
|
|
34634d776e | ||
|
|
673ded3819 | ||
|
|
b9a94ad3ae | ||
|
|
3f80b330cc | ||
|
|
01632d538c | ||
|
|
b0a9b1cd09 | ||
|
|
1f772081fd | ||
|
|
4ae54dbaad | ||
|
|
e47f4ff731 | ||
|
|
465369d79e | ||
|
|
15ddf6ff20 | ||
|
|
16a753bd95 | ||
|
|
c15103636c | ||
|
|
8a5f82ee7d | ||
|
|
5ec33ec821 | ||
|
|
ab7d383cf1 | ||
|
|
184e9a5c93 | ||
|
|
c4f5363cde | ||
|
|
002882cebf | ||
|
|
1cb3ec0c7b | ||
|
|
6bf325c6f6 | ||
|
|
09c7ff9e8b | ||
|
|
c2a94b61bf | ||
|
|
1db16232de | ||
|
|
3da681a6b1 | ||
|
|
a79b3e7852 | ||
|
|
b1099e6974 | ||
|
|
4f6e06131c | ||
|
|
19f69e9e6c | ||
|
|
01481da773 | ||
|
|
3e8f7e1cf1 | ||
|
|
5da69646f2 | ||
|
|
3cac01583b | ||
|
|
d16a26605e | ||
|
|
a4f692c788 | ||
|
|
9f01206c57 | ||
|
|
d34fc551ed | ||
|
|
7aa5f0d258 | ||
|
|
276a34bb66 | ||
|
|
0d820eda12 | ||
|
|
1991c1b677 | ||
|
|
459404e3f0 | ||
|
|
badc623a3c | ||
|
|
8e39f92cb7 | ||
|
|
3ff4885973 | ||
|
|
f9d45f7657 | ||
|
|
789ff9df5c | ||
|
|
a2064ed16b | ||
|
|
b3d06c0868 | ||
|
|
db1a6b3e38 | ||
|
|
8390237cc4 | ||
|
|
9967eae7bb | ||
|
|
b3be7d1c6f | ||
|
|
33ccb5dbb2 | ||
|
|
5b90c0d695 | ||
|
|
472a660239 | ||
|
|
ab67536d9a | ||
|
|
ee85fb3aec | ||
|
|
214b6f4358 | ||
|
|
af0d092054 | ||
|
|
b07903c3e9 | ||
|
|
ffa4c6bf09 | ||
|
|
b4125fa56c | ||
|
|
2c72302087 | ||
|
|
0fa52bc64f | ||
|
|
f55a80b15a | ||
|
|
0735483321 | ||
|
|
53fc2c7c21 | ||
|
|
f22133c3c5 | ||
|
|
2d5a6d6583 | ||
|
|
dc4adf2836 | ||
|
|
dd6e254e4f | ||
|
|
4c028c1659 | ||
|
|
d332a6777a | ||
|
|
378251f229 | ||
|
|
b6b9b903ed | ||
|
|
143d68cfd5 | ||
|
|
a31eac1426 | ||
|
|
797196f7fc | ||
|
|
c9d0bc81dd | ||
|
|
b5448ff607 | ||
|
|
5ebd363d5d | ||
|
|
1d439e673e | ||
|
|
0b7b7656b2 | ||
|
|
eb270df835 | ||
|
|
ff73dd2183 | ||
|
|
e043a03eb6 | ||
|
|
3cb4e8e373 | ||
|
|
7e6de528b4 | ||
|
|
df901c30ef | ||
|
|
13856b33ec | ||
|
|
a3a1c6f4c8 | ||
|
|
638998a861 | ||
|
|
6e2ec89a05 | ||
|
|
af67de8aa6 | ||
|
|
425dac478e | ||
|
|
b15c4ecd10 | ||
|
|
d7f88cf3a4 | ||
|
|
5b7fbcd9b8 | ||
|
|
7af64b0782 | ||
|
|
b84c70e811 | ||
|
|
f5b245c72d | ||
|
|
4307183817 | ||
|
|
aeb32783d6 | ||
|
|
3927b3bf27 | ||
|
|
da9d2f9417 | ||
|
|
1cec48e8f8 | ||
|
|
f1105393da | ||
|
|
dc7047e3c2 | ||
|
|
08b2945623 | ||
|
|
cbcc223150 | ||
|
|
9830f21e4a | ||
|
|
5f49567bf7 | ||
|
|
6154ae7342 | ||
|
|
978f3a3682 | ||
|
|
1f0961d574 | ||
|
|
a101252701 | ||
|
|
c96c29b1e3 | ||
|
|
3b0fc180ff | ||
|
|
9b8bfdf33c | ||
|
|
4328831fcd | ||
|
|
e5b3df41e9 | ||
|
|
cf5259e218 | ||
|
|
f24b6a520c | ||
|
|
4140163ab2 | ||
|
|
7afde0e93f | ||
|
|
d27a571882 | ||
|
|
1c70e3be25 | ||
|
|
1819f64467 | ||
|
|
9852e588c1 | ||
|
|
71a1ea481b | ||
|
|
9e32f0d778 | ||
|
|
4478174dc2 | ||
|
|
07553476d4 | ||
|
|
1773283456 | ||
|
|
221ab51d90 | ||
|
|
43e0dd922b | ||
|
|
b3262652c3 | ||
|
|
0cfa2b8c20 | ||
|
|
c4600b2187 | ||
|
|
89b15e3b57 | ||
|
|
07d8c3e770 | ||
|
|
c5ae64070e | ||
|
|
2cb7c52147 | ||
|
|
c045b16213 | ||
|
|
b29387d409 | ||
|
|
614a09db1d | ||
|
|
bcc5450aef | ||
|
|
b0420a0566 | ||
|
|
08d627bc9f | ||
|
|
5b5f048faf | ||
|
|
212ebae043 | ||
|
|
a0c99df6b2 | ||
|
|
b0fabd7897 | ||
|
|
938811f24f | ||
|
|
374d6e4d0f | ||
|
|
5f54cdee0f | ||
|
|
c2bd452391 | ||
|
|
d2bfc73b91 | ||
|
|
42c62206c8 | ||
|
|
4208b512f8 | ||
|
|
3a3d5cd487 | ||
|
|
e143a6d126 | ||
|
|
a99a19aa60 | ||
|
|
aba7d2b6a4 | ||
|
|
2fc6f835a8 | ||
|
|
27ce0e6d60 | ||
|
|
05c70f2adb | ||
|
|
904097b7b1 | ||
|
|
4e003c12a6 | ||
|
|
24f2cfb29f | ||
|
|
3f2b683fca | ||
|
|
83cee26d7d | ||
|
|
c7df0c9b28 | ||
|
|
26a8bfaac4 | ||
|
|
fc8a3be7d9 | ||
|
|
b195c4033d | ||
|
|
ab2732c55d | ||
|
|
7fd5c058be | ||
|
|
b22e8b4702 | ||
|
|
e2c2af3447 | ||
|
|
4cd738ecb5 | ||
|
|
e838470c26 | ||
|
|
68e0bc40e1 | ||
|
|
9fc8bcdf62 | ||
|
|
227b14a0b6 | ||
|
|
abcd184d5d | ||
|
|
3fd9f4b0df | ||
|
|
12ff3e963b | ||
|
|
558e392234 | ||
|
|
e747c2e263 | ||
|
|
4d78b30e8c | ||
|
|
9a1520d5e3 | ||
|
|
04f3543424 | ||
|
|
eae287be37 | ||
|
|
a0e698b058 | ||
|
|
cd2932adea | ||
|
|
286b270592 | ||
|
|
d1ebef2cc5 | ||
|
|
deb567fde7 | ||
|
|
26586fb9ef | ||
|
|
5f71a558b9 | ||
|
|
08882639e0 | ||
|
|
837ae2932f | ||
|
|
b51cc21140 | ||
|
|
f1115ba706 | ||
|
|
dc36aee7ff | ||
|
|
740f9581e6 | ||
|
|
de0e3a7bc9 | ||
|
|
95e894fb4d | ||
|
|
faacb0d69f | ||
|
|
28b139e1b8 | ||
|
|
39b1e0676b | ||
|
|
c05fc5bd36 | ||
|
|
bbae9157fb | ||
|
|
fc5c63a869 | ||
|
|
e2e068f8e5 | ||
|
|
43a068e30e | ||
|
|
2beb4b8c6f | ||
|
|
ad4230f7fa | ||
|
|
00369a2cfe | ||
|
|
248e487dd5 | ||
|
|
3a3dc02a66 | ||
|
|
f49c47c20d | ||
|
|
417ef1a7a4 | ||
|
|
8e8889483f | ||
|
|
b5818a9b62 | ||
|
|
e709f676dc | ||
|
|
bb611bf655 | ||
|
|
24e8ca67c5 | ||
|
|
0695941a77 | ||
|
|
7c71efd1b3 | ||
|
|
5099aff5c3 | ||
|
|
d3463250a9 | ||
|
|
3b58c02db0 | ||
|
|
64f0313d3c | ||
|
|
d3958e757b | ||
|
|
651020388d | ||
|
|
72ede666d4 | ||
|
|
a68c249d4e | ||
|
|
56caab4461 | ||
|
|
13b60351a6 | ||
|
|
ad49d38e46 | ||
|
|
082c9097e4 | ||
|
|
2fbdb29ebc | ||
|
|
ef34dce4dc | ||
|
|
577b7d8ec8 | ||
|
|
4ce099294c | ||
|
|
72bff7fa35 | ||
|
|
8c36b8803f | ||
|
|
c69993bd57 | ||
|
|
ea3e4982d2 | ||
|
|
9a5f6c7b9b | ||
|
|
033d56a4b3 | ||
|
|
dfa684cccc | ||
|
|
b4e0f43dfc | ||
|
|
783cf7f1b0 | ||
|
|
92d6fc3fad | ||
|
|
436cdea4fd | ||
|
|
6b144b3b1f | ||
|
|
7820082eb8 | ||
|
|
e732f921a3 | ||
|
|
8b7c5d8585 | ||
|
|
9e959b189c | ||
|
|
5c7a4cdc22 | ||
|
|
756e619e07 | ||
|
|
eea6194b90 | ||
|
|
a09c1fa154 | ||
|
|
38c742328c | ||
|
|
1d5db1446d | ||
|
|
3f5f3d143f | ||
|
|
d297a7198a | ||
|
|
e5bd99dee4 | ||
|
|
2720e13e88 | ||
|
|
0e9c1789ff | ||
|
|
281cb10f84 | ||
|
|
69a92ffe72 | ||
|
|
6447f159e5 | ||
|
|
94430883ad | ||
|
|
046512eb3d | ||
|
|
4479d97e90 | ||
|
|
bf5fea8951 | ||
|
|
07282e3de6 | ||
|
|
c2f90a20df | ||
|
|
481d2d699e | ||
|
|
cf9a7e6ed3 | ||
|
|
c35235371a | ||
|
|
5d5723ad58 | ||
|
|
6c77294a86 | ||
|
|
823f65f1ca | ||
|
|
0c378c1642 | ||
|
|
bbb4162867 | ||
|
|
5dbdde3f2b | ||
|
|
2521954bd9 | ||
|
|
5f1002894e | ||
|
|
0489b312a3 | ||
|
|
732be5a34f | ||
|
|
1f45c78ebb | ||
|
|
8b86c79bf9 | ||
|
|
710ed81067 | ||
|
|
24ac0e7b9b | ||
|
|
15b2bfbb29 | ||
|
|
b7494eb381 | ||
|
|
27ac590250 | ||
|
|
972076edab | ||
|
|
bfa9a1eb8a | ||
|
|
b0966f14e6 | ||
|
|
37cf0c2fb6 | ||
|
|
4eb11c32b0 | ||
|
|
25457bc09a | ||
|
|
d5cfb5f733 | ||
|
|
79ba6e628e | ||
|
|
ef73add05a | ||
|
|
ec3d11fb27 | ||
|
|
3fbc7031b5 | ||
|
|
40beb5e428 | ||
|
|
0f608c8ef0 | ||
|
|
8509cb4743 | ||
|
|
f4429e8c4a | ||
|
|
e9e0829cdc | ||
|
|
93f0230423 | ||
|
|
f26a0df4a4 | ||
|
|
c7d4624282 | ||
|
|
b03eee2a22 | ||
|
|
7d4d72e706 | ||
|
|
e3c367984b | ||
|
|
0ebfa10d32 | ||
|
|
16d9a077f0 | ||
|
|
a9d8bbad42 | ||
|
|
d78bb94af3 | ||
|
|
b139c0a824 | ||
|
|
5b0b924d34 | ||
|
|
f75acf820c | ||
|
|
43a47f33ac | ||
|
|
fcea3a0877 | ||
|
|
a950ec3bd5 | ||
|
|
e35501ff0a | ||
|
|
4bfad9dad8 | ||
|
|
c5c7a07c12 | ||
|
|
7e22e0e552 | ||
|
|
84ec4bdc79 | ||
|
|
2bcad9b637 | ||
|
|
c8d5f03070 | ||
|
|
168e101a5a | ||
|
|
b4bc7333d9 | ||
|
|
e8b58c940e | ||
|
|
ec7202e3f6 | ||
|
|
9a740f7962 | ||
|
|
9210fdee0d | ||
|
|
d7661f0964 | ||
|
|
139e148912 | ||
|
|
1b8dedb4ed | ||
|
|
5d6b0fa329 | ||
|
|
f35bbd89c9 | ||
|
|
538a9e42f4 | ||
|
|
623147dea7 | ||
|
|
dfecd0cd12 | ||
|
|
fe3af3a676 | ||
|
|
25f60331ed | ||
|
|
d4860a3426 | ||
|
|
e7e77ed86b | ||
|
|
dc80459c59 | ||
|
|
2f2de59234 | ||
|
|
7bccc21878 | ||
|
|
40f9dafa44 | ||
|
|
355d436d29 | ||
|
|
079b684388 | ||
|
|
fd11f46d30 | ||
|
|
cb7099199a | ||
|
|
8566d91e89 | ||
|
|
f44ce49ea7 | ||
|
|
6ef69f6b32 | ||
|
|
f5983d5f10 | ||
|
|
54cce5e089 | ||
|
|
4e4e596a1e | ||
|
|
727a1f5ad1 | ||
|
|
85fa86625b | ||
|
|
2c91877f83 | ||
|
|
7d1fac44e9 | ||
|
|
2e34abfc0d | ||
|
|
81ba63e247 | ||
|
|
8b11a65522 | ||
|
|
7190ad1d15 | ||
|
|
1c9bae5df5 | ||
|
|
cc7fd73916 | ||
|
|
6d8725f268 | ||
|
|
373c7cdbc4 | ||
|
|
a4855bb33b | ||
|
|
57c1358ded | ||
|
|
eb4ce1feab | ||
|
|
838c17e144 | ||
|
|
4499cbca3c | ||
|
|
a835a4a2f7 | ||
|
|
9cc6a94353 | ||
|
|
5ed9d9c4a0 | ||
|
|
9c5ac7080d | ||
|
|
6346370e86 | ||
|
|
80697f8f30 | ||
|
|
18b8b56367 | ||
|
|
760aacca26 | ||
|
|
1a4f0dcf5a | ||
|
|
947484a71c | ||
|
|
a74439d038 | ||
|
|
c338618593 | ||
|
|
011897da53 | ||
|
|
3fcaa58947 | ||
|
|
ef8bd4362a | ||
|
|
627a2ef6dd | ||
|
|
2732536d6e | ||
|
|
5a1b4b3ff8 | ||
|
|
d93ec82e4f | ||
|
|
15080972f3 | ||
|
|
171b58f737 | ||
|
|
c008ab6141 | ||
|
|
f14c3654dc | ||
|
|
ae05a61551 | ||
|
|
8e1def225b | ||
|
|
6e061764ee | ||
|
|
ac55b22839 | ||
|
|
49f77d3b75 | ||
|
|
4abc650edf | ||
|
|
5ba00b61be | ||
|
|
bc16a6c4cb | ||
|
|
ea4dc6f040 | ||
|
|
749ae8d5eb | ||
|
|
7a56ffb7c3 | ||
|
|
e62ab23de2 | ||
|
|
c6f6118506 | ||
|
|
8a5d5ad952 | ||
|
|
49e2615d14 | ||
|
|
9289394261 | ||
|
|
8da4c88fd3 | ||
|
|
a303850341 | ||
|
|
fb33610672 | ||
|
|
d024dd6563 | ||
|
|
0be48f9f59 | ||
|
|
df9292bafe | ||
|
|
c1dcef3477 | ||
|
|
48bc1f8361 | ||
|
|
2b2b4dbcf4 | ||
|
|
a1eadecdef | ||
|
|
f0b529952d | ||
|
|
c1ac2debb8 | ||
|
|
ac40094d37 | ||
|
|
cb2bb4cb67 | ||
|
|
f2965940cc | ||
|
|
c9ca147898 | ||
|
|
c379d7f846 | ||
|
|
45ae1ed265 | ||
|
|
9bf00eff40 | ||
|
|
1677b3d5b9 | ||
|
|
2a6806004a | ||
|
|
39347d69df | ||
|
|
a2c0e4d4b1 | ||
|
|
ab2ffd9ac1 | ||
|
|
c69fff52cc | ||
|
|
1cfe61dc72 | ||
|
|
a23f39d81e | ||
|
|
b7724ff583 | ||
|
|
e5dba60fab | ||
|
|
2ccf489a83 | ||
|
|
068939ca0b | ||
|
|
94ba8614ec | ||
|
|
f12a0c2379 | ||
|
|
8ab257645b | ||
|
|
6331a0615f | ||
|
|
a21855fa20 | ||
|
|
12150c2180 | ||
|
|
d90aecb164 | ||
|
|
e738f2bc9f | ||
|
|
2f72c41cda | ||
|
|
aa43d42cdb | ||
|
|
be8228e33c | ||
|
|
5591472dbd | ||
|
|
30e6ced4e9 | ||
|
|
5f4c2bae89 | ||
|
|
0f036d9a43 | ||
|
|
1695ac3a32 | ||
|
|
07a19ba619 | ||
|
|
4dd78d89a0 | ||
|
|
8f4056faa6 | ||
|
|
7b40c33892 | ||
|
|
b06bb5142f | ||
|
|
d576156ee1 | ||
|
|
77079968a5 | ||
|
|
e12aca6214 | ||
|
|
2a72891f28 | ||
|
|
6fe47e78f1 | ||
|
|
0094894b52 | ||
|
|
0951bfb7ac | ||
|
|
60e8519b65 | ||
|
|
78df0ed707 | ||
|
|
e3da0d6c9f | ||
|
|
5df30580a6 | ||
|
|
4816b7dcd8 | ||
|
|
75bced198b | ||
|
|
b500813617 | ||
|
|
a80037f7fc | ||
|
|
1a6345342f | ||
|
|
21b2193cd0 | ||
|
|
3efc496c41 | ||
|
|
16340fbb78 | ||
|
|
a858b28bc4 | ||
|
|
307961cc7e | ||
|
|
3074377b55 | ||
|
|
5a3edc00ac | ||
|
|
5a5f50e1e4 | ||
|
|
7f39a38d6c | ||
|
|
8321a48af7 | ||
|
|
7e613f032e | ||
|
|
1c38c39db2 | ||
|
|
4a0235c2ed | ||
|
|
b92961fda0 | ||
|
|
a2a06be62f | ||
|
|
c0956ed3b0 | ||
|
|
3705e4e4d4 | ||
|
|
3fdbe84573 | ||
|
|
fb8e7d803f | ||
|
|
b01821aa03 | ||
|
|
69f974c9d0 | ||
|
|
5db8b743fe | ||
|
|
c424b0c888 | ||
|
|
d035c7d3b8 | ||
|
|
144ffbc428 | ||
|
|
afa8486d40 | ||
|
|
a4cd42c448 | ||
|
|
853f4b75fa | ||
|
|
b95612287f | ||
|
|
64e779172c | ||
|
|
10a136b4a3 | ||
|
|
ddc3af28ab | ||
|
|
f602948dcf | ||
|
|
973229cf4e | ||
|
|
d1f5cbea4a | ||
|
|
49fe670ddb | ||
|
|
d6d87675c9 | ||
|
|
1ca1927904 | ||
|
|
454c3d1a3c | ||
|
|
11f5004112 | ||
|
|
625343f698 | ||
|
|
89d96a3ec1 | ||
|
|
c4c47fa196 | ||
|
|
ca35894b82 | ||
|
|
0213b6556b | ||
|
|
4edfd9be30 | ||
|
|
e55d9cafb6 | ||
|
|
8deb0ed556 | ||
|
|
82f995f243 | ||
|
|
b41c2ca724 | ||
|
|
06ddbaf2cc | ||
|
|
2adbfe1fbd | ||
|
|
7ae049b559 | ||
|
|
72913ceb1a | ||
|
|
6a2be22fa1 | ||
|
|
eaf20ce8d2 | ||
|
|
97f9e142b4 | ||
|
|
2e0f7b367f | ||
|
|
7312e3f452 | ||
|
|
8faa9f075b | ||
|
|
584dcae075 | ||
|
|
910e869b8d | ||
|
|
469e00b396 | ||
|
|
ec46c758ba | ||
|
|
8970e46bce | ||
|
|
3a4107d903 | ||
|
|
52ee21d550 | ||
|
|
cdda4826cb | ||
|
|
6745df5041 | ||
|
|
3d3efe1117 | ||
|
|
82e5ae05ce | ||
|
|
0dbdd55a6a | ||
|
|
424b0e61cb | ||
|
|
533da8f89c | ||
|
|
31506662db | ||
|
|
7ff1a88ca8 | ||
|
|
1851f26e3f | ||
|
|
84cd65dd6c | ||
|
|
8e0d792bf0 | ||
|
|
e74548b991 | ||
|
|
2356ff5ebb | ||
|
|
691f5d99ca | ||
|
|
ab7b65a30b | ||
|
|
814bb3006c | ||
|
|
4bd4d3ae03 | ||
|
|
af1b0ace19 | ||
|
|
fb54febe03 | ||
|
|
28faae5a4a | ||
|
|
624a920aec | ||
|
|
2bf8187bff | ||
|
|
cf06bf91e3 | ||
|
|
e96f0504c0 | ||
|
|
5fd61725bd | ||
|
|
3fddfa075b | ||
|
|
d712e5c409 | ||
|
|
6287afae6c | ||
|
|
925540055a | ||
|
|
d4373aae93 | ||
|
|
c4be310081 | ||
|
|
d1aa276465 | ||
|
|
2af6fc7452 | ||
|
|
ed15394a96 | ||
|
|
3791d11162 | ||
|
|
032ddabc06 | ||
|
|
bfb93ac6ed | ||
|
|
f6d889d752 | ||
|
|
a7053f4269 | ||
|
|
233a6d06be | ||
|
|
853224148f | ||
|
|
c5c8c27b2e | ||
|
|
d352d5fcff | ||
|
|
0003de9320 | ||
|
|
04f43e77af | ||
|
|
be7cc55488 | ||
|
|
c8f3379a48 | ||
|
|
b5a7945e49 | ||
|
|
0bdac2e97d | ||
|
|
1468a821fb | ||
|
|
3cdc8dc4b6 | ||
|
|
aa255aa7e6 | ||
|
|
66e5ccb9cc | ||
|
|
2215f300bf | ||
|
|
eec767406b | ||
|
|
31aa42c2fa | ||
|
|
e912c59402 | ||
|
|
c9988976f3 | ||
|
|
443be1c2c8 | ||
|
|
7f442cff3b | ||
|
|
3696ae44ad | ||
|
|
fc2d601424 | ||
|
|
8818f24114 | ||
|
|
0e12c8249e | ||
|
|
06d62a70a9 | ||
|
|
76d8018ca2 | ||
|
|
4123b41a5e | ||
|
|
5930257fed | ||
|
|
d3d60327ab | ||
|
|
5080ffb9fc | ||
|
|
9b688a5179 | ||
|
|
a603dc5227 | ||
|
|
c25f682caf | ||
|
|
27a2fd298d | ||
|
|
bb38053cb3 | ||
|
|
5e82ee8695 | ||
|
|
6c691ff9a8 | ||
|
|
ac5a14fe4a | ||
|
|
00402d13ef | ||
|
|
079a559247 | ||
|
|
a19ea8fdba | ||
|
|
c6e172f942 | ||
|
|
bdc9f3e8bf | ||
|
|
8ec5a587fc | ||
|
|
9caf46f2fb | ||
|
|
13fdbfc5e8 | ||
|
|
882c94110e | ||
|
|
97bc980611 | ||
|
|
be9bf5c173 | ||
|
|
6df38c389c | ||
|
|
6c6bceb8cc | ||
|
|
b5a897bb4d | ||
|
|
ab85b716bb | ||
|
|
8e256e6d5c | ||
|
|
288036a63b | ||
|
|
f2005c3343 | ||
|
|
79d516b899 | ||
|
|
28b2f6eae3 | ||
|
|
09ed2b945c | ||
|
|
74aec89ef0 | ||
|
|
4faa23d099 | ||
|
|
5c4997ab20 | ||
|
|
cd490ca946 | ||
|
|
793f6b00e6 | ||
|
|
c1ec568fda | ||
|
|
4e2b52975e | ||
|
|
c141df6b86 | ||
|
|
63b781765a | ||
|
|
c121e141e7 | ||
|
|
7544c9a9f5 | ||
|
|
722a088515 | ||
|
|
0ce75bff58 | ||
|
|
3744b6d3de | ||
|
|
a4ebd91e8d | ||
|
|
3bb0ee916d | ||
|
|
fd6afdf5f3 | ||
|
|
47c13a840e | ||
|
|
5b61992b3c | ||
|
|
36331dc253 | ||
|
|
4265cf31b2 | ||
|
|
337e47269f | ||
|
|
7039234471 | ||
|
|
f7f9333d91 | ||
|
|
bf35665932 | ||
|
|
089a2271c2 | ||
|
|
f8e83e3631 | ||
|
|
46fd329913 | ||
|
|
6b9ba96e77 | ||
|
|
b7d360d850 | ||
|
|
8e226302ab | ||
|
|
7795b9edaf | ||
|
|
9375d9699a | ||
|
|
cf0442d5b8 | ||
|
|
b386ca14df | ||
|
|
ea47fae31e | ||
|
|
e0fed07b10 | ||
|
|
779d5ff7b6 | ||
|
|
eb6fbd03ec | ||
|
|
95409d1b0e | ||
|
|
49599c8731 | ||
|
|
572f94e000 | ||
|
|
c0a2ad5f50 | ||
|
|
71fa5acc74 | ||
|
|
bac5b7679d | ||
|
|
93ade821a5 | ||
|
|
a718e19979 | ||
|
|
8ac83a46f5 | ||
|
|
1b65dcd7df | ||
|
|
bbad45f1e7 | ||
|
|
331b9cca18 | ||
|
|
a9accb7d85 | ||
|
|
1862e70628 | ||
|
|
c4f7054ca6 | ||
|
|
175e568a28 | ||
|
|
c8d580e7de | ||
|
|
bc0c50ee65 | ||
|
|
45e9dd96d1 | ||
|
|
1cc73562a3 | ||
|
|
d870ef0bd5 | ||
|
|
53d308dac5 | ||
|
|
89b06ae7c7 | ||
|
|
d38485a8ad | ||
|
|
834877c503 | ||
|
|
d033b79af4 | ||
|
|
daec2cc203 | ||
|
|
4e593cebab | ||
|
|
73d7701e94 | ||
|
|
24f1d7a72f | ||
|
|
6387a01d7b | ||
|
|
e838840548 | ||
|
|
6a430b441e | ||
|
|
7b977ea839 | ||
|
|
62b8521cbe | ||
|
|
308244d901 | ||
|
|
6f521183f9 | ||
|
|
76c6f7e733 | ||
|
|
80ebfbeb6b | ||
|
|
793901b319 | ||
|
|
3950df8ec9 | ||
|
|
e800b236aa | ||
|
|
4ab7871106 | ||
|
|
3de85549b6 | ||
|
|
73164f7182 | ||
|
|
004b000890 | ||
|
|
d9c703d944 | ||
|
|
364b650033 | ||
|
|
156eb874db | ||
|
|
1a28dd0311 | ||
|
|
e29b4b8609 | ||
|
|
c02997e6d9 | ||
|
|
7c9fc91af9 | ||
|
|
cf5198ac64 | ||
|
|
e76ddd6dd2 | ||
|
|
e3a4cf1cf5 | ||
|
|
5844616ea8 | ||
|
|
abeb580228 | ||
|
|
4d888dfce8 | ||
|
|
08ff6f0ede | ||
|
|
c458c27231 | ||
|
|
9821b70c38 | ||
|
|
8ab8401110 | ||
|
|
4f798c85cf | ||
|
|
1949bdb43f | ||
|
|
8cf2e6b31b | ||
|
|
b1069f9f18 | ||
|
|
fb8dfa9ae9 | ||
|
|
4402a56e94 | ||
|
|
f449808ba3 | ||
|
|
5599739433 | ||
|
|
197cf85f56 | ||
|
|
8c039c9c8b | ||
|
|
c1d9bc046d | ||
|
|
cd99fac7ed | ||
|
|
f4489e6807 | ||
|
|
f2078271b6 | ||
|
|
a3ae9acebb | ||
|
|
b0580265ca | ||
|
|
b4f012392a | ||
|
|
1598809f55 | ||
|
|
6d4f7aa61f | ||
|
|
382080ae4e | ||
|
|
66ac529bca | ||
|
|
ab72207027 | ||
|
|
e3aebf1ca2 | ||
|
|
0e5820c038 | ||
|
|
780e4d34df | ||
|
|
a8700572b7 | ||
|
|
055516312a | ||
|
|
76b4a6585e | ||
|
|
b57535c5ad | ||
|
|
eb10a15eee | ||
|
|
30ed362a8c | ||
|
|
34f071ed1d | ||
|
|
3d3d641e1c | ||
|
|
10c11f2c3d | ||
|
|
cec2745dc0 | ||
|
|
8d15edb063 | ||
|
|
38cf3dc141 | ||
|
|
c146290e07 | ||
|
|
a1745289be | ||
|
|
5a7dbfc87a | ||
|
|
f645950a8f | ||
|
|
b273da0b5e | ||
|
|
689f1eb0c5 | ||
|
|
b0a2edf5fa | ||
|
|
e7b5e02657 | ||
|
|
2d4efd6cf0 | ||
|
|
defc0ada78 | ||
|
|
2f3f4f609c | ||
|
|
4a9c9f8cd4 | ||
|
|
bdc089290d | ||
|
|
cf9f48d8da | ||
|
|
2d67279180 | ||
|
|
83e10aac27 | ||
|
|
9972124aa1 | ||
|
|
d0eb1ba96e | ||
|
|
f5d2910638 | ||
|
|
1cafaf3a79 | ||
|
|
fccc133cb2 | ||
|
|
9fb50b8a73 | ||
|
|
c66c1e17d3 | ||
|
|
4496760340 | ||
|
|
506200d2ee | ||
|
|
04898a3b01 | ||
|
|
f67fb53308 | ||
|
|
c5b78dde04 | ||
|
|
57d9c87de6 | ||
|
|
795f95d855 | ||
|
|
c0ebbc8e2f | ||
|
|
fb377c32ea | ||
|
|
e13faff2d7 | ||
|
|
b0c5348116 | ||
|
|
b462ec022a | ||
|
|
e45a0bf24b | ||
|
|
8962644ba8 | ||
|
|
ad5e04bbcc | ||
|
|
6fc7baec39 | ||
|
|
acd49a9c40 | ||
|
|
bf04358a47 | ||
|
|
b7e13c7b86 | ||
|
|
9b45f0661e | ||
|
|
2a61b1202b | ||
|
|
114f862ea4 | ||
|
|
5a490a8b5a | ||
|
|
8fdc1c1b21 | ||
|
|
32cac90720 | ||
|
|
b2160255d3 | ||
|
|
7fe1f4de93 | ||
|
|
1fbb1b1524 | ||
|
|
0105a53765 | ||
|
|
bd5ab80276 | ||
|
|
387d790228 | ||
|
|
d199a2be0d | ||
|
|
f81ecffda6 | ||
|
|
882f80de1e | ||
|
|
4359f2a0ce | ||
|
|
9c485c4d94 | ||
|
|
1330197036 | ||
|
|
0b0d5fa227 | ||
|
|
45424b8a52 | ||
|
|
0956acbdfb | ||
|
|
654f553d8f | ||
|
|
e4b6e20db6 | ||
|
|
b4f6c6f869 | ||
|
|
16edc52bae | ||
|
|
a33e6c03e4 | ||
|
|
4dccb40bf9 | ||
|
|
9ce1981f93 | ||
|
|
6374c77aa8 | ||
|
|
871bb391d6 | ||
|
|
c3903a7b35 | ||
|
|
6aabf82c11 | ||
|
|
89b624aadf | ||
|
|
67317292ee | ||
|
|
42e7f64856 | ||
|
|
79d963fd65 | ||
|
|
44649fd950 | ||
|
|
0e97f99f93 | ||
|
|
4f52ceb3e0 | ||
|
|
61253b5551 | ||
|
|
12bd6f0d9b | ||
|
|
a32010e03b | ||
|
|
4a934c9dab | ||
|
|
20766c1feb | ||
|
|
6cd4de548f | ||
|
|
8ac4dea8f1 | ||
|
|
e8af3e8d3c | ||
|
|
cd05b10168 | ||
|
|
140935bd8c | ||
|
|
ecb122d93c | ||
|
|
c6e08e0039 | ||
|
|
be1e14df81 | ||
|
|
28bca261fb | ||
|
|
2ab5bc1ad2 | ||
|
|
10c57cf6da | ||
|
|
e65c5eeab1 | ||
|
|
85fad35dc2 | ||
|
|
c992768efe | ||
|
|
7b13c0d059 | ||
|
|
2d3f41da6f | ||
|
|
43b9941dc8 | ||
|
|
dcf27f54aa | ||
|
|
fbf6b69e75 | ||
|
|
0bfebd90da | ||
|
|
e7c3dafa36 | ||
|
|
e90a36da79 | ||
|
|
93f33615ad | ||
|
|
99569081c9 | ||
|
|
588a0b3c41 | ||
|
|
4a1118ceb3 | ||
|
|
a65415bc10 | ||
|
|
8a0e66bf11 | ||
|
|
02cda47c28 | ||
|
|
d34a323a81 | ||
|
|
4166ae8db0 | ||
|
|
955b906b52 | ||
|
|
0d424aa81e | ||
|
|
80acbfa56a | ||
|
|
a7cac24004 | ||
|
|
2927bcf09d | ||
|
|
08dee6bb4f | ||
|
|
08c92f906a | ||
|
|
8e9c9802d1 | ||
|
|
138df66d5e | ||
|
|
0a71347e9a | ||
|
|
2a541a7b9c | ||
|
|
705c12e8da | ||
|
|
cf33df1339 | ||
|
|
87e543b5ef | ||
|
|
81caec99b7 | ||
|
|
41484f8673 | ||
|
|
da0d61f36a | ||
|
|
6f3bc74db0 | ||
|
|
af3bd6ec2f | ||
|
|
b5eb13449b | ||
|
|
bd78e8c275 | ||
|
|
2df21081a1 | ||
|
|
ffebff4ea9 | ||
|
|
2885bc99ca | ||
|
|
2657b80adb | ||
|
|
ebfc106701 | ||
|
|
4d60ca951d | ||
|
|
acf5c57599 | ||
|
|
927df5ff39 | ||
|
|
31fc031267 | ||
|
|
02794e0ebd | ||
|
|
ea6cce7068 | ||
|
|
e4cefeaa8f | ||
|
|
d12d5fd8ae | ||
|
|
0617c3fdc0 | ||
|
|
f00eedf57e | ||
|
|
6d36ae6197 | ||
|
|
45125abb8f | ||
|
|
045b0cd075 | ||
|
|
ff3333e1bf | ||
|
|
7663c5e149 | ||
|
|
4d4748a0a8 | ||
|
|
f8f84ed09e | ||
|
|
e7de7ebbfa | ||
|
|
c9f01f4bc4 | ||
|
|
f2675adc05 | ||
|
|
75beaa3684 | ||
|
|
079495cc32 | ||
|
|
c8bd89e56f | ||
|
|
b089ba2e04 | ||
|
|
adbf8495c6 | ||
|
|
ad062862d8 | ||
|
|
3a86a93154 | ||
|
|
dcf0d6f72d | ||
|
|
83d3725240 | ||
|
|
ce1dd69557 | ||
|
|
4081bdd752 | ||
|
|
c3f1e312b3 | ||
|
|
d820878b89 | ||
|
|
7fa1461d5e | ||
|
|
f4b1ef4d04 | ||
|
|
656130a739 | ||
|
|
aa8679dff5 | ||
|
|
f94a3095fd | ||
|
|
e11958dd58 | ||
|
|
a5a251a964 | ||
|
|
8cb1015a35 | ||
|
|
b5dd90b2d5 | ||
|
|
5f7efee00e | ||
|
|
4150e3efde | ||
|
|
8ebcb71e6e | ||
|
|
f3e852c042 | ||
|
|
5e2a07d144 | ||
|
|
25f6231e9d | ||
|
|
beeba88ea5 | ||
|
|
cc3d454d60 | ||
|
|
afb583cff4 | ||
|
|
561fa66393 | ||
|
|
870dc0d36f | ||
|
|
51462dee1e | ||
|
|
c752d28c6a | ||
|
|
d5ca0ca283 | ||
|
|
f371b3a338 | ||
|
|
93fc4a2c86 | ||
|
|
f10d3f86cc | ||
|
|
af17b0015b | ||
|
|
61af1d1c72 | ||
|
|
65780e1672 | ||
|
|
c92a7967ea | ||
|
|
60aed593b3 | ||
|
|
044f347729 | ||
|
|
aec9df1882 | ||
|
|
4f0a2515f8 | ||
|
|
5cde33711e | ||
|
|
64750025f6 | ||
|
|
cd1cbfdffe | ||
|
|
d413f2c3a7 | ||
|
|
ba314dd734 | ||
|
|
9105b7615c | ||
|
|
a9c162476c | ||
|
|
732b37aca0 | ||
|
|
291b5fad7f | ||
|
|
c2a6def8b9 | ||
|
|
9083c578cc | ||
|
|
bcfd1d39bb | ||
|
|
1185b910c4 | ||
|
|
540b6eba04 | ||
|
|
47f4287e64 | ||
|
|
264c6e259b | ||
|
|
0bbe9838c4 | ||
|
|
2fe337eac3 | ||
|
|
5d7caafdf7 | ||
|
|
f416ef925b | ||
|
|
60bd90848b | ||
|
|
b9f4407815 | ||
|
|
f9cd2639ff | ||
|
|
aeb36e8665 | ||
|
|
057482a3e5 | ||
|
|
15721da46e | ||
|
|
f12b82b5ce | ||
|
|
10dc725942 | ||
|
|
5bd5cdf435 | ||
|
|
84b3603c08 | ||
|
|
8f59b96731 | ||
|
|
e1de110dd7 | ||
|
|
8b6fd3d594 | ||
|
|
d7761e8d79 | ||
|
|
751d652a2f | ||
|
|
647e7e708a | ||
|
|
505c0eeae2 | ||
|
|
bf4001968e | ||
|
|
9d222e2c57 | ||
|
|
033300d659 | ||
|
|
4f2b04bd8f | ||
|
|
f8b9bb4b0f | ||
|
|
8ce8e320c3 | ||
|
|
7c0ab4212b | ||
|
|
26633e0982 | ||
|
|
d27a3f1f33 | ||
|
|
89252d0dba | ||
|
|
dbd2edf442 | ||
|
|
dabd6f8284 | ||
|
|
beb3ab463f | ||
|
|
1d67b623e0 | ||
|
|
2c8cde4d91 | ||
|
|
8cc1d48115 | ||
|
|
ec2468fb8d | ||
|
|
7b54cef23b | ||
|
|
a9da8811fc | ||
|
|
60e86b9881 | ||
|
|
a6766f3c99 | ||
|
|
e59c3c6f70 | ||
|
|
49aa344d8b | ||
|
|
4fed6ab298 | ||
|
|
58eab4d3bc | ||
|
|
5ef5da687d | ||
|
|
4875d319dc | ||
|
|
fb5a53435e | ||
|
|
4f805d65b3 | ||
|
|
56ffb0deb1 | ||
|
|
c0c1457073 | ||
|
|
85a0748ad9 | ||
|
|
c1939a36dd | ||
|
|
b7c394b7a5 | ||
|
|
a070681f89 | ||
|
|
d5e424eec8 | ||
|
|
e0366d38f1 | ||
|
|
cbf1d96b16 | ||
|
|
7cc0d6bb5a | ||
|
|
e19b840ee6 | ||
|
|
5c2ca1e3d9 | ||
|
|
059c4beb30 | ||
|
|
427808226f | ||
|
|
5448245942 | ||
|
|
34ab907007 | ||
|
|
e5fde27859 | ||
|
|
699e8e3ddb | ||
|
|
28ee967371 | ||
|
|
1b0b5f2554 | ||
|
|
1bcc86f989 | ||
|
|
f26f932fd7 | ||
|
|
2b7d48ce77 | ||
|
|
111712fd6d | ||
|
|
7609bc181e | ||
|
|
8b05af7ca3 | ||
|
|
20f9108ebf | ||
|
|
cecae7cdc3 | ||
|
|
e5f3123567 | ||
|
|
27b0e27cfd | ||
|
|
890fba0f61 | ||
|
|
c4b732ff93 | ||
|
|
b8fa2985d5 | ||
|
|
ba741fbce8 | ||
|
|
67d070c334 | ||
|
|
8576afe6f5 | ||
|
|
36807fd376 | ||
|
|
2ad1d27a59 | ||
|
|
7cc9c75d15 | ||
|
|
f33609bbf8 | ||
|
|
69eeb4b0f8 | ||
|
|
aa583ec1aa | ||
|
|
2b9f153257 | ||
|
|
cb9b7fc917 | ||
|
|
74b36c8884 | ||
|
|
89ff7d6dae | ||
|
|
91df420cb4 | ||
|
|
fc25c9f0bc | ||
|
|
12a27e3a8d | ||
|
|
125e32ff00 | ||
|
|
4a110633e8 | ||
|
|
65648f8abd | ||
|
|
50174861dc | ||
|
|
486eb1722e | ||
|
|
740ead4059 | ||
|
|
96424be0da | ||
|
|
cd9d659672 | ||
|
|
ca140388d9 | ||
|
|
8fe0229a2c | ||
|
|
1f43de9458 | ||
|
|
2793f38c2d | ||
|
|
42de7de21d | ||
|
|
1072dc0a41 | ||
|
|
9d8f310e30 | ||
|
|
170adfd00c | ||
|
|
d0135a5ff7 | ||
|
|
1c926cca45 | ||
|
|
ace8ecbb4e | ||
|
|
193fa176dc | ||
|
|
054db62cfa | ||
|
|
fe549cf4c5 | ||
|
|
d347e49b6a | ||
|
|
d6a3f7b329 | ||
|
|
4171bc4c70 | ||
|
|
deca5e5021 | ||
|
|
e0923a0494 | ||
|
|
0a1dfeb860 | ||
|
|
1c911575fa | ||
|
|
d2ef0a996f | ||
|
|
1e886cb12c | ||
|
|
984abc89a8 | ||
|
|
3c6c9741ff | ||
|
|
247a11146c | ||
|
|
d1108c533f | ||
|
|
881339848f | ||
|
|
c44638dcbe | ||
|
|
4887b85b8a | ||
|
|
239f58e290 | ||
|
|
560000f69d | ||
|
|
2d3509ae56 | ||
|
|
4cc926a627 | ||
|
|
a499a70633 | ||
|
|
60a9154326 | ||
|
|
f761b8d4e1 | ||
|
|
7a0f6684e5 | ||
|
|
3ed6817ac9 | ||
|
|
ba76385a2f | ||
|
|
7bcd5ba14c | ||
|
|
40db9f7020 | ||
|
|
dffc46551e | ||
|
|
cf92852bb3 | ||
|
|
844c4a28f4 | ||
|
|
d2fc5a6228 | ||
|
|
006da837aa | ||
|
|
d920e27ab3 | ||
|
|
27bafa8ab2 | ||
|
|
907d18a83a | ||
|
|
37b923bea3 | ||
|
|
91e597bbdd | ||
|
|
a0d697bf6f | ||
|
|
63d5018ad6 | ||
|
|
ca928bdacb | ||
|
|
f7e7791b8b | ||
|
|
80c2e5b141 | ||
|
|
63c171e3b4 | ||
|
|
b0bfb0fdd4 | ||
|
|
31b24d9a09 | ||
|
|
8b04a3b16a | ||
|
|
b88d35d7cb | ||
|
|
e00dcf1af0 | ||
|
|
7f23b9b424 | ||
|
|
e9bf04031b | ||
|
|
c8f2334003 | ||
|
|
380b84195f | ||
|
|
fd26137ad2 | ||
|
|
1ad163aac3 | ||
|
|
36dccc8157 | ||
|
|
6dcdf5bf92 | ||
|
|
0b460017b8 | ||
|
|
061b06cd08 | ||
|
|
86272e1788 | ||
|
|
86f3e011d8 | ||
|
|
0367c5bd1c | ||
|
|
eed008de4b | ||
|
|
74f713ee35 | ||
|
|
6dbb8751b2 | ||
|
|
368bb54870 | ||
|
|
77903a5ecd | ||
|
|
9be161d165 | ||
|
|
0ce5b50950 | ||
|
|
9dded5203e | ||
|
|
d1c2188e5c | ||
|
|
c4285a14b2 | ||
|
|
cf0a47e836 | ||
|
|
c38639afcb | ||
|
|
5863593c65 | ||
|
|
c2fa7f9a57 | ||
|
|
41f5cf6bee | ||
|
|
ea508e9c35 | ||
|
|
5ebf7cd273 | ||
|
|
9986088dc4 | ||
|
|
bfe0b2c634 | ||
|
|
cd2af6974c | ||
|
|
c452486573 | ||
|
|
79406b20f2 | ||
|
|
1226bc214d | ||
|
|
7da79dabdf | ||
|
|
b51026a2ee | ||
|
|
67d01f48a3 | ||
|
|
9fd5c5fc1c | ||
|
|
70bc5b83fa | ||
|
|
b380db51fa | ||
|
|
fab598ebff | ||
|
|
6f6d087fa2 | ||
|
|
6e463d1de3 | ||
|
|
21970f3065 | ||
|
|
9d7e44be2d | ||
|
|
9085fb8285 | ||
|
|
dd79d089f6 | ||
|
|
7aaad124d0 | ||
|
|
0025cb9f53 | ||
|
|
15c8f2a3ee | ||
|
|
fc1a2dac90 | ||
|
|
f698b860f7 | ||
|
|
86b057a301 | ||
|
|
b066158a4b | ||
|
|
046c822604 | ||
|
|
d427733bfc | ||
|
|
04d34a06c7 | ||
|
|
69d86513ae | ||
|
|
019b49a219 | ||
|
|
d9e787784a | ||
|
|
71969b88e3 | ||
|
|
7ae0f5e246 | ||
|
|
1ea7da4bb5 | ||
|
|
8b96bb5f27 | ||
|
|
aefce3ccd0 | ||
|
|
4e599e2aba | ||
|
|
4148c289af | ||
|
|
d575ab0b2b | ||
|
|
d09af19d3f | ||
|
|
a2dff17db9 | ||
|
|
c0fecb935f | ||
|
|
28249b7e99 | ||
|
|
eb63e2257f | ||
|
|
2211716d04 | ||
|
|
242137a50c | ||
|
|
c41311bf76 | ||
|
|
e0d959e3c5 | ||
|
|
f0a5c4b2c2 | ||
|
|
e10a50fdc1 | ||
|
|
380f2509ac | ||
|
|
c0fb35f6b9 | ||
|
|
3e658845d2 | ||
|
|
384209ba70 | ||
|
|
835b589894 | ||
|
|
76e684ee75 | ||
|
|
d0d2c83768 | ||
|
|
b476bc3168 | ||
|
|
5a2ad145e8 | ||
|
|
27233d2549 | ||
|
|
1a0bc75629 | ||
|
|
dc04961699 | ||
|
|
e594cf299e | ||
|
|
096c995a91 | ||
|
|
f64b175cd8 | ||
|
|
954e0e8a59 | ||
|
|
034b032cfa | ||
|
|
e33590bff9 | ||
|
|
55f610f3b2 | ||
|
|
87fd93a1cf | ||
|
|
2db77a248a | ||
|
|
f600274592 | ||
|
|
bc37d00a81 | ||
|
|
1956ea95ee | ||
|
|
a56e3b91e1 | ||
|
|
6bcc9d61e1 | ||
|
|
3ef34191a3 | ||
|
|
60de36aff9 | ||
|
|
b019dd1c51 | ||
|
|
3a083d5527 | ||
|
|
8006241a81 | ||
|
|
b05e3d24ee | ||
|
|
b78c0a4979 | ||
|
|
d3b3c309fa | ||
|
|
65615495d9 | ||
|
|
35f448c34f | ||
|
|
e1abd28a88 | ||
|
|
a109d8be64 | ||
|
|
333a0bc05a | ||
|
|
a831519b54 | ||
|
|
a25052ed96 | ||
|
|
676f8dc8be | ||
|
|
9c3cb82fca | ||
|
|
9b827f58ad | ||
|
|
22e327d391 | ||
|
|
451de4d72d | ||
|
|
0679b78c1d | ||
|
|
ad7084b897 | ||
|
|
3c068eaba9 | ||
|
|
819ae08c6a | ||
|
|
38414ad8de | ||
|
|
f0422f7634 | ||
|
|
2a004dadf3 | ||
|
|
b7ea586e44 | ||
|
|
2a5f286d07 | ||
|
|
0bc14671ec | ||
|
|
1a8fe18b8e | ||
|
|
4599b4a9cc | ||
|
|
6ab6ab56dd | ||
|
|
59f5dc21ac | ||
|
|
8f316db49c | ||
|
|
4c2f28311c | ||
|
|
6ae022fbec | ||
|
|
cfbb0f8fc0 | ||
|
|
3ad2c2ad6a | ||
|
|
1ce553fb65 | ||
|
|
ec5ec83edc | ||
|
|
18087fd797 | ||
|
|
f90de75e3a | ||
|
|
3241815a11 | ||
|
|
db3f8d3b83 | ||
|
|
9983dc3138 | ||
|
|
ad141c165b | ||
|
|
93b252b9e7 | ||
|
|
42e245e334 | ||
|
|
cb844084e8 | ||
|
|
3483736490 | ||
|
|
119a75588e | ||
|
|
2f42242305 | ||
|
|
4990f44b10 | ||
|
|
85eba24167 | ||
|
|
ce4be75803 | ||
|
|
706529248a | ||
|
|
79f50f5343 | ||
|
|
7437c208ff | ||
|
|
b838893e88 | ||
|
|
41e2a75675 | ||
|
|
ad5e366aad | ||
|
|
b35c641df6 | ||
|
|
22c476d507 | ||
|
|
8f9b1d708b | ||
|
|
9ce8b60cd2 | ||
|
|
9401ad2ba3 | ||
|
|
128b6c7ce9 | ||
|
|
04d509f6eb | ||
|
|
c91cef3507 | ||
|
|
a9304a840f | ||
|
|
3ba500b589 | ||
|
|
cc6a1ad63b | ||
|
|
a4120d3d3e | ||
|
|
494ab68dd2 | ||
|
|
708dd12243 | ||
|
|
49601423cf | ||
|
|
928aebd439 | ||
|
|
97717929dd | ||
|
|
c94f9073f8 | ||
|
|
5746ee74cf | ||
|
|
970dcaf0fd | ||
|
|
87c2007352 | ||
|
|
d53de00e2a | ||
|
|
513aafca16 | ||
|
|
1d35923f0c | ||
|
|
4de61e79fb | ||
|
|
b2fe64ed34 | ||
|
|
411cb27ead | ||
|
|
696dc0051e | ||
|
|
c0e1a9a359 | ||
|
|
b73f90c44d | ||
|
|
aeb7e3914e | ||
|
|
89e0524f90 | ||
|
|
bbc26a78f8 | ||
|
|
74fb44abd3 | ||
|
|
d692e4e5c6 | ||
|
|
5cf088c0de | ||
|
|
f222048efe | ||
|
|
21b2a694f0 | ||
|
|
8e210d8e01 | ||
|
|
7e9668584b | ||
|
|
ffd16e5401 | ||
|
|
14cfd1a34e | ||
|
|
a11f43520e | ||
|
|
e4159dd7c2 | ||
|
|
8738fa4137 | ||
|
|
9b7da3e071 | ||
|
|
a06de35aa5 | ||
|
|
d5fffc3641 | ||
|
|
a734ed8dfe | ||
|
|
9e12f8e3eb | ||
|
|
600f297472 | ||
|
|
92ee972e58 | ||
|
|
95a5c8a76a | ||
|
|
212d8e9278 | ||
|
|
7f844cae63 | ||
|
|
5034c92be9 | ||
|
|
9378bac10e | ||
|
|
b6db96b653 | ||
|
|
c271e05abc | ||
|
|
de7154eda8 | ||
|
|
030106986b | ||
|
|
32d33f03d7 | ||
|
|
750a5e1147 | ||
|
|
8dfcb353cb | ||
|
|
9a2740dede | ||
|
|
6d6874db37 | ||
|
|
01c6b266e5 | ||
|
|
d1445cb47e | ||
|
|
5c44742a9b | ||
|
|
486eedc03e | ||
|
|
7d8ba57e5f | ||
|
|
ab827a91dc | ||
|
|
e0bbcdb236 | ||
|
|
3d4b6783ed | ||
|
|
bb398b3275 | ||
|
|
4d05bf034b | ||
|
|
6594d90778 | ||
|
|
ee3981b748 | ||
|
|
f57416d22b | ||
|
|
bcc103e572 | ||
|
|
d398018633 | ||
|
|
45c4be3ae9 | ||
|
|
d93d72d538 | ||
|
|
d3bcb38669 | ||
|
|
7f19c43f4d | ||
|
|
98791015e5 | ||
|
|
213f08e171 | ||
|
|
4641115314 | ||
|
|
faee781042 | ||
|
|
de4885d223 | ||
|
|
cef334c210 | ||
|
|
2a54cb17e7 | ||
|
|
2e1b601508 | ||
|
|
719be46f9e | ||
|
|
649c061ee1 | ||
|
|
1023a3da6f | ||
|
|
404283be19 | ||
|
|
fc9f93791d | ||
|
|
55b0d1f24f | ||
|
|
d487351d5c | ||
|
|
e66fe78cbe | ||
|
|
ba38ccdbc6 | ||
|
|
a603e112e7 | ||
|
|
99f154be70 | ||
|
|
1ea259f8e3 | ||
|
|
8445f5587f | ||
|
|
301ca055bd | ||
|
|
d9dc89f25c | ||
|
|
07cfdbbc25 | ||
|
|
b0c951cdd2 | ||
|
|
bab01291b1 | ||
|
|
7c3f3da07d | ||
|
|
81d112928b | ||
|
|
9c09f0ce82 | ||
|
|
a20a2dbb71 | ||
|
|
cbf262be71 | ||
|
|
c58cfd407c | ||
|
|
c5db43854b | ||
|
|
52de8d0082 | ||
|
|
dea810996f | ||
|
|
f7af63c222 | ||
|
|
0d7e12e781 | ||
|
|
517285085a | ||
|
|
ceb0f5ead4 | ||
|
|
df5573f29a | ||
|
|
ce4e1b1ae4 | ||
|
|
2114cc98bb | ||
|
|
e38973ed4f | ||
|
|
4f8aaa98f7 | ||
|
|
4148a310a2 | ||
|
|
35397f6a3e | ||
|
|
19168ec6e8 | ||
|
|
2d087dfe15 | ||
|
|
3226633f51 | ||
|
|
33d2e0f836 | ||
|
|
6ccf661678 | ||
|
|
b5ba78def2 | ||
|
|
1706ba5765 | ||
|
|
a8f13a4157 | ||
|
|
2d8f30c40a | ||
|
|
d97d0fe359 | ||
|
|
1bae736284 | ||
|
|
017352b91e | ||
|
|
355afacaa1 | ||
|
|
fae79800c8 | ||
|
|
db298ba5e2 | ||
|
|
06a20d43ce | ||
|
|
63f29235e4 | ||
|
|
9bb00d99f6 | ||
|
|
bcd29b9fd2 | ||
|
|
046c221bc6 | ||
|
|
29a39b4e7f | ||
|
|
9fb3d06aac | ||
|
|
142d5e2347 | ||
|
|
58ea0bcbb0 | ||
|
|
1c0bbe5d33 | ||
|
|
8a7bba8ef3 | ||
|
|
3b93963688 | ||
|
|
77e5d0288f | ||
|
|
460e78a1b8 | ||
|
|
fcbade267d | ||
|
|
41b99d9aa0 | ||
|
|
96c761dbb5 | ||
|
|
d297564236 | ||
|
|
bca1a98938 | ||
|
|
23205bef65 | ||
|
|
7613b2f526 | ||
|
|
c5a521af1f | ||
|
|
f15c85e807 | ||
|
|
6129ad1f4d | ||
|
|
9972dc192b | ||
|
|
32b96a25e8 | ||
|
|
9d09e7f6fe | ||
|
|
5927483402 | ||
|
|
f228f79a8a | ||
|
|
072a3065cd | ||
|
|
718bd4c081 | ||
|
|
542cc0ec2f | ||
|
|
b357634f51 | ||
|
|
6968c4d0fb | ||
|
|
e35d618133 | ||
|
|
4a23fde6bf | ||
|
|
1ae577641d | ||
|
|
686a3bb42b | ||
|
|
1771d41871 | ||
|
|
ee8f4ca7ab | ||
|
|
4197a508a3 | ||
|
|
f38ffb505d | ||
|
|
679caf73d1 | ||
|
|
56d25c346c | ||
|
|
6ba26ba289 | ||
|
|
27582b7a4e | ||
|
|
2f4417d683 | ||
|
|
de97d29a82 | ||
|
|
b782a2c8a2 | ||
|
|
298783e2c5 | ||
|
|
bc9ec8025c | ||
|
|
26459763e5 | ||
|
|
1213306657 | ||
|
|
50add12e4b | ||
|
|
67c889f982 | ||
|
|
08cba25071 | ||
|
|
ff35b01bac | ||
|
|
faee1977fe | ||
|
|
6105b99a7f | ||
|
|
4993201b70 | ||
|
|
f456ca674d | ||
|
|
2ba350f76f | ||
|
|
3fe92a62ac | ||
|
|
f4dcf6821f | ||
|
|
0c10013858 | ||
|
|
3e9530fa8d | ||
|
|
0f4ffe4fce | ||
|
|
e1c01e5d25 | ||
|
|
51021131d7 | ||
|
|
89a08d1d5e | ||
|
|
ba8717f95a | ||
|
|
c8dfb9b0db | ||
|
|
3a02ece169 | ||
|
|
262df6b461 | ||
|
|
b9516fdfd4 | ||
|
|
9de41bc027 | ||
|
|
53b5cf3855 | ||
|
|
0567358783 | ||
|
|
c97bc55c6f | ||
|
|
3ef0bf60d0 | ||
|
|
b7b8084a38 | ||
|
|
5221f13498 | ||
|
|
0c0a8d70f3 | ||
|
|
2ff971878d | ||
|
|
1a0dc1e614 | ||
|
|
4a0bd99654 | ||
|
|
5cb98e44cb | ||
|
|
13ed99b9c3 | ||
|
|
0cda4e27aa | ||
|
|
0969e7f504 | ||
|
|
cad73e18e2 | ||
|
|
9eadeddfd9 | ||
|
|
de11cb173b | ||
|
|
5853bc68d1 | ||
|
|
7d1fd9d46f | ||
|
|
c977c822d5 | ||
|
|
c05fb33ea2 | ||
|
|
b9d0b3e152 | ||
|
|
a9e905b301 | ||
|
|
a8a714c820 | ||
|
|
9349ad9383 | ||
|
|
f686f00951 | ||
|
|
3d13c12cb7 | ||
|
|
2384a42d33 | ||
|
|
f507fec905 | ||
|
|
83a9724d17 | ||
|
|
4156e26f76 | ||
|
|
6d269e1786 | ||
|
|
ea447cab37 | ||
|
|
4f3e7de441 | ||
|
|
0a81fa99fc | ||
|
|
4aad44cb62 | ||
|
|
69dda39d02 | ||
|
|
ca3ba6f136 | ||
|
|
044cf4624a | ||
|
|
1fbfabdf66 | ||
|
|
db035351be | ||
|
|
2883ef840e | ||
|
|
8254ee911d | ||
|
|
560bc0a150 | ||
|
|
827898cd38 | ||
|
|
184dec146c | ||
|
|
298dbe96c8 | ||
|
|
6d888eb51a | ||
|
|
3694765611 | ||
|
|
b07ae3d34e | ||
|
|
64bcdf4734 | ||
|
|
1c23756fc4 | ||
|
|
50e3eeaafd | ||
|
|
843f528ebc | ||
|
|
faa0076988 | ||
|
|
59622c52ad | ||
|
|
a8e9aba58b | ||
|
|
36563cd1e1 | ||
|
|
072e712f0d | ||
|
|
121a186160 | ||
|
|
15a2ccc21e | ||
|
|
dbd8ea69eb | ||
|
|
8a57356f64 | ||
|
|
c77cb002f3 | ||
|
|
aa83a2b40b | ||
|
|
65b04cac6e | ||
|
|
5e577190a8 | ||
|
|
0143617056 | ||
|
|
a77dde7d3b | ||
|
|
7dcdb7c673 | ||
|
|
6de8eb56cd | ||
|
|
04e272d9bc | ||
|
|
17fe201473 | ||
|
|
25249be37f | ||
|
|
97ec12b5b3 | ||
|
|
246f82bfad | ||
|
|
db5679bbe9 | ||
|
|
feb0e1c45b | ||
|
|
edba837295 | ||
|
|
55882360ef | ||
|
|
6039370ad6 | ||
|
|
2d238c08d3 | ||
|
|
9b337b6a34 | ||
|
|
370db791aa | ||
|
|
9e3c547580 | ||
|
|
ab5d9b62b8 |
216
.clang-format
Normal file
216
.clang-format
Normal file
@@ -0,0 +1,216 @@
|
|||||||
|
---
|
||||||
|
Language: Cpp
|
||||||
|
# BasedOnStyle: LLVM
|
||||||
|
AccessModifierOffset: -1
|
||||||
|
AlignAfterOpenBracket: Align
|
||||||
|
AlignArrayOfStructures: None
|
||||||
|
AlignConsecutiveAssignments:
|
||||||
|
Enabled: false
|
||||||
|
AcrossEmptyLines: false
|
||||||
|
AcrossComments: false
|
||||||
|
AlignCompound: false
|
||||||
|
PadOperators: true
|
||||||
|
AlignConsecutiveBitFields:
|
||||||
|
Enabled: false
|
||||||
|
AcrossEmptyLines: false
|
||||||
|
AcrossComments: false
|
||||||
|
AlignCompound: false
|
||||||
|
PadOperators: false
|
||||||
|
AlignConsecutiveDeclarations:
|
||||||
|
Enabled: false
|
||||||
|
AcrossEmptyLines: false
|
||||||
|
AcrossComments: false
|
||||||
|
AlignCompound: false
|
||||||
|
PadOperators: false
|
||||||
|
AlignConsecutiveMacros:
|
||||||
|
Enabled: true
|
||||||
|
AcrossEmptyLines: false
|
||||||
|
AcrossComments: false
|
||||||
|
AlignCompound: false
|
||||||
|
PadOperators: false
|
||||||
|
AlignEscapedNewlines: Left
|
||||||
|
AlignOperands: DontAlign
|
||||||
|
AlignTrailingComments: true
|
||||||
|
AllowAllArgumentsOnNextLine: false
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: false
|
||||||
|
AllowShortEnumsOnASingleLine: true
|
||||||
|
AllowShortBlocksOnASingleLine: Never
|
||||||
|
AllowShortCaseLabelsOnASingleLine: true
|
||||||
|
AllowShortFunctionsOnASingleLine: All
|
||||||
|
AllowShortLambdasOnASingleLine: All
|
||||||
|
AllowShortIfStatementsOnASingleLine: AllIfsAndElse
|
||||||
|
AllowShortLoopsOnASingleLine: true
|
||||||
|
AlwaysBreakAfterDefinitionReturnType: None
|
||||||
|
AlwaysBreakAfterReturnType: None
|
||||||
|
AlwaysBreakBeforeMultilineStrings: false
|
||||||
|
AlwaysBreakTemplateDeclarations: No
|
||||||
|
AttributeMacros:
|
||||||
|
- __capability
|
||||||
|
BinPackArguments: true
|
||||||
|
BinPackParameters: true
|
||||||
|
BraceWrapping:
|
||||||
|
AfterCaseLabel: false
|
||||||
|
AfterClass: false
|
||||||
|
AfterControlStatement: Never
|
||||||
|
AfterEnum: false
|
||||||
|
AfterFunction: false
|
||||||
|
AfterNamespace: false
|
||||||
|
AfterObjCDeclaration: false
|
||||||
|
AfterStruct: false
|
||||||
|
AfterUnion: false
|
||||||
|
AfterExternBlock: false
|
||||||
|
BeforeCatch: false
|
||||||
|
BeforeElse: true
|
||||||
|
BeforeLambdaBody: false
|
||||||
|
BeforeWhile: false
|
||||||
|
IndentBraces: false
|
||||||
|
SplitEmptyFunction: false
|
||||||
|
SplitEmptyRecord: false
|
||||||
|
SplitEmptyNamespace: false
|
||||||
|
BreakBeforeBinaryOperators: None
|
||||||
|
BreakBeforeConceptDeclarations: Always
|
||||||
|
BreakBeforeBraces: Custom
|
||||||
|
BreakBeforeInheritanceComma: false
|
||||||
|
BreakInheritanceList: BeforeColon
|
||||||
|
BreakBeforeTernaryOperators: false
|
||||||
|
BreakConstructorInitializersBeforeComma: false
|
||||||
|
BreakConstructorInitializers: BeforeColon
|
||||||
|
BreakAfterJavaFieldAnnotations: false
|
||||||
|
BreakStringLiterals: false
|
||||||
|
ColumnLimit: 0
|
||||||
|
CommentPragmas: '^ IWYU pragma:'
|
||||||
|
QualifierAlignment: Leave
|
||||||
|
CompactNamespaces: false
|
||||||
|
ConstructorInitializerIndentWidth: 4
|
||||||
|
ContinuationIndentWidth: 2
|
||||||
|
Cpp11BracedListStyle: false
|
||||||
|
DeriveLineEnding: true
|
||||||
|
DerivePointerAlignment: false
|
||||||
|
DisableFormat: false
|
||||||
|
EmptyLineAfterAccessModifier: Never
|
||||||
|
EmptyLineBeforeAccessModifier: LogicalBlock
|
||||||
|
ExperimentalAutoDetectBinPacking: false
|
||||||
|
PackConstructorInitializers: BinPack
|
||||||
|
BasedOnStyle: ''
|
||||||
|
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||||
|
AllowAllConstructorInitializersOnNextLine: true
|
||||||
|
FixNamespaceComments: true
|
||||||
|
ForEachMacros:
|
||||||
|
- foreach
|
||||||
|
- Q_FOREACH
|
||||||
|
- BOOST_FOREACH
|
||||||
|
IfMacros:
|
||||||
|
- KJ_IF_MAYBE
|
||||||
|
IncludeBlocks: Preserve
|
||||||
|
IncludeCategories:
|
||||||
|
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
|
||||||
|
Priority: 2
|
||||||
|
SortPriority: 0
|
||||||
|
CaseSensitive: false
|
||||||
|
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
|
||||||
|
Priority: 3
|
||||||
|
SortPriority: 0
|
||||||
|
CaseSensitive: false
|
||||||
|
- Regex: '.*'
|
||||||
|
Priority: 1
|
||||||
|
SortPriority: 0
|
||||||
|
CaseSensitive: false
|
||||||
|
IncludeIsMainRegex: '(Test)?$'
|
||||||
|
IncludeIsMainSourceRegex: ''
|
||||||
|
IndentAccessModifiers: false
|
||||||
|
IndentCaseLabels: true
|
||||||
|
IndentCaseBlocks: false
|
||||||
|
IndentGotoLabels: true
|
||||||
|
IndentPPDirectives: AfterHash
|
||||||
|
IndentExternBlock: AfterExternBlock
|
||||||
|
IndentRequiresClause: true
|
||||||
|
IndentWidth: 2
|
||||||
|
IndentWrappedFunctionNames: false
|
||||||
|
InsertBraces: false
|
||||||
|
InsertTrailingCommas: None
|
||||||
|
JavaScriptQuotes: Leave
|
||||||
|
JavaScriptWrapImports: true
|
||||||
|
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||||
|
LambdaBodyIndentation: Signature
|
||||||
|
MacroBlockBegin: ''
|
||||||
|
MacroBlockEnd: ''
|
||||||
|
MaxEmptyLinesToKeep: 100
|
||||||
|
NamespaceIndentation: None
|
||||||
|
ObjCBinPackProtocolList: Auto
|
||||||
|
ObjCBlockIndentWidth: 2
|
||||||
|
ObjCBreakBeforeNestedBlockParam: true
|
||||||
|
ObjCSpaceAfterProperty: false
|
||||||
|
ObjCSpaceBeforeProtocolList: true
|
||||||
|
PenaltyBreakAssignment: 0
|
||||||
|
PenaltyBreakBeforeFirstCallParameter: 0
|
||||||
|
PenaltyBreakComment: 0
|
||||||
|
PenaltyBreakFirstLessLess: 0
|
||||||
|
PenaltyBreakOpenParenthesis: 0
|
||||||
|
PenaltyBreakString: 0
|
||||||
|
PenaltyBreakTemplateDeclaration: 0
|
||||||
|
PenaltyExcessCharacter: 0
|
||||||
|
PenaltyReturnTypeOnItsOwnLine: 0
|
||||||
|
PenaltyIndentedWhitespace: 0
|
||||||
|
PointerAlignment: Right
|
||||||
|
PPIndentWidth: -1
|
||||||
|
ReferenceAlignment: Pointer
|
||||||
|
ReflowComments: false
|
||||||
|
RemoveBracesLLVM: false
|
||||||
|
RequiresClausePosition: OwnLine
|
||||||
|
SeparateDefinitionBlocks: Leave
|
||||||
|
ShortNamespaceLines: 1
|
||||||
|
SortIncludes: false
|
||||||
|
SortJavaStaticImport: Before
|
||||||
|
SortUsingDeclarations: false
|
||||||
|
SpaceAfterCStyleCast: false
|
||||||
|
SpaceAfterLogicalNot: false
|
||||||
|
SpaceAfterTemplateKeyword: false
|
||||||
|
SpaceBeforeAssignmentOperators: true
|
||||||
|
SpaceBeforeCaseColon: false
|
||||||
|
SpaceBeforeCpp11BracedList: true
|
||||||
|
SpaceBeforeCtorInitializerColon: true
|
||||||
|
SpaceBeforeInheritanceColon: true
|
||||||
|
SpaceBeforeParens: ControlStatements
|
||||||
|
SpaceBeforeParensOptions:
|
||||||
|
AfterControlStatements: true
|
||||||
|
AfterForeachMacros: true
|
||||||
|
AfterFunctionDefinitionName: false
|
||||||
|
AfterFunctionDeclarationName: false
|
||||||
|
AfterIfMacros: true
|
||||||
|
AfterOverloadedOperator: false
|
||||||
|
AfterRequiresInClause: false
|
||||||
|
AfterRequiresInExpression: false
|
||||||
|
BeforeNonEmptyParentheses: false
|
||||||
|
SpaceAroundPointerQualifiers: Default
|
||||||
|
SpaceBeforeRangeBasedForLoopColon: true
|
||||||
|
SpaceInEmptyBlock: false
|
||||||
|
SpaceInEmptyParentheses: false
|
||||||
|
SpacesBeforeTrailingComments: 2
|
||||||
|
SpacesInAngles: Never
|
||||||
|
SpacesInConditionalStatement: false
|
||||||
|
SpacesInContainerLiterals: true
|
||||||
|
SpacesInCStyleCastParentheses: false
|
||||||
|
SpacesInLineCommentPrefix:
|
||||||
|
Minimum: 1
|
||||||
|
Maximum: -1
|
||||||
|
SpacesInParentheses: false
|
||||||
|
SpacesInSquareBrackets: false
|
||||||
|
SpaceBeforeSquareBrackets: false
|
||||||
|
BitFieldColonSpacing: Both
|
||||||
|
Standard: Latest
|
||||||
|
StatementAttributeLikeMacros:
|
||||||
|
- Q_EMIT
|
||||||
|
StatementMacros:
|
||||||
|
- Q_UNUSED
|
||||||
|
- QT_REQUIRE_VERSION
|
||||||
|
TabWidth: 8
|
||||||
|
UseCRLF: false
|
||||||
|
UseTab: Never
|
||||||
|
WhitespaceSensitiveMacros:
|
||||||
|
- STRINGIZE
|
||||||
|
- PP_STRINGIZE
|
||||||
|
- BOOST_PP_STRINGIZE
|
||||||
|
- NS_SWIFT_NAME
|
||||||
|
- CF_SWIFT_NAME
|
||||||
|
...
|
||||||
|
|
||||||
3
.github/FUNDING.yml
vendored
Normal file
3
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
github: jonaski
|
||||||
|
patreon: jonaskvinge
|
||||||
|
custom: https://paypal.me/jonaskvinge
|
||||||
31
.github/ISSUE_TEMPLATE.md
vendored
Normal file
31
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
---
|
||||||
|
name: Bug report
|
||||||
|
about: Create a report to help us improve
|
||||||
|
title: ''
|
||||||
|
labels: ''
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
- [ ] I have checked the [FAQ](https://wiki.strawberrymusicplayer.org/wiki/FAQ) for answers.
|
||||||
|
- [ ] I have checked the [Changelog](https://github.com/strawberrymusicplayer/strawberry/blob/master/Changelog) that the issue is not already fixed.
|
||||||
|
- [ ] I believe this issue is a bug, and not a general technical issue, question or feature requests that can be discussed on the [forum](https://forum.strawberrymusicplayer.org/).
|
||||||
|
|
||||||
|
**Describe the bug**
|
||||||
|
A clear and concise description of what the bug is.
|
||||||
|
|
||||||
|
**To Reproduce**
|
||||||
|
Steps to reproduce the behavior.
|
||||||
|
|
||||||
|
**Expected behavior**
|
||||||
|
A clear and concise description of what you expected to happen.
|
||||||
|
|
||||||
|
**Screenshots:**
|
||||||
|
If applicable, add screenshots to help explain your problem.
|
||||||
|
|
||||||
|
**System Information:**
|
||||||
|
- Operating system:
|
||||||
|
- Strawberry Version:
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Add any other context about the problem here.
|
||||||
1054
.github/workflows/build.yml
vendored
Normal file
1054
.github/workflows/build.yml
vendored
Normal file
File diff suppressed because it is too large
Load Diff
157
.gitignore
vendored
157
.gitignore
vendored
@@ -1,77 +1,120 @@
|
|||||||
# This file is used to ignore files which are generated
|
# This file is used to ignore files which are generated
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
*~
|
# Build
|
||||||
*.autosave
|
build/
|
||||||
*.a
|
bin/
|
||||||
*.core
|
|
||||||
*.moc
|
# CMake
|
||||||
|
CMakeLists.txt.user
|
||||||
|
CMakeCache.txt
|
||||||
|
CMakeFiles
|
||||||
|
CMakeScripts
|
||||||
|
Makefile*
|
||||||
|
Testing
|
||||||
|
cmake_install.cmake
|
||||||
|
install_manifest.txt
|
||||||
|
compile_commands.json
|
||||||
|
CTestTestfile.cmake
|
||||||
|
_deps
|
||||||
|
|
||||||
|
# Prerequisites
|
||||||
|
*.d
|
||||||
|
|
||||||
|
# Compiled Object files
|
||||||
|
*.slo
|
||||||
|
*.lo
|
||||||
*.o
|
*.o
|
||||||
*.obj
|
*.obj
|
||||||
*.orig
|
|
||||||
*.rej
|
# Precompiled Headers
|
||||||
|
*.gch
|
||||||
|
*.pch
|
||||||
|
|
||||||
|
# Compiled Dynamic libraries
|
||||||
*.so
|
*.so
|
||||||
*.so.*
|
*.so.*
|
||||||
*_pch.h.cpp
|
*.dylib
|
||||||
*_resource.rc
|
*.dll
|
||||||
*.qm
|
|
||||||
.#*
|
# Fortran module files
|
||||||
*.*#
|
*.mod
|
||||||
core
|
*.smod
|
||||||
!core/
|
|
||||||
tags
|
# Compiled Static libraries
|
||||||
.DS_Store
|
*.lai
|
||||||
.directory
|
*.la
|
||||||
*.debug
|
*.a
|
||||||
Makefile*
|
*.lib
|
||||||
*.prl
|
|
||||||
|
# Executables
|
||||||
|
*.exe
|
||||||
|
*.out
|
||||||
*.app
|
*.app
|
||||||
|
|
||||||
|
# Dump files
|
||||||
|
*.core
|
||||||
|
*.stackdump
|
||||||
|
|
||||||
|
# Qt
|
||||||
|
*build-*
|
||||||
moc_*.cpp
|
moc_*.cpp
|
||||||
ui_*.h
|
moc_*.h
|
||||||
qrc_*.cpp
|
qrc_*.cpp
|
||||||
Thumbs.db
|
ui_*.h
|
||||||
*.res
|
*.moc
|
||||||
*.rc
|
*.qm
|
||||||
/.qmake.cache
|
|
||||||
/.qmake.stash
|
|
||||||
*.spec
|
|
||||||
*.nsi
|
|
||||||
*.plist
|
|
||||||
maketarball.sh
|
|
||||||
|
|
||||||
# qtcreator generated files
|
# Temporary files
|
||||||
*.pro.user*
|
*~
|
||||||
|
*.autosave
|
||||||
# xemacs temporary files
|
*.orig
|
||||||
|
*.rej
|
||||||
|
.*.kate-swp
|
||||||
|
.swp.*
|
||||||
|
.*.swp
|
||||||
*.flc
|
*.flc
|
||||||
|
|
||||||
# Vim temporary files
|
# Directory files
|
||||||
.*.swp
|
.directory
|
||||||
|
.DS_Store
|
||||||
# Visual Studio generated files
|
Thumbs.db
|
||||||
*.ib_pdb_index
|
|
||||||
*.idb
|
|
||||||
*.ilk
|
|
||||||
*.pdb
|
|
||||||
*.sln
|
|
||||||
*.suo
|
|
||||||
*.vcproj
|
|
||||||
*vcproj.*.*.user
|
|
||||||
*.ncb
|
|
||||||
*.sdf
|
|
||||||
*.opensdf
|
|
||||||
*.vcxproj
|
|
||||||
*vcxproj.*
|
|
||||||
|
|
||||||
# MinGW generated files
|
# MinGW generated files
|
||||||
*.Debug
|
*.Debug
|
||||||
*.Release
|
*.Release
|
||||||
|
|
||||||
# Python byte code
|
# Package files
|
||||||
*.pyc
|
*.spec
|
||||||
|
*.nsi
|
||||||
|
*.plist
|
||||||
|
|
||||||
# Binaries
|
# Stuff in dist
|
||||||
# --------
|
maketarball.sh
|
||||||
*.dll
|
changelog
|
||||||
*.exe
|
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
translations.pot
|
||||||
|
zanata.xml
|
||||||
|
.zanata-cache/
|
||||||
|
|
||||||
|
# QtCreator
|
||||||
|
CMakeLists.txt.user*
|
||||||
|
*.pro.user
|
||||||
|
*.pro.user.*
|
||||||
|
*creator.user*
|
||||||
|
target_wrapper.*
|
||||||
|
compile_commands.json
|
||||||
|
|
||||||
|
*.kdev4
|
||||||
|
*.vscode
|
||||||
|
*.code-workspace
|
||||||
|
*.sublime-workspace
|
||||||
|
|
||||||
|
# MSVC
|
||||||
|
CMakeSettings.json
|
||||||
|
/.vs
|
||||||
|
/out
|
||||||
|
|
||||||
|
# CLion
|
||||||
|
/.idea
|
||||||
|
|||||||
30
.travis.yml
30
.travis.yml
@@ -1,30 +0,0 @@
|
|||||||
sudo: required
|
|
||||||
language: C++
|
|
||||||
os:
|
|
||||||
- linux
|
|
||||||
- osx
|
|
||||||
services:
|
|
||||||
- docker
|
|
||||||
compiler:
|
|
||||||
- gcc
|
|
||||||
- clang
|
|
||||||
|
|
||||||
before_install:
|
|
||||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker build -f Dockerfile -t strawberry-build . ; fi
|
|
||||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker run --name build -itd strawberry-build /bin/bash ; fi
|
|
||||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker exec build git clone https://github.com/jonaski/strawberry ; fi
|
|
||||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update ; fi
|
|
||||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew unlink python ; fi
|
|
||||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install glib pkgconfig protobuf protobuf-c qt ; fi
|
|
||||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install sqlite --with-fts ; fi
|
|
||||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install gstreamer gst-plugins-base ; fi
|
|
||||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install gst-plugins-good --with-flac ; fi
|
|
||||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install gst-plugins-bad gst-plugins-ugly ; fi
|
|
||||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install chromaprint ; fi
|
|
||||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then export Qt5_DIR=/usr/local/opt/qt5/lib/cmake ; fi
|
|
||||||
before_script:
|
|
||||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker exec build cmake -Hstrawberry -Bbuild ; fi
|
|
||||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then mkdir build; cd build; cmake .. -DFORCE_GIT_REVISION="0.0.0-0-g0000000"; fi
|
|
||||||
script:
|
|
||||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker exec build make -C build -j8 ; fi
|
|
||||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then make -j8 ; fi
|
|
||||||
30
3rdparty/README.md
vendored
Normal file
30
3rdparty/README.md
vendored
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
3rdparty libraries located in this directory
|
||||||
|
============================================
|
||||||
|
|
||||||
|
singleapplication
|
||||||
|
-----------------
|
||||||
|
This is a small static library used by Strawberry to prevent it from starting twice per user session.
|
||||||
|
If the user tries to start strawberry twice, the main window will maximize instead of starting another instance.
|
||||||
|
If you dynamically link to your systems version, you'll need two versions, one defined as QApplication and
|
||||||
|
one as a QCoreApplication.
|
||||||
|
It is included here because it is not packed by distros and is also used on macOS and Windows.
|
||||||
|
|
||||||
|
URL: https://github.com/itay-grudev/SingleApplication
|
||||||
|
|
||||||
|
|
||||||
|
SPMediaKeyTap
|
||||||
|
-------------
|
||||||
|
Used on macOS to exclusively enable strawberry to grab global media shortcuts.
|
||||||
|
Can safely be deleted on other platforms.
|
||||||
|
|
||||||
|
|
||||||
|
macdeployqt
|
||||||
|
-----------
|
||||||
|
A modified version of Qt's official macdeployqt utility that fixes some issues,
|
||||||
|
this version also deploys gstreamer plugins.
|
||||||
|
Can safely be deleted on other platforms.
|
||||||
|
|
||||||
|
|
||||||
|
getopt
|
||||||
|
------
|
||||||
|
getopt included only when compiling with MSVC on Windows.
|
||||||
2
3rdparty/SPMediaKeyTap/CMakeLists.txt
vendored
2
3rdparty/SPMediaKeyTap/CMakeLists.txt
vendored
@@ -1,11 +1,9 @@
|
|||||||
set(SPMEDIAKEY-SOURCES
|
set(SPMEDIAKEY-SOURCES
|
||||||
SPMediaKeyTap.m
|
SPMediaKeyTap.m
|
||||||
SPInvocationGrabbing/NSObject+SPInvocationGrabbing.m
|
|
||||||
)
|
)
|
||||||
|
|
||||||
set(SPMEDIAKEY-HEADERS
|
set(SPMEDIAKEY-HEADERS
|
||||||
SPMediaKeyTap.h
|
SPMediaKeyTap.h
|
||||||
SPInvocationGrabbing/NSObject+SPInvocationGrabbing.h
|
|
||||||
)
|
)
|
||||||
|
|
||||||
ADD_LIBRARY(SPMediaKeyTap STATIC
|
ADD_LIBRARY(SPMediaKeyTap STATIC
|
||||||
|
|||||||
4
3rdparty/SPMediaKeyTap/README.md
vendored
4
3rdparty/SPMediaKeyTap/README.md
vendored
@@ -1,7 +1,7 @@
|
|||||||
SPMediaKeyTap
|
SPMediaKeyTap
|
||||||
=============
|
=============
|
||||||
|
|
||||||
`SPMediaKeyTap` abstracts a `CGEventHook` and other nastiness in order to give you a relatively simple API to receive media key events (prev/next/playpause, on F7 to F9 on modern MacBook Pros) exclusively, without them reaching other applications like iTunes. `SPMediaKeyTap` is clever enough to resign its exclusive lock on media keys by looking for which application was active most recently: if that application is in `SPMediaKeyTap`'s whitelist, it will resign the keys. This is similar to the behavior of Apple's applications collaborating on media key handling exclusivity, but unfortunately, Apple are not exposing any APIs allowing third-parties to join in on this collaboration.
|
`SPMediaKeyTap` abstracts a `CGEventHook` and other nastiness in order to give you a relatively simple API to receive media key events (prev/next/playpause, on F7 to F9 on modern MacBook Pros) exclusively, without them reaching other applications like iTunes. `SPMediaKeyTap` is clever enough to resign its exclusive lock on media keys by looking for which application was active most recently: if that application is in `SPMediaKeyTap`'s whitelist, it will resign the keys. This is similar to the behavior of Apple's applications collaborating on media key handling exclusivity, but unfortunately, Apple is not exposing any APIs allowing third-parties to join in on this collaboration.
|
||||||
|
|
||||||
For now, the whitelist is just a hardcoded array in `+[SPMediaKeyTap defaultMediaKeyUserBundleIdentifiers]`. If your app starts using `SPMediaKeyTap`, please [mail me](mailto:nevyn@spotify.com) your bundle ID, and I'll include it in the canonical repository. This is a bad solution; a better solution would be to use distributed notifications to collaborate in creating this whitelist at runtime. Hopefully someone'll have the time and energy to write this soon.
|
For now, the whitelist is just a hardcoded array in `+[SPMediaKeyTap defaultMediaKeyUserBundleIdentifiers]`. If your app starts using `SPMediaKeyTap`, please [mail me](mailto:nevyn@spotify.com) your bundle ID, and I'll include it in the canonical repository. This is a bad solution; a better solution would be to use distributed notifications to collaborate in creating this whitelist at runtime. Hopefully someone'll have the time and energy to write this soon.
|
||||||
|
|
||||||
@@ -9,4 +9,4 @@ In `Example/SPMediaKeyTapExampleAppDelegate.m` is an example of both how you use
|
|||||||
|
|
||||||
`SPMediaKeyTap` and other `CGEventHook`s on the event type `NSSystemDefined` is known to interfere with each other and applications doing weird stuff with mouse input, because mouse clicks are also part of the `NSSystemDefined` category. The single issue we have had reported here at Spotify is Adobe Fireworks, in which item selection stops working with `SPMediaKeyTap` is active.
|
`SPMediaKeyTap` and other `CGEventHook`s on the event type `NSSystemDefined` is known to interfere with each other and applications doing weird stuff with mouse input, because mouse clicks are also part of the `NSSystemDefined` category. The single issue we have had reported here at Spotify is Adobe Fireworks, in which item selection stops working with `SPMediaKeyTap` is active.
|
||||||
|
|
||||||
`SPMediaKeyTap` requires 10.5 to work, and disables itself on 10.4.
|
`SPMediaKeyTap` requires 10.5 to work, and disables itself on 10.4.
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
#import <Foundation/Foundation.h>
|
|
||||||
|
|
||||||
@interface SPInvocationGrabber : NSObject {
|
|
||||||
id _object;
|
|
||||||
NSInvocation *_invocation;
|
|
||||||
int frameCount;
|
|
||||||
char **frameStrings;
|
|
||||||
BOOL backgroundAfterForward;
|
|
||||||
BOOL onMainAfterForward;
|
|
||||||
BOOL waitUntilDone;
|
|
||||||
}
|
|
||||||
-(id)initWithObject:(id)obj;
|
|
||||||
-(id)initWithObject:(id)obj stacktraceSaving:(BOOL)saveStack;
|
|
||||||
@property (readonly, retain, nonatomic) id object;
|
|
||||||
@property (readonly, retain, nonatomic) NSInvocation *invocation;
|
|
||||||
@property BOOL backgroundAfterForward;
|
|
||||||
@property BOOL onMainAfterForward;
|
|
||||||
@property BOOL waitUntilDone;
|
|
||||||
-(void)invoke; // will release object and invocation
|
|
||||||
-(void)printBacktrace;
|
|
||||||
-(void)saveBacktrace;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@interface NSObject (SPInvocationGrabbing)
|
|
||||||
-(id)grab;
|
|
||||||
-(id)invokeAfter:(NSTimeInterval)delta;
|
|
||||||
-(id)nextRunloop;
|
|
||||||
-(id)inBackground;
|
|
||||||
-(id)onMainAsync:(BOOL)async;
|
|
||||||
@end
|
|
||||||
@@ -1,128 +0,0 @@
|
|||||||
#import "NSObject+SPInvocationGrabbing.h"
|
|
||||||
#import <execinfo.h>
|
|
||||||
|
|
||||||
#pragma mark Invocation grabbing
|
|
||||||
@interface SPInvocationGrabber ()
|
|
||||||
@property (readwrite, retain, nonatomic) id object;
|
|
||||||
@property (readwrite, retain, nonatomic) NSInvocation *invocation;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation SPInvocationGrabber
|
|
||||||
- (id)initWithObject:(id)obj;
|
|
||||||
{
|
|
||||||
return [self initWithObject:obj stacktraceSaving:YES];
|
|
||||||
}
|
|
||||||
|
|
||||||
-(id)initWithObject:(id)obj stacktraceSaving:(BOOL)saveStack;
|
|
||||||
{
|
|
||||||
self.object = obj;
|
|
||||||
|
|
||||||
if(saveStack)
|
|
||||||
[self saveBacktrace];
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
-(void)dealloc;
|
|
||||||
{
|
|
||||||
free(frameStrings);
|
|
||||||
self.object = nil;
|
|
||||||
self.invocation = nil;
|
|
||||||
[super dealloc];
|
|
||||||
}
|
|
||||||
@synthesize invocation = _invocation, object = _object;
|
|
||||||
|
|
||||||
@synthesize backgroundAfterForward, onMainAfterForward, waitUntilDone;
|
|
||||||
- (void)runInBackground;
|
|
||||||
{
|
|
||||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
|
||||||
@try {
|
|
||||||
[self invoke];
|
|
||||||
}
|
|
||||||
@finally {
|
|
||||||
[pool drain];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
- (void)forwardInvocation:(NSInvocation *)anInvocation {
|
|
||||||
[anInvocation retainArguments];
|
|
||||||
anInvocation.target = _object;
|
|
||||||
self.invocation = anInvocation;
|
|
||||||
|
|
||||||
if(backgroundAfterForward)
|
|
||||||
[NSThread detachNewThreadSelector:@selector(runInBackground) toTarget:self withObject:nil];
|
|
||||||
else if(onMainAfterForward)
|
|
||||||
[self performSelectorOnMainThread:@selector(invoke) withObject:nil waitUntilDone:waitUntilDone];
|
|
||||||
}
|
|
||||||
- (NSMethodSignature *)methodSignatureForSelector:(SEL)inSelector {
|
|
||||||
NSMethodSignature *signature = [super methodSignatureForSelector:inSelector];
|
|
||||||
if (signature == NULL)
|
|
||||||
signature = [_object methodSignatureForSelector:inSelector];
|
|
||||||
|
|
||||||
return signature;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)invoke;
|
|
||||||
{
|
|
||||||
|
|
||||||
@try {
|
|
||||||
[_invocation invoke];
|
|
||||||
}
|
|
||||||
@catch (NSException * e) {
|
|
||||||
NSLog(@"SPInvocationGrabber's target raised %@:\n\t%@\nInvocation was originally scheduled at:", e.name, e);
|
|
||||||
[self printBacktrace];
|
|
||||||
printf("\n");
|
|
||||||
[e raise];
|
|
||||||
}
|
|
||||||
|
|
||||||
self.invocation = nil;
|
|
||||||
self.object = nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
-(void)saveBacktrace;
|
|
||||||
{
|
|
||||||
void *backtraceFrames[128];
|
|
||||||
frameCount = backtrace(&backtraceFrames[0], 128);
|
|
||||||
frameStrings = backtrace_symbols(&backtraceFrames[0], frameCount);
|
|
||||||
}
|
|
||||||
-(void)printBacktrace;
|
|
||||||
{
|
|
||||||
int x;
|
|
||||||
for(x = 3; x < frameCount; x++) {
|
|
||||||
if(frameStrings[x] == NULL) { break; }
|
|
||||||
printf("%s\n", frameStrings[x]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation NSObject (SPInvocationGrabbing)
|
|
||||||
-(id)grab;
|
|
||||||
{
|
|
||||||
return [[[SPInvocationGrabber alloc] initWithObject:self] autorelease];
|
|
||||||
}
|
|
||||||
-(id)invokeAfter:(NSTimeInterval)delta;
|
|
||||||
{
|
|
||||||
id grabber = [self grab];
|
|
||||||
[NSTimer scheduledTimerWithTimeInterval:delta target:grabber selector:@selector(invoke) userInfo:nil repeats:NO];
|
|
||||||
return grabber;
|
|
||||||
}
|
|
||||||
- (id)nextRunloop;
|
|
||||||
{
|
|
||||||
return [self invokeAfter:0];
|
|
||||||
}
|
|
||||||
-(id)inBackground;
|
|
||||||
{
|
|
||||||
SPInvocationGrabber *grabber = [self grab];
|
|
||||||
grabber.backgroundAfterForward = YES;
|
|
||||||
return grabber;
|
|
||||||
}
|
|
||||||
-(id)onMainAsync:(BOOL)async;
|
|
||||||
{
|
|
||||||
SPInvocationGrabber *grabber = [self grab];
|
|
||||||
grabber.onMainAfterForward = YES;
|
|
||||||
grabber.waitUntilDone = !async;
|
|
||||||
return grabber;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
// A
|
|
||||||
+(UIView*)flashAt:(CGRect)r in:(UIView*)parent color:(UIColor*)color;
|
|
||||||
{
|
|
||||||
float duration = 0.5;
|
|
||||||
UIView *flash = [[[UIView alloc] initWithFrame:r] autorelease];
|
|
||||||
flash.backgroundColor = color;
|
|
||||||
[parent addSubview:flash];
|
|
||||||
[[flash invokeAfter:duration+0.1] removeFromSuperview];
|
|
||||||
|
|
||||||
[UIView beginAnimations:@"SPFlash" context:NULL];
|
|
||||||
[UIView setAnimationDuration:duration];
|
|
||||||
flash.alpha = 0.0;
|
|
||||||
[UIView commitAnimations];
|
|
||||||
return flash;
|
|
||||||
}
|
|
||||||
|
|
||||||
// B
|
|
||||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
|
||||||
|
|
||||||
// Force the animation to happen by calling this method again after a small
|
|
||||||
// delay - see http://blog.instapaper.com/post/53568356
|
|
||||||
[[self nextRunloop] delayedTableViewDidSelectRowAtIndexPath: indexPath];
|
|
||||||
}
|
|
||||||
|
|
||||||
// C
|
|
||||||
[[tableView invokeAfter:0.15] selectRowAtIndexPath:indexPath animated:YES scrollPosition:UITableViewScrollPositionNone];
|
|
||||||
[[tableView invokeAfter:0.30] deselectRowAtIndexPath:indexPath animated:YES];
|
|
||||||
[[tableView invokeAfter:0.45] selectRowAtIndexPath:indexPath animated:YES scrollPosition:UITableViewScrollPositionNone];
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
@interface MyClass : NSObject
|
|
||||||
-(BOOL)areTheNewViewersGoneYet:(Duck*)duck;
|
|
||||||
@end
|
|
||||||
...
|
|
||||||
MyClass *myInstance = [[MyClass alloc] init];
|
|
||||||
id invocationGrabber = [[[SPInvocationGrabber alloc] initWithTarget:myInstance] autorelease];
|
|
||||||
|
|
||||||
|
|
||||||
[invocationGrabber areTheNewViewersGoneYet:[Duck yellowDuck]]; // line 9
|
|
||||||
|
|
||||||
|
|
||||||
NSInvocation *invocationForAreTheNewViewersGoneYet = [invocationGrabber invocation];
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
#import <Cocoa/Cocoa.h>
|
|
||||||
#import "NSObject+SPInvocationGrabbing.h"
|
|
||||||
|
|
||||||
@interface Foo : NSObject {
|
|
||||||
int a;
|
|
||||||
}
|
|
||||||
-(void)startIt;
|
|
||||||
-(void)theBackgroundStuff;
|
|
||||||
-(void)theForegroundStuff;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation Foo
|
|
||||||
-(void)startIt;
|
|
||||||
{
|
|
||||||
NSLog(@"Starting out on the main thread...");
|
|
||||||
a = 3;
|
|
||||||
[[self inBackground] theBackgroundStuff];
|
|
||||||
}
|
|
||||||
-(void)theBackgroundStuff;
|
|
||||||
{
|
|
||||||
NSLog(@"Woah, this is a background thread!");
|
|
||||||
a += 6;
|
|
||||||
[[self onMainAsync:YES] theForegroundStuff];
|
|
||||||
}
|
|
||||||
-(void)theForegroundStuff;
|
|
||||||
{
|
|
||||||
NSLog(@"Hey presto: %d", a);
|
|
||||||
}
|
|
||||||
@end
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
|
||||||
Foo *foo = [Foo new];
|
|
||||||
[foo startIt];
|
|
||||||
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];
|
|
||||||
[pool release];
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
61
3rdparty/SPMediaKeyTap/SPMediaKeyTap.h
vendored
61
3rdparty/SPMediaKeyTap/SPMediaKeyTap.h
vendored
@@ -1,34 +1,53 @@
|
|||||||
#include <Cocoa/Cocoa.h>
|
/*
|
||||||
|
Copyright (c) 2011, Joachim Bengtsson
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Neither the name of the organization nor the names of its contributors may
|
||||||
|
be used to endorse or promote products derived from this software without
|
||||||
|
specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
#import <IOKit/hidsystem/ev_keymap.h>
|
#import <IOKit/hidsystem/ev_keymap.h>
|
||||||
#import <Carbon/Carbon.h>
|
|
||||||
|
|
||||||
// http://overooped.com/post/2593597587/mediakeys
|
// http://overooped.com/post/2593597587/mediakeys
|
||||||
|
|
||||||
#define SPSystemDefinedEventMediaKeys 8
|
#define SPSystemDefinedEventMediaKeys 8
|
||||||
|
|
||||||
@interface SPMediaKeyTap : NSObject {
|
@interface SPMediaKeyTap : NSObject
|
||||||
EventHandlerRef _app_switching_ref;
|
|
||||||
EventHandlerRef _app_terminating_ref;
|
|
||||||
CFMachPortRef _eventPort;
|
|
||||||
CFRunLoopSourceRef _eventPortSource;
|
|
||||||
CFRunLoopRef _tapThreadRL;
|
|
||||||
BOOL _shouldInterceptMediaKeyEvents;
|
|
||||||
id _delegate;
|
|
||||||
// The app that is frontmost in this list owns media keys
|
|
||||||
NSMutableArray *_mediaKeyAppList;
|
|
||||||
}
|
|
||||||
+ (NSArray*)defaultMediaKeyUserBundleIdentifiers;
|
|
||||||
|
|
||||||
-(id)initWithDelegate:(id)delegate;
|
- (id)initWithDelegate:(id)delegate;
|
||||||
|
|
||||||
+(BOOL)usesGlobalMediaKeyTap;
|
+ (BOOL)usesGlobalMediaKeyTap;
|
||||||
-(void)startWatchingMediaKeys;
|
- (BOOL)startWatchingMediaKeys;
|
||||||
-(void)stopWatchingMediaKeys;
|
- (void)stopWatchingMediaKeys;
|
||||||
-(void)handleAndReleaseMediaKeyEvent:(NSEvent *)event;
|
- (void)handleAndReleaseMediaKeyEvent:(NSEvent *)event;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface NSObject (SPMediaKeyTapDelegate)
|
@interface NSObject (SPMediaKeyTapDelegate)
|
||||||
-(void)mediaKeyTap:(SPMediaKeyTap*)keyTap receivedMediaKeyEvent:(NSEvent*)event;
|
- (void)mediaKeyTap:(SPMediaKeyTap*)keyTap receivedMediaKeyEvent:(NSEvent*)event;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
extern NSString *kMediaKeyUsingBundleIdentifiersDefaultsKey;
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern NSString *kIgnoreMediaKeysDefaultsKey;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|||||||
495
3rdparty/SPMediaKeyTap/SPMediaKeyTap.m
vendored
495
3rdparty/SPMediaKeyTap/SPMediaKeyTap.m
vendored
@@ -1,18 +1,52 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2011, Joachim Bengtsson
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Neither the name of the organization nor the names of its contributors may
|
||||||
|
be used to endorse or promote products derived from this software without
|
||||||
|
specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
// Copyright (c) 2010 Spotify AB
|
// Copyright (c) 2010 Spotify AB
|
||||||
#import "SPMediaKeyTap.h"
|
#import "SPMediaKeyTap.h"
|
||||||
#import "SPInvocationGrabbing/NSObject+SPInvocationGrabbing.h" // https://gist.github.com/511181, in submodule
|
|
||||||
|
|
||||||
@interface SPMediaKeyTap ()
|
// Define to enable app list debug output
|
||||||
-(BOOL)shouldInterceptMediaKeyEvents;
|
// #define DEBUG_SPMEDIAKEY_APPLIST 1
|
||||||
-(void)setShouldInterceptMediaKeyEvents:(BOOL)newSetting;
|
|
||||||
-(void)startWatchingAppSwitching;
|
NSString *kIgnoreMediaKeysDefaultsKey = @"SPIgnoreMediaKeys";
|
||||||
-(void)stopWatchingAppSwitching;
|
|
||||||
-(void)eventTapThread;
|
@interface SPMediaKeyTap () {
|
||||||
|
CFMachPortRef _eventPort;
|
||||||
|
CFRunLoopSourceRef _eventPortSource;
|
||||||
|
CFRunLoopRef _tapThreadRL;
|
||||||
|
NSThread *_tapThread;
|
||||||
|
BOOL _shouldInterceptMediaKeyEvents;
|
||||||
|
id _delegate;
|
||||||
|
// The app that is frontmost in this list owns media keys
|
||||||
|
NSMutableArray<NSRunningApplication *> *_mediaKeyAppList;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)shouldInterceptMediaKeyEvents;
|
||||||
|
- (void)setShouldInterceptMediaKeyEvents:(BOOL)newSetting;
|
||||||
|
- (void)startWatchingAppSwitching;
|
||||||
|
- (void)stopWatchingAppSwitching;
|
||||||
|
- (void)eventTapThread;
|
||||||
@end
|
@end
|
||||||
static SPMediaKeyTap *singleton = nil;
|
|
||||||
|
|
||||||
static pascal OSStatus appSwitched (EventHandlerCallRef nextHandler, EventRef evt, void* userData);
|
|
||||||
static pascal OSStatus appTerminated (EventHandlerCallRef nextHandler, EventRef evt, void* userData);
|
|
||||||
static CGEventRef tapEventCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon);
|
static CGEventRef tapEventCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon);
|
||||||
|
|
||||||
|
|
||||||
@@ -22,127 +56,191 @@ static CGEventRef tapEventCallback(CGEventTapProxy proxy, CGEventType type, CGEv
|
|||||||
|
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
#pragma mark Setup and teardown
|
#pragma mark Setup and teardown
|
||||||
-(id)initWithDelegate:(id)delegate;
|
|
||||||
|
- (id)initWithDelegate:(id)delegate
|
||||||
{
|
{
|
||||||
_delegate = delegate;
|
self = [super init];
|
||||||
[self startWatchingAppSwitching];
|
if (self) {
|
||||||
singleton = self;
|
_delegate = delegate;
|
||||||
_mediaKeyAppList = [NSMutableArray new];
|
[self startWatchingAppSwitching];
|
||||||
return self;
|
_mediaKeyAppList = [NSMutableArray new];
|
||||||
}
|
}
|
||||||
-(void)dealloc;
|
return self;
|
||||||
{
|
|
||||||
[self stopWatchingMediaKeys];
|
|
||||||
[self stopWatchingAppSwitching];
|
|
||||||
[_mediaKeyAppList release];
|
|
||||||
[super dealloc];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
-(void)startWatchingAppSwitching;
|
- (void)dealloc
|
||||||
{
|
{
|
||||||
// Listen to "app switched" event, so that we don't intercept media keys if we
|
[self stopWatchingMediaKeys];
|
||||||
// weren't the last "media key listening" app to be active
|
[self stopWatchingAppSwitching];
|
||||||
EventTypeSpec eventType = { kEventClassApplication, kEventAppFrontSwitched };
|
[super dealloc];
|
||||||
OSStatus err = InstallApplicationEventHandler(NewEventHandlerUPP(appSwitched), 1, &eventType, self, &_app_switching_ref);
|
|
||||||
assert(err == noErr);
|
|
||||||
|
|
||||||
eventType.eventKind = kEventAppTerminated;
|
|
||||||
err = InstallApplicationEventHandler(NewEventHandlerUPP(appTerminated), 1, &eventType, self, &_app_terminating_ref);
|
|
||||||
assert(err == noErr);
|
|
||||||
}
|
|
||||||
-(void)stopWatchingAppSwitching;
|
|
||||||
{
|
|
||||||
if(!_app_switching_ref) return;
|
|
||||||
RemoveEventHandler(_app_switching_ref);
|
|
||||||
_app_switching_ref = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
-(void)startWatchingMediaKeys;{
|
- (void)startWatchingAppSwitching
|
||||||
[self setShouldInterceptMediaKeyEvents:YES];
|
{
|
||||||
|
// Listen to "app switched" event, so that we don't intercept media keys if we
|
||||||
// Add an event tap to intercept the system defined media key events
|
// weren't the last "media key listening" app to be active
|
||||||
_eventPort = CGEventTapCreate(kCGSessionEventTap,
|
|
||||||
kCGHeadInsertEventTap,
|
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self
|
||||||
kCGEventTapOptionDefault,
|
selector:@selector(frontmostAppChanged:)
|
||||||
CGEventMaskBit(NX_SYSDEFINED),
|
name:NSWorkspaceDidActivateApplicationNotification
|
||||||
tapEventCallback,
|
object:nil];
|
||||||
self);
|
|
||||||
assert(_eventPort != NULL);
|
|
||||||
|
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self
|
||||||
|
selector:@selector(appTerminated:)
|
||||||
|
name:NSWorkspaceDidTerminateApplicationNotification
|
||||||
|
object:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)stopWatchingAppSwitching
|
||||||
|
{
|
||||||
|
[[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)startWatchingMediaKeys
|
||||||
|
{
|
||||||
|
// Prevent having multiple mediaKeys threads
|
||||||
|
[self stopWatchingMediaKeys];
|
||||||
|
|
||||||
|
[self setShouldInterceptMediaKeyEvents:YES];
|
||||||
|
|
||||||
|
// Add an event tap to intercept the system defined media key events
|
||||||
|
_eventPort = CGEventTapCreate(kCGSessionEventTap,
|
||||||
|
kCGHeadInsertEventTap,
|
||||||
|
kCGEventTapOptionDefault,
|
||||||
|
CGEventMaskBit(NX_SYSDEFINED),
|
||||||
|
tapEventCallback,
|
||||||
|
(__bridge void * __nullable)(self));
|
||||||
|
|
||||||
|
// Can be NULL if the app has no accessibility access permission
|
||||||
|
if (_eventPort == NULL)
|
||||||
|
return NO;
|
||||||
|
|
||||||
_eventPortSource = CFMachPortCreateRunLoopSource(kCFAllocatorSystemDefault, _eventPort, 0);
|
_eventPortSource = CFMachPortCreateRunLoopSource(kCFAllocatorSystemDefault, _eventPort, 0);
|
||||||
assert(_eventPortSource != NULL);
|
assert(_eventPortSource != NULL);
|
||||||
|
|
||||||
// Let's do this in a separate thread so that a slow app doesn't lag the event tap
|
if (_eventPortSource == NULL)
|
||||||
[NSThread detachNewThreadSelector:@selector(eventTapThread) toTarget:self withObject:nil];
|
return NO;
|
||||||
|
|
||||||
|
// Let's do this in a separate thread so that a slow app doesn't lag the event tap
|
||||||
|
_tapThread = [[NSThread alloc] initWithTarget:self
|
||||||
|
selector:@selector(eventTapThread)
|
||||||
|
object:nil];
|
||||||
|
[_tapThread start];
|
||||||
|
|
||||||
|
return YES;
|
||||||
}
|
}
|
||||||
-(void)stopWatchingMediaKeys;
|
|
||||||
|
- (void)stopWatchingMediaKeys
|
||||||
{
|
{
|
||||||
// TODO<nevyn>: Shut down thread, remove event tap port and source
|
// Shut down tap thread
|
||||||
|
if(_tapThreadRL){
|
||||||
|
CFRunLoopStop(_tapThreadRL);
|
||||||
|
_tapThreadRL = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove tap port
|
||||||
|
if(_eventPort){
|
||||||
|
CFMachPortInvalidate(_eventPort);
|
||||||
|
CFRelease(_eventPort);
|
||||||
|
_eventPort = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove tap source
|
||||||
|
if(_eventPortSource){
|
||||||
|
CFRelease(_eventPortSource);
|
||||||
|
_eventPortSource = nil;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
#pragma mark Accessors
|
#pragma mark Accessors
|
||||||
|
|
||||||
+(BOOL)usesGlobalMediaKeyTap
|
+ (BOOL)usesGlobalMediaKeyTap
|
||||||
{
|
{
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
// breaking in gdb with a key tap inserted sometimes locks up all mouse and keyboard input forever, forcing reboot
|
// breaking in gdb with a key tap inserted sometimes locks up all mouse and keyboard input forever, forcing reboot
|
||||||
return NO;
|
return NO;
|
||||||
#else
|
#else
|
||||||
// XXX(nevyn): MediaKey event tap doesn't work on 10.4, feel free to figure out why if you have the energy.
|
// XXX(nevyn): MediaKey event tap doesn't work on 10.4, feel free to figure out why if you have the energy.
|
||||||
return floor(NSAppKitVersionNumber) >= 949/*NSAppKitVersionNumber10_5*/;
|
return
|
||||||
|
![[NSUserDefaults standardUserDefaults] boolForKey:kIgnoreMediaKeysDefaultsKey]
|
||||||
|
&& floor(NSAppKitVersionNumber) >= 949/*NSAppKitVersionNumber10_5*/;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (NSArray*)defaultMediaKeyUserBundleIdentifiers;
|
+ (NSArray*)mediaKeyUserBundleIdentifiers
|
||||||
{
|
{
|
||||||
return [NSArray arrayWithObjects:
|
return [NSArray arrayWithObjects:
|
||||||
[[NSBundle mainBundle] bundleIdentifier], // your app
|
[[NSBundle mainBundle] bundleIdentifier], // your app
|
||||||
@"com.spotify.client",
|
@"com.spotify.client",
|
||||||
@"com.apple.iTunes",
|
@"com.apple.iTunes",
|
||||||
@"com.apple.QuickTimePlayerX",
|
@"com.apple.QuickTimePlayerX",
|
||||||
@"com.apple.quicktimeplayer",
|
@"com.apple.quicktimeplayer",
|
||||||
@"com.apple.iWork.Keynote",
|
@"com.apple.iWork.Keynote",
|
||||||
@"com.apple.iPhoto",
|
@"com.apple.iPhoto",
|
||||||
@"org.videolan.vlc",
|
@"org.videolan.vlc",
|
||||||
@"com.apple.Aperture",
|
@"com.apple.Aperture",
|
||||||
@"com.plexsquared.Plex",
|
@"com.plexsquared.Plex",
|
||||||
@"com.soundcloud.desktop",
|
@"com.soundcloud.desktop",
|
||||||
@"com.macromedia.fireworks", // the tap messes up their mouse input
|
@"org.niltsh.MPlayerX",
|
||||||
nil
|
@"com.ilabs.PandorasHelper",
|
||||||
];
|
@"com.mahasoftware.pandabar",
|
||||||
|
@"com.bitcartel.pandorajam",
|
||||||
|
@"org.clementine-player.clementine",
|
||||||
|
@"fm.last.Last.fm",
|
||||||
|
@"fm.last.Scrobbler",
|
||||||
|
@"com.beatport.BeatportPro",
|
||||||
|
@"com.Timenut.SongKey",
|
||||||
|
@"com.macromedia.fireworks", // the tap messes up their mouse input
|
||||||
|
@"at.justp.Theremin",
|
||||||
|
@"ru.ya.themblsha.YandexMusic",
|
||||||
|
@"com.jriver.MediaCenter18",
|
||||||
|
@"com.jriver.MediaCenter19",
|
||||||
|
@"com.jriver.MediaCenter20",
|
||||||
|
@"co.rackit.mate",
|
||||||
|
@"com.ttitt.b-music",
|
||||||
|
@"com.beardedspice.BeardedSpice",
|
||||||
|
@"com.plug.Plug",
|
||||||
|
@"com.plug.Plug2",
|
||||||
|
@"com.netease.163music",
|
||||||
|
@"org.quodlibet.quodlibet",
|
||||||
|
nil
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
-(BOOL)shouldInterceptMediaKeyEvents;
|
- (BOOL)shouldInterceptMediaKeyEvents
|
||||||
{
|
{
|
||||||
BOOL shouldIntercept = NO;
|
BOOL shouldIntercept = NO;
|
||||||
@synchronized(self) {
|
@synchronized(self) {
|
||||||
shouldIntercept = _shouldInterceptMediaKeyEvents;
|
shouldIntercept = _shouldInterceptMediaKeyEvents;
|
||||||
}
|
}
|
||||||
return shouldIntercept;
|
return shouldIntercept;
|
||||||
}
|
}
|
||||||
|
|
||||||
-(void)pauseTapOnTapThread:(BOOL)yeahno;
|
- (void)pauseTapOnTapThread:(NSNumber *)yeahno
|
||||||
{
|
{
|
||||||
CGEventTapEnable(self->_eventPort, yeahno);
|
CGEventTapEnable(self->_eventPort, [yeahno boolValue]);
|
||||||
}
|
|
||||||
-(void)setShouldInterceptMediaKeyEvents:(BOOL)newSetting;
|
|
||||||
{
|
|
||||||
BOOL oldSetting;
|
|
||||||
@synchronized(self) {
|
|
||||||
oldSetting = _shouldInterceptMediaKeyEvents;
|
|
||||||
_shouldInterceptMediaKeyEvents = newSetting;
|
|
||||||
}
|
|
||||||
if(_tapThreadRL && oldSetting != newSetting) {
|
|
||||||
id grab = [self grab];
|
|
||||||
[grab pauseTapOnTapThread:newSetting];
|
|
||||||
NSTimer *timer = [NSTimer timerWithTimeInterval:0 invocation:[grab invocation] repeats:NO];
|
|
||||||
CFRunLoopAddTimer(_tapThreadRL, (CFRunLoopTimerRef)timer, kCFRunLoopCommonModes);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark
|
- (void)setShouldInterceptMediaKeyEvents:(BOOL)newSetting
|
||||||
|
{
|
||||||
|
BOOL oldSetting;
|
||||||
|
@synchronized(self) {
|
||||||
|
oldSetting = _shouldInterceptMediaKeyEvents;
|
||||||
|
_shouldInterceptMediaKeyEvents = newSetting;
|
||||||
|
}
|
||||||
|
if(_tapThreadRL && oldSetting != newSetting) {
|
||||||
|
[self performSelector:@selector(pauseTapOnTapThread:)
|
||||||
|
onThread:_tapThread
|
||||||
|
withObject:@(newSetting)
|
||||||
|
waitUntilDone:NO];
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
#pragma mark Event tap callbacks
|
#pragma mark Event tap callbacks
|
||||||
|
|
||||||
@@ -150,151 +248,114 @@ static CGEventRef tapEventCallback(CGEventTapProxy proxy, CGEventType type, CGEv
|
|||||||
|
|
||||||
static CGEventRef tapEventCallback2(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon)
|
static CGEventRef tapEventCallback2(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon)
|
||||||
{
|
{
|
||||||
SPMediaKeyTap *self = refcon;
|
#pragma unused(proxy)
|
||||||
|
SPMediaKeyTap *self = (__bridge SPMediaKeyTap *)refcon;
|
||||||
|
|
||||||
if(type == kCGEventTapDisabledByTimeout) {
|
if(type == kCGEventTapDisabledByTimeout) {
|
||||||
NSLog(@"Media key event tap was disabled by timeout");
|
NSLog(@"Media key event tap was disabled by timeout");
|
||||||
CGEventTapEnable(self->_eventPort, TRUE);
|
CGEventTapEnable(self->_eventPort, TRUE);
|
||||||
return event;
|
return event;
|
||||||
} else if(type == kCGEventTapDisabledByUserInput) {
|
} else if(type == kCGEventTapDisabledByUserInput) {
|
||||||
// Was disabled manually by -[pauseTapOnTapThread]
|
// Was disabled manually by -[pauseTapOnTapThread]
|
||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
NSEvent *nsEvent = nil;
|
NSEvent *nsEvent = nil;
|
||||||
@try {
|
@try {
|
||||||
nsEvent = [NSEvent eventWithCGEvent:event];
|
nsEvent = [NSEvent eventWithCGEvent:event];
|
||||||
}
|
}
|
||||||
@catch (NSException * e) {
|
@catch (NSException * e) {
|
||||||
NSLog(@"Strange CGEventType: %d: %@", type, e);
|
NSLog(@"Strange CGEventType: %d: %@", type, e);
|
||||||
assert(0);
|
assert(0);
|
||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type != NX_SYSDEFINED || [nsEvent subtype] != SPSystemDefinedEventMediaKeys)
|
if (type != NX_SYSDEFINED || [nsEvent subtype] != SPSystemDefinedEventMediaKeys)
|
||||||
return event;
|
return event;
|
||||||
|
|
||||||
int keyCode = (([nsEvent data1] & 0xFFFF0000) >> 16);
|
int keyCode = (([nsEvent data1] & 0xFFFF0000) >> 16);
|
||||||
if (keyCode != NX_KEYTYPE_PLAY && keyCode != NX_KEYTYPE_FAST && keyCode != NX_KEYTYPE_REWIND)
|
if (keyCode != NX_KEYTYPE_PLAY && keyCode != NX_KEYTYPE_FAST && keyCode != NX_KEYTYPE_REWIND && keyCode != NX_KEYTYPE_PREVIOUS && keyCode != NX_KEYTYPE_NEXT)
|
||||||
return event;
|
return event;
|
||||||
|
|
||||||
if (![self shouldInterceptMediaKeyEvents])
|
if (![self shouldInterceptMediaKeyEvents])
|
||||||
return event;
|
return event;
|
||||||
|
|
||||||
[nsEvent retain]; // matched in handleAndReleaseMediaKeyEvent:
|
[self performSelectorOnMainThread:@selector(handleAndReleaseMediaKeyEvent:) withObject:nsEvent waitUntilDone:NO];
|
||||||
[self performSelectorOnMainThread:@selector(handleAndReleaseMediaKeyEvent:) withObject:nsEvent waitUntilDone:NO];
|
|
||||||
|
return NULL;
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static CGEventRef tapEventCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon)
|
static CGEventRef tapEventCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon)
|
||||||
{
|
{
|
||||||
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
@autoreleasepool {
|
||||||
CGEventRef ret = tapEventCallback2(proxy, type, event, refcon);
|
CGEventRef ret = tapEventCallback2(proxy, type, event, refcon);
|
||||||
[pool drain];
|
return ret;
|
||||||
return ret;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)handleAndReleaseMediaKeyEvent:(NSEvent *)event
|
||||||
// event will have been retained in the other thread
|
|
||||||
-(void)handleAndReleaseMediaKeyEvent:(NSEvent *)event {
|
|
||||||
[event autorelease];
|
|
||||||
|
|
||||||
[_delegate mediaKeyTap:self receivedMediaKeyEvent:event];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
-(void)eventTapThread;
|
|
||||||
{
|
{
|
||||||
_tapThreadRL = CFRunLoopGetCurrent();
|
[_delegate mediaKeyTap:self receivedMediaKeyEvent:event];
|
||||||
CFRunLoopAddSource(_tapThreadRL, _eventPortSource, kCFRunLoopCommonModes);
|
|
||||||
CFRunLoopRun();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)eventTapThread
|
||||||
|
{
|
||||||
|
_tapThreadRL = CFRunLoopGetCurrent();
|
||||||
|
CFRunLoopAddSource(_tapThreadRL, _eventPortSource, kCFRunLoopCommonModes);
|
||||||
|
CFRunLoopRun();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
#pragma mark Task switching callbacks
|
#pragma mark Task switching callbacks
|
||||||
|
|
||||||
NSString *kMediaKeyUsingBundleIdentifiersDefaultsKey = @"SPApplicationsNeedingMediaKeys";
|
- (void)mediaKeyAppListChanged
|
||||||
|
|
||||||
|
|
||||||
-(void)mediaKeyAppListChanged;
|
|
||||||
{
|
{
|
||||||
if([_mediaKeyAppList count] == 0) return;
|
#ifdef DEBUG_SPMEDIAKEY_APPLIST
|
||||||
|
[self debugPrintAppList];
|
||||||
/*NSLog(@"--");
|
#endif
|
||||||
int i = 0;
|
|
||||||
for (NSValue *psnv in _mediaKeyAppList) {
|
|
||||||
ProcessSerialNumber psn; [psnv getValue:&psn];
|
|
||||||
NSDictionary *processInfo = [(id)ProcessInformationCopyDictionary(
|
|
||||||
&psn,
|
|
||||||
kProcessDictionaryIncludeAllInformationMask
|
|
||||||
) autorelease];
|
|
||||||
NSString *bundleIdentifier = [processInfo objectForKey:(id)kCFBundleIdentifierKey];
|
|
||||||
NSLog(@"%d: %@", i++, bundleIdentifier);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
ProcessSerialNumber mySerial, topSerial;
|
|
||||||
GetCurrentProcess(&mySerial);
|
|
||||||
[[_mediaKeyAppList objectAtIndex:0] getValue:&topSerial];
|
|
||||||
|
|
||||||
Boolean same;
|
if([_mediaKeyAppList count] == 0)
|
||||||
OSErr err = SameProcess(&mySerial, &topSerial, &same);
|
return;
|
||||||
[self setShouldInterceptMediaKeyEvents:(err == noErr && same)];
|
|
||||||
|
|
||||||
}
|
NSRunningApplication *thisApp = [NSRunningApplication currentApplication];
|
||||||
-(void)appIsNowFrontmost:(ProcessSerialNumber)psn;
|
NSRunningApplication *otherApp = [_mediaKeyAppList firstObject];
|
||||||
{
|
|
||||||
NSValue *psnv = [NSValue valueWithBytes:&psn objCType:@encode(ProcessSerialNumber)];
|
|
||||||
|
|
||||||
NSDictionary *processInfo = [(id)ProcessInformationCopyDictionary(
|
|
||||||
&psn,
|
|
||||||
kProcessDictionaryIncludeAllInformationMask
|
|
||||||
) autorelease];
|
|
||||||
NSString *bundleIdentifier = [processInfo objectForKey:(id)kCFBundleIdentifierKey];
|
|
||||||
|
|
||||||
NSArray *whitelistIdentifiers = [[NSUserDefaults standardUserDefaults] arrayForKey:kMediaKeyUsingBundleIdentifiersDefaultsKey];
|
BOOL isCurrent = [thisApp isEqual:otherApp];
|
||||||
if(![whitelistIdentifiers containsObject:bundleIdentifier]) return;
|
|
||||||
|
|
||||||
[_mediaKeyAppList removeObject:psnv];
|
[self setShouldInterceptMediaKeyEvents:isCurrent];
|
||||||
[_mediaKeyAppList insertObject:psnv atIndex:0];
|
|
||||||
[self mediaKeyAppListChanged];
|
|
||||||
}
|
|
||||||
-(void)appTerminated:(ProcessSerialNumber)psn;
|
|
||||||
{
|
|
||||||
NSValue *psnv = [NSValue valueWithBytes:&psn objCType:@encode(ProcessSerialNumber)];
|
|
||||||
[_mediaKeyAppList removeObject:psnv];
|
|
||||||
[self mediaKeyAppListChanged];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static pascal OSStatus appSwitched (EventHandlerCallRef nextHandler, EventRef evt, void* userData)
|
- (void)frontmostAppChanged:(NSNotification *)notification
|
||||||
{
|
{
|
||||||
SPMediaKeyTap *self = (id)userData;
|
NSRunningApplication *app = [notification.userInfo objectForKey:NSWorkspaceApplicationKey];
|
||||||
|
if (app.bundleIdentifier == nil)
|
||||||
|
return;
|
||||||
|
|
||||||
ProcessSerialNumber newSerial;
|
if (![[SPMediaKeyTap mediaKeyUserBundleIdentifiers] containsObject:app.bundleIdentifier])
|
||||||
GetFrontProcess(&newSerial);
|
return;
|
||||||
|
|
||||||
[self appIsNowFrontmost:newSerial];
|
[_mediaKeyAppList removeObject:app];
|
||||||
|
[_mediaKeyAppList insertObject:app atIndex:0];
|
||||||
return CallNextEventHandler(nextHandler, evt);
|
[self mediaKeyAppListChanged];
|
||||||
}
|
}
|
||||||
|
|
||||||
static pascal OSStatus appTerminated (EventHandlerCallRef nextHandler, EventRef evt, void* userData)
|
- (void)appTerminated:(NSNotification *)notification
|
||||||
{
|
{
|
||||||
SPMediaKeyTap *self = (id)userData;
|
NSRunningApplication *app = [notification.userInfo objectForKey:NSWorkspaceApplicationKey];
|
||||||
|
[_mediaKeyAppList removeObject:app];
|
||||||
ProcessSerialNumber deadPSN;
|
|
||||||
|
|
||||||
GetEventParameter(
|
[self mediaKeyAppListChanged];
|
||||||
evt,
|
|
||||||
kEventParamProcessID,
|
|
||||||
typeProcessSerialNumber,
|
|
||||||
NULL,
|
|
||||||
sizeof(deadPSN),
|
|
||||||
NULL,
|
|
||||||
&deadPSN
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
[self appTerminated:deadPSN];
|
|
||||||
return CallNextEventHandler(nextHandler, evt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG_SPMEDIAKEY_APPLIST
|
||||||
|
- (void)debugPrintAppList
|
||||||
|
{
|
||||||
|
NSMutableString *list = [NSMutableString stringWithCapacity:255];
|
||||||
|
for (NSRunningApplication *app in _mediaKeyAppList) {
|
||||||
|
[list appendFormat:@" - %@\n", app.bundleIdentifier];
|
||||||
|
}
|
||||||
|
NSLog(@"List: \n%@", list);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
25
3rdparty/SPMediaKeyTap/SPMediaKeyTapDelegate.m
vendored
25
3rdparty/SPMediaKeyTap/SPMediaKeyTapDelegate.m
vendored
@@ -1,25 +0,0 @@
|
|||||||
-(void)mediaKeyTap:(SPMediaKeyTap*)keyTap receivedMediaKeyEvent:(NSEvent*)event;
|
|
||||||
{
|
|
||||||
assert([event type] == NSSystemDefined && [event subtype] == SPSystemDefinedEventMediaKeys);
|
|
||||||
|
|
||||||
int keyCode = (([event data1] & 0xFFFF0000) >> 16);
|
|
||||||
int keyFlags = ([event data1] & 0x0000FFFF);
|
|
||||||
int keyState = (((keyFlags & 0xFF00) >> 8)) == 0xA;
|
|
||||||
int keyRepeat = (keyFlags & 0x1);
|
|
||||||
|
|
||||||
if (keyState == 1 && windowController != NULL) {
|
|
||||||
|
|
||||||
|
|
||||||
switch (keyCode) {
|
|
||||||
|
|
||||||
case NX_KEYTYPE_PLAY:
|
|
||||||
... return;
|
|
||||||
|
|
||||||
case NX_KEYTYPE_FAST:
|
|
||||||
... return;
|
|
||||||
|
|
||||||
case NX_KEYTYPE_REWIND:
|
|
||||||
... return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
2
3rdparty/getopt/CMakeLists.txt
vendored
Normal file
2
3rdparty/getopt/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
add_library(getopt STATIC getopt.c)
|
||||||
|
target_include_directories(getopt PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
562
3rdparty/getopt/getopt.c
vendored
Normal file
562
3rdparty/getopt/getopt.c
vendored
Normal file
@@ -0,0 +1,562 @@
|
|||||||
|
/* $OpenBSD: getopt_long.c,v 1.23 2007/10/31 12:34:57 chl Exp $ */
|
||||||
|
/* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*
|
||||||
|
* Sponsored in part by the Defense Advanced Research Projects
|
||||||
|
* Agency (DARPA) and Air Force Research Laboratory, Air Force
|
||||||
|
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
|
||||||
|
*/
|
||||||
|
/*-
|
||||||
|
* Copyright (c) 2000 The NetBSD Foundation, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This code is derived from software contributed to The NetBSD Foundation
|
||||||
|
* by Dieter Baron and Thomas Klausner.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||||
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||||
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#define REPLACE_GETOPT /* use this getopt as the system getopt(3) */
|
||||||
|
|
||||||
|
#ifdef REPLACE_GETOPT
|
||||||
|
int opterr = 1; /* if error message should be printed */
|
||||||
|
int optind = 1; /* index into parent argv vector */
|
||||||
|
int optopt = '?'; /* character checked for validity */
|
||||||
|
#undef optreset /* see getopt.h */
|
||||||
|
#define optreset __mingw_optreset
|
||||||
|
int optreset; /* reset getopt */
|
||||||
|
char *optarg; /* argument associated with option */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define PRINT_ERROR ((opterr) && (*options != ':'))
|
||||||
|
|
||||||
|
#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */
|
||||||
|
#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */
|
||||||
|
#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */
|
||||||
|
|
||||||
|
/* return values */
|
||||||
|
#define BADCH (int)'?'
|
||||||
|
#define BADARG ((*options == ':') ? (int)':' : (int)'?')
|
||||||
|
#define INORDER (int)1
|
||||||
|
|
||||||
|
#ifndef __CYGWIN__
|
||||||
|
#define __progname __argv[0]
|
||||||
|
#else
|
||||||
|
extern char __declspec(dllimport) *__progname;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __CYGWIN__
|
||||||
|
static char EMSG[] = "";
|
||||||
|
#else
|
||||||
|
#define EMSG ""
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int getopt_internal(int, char * const *, const char *,
|
||||||
|
const struct option *, int *, int);
|
||||||
|
static int parse_long_options(char * const *, const char *,
|
||||||
|
const struct option *, int *, int);
|
||||||
|
static int gcd(int, int);
|
||||||
|
static void permute_args(int, int, int, char * const *);
|
||||||
|
|
||||||
|
static char *place = EMSG; /* option letter processing */
|
||||||
|
|
||||||
|
/* XXX: set optreset to 1 rather than these two */
|
||||||
|
static int nonopt_start = -1; /* first non option argument (for permute) */
|
||||||
|
static int nonopt_end = -1; /* first option after non options (for permute) */
|
||||||
|
|
||||||
|
/* Error messages */
|
||||||
|
static const char recargchar[] = "option requires an argument -- %c";
|
||||||
|
static const char recargstring[] = "option requires an argument -- %s";
|
||||||
|
static const char ambig[] = "ambiguous option -- %.*s";
|
||||||
|
static const char noarg[] = "option doesn't take an argument -- %.*s";
|
||||||
|
static const char illoptchar[] = "unknown option -- %c";
|
||||||
|
static const char illoptstring[] = "unknown option -- %s";
|
||||||
|
|
||||||
|
static void
|
||||||
|
_vwarnx(const char *fmt,va_list ap)
|
||||||
|
{
|
||||||
|
(void)fprintf(stderr,"%s: ",__progname);
|
||||||
|
if (fmt != NULL)
|
||||||
|
(void)vfprintf(stderr,fmt,ap);
|
||||||
|
(void)fprintf(stderr,"\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
warnx(const char *fmt,...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap,fmt);
|
||||||
|
_vwarnx(fmt,ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compute the greatest common divisor of a and b.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
gcd(int a, int b)
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
|
||||||
|
c = a % b;
|
||||||
|
while (c != 0) {
|
||||||
|
a = b;
|
||||||
|
b = c;
|
||||||
|
c = a % b;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Exchange the block from nonopt_start to nonopt_end with the block
|
||||||
|
* from nonopt_end to opt_end (keeping the same order of arguments
|
||||||
|
* in each block).
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
permute_args(int panonopt_start, int panonopt_end, int opt_end,
|
||||||
|
char * const *nargv)
|
||||||
|
{
|
||||||
|
int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
|
||||||
|
char *swap;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* compute lengths of blocks and number and size of cycles
|
||||||
|
*/
|
||||||
|
nnonopts = panonopt_end - panonopt_start;
|
||||||
|
nopts = opt_end - panonopt_end;
|
||||||
|
ncycle = gcd(nnonopts, nopts);
|
||||||
|
cyclelen = (opt_end - panonopt_start) / ncycle;
|
||||||
|
|
||||||
|
for (i = 0; i < ncycle; i++) {
|
||||||
|
cstart = panonopt_end+i;
|
||||||
|
pos = cstart;
|
||||||
|
for (j = 0; j < cyclelen; j++) {
|
||||||
|
if (pos >= panonopt_end)
|
||||||
|
pos -= nnonopts;
|
||||||
|
else
|
||||||
|
pos += nopts;
|
||||||
|
swap = nargv[pos];
|
||||||
|
/* LINTED const cast */
|
||||||
|
((char **) nargv)[pos] = nargv[cstart];
|
||||||
|
/* LINTED const cast */
|
||||||
|
((char **)nargv)[cstart] = swap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* parse_long_options --
|
||||||
|
* Parse long options in argc/argv argument vector.
|
||||||
|
* Returns -1 if short_too is set and the option does not match long_options.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
parse_long_options(char * const *nargv, const char *options,
|
||||||
|
const struct option *long_options, int *idx, int short_too)
|
||||||
|
{
|
||||||
|
char *current_argv, *has_equal;
|
||||||
|
size_t current_argv_len;
|
||||||
|
int i, ambiguous, match;
|
||||||
|
|
||||||
|
#define IDENTICAL_INTERPRETATION(_x, _y) \
|
||||||
|
(long_options[(_x)].has_arg == long_options[(_y)].has_arg && \
|
||||||
|
long_options[(_x)].flag == long_options[(_y)].flag && \
|
||||||
|
long_options[(_x)].val == long_options[(_y)].val)
|
||||||
|
|
||||||
|
current_argv = place;
|
||||||
|
match = -1;
|
||||||
|
ambiguous = 0;
|
||||||
|
|
||||||
|
optind++;
|
||||||
|
|
||||||
|
if ((has_equal = strchr(current_argv, '=')) != NULL) {
|
||||||
|
/* argument found (--option=arg) */
|
||||||
|
current_argv_len = has_equal - current_argv;
|
||||||
|
has_equal++;
|
||||||
|
} else
|
||||||
|
current_argv_len = strlen(current_argv);
|
||||||
|
|
||||||
|
for (i = 0; long_options[i].name; i++) {
|
||||||
|
/* find matching long option */
|
||||||
|
if (strncmp(current_argv, long_options[i].name,
|
||||||
|
current_argv_len))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (strlen(long_options[i].name) == current_argv_len) {
|
||||||
|
/* exact match */
|
||||||
|
match = i;
|
||||||
|
ambiguous = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* If this is a known short option, don't allow
|
||||||
|
* a partial match of a single character.
|
||||||
|
*/
|
||||||
|
if (short_too && current_argv_len == 1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (match == -1) /* partial match */
|
||||||
|
match = i;
|
||||||
|
else if (!IDENTICAL_INTERPRETATION(i, match))
|
||||||
|
ambiguous = 1;
|
||||||
|
}
|
||||||
|
if (ambiguous) {
|
||||||
|
/* ambiguous abbreviation */
|
||||||
|
if (PRINT_ERROR)
|
||||||
|
warnx(ambig, (int)current_argv_len,
|
||||||
|
current_argv);
|
||||||
|
optopt = 0;
|
||||||
|
return (BADCH);
|
||||||
|
}
|
||||||
|
if (match != -1) { /* option found */
|
||||||
|
if (long_options[match].has_arg == no_argument
|
||||||
|
&& has_equal) {
|
||||||
|
if (PRINT_ERROR)
|
||||||
|
warnx(noarg, (int)current_argv_len,
|
||||||
|
current_argv);
|
||||||
|
/*
|
||||||
|
* XXX: GNU sets optopt to val regardless of flag
|
||||||
|
*/
|
||||||
|
if (long_options[match].flag == NULL)
|
||||||
|
optopt = long_options[match].val;
|
||||||
|
else
|
||||||
|
optopt = 0;
|
||||||
|
return (BADARG);
|
||||||
|
}
|
||||||
|
if (long_options[match].has_arg == required_argument ||
|
||||||
|
long_options[match].has_arg == optional_argument) {
|
||||||
|
if (has_equal)
|
||||||
|
optarg = has_equal;
|
||||||
|
else if (long_options[match].has_arg ==
|
||||||
|
required_argument) {
|
||||||
|
/*
|
||||||
|
* optional argument doesn't use next nargv
|
||||||
|
*/
|
||||||
|
optarg = nargv[optind++];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((long_options[match].has_arg == required_argument)
|
||||||
|
&& (optarg == NULL)) {
|
||||||
|
/*
|
||||||
|
* Missing argument; leading ':' indicates no error
|
||||||
|
* should be generated.
|
||||||
|
*/
|
||||||
|
if (PRINT_ERROR)
|
||||||
|
warnx(recargstring,
|
||||||
|
current_argv);
|
||||||
|
/*
|
||||||
|
* XXX: GNU sets optopt to val regardless of flag
|
||||||
|
*/
|
||||||
|
if (long_options[match].flag == NULL)
|
||||||
|
optopt = long_options[match].val;
|
||||||
|
else
|
||||||
|
optopt = 0;
|
||||||
|
--optind;
|
||||||
|
return (BADARG);
|
||||||
|
}
|
||||||
|
} else { /* unknown option */
|
||||||
|
if (short_too) {
|
||||||
|
--optind;
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
if (PRINT_ERROR)
|
||||||
|
warnx(illoptstring, current_argv);
|
||||||
|
optopt = 0;
|
||||||
|
return (BADCH);
|
||||||
|
}
|
||||||
|
if (idx)
|
||||||
|
*idx = match;
|
||||||
|
if (long_options[match].flag) {
|
||||||
|
*long_options[match].flag = long_options[match].val;
|
||||||
|
return (0);
|
||||||
|
} else
|
||||||
|
return (long_options[match].val);
|
||||||
|
#undef IDENTICAL_INTERPRETATION
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* getopt_internal --
|
||||||
|
* Parse argc/argv argument vector. Called by user level routines.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
getopt_internal(int nargc, char * const *nargv, const char *options,
|
||||||
|
const struct option *long_options, int *idx, int flags)
|
||||||
|
{
|
||||||
|
char *oli; /* option letter list index */
|
||||||
|
int optchar, short_too;
|
||||||
|
static int posixly_correct = -1;
|
||||||
|
|
||||||
|
if (options == NULL)
|
||||||
|
return (-1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XXX Some GNU programs (like cvs) set optind to 0 instead of
|
||||||
|
* XXX using optreset. Work around this braindamage.
|
||||||
|
*/
|
||||||
|
if (optind == 0)
|
||||||
|
optind = optreset = 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Disable GNU extensions if POSIXLY_CORRECT is set or options
|
||||||
|
* string begins with a '+'.
|
||||||
|
*
|
||||||
|
* CV, 2009-12-14: Check POSIXLY_CORRECT anew if optind == 0 or
|
||||||
|
* optreset != 0 for GNU compatibility.
|
||||||
|
*/
|
||||||
|
if (posixly_correct == -1 || optreset != 0)
|
||||||
|
posixly_correct = (GetEnvironmentVariableW(L"POSIXLY_CORRECT", NULL, 0) != 0);
|
||||||
|
if (*options == '-')
|
||||||
|
flags |= FLAG_ALLARGS;
|
||||||
|
else if (posixly_correct || *options == '+')
|
||||||
|
flags &= ~FLAG_PERMUTE;
|
||||||
|
if (*options == '+' || *options == '-')
|
||||||
|
options++;
|
||||||
|
|
||||||
|
optarg = NULL;
|
||||||
|
if (optreset)
|
||||||
|
nonopt_start = nonopt_end = -1;
|
||||||
|
start:
|
||||||
|
if (optreset || !*place) { /* update scanning pointer */
|
||||||
|
optreset = 0;
|
||||||
|
if (optind >= nargc) { /* end of argument vector */
|
||||||
|
place = EMSG;
|
||||||
|
if (nonopt_end != -1) {
|
||||||
|
/* do permutation, if we have to */
|
||||||
|
permute_args(nonopt_start, nonopt_end,
|
||||||
|
optind, nargv);
|
||||||
|
optind -= nonopt_end - nonopt_start;
|
||||||
|
}
|
||||||
|
else if (nonopt_start != -1) {
|
||||||
|
/*
|
||||||
|
* If we skipped non-options, set optind
|
||||||
|
* to the first of them.
|
||||||
|
*/
|
||||||
|
optind = nonopt_start;
|
||||||
|
}
|
||||||
|
nonopt_start = nonopt_end = -1;
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
if (*(place = nargv[optind]) != '-' ||
|
||||||
|
(place[1] == '\0' && strchr(options, '-') == NULL)) {
|
||||||
|
place = EMSG; /* found non-option */
|
||||||
|
if (flags & FLAG_ALLARGS) {
|
||||||
|
/*
|
||||||
|
* GNU extension:
|
||||||
|
* return non-option as argument to option 1
|
||||||
|
*/
|
||||||
|
optarg = nargv[optind++];
|
||||||
|
return (INORDER);
|
||||||
|
}
|
||||||
|
if (!(flags & FLAG_PERMUTE)) {
|
||||||
|
/*
|
||||||
|
* If no permutation wanted, stop parsing
|
||||||
|
* at first non-option.
|
||||||
|
*/
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
/* do permutation */
|
||||||
|
if (nonopt_start == -1)
|
||||||
|
nonopt_start = optind;
|
||||||
|
else if (nonopt_end != -1) {
|
||||||
|
permute_args(nonopt_start, nonopt_end,
|
||||||
|
optind, nargv);
|
||||||
|
nonopt_start = optind -
|
||||||
|
(nonopt_end - nonopt_start);
|
||||||
|
nonopt_end = -1;
|
||||||
|
}
|
||||||
|
optind++;
|
||||||
|
/* process next argument */
|
||||||
|
goto start;
|
||||||
|
}
|
||||||
|
if (nonopt_start != -1 && nonopt_end == -1)
|
||||||
|
nonopt_end = optind;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we have "-" do nothing, if "--" we are done.
|
||||||
|
*/
|
||||||
|
if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
|
||||||
|
optind++;
|
||||||
|
place = EMSG;
|
||||||
|
/*
|
||||||
|
* We found an option (--), so if we skipped
|
||||||
|
* non-options, we have to permute.
|
||||||
|
*/
|
||||||
|
if (nonopt_end != -1) {
|
||||||
|
permute_args(nonopt_start, nonopt_end,
|
||||||
|
optind, nargv);
|
||||||
|
optind -= nonopt_end - nonopt_start;
|
||||||
|
}
|
||||||
|
nonopt_start = nonopt_end = -1;
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check long options if:
|
||||||
|
* 1) we were passed some
|
||||||
|
* 2) the arg is not just "-"
|
||||||
|
* 3) either the arg starts with -- we are getopt_long_only()
|
||||||
|
*/
|
||||||
|
if (long_options != NULL && place != nargv[optind] &&
|
||||||
|
(*place == '-' || (flags & FLAG_LONGONLY))) {
|
||||||
|
short_too = 0;
|
||||||
|
if (*place == '-')
|
||||||
|
place++; /* --foo long option */
|
||||||
|
else if (*place != ':' && strchr(options, *place) != NULL)
|
||||||
|
short_too = 1; /* could be short option too */
|
||||||
|
|
||||||
|
optchar = parse_long_options(nargv, options, long_options,
|
||||||
|
idx, short_too);
|
||||||
|
if (optchar != -1) {
|
||||||
|
place = EMSG;
|
||||||
|
return (optchar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((optchar = (int)*place++) == (int)':' ||
|
||||||
|
(optchar == (int)'-' && *place != '\0') ||
|
||||||
|
(oli = strchr(options, optchar)) == NULL) {
|
||||||
|
/*
|
||||||
|
* If the user specified "-" and '-' isn't listed in
|
||||||
|
* options, return -1 (non-option) as per POSIX.
|
||||||
|
* Otherwise, it is an unknown option character (or ':').
|
||||||
|
*/
|
||||||
|
if (optchar == (int)'-' && *place == '\0')
|
||||||
|
return (-1);
|
||||||
|
if (!*place)
|
||||||
|
++optind;
|
||||||
|
if (PRINT_ERROR)
|
||||||
|
warnx(illoptchar, optchar);
|
||||||
|
optopt = optchar;
|
||||||
|
return (BADCH);
|
||||||
|
}
|
||||||
|
if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
|
||||||
|
/* -W long-option */
|
||||||
|
if (*place) /* no space */
|
||||||
|
/* NOTHING */;
|
||||||
|
else if (++optind >= nargc) { /* no arg */
|
||||||
|
place = EMSG;
|
||||||
|
if (PRINT_ERROR)
|
||||||
|
warnx(recargchar, optchar);
|
||||||
|
optopt = optchar;
|
||||||
|
return (BADARG);
|
||||||
|
} else /* white space */
|
||||||
|
place = nargv[optind];
|
||||||
|
optchar = parse_long_options(nargv, options, long_options,
|
||||||
|
idx, 0);
|
||||||
|
place = EMSG;
|
||||||
|
return (optchar);
|
||||||
|
}
|
||||||
|
if (*++oli != ':') { /* doesn't take argument */
|
||||||
|
if (!*place)
|
||||||
|
++optind;
|
||||||
|
} else { /* takes (optional) argument */
|
||||||
|
optarg = NULL;
|
||||||
|
if (*place) /* no white space */
|
||||||
|
optarg = place;
|
||||||
|
else if (oli[1] != ':') { /* arg not optional */
|
||||||
|
if (++optind >= nargc) { /* no arg */
|
||||||
|
place = EMSG;
|
||||||
|
if (PRINT_ERROR)
|
||||||
|
warnx(recargchar, optchar);
|
||||||
|
optopt = optchar;
|
||||||
|
return (BADARG);
|
||||||
|
} else
|
||||||
|
optarg = nargv[optind];
|
||||||
|
}
|
||||||
|
place = EMSG;
|
||||||
|
++optind;
|
||||||
|
}
|
||||||
|
/* dump back option letter */
|
||||||
|
return (optchar);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef REPLACE_GETOPT
|
||||||
|
/*
|
||||||
|
* getopt --
|
||||||
|
* Parse argc/argv argument vector.
|
||||||
|
*
|
||||||
|
* [eventually this will replace the BSD getopt]
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
getopt(int nargc, char * const *nargv, const char *options)
|
||||||
|
{
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We don't pass FLAG_PERMUTE to getopt_internal() since
|
||||||
|
* the BSD getopt(3) (unlike GNU) has never done this.
|
||||||
|
*
|
||||||
|
* Furthermore, since many privileged programs call getopt()
|
||||||
|
* before dropping privileges it makes sense to keep things
|
||||||
|
* as simple (and bug-free) as possible.
|
||||||
|
*/
|
||||||
|
return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
|
||||||
|
}
|
||||||
|
#endif /* REPLACE_GETOPT */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* getopt_long --
|
||||||
|
* Parse argc/argv argument vector.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
getopt_long(int nargc, char * const *nargv, const char *options,
|
||||||
|
const struct option *long_options, int *idx)
|
||||||
|
{
|
||||||
|
|
||||||
|
return (getopt_internal(nargc, nargv, options, long_options, idx,
|
||||||
|
FLAG_PERMUTE));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* getopt_long_only --
|
||||||
|
* Parse argc/argv argument vector.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
getopt_long_only(int nargc, char * const *nargv, const char *options,
|
||||||
|
const struct option *long_options, int *idx)
|
||||||
|
{
|
||||||
|
|
||||||
|
return (getopt_internal(nargc, nargv, options, long_options, idx,
|
||||||
|
FLAG_PERMUTE|FLAG_LONGONLY));
|
||||||
|
}
|
||||||
95
3rdparty/getopt/getopt.h
vendored
Normal file
95
3rdparty/getopt/getopt.h
vendored
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
#ifndef __GETOPT_H__
|
||||||
|
/**
|
||||||
|
* DISCLAIMER
|
||||||
|
* This file has no copyright assigned and is placed in the Public Domain.
|
||||||
|
* This file is part of the mingw-w64 runtime package.
|
||||||
|
*
|
||||||
|
* The mingw-w64 runtime package and its code is distributed in the hope that it
|
||||||
|
* will be useful but WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESSED OR
|
||||||
|
* IMPLIED ARE HEREBY DISCLAIMED. This includes but is not limited to
|
||||||
|
* warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define __GETOPT_H__
|
||||||
|
|
||||||
|
/* All the headers include this file. */
|
||||||
|
#include <crtdefs.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern int optind; /* index of first non-option in argv */
|
||||||
|
extern int optopt; /* single option character, as parsed */
|
||||||
|
extern int opterr; /* flag to enable built-in diagnostics... */
|
||||||
|
/* (user may set to zero, to suppress) */
|
||||||
|
|
||||||
|
extern char *optarg; /* pointer to argument of current option */
|
||||||
|
|
||||||
|
extern int getopt(int nargc, char * const *nargv, const char *options);
|
||||||
|
|
||||||
|
#ifdef _BSD_SOURCE
|
||||||
|
/*
|
||||||
|
* BSD adds the non-standard `optreset' feature, for reinitialisation
|
||||||
|
* of `getopt' parsing. We support this feature, for applications which
|
||||||
|
* proclaim their BSD heritage, before including this header; however,
|
||||||
|
* to maintain portability, developers are advised to avoid it.
|
||||||
|
*/
|
||||||
|
# define optreset __mingw_optreset
|
||||||
|
extern int optreset;
|
||||||
|
#endif
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
/*
|
||||||
|
* POSIX requires the `getopt' API to be specified in `unistd.h';
|
||||||
|
* thus, `unistd.h' includes this header. However, we do not want
|
||||||
|
* to expose the `getopt_long' or `getopt_long_only' APIs, when
|
||||||
|
* included in this manner. Thus, close the standard __GETOPT_H__
|
||||||
|
* declarations block, and open an additional __GETOPT_LONG_H__
|
||||||
|
* specific block, only when *not* __UNISTD_H_SOURCED__, in which
|
||||||
|
* to declare the extended API.
|
||||||
|
*/
|
||||||
|
#endif /* !defined(__GETOPT_H__) */
|
||||||
|
|
||||||
|
#if !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__)
|
||||||
|
#define __GETOPT_LONG_H__
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct option /* specification for a long form option... */
|
||||||
|
{
|
||||||
|
const char *name; /* option name, without leading hyphens */
|
||||||
|
int has_arg; /* does it take an argument? */
|
||||||
|
int *flag; /* where to save its status, or NULL */
|
||||||
|
int val; /* its associated status value */
|
||||||
|
};
|
||||||
|
|
||||||
|
enum /* permitted values for its `has_arg' field... */
|
||||||
|
{
|
||||||
|
no_argument = 0, /* option never takes an argument */
|
||||||
|
required_argument, /* option always requires an argument */
|
||||||
|
optional_argument /* option may take an argument */
|
||||||
|
};
|
||||||
|
|
||||||
|
extern int getopt_long(int nargc, char * const *nargv, const char *options,
|
||||||
|
const struct option *long_options, int *idx);
|
||||||
|
extern int getopt_long_only(int nargc, char * const *nargv, const char *options,
|
||||||
|
const struct option *long_options, int *idx);
|
||||||
|
/*
|
||||||
|
* Previous MinGW implementation had...
|
||||||
|
*/
|
||||||
|
#ifndef HAVE_DECL_GETOPT
|
||||||
|
/*
|
||||||
|
* ...for the long form API only; keep this for compatibility.
|
||||||
|
*/
|
||||||
|
# define HAVE_DECL_GETOPT 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) */
|
||||||
7
3rdparty/macdeployqt/CMakeLists.txt
vendored
Normal file
7
3rdparty/macdeployqt/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
add_executable(macdeployqt main.cpp shared.cpp)
|
||||||
|
target_link_libraries(macdeployqt PRIVATE
|
||||||
|
"-framework AppKit"
|
||||||
|
${QtCore_LIBRARIES}
|
||||||
|
)
|
||||||
|
|
||||||
|
#execute_process(COMMAND cp ${CMAKE_CURRENT_BINARY_DIR}/macdeployqt ${CMAKE_BINARY_DIR})
|
||||||
286
3rdparty/macdeployqt/main.cpp
vendored
Normal file
286
3rdparty/macdeployqt/main.cpp
vendored
Normal file
@@ -0,0 +1,286 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2016 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of the tools applications of the Qt Toolkit.
|
||||||
|
**
|
||||||
|
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
** $QT_END_LICENSE$
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#undef QT_NO_DEBUG_OUTPUT
|
||||||
|
#undef QT_NO_WARNING_OUTPUT
|
||||||
|
#undef QT_NO_INFO_OUTPUT
|
||||||
|
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QLibraryInfo>
|
||||||
|
|
||||||
|
#include "shared.h"
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
QCoreApplication app(argc, argv);
|
||||||
|
|
||||||
|
QString appBundlePath;
|
||||||
|
if (argc > 1)
|
||||||
|
appBundlePath = QString::fromLocal8Bit(argv[1]);
|
||||||
|
|
||||||
|
if (argc < 2 || appBundlePath.startsWith("-")) {
|
||||||
|
qDebug() << "Usage: macdeployqt app-bundle [options]";
|
||||||
|
qDebug() << "";
|
||||||
|
qDebug() << "Options:";
|
||||||
|
qDebug() << " -verbose=<0-3> : 0 = no output, 1 = error/warning (default), 2 = normal, 3 = debug";
|
||||||
|
qDebug() << " -no-plugins : Skip plugin deployment";
|
||||||
|
qDebug() << " -dmg : Create a .dmg disk image";
|
||||||
|
qDebug() << " -no-strip : Don't run 'strip' on the binaries";
|
||||||
|
qDebug() << " -use-debug-libs : Deploy with debug versions of frameworks and plugins (implies -no-strip)";
|
||||||
|
qDebug() << " -executable=<path> : Let the given executable use the deployed frameworks too";
|
||||||
|
qDebug() << " -qmldir=<path> : Scan for QML imports in the given path";
|
||||||
|
qDebug() << " -qmlimport=<path> : Add the given path to the QML module search locations";
|
||||||
|
qDebug() << " -always-overwrite : Copy files even if the target file exists";
|
||||||
|
qDebug() << " -codesign=<ident> : Run codesign with the given identity on all executables";
|
||||||
|
qDebug() << " -hardened-runtime : Enable Hardened Runtime when code signing";
|
||||||
|
qDebug() << " -timestamp : Include a secure timestamp when code signing (requires internet connection)";
|
||||||
|
qDebug() << " -sign-for-notarization=<ident>: Activate the necessary options for notarization (requires internet connection)";
|
||||||
|
qDebug() << " -appstore-compliant : Skip deployment of components that use private API";
|
||||||
|
qDebug() << " -libpath=<path> : Add the given path to the library search path";
|
||||||
|
qDebug() << " -fs=<filesystem> : Set the filesystem used for the .dmg disk image (defaults to HFS+)";
|
||||||
|
qDebug() << "";
|
||||||
|
qDebug() << "macdeployqt takes an application bundle as input and makes it";
|
||||||
|
qDebug() << "self-contained by copying in the Qt frameworks and plugins that";
|
||||||
|
qDebug() << "the application uses.";
|
||||||
|
qDebug() << "";
|
||||||
|
qDebug() << "Plugins related to a framework are copied in with the";
|
||||||
|
qDebug() << "framework. The accessibility, image formats, and text codec";
|
||||||
|
qDebug() << "plugins are always copied, unless \"-no-plugins\" is specified.";
|
||||||
|
qDebug() << "";
|
||||||
|
qDebug() << "Qt plugins may use private API and will cause the app to be";
|
||||||
|
qDebug() << "rejected from the Mac App store. MacDeployQt will print a warning";
|
||||||
|
qDebug() << "when known incompatible plugins are deployed. Use -appstore-compliant ";
|
||||||
|
qDebug() << "to skip these plugins. Currently two SQL plugins are known to";
|
||||||
|
qDebug() << "be incompatible: qsqlodbc and qsqlpsql.";
|
||||||
|
qDebug() << "";
|
||||||
|
qDebug() << "See the \"Deploying Applications on OS X\" topic in the";
|
||||||
|
qDebug() << "documentation for more information about deployment on OS X.";
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
appBundlePath = QDir::cleanPath(appBundlePath);
|
||||||
|
|
||||||
|
if (!QDir(appBundlePath).exists()) {
|
||||||
|
qDebug() << "Error: Could not find app bundle" << appBundlePath;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool plugins = true;
|
||||||
|
bool dmg = false;
|
||||||
|
QByteArray filesystem("HFS+");
|
||||||
|
bool useDebugLibs = false;
|
||||||
|
extern bool runStripEnabled;
|
||||||
|
extern bool alwaysOwerwriteEnabled;
|
||||||
|
extern QStringList librarySearchPath;
|
||||||
|
QStringList additionalExecutables;
|
||||||
|
bool qmldirArgumentUsed = false;
|
||||||
|
QStringList qmlDirs;
|
||||||
|
QStringList qmlImportPaths;
|
||||||
|
extern bool runCodesign;
|
||||||
|
extern QString codesignIdentiy;
|
||||||
|
extern bool hardenedRuntime;
|
||||||
|
extern bool appstoreCompliant;
|
||||||
|
extern bool deployFramework;
|
||||||
|
extern bool secureTimestamp;
|
||||||
|
|
||||||
|
for (int i = 2; i < argc; ++i) {
|
||||||
|
QByteArray argument = QByteArray(argv[i]);
|
||||||
|
if (argument == QByteArray("-no-plugins")) {
|
||||||
|
LogDebug() << "Argument found:" << argument;
|
||||||
|
plugins = false;
|
||||||
|
} else if (argument == QByteArray("-dmg")) {
|
||||||
|
LogDebug() << "Argument found:" << argument;
|
||||||
|
dmg = true;
|
||||||
|
} else if (argument == QByteArray("-no-strip")) {
|
||||||
|
LogDebug() << "Argument found:" << argument;
|
||||||
|
runStripEnabled = false;
|
||||||
|
} else if (argument == QByteArray("-use-debug-libs")) {
|
||||||
|
LogDebug() << "Argument found:" << argument;
|
||||||
|
useDebugLibs = true;
|
||||||
|
runStripEnabled = false;
|
||||||
|
} else if (argument.startsWith(QByteArray("-verbose"))) {
|
||||||
|
LogDebug() << "Argument found:" << argument;
|
||||||
|
int index = argument.indexOf("=");
|
||||||
|
bool ok = false;
|
||||||
|
int number = argument.mid(index+1).toInt(&ok);
|
||||||
|
if (!ok)
|
||||||
|
LogError() << "Could not parse verbose level";
|
||||||
|
else
|
||||||
|
logLevel = number;
|
||||||
|
} else if (argument.startsWith(QByteArray("-executable"))) {
|
||||||
|
LogDebug() << "Argument found:" << argument;
|
||||||
|
int index = argument.indexOf('=');
|
||||||
|
if (index == -1)
|
||||||
|
LogError() << "Missing executable path";
|
||||||
|
else
|
||||||
|
additionalExecutables << argument.mid(index+1);
|
||||||
|
} else if (argument.startsWith(QByteArray("-qmldir"))) {
|
||||||
|
LogDebug() << "Argument found:" << argument;
|
||||||
|
qmldirArgumentUsed = true;
|
||||||
|
int index = argument.indexOf('=');
|
||||||
|
if (index == -1)
|
||||||
|
LogError() << "Missing qml directory path";
|
||||||
|
else
|
||||||
|
qmlDirs << argument.mid(index+1);
|
||||||
|
} else if (argument.startsWith(QByteArray("-qmlimport"))) {
|
||||||
|
LogDebug() << "Argument found:" << argument;
|
||||||
|
int index = argument.indexOf('=');
|
||||||
|
if (index == -1)
|
||||||
|
LogError() << "Missing qml import path";
|
||||||
|
else
|
||||||
|
qmlImportPaths << argument.mid(index+1);
|
||||||
|
} else if (argument.startsWith(QByteArray("-libpath"))) {
|
||||||
|
LogDebug() << "Argument found:" << argument;
|
||||||
|
int index = argument.indexOf('=');
|
||||||
|
if (index == -1)
|
||||||
|
LogError() << "Missing library search path";
|
||||||
|
else
|
||||||
|
librarySearchPath << argument.mid(index+1);
|
||||||
|
} else if (argument == QByteArray("-always-overwrite")) {
|
||||||
|
LogDebug() << "Argument found:" << argument;
|
||||||
|
alwaysOwerwriteEnabled = true;
|
||||||
|
} else if (argument.startsWith(QByteArray("-codesign"))) {
|
||||||
|
LogDebug() << "Argument found:" << argument;
|
||||||
|
int index = argument.indexOf("=");
|
||||||
|
if (index < 0 || index >= argument.size()) {
|
||||||
|
LogError() << "Missing code signing identity";
|
||||||
|
} else {
|
||||||
|
runCodesign = true;
|
||||||
|
codesignIdentiy = argument.mid(index+1);
|
||||||
|
}
|
||||||
|
} else if (argument.startsWith(QByteArray("-sign-for-notarization"))) {
|
||||||
|
LogDebug() << "Argument found:" << argument;
|
||||||
|
int index = argument.indexOf("=");
|
||||||
|
if (index < 0 || index >= argument.size()) {
|
||||||
|
LogError() << "Missing code signing identity";
|
||||||
|
} else {
|
||||||
|
runCodesign = true;
|
||||||
|
hardenedRuntime = true;
|
||||||
|
secureTimestamp = true;
|
||||||
|
codesignIdentiy = argument.mid(index+1);
|
||||||
|
}
|
||||||
|
} else if (argument.startsWith(QByteArray("-hardened-runtime"))) {
|
||||||
|
LogDebug() << "Argument found:" << argument;
|
||||||
|
hardenedRuntime = true;
|
||||||
|
} else if (argument.startsWith(QByteArray("-timestamp"))) {
|
||||||
|
LogDebug() << "Argument found:" << argument;
|
||||||
|
secureTimestamp = true;
|
||||||
|
} else if (argument == QByteArray("-appstore-compliant")) {
|
||||||
|
LogDebug() << "Argument found:" << argument;
|
||||||
|
appstoreCompliant = true;
|
||||||
|
|
||||||
|
// Undocumented option, may not work as intended
|
||||||
|
} else if (argument == QByteArray("-deploy-framework")) {
|
||||||
|
LogDebug() << "Argument found:" << argument;
|
||||||
|
deployFramework = true;
|
||||||
|
|
||||||
|
} else if (argument.startsWith(QByteArray("-fs"))) {
|
||||||
|
LogDebug() << "Argument found:" << argument;
|
||||||
|
int index = argument.indexOf('=');
|
||||||
|
if (index == -1)
|
||||||
|
LogError() << "Missing filesystem type";
|
||||||
|
else
|
||||||
|
filesystem = argument.mid(index+1);
|
||||||
|
} else if (argument.startsWith("-")) {
|
||||||
|
LogError() << "Unknown argument" << argument << "\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DeploymentInfo deploymentInfo = deployQtFrameworks(appBundlePath, additionalExecutables, useDebugLibs);
|
||||||
|
|
||||||
|
if (deploymentInfo.isDebug)
|
||||||
|
useDebugLibs = true;
|
||||||
|
|
||||||
|
if (deployFramework && deploymentInfo.isFramework)
|
||||||
|
fixupFramework(appBundlePath);
|
||||||
|
|
||||||
|
// Convenience: Look for .qml files in the current directory if no -qmldir specified.
|
||||||
|
if (qmlDirs.isEmpty()) {
|
||||||
|
QDir dir;
|
||||||
|
if (!dir.entryList(QStringList() << QStringLiteral("*.qml")).isEmpty()) {
|
||||||
|
qmlDirs += QStringLiteral(".");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!qmlDirs.isEmpty()) {
|
||||||
|
bool ok = deployQmlImports(appBundlePath, deploymentInfo, qmlDirs, qmlImportPaths);
|
||||||
|
if (!ok && qmldirArgumentUsed)
|
||||||
|
return 1; // exit if the user explicitly asked for qml import deployment
|
||||||
|
|
||||||
|
// Update deploymentInfo.deployedFrameworks - the QML imports
|
||||||
|
// may have brought in extra frameworks as dependencies.
|
||||||
|
deploymentInfo.deployedFrameworks += findAppFrameworkNames(appBundlePath);
|
||||||
|
deploymentInfo.deployedFrameworks =
|
||||||
|
QSet<QString>(deploymentInfo.deployedFrameworks.begin(),
|
||||||
|
deploymentInfo.deployedFrameworks.end()).values();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle plugins
|
||||||
|
if (plugins) {
|
||||||
|
// Set the plugins search directory
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||||
|
deploymentInfo.pluginPath = QLibraryInfo::path(QLibraryInfo::PluginsPath);
|
||||||
|
#else
|
||||||
|
deploymentInfo.pluginPath = QLibraryInfo::location(QLibraryInfo::PluginsPath);
|
||||||
|
#endif
|
||||||
|
// Sanity checks
|
||||||
|
if (deploymentInfo.pluginPath.isEmpty()) {
|
||||||
|
LogError() << "Missing Qt plugins path\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!QDir(deploymentInfo.pluginPath).exists()) {
|
||||||
|
LogError() << "Plugins path does not exist" << deploymentInfo.pluginPath << "\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deploy plugins
|
||||||
|
Q_ASSERT(!deploymentInfo.pluginPath.isEmpty());
|
||||||
|
if (!deploymentInfo.pluginPath.isEmpty()) {
|
||||||
|
LogNormal();
|
||||||
|
deployPlugins(appBundlePath, deploymentInfo, useDebugLibs);
|
||||||
|
createQtConf(appBundlePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (runStripEnabled)
|
||||||
|
stripAppBinary(appBundlePath);
|
||||||
|
|
||||||
|
if (runCodesign)
|
||||||
|
codesign(codesignIdentiy, appBundlePath);
|
||||||
|
|
||||||
|
if (dmg) {
|
||||||
|
LogNormal();
|
||||||
|
createDiskImage(appBundlePath, filesystem);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
1802
3rdparty/macdeployqt/shared.cpp
vendored
Normal file
1802
3rdparty/macdeployqt/shared.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
141
3rdparty/macdeployqt/shared.h
vendored
Normal file
141
3rdparty/macdeployqt/shared.h
vendored
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2016 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of the tools applications of the Qt Toolkit.
|
||||||
|
**
|
||||||
|
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
** $QT_END_LICENSE$
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
#ifndef MAC_DEPLOMYMENT_SHARED_H
|
||||||
|
#define MAC_DEPLOMYMENT_SHARED_H
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QSet>
|
||||||
|
#include <QVersionNumber>
|
||||||
|
|
||||||
|
extern int logLevel;
|
||||||
|
#define LogError() if (logLevel < 0) {} else qDebug() << "ERROR:"
|
||||||
|
#define LogWarning() if (logLevel < 1) {} else qDebug() << "WARNING:"
|
||||||
|
#define LogNormal() if (logLevel < 2) {} else qDebug() << "Log:"
|
||||||
|
#define LogDebug() if (logLevel < 3) {} else qDebug() << "Log:"
|
||||||
|
|
||||||
|
extern bool runStripEnabled;
|
||||||
|
|
||||||
|
class FrameworkInfo
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool isDylib;
|
||||||
|
QString frameworkDirectory;
|
||||||
|
QString frameworkName;
|
||||||
|
QString frameworkPath;
|
||||||
|
QString binaryDirectory;
|
||||||
|
QString binaryName;
|
||||||
|
QString binaryPath;
|
||||||
|
QString rpathUsed;
|
||||||
|
QString version;
|
||||||
|
QString installName;
|
||||||
|
QString deployedInstallName;
|
||||||
|
QString sourceFilePath;
|
||||||
|
QString frameworkDestinationDirectory;
|
||||||
|
QString binaryDestinationDirectory;
|
||||||
|
|
||||||
|
bool isDebugLibrary() const
|
||||||
|
{
|
||||||
|
return binaryName.endsWith(QStringLiteral("_debug"));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class DylibInfo
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QString binaryPath;
|
||||||
|
QVersionNumber currentVersion;
|
||||||
|
QVersionNumber compatibilityVersion;
|
||||||
|
};
|
||||||
|
|
||||||
|
class OtoolInfo
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QString installName;
|
||||||
|
QString binaryPath;
|
||||||
|
QVersionNumber currentVersion;
|
||||||
|
QVersionNumber compatibilityVersion;
|
||||||
|
QList<DylibInfo> dependencies;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool operator==(const FrameworkInfo &a, const FrameworkInfo &b);
|
||||||
|
QDebug operator<<(QDebug debug, const FrameworkInfo &info);
|
||||||
|
|
||||||
|
class ApplicationBundleInfo
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QString path;
|
||||||
|
QString binaryPath;
|
||||||
|
QStringList libraryPaths;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DeploymentInfo
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QString qtPath;
|
||||||
|
QString pluginPath;
|
||||||
|
QStringList deployedFrameworks;
|
||||||
|
QList<QString> rpathsUsed;
|
||||||
|
bool useLoaderPath;
|
||||||
|
bool isFramework;
|
||||||
|
bool isDebug;
|
||||||
|
|
||||||
|
bool containsModule(const QString &module, const QString &libInFix) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline QDebug operator<<(QDebug debug, const ApplicationBundleInfo &info);
|
||||||
|
|
||||||
|
OtoolInfo findDependencyInfo(const QString &binaryPath);
|
||||||
|
FrameworkInfo parseOtoolLibraryLine(const QString &line, const QString &appBundlePath, const QList<QString> &rpaths, bool useDebugLibs);
|
||||||
|
QString findAppBinary(const QString &appBundlePath);
|
||||||
|
QList<FrameworkInfo> getQtFrameworks(const QString &path, const QString &appBundlePath, const QList<QString> &rpaths, bool useDebugLibs);
|
||||||
|
QList<FrameworkInfo> getQtFrameworks(const QStringList &otoolLines, const QString &appBundlePath, const QList<QString> &rpaths, bool useDebugLibs);
|
||||||
|
QString copyFramework(const FrameworkInfo &framework, const QString path);
|
||||||
|
DeploymentInfo deployQtFrameworks(const QString &appBundlePath, const QStringList &additionalExecutables, bool useDebugLibs);
|
||||||
|
DeploymentInfo deployQtFrameworks(QList<FrameworkInfo> frameworks,const QString &bundlePath, const QStringList &binaryPaths, bool useDebugLibs, bool useLoaderPath);
|
||||||
|
void createQtConf(const QString &appBundlePath);
|
||||||
|
void deployPlugins(const QString &appBundlePath, DeploymentInfo deploymentInfo, bool useDebugLibs);
|
||||||
|
bool deployQmlImports(const QString &appBundlePath, DeploymentInfo deploymentInfo, QStringList &qmlDirs, QStringList &qmlImportPaths);
|
||||||
|
void changeIdentification(const QString &id, const QString &binaryPath);
|
||||||
|
void changeInstallName(const QString &oldName, const QString &newName, const QString &binaryPath);
|
||||||
|
void runStrip(const QString &binaryPath);
|
||||||
|
void stripAppBinary(const QString &bundlePath);
|
||||||
|
QString findAppBinary(const QString &appBundlePath);
|
||||||
|
QStringList findAppFrameworkNames(const QString &appBundlePath);
|
||||||
|
QStringList findAppFrameworkPaths(const QString &appBundlePath);
|
||||||
|
void codesignFile(const QString &identity, const QString &filePath);
|
||||||
|
QSet<QString> codesignBundle(const QString &identity,
|
||||||
|
const QString &appBundlePath,
|
||||||
|
QList<QString> additionalBinariesContainingRpaths);
|
||||||
|
void codesign(const QString &identity, const QString &appBundlePath);
|
||||||
|
void createDiskImage(const QString &appBundlePath, const QString &filesystemType);
|
||||||
|
void fixupFramework(const QString &appBundlePath);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
35
3rdparty/qocoa/CMakeLists.txt
vendored
35
3rdparty/qocoa/CMakeLists.txt
vendored
@@ -1,35 +0,0 @@
|
|||||||
cmake_minimum_required(VERSION 2.8.11)
|
|
||||||
set(CMAKE_CXX_STANDARD 11)
|
|
||||||
|
|
||||||
set(SOURCES)
|
|
||||||
|
|
||||||
set(HEADERS
|
|
||||||
qsearchfield.h
|
|
||||||
qbutton.h
|
|
||||||
qprogressindicatorspinning.h
|
|
||||||
)
|
|
||||||
|
|
||||||
qt5_wrap_cpp(MOC_SOURCES ${HEADERS})
|
|
||||||
|
|
||||||
if(APPLE)
|
|
||||||
list(APPEND SOURCES
|
|
||||||
qsearchfield_mac.mm
|
|
||||||
qbutton_mac.mm
|
|
||||||
qprogressindicatorspinning_mac.mm
|
|
||||||
)
|
|
||||||
else()
|
|
||||||
list(APPEND SOURCES
|
|
||||||
qsearchfield_nonmac.cpp
|
|
||||||
qbutton_nonmac.cpp
|
|
||||||
qprogressindicatorspinning_nonmac.cpp
|
|
||||||
)
|
|
||||||
set(RESOURCES
|
|
||||||
qsearchfield_nonmac.qrc
|
|
||||||
qprogressindicatorspinning_nonmac.qrc
|
|
||||||
)
|
|
||||||
qt5_add_resources(RESOURCES_SOURCES ${RESOURCES})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
add_library(Qocoa STATIC ${SOURCES} ${MOC_SOURCES} ${RESOURCES_SOURCES})
|
|
||||||
target_link_libraries(Qocoa ${QT_LIBRARIES})
|
|
||||||
|
|
||||||
38
3rdparty/qocoa/README.md
vendored
38
3rdparty/qocoa/README.md
vendored
@@ -1,38 +0,0 @@
|
|||||||
# Qocoa
|
|
||||||
Qocoa is a collection of Qt wrappers for OSX's Cocoa widgets.
|
|
||||||
|
|
||||||
## Features
|
|
||||||
- basic fallback to sensible Qt types on non-OSX platforms
|
|
||||||
- shared class headers which expose no implementation details
|
|
||||||
- typical Qt signal/slot-based API
|
|
||||||
- trivial to import into projects (class header/implementation, [single shared global header](https://github.com/mikemcquaid/Qocoa/blob/master/qocoa_mac.h))
|
|
||||||
|
|
||||||
## Building
|
|
||||||
```
|
|
||||||
git clone git://github.com/mikemcquaid/Qocoa.git
|
|
||||||
cd Qocoa
|
|
||||||
qmake # or cmake .
|
|
||||||
make
|
|
||||||
```
|
|
||||||
|
|
||||||
## Status
|
|
||||||
I'm not personally working on this any more but will accept pull-requests.
|
|
||||||
|
|
||||||
[](https://travis-ci.org/MikeMcQuaid/Qocoa)
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
For each class you want to use copy the [`qocoa_mac.h`](https://github.com/mikemcquaid/Qocoa/blob/master/qocoa_mac.h), `$CLASS.h`, `$CLASS_mac.*` and `$CLASS_nonmac.*` files into your source tree and add them to your buildsystem. Examples are provided for [CMake](https://github.com/mikemcquaid/Qocoa/blob/master/CMakeLists.txt) and [QMake](https://github.com/mikemcquaid/Qocoa/blob/master/Qocoa.pro).
|
|
||||||
|
|
||||||
## Contact
|
|
||||||
[Mike McQuaid](mailto:mike@mikemcquaid.com)
|
|
||||||
|
|
||||||
## License
|
|
||||||
Qocoa is licensed under the [MIT License](http://en.wikipedia.org/wiki/MIT_License).
|
|
||||||
The full license text is available in [LICENSE.txt](https://github.com/mikemcquaid/Qocoa/blob/master/LICENSE.txt).
|
|
||||||
|
|
||||||
Magnifier and EditClear icons taken from [QtCreator](http://qt-project.org/) and are licensed under the [LGPL](http://www.gnu.org/copyleft/lesser.html).
|
|
||||||
|
|
||||||
Other icons are taken from the [Oxygen Project](http://www.oxygen-icons.org/) and are licensed under the [Creative Commons Attribution-ShareAlike 3.0 License](http://creativecommons.org/licenses/by-sa/3.0/).
|
|
||||||
|
|
||||||
## Gallery
|
|
||||||

|
|
||||||
13
3rdparty/qocoa/TODO.md
vendored
13
3rdparty/qocoa/TODO.md
vendored
@@ -1,13 +0,0 @@
|
|||||||
Widgets I hope to implement (or at least investigate):
|
|
||||||
|
|
||||||
- NSTokenField
|
|
||||||
- NSSegmentedControl
|
|
||||||
- NSLevelIndicator
|
|
||||||
- NSPathControl
|
|
||||||
- NSSlider (Circular)
|
|
||||||
- NSSplitView
|
|
||||||
- NSTextFinder
|
|
||||||
- NSOutlineView in an NSScrollView (Source List)
|
|
||||||
- NSDrawer
|
|
||||||
- PDFView
|
|
||||||
- WebView
|
|
||||||
49
3rdparty/qocoa/qbutton.h
vendored
49
3rdparty/qocoa/qbutton.h
vendored
@@ -1,49 +0,0 @@
|
|||||||
#ifndef QBUTTON_H
|
|
||||||
#define QBUTTON_H
|
|
||||||
|
|
||||||
#include <QWidget>
|
|
||||||
#include <QPointer>
|
|
||||||
|
|
||||||
class QButtonPrivate;
|
|
||||||
class QButton : public QWidget
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
// Matches NSBezelStyle
|
|
||||||
enum BezelStyle {
|
|
||||||
Rounded = 1,
|
|
||||||
RegularSquare = 2,
|
|
||||||
Disclosure = 5,
|
|
||||||
ShadowlessSquare = 6,
|
|
||||||
Circular = 7,
|
|
||||||
TexturedSquare = 8,
|
|
||||||
HelpButton = 9,
|
|
||||||
SmallSquare = 10,
|
|
||||||
TexturedRounded = 11,
|
|
||||||
RoundRect = 12,
|
|
||||||
Recessed = 13,
|
|
||||||
RoundedDisclosure = 14,
|
|
||||||
#ifdef __MAC_10_7
|
|
||||||
Inline = 15
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
explicit QButton(QWidget *parent, BezelStyle bezelStyle = Rounded);
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void setText(const QString &text);
|
|
||||||
void setImage(const QPixmap &image);
|
|
||||||
void setChecked(bool checked);
|
|
||||||
|
|
||||||
public:
|
|
||||||
void setCheckable(bool checkable);
|
|
||||||
bool isChecked();
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void clicked(bool checked = false);
|
|
||||||
|
|
||||||
private:
|
|
||||||
friend class QButtonPrivate;
|
|
||||||
QPointer<QButtonPrivate> pimpl;
|
|
||||||
};
|
|
||||||
#endif // QBUTTON_H
|
|
||||||
229
3rdparty/qocoa/qbutton_mac.mm
vendored
229
3rdparty/qocoa/qbutton_mac.mm
vendored
@@ -1,229 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (C) 2011 by Mike McQuaid
|
|
||||||
|
|
||||||
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 "qbutton.h"
|
|
||||||
|
|
||||||
#include "qocoa_mac.h"
|
|
||||||
|
|
||||||
#import "Foundation/NSAutoreleasePool.h"
|
|
||||||
#import "AppKit/NSButton.h"
|
|
||||||
#import "AppKit/NSFont.h"
|
|
||||||
|
|
||||||
class QButtonPrivate : public QObject
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
QButtonPrivate(QButton *qButton, NSButton *nsButton, QButton::BezelStyle bezelStyle)
|
|
||||||
: QObject(qButton), qButton(qButton), nsButton(nsButton)
|
|
||||||
{
|
|
||||||
switch(bezelStyle) {
|
|
||||||
case QButton::Disclosure:
|
|
||||||
case QButton::Circular:
|
|
||||||
#ifdef __MAC_10_7
|
|
||||||
case QButton::Inline:
|
|
||||||
#endif
|
|
||||||
case QButton::RoundedDisclosure:
|
|
||||||
case QButton::HelpButton:
|
|
||||||
[nsButton setTitle:@""];
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
NSFont* font = 0;
|
|
||||||
switch(bezelStyle) {
|
|
||||||
case QButton::RoundRect:
|
|
||||||
font = [NSFont fontWithName:@"Lucida Grande" size:12];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case QButton::Recessed:
|
|
||||||
font = [NSFont fontWithName:@"Lucida Grande Bold" size:12];
|
|
||||||
break;
|
|
||||||
|
|
||||||
#ifdef __MAC_10_7
|
|
||||||
case QButton::Inline:
|
|
||||||
font = [NSFont boldSystemFontOfSize:[NSFont systemFontSizeForControlSize:NSSmallControlSize]];
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
default:
|
|
||||||
font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSRegularControlSize]];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
[nsButton setFont:font];
|
|
||||||
|
|
||||||
switch(bezelStyle) {
|
|
||||||
case QButton::Rounded:
|
|
||||||
qButton->setMinimumWidth(40);
|
|
||||||
qButton->setFixedHeight(24);
|
|
||||||
qButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
|
|
||||||
break;
|
|
||||||
case QButton::RegularSquare:
|
|
||||||
case QButton::TexturedSquare:
|
|
||||||
qButton->setMinimumSize(14, 23);
|
|
||||||
qButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
|
||||||
break;
|
|
||||||
case QButton::ShadowlessSquare:
|
|
||||||
qButton->setMinimumSize(5, 25);
|
|
||||||
qButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
|
||||||
break;
|
|
||||||
case QButton::SmallSquare:
|
|
||||||
qButton->setMinimumSize(4, 21);
|
|
||||||
qButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
|
||||||
break;
|
|
||||||
case QButton::TexturedRounded:
|
|
||||||
qButton->setMinimumSize(10, 22);
|
|
||||||
qButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
|
||||||
break;
|
|
||||||
case QButton::RoundRect:
|
|
||||||
case QButton::Recessed:
|
|
||||||
qButton->setMinimumWidth(16);
|
|
||||||
qButton->setFixedHeight(18);
|
|
||||||
qButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
|
|
||||||
break;
|
|
||||||
case QButton::Disclosure:
|
|
||||||
qButton->setMinimumWidth(13);
|
|
||||||
qButton->setFixedHeight(13);
|
|
||||||
qButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
|
|
||||||
break;
|
|
||||||
case QButton::Circular:
|
|
||||||
qButton->setMinimumSize(16, 16);
|
|
||||||
qButton->setMaximumHeight(40);
|
|
||||||
qButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
|
||||||
break;
|
|
||||||
case QButton::HelpButton:
|
|
||||||
case QButton::RoundedDisclosure:
|
|
||||||
qButton->setMinimumWidth(22);
|
|
||||||
qButton->setFixedHeight(22);
|
|
||||||
qButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
|
|
||||||
break;
|
|
||||||
#ifdef __MAC_10_7
|
|
||||||
case QButton::Inline:
|
|
||||||
qButton->setMinimumWidth(10);
|
|
||||||
qButton->setFixedHeight(16);
|
|
||||||
qButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(bezelStyle) {
|
|
||||||
case QButton::Recessed:
|
|
||||||
[nsButton setButtonType:NSPushOnPushOffButton];
|
|
||||||
case QButton::Disclosure:
|
|
||||||
[nsButton setButtonType:NSOnOffButton];
|
|
||||||
default:
|
|
||||||
[nsButton setButtonType:NSMomentaryPushInButton];
|
|
||||||
}
|
|
||||||
|
|
||||||
[nsButton setBezelStyle:(__bridge NSBezelStyle)bezelStyle];
|
|
||||||
}
|
|
||||||
|
|
||||||
void clicked()
|
|
||||||
{
|
|
||||||
emit qButton->clicked(qButton->isChecked());
|
|
||||||
}
|
|
||||||
|
|
||||||
~QButtonPrivate() {
|
|
||||||
[[nsButton target] release];
|
|
||||||
[nsButton setTarget:nil];
|
|
||||||
}
|
|
||||||
|
|
||||||
QButton *qButton;
|
|
||||||
NSButton *nsButton;
|
|
||||||
};
|
|
||||||
|
|
||||||
@interface QButtonTarget : NSObject
|
|
||||||
{
|
|
||||||
@public
|
|
||||||
QPointer<QButtonPrivate> pimpl;
|
|
||||||
}
|
|
||||||
-(void)clicked;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation QButtonTarget
|
|
||||||
-(void)clicked {
|
|
||||||
Q_ASSERT(pimpl);
|
|
||||||
if (pimpl)
|
|
||||||
pimpl->clicked();
|
|
||||||
}
|
|
||||||
@end
|
|
||||||
|
|
||||||
QButton::QButton(QWidget *parent, BezelStyle bezelStyle) : QWidget(parent)
|
|
||||||
{
|
|
||||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
|
||||||
|
|
||||||
NSButton *button = [[NSButton alloc] init];
|
|
||||||
pimpl = new QButtonPrivate(this, button, bezelStyle);
|
|
||||||
|
|
||||||
QButtonTarget *target = [[QButtonTarget alloc] init];
|
|
||||||
target->pimpl = pimpl;
|
|
||||||
[button setTarget:target];
|
|
||||||
|
|
||||||
[button setAction:@selector(clicked)];
|
|
||||||
|
|
||||||
setupLayout(button, this);
|
|
||||||
|
|
||||||
[button release];
|
|
||||||
|
|
||||||
[pool drain];
|
|
||||||
}
|
|
||||||
|
|
||||||
void QButton::setText(const QString &text)
|
|
||||||
{
|
|
||||||
Q_ASSERT(pimpl);
|
|
||||||
if (!pimpl)
|
|
||||||
return;
|
|
||||||
|
|
||||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
|
||||||
[pimpl->nsButton setTitle:fromQString(text)];
|
|
||||||
[pool drain];
|
|
||||||
}
|
|
||||||
|
|
||||||
void QButton::setImage(const QPixmap &image)
|
|
||||||
{
|
|
||||||
Q_ASSERT(pimpl);
|
|
||||||
if (pimpl)
|
|
||||||
[pimpl->nsButton setImage:fromQPixmap(image)];
|
|
||||||
}
|
|
||||||
|
|
||||||
void QButton::setChecked(bool checked)
|
|
||||||
{
|
|
||||||
Q_ASSERT(pimpl);
|
|
||||||
if (pimpl)
|
|
||||||
[pimpl->nsButton setState:checked];
|
|
||||||
}
|
|
||||||
|
|
||||||
void QButton::setCheckable(bool checkable)
|
|
||||||
{
|
|
||||||
const NSInteger cellMask = checkable ? NSChangeBackgroundCellMask : NSNoCellMask;
|
|
||||||
|
|
||||||
Q_ASSERT(pimpl);
|
|
||||||
if (pimpl)
|
|
||||||
[[pimpl->nsButton cell] setShowsStateBy:cellMask];
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QButton::isChecked()
|
|
||||||
{
|
|
||||||
Q_ASSERT(pimpl);
|
|
||||||
if (!pimpl)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return [pimpl->nsButton state];
|
|
||||||
}
|
|
||||||
89
3rdparty/qocoa/qbutton_nonmac.cpp
vendored
89
3rdparty/qocoa/qbutton_nonmac.cpp
vendored
@@ -1,89 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (C) 2011 by Mike McQuaid
|
|
||||||
|
|
||||||
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 "qbutton.h"
|
|
||||||
|
|
||||||
#include <QToolBar>
|
|
||||||
#include <QToolButton>
|
|
||||||
#include <QPushButton>
|
|
||||||
#include <QVBoxLayout>
|
|
||||||
|
|
||||||
class QButtonPrivate : public QObject
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
QButtonPrivate(QButton *button, QAbstractButton *abstractButton)
|
|
||||||
: QObject(button), abstractButton(abstractButton) {}
|
|
||||||
QPointer<QAbstractButton> abstractButton;
|
|
||||||
};
|
|
||||||
|
|
||||||
QButton::QButton(QWidget *parent, BezelStyle) : QWidget(parent)
|
|
||||||
{
|
|
||||||
QAbstractButton *button = 0;
|
|
||||||
if (qobject_cast<QToolBar*>(parent))
|
|
||||||
button = new QToolButton(this);
|
|
||||||
else
|
|
||||||
button = new QPushButton(this);
|
|
||||||
connect(button, SIGNAL(clicked()),
|
|
||||||
this, SIGNAL(clicked()));
|
|
||||||
pimpl = new QButtonPrivate(this, button);
|
|
||||||
|
|
||||||
QVBoxLayout *layout = new QVBoxLayout(this);
|
|
||||||
layout->setMargin(0);
|
|
||||||
layout->addWidget(button);
|
|
||||||
}
|
|
||||||
|
|
||||||
void QButton::setText(const QString &text)
|
|
||||||
{
|
|
||||||
Q_ASSERT(pimpl);
|
|
||||||
if (pimpl)
|
|
||||||
pimpl->abstractButton->setText(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
void QButton::setImage(const QPixmap &image)
|
|
||||||
{
|
|
||||||
Q_ASSERT(pimpl);
|
|
||||||
if (pimpl)
|
|
||||||
pimpl->abstractButton->setIcon(image);
|
|
||||||
}
|
|
||||||
|
|
||||||
void QButton::setChecked(bool checked)
|
|
||||||
{
|
|
||||||
Q_ASSERT(pimpl);
|
|
||||||
if (pimpl)
|
|
||||||
pimpl->abstractButton->setChecked(checked);
|
|
||||||
}
|
|
||||||
|
|
||||||
void QButton::setCheckable(bool checkable)
|
|
||||||
{
|
|
||||||
Q_ASSERT(pimpl);
|
|
||||||
if (pimpl)
|
|
||||||
pimpl->abstractButton->setCheckable(checkable);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QButton::isChecked()
|
|
||||||
{
|
|
||||||
Q_ASSERT(pimpl);
|
|
||||||
if (!pimpl)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return pimpl->abstractButton->isChecked();
|
|
||||||
}
|
|
||||||
29
3rdparty/qocoa/qprogressindicatorspinning.h
vendored
29
3rdparty/qocoa/qprogressindicatorspinning.h
vendored
@@ -1,29 +0,0 @@
|
|||||||
#ifndef QPROGRESSINDICATORSPINNING_H
|
|
||||||
#define QPROGRESSINDICATORSPINNING_H
|
|
||||||
|
|
||||||
#include <QWidget>
|
|
||||||
#include <QPointer>
|
|
||||||
|
|
||||||
class QProgressIndicatorSpinningPrivate;
|
|
||||||
class QProgressIndicatorSpinning : public QWidget
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
// Matches NSProgressIndicatorThickness
|
|
||||||
enum Thickness {
|
|
||||||
Default = 14,
|
|
||||||
Small = 10,
|
|
||||||
Large = 18,
|
|
||||||
Aqua = 12
|
|
||||||
};
|
|
||||||
|
|
||||||
explicit QProgressIndicatorSpinning(QWidget *parent,
|
|
||||||
Thickness thickness = Default);
|
|
||||||
public slots:
|
|
||||||
void animate(bool animate = true);
|
|
||||||
private:
|
|
||||||
friend class QProgressIndicatorSpinningPrivate;
|
|
||||||
QPointer<QProgressIndicatorSpinningPrivate> pimpl;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // QPROGRESSINDICATORSPINNING_H
|
|
||||||
70
3rdparty/qocoa/qprogressindicatorspinning_mac.mm
vendored
70
3rdparty/qocoa/qprogressindicatorspinning_mac.mm
vendored
@@ -1,70 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (C) 2011 by Mike McQuaid
|
|
||||||
|
|
||||||
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 "qprogressindicatorspinning.h"
|
|
||||||
|
|
||||||
#include "qocoa_mac.h"
|
|
||||||
|
|
||||||
#import "Foundation/NSAutoreleasePool.h"
|
|
||||||
#import "AppKit/NSProgressIndicator.h"
|
|
||||||
|
|
||||||
class QProgressIndicatorSpinningPrivate : public QObject
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
QProgressIndicatorSpinningPrivate(QProgressIndicatorSpinning *qProgressIndicatorSpinning,
|
|
||||||
NSProgressIndicator *nsProgressIndicator)
|
|
||||||
: QObject(qProgressIndicatorSpinning), nsProgressIndicator(nsProgressIndicator) {}
|
|
||||||
|
|
||||||
NSProgressIndicator *nsProgressIndicator;
|
|
||||||
};
|
|
||||||
|
|
||||||
QProgressIndicatorSpinning::QProgressIndicatorSpinning(QWidget *parent,
|
|
||||||
Thickness thickness)
|
|
||||||
: QWidget(parent)
|
|
||||||
{
|
|
||||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
|
||||||
|
|
||||||
NSProgressIndicator *progress = [[NSProgressIndicator alloc] init];
|
|
||||||
[progress setStyle:NSProgressIndicatorSpinningStyle];
|
|
||||||
|
|
||||||
pimpl = new QProgressIndicatorSpinningPrivate(this, progress);
|
|
||||||
|
|
||||||
setupLayout(progress, this);
|
|
||||||
|
|
||||||
setFixedSize(thickness, thickness);
|
|
||||||
|
|
||||||
[progress release];
|
|
||||||
|
|
||||||
[pool drain];
|
|
||||||
}
|
|
||||||
|
|
||||||
void QProgressIndicatorSpinning::animate(bool animate)
|
|
||||||
{
|
|
||||||
Q_ASSERT(pimpl);
|
|
||||||
if (!pimpl)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (animate)
|
|
||||||
[pimpl->nsProgressIndicator startAnimation:nil];
|
|
||||||
else
|
|
||||||
[pimpl->nsProgressIndicator stopAnimation:nil];
|
|
||||||
}
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (C) 2011 by Mike McQuaid
|
|
||||||
|
|
||||||
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 "qprogressindicatorspinning.h"
|
|
||||||
|
|
||||||
#include <QVBoxLayout>
|
|
||||||
#include <QMovie>
|
|
||||||
#include <QLabel>
|
|
||||||
|
|
||||||
class QProgressIndicatorSpinningPrivate : public QObject
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
QProgressIndicatorSpinningPrivate(QProgressIndicatorSpinning *qProgressIndicatorSpinning,
|
|
||||||
QMovie *movie)
|
|
||||||
: QObject(qProgressIndicatorSpinning), movie(movie) {}
|
|
||||||
|
|
||||||
QPointer<QMovie> movie;
|
|
||||||
};
|
|
||||||
|
|
||||||
QProgressIndicatorSpinning::QProgressIndicatorSpinning(QWidget *parent,
|
|
||||||
Thickness thickness)
|
|
||||||
: QWidget(parent)
|
|
||||||
{
|
|
||||||
QVBoxLayout *layout = new QVBoxLayout(this);
|
|
||||||
layout->setMargin(0);
|
|
||||||
|
|
||||||
QSize size(thickness, thickness);
|
|
||||||
QMovie *movie = new QMovie(this);
|
|
||||||
movie->setFileName(":/Qocoa/qprogressindicatorspinning_nonmac.gif");
|
|
||||||
movie->setScaledSize(size);
|
|
||||||
// Roughly match OSX speed.
|
|
||||||
movie->setSpeed(200);
|
|
||||||
pimpl = new QProgressIndicatorSpinningPrivate(this, movie);
|
|
||||||
|
|
||||||
QLabel *label = new QLabel(this);
|
|
||||||
label->setMovie(movie);
|
|
||||||
|
|
||||||
layout->addWidget(label);
|
|
||||||
setFixedSize(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void QProgressIndicatorSpinning::animate(bool animate)
|
|
||||||
{
|
|
||||||
Q_ASSERT(pimpl && pimpl->movie);
|
|
||||||
if (!(pimpl && pimpl->movie))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (animate)
|
|
||||||
pimpl->movie->start();
|
|
||||||
else
|
|
||||||
pimpl->movie->stop();
|
|
||||||
}
|
|
||||||
BIN
3rdparty/qocoa/qprogressindicatorspinning_nonmac.gif
vendored
BIN
3rdparty/qocoa/qprogressindicatorspinning_nonmac.gif
vendored
Binary file not shown.
|
Before Width: | Height: | Size: 3.1 KiB |
@@ -1,5 +0,0 @@
|
|||||||
<RCC>
|
|
||||||
<qresource prefix="/Qocoa">
|
|
||||||
<file>qprogressindicatorspinning_nonmac.gif</file>
|
|
||||||
</qresource>
|
|
||||||
</RCC>
|
|
||||||
161
3rdparty/qocoa/qsearchfield_nonmac.cpp
vendored
161
3rdparty/qocoa/qsearchfield_nonmac.cpp
vendored
@@ -1,161 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (C) 2011 by Mike McQuaid
|
|
||||||
|
|
||||||
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 "qsearchfield.h"
|
|
||||||
|
|
||||||
#include <QApplication>
|
|
||||||
#include <QDesktopWidget>
|
|
||||||
#include <QLineEdit>
|
|
||||||
#include <QVBoxLayout>
|
|
||||||
#include <QToolButton>
|
|
||||||
#include <QStyle>
|
|
||||||
#include <QEvent>
|
|
||||||
|
|
||||||
#include <QDir>
|
|
||||||
#include <QDebug>
|
|
||||||
|
|
||||||
#include "../../src/core/iconloader.h"
|
|
||||||
|
|
||||||
class QSearchFieldPrivate : public QObject {
|
|
||||||
public:
|
|
||||||
QSearchFieldPrivate(QSearchField *searchField, QLineEdit *lineEdit, QToolButton *clearButton)
|
|
||||||
: QObject(searchField), lineEdit(lineEdit), clearButton(clearButton) {}
|
|
||||||
|
|
||||||
int lineEditFrameWidth() const {
|
|
||||||
return lineEdit->style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
|
|
||||||
}
|
|
||||||
|
|
||||||
int clearButtonPaddedWidth() const {
|
|
||||||
return clearButton->width() + lineEditFrameWidth() * 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
int clearButtonPaddedHeight() const {
|
|
||||||
return clearButton->height() + lineEditFrameWidth() * 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPointer<QLineEdit> lineEdit;
|
|
||||||
QPointer<QToolButton> clearButton;
|
|
||||||
};
|
|
||||||
|
|
||||||
QSearchField::QSearchField(QWidget *parent) : QWidget(parent) {
|
|
||||||
|
|
||||||
QLineEdit *lineEdit = new QLineEdit(this);
|
|
||||||
connect(lineEdit, SIGNAL(textChanged(QString)), this, SIGNAL(textChanged(QString)));
|
|
||||||
connect(lineEdit, SIGNAL(editingFinished()), this, SIGNAL(editingFinished()));
|
|
||||||
connect(lineEdit, SIGNAL(returnPressed()), this, SIGNAL(returnPressed()));
|
|
||||||
connect(lineEdit, SIGNAL(textChanged(QString)), this, SLOT(setText(QString)));
|
|
||||||
|
|
||||||
QToolButton *clearButton = new QToolButton(this);
|
|
||||||
QIcon clearIcon(IconLoader::Load("edit-clear-locationbar-ltr"));
|
|
||||||
|
|
||||||
clearButton->setIcon(clearIcon);
|
|
||||||
clearButton->setIconSize(QSize(16, 16));
|
|
||||||
clearButton->setStyleSheet("border: none; padding: 0px;");
|
|
||||||
clearButton->resize(clearButton->sizeHint());
|
|
||||||
|
|
||||||
connect(clearButton, SIGNAL(clicked()), this, SLOT(clear()));
|
|
||||||
|
|
||||||
pimpl = new QSearchFieldPrivate(this, lineEdit, clearButton);
|
|
||||||
|
|
||||||
const int frame_width = lineEdit->style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
|
|
||||||
|
|
||||||
lineEdit->setStyleSheet(QString("QLineEdit { padding-left: %1px; } ").arg(clearButton->width()));
|
|
||||||
const int width = frame_width + qMax(lineEdit->minimumSizeHint().width(), pimpl->clearButtonPaddedWidth());
|
|
||||||
const int height = frame_width + qMax(lineEdit->minimumSizeHint().height(), pimpl->clearButtonPaddedHeight());
|
|
||||||
lineEdit->setMinimumSize(width, height);
|
|
||||||
|
|
||||||
QVBoxLayout *layout = new QVBoxLayout(this);
|
|
||||||
layout->setMargin(0);
|
|
||||||
layout->addWidget(lineEdit);
|
|
||||||
|
|
||||||
lineEdit->installEventFilter(this);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void QSearchField::setText(const QString &text) {
|
|
||||||
|
|
||||||
Q_ASSERT(pimpl && pimpl->clearButton && pimpl->lineEdit);
|
|
||||||
if (!(pimpl && pimpl->clearButton && pimpl->lineEdit)) return;
|
|
||||||
if (text != this->text()) pimpl->lineEdit->setText(text);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void QSearchField::setPlaceholderText(const QString &text) {
|
|
||||||
Q_ASSERT(pimpl && pimpl->lineEdit);
|
|
||||||
if (!(pimpl && pimpl->lineEdit)) return;
|
|
||||||
pimpl->lineEdit->setPlaceholderText(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString QSearchField::placeholderText() const {
|
|
||||||
return pimpl->lineEdit->placeholderText();
|
|
||||||
}
|
|
||||||
|
|
||||||
void QSearchField::setFocus(Qt::FocusReason reason) {
|
|
||||||
Q_ASSERT(pimpl && pimpl->lineEdit);
|
|
||||||
if (pimpl && pimpl->lineEdit) pimpl->lineEdit->setFocus(reason);
|
|
||||||
}
|
|
||||||
|
|
||||||
void QSearchField::setFocus() {
|
|
||||||
setFocus(Qt::OtherFocusReason);
|
|
||||||
}
|
|
||||||
|
|
||||||
void QSearchField::clear() {
|
|
||||||
Q_ASSERT(pimpl && pimpl->lineEdit);
|
|
||||||
if (!(pimpl && pimpl->lineEdit)) return;
|
|
||||||
pimpl->lineEdit->clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void QSearchField::selectAll() {
|
|
||||||
Q_ASSERT(pimpl && pimpl->lineEdit);
|
|
||||||
if (!(pimpl && pimpl->lineEdit)) return;
|
|
||||||
pimpl->lineEdit->selectAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString QSearchField::text() const {
|
|
||||||
Q_ASSERT(pimpl && pimpl->lineEdit);
|
|
||||||
if (!(pimpl && pimpl->lineEdit)) return QString();
|
|
||||||
return pimpl->lineEdit->text();
|
|
||||||
}
|
|
||||||
|
|
||||||
void QSearchField::resizeEvent(QResizeEvent *resizeEvent) {
|
|
||||||
Q_ASSERT(pimpl && pimpl->clearButton && pimpl->lineEdit);
|
|
||||||
if (!(pimpl && pimpl->clearButton && pimpl->lineEdit)) return;
|
|
||||||
|
|
||||||
QWidget::resizeEvent(resizeEvent);
|
|
||||||
const int x = pimpl->lineEditFrameWidth();
|
|
||||||
const int y = (height() - pimpl->clearButton->height())/2;
|
|
||||||
pimpl->clearButton->move(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QSearchField::eventFilter(QObject *o, QEvent *e) {
|
|
||||||
if (pimpl && pimpl->lineEdit && o == pimpl->lineEdit) {
|
|
||||||
// Forward some lineEdit events to QSearchField (only those we need for
|
|
||||||
// now, but some might be added later if needed)
|
|
||||||
switch (e->type()) {
|
|
||||||
case QEvent::FocusIn:
|
|
||||||
case QEvent::FocusOut:
|
|
||||||
QApplication::sendEvent(this, e);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return QWidget::eventFilter(o, e);
|
|
||||||
}
|
|
||||||
7
3rdparty/qocoa/qsearchfield_nonmac.qrc
vendored
7
3rdparty/qocoa/qsearchfield_nonmac.qrc
vendored
@@ -1,7 +0,0 @@
|
|||||||
<RCC>
|
|
||||||
<qresource prefix="/Qocoa">
|
|
||||||
<file>qsearchfield_nonmac_clear.png</file>
|
|
||||||
<file>qsearchfield_nonmac_magnifier_menu.png</file>
|
|
||||||
<file>qsearchfield_nonmac_magnifier.png</file>
|
|
||||||
</qresource>
|
|
||||||
</RCC>
|
|
||||||
BIN
3rdparty/qocoa/qsearchfield_nonmac_clear.png
vendored
BIN
3rdparty/qocoa/qsearchfield_nonmac_clear.png
vendored
Binary file not shown.
|
Before Width: | Height: | Size: 736 B |
BIN
3rdparty/qocoa/qsearchfield_nonmac_magnifier.png
vendored
BIN
3rdparty/qocoa/qsearchfield_nonmac_magnifier.png
vendored
Binary file not shown.
|
Before Width: | Height: | Size: 300 B |
Binary file not shown.
|
Before Width: | Height: | Size: 439 B |
31
3rdparty/qtsingleapplication/CMakeLists.txt
vendored
31
3rdparty/qtsingleapplication/CMakeLists.txt
vendored
@@ -1,31 +0,0 @@
|
|||||||
cmake_minimum_required(VERSION 2.8.11)
|
|
||||||
set(CMAKE_CXX_STANDARD 11)
|
|
||||||
|
|
||||||
set(SINGLEAPP-SOURCES
|
|
||||||
qtlocalpeer.cpp
|
|
||||||
qtsingleapplication.cpp
|
|
||||||
qtsinglecoreapplication.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
set(SINGLEAPP-MOC-HEADERS
|
|
||||||
qtlocalpeer.h
|
|
||||||
qtsingleapplication.h
|
|
||||||
qtsinglecoreapplication.h
|
|
||||||
)
|
|
||||||
|
|
||||||
if(WIN32)
|
|
||||||
set(SINGLEAPP-SOURCES ${SINGLEAPP-SOURCES} qtlockedfile_win.cpp)
|
|
||||||
elseif(WIN32)
|
|
||||||
set(SINGLEAPP-SOURCES ${SINGLEAPP-SOURCES} qtlockedfile_unix.cpp)
|
|
||||||
endif(WIN32)
|
|
||||||
|
|
||||||
QT5_WRAP_CPP(SINGLEAPP-SOURCES-MOC ${SINGLEAPP-MOC-HEADERS})
|
|
||||||
|
|
||||||
ADD_LIBRARY(qtsingleapplication STATIC
|
|
||||||
${SINGLEAPP-SOURCES}
|
|
||||||
${SINGLEAPP-SOURCES-MOC}
|
|
||||||
)
|
|
||||||
|
|
||||||
target_link_libraries(qtsingleapplication Qt5::Core Qt5::Widgets Qt5::Network)
|
|
||||||
|
|
||||||
include_directories(${CMAKE_BINARY_DIR}/src)
|
|
||||||
504
3rdparty/qtsingleapplication/LICENSE.LGPL
vendored
504
3rdparty/qtsingleapplication/LICENSE.LGPL
vendored
@@ -1,504 +0,0 @@
|
|||||||
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!
|
|
||||||
|
|
||||||
|
|
||||||
210
3rdparty/qtsingleapplication/qtlocalpeer.cpp
vendored
210
3rdparty/qtsingleapplication/qtlocalpeer.cpp
vendored
@@ -1,210 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
**
|
|
||||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
|
||||||
** All rights reserved.
|
|
||||||
**
|
|
||||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
|
||||||
**
|
|
||||||
** This file is part of a Qt Solutions component.
|
|
||||||
**
|
|
||||||
** You may use this file under the terms of the BSD license as follows:
|
|
||||||
**
|
|
||||||
** "Redistribution and use in source and binary forms, with or without
|
|
||||||
** modification, are permitted provided that the following conditions are
|
|
||||||
** met:
|
|
||||||
** * Redistributions of source code must retain the above copyright
|
|
||||||
** notice, this list of conditions and the following disclaimer.
|
|
||||||
** * Redistributions in binary form must reproduce the above copyright
|
|
||||||
** notice, this list of conditions and the following disclaimer in
|
|
||||||
** the documentation and/or other materials provided with the
|
|
||||||
** distribution.
|
|
||||||
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
|
|
||||||
** the names of its contributors may be used to endorse or promote
|
|
||||||
** products derived from this software without specific prior written
|
|
||||||
** permission.
|
|
||||||
**
|
|
||||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
|
||||||
**
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
|
|
||||||
#include "qtlocalpeer.h"
|
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include <QtGlobal>
|
|
||||||
#include <QCoreApplication>
|
|
||||||
#include <QObject>
|
|
||||||
#include <QAbstractSocket>
|
|
||||||
#include <QByteArray>
|
|
||||||
#include <QChar>
|
|
||||||
#include <QDataStream>
|
|
||||||
#include <QDir>
|
|
||||||
#include <QFile>
|
|
||||||
#include <QIODevice>
|
|
||||||
#include <QLocalServer>
|
|
||||||
#include <QLocalSocket>
|
|
||||||
#include <QRegExp>
|
|
||||||
|
|
||||||
#if defined(Q_OS_WIN)
|
|
||||||
#include <qt_windows.h>
|
|
||||||
#include <QLibrary>
|
|
||||||
|
|
||||||
typedef BOOL(WINAPI*PProcessIdToSessionId)(DWORD,DWORD*);
|
|
||||||
static PProcessIdToSessionId pProcessIdToSessionId = 0;
|
|
||||||
#endif
|
|
||||||
#if defined(Q_OS_UNIX)
|
|
||||||
#include <time.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "qtlockedfile.cpp"
|
|
||||||
#if defined(Q_OS_WIN)
|
|
||||||
#include "qtlockedfile_win.cpp"
|
|
||||||
#else
|
|
||||||
#include "qtlockedfile_unix.cpp"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
const char* QtLocalPeer::ack = "ack";
|
|
||||||
|
|
||||||
QtLocalPeer::QtLocalPeer(QObject* parent, const QString &appId)
|
|
||||||
: QObject(parent), id(appId)
|
|
||||||
{
|
|
||||||
QString prefix = id;
|
|
||||||
if (id.isEmpty()) {
|
|
||||||
id = QCoreApplication::applicationFilePath();
|
|
||||||
#if defined(Q_OS_WIN)
|
|
||||||
id = id.toLower();
|
|
||||||
#endif
|
|
||||||
prefix = id.section(QLatin1Char('/'), -1);
|
|
||||||
}
|
|
||||||
prefix.remove(QRegExp("[^a-zA-Z]"));
|
|
||||||
prefix.truncate(6);
|
|
||||||
|
|
||||||
QByteArray idc = id.toUtf8();
|
|
||||||
quint16 idNum = qChecksum(idc.constData(), idc.size());
|
|
||||||
socketName = QLatin1String("qtsingleapp-") + prefix + QLatin1Char('-') + QString::number(idNum, 16);
|
|
||||||
|
|
||||||
#if defined(Q_OS_WIN)
|
|
||||||
if (!pProcessIdToSessionId) {
|
|
||||||
QLibrary lib("kernel32");
|
|
||||||
pProcessIdToSessionId = (PProcessIdToSessionId)lib.resolve("ProcessIdToSessionId");
|
|
||||||
}
|
|
||||||
if (pProcessIdToSessionId) {
|
|
||||||
DWORD sessionId = 0;
|
|
||||||
pProcessIdToSessionId(GetCurrentProcessId(), &sessionId);
|
|
||||||
socketName += QLatin1Char('-') + QString::number(sessionId, 16);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
socketName += QLatin1Char('-') + QString::number(::getuid(), 16);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
server = new QLocalServer(this);
|
|
||||||
QString lockName = QDir(QDir::tempPath()).absolutePath() + QLatin1Char('/') + socketName + QLatin1String("-lockfile");
|
|
||||||
lockFile.setFileName(lockName);
|
|
||||||
lockFile.open(QIODevice::ReadWrite);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool QtLocalPeer::isClient()
|
|
||||||
{
|
|
||||||
if (lockFile.isLocked())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!lockFile.lock(QtLockedFile::WriteLock, false))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
bool res = server->listen(socketName);
|
|
||||||
#if defined(Q_OS_UNIX) && (QT_VERSION >= QT_VERSION_CHECK(4,5,0))
|
|
||||||
// ### Workaround
|
|
||||||
if (!res && server->serverError() == QAbstractSocket::AddressInUseError) {
|
|
||||||
QFile::remove(QDir::cleanPath(QDir::tempPath())+QLatin1Char('/')+socketName);
|
|
||||||
res = server->listen(socketName);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (!res)
|
|
||||||
qWarning("QtSingleCoreApplication: listen on local socket failed, %s", qPrintable(server->errorString()));
|
|
||||||
QObject::connect(server, SIGNAL(newConnection()), SLOT(receiveConnection()));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool QtLocalPeer::sendMessage(const QString &message, int timeout)
|
|
||||||
{
|
|
||||||
if (!isClient())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
QLocalSocket socket;
|
|
||||||
bool connOk = false;
|
|
||||||
for(int i = 0; i < 2; i++) {
|
|
||||||
// Try twice, in case the other instance is just starting up
|
|
||||||
socket.connectToServer(socketName);
|
|
||||||
connOk = socket.waitForConnected(timeout/2);
|
|
||||||
if (connOk || i)
|
|
||||||
break;
|
|
||||||
int ms = 250;
|
|
||||||
#if defined(Q_OS_WIN)
|
|
||||||
Sleep(DWORD(ms));
|
|
||||||
#else
|
|
||||||
struct timespec ts = { ms / 1000, (ms % 1000) * 1000 * 1000 };
|
|
||||||
nanosleep(&ts, NULL);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
if (!connOk)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
QByteArray uMsg(message.toUtf8());
|
|
||||||
QDataStream ds(&socket);
|
|
||||||
ds.writeBytes(uMsg.constData(), uMsg.size());
|
|
||||||
bool res = socket.waitForBytesWritten(timeout);
|
|
||||||
if (res) {
|
|
||||||
res &= socket.waitForReadyRead(timeout); // wait for ack
|
|
||||||
if (res)
|
|
||||||
res &= (socket.read(qstrlen(ack)) == ack);
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void QtLocalPeer::receiveConnection()
|
|
||||||
{
|
|
||||||
QLocalSocket* socket = server->nextPendingConnection();
|
|
||||||
if (!socket)
|
|
||||||
return;
|
|
||||||
|
|
||||||
while (socket->bytesAvailable() < (int)sizeof(quint32))
|
|
||||||
socket->waitForReadyRead();
|
|
||||||
QDataStream ds(socket);
|
|
||||||
QByteArray uMsg;
|
|
||||||
quint32 remaining;
|
|
||||||
ds >> remaining;
|
|
||||||
uMsg.resize(remaining);
|
|
||||||
int got = 0;
|
|
||||||
char* uMsgBuf = uMsg.data();
|
|
||||||
do {
|
|
||||||
got = ds.readRawData(uMsgBuf, remaining);
|
|
||||||
remaining -= got;
|
|
||||||
uMsgBuf += got;
|
|
||||||
}
|
|
||||||
while (remaining && got >= 0 && socket->waitForReadyRead(2000));
|
|
||||||
if (got < 0) {
|
|
||||||
qWarning("QtLocalPeer: Message reception failed %s", socket->errorString().toLatin1().constData());
|
|
||||||
delete socket;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
QString message(QString::fromUtf8(uMsg));
|
|
||||||
socket->write(ack, qstrlen(ack));
|
|
||||||
socket->waitForBytesWritten(1000);
|
|
||||||
delete socket;
|
|
||||||
emit messageReceived(message); //### (might take a long time to return)
|
|
||||||
}
|
|
||||||
76
3rdparty/qtsingleapplication/qtlocalpeer.h
vendored
76
3rdparty/qtsingleapplication/qtlocalpeer.h
vendored
@@ -1,76 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
**
|
|
||||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
|
||||||
** All rights reserved.
|
|
||||||
**
|
|
||||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
|
||||||
**
|
|
||||||
** This file is part of a Qt Solutions component.
|
|
||||||
**
|
|
||||||
** You may use this file under the terms of the BSD license as follows:
|
|
||||||
**
|
|
||||||
** "Redistribution and use in source and binary forms, with or without
|
|
||||||
** modification, are permitted provided that the following conditions are
|
|
||||||
** met:
|
|
||||||
** * Redistributions of source code must retain the above copyright
|
|
||||||
** notice, this list of conditions and the following disclaimer.
|
|
||||||
** * Redistributions in binary form must reproduce the above copyright
|
|
||||||
** notice, this list of conditions and the following disclaimer in
|
|
||||||
** the documentation and/or other materials provided with the
|
|
||||||
** distribution.
|
|
||||||
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
|
|
||||||
** the names of its contributors may be used to endorse or promote
|
|
||||||
** products derived from this software without specific prior written
|
|
||||||
** permission.
|
|
||||||
**
|
|
||||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
|
||||||
**
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifndef QTLOCALPEER_H
|
|
||||||
#define QTLOCALPEER_H
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QString>
|
|
||||||
#include <QLocalServer>
|
|
||||||
|
|
||||||
#include "qtlockedfile.h"
|
|
||||||
|
|
||||||
class QtLocalPeer : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
QtLocalPeer(QObject *parent = 0, const QString &appId = QString());
|
|
||||||
bool isClient();
|
|
||||||
bool sendMessage(const QString &message, int timeout);
|
|
||||||
QString applicationId() const
|
|
||||||
{ return id; }
|
|
||||||
|
|
||||||
Q_SIGNALS:
|
|
||||||
void messageReceived(const QString &message);
|
|
||||||
|
|
||||||
protected Q_SLOTS:
|
|
||||||
void receiveConnection();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
QString id;
|
|
||||||
QString socketName;
|
|
||||||
QLocalServer *server;
|
|
||||||
QtLockedFile lockFile;
|
|
||||||
|
|
||||||
private:
|
|
||||||
static const char* ack;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // QTLOCALPEER_H
|
|
||||||
195
3rdparty/qtsingleapplication/qtlockedfile.cpp
vendored
195
3rdparty/qtsingleapplication/qtlockedfile.cpp
vendored
@@ -1,195 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
**
|
|
||||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
|
||||||
** All rights reserved.
|
|
||||||
**
|
|
||||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
|
||||||
**
|
|
||||||
** This file is part of a Qt Solutions component.
|
|
||||||
**
|
|
||||||
** You may use this file under the terms of the BSD license as follows:
|
|
||||||
**
|
|
||||||
** "Redistribution and use in source and binary forms, with or without
|
|
||||||
** modification, are permitted provided that the following conditions are
|
|
||||||
** met:
|
|
||||||
** * Redistributions of source code must retain the above copyright
|
|
||||||
** notice, this list of conditions and the following disclaimer.
|
|
||||||
** * Redistributions in binary form must reproduce the above copyright
|
|
||||||
** notice, this list of conditions and the following disclaimer in
|
|
||||||
** the documentation and/or other materials provided with the
|
|
||||||
** distribution.
|
|
||||||
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
|
|
||||||
** the names of its contributors may be used to endorse or promote
|
|
||||||
** products derived from this software without specific prior written
|
|
||||||
** permission.
|
|
||||||
**
|
|
||||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
|
||||||
**
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#include <QFile>
|
|
||||||
#include <QString>
|
|
||||||
|
|
||||||
#include "qtlockedfile.h"
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\class QtLockedFile
|
|
||||||
|
|
||||||
\brief The QtLockedFile class extends QFile with advisory locking
|
|
||||||
functions.
|
|
||||||
|
|
||||||
A file may be locked in read or write mode. Multiple instances of
|
|
||||||
\e QtLockedFile, created in multiple processes running on the same
|
|
||||||
machine, may have a file locked in read mode. Exactly one instance
|
|
||||||
may have it locked in write mode. A read and a write lock cannot
|
|
||||||
exist simultaneously on the same file.
|
|
||||||
|
|
||||||
The file locks are advisory. This means that nothing prevents
|
|
||||||
another process from manipulating a locked file using QFile or
|
|
||||||
file system functions offered by the OS. Serialization is only
|
|
||||||
guaranteed if all processes that access the file use
|
|
||||||
QLockedFile. Also, while holding a lock on a file, a process
|
|
||||||
must not open the same file again (through any API), or locks
|
|
||||||
can be unexpectedly lost.
|
|
||||||
|
|
||||||
The lock provided by an instance of \e QtLockedFile is released
|
|
||||||
whenever the program terminates. This is true even when the
|
|
||||||
program crashes and no destructors are called.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*! \enum QtLockedFile::LockMode
|
|
||||||
|
|
||||||
This enum describes the available lock modes.
|
|
||||||
|
|
||||||
\value ReadLock A read lock.
|
|
||||||
\value WriteLock A write lock.
|
|
||||||
\value NoLock Neither a read lock nor a write lock.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Constructs an unlocked \e QtLockedFile object. This constructor
|
|
||||||
behaves in the same way as \e QFile::QFile().
|
|
||||||
|
|
||||||
\sa QFile::QFile()
|
|
||||||
*/
|
|
||||||
QtLockedFile::QtLockedFile()
|
|
||||||
: QFile()
|
|
||||||
{
|
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
wmutex = 0;
|
|
||||||
rmutex = 0;
|
|
||||||
#endif
|
|
||||||
m_lock_mode = NoLock;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Constructs an unlocked QtLockedFile object with file \a name. This
|
|
||||||
constructor behaves in the same way as \e QFile::QFile(const
|
|
||||||
QString&).
|
|
||||||
|
|
||||||
\sa QFile::QFile()
|
|
||||||
*/
|
|
||||||
QtLockedFile::QtLockedFile(const QString &name)
|
|
||||||
: QFile(name)
|
|
||||||
{
|
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
wmutex = 0;
|
|
||||||
rmutex = 0;
|
|
||||||
#endif
|
|
||||||
m_lock_mode = NoLock;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Opens the file in OpenMode \a mode.
|
|
||||||
|
|
||||||
This is identical to QFile::open(), with the one exception that the
|
|
||||||
Truncate mode flag is disallowed. Truncation would conflict with the
|
|
||||||
advisory file locking, since the file would be modified before the
|
|
||||||
write lock is obtained. If truncation is required, use resize(0)
|
|
||||||
after obtaining the write lock.
|
|
||||||
|
|
||||||
Returns true if successful; otherwise false.
|
|
||||||
|
|
||||||
\sa QFile::open(), QFile::resize()
|
|
||||||
*/
|
|
||||||
bool QtLockedFile::open(OpenMode mode)
|
|
||||||
{
|
|
||||||
if (mode & QIODevice::Truncate) {
|
|
||||||
qWarning("QtLockedFile::open(): Truncate mode not allowed.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return QFile::open(mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Returns \e true if this object has a in read or write lock;
|
|
||||||
otherwise returns \e false.
|
|
||||||
|
|
||||||
\sa lockMode()
|
|
||||||
*/
|
|
||||||
bool QtLockedFile::isLocked() const
|
|
||||||
{
|
|
||||||
return m_lock_mode != NoLock;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Returns the type of lock currently held by this object, or \e
|
|
||||||
QtLockedFile::NoLock.
|
|
||||||
|
|
||||||
\sa isLocked()
|
|
||||||
*/
|
|
||||||
QtLockedFile::LockMode QtLockedFile::lockMode() const
|
|
||||||
{
|
|
||||||
return m_lock_mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\fn bool QtLockedFile::lock(LockMode mode, bool block = true)
|
|
||||||
|
|
||||||
Obtains a lock of type \a mode. The file must be opened before it
|
|
||||||
can be locked.
|
|
||||||
|
|
||||||
If \a block is true, this function will block until the lock is
|
|
||||||
aquired. If \a block is false, this function returns \e false
|
|
||||||
immediately if the lock cannot be aquired.
|
|
||||||
|
|
||||||
If this object already has a lock of type \a mode, this function
|
|
||||||
returns \e true immediately. If this object has a lock of a
|
|
||||||
different type than \a mode, the lock is first released and then a
|
|
||||||
new lock is obtained.
|
|
||||||
|
|
||||||
This function returns \e true if, after it executes, the file is
|
|
||||||
locked by this object, and \e false otherwise.
|
|
||||||
|
|
||||||
\sa unlock(), isLocked(), lockMode()
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\fn bool QtLockedFile::unlock()
|
|
||||||
|
|
||||||
Releases a lock.
|
|
||||||
|
|
||||||
If the object has no lock, this function returns immediately.
|
|
||||||
|
|
||||||
This function returns \e true if, after it executes, the file is
|
|
||||||
not locked by this object, and \e false otherwise.
|
|
||||||
|
|
||||||
\sa lock(), isLocked(), lockMode()
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\fn QtLockedFile::~QtLockedFile()
|
|
||||||
|
|
||||||
Destroys the \e QtLockedFile object. If any locks were held, they
|
|
||||||
are released.
|
|
||||||
*/
|
|
||||||
94
3rdparty/qtsingleapplication/qtlockedfile.h
vendored
94
3rdparty/qtsingleapplication/qtlockedfile.h
vendored
@@ -1,94 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
**
|
|
||||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
|
||||||
** All rights reserved.
|
|
||||||
**
|
|
||||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
|
||||||
**
|
|
||||||
** This file is part of a Qt Solutions component.
|
|
||||||
**
|
|
||||||
** You may use this file under the terms of the BSD license as follows:
|
|
||||||
**
|
|
||||||
** "Redistribution and use in source and binary forms, with or without
|
|
||||||
** modification, are permitted provided that the following conditions are
|
|
||||||
** met:
|
|
||||||
** * Redistributions of source code must retain the above copyright
|
|
||||||
** notice, this list of conditions and the following disclaimer.
|
|
||||||
** * Redistributions in binary form must reproduce the above copyright
|
|
||||||
** notice, this list of conditions and the following disclaimer in
|
|
||||||
** the documentation and/or other materials provided with the
|
|
||||||
** distribution.
|
|
||||||
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
|
|
||||||
** the names of its contributors may be used to endorse or promote
|
|
||||||
** products derived from this software without specific prior written
|
|
||||||
** permission.
|
|
||||||
**
|
|
||||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
|
||||||
**
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifndef QTLOCKEDFILE_H
|
|
||||||
#define QTLOCKEDFILE_H
|
|
||||||
|
|
||||||
#include <QFile>
|
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
#include <QVector>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(Q_OS_WIN)
|
|
||||||
# if !defined(QT_QTLOCKEDFILE_EXPORT) && !defined(QT_QTLOCKEDFILE_IMPORT)
|
|
||||||
# define QT_QTLOCKEDFILE_EXPORT
|
|
||||||
# elif defined(QT_QTLOCKEDFILE_IMPORT)
|
|
||||||
# if defined(QT_QTLOCKEDFILE_EXPORT)
|
|
||||||
# undef QT_QTLOCKEDFILE_EXPORT
|
|
||||||
# endif
|
|
||||||
# define QT_QTLOCKEDFILE_EXPORT __declspec(dllimport)
|
|
||||||
# elif defined(QT_QTLOCKEDFILE_EXPORT)
|
|
||||||
# undef QT_QTLOCKEDFILE_EXPORT
|
|
||||||
# define QT_QTLOCKEDFILE_EXPORT __declspec(dllexport)
|
|
||||||
# endif
|
|
||||||
#else
|
|
||||||
# define QT_QTLOCKEDFILE_EXPORT
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class QT_QTLOCKEDFILE_EXPORT QtLockedFile : public QFile
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum LockMode { NoLock = 0, ReadLock, WriteLock };
|
|
||||||
|
|
||||||
QtLockedFile();
|
|
||||||
QtLockedFile(const QString &name);
|
|
||||||
~QtLockedFile();
|
|
||||||
|
|
||||||
bool open(OpenMode mode);
|
|
||||||
|
|
||||||
bool lock(LockMode mode, bool block = true);
|
|
||||||
bool unlock();
|
|
||||||
bool isLocked() const;
|
|
||||||
LockMode lockMode() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
Qt::HANDLE wmutex;
|
|
||||||
Qt::HANDLE rmutex;
|
|
||||||
QVector<Qt::HANDLE> rmutexes;
|
|
||||||
QString mutexname;
|
|
||||||
|
|
||||||
Qt::HANDLE getMutexHandle(int idx, bool doCreate);
|
|
||||||
bool waitMutex(Qt::HANDLE mutex, bool doBlock);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
LockMode m_lock_mode;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
114
3rdparty/qtsingleapplication/qtlockedfile_unix.cpp
vendored
114
3rdparty/qtsingleapplication/qtlockedfile_unix.cpp
vendored
@@ -1,114 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
**
|
|
||||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
|
||||||
** All rights reserved.
|
|
||||||
**
|
|
||||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
|
||||||
**
|
|
||||||
** This file is part of a Qt Solutions component.
|
|
||||||
**
|
|
||||||
** You may use this file under the terms of the BSD license as follows:
|
|
||||||
**
|
|
||||||
** "Redistribution and use in source and binary forms, with or without
|
|
||||||
** modification, are permitted provided that the following conditions are
|
|
||||||
** met:
|
|
||||||
** * Redistributions of source code must retain the above copyright
|
|
||||||
** notice, this list of conditions and the following disclaimer.
|
|
||||||
** * Redistributions in binary form must reproduce the above copyright
|
|
||||||
** notice, this list of conditions and the following disclaimer in
|
|
||||||
** the documentation and/or other materials provided with the
|
|
||||||
** distribution.
|
|
||||||
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
|
|
||||||
** the names of its contributors may be used to endorse or promote
|
|
||||||
** products derived from this software without specific prior written
|
|
||||||
** permission.
|
|
||||||
**
|
|
||||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
|
||||||
**
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
|
|
||||||
#include "qtlockedfile.h"
|
|
||||||
|
|
||||||
bool QtLockedFile::lock(LockMode mode, bool block)
|
|
||||||
{
|
|
||||||
if (!isOpen()) {
|
|
||||||
qWarning("QtLockedFile::lock(): file is not opened");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mode == NoLock)
|
|
||||||
return unlock();
|
|
||||||
|
|
||||||
if (mode == m_lock_mode)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (m_lock_mode != NoLock)
|
|
||||||
unlock();
|
|
||||||
|
|
||||||
struct flock fl;
|
|
||||||
fl.l_whence = SEEK_SET;
|
|
||||||
fl.l_start = 0;
|
|
||||||
fl.l_len = 0;
|
|
||||||
fl.l_type = (mode == ReadLock) ? F_RDLCK : F_WRLCK;
|
|
||||||
int cmd = block ? F_SETLKW : F_SETLK;
|
|
||||||
int ret = fcntl(handle(), cmd, &fl);
|
|
||||||
|
|
||||||
if (ret == -1) {
|
|
||||||
if (errno != EINTR && errno != EAGAIN)
|
|
||||||
qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
m_lock_mode = mode;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool QtLockedFile::unlock()
|
|
||||||
{
|
|
||||||
if (!isOpen()) {
|
|
||||||
qWarning("QtLockedFile::unlock(): file is not opened");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isLocked())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
struct flock fl;
|
|
||||||
fl.l_whence = SEEK_SET;
|
|
||||||
fl.l_start = 0;
|
|
||||||
fl.l_len = 0;
|
|
||||||
fl.l_type = F_UNLCK;
|
|
||||||
int ret = fcntl(handle(), F_SETLKW, &fl);
|
|
||||||
|
|
||||||
if (ret == -1) {
|
|
||||||
qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_lock_mode = NoLock;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
QtLockedFile::~QtLockedFile()
|
|
||||||
{
|
|
||||||
if (isOpen())
|
|
||||||
unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
203
3rdparty/qtsingleapplication/qtlockedfile_win.cpp
vendored
203
3rdparty/qtsingleapplication/qtlockedfile_win.cpp
vendored
@@ -1,203 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
**
|
|
||||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
|
||||||
** All rights reserved.
|
|
||||||
**
|
|
||||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
|
||||||
**
|
|
||||||
** This file is part of a Qt Solutions component.
|
|
||||||
**
|
|
||||||
** You may use this file under the terms of the BSD license as follows:
|
|
||||||
**
|
|
||||||
** "Redistribution and use in source and binary forms, with or without
|
|
||||||
** modification, are permitted provided that the following conditions are
|
|
||||||
** met:
|
|
||||||
** * Redistributions of source code must retain the above copyright
|
|
||||||
** notice, this list of conditions and the following disclaimer.
|
|
||||||
** * Redistributions in binary form must reproduce the above copyright
|
|
||||||
** notice, this list of conditions and the following disclaimer in
|
|
||||||
** the documentation and/or other materials provided with the
|
|
||||||
** distribution.
|
|
||||||
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
|
|
||||||
** the names of its contributors may be used to endorse or promote
|
|
||||||
** products derived from this software without specific prior written
|
|
||||||
** permission.
|
|
||||||
**
|
|
||||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
|
||||||
**
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#include <QFileInfo>
|
|
||||||
|
|
||||||
#include "qtlockedfile.h"
|
|
||||||
#include <qt_windows.h>
|
|
||||||
|
|
||||||
#define MUTEX_PREFIX "QtLockedFile mutex "
|
|
||||||
// Maximum number of concurrent read locks. Must not be greater than MAXIMUM_WAIT_OBJECTS
|
|
||||||
#define MAX_READERS MAXIMUM_WAIT_OBJECTS
|
|
||||||
|
|
||||||
Qt::HANDLE QtLockedFile::getMutexHandle(int idx, bool doCreate)
|
|
||||||
{
|
|
||||||
if (mutexname.isEmpty()) {
|
|
||||||
QFileInfo fi(*this);
|
|
||||||
mutexname = QString::fromLatin1(MUTEX_PREFIX) + fi.absoluteFilePath().toLower();
|
|
||||||
}
|
|
||||||
QString mname(mutexname);
|
|
||||||
if (idx >= 0)
|
|
||||||
mname += QString::number(idx);
|
|
||||||
|
|
||||||
Qt::HANDLE mutex;
|
|
||||||
if (doCreate) {
|
|
||||||
mutex = CreateMutexW(NULL, FALSE, (WCHAR*)mname.utf16());
|
|
||||||
if (!mutex) {
|
|
||||||
qErrnoWarning("QtLockedFile::lock(): CreateMutex failed");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
mutex = OpenMutexW(SYNCHRONIZE | MUTEX_MODIFY_STATE, FALSE, (WCHAR*)mname.utf16());
|
|
||||||
if (!mutex) {
|
|
||||||
if (GetLastError() != ERROR_FILE_NOT_FOUND)
|
|
||||||
qErrnoWarning("QtLockedFile::lock(): OpenMutex failed");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return mutex;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QtLockedFile::waitMutex(Qt::HANDLE mutex, bool doBlock)
|
|
||||||
{
|
|
||||||
Q_ASSERT(mutex);
|
|
||||||
DWORD res = WaitForSingleObject(mutex, doBlock ? INFINITE : 0);
|
|
||||||
switch (res) {
|
|
||||||
case WAIT_OBJECT_0:
|
|
||||||
case WAIT_ABANDONED:
|
|
||||||
return true;
|
|
||||||
break;
|
|
||||||
case WAIT_TIMEOUT:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
qErrnoWarning("QtLockedFile::lock(): WaitForSingleObject failed");
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool QtLockedFile::lock(LockMode mode, bool block)
|
|
||||||
{
|
|
||||||
if (!isOpen()) {
|
|
||||||
qWarning("QtLockedFile::lock(): file is not opened");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mode == NoLock)
|
|
||||||
return unlock();
|
|
||||||
|
|
||||||
if (mode == m_lock_mode)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (m_lock_mode != NoLock)
|
|
||||||
unlock();
|
|
||||||
|
|
||||||
if (!wmutex && !(wmutex = getMutexHandle(-1, true)))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!waitMutex(wmutex, block))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (mode == ReadLock) {
|
|
||||||
int idx = 0;
|
|
||||||
for (; idx < MAX_READERS; idx++) {
|
|
||||||
rmutex = getMutexHandle(idx, false);
|
|
||||||
if (!rmutex || waitMutex(rmutex, false))
|
|
||||||
break;
|
|
||||||
CloseHandle(rmutex);
|
|
||||||
}
|
|
||||||
bool ok = true;
|
|
||||||
if (idx >= MAX_READERS) {
|
|
||||||
qWarning("QtLockedFile::lock(): too many readers");
|
|
||||||
rmutex = 0;
|
|
||||||
ok = false;
|
|
||||||
}
|
|
||||||
else if (!rmutex) {
|
|
||||||
rmutex = getMutexHandle(idx, true);
|
|
||||||
if (!rmutex || !waitMutex(rmutex, false))
|
|
||||||
ok = false;
|
|
||||||
}
|
|
||||||
if (!ok && rmutex) {
|
|
||||||
CloseHandle(rmutex);
|
|
||||||
rmutex = 0;
|
|
||||||
}
|
|
||||||
ReleaseMutex(wmutex);
|
|
||||||
if (!ok)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Q_ASSERT(rmutexes.isEmpty());
|
|
||||||
for (int i = 0; i < MAX_READERS; i++) {
|
|
||||||
Qt::HANDLE mutex = getMutexHandle(i, false);
|
|
||||||
if (mutex)
|
|
||||||
rmutexes.append(mutex);
|
|
||||||
}
|
|
||||||
if (rmutexes.size()) {
|
|
||||||
DWORD res = WaitForMultipleObjects(rmutexes.size(), rmutexes.constData(), TRUE, block ? INFINITE : 0);
|
|
||||||
if (res != WAIT_OBJECT_0 && res != WAIT_ABANDONED) {
|
|
||||||
if (res != WAIT_TIMEOUT)
|
|
||||||
qErrnoWarning("QtLockedFile::lock(): WaitForMultipleObjects failed");
|
|
||||||
m_lock_mode = WriteLock; // trick unlock() to clean up - semiyucky
|
|
||||||
unlock();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_lock_mode = mode;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QtLockedFile::unlock()
|
|
||||||
{
|
|
||||||
if (!isOpen()) {
|
|
||||||
qWarning("QtLockedFile::unlock(): file is not opened");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isLocked())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (m_lock_mode == ReadLock) {
|
|
||||||
ReleaseMutex(rmutex);
|
|
||||||
CloseHandle(rmutex);
|
|
||||||
rmutex = 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
foreach(Qt::HANDLE mutex, rmutexes) {
|
|
||||||
ReleaseMutex(mutex);
|
|
||||||
CloseHandle(mutex);
|
|
||||||
}
|
|
||||||
rmutexes.clear();
|
|
||||||
ReleaseMutex(wmutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_lock_mode = QtLockedFile::NoLock;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
QtLockedFile::~QtLockedFile()
|
|
||||||
{
|
|
||||||
if (isOpen())
|
|
||||||
unlock();
|
|
||||||
if (wmutex)
|
|
||||||
CloseHandle(wmutex);
|
|
||||||
}
|
|
||||||
340
3rdparty/qtsingleapplication/qtsingleapplication.cpp
vendored
340
3rdparty/qtsingleapplication/qtsingleapplication.cpp
vendored
@@ -1,340 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
**
|
|
||||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
|
||||||
** All rights reserved.
|
|
||||||
**
|
|
||||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
|
||||||
**
|
|
||||||
** This file is part of a Qt Solutions component.
|
|
||||||
**
|
|
||||||
** You may use this file under the terms of the BSD license as follows:
|
|
||||||
**
|
|
||||||
** "Redistribution and use in source and binary forms, with or without
|
|
||||||
** modification, are permitted provided that the following conditions are
|
|
||||||
** met:
|
|
||||||
** * Redistributions of source code must retain the above copyright
|
|
||||||
** notice, this list of conditions and the following disclaimer.
|
|
||||||
** * Redistributions in binary form must reproduce the above copyright
|
|
||||||
** notice, this list of conditions and the following disclaimer in
|
|
||||||
** the documentation and/or other materials provided with the
|
|
||||||
** distribution.
|
|
||||||
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
|
|
||||||
** the names of its contributors may be used to endorse or promote
|
|
||||||
** products derived from this software without specific prior written
|
|
||||||
** permission.
|
|
||||||
**
|
|
||||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
|
||||||
**
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include "qtsingleapplication.h"
|
|
||||||
|
|
||||||
#include <QApplication>
|
|
||||||
#include <QWidget>
|
|
||||||
#include <QString>
|
|
||||||
|
|
||||||
#ifdef HAVE_X11_ // FIXME
|
|
||||||
# include <X11/Xlib.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "qtlocalpeer.h"
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\class QtSingleApplication qtsingleapplication.h
|
|
||||||
\brief The QtSingleApplication class provides an API to detect and
|
|
||||||
communicate with running instances of an application.
|
|
||||||
|
|
||||||
This class allows you to create applications where only one
|
|
||||||
instance should be running at a time. I.e., if the user tries to
|
|
||||||
launch another instance, the already running instance will be
|
|
||||||
activated instead. Another usecase is a client-server system,
|
|
||||||
where the first started instance will assume the role of server,
|
|
||||||
and the later instances will act as clients of that server.
|
|
||||||
|
|
||||||
By default, the full path of the executable file is used to
|
|
||||||
determine whether two processes are instances of the same
|
|
||||||
application. You can also provide an explicit identifier string
|
|
||||||
that will be compared instead.
|
|
||||||
|
|
||||||
The application should create the QtSingleApplication object early
|
|
||||||
in the startup phase, and call isRunning() to find out if another
|
|
||||||
instance of this application is already running. If isRunning()
|
|
||||||
returns false, it means that no other instance is running, and
|
|
||||||
this instance has assumed the role as the running instance. In
|
|
||||||
this case, the application should continue with the initialization
|
|
||||||
of the application user interface before entering the event loop
|
|
||||||
with exec(), as normal.
|
|
||||||
|
|
||||||
The messageReceived() signal will be emitted when the running
|
|
||||||
application receives messages from another instance of the same
|
|
||||||
application. When a message is received it might be helpful to the
|
|
||||||
user to raise the application so that it becomes visible. To
|
|
||||||
facilitate this, QtSingleApplication provides the
|
|
||||||
setActivationWindow() function and the activateWindow() slot.
|
|
||||||
|
|
||||||
If isRunning() returns true, another instance is already
|
|
||||||
running. It may be alerted to the fact that another instance has
|
|
||||||
started by using the sendMessage() function. Also data such as
|
|
||||||
startup parameters (e.g. the name of the file the user wanted this
|
|
||||||
new instance to open) can be passed to the running instance with
|
|
||||||
this function. Then, the application should terminate (or enter
|
|
||||||
client mode).
|
|
||||||
|
|
||||||
If isRunning() returns true, but sendMessage() fails, that is an
|
|
||||||
indication that the running instance is frozen.
|
|
||||||
|
|
||||||
Here's an example that shows how to convert an existing
|
|
||||||
application to use QtSingleApplication. It is very simple and does
|
|
||||||
not make use of all QtSingleApplication's functionality (see the
|
|
||||||
examples for that).
|
|
||||||
|
|
||||||
\code
|
|
||||||
// Original
|
|
||||||
int main(int argc, char **argv)
|
|
||||||
{
|
|
||||||
QApplication app(argc, argv);
|
|
||||||
|
|
||||||
MyMainWidget mmw;
|
|
||||||
mmw.show();
|
|
||||||
return app.exec();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Single instance
|
|
||||||
int main(int argc, char **argv)
|
|
||||||
{
|
|
||||||
QtSingleApplication app(argc, argv);
|
|
||||||
|
|
||||||
if (app.isRunning())
|
|
||||||
return !app.sendMessage(someDataString);
|
|
||||||
|
|
||||||
MyMainWidget mmw;
|
|
||||||
app.setActivationWindow(&mmw);
|
|
||||||
mmw.show();
|
|
||||||
return app.exec();
|
|
||||||
}
|
|
||||||
\endcode
|
|
||||||
|
|
||||||
Once this QtSingleApplication instance is destroyed (normally when
|
|
||||||
the process exits or crashes), when the user next attempts to run the
|
|
||||||
application this instance will not, of course, be encountered. The
|
|
||||||
next instance to call isRunning() or sendMessage() will assume the
|
|
||||||
role as the new running instance.
|
|
||||||
|
|
||||||
For console (non-GUI) applications, QtSingleCoreApplication may be
|
|
||||||
used instead of this class, to avoid the dependency on the QtGui
|
|
||||||
library.
|
|
||||||
|
|
||||||
\sa QtSingleCoreApplication
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
void QtSingleApplication::sysInit(const QString &appId)
|
|
||||||
{
|
|
||||||
actWin = 0;
|
|
||||||
peer = new QtLocalPeer(this, appId);
|
|
||||||
connect(peer, SIGNAL(messageReceived(const QString&)), SIGNAL(messageReceived(const QString&)));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Creates a QtSingleApplication object. The application identifier
|
|
||||||
will be QCoreApplication::applicationFilePath(). \a argc, \a
|
|
||||||
argv, and \a GUIenabled are passed on to the QAppliation constructor.
|
|
||||||
|
|
||||||
If you are creating a console application (i.e. setting \a
|
|
||||||
GUIenabled to false), you may consider using
|
|
||||||
QtSingleCoreApplication instead.
|
|
||||||
*/
|
|
||||||
|
|
||||||
QtSingleApplication::QtSingleApplication(int &argc, char **argv, bool GUIenabled)
|
|
||||||
: QApplication(argc, argv, GUIenabled)
|
|
||||||
{
|
|
||||||
sysInit();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Creates a QtSingleApplication object with the application
|
|
||||||
identifier \a appId. \a argc and \a argv are passed on to the
|
|
||||||
QAppliation constructor.
|
|
||||||
*/
|
|
||||||
|
|
||||||
QtSingleApplication::QtSingleApplication(const QString &appId, int &argc, char **argv)
|
|
||||||
: QApplication(argc, argv)
|
|
||||||
{
|
|
||||||
sysInit(appId);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#if defined(HAVE_X11_) // FIXME
|
|
||||||
/*!
|
|
||||||
Special constructor for X11, ref. the documentation of
|
|
||||||
QApplication's corresponding constructor. The application identifier
|
|
||||||
will be QCoreApplication::applicationFilePath(). \a dpy, \a visual,
|
|
||||||
and \a cmap are passed on to the QApplication constructor.
|
|
||||||
*/
|
|
||||||
QtSingleApplication::QtSingleApplication(Display *dpy, Qt::HANDLE visual, Qt::HANDLE cmap)
|
|
||||||
: QApplication(dpy, visual, cmap)
|
|
||||||
{
|
|
||||||
sysInit();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Special constructor for X11, ref. the documentation of
|
|
||||||
QApplication's corresponding constructor. The application identifier
|
|
||||||
will be QCoreApplication::applicationFilePath(). \a dpy, \a argc, \a
|
|
||||||
argv, \a visual, and \a cmap are passed on to the QApplication
|
|
||||||
constructor.
|
|
||||||
*/
|
|
||||||
QtSingleApplication::QtSingleApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual, Qt::HANDLE cmap)
|
|
||||||
: QApplication(dpy, argc, argv, visual, cmap)
|
|
||||||
{
|
|
||||||
sysInit();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Special constructor for X11, ref. the documentation of
|
|
||||||
QApplication's corresponding constructor. The application identifier
|
|
||||||
will be \a appId. \a dpy, \a argc, \a
|
|
||||||
argv, \a visual, and \a cmap are passed on to the QApplication
|
|
||||||
constructor.
|
|
||||||
*/
|
|
||||||
QtSingleApplication::QtSingleApplication(Display *dpy, const QString &appId, int argc, char **argv, Qt::HANDLE visual, Qt::HANDLE cmap)
|
|
||||||
: QApplication(dpy, argc, argv, visual, cmap)
|
|
||||||
{
|
|
||||||
sysInit(appId);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Returns true if another instance of this application is running;
|
|
||||||
otherwise false.
|
|
||||||
|
|
||||||
This function does not find instances of this application that are
|
|
||||||
being run by a different user (on Windows: that are running in
|
|
||||||
another session).
|
|
||||||
|
|
||||||
\sa sendMessage()
|
|
||||||
*/
|
|
||||||
|
|
||||||
bool QtSingleApplication::isRunning()
|
|
||||||
{
|
|
||||||
return peer->isClient();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Tries to send the text \a message to the currently running
|
|
||||||
instance. The QtSingleApplication object in the running instance
|
|
||||||
will emit the messageReceived() signal when it receives the
|
|
||||||
message.
|
|
||||||
|
|
||||||
This function returns true if the message has been sent to, and
|
|
||||||
processed by, the current instance. If there is no instance
|
|
||||||
currently running, or if the running instance fails to process the
|
|
||||||
message within \a timeout milliseconds, this function return false.
|
|
||||||
|
|
||||||
\sa isRunning(), messageReceived()
|
|
||||||
*/
|
|
||||||
bool QtSingleApplication::sendMessage(const QString &message, int timeout)
|
|
||||||
{
|
|
||||||
return peer->sendMessage(message, timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Returns the application identifier. Two processes with the same
|
|
||||||
identifier will be regarded as instances of the same application.
|
|
||||||
*/
|
|
||||||
QString QtSingleApplication::id() const
|
|
||||||
{
|
|
||||||
return peer->applicationId();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Sets the activation window of this application to \a aw. The
|
|
||||||
activation window is the widget that will be activated by
|
|
||||||
activateWindow(). This is typically the application's main window.
|
|
||||||
|
|
||||||
If \a activateOnMessage is true (the default), the window will be
|
|
||||||
activated automatically every time a message is received, just prior
|
|
||||||
to the messageReceived() signal being emitted.
|
|
||||||
|
|
||||||
\sa activateWindow(), messageReceived()
|
|
||||||
*/
|
|
||||||
|
|
||||||
void QtSingleApplication::setActivationWindow(QWidget* aw, bool activateOnMessage)
|
|
||||||
{
|
|
||||||
actWin = aw;
|
|
||||||
if (activateOnMessage)
|
|
||||||
connect(peer, SIGNAL(messageReceived(const QString&)), this, SLOT(activateWindow()));
|
|
||||||
else
|
|
||||||
disconnect(peer, SIGNAL(messageReceived(const QString&)), this, SLOT(activateWindow()));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Returns the applications activation window if one has been set by
|
|
||||||
calling setActivationWindow(), otherwise returns 0.
|
|
||||||
|
|
||||||
\sa setActivationWindow()
|
|
||||||
*/
|
|
||||||
QWidget* QtSingleApplication::activationWindow() const
|
|
||||||
{
|
|
||||||
return actWin;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*!
|
|
||||||
De-minimizes, raises, and activates this application's activation window.
|
|
||||||
This function does nothing if no activation window has been set.
|
|
||||||
|
|
||||||
This is a convenience function to show the user that this
|
|
||||||
application instance has been activated when he has tried to start
|
|
||||||
another instance.
|
|
||||||
|
|
||||||
This function should typically be called in response to the
|
|
||||||
messageReceived() signal. By default, that will happen
|
|
||||||
automatically, if an activation window has been set.
|
|
||||||
|
|
||||||
\sa setActivationWindow(), messageReceived(), initialize()
|
|
||||||
*/
|
|
||||||
void QtSingleApplication::activateWindow()
|
|
||||||
{
|
|
||||||
if (actWin) {
|
|
||||||
actWin->setWindowState(actWin->windowState() & ~Qt::WindowMinimized);
|
|
||||||
actWin->raise();
|
|
||||||
actWin->activateWindow();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\fn void QtSingleApplication::messageReceived(const QString& message)
|
|
||||||
|
|
||||||
This signal is emitted when the current instance receives a \a
|
|
||||||
message from another instance of this application.
|
|
||||||
|
|
||||||
\sa sendMessage(), setActivationWindow(), activateWindow()
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\fn void QtSingleApplication::initialize(bool dummy = true)
|
|
||||||
|
|
||||||
\obsolete
|
|
||||||
*/
|
|
||||||
111
3rdparty/qtsingleapplication/qtsingleapplication.h
vendored
111
3rdparty/qtsingleapplication/qtsingleapplication.h
vendored
@@ -1,111 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
**
|
|
||||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
|
||||||
** All rights reserved.
|
|
||||||
**
|
|
||||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
|
||||||
**
|
|
||||||
** This file is part of a Qt Solutions component.
|
|
||||||
**
|
|
||||||
** You may use this file under the terms of the BSD license as follows:
|
|
||||||
**
|
|
||||||
** "Redistribution and use in source and binary forms, with or without
|
|
||||||
** modification, are permitted provided that the following conditions are
|
|
||||||
** met:
|
|
||||||
** * Redistributions of source code must retain the above copyright
|
|
||||||
** notice, this list of conditions and the following disclaimer.
|
|
||||||
** * Redistributions in binary form must reproduce the above copyright
|
|
||||||
** notice, this list of conditions and the following disclaimer in
|
|
||||||
** the documentation and/or other materials provided with the
|
|
||||||
** distribution.
|
|
||||||
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
|
|
||||||
** the names of its contributors may be used to endorse or promote
|
|
||||||
** products derived from this software without specific prior written
|
|
||||||
** permission.
|
|
||||||
**
|
|
||||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
|
||||||
**
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifndef QTSINGLEAPPLICATION_H
|
|
||||||
#define QTSINGLEAPPLICATION_H
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <QtGlobal>
|
|
||||||
#include <QObject>
|
|
||||||
#include <QWidget>
|
|
||||||
#include <QApplication>
|
|
||||||
#include <QString>
|
|
||||||
|
|
||||||
#if defined(HAVE_X11_) // FIXME
|
|
||||||
# include <X11/Xlib.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class QtLocalPeer;
|
|
||||||
|
|
||||||
#if defined(Q_OS_WIN) || defined(Q_OS_WIN32)
|
|
||||||
# if !defined(QT_QTSINGLEAPPLICATION_EXPORT) && !defined(QT_QTSINGLEAPPLICATION_IMPORT)
|
|
||||||
# define QT_QTSINGLEAPPLICATION_EXPORT
|
|
||||||
# elif defined(QT_QTSINGLEAPPLICATION_IMPORT)
|
|
||||||
# if defined(QT_QTSINGLEAPPLICATION_EXPORT)
|
|
||||||
# undef QT_QTSINGLEAPPLICATION_EXPORT
|
|
||||||
# endif
|
|
||||||
# define QT_QTSINGLEAPPLICATION_EXPORT __declspec(dllimport)
|
|
||||||
# elif defined(QT_QTSINGLEAPPLICATION_EXPORT)
|
|
||||||
# undef QT_QTSINGLEAPPLICATION_EXPORT
|
|
||||||
# define QT_QTSINGLEAPPLICATION_EXPORT __declspec(dllexport)
|
|
||||||
# endif
|
|
||||||
#else
|
|
||||||
# define QT_QTSINGLEAPPLICATION_EXPORT
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class QT_QTSINGLEAPPLICATION_EXPORT QtSingleApplication : public QApplication
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
QtSingleApplication(int &argc, char **argv, bool GUIenabled = true);
|
|
||||||
QtSingleApplication(const QString &id, int &argc, char **argv);
|
|
||||||
#if defined(HAVE_X11_) // FIXME
|
|
||||||
QtSingleApplication(Display *dpy, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0);
|
|
||||||
QtSingleApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE cmap= 0);
|
|
||||||
QtSingleApplication(Display *dpy, const QString &appId, int argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bool isRunning();
|
|
||||||
QString id() const;
|
|
||||||
|
|
||||||
void setActivationWindow(QWidget* aw, bool activateOnMessage = true);
|
|
||||||
QWidget* activationWindow() const;
|
|
||||||
|
|
||||||
// Obsolete:
|
|
||||||
void initialize(bool dummy = true)
|
|
||||||
{ isRunning(); Q_UNUSED(dummy) }
|
|
||||||
|
|
||||||
public Q_SLOTS:
|
|
||||||
bool sendMessage(const QString &message, int timeout = 5000);
|
|
||||||
void activateWindow();
|
|
||||||
|
|
||||||
|
|
||||||
Q_SIGNALS:
|
|
||||||
void messageReceived(const QString &message);
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
|
||||||
void sysInit(const QString &appId = QString());
|
|
||||||
QtLocalPeer *peer;
|
|
||||||
QWidget *actWin;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // QTSINGLEAPPLICATION_H
|
|
||||||
@@ -1,146 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
**
|
|
||||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
|
||||||
** All rights reserved.
|
|
||||||
**
|
|
||||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
|
||||||
**
|
|
||||||
** This file is part of a Qt Solutions component.
|
|
||||||
**
|
|
||||||
** You may use this file under the terms of the BSD license as follows:
|
|
||||||
**
|
|
||||||
** "Redistribution and use in source and binary forms, with or without
|
|
||||||
** modification, are permitted provided that the following conditions are
|
|
||||||
** met:
|
|
||||||
** * Redistributions of source code must retain the above copyright
|
|
||||||
** notice, this list of conditions and the following disclaimer.
|
|
||||||
** * Redistributions in binary form must reproduce the above copyright
|
|
||||||
** notice, this list of conditions and the following disclaimer in
|
|
||||||
** the documentation and/or other materials provided with the
|
|
||||||
** distribution.
|
|
||||||
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
|
|
||||||
** the names of its contributors may be used to endorse or promote
|
|
||||||
** products derived from this software without specific prior written
|
|
||||||
** permission.
|
|
||||||
**
|
|
||||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
|
||||||
**
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#include <QCoreApplication>
|
|
||||||
#include <QString>
|
|
||||||
#include <QFlags>
|
|
||||||
|
|
||||||
#include "qtsinglecoreapplication.h"
|
|
||||||
#include "qtlocalpeer.h"
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\class QtSingleCoreApplication qtsinglecoreapplication.h
|
|
||||||
\brief A variant of the QtSingleApplication class for non-GUI applications.
|
|
||||||
|
|
||||||
This class is a variant of QtSingleApplication suited for use in
|
|
||||||
console (non-GUI) applications. It is an extension of
|
|
||||||
QCoreApplication (instead of QApplication). It does not require
|
|
||||||
the QtGui library.
|
|
||||||
|
|
||||||
The API and usage is identical to QtSingleApplication, except that
|
|
||||||
functions relating to the "activation window" are not present, for
|
|
||||||
obvious reasons. Please refer to the QtSingleApplication
|
|
||||||
documentation for explanation of the usage.
|
|
||||||
|
|
||||||
A QtSingleCoreApplication instance can communicate to a
|
|
||||||
QtSingleApplication instance if they share the same application
|
|
||||||
id. Hence, this class can be used to create a light-weight
|
|
||||||
command-line tool that sends commands to a GUI application.
|
|
||||||
|
|
||||||
\sa QtSingleApplication
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Creates a QtSingleCoreApplication object. The application identifier
|
|
||||||
will be QCoreApplication::applicationFilePath(). \a argc and \a
|
|
||||||
argv are passed on to the QCoreAppliation constructor.
|
|
||||||
*/
|
|
||||||
|
|
||||||
QtSingleCoreApplication::QtSingleCoreApplication(int &argc, char **argv)
|
|
||||||
: QCoreApplication(argc, argv) {
|
|
||||||
peer = new QtLocalPeer(this);
|
|
||||||
connect(peer, SIGNAL(messageReceived(const QString&)), SIGNAL(messageReceived(const QString&)));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Creates a QtSingleCoreApplication object with the application
|
|
||||||
identifier \a appId. \a argc and \a argv are passed on to the
|
|
||||||
QCoreAppliation constructor.
|
|
||||||
*/
|
|
||||||
QtSingleCoreApplication::QtSingleCoreApplication(const QString &appId, int &argc, char **argv)
|
|
||||||
: QCoreApplication(argc, argv) {
|
|
||||||
peer = new QtLocalPeer(this, appId);
|
|
||||||
connect(peer, SIGNAL(messageReceived(const QString&)), SIGNAL(messageReceived(const QString&)));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Returns true if another instance of this application is running;
|
|
||||||
otherwise false.
|
|
||||||
|
|
||||||
This function does not find instances of this application that are
|
|
||||||
being run by a different user (on Windows: that are running in
|
|
||||||
another session).
|
|
||||||
|
|
||||||
\sa sendMessage()
|
|
||||||
*/
|
|
||||||
|
|
||||||
bool QtSingleCoreApplication::isRunning() {
|
|
||||||
return peer->isClient();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Tries to send the text \a message to the currently running
|
|
||||||
instance. The QtSingleCoreApplication object in the running instance
|
|
||||||
will emit the messageReceived() signal when it receives the
|
|
||||||
message.
|
|
||||||
|
|
||||||
This function returns true if the message has been sent to, and
|
|
||||||
processed by, the current instance. If there is no instance
|
|
||||||
currently running, or if the running instance fails to process the
|
|
||||||
message within \a timeout milliseconds, this function return false.
|
|
||||||
|
|
||||||
\sa isRunning(), messageReceived()
|
|
||||||
*/
|
|
||||||
|
|
||||||
bool QtSingleCoreApplication::sendMessage(const QString &message, int timeout) {
|
|
||||||
return peer->sendMessage(message, timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Returns the application identifier. Two processes with the same
|
|
||||||
identifier will be regarded as instances of the same application.
|
|
||||||
*/
|
|
||||||
|
|
||||||
QString QtSingleCoreApplication::id() const {
|
|
||||||
return peer->applicationId();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\fn void QtSingleCoreApplication::messageReceived(const QString& message)
|
|
||||||
|
|
||||||
This signal is emitted when the current instance receives a \a
|
|
||||||
message from another instance of this application.
|
|
||||||
|
|
||||||
\sa sendMessage()
|
|
||||||
*/
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
**
|
|
||||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
|
||||||
** All rights reserved.
|
|
||||||
**
|
|
||||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
|
||||||
**
|
|
||||||
** This file is part of a Qt Solutions component.
|
|
||||||
**
|
|
||||||
** You may use this file under the terms of the BSD license as follows:
|
|
||||||
**
|
|
||||||
** "Redistribution and use in source and binary forms, with or without
|
|
||||||
** modification, are permitted provided that the following conditions are
|
|
||||||
** met:
|
|
||||||
** * Redistributions of source code must retain the above copyright
|
|
||||||
** notice, this list of conditions and the following disclaimer.
|
|
||||||
** * Redistributions in binary form must reproduce the above copyright
|
|
||||||
** notice, this list of conditions and the following disclaimer in
|
|
||||||
** the documentation and/or other materials provided with the
|
|
||||||
** distribution.
|
|
||||||
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
|
|
||||||
** the names of its contributors may be used to endorse or promote
|
|
||||||
** products derived from this software without specific prior written
|
|
||||||
** permission.
|
|
||||||
**
|
|
||||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
|
||||||
**
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifndef QTSINGLECOREAPPLICATION_H
|
|
||||||
#define QTSINGLECOREAPPLICATION_H
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <QCoreApplication>
|
|
||||||
#include <QObject>
|
|
||||||
#include <QString>
|
|
||||||
|
|
||||||
class QtLocalPeer;
|
|
||||||
|
|
||||||
class QtSingleCoreApplication : public QCoreApplication
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
QtSingleCoreApplication(int &argc, char **argv);
|
|
||||||
QtSingleCoreApplication(const QString &id, int &argc, char **argv);
|
|
||||||
|
|
||||||
bool isRunning();
|
|
||||||
QString id() const;
|
|
||||||
|
|
||||||
public Q_SLOTS:
|
|
||||||
bool sendMessage(const QString &message, int timeout = 5000);
|
|
||||||
|
|
||||||
|
|
||||||
Q_SIGNALS:
|
|
||||||
void messageReceived(const QString &message);
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
|
||||||
QtLocalPeer* peer;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // QTSINGLECOREAPPLICATION_H
|
|
||||||
43
3rdparty/qxt/CMakeLists.txt
vendored
43
3rdparty/qxt/CMakeLists.txt
vendored
@@ -1,43 +0,0 @@
|
|||||||
cmake_minimum_required(VERSION 2.8.11)
|
|
||||||
set(CMAKE_CXX_STANDARD 11)
|
|
||||||
|
|
||||||
include_directories(${Qt5Gui_PRIVATE_INCLUDE_DIRS})
|
|
||||||
if (NOT WIN32 AND NOT APPLE)
|
|
||||||
find_path(HAVE_QPA_QPLATFORMNATIVEINTERFACE_H qpa/qplatformnativeinterface.h PATHS ${Qt5Gui_PRIVATE_INCLUDE_DIRS})
|
|
||||||
if(NOT HAVE_QPA_QPLATFORMNATIVEINTERFACE_H)
|
|
||||||
message(FATAL_ERROR "Missing qpa/qplatformnativeinterface.h, check that you got the QT private headers installed (package libQt5Gui-private-headers-devel, qtbase5-private-dev or similar)")
|
|
||||||
endif(NOT HAVE_QPA_QPLATFORMNATIVEINTERFACE_H)
|
|
||||||
endif(NOT WIN32 AND NOT APPLE)
|
|
||||||
|
|
||||||
set(QXT-SOURCES
|
|
||||||
qxtglobal.cpp
|
|
||||||
qxtglobalshortcut.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
set(QXT-MOC-HEADERS
|
|
||||||
qxtglobalshortcut.h
|
|
||||||
)
|
|
||||||
|
|
||||||
find_package(X11)
|
|
||||||
include_directories(${X11_INCLUDE_DIR})
|
|
||||||
|
|
||||||
if(WIN32)
|
|
||||||
set(QXT-SOURCES ${QXT-SOURCES} qxtglobalshortcut_win.cpp)
|
|
||||||
elseif(APPLE)
|
|
||||||
set(QXT-SOURCES ${QXT-SOURCES} qxtglobalshortcut_mac.cpp)
|
|
||||||
else(WIN32)
|
|
||||||
set(QXT-SOURCES ${QXT-SOURCES} qxtglobalshortcut_x11.cpp)
|
|
||||||
endif(WIN32)
|
|
||||||
|
|
||||||
QT5_WRAP_CPP(QXT-SOURCES-MOC ${QXT-MOC-HEADERS})
|
|
||||||
|
|
||||||
ADD_LIBRARY(qxt STATIC
|
|
||||||
${QXT-SOURCES}
|
|
||||||
${QXT-SOURCES-MOC}
|
|
||||||
)
|
|
||||||
|
|
||||||
if(WIN32)
|
|
||||||
target_link_libraries(qxt Qt5::Core Qt5::Widgets)
|
|
||||||
else(WIN32)
|
|
||||||
target_link_libraries(qxt Qt5::Core Qt5::Widgets Qt5::X11Extras)
|
|
||||||
endif(WIN32)
|
|
||||||
89
3rdparty/qxt/LICENSE
vendored
89
3rdparty/qxt/LICENSE
vendored
@@ -1,89 +0,0 @@
|
|||||||
Qt Extension Library
|
|
||||||
Copyright (C) 2007 Qxt Foundation
|
|
||||||
|
|
||||||
------------------- Disclaimer ------------------------------------------------
|
|
||||||
|
|
||||||
Until the Qxt Foundation is legally established, copyright for the
|
|
||||||
source code falls back to the original contributor. For information about the
|
|
||||||
status of the Qxt Foundation, or about the copyright status of any part of Qxt,
|
|
||||||
contact the Qxt project maintainers at <foundation@libqxt.org>
|
|
||||||
|
|
||||||
Once the Qxt Foundation has been legally established, all contributors must
|
|
||||||
transfer all copyright interest to the Qxt Foundation before their submissions
|
|
||||||
will be added to the project.
|
|
||||||
|
|
||||||
------------------- License ---------------------------------------------------
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or modify it
|
|
||||||
under the terms of the Common Public License, version 1.0, as published by IBM
|
|
||||||
or under the terms of the GNU Lesser General Public License, version 2.1,
|
|
||||||
as published by the Free Software Foundation
|
|
||||||
|
|
||||||
This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
|
|
||||||
WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
|
|
||||||
You should have received a copy of the CPL along with this file.
|
|
||||||
See the LICENSE file and the cpl1.0.txt file included with the source
|
|
||||||
distribution for more information. If you did not receive a copy of the
|
|
||||||
license, contact the Qxt Foundation.
|
|
||||||
|
|
||||||
You should have received a copy of the LGPL along with this file.
|
|
||||||
See the LICENSE file and the lgpl-2.1.txt file included with the source
|
|
||||||
distribution for more information. If you did not receive a copy of the
|
|
||||||
license, contact the Qxt Foundation.
|
|
||||||
|
|
||||||
Parts of Qxt depend on Qt 4 and/or other libraries that have their own
|
|
||||||
licenses. Qxt is independent of these licenses; however, use of these other
|
|
||||||
libraries is subject to their respective license agreements.
|
|
||||||
|
|
||||||
------------------- Intent ----------------------------------------------------
|
|
||||||
|
|
||||||
The following section describes the opinions and intent of the Qxt Foundation
|
|
||||||
with regards to the licensing and use of the Qxt source code and library. In
|
|
||||||
the event that the CPL is found to be illegal or invalid, or if any application
|
|
||||||
or clause of the license is subjected to question or abuse, this section is a
|
|
||||||
general statement of the desired interpretation.
|
|
||||||
|
|
||||||
This section has no legal standing and the statements made here are strictly
|
|
||||||
subject to the text of the CPL; that is, if this section and the CPL are in
|
|
||||||
disagreement, the text of the CPL takes precedence. In no way does this
|
|
||||||
intent grant you any additional rights or impose any additional restrictions.
|
|
||||||
|
|
||||||
If you have questions about licensing, contact the maintainers.
|
|
||||||
|
|
||||||
Qxt is built and supported by open-source enthusiasts.
|
|
||||||
- Please respect the open-source background of the contributors. The code is
|
|
||||||
provided for everyone's use; you may not restrict the rights of anyone to
|
|
||||||
use it.
|
|
||||||
- No individual may claim ownership of any part of the code. It belongs
|
|
||||||
to the community.
|
|
||||||
- You may modify the source code to suit your needs, but these changes
|
|
||||||
must be made free. If you distribute a modified form of Qxt, you must
|
|
||||||
also distribute the entire source code of the modified form.
|
|
||||||
- Digital Rights Management (DRM) puts unfair, unfree restrictions on
|
|
||||||
users and developers. It is the opposite of Free Software. We can't
|
|
||||||
stop you from using it, but please don't use the Qxt name for software
|
|
||||||
restricted by DRM.
|
|
||||||
- Please respect the time and effort put into the project by the developers.
|
|
||||||
- If you find Qxt useful, it would be appreciated if you would include
|
|
||||||
text in your application (for instance, in the About dialog) giving
|
|
||||||
acknowledgement to Qxt.
|
|
||||||
- If you make modifications to the source code, you must not call the
|
|
||||||
modified version "Qxt." It's okay to include "Qxt" in the name, but
|
|
||||||
anyone who receives the modified version needs to know that it's not
|
|
||||||
the same as the version distributed by the Qxt Foundation.
|
|
||||||
- We want everyone to be able to use Qxt without restrictions.
|
|
||||||
- If you distribute Qxt in compiled binary form, please ensure that
|
|
||||||
everyone who receives it can get the source code used to create it.
|
|
||||||
- You are free to use Qxt in closed-source applications as long as you
|
|
||||||
distribute Qxt in an open-source fashion. This does not require you
|
|
||||||
to make your entire application open-source.
|
|
||||||
- The Qxt Foundation is a non-profit, non-political organization.
|
|
||||||
- Please don't use the Qxt name in any political or semi-political
|
|
||||||
propaganda or publication. We don't like it.
|
|
||||||
- Qxt is distributed "as-is," with no warranty.
|
|
||||||
- If it makes your program crash, your computer blow up, or tiny demons
|
|
||||||
fly out of your nose, please don't sue us.
|
|
||||||
|
|
||||||
372
3rdparty/qxt/keymapper_x11.h
vendored
372
3rdparty/qxt/keymapper_x11.h
vendored
@@ -1,372 +0,0 @@
|
|||||||
#ifndef KEYMAPPER_X11_H
|
|
||||||
#define KEYMAPPER_X11_H
|
|
||||||
|
|
||||||
// (davidsansome) Nicked from qkeymapper_x11.cpp
|
|
||||||
|
|
||||||
#include <Qt>
|
|
||||||
|
|
||||||
#define XK_MISCELLANY
|
|
||||||
#define XK_LATIN1
|
|
||||||
#define XK_KOREAN
|
|
||||||
#define XK_XKB_KEYS
|
|
||||||
#include <X11/keysymdef.h>
|
|
||||||
|
|
||||||
//
|
|
||||||
// Keyboard event translation
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef XK_ISO_Left_Tab
|
|
||||||
#define XK_ISO_Left_Tab 0xFE20
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef XK_dead_hook
|
|
||||||
#define XK_dead_hook 0xFE61
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef XK_dead_horn
|
|
||||||
#define XK_dead_horn 0xFE62
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef XK_Codeinput
|
|
||||||
#define XK_Codeinput 0xFF37
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef XK_Kanji_Bangou
|
|
||||||
#define XK_Kanji_Bangou 0xFF37 /* same as codeinput */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Fix old X libraries
|
|
||||||
#ifndef XK_KP_Home
|
|
||||||
#define XK_KP_Home 0xFF95
|
|
||||||
#endif
|
|
||||||
#ifndef XK_KP_Left
|
|
||||||
#define XK_KP_Left 0xFF96
|
|
||||||
#endif
|
|
||||||
#ifndef XK_KP_Up
|
|
||||||
#define XK_KP_Up 0xFF97
|
|
||||||
#endif
|
|
||||||
#ifndef XK_KP_Right
|
|
||||||
#define XK_KP_Right 0xFF98
|
|
||||||
#endif
|
|
||||||
#ifndef XK_KP_Down
|
|
||||||
#define XK_KP_Down 0xFF99
|
|
||||||
#endif
|
|
||||||
#ifndef XK_KP_Prior
|
|
||||||
#define XK_KP_Prior 0xFF9A
|
|
||||||
#endif
|
|
||||||
#ifndef XK_KP_Next
|
|
||||||
#define XK_KP_Next 0xFF9B
|
|
||||||
#endif
|
|
||||||
#ifndef XK_KP_End
|
|
||||||
#define XK_KP_End 0xFF9C
|
|
||||||
#endif
|
|
||||||
#ifndef XK_KP_Insert
|
|
||||||
#define XK_KP_Insert 0xFF9E
|
|
||||||
#endif
|
|
||||||
#ifndef XK_KP_Delete
|
|
||||||
#define XK_KP_Delete 0xFF9F
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// the next lines are taken from XFree > 4.0 (X11/XF86keysyms.h), defining some special
|
|
||||||
// multimedia keys. They are included here as not every system has them.
|
|
||||||
#define XF86XK_Standby 0x1008FF10
|
|
||||||
#define XF86XK_AudioLowerVolume 0x1008FF11
|
|
||||||
#define XF86XK_AudioMute 0x1008FF12
|
|
||||||
#define XF86XK_AudioRaiseVolume 0x1008FF13
|
|
||||||
#define XF86XK_AudioPlay 0x1008FF14
|
|
||||||
#define XF86XK_AudioStop 0x1008FF15
|
|
||||||
#define XF86XK_AudioPrev 0x1008FF16
|
|
||||||
#define XF86XK_AudioNext 0x1008FF17
|
|
||||||
#define XF86XK_HomePage 0x1008FF18
|
|
||||||
#define XF86XK_Calculator 0x1008FF1D
|
|
||||||
#define XF86XK_Mail 0x1008FF19
|
|
||||||
#define XF86XK_Start 0x1008FF1A
|
|
||||||
#define XF86XK_Search 0x1008FF1B
|
|
||||||
#define XF86XK_AudioRecord 0x1008FF1C
|
|
||||||
#define XF86XK_Back 0x1008FF26
|
|
||||||
#define XF86XK_Forward 0x1008FF27
|
|
||||||
#define XF86XK_Stop 0x1008FF28
|
|
||||||
#define XF86XK_Refresh 0x1008FF29
|
|
||||||
#define XF86XK_Favorites 0x1008FF30
|
|
||||||
#define XF86XK_AudioPause 0x1008FF31
|
|
||||||
#define XF86XK_AudioMedia 0x1008FF32
|
|
||||||
#define XF86XK_MyComputer 0x1008FF33
|
|
||||||
#define XF86XK_OpenURL 0x1008FF38
|
|
||||||
#define XF86XK_Launch0 0x1008FF40
|
|
||||||
#define XF86XK_Launch1 0x1008FF41
|
|
||||||
#define XF86XK_Launch2 0x1008FF42
|
|
||||||
#define XF86XK_Launch3 0x1008FF43
|
|
||||||
#define XF86XK_Launch4 0x1008FF44
|
|
||||||
#define XF86XK_Launch5 0x1008FF45
|
|
||||||
#define XF86XK_Launch6 0x1008FF46
|
|
||||||
#define XF86XK_Launch7 0x1008FF47
|
|
||||||
#define XF86XK_Launch8 0x1008FF48
|
|
||||||
#define XF86XK_Launch9 0x1008FF49
|
|
||||||
#define XF86XK_LaunchA 0x1008FF4A
|
|
||||||
#define XF86XK_LaunchB 0x1008FF4B
|
|
||||||
#define XF86XK_LaunchC 0x1008FF4C
|
|
||||||
#define XF86XK_LaunchD 0x1008FF4D
|
|
||||||
#define XF86XK_LaunchE 0x1008FF4E
|
|
||||||
#define XF86XK_LaunchF 0x1008FF4F
|
|
||||||
// end of XF86keysyms.h
|
|
||||||
|
|
||||||
// Special keys used by Qtopia, mapped into the X11 private keypad range.
|
|
||||||
#define QTOPIAXK_Select 0x11000601
|
|
||||||
#define QTOPIAXK_Yes 0x11000602
|
|
||||||
#define QTOPIAXK_No 0x11000603
|
|
||||||
#define QTOPIAXK_Cancel 0x11000604
|
|
||||||
#define QTOPIAXK_Printer 0x11000605
|
|
||||||
#define QTOPIAXK_Execute 0x11000606
|
|
||||||
#define QTOPIAXK_Sleep 0x11000607
|
|
||||||
#define QTOPIAXK_Play 0x11000608
|
|
||||||
#define QTOPIAXK_Zoom 0x11000609
|
|
||||||
#define QTOPIAXK_Context1 0x1100060A
|
|
||||||
#define QTOPIAXK_Context2 0x1100060B
|
|
||||||
#define QTOPIAXK_Context3 0x1100060C
|
|
||||||
#define QTOPIAXK_Context4 0x1100060D
|
|
||||||
#define QTOPIAXK_Call 0x1100060E
|
|
||||||
#define QTOPIAXK_Hangup 0x1100060F
|
|
||||||
#define QTOPIAXK_Flip 0x11000610
|
|
||||||
|
|
||||||
// keyboard mapping table
|
|
||||||
static const unsigned int KeyTbl[] = {
|
|
||||||
|
|
||||||
// misc keys
|
|
||||||
|
|
||||||
XK_Escape, Qt::Key_Escape,
|
|
||||||
XK_Tab, Qt::Key_Tab,
|
|
||||||
XK_ISO_Left_Tab, Qt::Key_Backtab,
|
|
||||||
XK_BackSpace, Qt::Key_Backspace,
|
|
||||||
XK_Return, Qt::Key_Return,
|
|
||||||
XK_Insert, Qt::Key_Insert,
|
|
||||||
XK_Delete, Qt::Key_Delete,
|
|
||||||
XK_Clear, Qt::Key_Delete,
|
|
||||||
XK_Pause, Qt::Key_Pause,
|
|
||||||
XK_Print, Qt::Key_Print,
|
|
||||||
0x1005FF60, Qt::Key_SysReq, // hardcoded Sun SysReq
|
|
||||||
0x1007ff00, Qt::Key_SysReq, // hardcoded X386 SysReq
|
|
||||||
|
|
||||||
// cursor movement
|
|
||||||
|
|
||||||
XK_Home, Qt::Key_Home,
|
|
||||||
XK_End, Qt::Key_End,
|
|
||||||
XK_Left, Qt::Key_Left,
|
|
||||||
XK_Up, Qt::Key_Up,
|
|
||||||
XK_Right, Qt::Key_Right,
|
|
||||||
XK_Down, Qt::Key_Down,
|
|
||||||
XK_Prior, Qt::Key_PageUp,
|
|
||||||
XK_Next, Qt::Key_PageDown,
|
|
||||||
|
|
||||||
// modifiers
|
|
||||||
|
|
||||||
XK_Shift_L, Qt::Key_Shift,
|
|
||||||
XK_Shift_R, Qt::Key_Shift,
|
|
||||||
XK_Shift_Lock, Qt::Key_Shift,
|
|
||||||
XK_Control_L, Qt::Key_Control,
|
|
||||||
XK_Control_R, Qt::Key_Control,
|
|
||||||
XK_Meta_L, Qt::Key_Meta,
|
|
||||||
XK_Meta_R, Qt::Key_Meta,
|
|
||||||
XK_Alt_L, Qt::Key_Alt,
|
|
||||||
XK_Alt_R, Qt::Key_Alt,
|
|
||||||
XK_Caps_Lock, Qt::Key_CapsLock,
|
|
||||||
XK_Num_Lock, Qt::Key_NumLock,
|
|
||||||
XK_Scroll_Lock, Qt::Key_ScrollLock,
|
|
||||||
XK_Super_L, Qt::Key_Super_L,
|
|
||||||
XK_Super_R, Qt::Key_Super_R,
|
|
||||||
XK_Menu, Qt::Key_Menu,
|
|
||||||
XK_Hyper_L, Qt::Key_Hyper_L,
|
|
||||||
XK_Hyper_R, Qt::Key_Hyper_R,
|
|
||||||
XK_Help, Qt::Key_Help,
|
|
||||||
0x1000FF74, Qt::Key_Backtab, // hardcoded HP backtab
|
|
||||||
0x1005FF10, Qt::Key_F11, // hardcoded Sun F36 (labeled F11)
|
|
||||||
0x1005FF11, Qt::Key_F12, // hardcoded Sun F37 (labeled F12)
|
|
||||||
|
|
||||||
// numeric and function keypad keys
|
|
||||||
|
|
||||||
XK_KP_Enter, Qt::Key_Enter,
|
|
||||||
|
|
||||||
// special and additional keys
|
|
||||||
|
|
||||||
XK_Clear, Qt::Key_Clear,
|
|
||||||
XK_Delete, Qt::Key_Delete,
|
|
||||||
XK_space, Qt::Key_Space,
|
|
||||||
XK_exclam, Qt::Key_Exclam,
|
|
||||||
XK_quotedbl, Qt::Key_QuoteDbl,
|
|
||||||
XK_numbersign, Qt::Key_NumberSign,
|
|
||||||
XK_dollar, Qt::Key_Dollar,
|
|
||||||
XK_percent, Qt::Key_Percent,
|
|
||||||
XK_ampersand, Qt::Key_Ampersand,
|
|
||||||
XK_apostrophe, Qt::Key_Apostrophe,
|
|
||||||
XK_parenleft, Qt::Key_ParenLeft,
|
|
||||||
XK_parenright, Qt::Key_ParenRight,
|
|
||||||
XK_asterisk, Qt::Key_Asterisk,
|
|
||||||
XK_plus, Qt::Key_Plus,
|
|
||||||
XK_comma, Qt::Key_Comma,
|
|
||||||
XK_minus, Qt::Key_Minus,
|
|
||||||
XK_period, Qt::Key_Period,
|
|
||||||
XK_slash, Qt::Key_Slash,
|
|
||||||
XK_colon, Qt::Key_Colon,
|
|
||||||
XK_semicolon, Qt::Key_Semicolon,
|
|
||||||
XK_less, Qt::Key_Less,
|
|
||||||
XK_equal, Qt::Key_Equal,
|
|
||||||
XK_greater, Qt::Key_Greater,
|
|
||||||
XK_question, Qt::Key_Question,
|
|
||||||
XK_bracketleft, Qt::Key_BracketLeft,
|
|
||||||
XK_backslash, Qt::Key_Backslash,
|
|
||||||
XK_bracketright, Qt::Key_BracketRight,
|
|
||||||
XK_asciicircum, Qt::Key_AsciiCircum,
|
|
||||||
XK_underscore, Qt::Key_Underscore,
|
|
||||||
|
|
||||||
// International input method support keys
|
|
||||||
|
|
||||||
// International & multi-key character composition
|
|
||||||
XK_ISO_Level3_Shift, Qt::Key_AltGr,
|
|
||||||
XK_Multi_key, Qt::Key_Multi_key,
|
|
||||||
XK_Codeinput, Qt::Key_Codeinput,
|
|
||||||
XK_SingleCandidate, Qt::Key_SingleCandidate,
|
|
||||||
XK_MultipleCandidate, Qt::Key_MultipleCandidate,
|
|
||||||
XK_PreviousCandidate, Qt::Key_PreviousCandidate,
|
|
||||||
|
|
||||||
// Misc Functions
|
|
||||||
XK_Mode_switch, Qt::Key_Mode_switch,
|
|
||||||
XK_script_switch, Qt::Key_Mode_switch,
|
|
||||||
|
|
||||||
// Japanese keyboard support
|
|
||||||
XK_Kanji, Qt::Key_Kanji,
|
|
||||||
XK_Muhenkan, Qt::Key_Muhenkan,
|
|
||||||
//XK_Henkan_Mode, Qt::Key_Henkan_Mode,
|
|
||||||
XK_Henkan_Mode, Qt::Key_Henkan,
|
|
||||||
XK_Henkan, Qt::Key_Henkan,
|
|
||||||
XK_Romaji, Qt::Key_Romaji,
|
|
||||||
XK_Hiragana, Qt::Key_Hiragana,
|
|
||||||
XK_Katakana, Qt::Key_Katakana,
|
|
||||||
XK_Hiragana_Katakana, Qt::Key_Hiragana_Katakana,
|
|
||||||
XK_Zenkaku, Qt::Key_Zenkaku,
|
|
||||||
XK_Hankaku, Qt::Key_Hankaku,
|
|
||||||
XK_Zenkaku_Hankaku, Qt::Key_Zenkaku_Hankaku,
|
|
||||||
XK_Touroku, Qt::Key_Touroku,
|
|
||||||
XK_Massyo, Qt::Key_Massyo,
|
|
||||||
XK_Kana_Lock, Qt::Key_Kana_Lock,
|
|
||||||
XK_Kana_Shift, Qt::Key_Kana_Shift,
|
|
||||||
XK_Eisu_Shift, Qt::Key_Eisu_Shift,
|
|
||||||
XK_Eisu_toggle, Qt::Key_Eisu_toggle,
|
|
||||||
//XK_Kanji_Bangou, Qt::Key_Kanji_Bangou,
|
|
||||||
//XK_Zen_Koho, Qt::Key_Zen_Koho,
|
|
||||||
//XK_Mae_Koho, Qt::Key_Mae_Koho,
|
|
||||||
XK_Kanji_Bangou, Qt::Key_Codeinput,
|
|
||||||
XK_Zen_Koho, Qt::Key_MultipleCandidate,
|
|
||||||
XK_Mae_Koho, Qt::Key_PreviousCandidate,
|
|
||||||
|
|
||||||
#ifdef XK_KOREAN
|
|
||||||
// Korean keyboard support
|
|
||||||
XK_Hangul, Qt::Key_Hangul,
|
|
||||||
XK_Hangul_Start, Qt::Key_Hangul_Start,
|
|
||||||
XK_Hangul_End, Qt::Key_Hangul_End,
|
|
||||||
XK_Hangul_Hanja, Qt::Key_Hangul_Hanja,
|
|
||||||
XK_Hangul_Jamo, Qt::Key_Hangul_Jamo,
|
|
||||||
XK_Hangul_Romaja, Qt::Key_Hangul_Romaja,
|
|
||||||
//XK_Hangul_Codeinput, Qt::Key_Hangul_Codeinput,
|
|
||||||
XK_Hangul_Codeinput, Qt::Key_Codeinput,
|
|
||||||
XK_Hangul_Jeonja, Qt::Key_Hangul_Jeonja,
|
|
||||||
XK_Hangul_Banja, Qt::Key_Hangul_Banja,
|
|
||||||
XK_Hangul_PreHanja, Qt::Key_Hangul_PreHanja,
|
|
||||||
XK_Hangul_PostHanja, Qt::Key_Hangul_PostHanja,
|
|
||||||
//XK_Hangul_SingleCandidate,Qt::Key_Hangul_SingleCandidate,
|
|
||||||
//XK_Hangul_MultipleCandidate,Qt::Key_Hangul_MultipleCandidate,
|
|
||||||
//XK_Hangul_PreviousCandidate,Qt::Key_Hangul_PreviousCandidate,
|
|
||||||
XK_Hangul_SingleCandidate, Qt::Key_SingleCandidate,
|
|
||||||
XK_Hangul_MultipleCandidate,Qt::Key_MultipleCandidate,
|
|
||||||
XK_Hangul_PreviousCandidate,Qt::Key_PreviousCandidate,
|
|
||||||
XK_Hangul_Special, Qt::Key_Hangul_Special,
|
|
||||||
//XK_Hangul_switch, Qt::Key_Hangul_switch,
|
|
||||||
XK_Hangul_switch, Qt::Key_Mode_switch,
|
|
||||||
#endif // XK_KOREAN
|
|
||||||
|
|
||||||
// dead keys
|
|
||||||
XK_dead_grave, Qt::Key_Dead_Grave,
|
|
||||||
XK_dead_acute, Qt::Key_Dead_Acute,
|
|
||||||
XK_dead_circumflex, Qt::Key_Dead_Circumflex,
|
|
||||||
XK_dead_tilde, Qt::Key_Dead_Tilde,
|
|
||||||
XK_dead_macron, Qt::Key_Dead_Macron,
|
|
||||||
XK_dead_breve, Qt::Key_Dead_Breve,
|
|
||||||
XK_dead_abovedot, Qt::Key_Dead_Abovedot,
|
|
||||||
XK_dead_diaeresis, Qt::Key_Dead_Diaeresis,
|
|
||||||
XK_dead_abovering, Qt::Key_Dead_Abovering,
|
|
||||||
XK_dead_doubleacute, Qt::Key_Dead_Doubleacute,
|
|
||||||
XK_dead_caron, Qt::Key_Dead_Caron,
|
|
||||||
XK_dead_cedilla, Qt::Key_Dead_Cedilla,
|
|
||||||
XK_dead_ogonek, Qt::Key_Dead_Ogonek,
|
|
||||||
XK_dead_iota, Qt::Key_Dead_Iota,
|
|
||||||
XK_dead_voiced_sound, Qt::Key_Dead_Voiced_Sound,
|
|
||||||
XK_dead_semivoiced_sound, Qt::Key_Dead_Semivoiced_Sound,
|
|
||||||
XK_dead_belowdot, Qt::Key_Dead_Belowdot,
|
|
||||||
XK_dead_hook, Qt::Key_Dead_Hook,
|
|
||||||
XK_dead_horn, Qt::Key_Dead_Horn,
|
|
||||||
|
|
||||||
// Special multimedia keys
|
|
||||||
// currently only tested with MS internet keyboard
|
|
||||||
|
|
||||||
// browsing keys
|
|
||||||
XF86XK_Back, Qt::Key_Back,
|
|
||||||
XF86XK_Forward, Qt::Key_Forward,
|
|
||||||
XF86XK_Stop, Qt::Key_Stop,
|
|
||||||
XF86XK_Refresh, Qt::Key_Refresh,
|
|
||||||
XF86XK_Favorites, Qt::Key_Favorites,
|
|
||||||
XF86XK_AudioMedia, Qt::Key_LaunchMedia,
|
|
||||||
XF86XK_OpenURL, Qt::Key_OpenUrl,
|
|
||||||
XF86XK_HomePage, Qt::Key_HomePage,
|
|
||||||
XF86XK_Search, Qt::Key_Search,
|
|
||||||
|
|
||||||
// media keys
|
|
||||||
XF86XK_AudioLowerVolume, Qt::Key_VolumeDown,
|
|
||||||
XF86XK_AudioMute, Qt::Key_VolumeMute,
|
|
||||||
XF86XK_AudioRaiseVolume, Qt::Key_VolumeUp,
|
|
||||||
XF86XK_AudioPlay, Qt::Key_MediaPlay,
|
|
||||||
XF86XK_AudioStop, Qt::Key_MediaStop,
|
|
||||||
XF86XK_AudioPrev, Qt::Key_MediaPrevious,
|
|
||||||
XF86XK_AudioNext, Qt::Key_MediaNext,
|
|
||||||
XF86XK_AudioRecord, Qt::Key_MediaRecord,
|
|
||||||
|
|
||||||
// launch keys
|
|
||||||
XF86XK_Mail, Qt::Key_LaunchMail,
|
|
||||||
XF86XK_MyComputer, Qt::Key_Launch0,
|
|
||||||
XF86XK_Calculator, Qt::Key_Launch1,
|
|
||||||
XF86XK_Standby, Qt::Key_Standby,
|
|
||||||
|
|
||||||
XF86XK_Launch0, Qt::Key_Launch2,
|
|
||||||
XF86XK_Launch1, Qt::Key_Launch3,
|
|
||||||
XF86XK_Launch2, Qt::Key_Launch4,
|
|
||||||
XF86XK_Launch3, Qt::Key_Launch5,
|
|
||||||
XF86XK_Launch4, Qt::Key_Launch6,
|
|
||||||
XF86XK_Launch5, Qt::Key_Launch7,
|
|
||||||
XF86XK_Launch6, Qt::Key_Launch8,
|
|
||||||
XF86XK_Launch7, Qt::Key_Launch9,
|
|
||||||
XF86XK_Launch8, Qt::Key_LaunchA,
|
|
||||||
XF86XK_Launch9, Qt::Key_LaunchB,
|
|
||||||
XF86XK_LaunchA, Qt::Key_LaunchC,
|
|
||||||
XF86XK_LaunchB, Qt::Key_LaunchD,
|
|
||||||
XF86XK_LaunchC, Qt::Key_LaunchE,
|
|
||||||
XF86XK_LaunchD, Qt::Key_LaunchF,
|
|
||||||
|
|
||||||
// Qtopia keys
|
|
||||||
QTOPIAXK_Select, Qt::Key_Select,
|
|
||||||
QTOPIAXK_Yes, Qt::Key_Yes,
|
|
||||||
QTOPIAXK_No, Qt::Key_No,
|
|
||||||
QTOPIAXK_Cancel, Qt::Key_Cancel,
|
|
||||||
QTOPIAXK_Printer, Qt::Key_Printer,
|
|
||||||
QTOPIAXK_Execute, Qt::Key_Execute,
|
|
||||||
QTOPIAXK_Sleep, Qt::Key_Sleep,
|
|
||||||
QTOPIAXK_Play, Qt::Key_Play,
|
|
||||||
QTOPIAXK_Zoom, Qt::Key_Zoom,
|
|
||||||
QTOPIAXK_Context1, Qt::Key_Context1,
|
|
||||||
QTOPIAXK_Context2, Qt::Key_Context2,
|
|
||||||
QTOPIAXK_Context3, Qt::Key_Context3,
|
|
||||||
QTOPIAXK_Context4, Qt::Key_Context4,
|
|
||||||
QTOPIAXK_Call, Qt::Key_Call,
|
|
||||||
QTOPIAXK_Hangup, Qt::Key_Hangup,
|
|
||||||
QTOPIAXK_Flip, Qt::Key_Flip,
|
|
||||||
|
|
||||||
0, 0
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // KEYMAPPER_X11_H
|
|
||||||
251
3rdparty/qxt/qxtglobal.cpp
vendored
251
3rdparty/qxt/qxtglobal.cpp
vendored
@@ -1,251 +0,0 @@
|
|||||||
|
|
||||||
/****************************************************************************
|
|
||||||
** Copyright (c) 2006 - 2011, the LibQxt project.
|
|
||||||
** See the Qxt AUTHORS file for a list of authors and copyright holders.
|
|
||||||
** All rights reserved.
|
|
||||||
**
|
|
||||||
** Redistribution and use in source and binary forms, with or without
|
|
||||||
** modification, are permitted provided that the following conditions are met:
|
|
||||||
** * Redistributions of source code must retain the above copyright
|
|
||||||
** notice, this list of conditions and the following disclaimer.
|
|
||||||
** * Redistributions in binary form must reproduce the above copyright
|
|
||||||
** notice, this list of conditions and the following disclaimer in the
|
|
||||||
** documentation and/or other materials provided with the distribution.
|
|
||||||
** * Neither the name of the LibQxt project nor the
|
|
||||||
** names of its contributors may be used to endorse or promote products
|
|
||||||
** derived from this software without specific prior written permission.
|
|
||||||
**
|
|
||||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
** DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
|
||||||
** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
**
|
|
||||||
** <http://libqxt.org> <foundation@libqxt.org>
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
#include "qxtglobal.h"
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\headerfile <QxtGlobal>
|
|
||||||
\title Global Qxt Declarations
|
|
||||||
\inmodule QxtCore
|
|
||||||
|
|
||||||
\brief The <QxtGlobal> header provides basic declarations and
|
|
||||||
is included by all other Qxt headers.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\macro QXT_VERSION
|
|
||||||
\relates <QxtGlobal>
|
|
||||||
|
|
||||||
This macro expands a numeric value of the form 0xMMNNPP (MM =
|
|
||||||
major, NN = minor, PP = patch) that specifies Qxt's version
|
|
||||||
number. For example, if you compile your application against Qxt
|
|
||||||
0.4.0, the QXT_VERSION macro will expand to 0x000400.
|
|
||||||
|
|
||||||
You can use QXT_VERSION to use the latest Qt features where
|
|
||||||
available. For example:
|
|
||||||
\code
|
|
||||||
#if QXT_VERSION >= 0x000400
|
|
||||||
qxtTabWidget->setTabMovementMode(QxtTabWidget::InPlaceMovement);
|
|
||||||
#endif
|
|
||||||
\endcode
|
|
||||||
|
|
||||||
\sa QXT_VERSION_STR, qxtVersion()
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\macro QXT_VERSION_STR
|
|
||||||
\relates <QxtGlobal>
|
|
||||||
|
|
||||||
This macro expands to a string that specifies Qxt's version number
|
|
||||||
(for example, "0.4.0"). This is the version against which the
|
|
||||||
application is compiled.
|
|
||||||
|
|
||||||
\sa qxtVersion(), QXT_VERSION
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\relates <QxtGlobal>
|
|
||||||
|
|
||||||
Returns the version number of Qxt at run-time as a string (for
|
|
||||||
example, "0.4.0"). This may be a different version than the
|
|
||||||
version the application was compiled against.
|
|
||||||
|
|
||||||
\sa QXT_VERSION_STR
|
|
||||||
*/
|
|
||||||
const char * qxtVersion()
|
|
||||||
{
|
|
||||||
return QXT_VERSION_STR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\headerfile <QxtPimpl>
|
|
||||||
\title The Qxt private implementation
|
|
||||||
\inmodule QxtCore
|
|
||||||
|
|
||||||
\brief The <QxtPimpl> header provides tools for hiding
|
|
||||||
details of a class.
|
|
||||||
|
|
||||||
Application code generally doesn't have to be concerned about hiding its
|
|
||||||
implementation details, but when writing library code it is important to
|
|
||||||
maintain a constant interface, both source and binary. Maintaining a constant
|
|
||||||
source interface is easy enough, but keeping the binary interface constant
|
|
||||||
means moving implementation details into a private class. The PIMPL, or
|
|
||||||
d-pointer, idiom is a common method of implementing this separation. QxtPimpl
|
|
||||||
offers a convenient way to connect the public and private sides of your class.
|
|
||||||
|
|
||||||
\section1 Getting Started
|
|
||||||
Before you declare the public class, you need to make a forward declaration
|
|
||||||
of the private class. The private class must have the same name as the public
|
|
||||||
class, followed by the word Private. For example, a class named MyTest would
|
|
||||||
declare the private class with:
|
|
||||||
\code
|
|
||||||
class MyTestPrivate;
|
|
||||||
\endcode
|
|
||||||
|
|
||||||
\section1 The Public Class
|
|
||||||
Generally, you shouldn't keep any data members in the public class without a
|
|
||||||
good reason. Functions that are part of the public interface should be declared
|
|
||||||
in the public class, and functions that need to be available to subclasses (for
|
|
||||||
calling or overriding) should be in the protected section of the public class.
|
|
||||||
To connect the private class to the public class, include the
|
|
||||||
QXT_DECLARE_PRIVATE macro in the private section of the public class. In the
|
|
||||||
example above, the private class is connected as follows:
|
|
||||||
\code
|
|
||||||
private:
|
|
||||||
QXT_DECLARE_PRIVATE(MyTest)
|
|
||||||
\endcode
|
|
||||||
|
|
||||||
Additionally, you must include the QXT_INIT_PRIVATE macro in the public class's
|
|
||||||
constructor. Continuing with the MyTest example, your constructor might look
|
|
||||||
like this:
|
|
||||||
\code
|
|
||||||
MyTest::MyTest() {
|
|
||||||
// initialization
|
|
||||||
QXT_INIT_PRIVATE(MyTest);
|
|
||||||
}
|
|
||||||
\endcode
|
|
||||||
|
|
||||||
\section1 The Private Class
|
|
||||||
As mentioned above, data members should usually be kept in the private class.
|
|
||||||
This allows the memory layout of the private class to change without breaking
|
|
||||||
binary compatibility for the public class. Functions that exist only as
|
|
||||||
implementation details, or functions that need access to private data members,
|
|
||||||
should be implemented here.
|
|
||||||
|
|
||||||
To define the private class, inherit from the template QxtPrivate class, and
|
|
||||||
include the QXT_DECLARE_PUBLIC macro in its public section. The template
|
|
||||||
parameter should be the name of the public class. For example:
|
|
||||||
\code
|
|
||||||
class MyTestPrivate : public QxtPrivate<MyTest> {
|
|
||||||
public:
|
|
||||||
MyTestPrivate();
|
|
||||||
QXT_DECLARE_PUBLIC(MyTest)
|
|
||||||
};
|
|
||||||
\endcode
|
|
||||||
|
|
||||||
\section1 Accessing Private Members
|
|
||||||
Use the qxt_d() function (actually a function-like object) from functions in
|
|
||||||
the public class to access the private class. Similarly, functions in the
|
|
||||||
private class can invoke functions in the public class by using the qxt_p()
|
|
||||||
function (this one's actually a function).
|
|
||||||
|
|
||||||
For example, assume that MyTest has methods named getFoobar and doBaz(),
|
|
||||||
and MyTestPrivate has a member named foobar and a method named doQuux().
|
|
||||||
The code might resemble this example:
|
|
||||||
\code
|
|
||||||
int MyTest::getFoobar() {
|
|
||||||
return qxt_d().foobar;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MyTestPrivate::doQuux() {
|
|
||||||
qxt_p().doBaz(foobar);
|
|
||||||
}
|
|
||||||
\endcode
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \macro QXT_DECLARE_PRIVATE(PUB)
|
|
||||||
* \relates <QxtPimpl>
|
|
||||||
* Declares that a public class has a related private class.
|
|
||||||
*
|
|
||||||
* This shuold be put in the private section of the public class. The
|
|
||||||
* parameter \a PUB must be the name of the public class.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \macro QXT_DECLARE_PUBLIC(PUB)
|
|
||||||
* \relates <QxtPimpl>
|
|
||||||
* Declares that a private class has a related public class named \a PUB.
|
|
||||||
*
|
|
||||||
* This may be put anywhere in the declaration of the private class. The parameter is the name of the public class.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \macro QXT_INIT_PRIVATE(PUB)
|
|
||||||
* \relates <QxtPimpl>
|
|
||||||
* Initializes resources owned by the private class.
|
|
||||||
*
|
|
||||||
* This should be called from the public class's constructor,
|
|
||||||
* before qxt_d() is used for the first time. The parameter \a PUB must be
|
|
||||||
* the name of the public class.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \macro QXT_D(PUB)
|
|
||||||
* \relates <QxtPimpl>
|
|
||||||
* Returns a reference in the current scope named "d" to the private class
|
|
||||||
* associated with the public class \a PUB.
|
|
||||||
*
|
|
||||||
* This function is only available in a class using QXT_DECLARE_PRIVATE().
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \macro QXT_P(PUB)
|
|
||||||
* \relates <QxtPimpl>
|
|
||||||
* Creates a reference in the current scope named "q" to the public class
|
|
||||||
* named \a PUB.
|
|
||||||
*
|
|
||||||
* This macro only works in a class using QXT_DECLARE_PUBLIC().
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \fn QxtPrivate<PUB>& PUB::qxt_d()
|
|
||||||
* \relates <QxtPimpl>
|
|
||||||
* Returns a reference to the private class.
|
|
||||||
*
|
|
||||||
* This function is only available in a class using \a QXT_DECLARE_PRIVATE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \fn const QxtPrivate<PUB>& PUB::qxt_d() const
|
|
||||||
* \relates <QxtPimpl>
|
|
||||||
* Returns a const reference to the private class.
|
|
||||||
*
|
|
||||||
* This function is only available in a class using \a QXT_DECLARE_PRIVATE.
|
|
||||||
* This overload will be automatically used in const functions.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \fn PUB& QxtPrivate::qxt_p()
|
|
||||||
* \relates <QxtPimpl>
|
|
||||||
* Returns a reference to the public class.
|
|
||||||
*
|
|
||||||
* This function is only available in a class using QXT_DECLARE_PUBLIC().
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \fn const PUB& QxtPrivate::qxt_p() const
|
|
||||||
* \relates <QxtPimpl>
|
|
||||||
* Returns a const reference to the public class.
|
|
||||||
*
|
|
||||||
* This function is only available in a class using QXT_DECLARE_PUBLIC().
|
|
||||||
* This overload will be automatically used in const functions.
|
|
||||||
*/
|
|
||||||
233
3rdparty/qxt/qxtglobal.h
vendored
233
3rdparty/qxt/qxtglobal.h
vendored
@@ -1,233 +0,0 @@
|
|||||||
|
|
||||||
/****************************************************************************
|
|
||||||
** Copyright (c) 2006 - 2011, the LibQxt project.
|
|
||||||
** See the Qxt AUTHORS file for a list of authors and copyright holders.
|
|
||||||
** All rights reserved.
|
|
||||||
**
|
|
||||||
** Redistribution and use in source and binary forms, with or without
|
|
||||||
** modification, are permitted provided that the following conditions are met:
|
|
||||||
** * Redistributions of source code must retain the above copyright
|
|
||||||
** notice, this list of conditions and the following disclaimer.
|
|
||||||
** * Redistributions in binary form must reproduce the above copyright
|
|
||||||
** notice, this list of conditions and the following disclaimer in the
|
|
||||||
** documentation and/or other materials provided with the distribution.
|
|
||||||
** * Neither the name of the LibQxt project nor the
|
|
||||||
** names of its contributors may be used to endorse or promote products
|
|
||||||
** derived from this software without specific prior written permission.
|
|
||||||
**
|
|
||||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
** DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
|
||||||
** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
**
|
|
||||||
** <http://libqxt.org> <foundation@libqxt.org>
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
#ifndef QXTGLOBAL_H
|
|
||||||
#define QXTGLOBAL_H
|
|
||||||
|
|
||||||
#include <QtGlobal>
|
|
||||||
|
|
||||||
#define QXT_VERSION 0x000700
|
|
||||||
#define QXT_VERSION_STR "0.7.0"
|
|
||||||
|
|
||||||
//--------------------------global macros------------------------------
|
|
||||||
|
|
||||||
#ifndef QXT_NO_MACROS
|
|
||||||
|
|
||||||
#ifndef _countof
|
|
||||||
#define _countof(x) (sizeof(x)/sizeof(*x))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // QXT_NO_MACROS
|
|
||||||
|
|
||||||
//--------------------------export macros------------------------------
|
|
||||||
|
|
||||||
#define QXT_DLLEXPORT DO_NOT_USE_THIS_ANYMORE
|
|
||||||
|
|
||||||
#if !defined(QXT_STATIC) && !defined(QXT_DOXYGEN_RUN)
|
|
||||||
# if defined(BUILD_QXT_CORE)
|
|
||||||
# define QXT_CORE_EXPORT Q_DECL_EXPORT
|
|
||||||
# else
|
|
||||||
# define QXT_CORE_EXPORT Q_DECL_IMPORT
|
|
||||||
# endif
|
|
||||||
#else
|
|
||||||
# define QXT_CORE_EXPORT
|
|
||||||
#endif // BUILD_QXT_CORE
|
|
||||||
|
|
||||||
#if !defined(QXT_STATIC) && !defined(QXT_DOXYGEN_RUN)
|
|
||||||
# if defined(BUILD_QXT_GUI)
|
|
||||||
# define QXT_GUI_EXPORT Q_DECL_EXPORT
|
|
||||||
# else
|
|
||||||
# define QXT_GUI_EXPORT Q_DECL_IMPORT
|
|
||||||
# endif
|
|
||||||
#else
|
|
||||||
# define QXT_GUI_EXPORT
|
|
||||||
#endif // BUILD_QXT_GUI
|
|
||||||
|
|
||||||
#if !defined(QXT_STATIC) && !defined(QXT_DOXYGEN_RUN)
|
|
||||||
# if defined(BUILD_QXT_NETWORK)
|
|
||||||
# define QXT_NETWORK_EXPORT Q_DECL_EXPORT
|
|
||||||
# else
|
|
||||||
# define QXT_NETWORK_EXPORT Q_DECL_IMPORT
|
|
||||||
# endif
|
|
||||||
#else
|
|
||||||
# define QXT_NETWORK_EXPORT
|
|
||||||
#endif // BUILD_QXT_NETWORK
|
|
||||||
|
|
||||||
#if !defined(QXT_STATIC) && !defined(QXT_DOXYGEN_RUN)
|
|
||||||
# if defined(BUILD_QXT_SQL)
|
|
||||||
# define QXT_SQL_EXPORT Q_DECL_EXPORT
|
|
||||||
# else
|
|
||||||
# define QXT_SQL_EXPORT Q_DECL_IMPORT
|
|
||||||
# endif
|
|
||||||
#else
|
|
||||||
# define QXT_SQL_EXPORT
|
|
||||||
#endif // BUILD_QXT_SQL
|
|
||||||
|
|
||||||
#if !defined(QXT_STATIC) && !defined(QXT_DOXYGEN_RUN)
|
|
||||||
# if defined(BUILD_QXT_WEB)
|
|
||||||
# define QXT_WEB_EXPORT Q_DECL_EXPORT
|
|
||||||
# else
|
|
||||||
# define QXT_WEB_EXPORT Q_DECL_IMPORT
|
|
||||||
# endif
|
|
||||||
#else
|
|
||||||
# define QXT_WEB_EXPORT
|
|
||||||
#endif // BUILD_QXT_WEB
|
|
||||||
|
|
||||||
#if !defined(QXT_STATIC) && !defined(QXT_DOXYGEN_RUN)
|
|
||||||
# if defined(BUILD_QXT_BERKELEY)
|
|
||||||
# define QXT_BERKELEY_EXPORT Q_DECL_EXPORT
|
|
||||||
# else
|
|
||||||
# define QXT_BERKELEY_EXPORT Q_DECL_IMPORT
|
|
||||||
# endif
|
|
||||||
#else
|
|
||||||
# define QXT_BERKELEY_EXPORT
|
|
||||||
#endif // BUILD_QXT_BERKELEY
|
|
||||||
|
|
||||||
#if !defined(QXT_STATIC) && !defined(QXT_DOXYGEN_RUN)
|
|
||||||
# if defined(BUILD_QXT_ZEROCONF)
|
|
||||||
# define QXT_ZEROCONF_EXPORT Q_DECL_EXPORT
|
|
||||||
# else
|
|
||||||
# define QXT_ZEROCONF_EXPORT Q_DECL_IMPORT
|
|
||||||
# endif
|
|
||||||
#else
|
|
||||||
# define QXT_ZEROCONF_EXPORT
|
|
||||||
#endif // QXT_ZEROCONF_EXPORT
|
|
||||||
|
|
||||||
#if defined(BUILD_QXT_CORE) || defined(BUILD_QXT_GUI) || defined(BUILD_QXT_SQL) || defined(BUILD_QXT_NETWORK) || defined(BUILD_QXT_WEB) || defined(BUILD_QXT_BERKELEY) || defined(BUILD_QXT_ZEROCONF)
|
|
||||||
# define BUILD_QXT
|
|
||||||
#endif
|
|
||||||
|
|
||||||
QXT_CORE_EXPORT const char* qxtVersion();
|
|
||||||
|
|
||||||
#ifndef QT_BEGIN_NAMESPACE
|
|
||||||
#define QT_BEGIN_NAMESPACE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef QT_END_NAMESPACE
|
|
||||||
#define QT_END_NAMESPACE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef QT_FORWARD_DECLARE_CLASS
|
|
||||||
#define QT_FORWARD_DECLARE_CLASS(Class) class Class;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
** This file is derived from code bearing the following notice:
|
|
||||||
** The sole author of this file, Adam Higerd, has explicitly disclaimed all
|
|
||||||
** copyright interest and protection for the content within. This file has
|
|
||||||
** been placed in the public domain according to United States copyright
|
|
||||||
** statute and case law. In jurisdictions where this public domain dedication
|
|
||||||
** is not legally recognized, anyone who receives a copy of this file is
|
|
||||||
** permitted to use, modify, duplicate, and redistribute this file, in whole
|
|
||||||
** or in part, with no restrictions or conditions. In these jurisdictions,
|
|
||||||
** this file shall be copyright (C) 2006-2008 by Adam Higerd.
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#define QXT_DECLARE_PRIVATE(PUB) friend class PUB##Private; QxtPrivateInterface<PUB, PUB##Private> qxt_d;
|
|
||||||
#define QXT_DECLARE_PUBLIC(PUB) friend class PUB;
|
|
||||||
#define QXT_INIT_PRIVATE(PUB) qxt_d.setPublic(this);
|
|
||||||
#define QXT_D(PUB) PUB##Private& d = qxt_d()
|
|
||||||
#define QXT_P(PUB) PUB& p = qxt_p()
|
|
||||||
|
|
||||||
template <typename PUB>
|
|
||||||
class QxtPrivate
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~QxtPrivate()
|
|
||||||
{}
|
|
||||||
inline void QXT_setPublic(PUB* pub)
|
|
||||||
{
|
|
||||||
qxt_p_ptr = pub;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
inline PUB& qxt_p()
|
|
||||||
{
|
|
||||||
return *qxt_p_ptr;
|
|
||||||
}
|
|
||||||
inline const PUB& qxt_p() const
|
|
||||||
{
|
|
||||||
return *qxt_p_ptr;
|
|
||||||
}
|
|
||||||
inline PUB* qxt_ptr()
|
|
||||||
{
|
|
||||||
return qxt_p_ptr;
|
|
||||||
}
|
|
||||||
inline const PUB* qxt_ptr() const
|
|
||||||
{
|
|
||||||
return qxt_p_ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
PUB* qxt_p_ptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename PUB, typename PVT>
|
|
||||||
class QxtPrivateInterface
|
|
||||||
{
|
|
||||||
friend class QxtPrivate<PUB>;
|
|
||||||
public:
|
|
||||||
QxtPrivateInterface()
|
|
||||||
{
|
|
||||||
pvt = new PVT;
|
|
||||||
}
|
|
||||||
~QxtPrivateInterface()
|
|
||||||
{
|
|
||||||
delete pvt;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void setPublic(PUB* pub)
|
|
||||||
{
|
|
||||||
pvt->QXT_setPublic(pub);
|
|
||||||
}
|
|
||||||
inline PVT& operator()()
|
|
||||||
{
|
|
||||||
return *static_cast<PVT*>(pvt);
|
|
||||||
}
|
|
||||||
inline const PVT& operator()() const
|
|
||||||
{
|
|
||||||
return *static_cast<PVT*>(pvt);
|
|
||||||
}
|
|
||||||
inline PVT * operator->()
|
|
||||||
{
|
|
||||||
return static_cast<PVT*>(pvt);
|
|
||||||
}
|
|
||||||
inline const PVT * operator->() const
|
|
||||||
{
|
|
||||||
return static_cast<PVT*>(pvt);
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
QxtPrivateInterface(const QxtPrivateInterface&) { }
|
|
||||||
QxtPrivateInterface& operator=(const QxtPrivateInterface&) { }
|
|
||||||
QxtPrivate<PUB>* pvt;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // QXT_GLOBAL
|
|
||||||
222
3rdparty/qxt/qxtglobalshortcut.cpp
vendored
222
3rdparty/qxt/qxtglobalshortcut.cpp
vendored
@@ -1,222 +0,0 @@
|
|||||||
#include "qxtglobalshortcut.h"
|
|
||||||
/****************************************************************************
|
|
||||||
** Copyright (c) 2006 - 2011, the LibQxt project.
|
|
||||||
** See the Qxt AUTHORS file for a list of authors and copyright holders.
|
|
||||||
** All rights reserved.
|
|
||||||
**
|
|
||||||
** Redistribution and use in source and binary forms, with or without
|
|
||||||
** modification, are permitted provided that the following conditions are met:
|
|
||||||
** * Redistributions of source code must retain the above copyright
|
|
||||||
** notice, this list of conditions and the following disclaimer.
|
|
||||||
** * Redistributions in binary form must reproduce the above copyright
|
|
||||||
** notice, this list of conditions and the following disclaimer in the
|
|
||||||
** documentation and/or other materials provided with the distribution.
|
|
||||||
** * Neither the name of the LibQxt project nor the
|
|
||||||
** names of its contributors may be used to endorse or promote products
|
|
||||||
** derived from this software without specific prior written permission.
|
|
||||||
**
|
|
||||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
** DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
|
||||||
** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
**
|
|
||||||
** <http://libqxt.org> <foundation@libqxt.org>
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
#include <QtGlobal>
|
|
||||||
#include <QAbstractEventDispatcher>
|
|
||||||
#include <QHash>
|
|
||||||
#include <QPair>
|
|
||||||
#include <QtDebug>
|
|
||||||
|
|
||||||
#include "qxtglobalshortcut_p.h"
|
|
||||||
|
|
||||||
bool QxtGlobalShortcutPrivate::error = false;
|
|
||||||
#ifndef Q_OS_MAC
|
|
||||||
int QxtGlobalShortcutPrivate::ref = 0;
|
|
||||||
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
|
|
||||||
QAbstractEventDispatcher::EventFilter QxtGlobalShortcutPrivate::prevEventFilter = 0;
|
|
||||||
#endif
|
|
||||||
#endif // Q_OS_MAC
|
|
||||||
QHash<QPair<quint32, quint32>, QxtGlobalShortcut*> QxtGlobalShortcutPrivate::shortcuts;
|
|
||||||
|
|
||||||
QxtGlobalShortcutPrivate::QxtGlobalShortcutPrivate() : enabled(true), key(Qt::Key(0)), mods(Qt::NoModifier)
|
|
||||||
{
|
|
||||||
#ifndef Q_OS_MAC
|
|
||||||
if (!ref++)
|
|
||||||
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
|
|
||||||
prevEventFilter = QAbstractEventDispatcher::instance()->setEventFilter(eventFilter);
|
|
||||||
#else
|
|
||||||
QAbstractEventDispatcher::instance()->installNativeEventFilter(this);
|
|
||||||
#endif
|
|
||||||
#endif // Q_OS_MAC
|
|
||||||
}
|
|
||||||
|
|
||||||
QxtGlobalShortcutPrivate::~QxtGlobalShortcutPrivate()
|
|
||||||
{
|
|
||||||
#ifndef Q_OS_MAC
|
|
||||||
if (!--ref)
|
|
||||||
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
|
|
||||||
QAbstractEventDispatcher::instance()->setEventFilter(prevEventFilter);
|
|
||||||
#else
|
|
||||||
QAbstractEventDispatcher::instance()->removeNativeEventFilter(this);
|
|
||||||
#endif
|
|
||||||
#endif // Q_OS_MAC
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QxtGlobalShortcutPrivate::setShortcut(const QKeySequence& shortcut)
|
|
||||||
{
|
|
||||||
Qt::KeyboardModifiers allMods = Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier;
|
|
||||||
key = shortcut.isEmpty() ? Qt::Key(0) : Qt::Key((shortcut[0] ^ allMods) & shortcut[0]);
|
|
||||||
mods = shortcut.isEmpty() ? Qt::KeyboardModifiers(0) : Qt::KeyboardModifiers(shortcut[0] & allMods);
|
|
||||||
const quint32 nativeKey = nativeKeycode(key);
|
|
||||||
const quint32 nativeMods = nativeModifiers(mods);
|
|
||||||
const bool res = registerShortcut(nativeKey, nativeMods);
|
|
||||||
if (res)
|
|
||||||
shortcuts.insert(qMakePair(nativeKey, nativeMods), &qxt_p());
|
|
||||||
else
|
|
||||||
qWarning() << "QxtGlobalShortcut failed to register:" << QKeySequence(key + mods).toString();
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QxtGlobalShortcutPrivate::unsetShortcut()
|
|
||||||
{
|
|
||||||
bool res = false;
|
|
||||||
const quint32 nativeKey = nativeKeycode(key);
|
|
||||||
const quint32 nativeMods = nativeModifiers(mods);
|
|
||||||
if (shortcuts.value(qMakePair(nativeKey, nativeMods)) == &qxt_p())
|
|
||||||
res = unregisterShortcut(nativeKey, nativeMods);
|
|
||||||
if (res)
|
|
||||||
shortcuts.remove(qMakePair(nativeKey, nativeMods));
|
|
||||||
else
|
|
||||||
qWarning() << "QxtGlobalShortcut failed to unregister:" << QKeySequence(key + mods).toString();
|
|
||||||
key = Qt::Key(0);
|
|
||||||
mods = Qt::KeyboardModifiers(0);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
void QxtGlobalShortcutPrivate::activateShortcut(quint32 nativeKey, quint32 nativeMods)
|
|
||||||
{
|
|
||||||
QxtGlobalShortcut* shortcut = shortcuts.value(qMakePair(nativeKey, nativeMods));
|
|
||||||
if (shortcut && shortcut->isEnabled())
|
|
||||||
emit shortcut->activated();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\class QxtGlobalShortcut
|
|
||||||
\inmodule QxtWidgets
|
|
||||||
\brief The QxtGlobalShortcut class provides a global shortcut aka "hotkey".
|
|
||||||
|
|
||||||
A global shortcut triggers even if the application is not active. This
|
|
||||||
makes it easy to implement applications that react to certain shortcuts
|
|
||||||
still if some other application is active or if the application is for
|
|
||||||
example minimized to the system tray.
|
|
||||||
|
|
||||||
Example usage:
|
|
||||||
\code
|
|
||||||
QxtGlobalShortcut* shortcut = new QxtGlobalShortcut(window);
|
|
||||||
connect(shortcut, SIGNAL(activated()), window, SLOT(toggleVisibility()));
|
|
||||||
shortcut->setShortcut(QKeySequence("Ctrl+Shift+F12"));
|
|
||||||
\endcode
|
|
||||||
|
|
||||||
\bold {Note:} Since Qxt 0.6 QxtGlobalShortcut no more requires QxtApplication.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\fn QxtGlobalShortcut::activated()
|
|
||||||
|
|
||||||
This signal is emitted when the user types the shortcut's key sequence.
|
|
||||||
|
|
||||||
\sa shortcut
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Constructs a new QxtGlobalShortcut with \a parent.
|
|
||||||
*/
|
|
||||||
QxtGlobalShortcut::QxtGlobalShortcut(QObject* parent)
|
|
||||||
: QObject(parent)
|
|
||||||
{
|
|
||||||
QXT_INIT_PRIVATE(QxtGlobalShortcut);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Constructs a new QxtGlobalShortcut with \a shortcut and \a parent.
|
|
||||||
*/
|
|
||||||
QxtGlobalShortcut::QxtGlobalShortcut(const QKeySequence& shortcut, QObject* parent)
|
|
||||||
: QObject(parent)
|
|
||||||
{
|
|
||||||
QXT_INIT_PRIVATE(QxtGlobalShortcut);
|
|
||||||
setShortcut(shortcut);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Destructs the QxtGlobalShortcut.
|
|
||||||
*/
|
|
||||||
QxtGlobalShortcut::~QxtGlobalShortcut()
|
|
||||||
{
|
|
||||||
if (qxt_d().key != 0)
|
|
||||||
qxt_d().unsetShortcut();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\property QxtGlobalShortcut::shortcut
|
|
||||||
\brief the shortcut key sequence
|
|
||||||
|
|
||||||
\bold {Note:} Notice that corresponding key press and release events are not
|
|
||||||
delivered for registered global shortcuts even if they are disabled.
|
|
||||||
Also, comma separated key sequences are not supported.
|
|
||||||
Only the first part is used:
|
|
||||||
|
|
||||||
\code
|
|
||||||
qxtShortcut->setShortcut(QKeySequence("Ctrl+Alt+A,Ctrl+Alt+B"));
|
|
||||||
Q_ASSERT(qxtShortcut->shortcut() == QKeySequence("Ctrl+Alt+A"));
|
|
||||||
\endcode
|
|
||||||
*/
|
|
||||||
QKeySequence QxtGlobalShortcut::shortcut() const
|
|
||||||
{
|
|
||||||
return QKeySequence(qxt_d().key | qxt_d().mods);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QxtGlobalShortcut::setShortcut(const QKeySequence& shortcut)
|
|
||||||
{
|
|
||||||
if (qxt_d().key != 0)
|
|
||||||
qxt_d().unsetShortcut();
|
|
||||||
return qxt_d().setShortcut(shortcut);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\property QxtGlobalShortcut::enabled
|
|
||||||
\brief whether the shortcut is enabled
|
|
||||||
|
|
||||||
A disabled shortcut does not get activated.
|
|
||||||
|
|
||||||
The default value is \c true.
|
|
||||||
|
|
||||||
\sa setDisabled()
|
|
||||||
*/
|
|
||||||
bool QxtGlobalShortcut::isEnabled() const
|
|
||||||
{
|
|
||||||
return qxt_d().enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
void QxtGlobalShortcut::setEnabled(bool enabled)
|
|
||||||
{
|
|
||||||
qxt_d().enabled = enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Sets the shortcut \a disabled.
|
|
||||||
|
|
||||||
\sa enabled
|
|
||||||
*/
|
|
||||||
void QxtGlobalShortcut::setDisabled(bool disabled)
|
|
||||||
{
|
|
||||||
qxt_d().enabled = !disabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
68
3rdparty/qxt/qxtglobalshortcut.h
vendored
68
3rdparty/qxt/qxtglobalshortcut.h
vendored
@@ -1,68 +0,0 @@
|
|||||||
#ifndef QXTGLOBALSHORTCUT_H
|
|
||||||
/****************************************************************************
|
|
||||||
** Copyright (c) 2006 - 2011, the LibQxt project.
|
|
||||||
** See the Qxt AUTHORS file for a list of authors and copyright holders.
|
|
||||||
** All rights reserved.
|
|
||||||
**
|
|
||||||
** Redistribution and use in source and binary forms, with or without
|
|
||||||
** modification, are permitted provided that the following conditions are met:
|
|
||||||
** * Redistributions of source code must retain the above copyright
|
|
||||||
** notice, this list of conditions and the following disclaimer.
|
|
||||||
** * Redistributions in binary form must reproduce the above copyright
|
|
||||||
** notice, this list of conditions and the following disclaimer in the
|
|
||||||
** documentation and/or other materials provided with the distribution.
|
|
||||||
** * Neither the name of the LibQxt project nor the
|
|
||||||
** names of its contributors may be used to endorse or promote products
|
|
||||||
** derived from this software without specific prior written permission.
|
|
||||||
**
|
|
||||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
** DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
|
||||||
** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
**
|
|
||||||
** <http://libqxt.org> <foundation@libqxt.org>
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
#define QXTGLOBALSHORTCUT_H
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QKeySequence>
|
|
||||||
#include <QString>
|
|
||||||
|
|
||||||
#include "qxtglobal.h"
|
|
||||||
|
|
||||||
class QxtGlobalShortcutPrivate;
|
|
||||||
|
|
||||||
class QXT_GUI_EXPORT QxtGlobalShortcut : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
QXT_DECLARE_PRIVATE(QxtGlobalShortcut)
|
|
||||||
Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled)
|
|
||||||
Q_PROPERTY(QKeySequence shortcut READ shortcut WRITE setShortcut)
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit QxtGlobalShortcut(QObject* parent = 0);
|
|
||||||
explicit QxtGlobalShortcut(const QKeySequence& shortcut, QObject* parent = 0);
|
|
||||||
virtual ~QxtGlobalShortcut();
|
|
||||||
|
|
||||||
QKeySequence shortcut() const;
|
|
||||||
bool setShortcut(const QKeySequence& shortcut);
|
|
||||||
|
|
||||||
bool isEnabled() const;
|
|
||||||
|
|
||||||
public Q_SLOTS:
|
|
||||||
void setEnabled(bool enabled = true);
|
|
||||||
void setDisabled(bool disabled = true);
|
|
||||||
|
|
||||||
Q_SIGNALS:
|
|
||||||
void activated();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // QXTGLOBALSHORTCUT_H
|
|
||||||
|
|
||||||
258
3rdparty/qxt/qxtglobalshortcut_mac.cpp
vendored
258
3rdparty/qxt/qxtglobalshortcut_mac.cpp
vendored
@@ -1,258 +0,0 @@
|
|||||||
#include <Carbon/Carbon.h>
|
|
||||||
/****************************************************************************
|
|
||||||
** Copyright (c) 2006 - 2011, the LibQxt project.
|
|
||||||
** See the Qxt AUTHORS file for a list of authors and copyright holders.
|
|
||||||
** All rights reserved.
|
|
||||||
**
|
|
||||||
** Redistribution and use in source and binary forms, with or without
|
|
||||||
** modification, are permitted provided that the following conditions are met:
|
|
||||||
** * Redistributions of source code must retain the above copyright
|
|
||||||
** notice, this list of conditions and the following disclaimer.
|
|
||||||
** * Redistributions in binary form must reproduce the above copyright
|
|
||||||
** notice, this list of conditions and the following disclaimer in the
|
|
||||||
** documentation and/or other materials provided with the distribution.
|
|
||||||
** * Neither the name of the LibQxt project nor the
|
|
||||||
** names of its contributors may be used to endorse or promote products
|
|
||||||
** derived from this software without specific prior written permission.
|
|
||||||
**
|
|
||||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
** DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
|
||||||
** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
**
|
|
||||||
** <http://libqxt.org> <foundation@libqxt.org>
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
#include "qxtglobalshortcut_p.h"
|
|
||||||
#include <QMap>
|
|
||||||
#include <QHash>
|
|
||||||
#include <QtDebug>
|
|
||||||
#include <QApplication>
|
|
||||||
|
|
||||||
typedef QPair<uint, uint> Identifier;
|
|
||||||
static QMap<quint32, EventHotKeyRef> keyRefs;
|
|
||||||
static QHash<Identifier, quint32> keyIDs;
|
|
||||||
static quint32 hotKeySerial = 0;
|
|
||||||
static bool qxt_mac_handler_installed = false;
|
|
||||||
|
|
||||||
OSStatus qxt_mac_handle_hot_key(EventHandlerCallRef nextHandler, EventRef event, void* data)
|
|
||||||
{
|
|
||||||
Q_UNUSED(nextHandler);
|
|
||||||
Q_UNUSED(data);
|
|
||||||
if (GetEventClass(event) == kEventClassKeyboard && GetEventKind(event) == kEventHotKeyPressed)
|
|
||||||
{
|
|
||||||
EventHotKeyID keyID;
|
|
||||||
GetEventParameter(event, kEventParamDirectObject, typeEventHotKeyID, NULL, sizeof(keyID), NULL, &keyID);
|
|
||||||
Identifier id = keyIDs.key(keyID.id);
|
|
||||||
QxtGlobalShortcutPrivate::activateShortcut(id.second, id.first);
|
|
||||||
}
|
|
||||||
return noErr;
|
|
||||||
}
|
|
||||||
|
|
||||||
quint32 QxtGlobalShortcutPrivate::nativeModifiers(Qt::KeyboardModifiers modifiers)
|
|
||||||
{
|
|
||||||
quint32 native = 0;
|
|
||||||
if (modifiers & Qt::ShiftModifier)
|
|
||||||
native |= shiftKey;
|
|
||||||
if (modifiers & Qt::ControlModifier)
|
|
||||||
native |= cmdKey;
|
|
||||||
if (modifiers & Qt::AltModifier)
|
|
||||||
native |= optionKey;
|
|
||||||
if (modifiers & Qt::MetaModifier)
|
|
||||||
native |= controlKey;
|
|
||||||
if (modifiers & Qt::KeypadModifier)
|
|
||||||
native |= kEventKeyModifierNumLockMask;
|
|
||||||
return native;
|
|
||||||
}
|
|
||||||
|
|
||||||
quint32 QxtGlobalShortcutPrivate::nativeKeycode(Qt::Key key)
|
|
||||||
{
|
|
||||||
UTF16Char ch;
|
|
||||||
// Constants found in NSEvent.h from AppKit.framework
|
|
||||||
switch (key)
|
|
||||||
{
|
|
||||||
case Qt::Key_Return:
|
|
||||||
return kVK_Return;
|
|
||||||
case Qt::Key_Enter:
|
|
||||||
return kVK_ANSI_KeypadEnter;
|
|
||||||
case Qt::Key_Tab:
|
|
||||||
return kVK_Tab;
|
|
||||||
case Qt::Key_Space:
|
|
||||||
return kVK_Space;
|
|
||||||
case Qt::Key_Backspace:
|
|
||||||
return kVK_Delete;
|
|
||||||
case Qt::Key_Control:
|
|
||||||
return kVK_Command;
|
|
||||||
case Qt::Key_Shift:
|
|
||||||
return kVK_Shift;
|
|
||||||
case Qt::Key_CapsLock:
|
|
||||||
return kVK_CapsLock;
|
|
||||||
case Qt::Key_Option:
|
|
||||||
return kVK_Option;
|
|
||||||
case Qt::Key_Meta:
|
|
||||||
return kVK_Control;
|
|
||||||
case Qt::Key_F17:
|
|
||||||
return kVK_F17;
|
|
||||||
case Qt::Key_VolumeUp:
|
|
||||||
return kVK_VolumeUp;
|
|
||||||
case Qt::Key_VolumeDown:
|
|
||||||
return kVK_VolumeDown;
|
|
||||||
case Qt::Key_F18:
|
|
||||||
return kVK_F18;
|
|
||||||
case Qt::Key_F19:
|
|
||||||
return kVK_F19;
|
|
||||||
case Qt::Key_F20:
|
|
||||||
return kVK_F20;
|
|
||||||
case Qt::Key_F5:
|
|
||||||
return kVK_F5;
|
|
||||||
case Qt::Key_F6:
|
|
||||||
return kVK_F6;
|
|
||||||
case Qt::Key_F7:
|
|
||||||
return kVK_F7;
|
|
||||||
case Qt::Key_F3:
|
|
||||||
return kVK_F3;
|
|
||||||
case Qt::Key_F8:
|
|
||||||
return kVK_F8;
|
|
||||||
case Qt::Key_F9:
|
|
||||||
return kVK_F9;
|
|
||||||
case Qt::Key_F11:
|
|
||||||
return kVK_F11;
|
|
||||||
case Qt::Key_F13:
|
|
||||||
return kVK_F13;
|
|
||||||
case Qt::Key_F16:
|
|
||||||
return kVK_F16;
|
|
||||||
case Qt::Key_F14:
|
|
||||||
return kVK_F14;
|
|
||||||
case Qt::Key_F10:
|
|
||||||
return kVK_F10;
|
|
||||||
case Qt::Key_F12:
|
|
||||||
return kVK_F12;
|
|
||||||
case Qt::Key_F15:
|
|
||||||
return kVK_F15;
|
|
||||||
case Qt::Key_Help:
|
|
||||||
return kVK_Help;
|
|
||||||
case Qt::Key_Home:
|
|
||||||
return kVK_Home;
|
|
||||||
case Qt::Key_PageUp:
|
|
||||||
return kVK_PageUp;
|
|
||||||
case Qt::Key_Delete:
|
|
||||||
return kVK_ForwardDelete;
|
|
||||||
case Qt::Key_F4:
|
|
||||||
return kVK_F4;
|
|
||||||
case Qt::Key_End:
|
|
||||||
return kVK_End;
|
|
||||||
case Qt::Key_F2:
|
|
||||||
return kVK_F2;
|
|
||||||
case Qt::Key_PageDown:
|
|
||||||
return kVK_PageDown;
|
|
||||||
case Qt::Key_F1:
|
|
||||||
return kVK_F1;
|
|
||||||
case Qt::Key_Left:
|
|
||||||
return kVK_LeftArrow;
|
|
||||||
case Qt::Key_Right:
|
|
||||||
return kVK_RightArrow;
|
|
||||||
case Qt::Key_Down:
|
|
||||||
return kVK_DownArrow;
|
|
||||||
case Qt::Key_Up:
|
|
||||||
return kVK_UpArrow;
|
|
||||||
default:
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (key == Qt::Key_Escape) ch = 27;
|
|
||||||
else if (key == Qt::Key_Return) ch = 13;
|
|
||||||
else if (key == Qt::Key_Enter) ch = 3;
|
|
||||||
else if (key == Qt::Key_Tab) ch = 9;
|
|
||||||
else ch = key;
|
|
||||||
|
|
||||||
CFDataRef currentLayoutData;
|
|
||||||
TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
|
|
||||||
|
|
||||||
if (currentKeyboard == NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
currentLayoutData = (CFDataRef)TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData);
|
|
||||||
CFRelease(currentKeyboard);
|
|
||||||
if (currentLayoutData == NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
UCKeyboardLayout* header = (UCKeyboardLayout*)CFDataGetBytePtr(currentLayoutData);
|
|
||||||
UCKeyboardTypeHeader* table = header->keyboardTypeList;
|
|
||||||
|
|
||||||
uint8_t *data = (uint8_t*)header;
|
|
||||||
// God, would a little documentation for this shit kill you...
|
|
||||||
for (quint32 i=0; i < header->keyboardTypeCount; i++)
|
|
||||||
{
|
|
||||||
UCKeyStateRecordsIndex* stateRec = 0;
|
|
||||||
if (table[i].keyStateRecordsIndexOffset != 0)
|
|
||||||
{
|
|
||||||
stateRec = reinterpret_cast<UCKeyStateRecordsIndex*>(data + table[i].keyStateRecordsIndexOffset);
|
|
||||||
if (stateRec->keyStateRecordsIndexFormat != kUCKeyStateRecordsIndexFormat) stateRec = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
UCKeyToCharTableIndex* charTable = reinterpret_cast<UCKeyToCharTableIndex*>(data + table[i].keyToCharTableIndexOffset);
|
|
||||||
if (charTable->keyToCharTableIndexFormat != kUCKeyToCharTableIndexFormat) continue;
|
|
||||||
|
|
||||||
for (quint32 j=0; j < charTable->keyToCharTableCount; j++)
|
|
||||||
{
|
|
||||||
UCKeyOutput* keyToChar = reinterpret_cast<UCKeyOutput*>(data + charTable->keyToCharTableOffsets[j]);
|
|
||||||
for (quint32 k=0; k < charTable->keyToCharTableSize; k++)
|
|
||||||
{
|
|
||||||
if (keyToChar[k] & kUCKeyOutputTestForIndexMask)
|
|
||||||
{
|
|
||||||
long idx = keyToChar[k] & kUCKeyOutputGetIndexMask;
|
|
||||||
if (stateRec && idx < stateRec->keyStateRecordCount)
|
|
||||||
{
|
|
||||||
UCKeyStateRecord* rec = reinterpret_cast<UCKeyStateRecord*>(data + stateRec->keyStateRecordOffsets[idx]);
|
|
||||||
if (rec->stateZeroCharData == ch) return k;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!(keyToChar[k] & kUCKeyOutputSequenceIndexMask) && keyToChar[k] < 0xFFFE)
|
|
||||||
{
|
|
||||||
if (keyToChar[k] == ch) return k;
|
|
||||||
}
|
|
||||||
} // for k
|
|
||||||
} // for j
|
|
||||||
} // for i
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QxtGlobalShortcutPrivate::registerShortcut(quint32 nativeKey, quint32 nativeMods)
|
|
||||||
{
|
|
||||||
if (!qxt_mac_handler_installed)
|
|
||||||
{
|
|
||||||
EventTypeSpec t;
|
|
||||||
t.eventClass = kEventClassKeyboard;
|
|
||||||
t.eventKind = kEventHotKeyPressed;
|
|
||||||
InstallApplicationEventHandler(&qxt_mac_handle_hot_key, 1, &t, NULL, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
EventHotKeyID keyID;
|
|
||||||
keyID.signature = 'cute';
|
|
||||||
keyID.id = ++hotKeySerial;
|
|
||||||
|
|
||||||
EventHotKeyRef ref = 0;
|
|
||||||
bool rv = !RegisterEventHotKey(nativeKey, nativeMods, keyID, GetApplicationEventTarget(), 0, &ref);
|
|
||||||
if (rv)
|
|
||||||
{
|
|
||||||
keyIDs.insert(Identifier(nativeMods, nativeKey), keyID.id);
|
|
||||||
keyRefs.insert(keyID.id, ref);
|
|
||||||
}
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QxtGlobalShortcutPrivate::unregisterShortcut(quint32 nativeKey, quint32 nativeMods)
|
|
||||||
{
|
|
||||||
Identifier id(nativeMods, nativeKey);
|
|
||||||
if (!keyIDs.contains(id)) return false;
|
|
||||||
|
|
||||||
EventHotKeyRef ref = keyRefs.take(keyIDs[id]);
|
|
||||||
keyIDs.remove(id);
|
|
||||||
return !UnregisterEventHotKey(ref);
|
|
||||||
}
|
|
||||||
84
3rdparty/qxt/qxtglobalshortcut_p.h
vendored
84
3rdparty/qxt/qxtglobalshortcut_p.h
vendored
@@ -1,84 +0,0 @@
|
|||||||
#ifndef QXTGLOBALSHORTCUT_P_H
|
|
||||||
/****************************************************************************
|
|
||||||
** Copyright (c) 2006 - 2011, the LibQxt project.
|
|
||||||
** See the Qxt AUTHORS file for a list of authors and copyright holders.
|
|
||||||
** All rights reserved.
|
|
||||||
**
|
|
||||||
** Redistribution and use in source and binary forms, with or without
|
|
||||||
** modification, are permitted provided that the following conditions are met:
|
|
||||||
** * Redistributions of source code must retain the above copyright
|
|
||||||
** notice, this list of conditions and the following disclaimer.
|
|
||||||
** * Redistributions in binary form must reproduce the above copyright
|
|
||||||
** notice, this list of conditions and the following disclaimer in the
|
|
||||||
** documentation and/or other materials provided with the distribution.
|
|
||||||
** * Neither the name of the LibQxt project nor the
|
|
||||||
** names of its contributors may be used to endorse or promote products
|
|
||||||
** derived from this software without specific prior written permission.
|
|
||||||
**
|
|
||||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
** DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
|
||||||
** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
**
|
|
||||||
** <http://libqxt.org> <foundation@libqxt.org>
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
#define QXTGLOBALSHORTCUT_P_H
|
|
||||||
|
|
||||||
#include "qxtglobalshortcut.h"
|
|
||||||
#include <QAbstractEventDispatcher>
|
|
||||||
#include <QKeySequence>
|
|
||||||
#include <QHash>
|
|
||||||
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
|
||||||
#include <QAbstractNativeEventFilter>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
class QxtGlobalShortcutPrivate : public QxtPrivate<QxtGlobalShortcut>
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
|
||||||
,public QAbstractNativeEventFilter
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
QXT_DECLARE_PUBLIC(QxtGlobalShortcut)
|
|
||||||
QxtGlobalShortcutPrivate();
|
|
||||||
~QxtGlobalShortcutPrivate();
|
|
||||||
|
|
||||||
bool enabled;
|
|
||||||
Qt::Key key;
|
|
||||||
Qt::KeyboardModifiers mods;
|
|
||||||
|
|
||||||
bool setShortcut(const QKeySequence& shortcut);
|
|
||||||
bool unsetShortcut();
|
|
||||||
|
|
||||||
static bool error;
|
|
||||||
#ifndef Q_OS_MAC
|
|
||||||
static int ref;
|
|
||||||
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
|
|
||||||
static QAbstractEventDispatcher::EventFilter prevEventFilter;
|
|
||||||
static bool eventFilter(void* message);
|
|
||||||
#else
|
|
||||||
virtual bool nativeEventFilter(const QByteArray & eventType, void * message, long * result);
|
|
||||||
#endif // QT_VERSION < QT_VERSION_CHECK(5,0,0)
|
|
||||||
#endif // Q_OS_MAC
|
|
||||||
|
|
||||||
static void activateShortcut(quint32 nativeKey, quint32 nativeMods);
|
|
||||||
|
|
||||||
private:
|
|
||||||
static quint32 nativeKeycode(Qt::Key keycode);
|
|
||||||
static quint32 nativeModifiers(Qt::KeyboardModifiers modifiers);
|
|
||||||
|
|
||||||
static bool registerShortcut(quint32 nativeKey, quint32 nativeMods);
|
|
||||||
static bool unregisterShortcut(quint32 nativeKey, quint32 nativeMods);
|
|
||||||
|
|
||||||
static QHash<QPair<quint32, quint32>, QxtGlobalShortcut*> shortcuts;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // QXTGLOBALSHORTCUT_P_H
|
|
||||||
247
3rdparty/qxt/qxtglobalshortcut_win.cpp
vendored
247
3rdparty/qxt/qxtglobalshortcut_win.cpp
vendored
@@ -1,247 +0,0 @@
|
|||||||
#include "qxtglobalshortcut_p.h"
|
|
||||||
/****************************************************************************
|
|
||||||
** Copyright (c) 2006 - 2011, the LibQxt project.
|
|
||||||
** See the Qxt AUTHORS file for a list of authors and copyright holders.
|
|
||||||
** All rights reserved.
|
|
||||||
**
|
|
||||||
** Redistribution and use in source and binary forms, with or without
|
|
||||||
** modification, are permitted provided that the following conditions are met:
|
|
||||||
** * Redistributions of source code must retain the above copyright
|
|
||||||
** notice, this list of conditions and the following disclaimer.
|
|
||||||
** * Redistributions in binary form must reproduce the above copyright
|
|
||||||
** notice, this list of conditions and the following disclaimer in the
|
|
||||||
** documentation and/or other materials provided with the distribution.
|
|
||||||
** * Neither the name of the LibQxt project nor the
|
|
||||||
** names of its contributors may be used to endorse or promote products
|
|
||||||
** derived from this software without specific prior written permission.
|
|
||||||
**
|
|
||||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
** DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
|
||||||
** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
**
|
|
||||||
** <http://libqxt.org> <foundation@libqxt.org>
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
#include <qt_windows.h>
|
|
||||||
|
|
||||||
|
|
||||||
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
|
|
||||||
bool QxtGlobalShortcutPrivate::eventFilter(void* message)
|
|
||||||
{
|
|
||||||
#else
|
|
||||||
bool QxtGlobalShortcutPrivate::nativeEventFilter(const QByteArray & eventType,
|
|
||||||
void * message, long * result)
|
|
||||||
{
|
|
||||||
Q_UNUSED(eventType);
|
|
||||||
Q_UNUSED(result);
|
|
||||||
#endif
|
|
||||||
MSG* msg = static_cast<MSG*>(message);
|
|
||||||
if (msg->message == WM_HOTKEY)
|
|
||||||
{
|
|
||||||
const quint32 keycode = HIWORD(msg->lParam);
|
|
||||||
const quint32 modifiers = LOWORD(msg->lParam);
|
|
||||||
activateShortcut(keycode, modifiers);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
quint32 QxtGlobalShortcutPrivate::nativeModifiers(Qt::KeyboardModifiers modifiers)
|
|
||||||
{
|
|
||||||
// MOD_ALT, MOD_CONTROL, (MOD_KEYUP), MOD_SHIFT, MOD_WIN
|
|
||||||
quint32 native = 0;
|
|
||||||
if (modifiers & Qt::ShiftModifier)
|
|
||||||
native |= MOD_SHIFT;
|
|
||||||
if (modifiers & Qt::ControlModifier)
|
|
||||||
native |= MOD_CONTROL;
|
|
||||||
if (modifiers & Qt::AltModifier)
|
|
||||||
native |= MOD_ALT;
|
|
||||||
if (modifiers & Qt::MetaModifier)
|
|
||||||
native |= MOD_WIN;
|
|
||||||
// TODO: resolve these?
|
|
||||||
//if (modifiers & Qt::KeypadModifier)
|
|
||||||
//if (modifiers & Qt::GroupSwitchModifier)
|
|
||||||
return native;
|
|
||||||
}
|
|
||||||
|
|
||||||
quint32 QxtGlobalShortcutPrivate::nativeKeycode(Qt::Key key)
|
|
||||||
{
|
|
||||||
switch (key)
|
|
||||||
{
|
|
||||||
case Qt::Key_Escape:
|
|
||||||
return VK_ESCAPE;
|
|
||||||
case Qt::Key_Tab:
|
|
||||||
case Qt::Key_Backtab:
|
|
||||||
return VK_TAB;
|
|
||||||
case Qt::Key_Backspace:
|
|
||||||
return VK_BACK;
|
|
||||||
case Qt::Key_Return:
|
|
||||||
case Qt::Key_Enter:
|
|
||||||
return VK_RETURN;
|
|
||||||
case Qt::Key_Insert:
|
|
||||||
return VK_INSERT;
|
|
||||||
case Qt::Key_Delete:
|
|
||||||
return VK_DELETE;
|
|
||||||
case Qt::Key_Pause:
|
|
||||||
return VK_PAUSE;
|
|
||||||
case Qt::Key_Print:
|
|
||||||
return VK_PRINT;
|
|
||||||
case Qt::Key_Clear:
|
|
||||||
return VK_CLEAR;
|
|
||||||
case Qt::Key_Home:
|
|
||||||
return VK_HOME;
|
|
||||||
case Qt::Key_End:
|
|
||||||
return VK_END;
|
|
||||||
case Qt::Key_Left:
|
|
||||||
return VK_LEFT;
|
|
||||||
case Qt::Key_Up:
|
|
||||||
return VK_UP;
|
|
||||||
case Qt::Key_Right:
|
|
||||||
return VK_RIGHT;
|
|
||||||
case Qt::Key_Down:
|
|
||||||
return VK_DOWN;
|
|
||||||
case Qt::Key_PageUp:
|
|
||||||
return VK_PRIOR;
|
|
||||||
case Qt::Key_PageDown:
|
|
||||||
return VK_NEXT;
|
|
||||||
case Qt::Key_F1:
|
|
||||||
return VK_F1;
|
|
||||||
case Qt::Key_F2:
|
|
||||||
return VK_F2;
|
|
||||||
case Qt::Key_F3:
|
|
||||||
return VK_F3;
|
|
||||||
case Qt::Key_F4:
|
|
||||||
return VK_F4;
|
|
||||||
case Qt::Key_F5:
|
|
||||||
return VK_F5;
|
|
||||||
case Qt::Key_F6:
|
|
||||||
return VK_F6;
|
|
||||||
case Qt::Key_F7:
|
|
||||||
return VK_F7;
|
|
||||||
case Qt::Key_F8:
|
|
||||||
return VK_F8;
|
|
||||||
case Qt::Key_F9:
|
|
||||||
return VK_F9;
|
|
||||||
case Qt::Key_F10:
|
|
||||||
return VK_F10;
|
|
||||||
case Qt::Key_F11:
|
|
||||||
return VK_F11;
|
|
||||||
case Qt::Key_F12:
|
|
||||||
return VK_F12;
|
|
||||||
case Qt::Key_F13:
|
|
||||||
return VK_F13;
|
|
||||||
case Qt::Key_F14:
|
|
||||||
return VK_F14;
|
|
||||||
case Qt::Key_F15:
|
|
||||||
return VK_F15;
|
|
||||||
case Qt::Key_F16:
|
|
||||||
return VK_F16;
|
|
||||||
case Qt::Key_F17:
|
|
||||||
return VK_F17;
|
|
||||||
case Qt::Key_F18:
|
|
||||||
return VK_F18;
|
|
||||||
case Qt::Key_F19:
|
|
||||||
return VK_F19;
|
|
||||||
case Qt::Key_F20:
|
|
||||||
return VK_F20;
|
|
||||||
case Qt::Key_F21:
|
|
||||||
return VK_F21;
|
|
||||||
case Qt::Key_F22:
|
|
||||||
return VK_F22;
|
|
||||||
case Qt::Key_F23:
|
|
||||||
return VK_F23;
|
|
||||||
case Qt::Key_F24:
|
|
||||||
return VK_F24;
|
|
||||||
case Qt::Key_Space:
|
|
||||||
return VK_SPACE;
|
|
||||||
case Qt::Key_Asterisk:
|
|
||||||
return VK_MULTIPLY;
|
|
||||||
case Qt::Key_Plus:
|
|
||||||
return VK_ADD;
|
|
||||||
case Qt::Key_Comma:
|
|
||||||
return VK_SEPARATOR;
|
|
||||||
case Qt::Key_Minus:
|
|
||||||
return VK_SUBTRACT;
|
|
||||||
case Qt::Key_Slash:
|
|
||||||
return VK_DIVIDE;
|
|
||||||
case Qt::Key_MediaNext:
|
|
||||||
return VK_MEDIA_NEXT_TRACK;
|
|
||||||
case Qt::Key_MediaPrevious:
|
|
||||||
return VK_MEDIA_PREV_TRACK;
|
|
||||||
case Qt::Key_MediaPlay:
|
|
||||||
return VK_MEDIA_PLAY_PAUSE;
|
|
||||||
case Qt::Key_MediaStop:
|
|
||||||
return VK_MEDIA_STOP;
|
|
||||||
// couldn't find those in VK_*
|
|
||||||
//case Qt::Key_MediaLast:
|
|
||||||
//case Qt::Key_MediaRecord:
|
|
||||||
case Qt::Key_VolumeDown:
|
|
||||||
return VK_VOLUME_DOWN;
|
|
||||||
case Qt::Key_VolumeUp:
|
|
||||||
return VK_VOLUME_UP;
|
|
||||||
case Qt::Key_VolumeMute:
|
|
||||||
return VK_VOLUME_MUTE;
|
|
||||||
|
|
||||||
// numbers
|
|
||||||
case Qt::Key_0:
|
|
||||||
case Qt::Key_1:
|
|
||||||
case Qt::Key_2:
|
|
||||||
case Qt::Key_3:
|
|
||||||
case Qt::Key_4:
|
|
||||||
case Qt::Key_5:
|
|
||||||
case Qt::Key_6:
|
|
||||||
case Qt::Key_7:
|
|
||||||
case Qt::Key_8:
|
|
||||||
case Qt::Key_9:
|
|
||||||
return key;
|
|
||||||
|
|
||||||
// letters
|
|
||||||
case Qt::Key_A:
|
|
||||||
case Qt::Key_B:
|
|
||||||
case Qt::Key_C:
|
|
||||||
case Qt::Key_D:
|
|
||||||
case Qt::Key_E:
|
|
||||||
case Qt::Key_F:
|
|
||||||
case Qt::Key_G:
|
|
||||||
case Qt::Key_H:
|
|
||||||
case Qt::Key_I:
|
|
||||||
case Qt::Key_J:
|
|
||||||
case Qt::Key_K:
|
|
||||||
case Qt::Key_L:
|
|
||||||
case Qt::Key_M:
|
|
||||||
case Qt::Key_N:
|
|
||||||
case Qt::Key_O:
|
|
||||||
case Qt::Key_P:
|
|
||||||
case Qt::Key_Q:
|
|
||||||
case Qt::Key_R:
|
|
||||||
case Qt::Key_S:
|
|
||||||
case Qt::Key_T:
|
|
||||||
case Qt::Key_U:
|
|
||||||
case Qt::Key_V:
|
|
||||||
case Qt::Key_W:
|
|
||||||
case Qt::Key_X:
|
|
||||||
case Qt::Key_Y:
|
|
||||||
case Qt::Key_Z:
|
|
||||||
return key;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QxtGlobalShortcutPrivate::registerShortcut(quint32 nativeKey, quint32 nativeMods)
|
|
||||||
{
|
|
||||||
return RegisterHotKey(0, nativeMods ^ nativeKey, nativeMods, nativeKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QxtGlobalShortcutPrivate::unregisterShortcut(quint32 nativeKey, quint32 nativeMods)
|
|
||||||
{
|
|
||||||
return UnregisterHotKey(0, nativeMods ^ nativeKey);
|
|
||||||
}
|
|
||||||
263
3rdparty/qxt/qxtglobalshortcut_x11.cpp
vendored
263
3rdparty/qxt/qxtglobalshortcut_x11.cpp
vendored
@@ -1,263 +0,0 @@
|
|||||||
#include "qxtglobalshortcut_p.h"
|
|
||||||
/****************************************************************************
|
|
||||||
** Copyright (c) 2006 - 2011, the LibQxt project.
|
|
||||||
** See the Qxt AUTHORS file for a list of authors and copyright holders.
|
|
||||||
** All rights reserved.
|
|
||||||
**
|
|
||||||
** Redistribution and use in source and binary forms, with or without
|
|
||||||
** modification, are permitted provided that the following conditions are met:
|
|
||||||
** * Redistributions of source code must retain the above copyright
|
|
||||||
** notice, this list of conditions and the following disclaimer.
|
|
||||||
** * Redistributions in binary form must reproduce the above copyright
|
|
||||||
** notice, this list of conditions and the following disclaimer in the
|
|
||||||
** documentation and/or other materials provided with the distribution.
|
|
||||||
** * Neither the name of the LibQxt project nor the
|
|
||||||
** names of its contributors may be used to endorse or promote products
|
|
||||||
** derived from this software without specific prior written permission.
|
|
||||||
**
|
|
||||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
** DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
|
||||||
** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
**
|
|
||||||
** <http://libqxt.org> <foundation@libqxt.org>
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
|
|
||||||
# include <QX11Info>
|
|
||||||
#else
|
|
||||||
# include <qpa/qplatformnativeinterface.h>
|
|
||||||
# include <xcb/xcb.h>
|
|
||||||
# include <QApplication>
|
|
||||||
#endif
|
|
||||||
#include <X11/X.h>
|
|
||||||
#include <X11/Xlib.h>
|
|
||||||
#include <xcb/xproto.h>
|
|
||||||
|
|
||||||
#include <QtGlobal>
|
|
||||||
#include <QByteArray>
|
|
||||||
#include <QGuiApplication>
|
|
||||||
#include <QKeySequence>
|
|
||||||
#include <QString>
|
|
||||||
#include <QVector>
|
|
||||||
|
|
||||||
#include "keymapper_x11.h"
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
const QVector<quint32> maskModifiers = QVector<quint32>()
|
|
||||||
<< 0 << Mod2Mask << LockMask << (Mod2Mask | LockMask);
|
|
||||||
|
|
||||||
typedef int (*X11ErrorHandler)(Display *display, XErrorEvent *event);
|
|
||||||
|
|
||||||
class QxtX11ErrorHandler {
|
|
||||||
public:
|
|
||||||
static bool error;
|
|
||||||
|
|
||||||
static int qxtX11ErrorHandler(Display *display, XErrorEvent *event)
|
|
||||||
{
|
|
||||||
Q_UNUSED(display);
|
|
||||||
switch (event->error_code)
|
|
||||||
{
|
|
||||||
case BadAccess:
|
|
||||||
case BadValue:
|
|
||||||
case BadWindow:
|
|
||||||
if (event->request_code == 33 /* X_GrabKey */ ||
|
|
||||||
event->request_code == 34 /* X_UngrabKey */)
|
|
||||||
{
|
|
||||||
error = true;
|
|
||||||
//TODO:
|
|
||||||
//char errstr[256];
|
|
||||||
//XGetErrorText(dpy, err->error_code, errstr, 256);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
QxtX11ErrorHandler()
|
|
||||||
{
|
|
||||||
error = false;
|
|
||||||
m_previousErrorHandler = XSetErrorHandler(qxtX11ErrorHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
~QxtX11ErrorHandler()
|
|
||||||
{
|
|
||||||
XSetErrorHandler(m_previousErrorHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
X11ErrorHandler m_previousErrorHandler;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool QxtX11ErrorHandler::error = false;
|
|
||||||
|
|
||||||
class QxtX11Data {
|
|
||||||
public:
|
|
||||||
QxtX11Data()
|
|
||||||
{
|
|
||||||
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
|
|
||||||
m_display = QX11Info::display();
|
|
||||||
#else
|
|
||||||
QPlatformNativeInterface *native = qApp->platformNativeInterface();
|
|
||||||
void *display = native->nativeResourceForScreen(QByteArray("display"),
|
|
||||||
QGuiApplication::primaryScreen());
|
|
||||||
m_display = reinterpret_cast<Display *>(display);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isValid()
|
|
||||||
{
|
|
||||||
return m_display != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Display *display()
|
|
||||||
{
|
|
||||||
Q_ASSERT(isValid());
|
|
||||||
return m_display;
|
|
||||||
}
|
|
||||||
|
|
||||||
Window rootWindow()
|
|
||||||
{
|
|
||||||
return DefaultRootWindow(display());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool grabKey(quint32 keycode, quint32 modifiers, Window window)
|
|
||||||
{
|
|
||||||
QxtX11ErrorHandler errorHandler;
|
|
||||||
|
|
||||||
for (int i = 0; !errorHandler.error && i < maskModifiers.size(); ++i) {
|
|
||||||
XGrabKey(display(), keycode, modifiers | maskModifiers[i], window, True,
|
|
||||||
GrabModeAsync, GrabModeAsync);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (errorHandler.error) {
|
|
||||||
ungrabKey(keycode, modifiers, window);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ungrabKey(quint32 keycode, quint32 modifiers, Window window)
|
|
||||||
{
|
|
||||||
QxtX11ErrorHandler errorHandler;
|
|
||||||
|
|
||||||
foreach (quint32 maskMods, maskModifiers) {
|
|
||||||
XUngrabKey(display(), keycode, modifiers | maskMods, window);
|
|
||||||
}
|
|
||||||
|
|
||||||
return !errorHandler.error;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
Display *m_display;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
|
|
||||||
bool QxtGlobalShortcutPrivate::eventFilter(void *message)
|
|
||||||
{
|
|
||||||
XEvent *event = static_cast<XEvent *>(message);
|
|
||||||
if (event->type == KeyPress)
|
|
||||||
{
|
|
||||||
XKeyEvent *key = reinterpret_cast<XKeyEvent *>(event);
|
|
||||||
unsigned int keycode = key->keycode;
|
|
||||||
unsigned int keystate = key->state;
|
|
||||||
#else
|
|
||||||
bool QxtGlobalShortcutPrivate::nativeEventFilter(const QByteArray & eventType,
|
|
||||||
void *message, long *result)
|
|
||||||
{
|
|
||||||
Q_UNUSED(result);
|
|
||||||
|
|
||||||
xcb_key_press_event_t *kev = 0;
|
|
||||||
if (eventType == "xcb_generic_event_t") {
|
|
||||||
xcb_generic_event_t *ev = static_cast<xcb_generic_event_t *>(message);
|
|
||||||
if ((ev->response_type & 127) == XCB_KEY_PRESS)
|
|
||||||
kev = static_cast<xcb_key_press_event_t *>(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (kev != 0) {
|
|
||||||
unsigned int keycode = kev->detail;
|
|
||||||
unsigned int keystate = 0;
|
|
||||||
if(kev->state & XCB_MOD_MASK_1)
|
|
||||||
keystate |= Mod1Mask;
|
|
||||||
if(kev->state & XCB_MOD_MASK_CONTROL)
|
|
||||||
keystate |= ControlMask;
|
|
||||||
if(kev->state & XCB_MOD_MASK_4)
|
|
||||||
keystate |= Mod4Mask;
|
|
||||||
if(kev->state & XCB_MOD_MASK_SHIFT)
|
|
||||||
keystate |= ShiftMask;
|
|
||||||
#endif
|
|
||||||
activateShortcut(keycode,
|
|
||||||
// Mod1Mask == Alt, Mod4Mask == Meta
|
|
||||||
keystate & (ShiftMask | ControlMask | Mod1Mask | Mod4Mask));
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
quint32 QxtGlobalShortcutPrivate::nativeModifiers(Qt::KeyboardModifiers modifiers)
|
|
||||||
{
|
|
||||||
// ShiftMask, LockMask, ControlMask, Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, and Mod5Mask
|
|
||||||
quint32 native = 0;
|
|
||||||
if (modifiers & Qt::ShiftModifier)
|
|
||||||
native |= ShiftMask;
|
|
||||||
if (modifiers & Qt::ControlModifier)
|
|
||||||
native |= ControlMask;
|
|
||||||
if (modifiers & Qt::AltModifier)
|
|
||||||
native |= Mod1Mask;
|
|
||||||
if (modifiers & Qt::MetaModifier)
|
|
||||||
native |= Mod4Mask;
|
|
||||||
|
|
||||||
// TODO: resolve these?
|
|
||||||
//if (modifiers & Qt::MetaModifier)
|
|
||||||
//if (modifiers & Qt::KeypadModifier)
|
|
||||||
//if (modifiers & Qt::GroupSwitchModifier)
|
|
||||||
return native;
|
|
||||||
}
|
|
||||||
|
|
||||||
quint32 QxtGlobalShortcutPrivate::nativeKeycode(Qt::Key key)
|
|
||||||
{
|
|
||||||
// (davidsansome) Try the table from QKeyMapper first - this seems to be
|
|
||||||
// the only way to get Keysyms for the media keys.
|
|
||||||
unsigned int keysym = 0;
|
|
||||||
int i = 0;
|
|
||||||
while (KeyTbl[i]) {
|
|
||||||
if (KeyTbl[i+1] == static_cast<uint>(key)) {
|
|
||||||
keysym = KeyTbl[i];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
i += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If that didn't work then fall back on XStringToKeysym
|
|
||||||
if (!keysym) {
|
|
||||||
keysym = XStringToKeysym(QKeySequence(key).toString().toLatin1().data());
|
|
||||||
if (keysym == NoSymbol)
|
|
||||||
keysym = static_cast<ushort>(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
QxtX11Data x11;
|
|
||||||
if (!x11.isValid())
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return XKeysymToKeycode(x11.display(), keysym);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QxtGlobalShortcutPrivate::registerShortcut(quint32 nativeKey, quint32 nativeMods)
|
|
||||||
{
|
|
||||||
QxtX11Data x11;
|
|
||||||
return x11.isValid() && x11.grabKey(nativeKey, nativeMods, x11.rootWindow());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QxtGlobalShortcutPrivate::unregisterShortcut(quint32 nativeKey, quint32 nativeMods)
|
|
||||||
{
|
|
||||||
QxtX11Data x11;
|
|
||||||
return x11.isValid() && x11.ungrabKey(nativeKey, nativeMods, x11.rootWindow());
|
|
||||||
}
|
|
||||||
4
3rdparty/sha2/CMakeLists.txt
vendored
4
3rdparty/sha2/CMakeLists.txt
vendored
@@ -1,4 +0,0 @@
|
|||||||
cmake_minimum_required(VERSION 2.8.11)
|
|
||||||
set(CMAKE_CXX_STANDARD 11)
|
|
||||||
|
|
||||||
add_library(sha2 STATIC sha2.cpp)
|
|
||||||
589
3rdparty/sha2/sha2.cpp
vendored
589
3rdparty/sha2/sha2.cpp
vendored
@@ -1,589 +0,0 @@
|
|||||||
/*
|
|
||||||
* FILE: sha2.c
|
|
||||||
* AUTHOR: Aaron D. Gifford - http://www.aarongifford.com/
|
|
||||||
*
|
|
||||||
* Copyright (c) 2000-2001, Aaron D. Gifford
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of the copyright holder nor the names of contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND
|
|
||||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE
|
|
||||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
||||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
||||||
* SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
#include "sha2.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
* ASSERT NOTE:
|
|
||||||
* Some sanity checking code is included using assert(). On my FreeBSD
|
|
||||||
* system, this additional code can be removed by compiling with NDEBUG
|
|
||||||
* defined. Check your own systems manpage on assert() to see how to
|
|
||||||
* compile WITHOUT the sanity checking code on your system.
|
|
||||||
*
|
|
||||||
* UNROLLED TRANSFORM LOOP NOTE:
|
|
||||||
* You can define SHA2_UNROLL_TRANSFORM to use the unrolled transform
|
|
||||||
* loop version for the hash transform rounds (defined using macros
|
|
||||||
* later in this file). Either define on the command line, for example:
|
|
||||||
*
|
|
||||||
* cc -DSHA2_UNROLL_TRANSFORM -o sha2 sha2.c sha2prog.c
|
|
||||||
*
|
|
||||||
* or define below:
|
|
||||||
*
|
|
||||||
* #define SHA2_UNROLL_TRANSFORM
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/*** SHA-256/384/512 Machine Architecture Definitions *****************/
|
|
||||||
/*
|
|
||||||
* BYTE_ORDER NOTE:
|
|
||||||
*
|
|
||||||
* Please make sure that your system defines BYTE_ORDER. If your
|
|
||||||
* architecture is little-endian, make sure it also defines
|
|
||||||
* LITTLE_ENDIAN and that the two (BYTE_ORDER and LITTLE_ENDIAN) are
|
|
||||||
* equivilent.
|
|
||||||
*
|
|
||||||
* If your system does not define the above, then you can do so by
|
|
||||||
* hand like this:
|
|
||||||
*
|
|
||||||
* #define LITTLE_ENDIAN 1234
|
|
||||||
* #define BIG_ENDIAN 4321
|
|
||||||
*
|
|
||||||
* And for little-endian machines, add:
|
|
||||||
*
|
|
||||||
* #define BYTE_ORDER LITTLE_ENDIAN
|
|
||||||
*
|
|
||||||
* Or for big-endian machines:
|
|
||||||
*
|
|
||||||
* #define BYTE_ORDER BIG_ENDIAN
|
|
||||||
*
|
|
||||||
* The FreeBSD machine this was written on defines BYTE_ORDER
|
|
||||||
* appropriately by including <sys/types.h> (which in turn includes
|
|
||||||
* <machine/endian.h> where the appropriate definitions are actually
|
|
||||||
* made).
|
|
||||||
*/
|
|
||||||
#ifdef __MINGW32__
|
|
||||||
#include <sys/param.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(BYTE_ORDER) || (BYTE_ORDER != LITTLE_ENDIAN && BYTE_ORDER != BIG_ENDIAN)
|
|
||||||
#error Define BYTE_ORDER to be equal to either LITTLE_ENDIAN or BIG_ENDIAN
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace strawberry_sha2 {
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Define the followingsha2_* types to types of the correct length on
|
|
||||||
* the native archtecture. Most BSD systems and Linux define u_intXX_t
|
|
||||||
* types. Machines with very recent ANSI C headers, can use the
|
|
||||||
* uintXX_t definintions from inttypes.h by defining SHA2_USE_INTTYPES_H
|
|
||||||
* during compile or in the sha.h header file.
|
|
||||||
*
|
|
||||||
* Machines that support neither u_intXX_t nor inttypes.h's uintXX_t
|
|
||||||
* will need to define these three typedefs below (and the appropriate
|
|
||||||
* ones in sha.h too) by hand according to their system architecture.
|
|
||||||
*
|
|
||||||
* Thank you, Jun-ichiro itojun Hagino, for suggesting using u_intXX_t
|
|
||||||
* types and pointing out recent ANSI C support for uintXX_t in inttypes.h.
|
|
||||||
*/
|
|
||||||
#ifdef SHA2_USE_INTTYPES_H
|
|
||||||
|
|
||||||
typedef uint8_t sha2_byte; /* Exactly 1 byte */
|
|
||||||
typedef uint32_t sha2_word32; /* Exactly 4 bytes */
|
|
||||||
typedef uint64_t sha2_word64; /* Exactly 8 bytes */
|
|
||||||
|
|
||||||
#else /* SHA2_USE_INTTYPES_H */
|
|
||||||
|
|
||||||
typedef u_int8_t sha2_byte; /* Exactly 1 byte */
|
|
||||||
typedef u_int32_t sha2_word32; /* Exactly 4 bytes */
|
|
||||||
typedef u_int64_t sha2_word64; /* Exactly 8 bytes */
|
|
||||||
|
|
||||||
#endif /* SHA2_USE_INTTYPES_H */
|
|
||||||
|
|
||||||
|
|
||||||
/*** SHA-256/384/512 Various Length Definitions ***********************/
|
|
||||||
/* NOTE: Most of these are in sha2.h */
|
|
||||||
#define SHA256_SHORT_BLOCK_LENGTH (SHA256_BLOCK_LENGTH - 8)
|
|
||||||
|
|
||||||
|
|
||||||
/*** ENDIAN REVERSAL MACROS *******************************************/
|
|
||||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
|
||||||
#define REVERSE32(w,x) { \
|
|
||||||
sha2_word32 tmp = (w); \
|
|
||||||
tmp = (tmp >> 16) | (tmp << 16); \
|
|
||||||
(x) = ((tmp & 0xff00ff00UL) >> 8) | ((tmp & 0x00ff00ffUL) << 8); \
|
|
||||||
}
|
|
||||||
#define REVERSE64(w,x) { \
|
|
||||||
sha2_word64 tmp = (w); \
|
|
||||||
tmp = (tmp >> 32) | (tmp << 32); \
|
|
||||||
tmp = ((tmp & 0xff00ff00ff00ff00ULL) >> 8) | \
|
|
||||||
((tmp & 0x00ff00ff00ff00ffULL) << 8); \
|
|
||||||
(x) = ((tmp & 0xffff0000ffff0000ULL) >> 16) | \
|
|
||||||
((tmp & 0x0000ffff0000ffffULL) << 16); \
|
|
||||||
}
|
|
||||||
#endif /* BYTE_ORDER == LITTLE_ENDIAN */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Macro for incrementally adding the unsigned 64-bit integer n to the
|
|
||||||
* unsigned 128-bit integer (represented using a two-element array of
|
|
||||||
* 64-bit words):
|
|
||||||
*/
|
|
||||||
#define ADDINC128(w,n) { \
|
|
||||||
(w)[0] += (sha2_word64)(n); \
|
|
||||||
if ((w)[0] < (n)) { \
|
|
||||||
(w)[1]++; \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Macros for copying blocks of memory and for zeroing out ranges
|
|
||||||
* of memory. Using these macros makes it easy to switch from
|
|
||||||
* using memset()/memcpy() and using bzero()/bcopy().
|
|
||||||
*
|
|
||||||
* Please define either SHA2_USE_MEMSET_MEMCPY or define
|
|
||||||
* SHA2_USE_BZERO_BCOPY depending on which function set you
|
|
||||||
* choose to use:
|
|
||||||
*/
|
|
||||||
#if !defined(SHA2_USE_MEMSET_MEMCPY) && !defined(SHA2_USE_BZERO_BCOPY)
|
|
||||||
/* Default to memset()/memcpy() if no option is specified */
|
|
||||||
#define SHA2_USE_MEMSET_MEMCPY 1
|
|
||||||
#endif
|
|
||||||
#if defined(SHA2_USE_MEMSET_MEMCPY) && defined(SHA2_USE_BZERO_BCOPY)
|
|
||||||
/* Abort with an error if BOTH options are defined */
|
|
||||||
#error Define either SHA2_USE_MEMSET_MEMCPY or SHA2_USE_BZERO_BCOPY, not both!
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef SHA2_USE_MEMSET_MEMCPY
|
|
||||||
#define MEMSET_BZERO(p,l) memset((p), 0, (l))
|
|
||||||
#define MEMCPY_BCOPY(d,s,l) memcpy((d), (s), (l))
|
|
||||||
#endif
|
|
||||||
#ifdef SHA2_USE_BZERO_BCOPY
|
|
||||||
#define MEMSET_BZERO(p,l) bzero((p), (l))
|
|
||||||
#define MEMCPY_BCOPY(d,s,l) bcopy((s), (d), (l))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/*** THE SIX LOGICAL FUNCTIONS ****************************************/
|
|
||||||
/*
|
|
||||||
* Bit shifting and rotation (used by the six SHA-XYZ logical functions:
|
|
||||||
*
|
|
||||||
* NOTE: The naming of R and S appears backwards here (R is a SHIFT and
|
|
||||||
* S is a ROTATION) because the SHA-256/384/512 description document
|
|
||||||
* (see http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf) uses this
|
|
||||||
* same "backwards" definition.
|
|
||||||
*/
|
|
||||||
/* Shift-right (used in SHA-256, SHA-384, and SHA-512): */
|
|
||||||
#define R(b,x) ((x) >> (b))
|
|
||||||
/* 32-bit Rotate-right (used in SHA-256): */
|
|
||||||
#define S32(b,x) (((x) >> (b)) | ((x) << (32 - (b))))
|
|
||||||
|
|
||||||
/* Two of six logical functions used in SHA-256, SHA-384, and SHA-512: */
|
|
||||||
#define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z)))
|
|
||||||
#define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
|
|
||||||
|
|
||||||
/* Four of six logical functions used in SHA-256: */
|
|
||||||
#define Sigma0_256(x) (S32(2, (x)) ^ S32(13, (x)) ^ S32(22, (x)))
|
|
||||||
#define Sigma1_256(x) (S32(6, (x)) ^ S32(11, (x)) ^ S32(25, (x)))
|
|
||||||
#define sigma0_256(x) (S32(7, (x)) ^ S32(18, (x)) ^ R(3 , (x)))
|
|
||||||
#define sigma1_256(x) (S32(17, (x)) ^ S32(19, (x)) ^ R(10, (x)))
|
|
||||||
|
|
||||||
/*** INTERNAL FUNCTION PROTOTYPES *************************************/
|
|
||||||
/* NOTE: These should not be accessed directly from outside this
|
|
||||||
* library -- they are intended for private internal visibility/use
|
|
||||||
* only.
|
|
||||||
*/
|
|
||||||
void SHA256_Transform(SHA256_CTX*, const sha2_word32*);
|
|
||||||
|
|
||||||
|
|
||||||
/*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/
|
|
||||||
/* Hash constant words K for SHA-256: */
|
|
||||||
const static sha2_word32 K256[64] = {
|
|
||||||
0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL,
|
|
||||||
0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL,
|
|
||||||
0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL,
|
|
||||||
0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL,
|
|
||||||
0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
|
|
||||||
0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL,
|
|
||||||
0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL,
|
|
||||||
0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL,
|
|
||||||
0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL,
|
|
||||||
0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
|
|
||||||
0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL,
|
|
||||||
0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL,
|
|
||||||
0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL,
|
|
||||||
0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL,
|
|
||||||
0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
|
|
||||||
0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Initial hash value H for SHA-256: */
|
|
||||||
const static sha2_word32 sha256_initial_hash_value[8] = {
|
|
||||||
0x6a09e667UL,
|
|
||||||
0xbb67ae85UL,
|
|
||||||
0x3c6ef372UL,
|
|
||||||
0xa54ff53aUL,
|
|
||||||
0x510e527fUL,
|
|
||||||
0x9b05688cUL,
|
|
||||||
0x1f83d9abUL,
|
|
||||||
0x5be0cd19UL
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Constant used by SHA256/384/512_End() functions for converting the
|
|
||||||
* digest to a readable hexadecimal character string:
|
|
||||||
*/
|
|
||||||
static const char *sha2_hex_digits = "0123456789abcdef";
|
|
||||||
|
|
||||||
|
|
||||||
/*** SHA-256: *********************************************************/
|
|
||||||
void SHA256_Init(SHA256_CTX* context) {
|
|
||||||
if (context == (SHA256_CTX*)0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
MEMCPY_BCOPY(context->state, sha256_initial_hash_value, SHA256_DIGEST_LENGTH);
|
|
||||||
MEMSET_BZERO(context->buffer, SHA256_BLOCK_LENGTH);
|
|
||||||
context->bitcount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef SHA2_UNROLL_TRANSFORM
|
|
||||||
|
|
||||||
/* Unrolled SHA-256 round macros: */
|
|
||||||
|
|
||||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
|
||||||
|
|
||||||
#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \
|
|
||||||
REVERSE32(*data++, W256[j]); \
|
|
||||||
T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \
|
|
||||||
K256[j] + W256[j]; \
|
|
||||||
(d) += T1; \
|
|
||||||
(h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \
|
|
||||||
j++
|
|
||||||
|
|
||||||
|
|
||||||
#else /* BYTE_ORDER == LITTLE_ENDIAN */
|
|
||||||
|
|
||||||
#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \
|
|
||||||
T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \
|
|
||||||
K256[j] + (W256[j] = *data++); \
|
|
||||||
(d) += T1; \
|
|
||||||
(h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \
|
|
||||||
j++
|
|
||||||
|
|
||||||
#endif /* BYTE_ORDER == LITTLE_ENDIAN */
|
|
||||||
|
|
||||||
#define ROUND256(a,b,c,d,e,f,g,h) \
|
|
||||||
s0 = W256[(j+1)&0x0f]; \
|
|
||||||
s0 = sigma0_256(s0); \
|
|
||||||
s1 = W256[(j+14)&0x0f]; \
|
|
||||||
s1 = sigma1_256(s1); \
|
|
||||||
T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + K256[j] + \
|
|
||||||
(W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); \
|
|
||||||
(d) += T1; \
|
|
||||||
(h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \
|
|
||||||
j++
|
|
||||||
|
|
||||||
void SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) {
|
|
||||||
sha2_word32 a, b, c, d, e, f, g, h, s0, s1;
|
|
||||||
sha2_word32 T1, *W256;
|
|
||||||
int j;
|
|
||||||
|
|
||||||
W256 = (sha2_word32*)context->buffer;
|
|
||||||
|
|
||||||
/* Initialize registers with the prev. intermediate value */
|
|
||||||
a = context->state[0];
|
|
||||||
b = context->state[1];
|
|
||||||
c = context->state[2];
|
|
||||||
d = context->state[3];
|
|
||||||
e = context->state[4];
|
|
||||||
f = context->state[5];
|
|
||||||
g = context->state[6];
|
|
||||||
h = context->state[7];
|
|
||||||
|
|
||||||
j = 0;
|
|
||||||
do {
|
|
||||||
/* Rounds 0 to 15 (unrolled): */
|
|
||||||
ROUND256_0_TO_15(a,b,c,d,e,f,g,h);
|
|
||||||
ROUND256_0_TO_15(h,a,b,c,d,e,f,g);
|
|
||||||
ROUND256_0_TO_15(g,h,a,b,c,d,e,f);
|
|
||||||
ROUND256_0_TO_15(f,g,h,a,b,c,d,e);
|
|
||||||
ROUND256_0_TO_15(e,f,g,h,a,b,c,d);
|
|
||||||
ROUND256_0_TO_15(d,e,f,g,h,a,b,c);
|
|
||||||
ROUND256_0_TO_15(c,d,e,f,g,h,a,b);
|
|
||||||
ROUND256_0_TO_15(b,c,d,e,f,g,h,a);
|
|
||||||
} while (j < 16);
|
|
||||||
|
|
||||||
/* Now for the remaining rounds to 64: */
|
|
||||||
do {
|
|
||||||
ROUND256(a,b,c,d,e,f,g,h);
|
|
||||||
ROUND256(h,a,b,c,d,e,f,g);
|
|
||||||
ROUND256(g,h,a,b,c,d,e,f);
|
|
||||||
ROUND256(f,g,h,a,b,c,d,e);
|
|
||||||
ROUND256(e,f,g,h,a,b,c,d);
|
|
||||||
ROUND256(d,e,f,g,h,a,b,c);
|
|
||||||
ROUND256(c,d,e,f,g,h,a,b);
|
|
||||||
ROUND256(b,c,d,e,f,g,h,a);
|
|
||||||
} while (j < 64);
|
|
||||||
|
|
||||||
/* Compute the current intermediate hash value */
|
|
||||||
context->state[0] += a;
|
|
||||||
context->state[1] += b;
|
|
||||||
context->state[2] += c;
|
|
||||||
context->state[3] += d;
|
|
||||||
context->state[4] += e;
|
|
||||||
context->state[5] += f;
|
|
||||||
context->state[6] += g;
|
|
||||||
context->state[7] += h;
|
|
||||||
|
|
||||||
/* Clean up */
|
|
||||||
a = b = c = d = e = f = g = h = T1 = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else /* SHA2_UNROLL_TRANSFORM */
|
|
||||||
|
|
||||||
void SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) {
|
|
||||||
sha2_word32 a, b, c, d, e, f, g, h, s0, s1;
|
|
||||||
sha2_word32 T1, T2, *W256;
|
|
||||||
int j;
|
|
||||||
|
|
||||||
W256 = (sha2_word32*)context->buffer;
|
|
||||||
|
|
||||||
/* Initialize registers with the prev. intermediate value */
|
|
||||||
a = context->state[0];
|
|
||||||
b = context->state[1];
|
|
||||||
c = context->state[2];
|
|
||||||
d = context->state[3];
|
|
||||||
e = context->state[4];
|
|
||||||
f = context->state[5];
|
|
||||||
g = context->state[6];
|
|
||||||
h = context->state[7];
|
|
||||||
|
|
||||||
j = 0;
|
|
||||||
do {
|
|
||||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
|
||||||
/* Copy data while converting to host byte order */
|
|
||||||
REVERSE32(*data++,W256[j]);
|
|
||||||
/* Apply the SHA-256 compression function to update a..h */
|
|
||||||
T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + W256[j];
|
|
||||||
#else /* BYTE_ORDER == LITTLE_ENDIAN */
|
|
||||||
/* Apply the SHA-256 compression function to update a..h with copy */
|
|
||||||
T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + (W256[j] = *data++);
|
|
||||||
#endif /* BYTE_ORDER == LITTLE_ENDIAN */
|
|
||||||
T2 = Sigma0_256(a) + Maj(a, b, c);
|
|
||||||
h = g;
|
|
||||||
g = f;
|
|
||||||
f = e;
|
|
||||||
e = d + T1;
|
|
||||||
d = c;
|
|
||||||
c = b;
|
|
||||||
b = a;
|
|
||||||
a = T1 + T2;
|
|
||||||
|
|
||||||
j++;
|
|
||||||
} while (j < 16);
|
|
||||||
|
|
||||||
do {
|
|
||||||
/* Part of the message block expansion: */
|
|
||||||
s0 = W256[(j+1)&0x0f];
|
|
||||||
s0 = sigma0_256(s0);
|
|
||||||
s1 = W256[(j+14)&0x0f];
|
|
||||||
s1 = sigma1_256(s1);
|
|
||||||
|
|
||||||
/* Apply the SHA-256 compression function to update a..h */
|
|
||||||
T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] +
|
|
||||||
(W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0);
|
|
||||||
T2 = Sigma0_256(a) + Maj(a, b, c);
|
|
||||||
h = g;
|
|
||||||
g = f;
|
|
||||||
f = e;
|
|
||||||
e = d + T1;
|
|
||||||
d = c;
|
|
||||||
c = b;
|
|
||||||
b = a;
|
|
||||||
a = T1 + T2;
|
|
||||||
|
|
||||||
j++;
|
|
||||||
} while (j < 64);
|
|
||||||
|
|
||||||
/* Compute the current intermediate hash value */
|
|
||||||
context->state[0] += a;
|
|
||||||
context->state[1] += b;
|
|
||||||
context->state[2] += c;
|
|
||||||
context->state[3] += d;
|
|
||||||
context->state[4] += e;
|
|
||||||
context->state[5] += f;
|
|
||||||
context->state[6] += g;
|
|
||||||
context->state[7] += h;
|
|
||||||
|
|
||||||
/* Clean up */
|
|
||||||
a = b = c = d = e = f = g = h = T1 = T2 = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* SHA2_UNROLL_TRANSFORM */
|
|
||||||
|
|
||||||
void SHA256_Update(SHA256_CTX* context, const sha2_byte *data, size_t len) {
|
|
||||||
unsigned int freespace, usedspace;
|
|
||||||
|
|
||||||
if (len == 0) {
|
|
||||||
/* Calling with no data is valid - we do nothing */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Sanity check: */
|
|
||||||
assert(context != (SHA256_CTX*)0 && data != (sha2_byte*)0);
|
|
||||||
|
|
||||||
usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH;
|
|
||||||
if (usedspace > 0) {
|
|
||||||
/* Calculate how much free space is available in the buffer */
|
|
||||||
freespace = SHA256_BLOCK_LENGTH - usedspace;
|
|
||||||
|
|
||||||
if (len >= freespace) {
|
|
||||||
/* Fill the buffer completely and process it */
|
|
||||||
MEMCPY_BCOPY(&context->buffer[usedspace], data, freespace);
|
|
||||||
context->bitcount += freespace << 3;
|
|
||||||
len -= freespace;
|
|
||||||
data += freespace;
|
|
||||||
SHA256_Transform(context, (sha2_word32*)context->buffer);
|
|
||||||
} else {
|
|
||||||
/* The buffer is not yet full */
|
|
||||||
MEMCPY_BCOPY(&context->buffer[usedspace], data, len);
|
|
||||||
context->bitcount += len << 3;
|
|
||||||
/* Clean up: */
|
|
||||||
usedspace = freespace = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while (len >= SHA256_BLOCK_LENGTH) {
|
|
||||||
/* Process as many complete blocks as we can */
|
|
||||||
SHA256_Transform(context, (sha2_word32*)data);
|
|
||||||
context->bitcount += SHA256_BLOCK_LENGTH << 3;
|
|
||||||
len -= SHA256_BLOCK_LENGTH;
|
|
||||||
data += SHA256_BLOCK_LENGTH;
|
|
||||||
}
|
|
||||||
if (len > 0) {
|
|
||||||
/* There's left-overs, so save 'em */
|
|
||||||
MEMCPY_BCOPY(context->buffer, data, len);
|
|
||||||
context->bitcount += len << 3;
|
|
||||||
}
|
|
||||||
/* Clean up: */
|
|
||||||
usedspace = freespace = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SHA256_Final(sha2_byte digest[], SHA256_CTX* context) {
|
|
||||||
sha2_word32 *d = (sha2_word32*)digest;
|
|
||||||
unsigned int usedspace;
|
|
||||||
|
|
||||||
/* Sanity check: */
|
|
||||||
assert(context != (SHA256_CTX*)0);
|
|
||||||
|
|
||||||
/* If no digest buffer is passed, we don't bother doing this: */
|
|
||||||
if (digest != (sha2_byte*)0) {
|
|
||||||
usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH;
|
|
||||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
|
||||||
/* Convert FROM host byte order */
|
|
||||||
REVERSE64(context->bitcount,context->bitcount);
|
|
||||||
#endif
|
|
||||||
if (usedspace > 0) {
|
|
||||||
/* Begin padding with a 1 bit: */
|
|
||||||
context->buffer[usedspace++] = 0x80;
|
|
||||||
|
|
||||||
if (usedspace <= SHA256_SHORT_BLOCK_LENGTH) {
|
|
||||||
/* Set-up for the last transform: */
|
|
||||||
MEMSET_BZERO(&context->buffer[usedspace], SHA256_SHORT_BLOCK_LENGTH - usedspace);
|
|
||||||
} else {
|
|
||||||
if (usedspace < SHA256_BLOCK_LENGTH) {
|
|
||||||
MEMSET_BZERO(&context->buffer[usedspace], SHA256_BLOCK_LENGTH - usedspace);
|
|
||||||
}
|
|
||||||
/* Do second-to-last transform: */
|
|
||||||
SHA256_Transform(context, (sha2_word32*)context->buffer);
|
|
||||||
|
|
||||||
/* And set-up for the last transform: */
|
|
||||||
MEMSET_BZERO(context->buffer, SHA256_SHORT_BLOCK_LENGTH);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* Set-up for the last transform: */
|
|
||||||
MEMSET_BZERO(context->buffer, SHA256_SHORT_BLOCK_LENGTH);
|
|
||||||
|
|
||||||
/* Begin padding with a 1 bit: */
|
|
||||||
*context->buffer = 0x80;
|
|
||||||
}
|
|
||||||
/* Set the bit count: */
|
|
||||||
*(sha2_word64*)&context->buffer[SHA256_SHORT_BLOCK_LENGTH] = context->bitcount;
|
|
||||||
|
|
||||||
/* Final transform: */
|
|
||||||
SHA256_Transform(context, (sha2_word32*)context->buffer);
|
|
||||||
|
|
||||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
|
||||||
{
|
|
||||||
/* Convert TO host byte order */
|
|
||||||
int j;
|
|
||||||
for (j = 0; j < 8; j++) {
|
|
||||||
REVERSE32(context->state[j],context->state[j]);
|
|
||||||
*d++ = context->state[j];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
MEMCPY_BCOPY(d, context->state, SHA256_DIGEST_LENGTH);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Clean up state data: */
|
|
||||||
MEMSET_BZERO(context, sizeof(SHA256_CTX));
|
|
||||||
usedspace = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *SHA256_End(SHA256_CTX* context, char buffer[]) {
|
|
||||||
sha2_byte digest[SHA256_DIGEST_LENGTH], *d = digest;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
/* Sanity check: */
|
|
||||||
assert(context != (SHA256_CTX*)0);
|
|
||||||
|
|
||||||
if (buffer != (char*)0) {
|
|
||||||
SHA256_Final(digest, context);
|
|
||||||
|
|
||||||
for (i = 0; i < SHA256_DIGEST_LENGTH; i++) {
|
|
||||||
*buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4];
|
|
||||||
*buffer++ = sha2_hex_digits[*d & 0x0f];
|
|
||||||
d++;
|
|
||||||
}
|
|
||||||
*buffer = (char)0;
|
|
||||||
} else {
|
|
||||||
MEMSET_BZERO(context, sizeof(SHA256_CTX));
|
|
||||||
}
|
|
||||||
MEMSET_BZERO(digest, SHA256_DIGEST_LENGTH);
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* SHA256_Data(const sha2_byte* data, size_t len, char digest[SHA256_DIGEST_STRING_LENGTH]) {
|
|
||||||
SHA256_CTX context;
|
|
||||||
|
|
||||||
SHA256_Init(&context);
|
|
||||||
SHA256_Update(&context, data, len);
|
|
||||||
return SHA256_End(&context, digest);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace strawberry_sha2
|
|
||||||
81
3rdparty/sha2/sha2.h
vendored
81
3rdparty/sha2/sha2.h
vendored
@@ -1,81 +0,0 @@
|
|||||||
/*
|
|
||||||
* FILE: sha2.h
|
|
||||||
* AUTHOR: Aaron D. Gifford - http://www.aarongifford.com/
|
|
||||||
*
|
|
||||||
* Copyright (c) 2000-2001, Aaron D. Gifford
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of the copyright holder nor the names of contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND
|
|
||||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE
|
|
||||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
||||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
||||||
* SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* $Id: sha2.h,v 1.1 2001/11/08 00:02:01 adg Exp adg $
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __STRAWBERRY_SHA2_H__
|
|
||||||
#define __STRAWBERRY_SHA2_H__
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Import u_intXX_t size_t type definitions from system headers. You
|
|
||||||
* may need to change this, or define these things yourself in this
|
|
||||||
* file.
|
|
||||||
*/
|
|
||||||
#include <sys/types.h>
|
|
||||||
|
|
||||||
namespace strawberry_sha2 {
|
|
||||||
|
|
||||||
/*** SHA-256/384/512 Various Length Definitions ***********************/
|
|
||||||
static const int SHA256_BLOCK_LENGTH = 64;
|
|
||||||
static const int SHA256_DIGEST_LENGTH = 32;
|
|
||||||
static const int SHA256_DIGEST_STRING_LENGTH = (SHA256_DIGEST_LENGTH * 2 + 1);
|
|
||||||
|
|
||||||
|
|
||||||
/*** SHA-256/384/512 Context Structures *******************************/
|
|
||||||
/* NOTE: If your architecture does not define either u_intXX_t types or
|
|
||||||
* uintXX_t (from inttypes.h), you may need to define things by hand
|
|
||||||
* for your system:
|
|
||||||
*/
|
|
||||||
#ifdef __MINGW32__
|
|
||||||
typedef unsigned char u_int8_t; /* 1-byte (8-bits) */
|
|
||||||
typedef unsigned int u_int32_t; /* 4-bytes (32-bits) */
|
|
||||||
typedef unsigned long long u_int64_t; /* 8-bytes (64-bits) */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct _SHA256_CTX {
|
|
||||||
u_int32_t state[8];
|
|
||||||
u_int64_t bitcount;
|
|
||||||
u_int8_t buffer[SHA256_BLOCK_LENGTH];
|
|
||||||
} SHA256_CTX;
|
|
||||||
|
|
||||||
|
|
||||||
void SHA256_Init(SHA256_CTX *);
|
|
||||||
void SHA256_Update(SHA256_CTX*, const u_int8_t*, size_t);
|
|
||||||
void SHA256_Final(u_int8_t[SHA256_DIGEST_LENGTH], SHA256_CTX*);
|
|
||||||
char* SHA256_End(SHA256_CTX*, char[SHA256_DIGEST_STRING_LENGTH]);
|
|
||||||
char* SHA256_Data(const u_int8_t*, size_t, char[SHA256_DIGEST_STRING_LENGTH]);
|
|
||||||
|
|
||||||
} // namespace strawberry_sha2
|
|
||||||
|
|
||||||
#endif /* __STRAWBERRY_SHA2_H__ */
|
|
||||||
36
3rdparty/singleapplication/CMakeLists.txt
vendored
Normal file
36
3rdparty/singleapplication/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.7)
|
||||||
|
|
||||||
|
include(CheckIncludeFiles)
|
||||||
|
include(CheckFunctionExists)
|
||||||
|
|
||||||
|
check_function_exists(geteuid HAVE_GETEUID)
|
||||||
|
check_function_exists(getpwuid HAVE_GETPWUID)
|
||||||
|
|
||||||
|
set(SINGLEAPP-SOURCES singleapplication.cpp singleapplication_p.cpp)
|
||||||
|
set(SINGLEAPP-MOC-HEADERS singleapplication.h singleapplication_p.h)
|
||||||
|
qt_wrap_cpp(SINGLEAPP-SOURCES-MOC ${SINGLEAPP-MOC-HEADERS})
|
||||||
|
add_library(singleapplication STATIC ${SINGLEAPP-SOURCES} ${SINGLEAPP-SOURCES-MOC})
|
||||||
|
target_include_directories(singleapplication PRIVATE
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
)
|
||||||
|
target_link_libraries(singleapplication PRIVATE
|
||||||
|
${QtCore_LIBRARIES}
|
||||||
|
${QtWidgets_LIBRARIES}
|
||||||
|
${QtNetwork_LIBRARIES}
|
||||||
|
)
|
||||||
|
|
||||||
|
set(SINGLECOREAPP-SOURCES singlecoreapplication.cpp singlecoreapplication_p.cpp)
|
||||||
|
set(SINGLECOREAPP-MOC-HEADERS singlecoreapplication.h singlecoreapplication_p.h)
|
||||||
|
qt_wrap_cpp(SINGLECOREAPP-SOURCES-MOC ${SINGLECOREAPP-MOC-HEADERS})
|
||||||
|
add_library(singlecoreapplication STATIC ${SINGLECOREAPP-SOURCES} ${SINGLECOREAPP-SOURCES-MOC})
|
||||||
|
target_include_directories(singlecoreapplication PRIVATE
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
)
|
||||||
|
target_link_libraries(singlecoreapplication PRIVATE
|
||||||
|
${QtCore_LIBRARIES}
|
||||||
|
${QtNetwork_LIBRARIES}
|
||||||
|
)
|
||||||
|
|
||||||
|
configure_file(config.h.in "${CMAKE_CURRENT_BINARY_DIR}/config.h")
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
Copyright (C) 2011 by Mike McQuaid
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) Itay Grudev 2015 - 2020
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -17,3 +19,6 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
|
|
||||||
|
Note: Some of the examples include code not distributed under the terms of the
|
||||||
|
MIT License.
|
||||||
305
3rdparty/singleapplication/README.md
vendored
Normal file
305
3rdparty/singleapplication/README.md
vendored
Normal file
@@ -0,0 +1,305 @@
|
|||||||
|
SingleApplication
|
||||||
|
=================
|
||||||
|
[](https://github.com/itay-grudev/SingleApplication/actions)
|
||||||
|
|
||||||
|
This is a replacement of the QtSingleApplication for `Qt5` and `Qt6`.
|
||||||
|
|
||||||
|
Keeps the Primary Instance of your Application and kills each subsequent
|
||||||
|
instances. It can (if enabled) spawn secondary (non-related to the primary)
|
||||||
|
instances and can send data to the primary instance from secondary instances.
|
||||||
|
|
||||||
|
Usage
|
||||||
|
-----
|
||||||
|
|
||||||
|
The `SingleApplication` class inherits from whatever `Q[Core|Gui]Application`
|
||||||
|
class you specify via the `QAPPLICATION_CLASS` macro (`QCoreApplication` is the
|
||||||
|
default). Further usage is similar to the use of the `Q[Core|Gui]Application`
|
||||||
|
classes.
|
||||||
|
|
||||||
|
You can use the library as if you use any other `QCoreApplication` derived
|
||||||
|
class:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <QApplication>
|
||||||
|
#include <SingleApplication.h>
|
||||||
|
|
||||||
|
int main( int argc, char* argv[] )
|
||||||
|
{
|
||||||
|
SingleApplication app( argc, argv );
|
||||||
|
|
||||||
|
return app.exec();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
To include the library files I would recommend that you add it as a git
|
||||||
|
submodule to your project. Here is how:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git submodule add https://github.com/itay-grudev/SingleApplication.git singleapplication
|
||||||
|
```
|
||||||
|
|
||||||
|
**Qmake:**
|
||||||
|
|
||||||
|
Then include the `singleapplication.pri` file in your `.pro` project file.
|
||||||
|
|
||||||
|
```qmake
|
||||||
|
include(singleapplication/singleapplication.pri)
|
||||||
|
DEFINES += QAPPLICATION_CLASS=QApplication
|
||||||
|
```
|
||||||
|
|
||||||
|
**CMake:**
|
||||||
|
|
||||||
|
Then include the subdirectory in your `CMakeLists.txt` project file.
|
||||||
|
|
||||||
|
```cmake
|
||||||
|
set(QAPPLICATION_CLASS QApplication CACHE STRING "Inheritance class for SingleApplication")
|
||||||
|
add_subdirectory(src/third-party/singleapplication)
|
||||||
|
target_link_libraries(${PROJECT_NAME} SingleApplication::SingleApplication)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
The library sets up a `QLocalServer` and a `QSharedMemory` block. The first
|
||||||
|
instance of your Application is your Primary Instance. It would check if the
|
||||||
|
shared memory block exists and if not it will start a `QLocalServer` and listen
|
||||||
|
for connections. Each subsequent instance of your application would check if the
|
||||||
|
shared memory block exists and if it does, it will connect to the QLocalServer
|
||||||
|
to notify the primary instance that a new instance had been started, after which
|
||||||
|
it would terminate with status code `0`. In the Primary Instance
|
||||||
|
`SingleApplication` would emit the `instanceStarted()` signal upon detecting
|
||||||
|
that a new instance had been started.
|
||||||
|
|
||||||
|
The library uses `stdlib` to terminate the program with the `exit()` function.
|
||||||
|
|
||||||
|
Also don't forget to specify which `QCoreApplication` class your app is using if it
|
||||||
|
is not `QCoreApplication` as in examples above.
|
||||||
|
|
||||||
|
The `Instance Started` signal
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
The SingleApplication class implements a `instanceStarted()` signal. You can
|
||||||
|
bind to that signal to raise your application's window when a new instance had
|
||||||
|
been started, for example.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// window is a QWindow instance
|
||||||
|
QObject::connect(
|
||||||
|
&app,
|
||||||
|
&SingleApplication::instanceStarted,
|
||||||
|
&window,
|
||||||
|
&QWindow::raise
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
Using `SingleApplication::instance()` is a neat way to get the
|
||||||
|
`SingleApplication` instance for binding to it's signals anywhere in your
|
||||||
|
program.
|
||||||
|
|
||||||
|
__Note:__ On Windows the ability to bring the application windows to the
|
||||||
|
foreground is restricted. See [Windows specific implementations](Windows.md)
|
||||||
|
for a workaround and an example implementation.
|
||||||
|
|
||||||
|
|
||||||
|
Secondary Instances
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
If you want to be able to launch additional Secondary Instances (not related to
|
||||||
|
your Primary Instance) you have to enable that with the third parameter of the
|
||||||
|
`SingleApplication` constructor. The default is `false` meaning no Secondary
|
||||||
|
Instances. Here is an example of how you would start a Secondary Instance send
|
||||||
|
a message with the command line arguments to the primary instance and then shut
|
||||||
|
down.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
SingleApplication app( argc, argv, true );
|
||||||
|
|
||||||
|
if( app.isSecondary() ) {
|
||||||
|
app.sendMessage( app.arguments().join(' ')).toUtf8() );
|
||||||
|
app.exit( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.exec();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
*__Note:__ A secondary instance won't cause the emission of the
|
||||||
|
`instanceStarted()` signal by default. See `SingleApplication::Mode` for more
|
||||||
|
details.*
|
||||||
|
|
||||||
|
You can check whether your instance is a primary or secondary with the following
|
||||||
|
methods:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
app.isPrimary();
|
||||||
|
// or
|
||||||
|
app.isSecondary();
|
||||||
|
```
|
||||||
|
|
||||||
|
*__Note:__ If your Primary Instance is terminated a newly launched instance
|
||||||
|
will replace the Primary one even if the Secondary flag has been set.*
|
||||||
|
|
||||||
|
Examples
|
||||||
|
--------
|
||||||
|
|
||||||
|
There are three examples provided in this repository:
|
||||||
|
|
||||||
|
* Basic example that prevents a secondary instance from starting [`examples/basic`](https://github.com/itay-grudev/SingleApplication/tree/master/examples/basic)
|
||||||
|
* An example of a graphical application raising it's parent window [`examples/calculator`](https://github.com/itay-grudev/SingleApplication/tree/master/examples/calculator)
|
||||||
|
* A console application sending the primary instance it's command line parameters [`examples/sending_arguments`](https://github.com/itay-grudev/SingleApplication/tree/master/examples/sending_arguments)
|
||||||
|
|
||||||
|
API
|
||||||
|
---
|
||||||
|
|
||||||
|
### Members
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
SingleApplication::SingleApplication( int &argc, char *argv[], bool allowSecondary = false, Options options = Mode::User, int timeout = 100, QString userData = QString() )
|
||||||
|
```
|
||||||
|
|
||||||
|
Depending on whether `allowSecondary` is set, this constructor may terminate
|
||||||
|
your app if there is already a primary instance running. Additional `Options`
|
||||||
|
can be specified to set whether the SingleApplication block should work
|
||||||
|
user-wide or system-wide. Additionally the `Mode::SecondaryNotification` may be
|
||||||
|
used to notify the primary instance whenever a secondary instance had been
|
||||||
|
started (disabled by default). `timeout` specifies the maximum time in
|
||||||
|
milliseconds to wait for blocking operations. Setting `userData` provides additional data that will isolate this instance from other instances that do not have the same (or any) user data set.
|
||||||
|
|
||||||
|
*__Note:__ `argc` and `argv` may be changed as Qt removes arguments that it
|
||||||
|
recognizes.*
|
||||||
|
|
||||||
|
*__Note:__ `Mode::SecondaryNotification` only works if set on both the primary
|
||||||
|
and the secondary instance.*
|
||||||
|
|
||||||
|
*__Note:__ Operating system can restrict the shared memory blocks to the same
|
||||||
|
user, in which case the User/System modes will have no effect and the block will
|
||||||
|
be user wide.*
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
bool SingleApplication::sendMessage( QByteArray message, int timeout = 100 )
|
||||||
|
```
|
||||||
|
|
||||||
|
Sends `message` to the Primary Instance. Uses `timeout` as a the maximum timeout
|
||||||
|
in milliseconds for blocking functions. Returns `true` if the message has been sent
|
||||||
|
successfully. If the message can't be sent or the function timeouts - returns `false`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
bool SingleApplication::isPrimary()
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns if the instance is the primary instance.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
bool SingleApplication::isSecondary()
|
||||||
|
```
|
||||||
|
Returns if the instance is a secondary instance.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
quint32 SingleApplication::instanceId()
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns a unique identifier for the current instance.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
qint64 SingleApplication::primaryPid()
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns the process ID (PID) of the primary instance.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
QString SingleApplication::primaryUser()
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns the username the primary instance is running as.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
QString SingleApplication::currentUser()
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns the username the current instance is running as.
|
||||||
|
|
||||||
|
### Signals
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
void SingleApplication::instanceStarted()
|
||||||
|
```
|
||||||
|
|
||||||
|
Triggered whenever a new instance had been started, except for secondary
|
||||||
|
instances if the `Mode::SecondaryNotification` flag is not specified.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
void SingleApplication::receivedMessage( quint32 instanceId, QByteArray message )
|
||||||
|
```
|
||||||
|
|
||||||
|
Triggered whenever there is a message received from a secondary instance.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Flags
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
enum SingleApplication::Mode
|
||||||
|
```
|
||||||
|
|
||||||
|
* `Mode::User` - The SingleApplication block should apply user wide. This adds
|
||||||
|
user specific data to the key used for the shared memory and server name.
|
||||||
|
This is the default functionality.
|
||||||
|
* `Mode::System` – The SingleApplication block applies system-wide.
|
||||||
|
* `Mode::SecondaryNotification` – Whether to trigger `instanceStarted()` even
|
||||||
|
whenever secondary instances are started.
|
||||||
|
* `Mode::ExcludeAppPath` – Excludes the application path from the server name
|
||||||
|
(and memory block) hash.
|
||||||
|
* `Mode::ExcludeAppVersion` – Excludes the application version from the server
|
||||||
|
name (and memory block) hash.
|
||||||
|
|
||||||
|
*__Note:__ `Mode::SecondaryNotification` only works if set on both the primary
|
||||||
|
and the secondary instance.*
|
||||||
|
|
||||||
|
*__Note:__ Operating system can restrict the shared memory blocks to the same
|
||||||
|
user, in which case the User/System modes will have no effect and the block will
|
||||||
|
be user wide.*
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Versioning
|
||||||
|
----------
|
||||||
|
|
||||||
|
Each major version introduces either very significant changes or is not
|
||||||
|
backwards compatible with the previous version. Minor versions only add
|
||||||
|
additional features, bug fixes or performance improvements and are backwards
|
||||||
|
compatible with the previous release. See [`CHANGELOG.md`](CHANGELOG.md) for
|
||||||
|
more details.
|
||||||
|
|
||||||
|
Implementation
|
||||||
|
--------------
|
||||||
|
|
||||||
|
The library is implemented with a QSharedMemory block which is thread safe and
|
||||||
|
guarantees a race condition will not occur. It also uses a QLocalSocket to
|
||||||
|
notify the main process that a new instance had been spawned and thus invoke the
|
||||||
|
`instanceStarted()` signal and for messaging the primary instance.
|
||||||
|
|
||||||
|
Additionally the library can recover from being forcefully killed on *nix
|
||||||
|
systems and will reset the memory block given that there are no other
|
||||||
|
instances running.
|
||||||
|
|
||||||
|
License
|
||||||
|
-------
|
||||||
|
This library and it's supporting documentation are released under
|
||||||
|
`The MIT License (MIT)` with the exception of the Qt calculator examples which
|
||||||
|
is distributed under the BSD license.
|
||||||
2
3rdparty/singleapplication/config.h.in
vendored
Normal file
2
3rdparty/singleapplication/config.h.in
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
#cmakedefine HAVE_GETEUID
|
||||||
|
#cmakedefine HAVE_GETPWUID
|
||||||
266
3rdparty/singleapplication/singleapplication.cpp
vendored
Normal file
266
3rdparty/singleapplication/singleapplication.cpp
vendored
Normal file
@@ -0,0 +1,266 @@
|
|||||||
|
// The MIT License (MIT)
|
||||||
|
//
|
||||||
|
// Copyright (c) Itay Grudev 2015 - 2020
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
//
|
||||||
|
// W A R N I N G !!!
|
||||||
|
// -----------------
|
||||||
|
//
|
||||||
|
// This is a modified version of SingleApplication,
|
||||||
|
// The original version is at:
|
||||||
|
//
|
||||||
|
// https://github.com/itay-grudev/SingleApplication
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
#include <QtGlobal>
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QThread>
|
||||||
|
#include <QSharedMemory>
|
||||||
|
#include <QLocalSocket>
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QElapsedTimer>
|
||||||
|
#include <QtDebug>
|
||||||
|
|
||||||
|
#include "singleapplication.h"
|
||||||
|
#include "singleapplication_p.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Constructor. Checks and fires up LocalServer or closes the program if another instance already exists
|
||||||
|
* @param argc
|
||||||
|
* @param argv
|
||||||
|
* @param allowSecondary Whether to enable secondary instance support
|
||||||
|
* @param options Optional flags to toggle specific behaviour
|
||||||
|
* @param timeout Maximum time blocking functions are allowed during app load
|
||||||
|
*/
|
||||||
|
SingleApplication::SingleApplication(int &argc, char *argv[], const bool allowSecondary, const Options options, const int timeout)
|
||||||
|
: app_t(argc, argv),
|
||||||
|
d_ptr(new SingleApplicationPrivate(this)) {
|
||||||
|
|
||||||
|
Q_D(SingleApplication);
|
||||||
|
|
||||||
|
// Store the current mode of the program
|
||||||
|
d->options_ = options;
|
||||||
|
|
||||||
|
// Generating an application ID used for identifying the shared memory block and QLocalServer
|
||||||
|
d->genBlockServerName();
|
||||||
|
|
||||||
|
// To mitigate QSharedMemory issues with large amount of processes attempting to attach at the same time
|
||||||
|
SingleApplicationPrivate::randomSleep();
|
||||||
|
|
||||||
|
#ifdef Q_OS_UNIX
|
||||||
|
// By explicitly attaching it and then deleting it we make sure that the memory is deleted even after the process has crashed on Unix.
|
||||||
|
d->memory_ = new QSharedMemory(d->blockServerName_);
|
||||||
|
d->memory_->attach();
|
||||||
|
delete d->memory_;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Guarantee thread safe behaviour with a shared memory block.
|
||||||
|
d->memory_ = new QSharedMemory(d->blockServerName_);
|
||||||
|
|
||||||
|
// Create a shared memory block
|
||||||
|
if (d->memory_->create(sizeof(InstancesInfo))) {
|
||||||
|
// Initialize the shared memory block
|
||||||
|
if (!d->memory_->lock()) {
|
||||||
|
qCritical() << "SingleApplication: Unable to lock memory block after create.";
|
||||||
|
abortSafely();
|
||||||
|
}
|
||||||
|
d->initializeMemoryBlock();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (d->memory_->error() == QSharedMemory::AlreadyExists) {
|
||||||
|
// Attempt to attach to the memory segment
|
||||||
|
if (!d->memory_->attach()) {
|
||||||
|
qCritical() << "SingleApplication: Unable to attach to shared memory block.";
|
||||||
|
abortSafely();
|
||||||
|
}
|
||||||
|
if (!d->memory_->lock()) {
|
||||||
|
qCritical() << "SingleApplication: Unable to lock memory block after attach.";
|
||||||
|
abortSafely();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
qCritical() << "SingleApplication: Unable to create block.";
|
||||||
|
abortSafely();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
InstancesInfo *instance = static_cast<InstancesInfo*>(d->memory_->data());
|
||||||
|
QElapsedTimer time;
|
||||||
|
time.start();
|
||||||
|
|
||||||
|
// Make sure the shared memory block is initialised and in consistent state
|
||||||
|
forever {
|
||||||
|
// If the shared memory block's checksum is valid continue
|
||||||
|
if (d->blockChecksum() == instance->checksum) break;
|
||||||
|
|
||||||
|
// If more than 5s have elapsed, assume the primary instance crashed and assume it's position
|
||||||
|
if (time.elapsed() > 5000) {
|
||||||
|
qWarning() << "SingleApplication: Shared memory block has been in an inconsistent state from more than 5s. Assuming primary instance failure.";
|
||||||
|
d->initializeMemoryBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise wait for a random period and try again.
|
||||||
|
// The random sleep here limits the probability of a collision between two racing apps and allows the app to initialise faster
|
||||||
|
if (!d->memory_->unlock()) {
|
||||||
|
qDebug() << "SingleApplication: Unable to unlock memory for random wait.";
|
||||||
|
qDebug() << d->memory_->errorString();
|
||||||
|
}
|
||||||
|
SingleApplicationPrivate::randomSleep();
|
||||||
|
if (!d->memory_->lock()) {
|
||||||
|
qCritical() << "SingleApplication: Unable to lock memory after random wait.";
|
||||||
|
abortSafely();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!instance->primary) {
|
||||||
|
d->startPrimary();
|
||||||
|
if (!d->memory_->unlock()) {
|
||||||
|
qDebug() << "SingleApplication: Unable to unlock memory after primary start.";
|
||||||
|
qDebug() << d->memory_->errorString();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if another instance can be started
|
||||||
|
if (allowSecondary) {
|
||||||
|
d->startSecondary();
|
||||||
|
if (d->options_ & Mode::SecondaryNotification) {
|
||||||
|
d->connectToPrimary(timeout, SingleApplicationPrivate::SecondaryInstance);
|
||||||
|
}
|
||||||
|
if (!d->memory_->unlock()) {
|
||||||
|
qDebug() << "SingleApplication: Unable to unlock memory after secondary start.";
|
||||||
|
qDebug() << d->memory_->errorString();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!d->memory_->unlock()) {
|
||||||
|
qDebug() << "SingleApplication: Unable to unlock memory at end of execution.";
|
||||||
|
qDebug() << d->memory_->errorString();
|
||||||
|
}
|
||||||
|
|
||||||
|
d->connectToPrimary(timeout, SingleApplicationPrivate::NewInstance);
|
||||||
|
|
||||||
|
delete d;
|
||||||
|
|
||||||
|
::exit(EXIT_SUCCESS);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
SingleApplication::~SingleApplication() {
|
||||||
|
Q_D(SingleApplication);
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the current application instance is primary.
|
||||||
|
* @return Returns true if the instance is primary, false otherwise.
|
||||||
|
*/
|
||||||
|
bool SingleApplication::isPrimary() const {
|
||||||
|
Q_D(const SingleApplication);
|
||||||
|
return d->server_ != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the current application instance is secondary.
|
||||||
|
* @return Returns true if the instance is secondary, false otherwise.
|
||||||
|
*/
|
||||||
|
bool SingleApplication::isSecondary() const {
|
||||||
|
Q_D(const SingleApplication);
|
||||||
|
return d->server_ == nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows you to identify an instance by returning unique consecutive instance ids.
|
||||||
|
* It is reset when the first (primary) instance of your app starts and only incremented afterwards.
|
||||||
|
* @return Returns a unique instance id.
|
||||||
|
*/
|
||||||
|
quint32 SingleApplication::instanceId() const {
|
||||||
|
Q_D(const SingleApplication);
|
||||||
|
return d->instanceNumber_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the OS PID (Process Identifier) of the process running the primary instance.
|
||||||
|
* Especially useful when SingleApplication is coupled with OS. specific APIs.
|
||||||
|
* @return Returns the primary instance PID.
|
||||||
|
*/
|
||||||
|
qint64 SingleApplication::primaryPid() const {
|
||||||
|
Q_D(const SingleApplication);
|
||||||
|
return d->primaryPid();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the username the primary instance is running as.
|
||||||
|
* @return Returns the username the primary instance is running as.
|
||||||
|
*/
|
||||||
|
QString SingleApplication::primaryUser() const {
|
||||||
|
Q_D(const SingleApplication);
|
||||||
|
return d->primaryUser();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the username the current instance is running as.
|
||||||
|
* @return Returns the username the current instance is running as.
|
||||||
|
*/
|
||||||
|
QString SingleApplication::currentUser() const {
|
||||||
|
return SingleApplicationPrivate::getUsername();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends message to the Primary Instance.
|
||||||
|
* @param message The message to send.
|
||||||
|
* @param timeout the maximum timeout in milliseconds for blocking functions.
|
||||||
|
* @return true if the message was sent successfully, false otherwise.
|
||||||
|
*/
|
||||||
|
bool SingleApplication::sendMessage(const QByteArray &message, const int timeout) {
|
||||||
|
|
||||||
|
Q_D(SingleApplication);
|
||||||
|
|
||||||
|
// Nobody to connect to
|
||||||
|
if (isPrimary()) return false;
|
||||||
|
|
||||||
|
// Make sure the socket is connected
|
||||||
|
if (!d->connectToPrimary(timeout, SingleApplicationPrivate::Reconnect)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return d->writeConfirmedMessage(timeout, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleans up the shared memory block and exits with a failure.
|
||||||
|
* This function halts program execution.
|
||||||
|
*/
|
||||||
|
void SingleApplication::abortSafely() {
|
||||||
|
|
||||||
|
Q_D(SingleApplication);
|
||||||
|
|
||||||
|
qCritical() << "SingleApplication: " << d->memory_->error() << d->memory_->errorString();
|
||||||
|
delete d;
|
||||||
|
|
||||||
|
::exit(EXIT_FAILURE);
|
||||||
|
|
||||||
|
}
|
||||||
152
3rdparty/singleapplication/singleapplication.h
vendored
Normal file
152
3rdparty/singleapplication/singleapplication.h
vendored
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
// The MIT License (MIT)
|
||||||
|
//
|
||||||
|
// Copyright (c) Itay Grudev 2015 - 2020
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
//
|
||||||
|
// W A R N I N G !!!
|
||||||
|
// -----------------
|
||||||
|
//
|
||||||
|
// This is a modified version of SingleApplication,
|
||||||
|
// The original version is at:
|
||||||
|
//
|
||||||
|
// https://github.com/itay-grudev/SingleApplication
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef SINGLEAPPLICATION_H
|
||||||
|
#define SINGLEAPPLICATION_H
|
||||||
|
|
||||||
|
#include <QtGlobal>
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QFlags>
|
||||||
|
#include <QByteArray>
|
||||||
|
|
||||||
|
class SingleApplicationPrivate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The SingleApplication class handles multiple instances of the same Application
|
||||||
|
* @see QApplication
|
||||||
|
*/
|
||||||
|
class SingleApplication : public QApplication { // clazy:exclude=ctor-missing-parent-argument
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
using app_t = QApplication;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Mode of operation of SingleApplication.
|
||||||
|
* Whether the block should be user-wide or system-wide and whether the
|
||||||
|
* primary instance should be notified when a secondary instance had been
|
||||||
|
* started.
|
||||||
|
* @note Operating system can restrict the shared memory blocks to the same
|
||||||
|
* user, in which case the User/System modes will have no effect and the
|
||||||
|
* block will be user wide.
|
||||||
|
* @enum
|
||||||
|
*/
|
||||||
|
enum Mode {
|
||||||
|
User = 1 << 0,
|
||||||
|
System = 1 << 1,
|
||||||
|
SecondaryNotification = 1 << 2,
|
||||||
|
ExcludeAppVersion = 1 << 3,
|
||||||
|
ExcludeAppPath = 1 << 4
|
||||||
|
};
|
||||||
|
Q_DECLARE_FLAGS(Options, Mode)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Intitializes a SingleApplication instance with argc command line
|
||||||
|
* arguments in argv
|
||||||
|
* @arg {int &} argc - Number of arguments in argv
|
||||||
|
* @arg {const char *[]} argv - Supplied command line arguments
|
||||||
|
* @arg {bool} allowSecondary - Whether to start the instance as secondary
|
||||||
|
* if there is already a primary instance.
|
||||||
|
* @arg {Mode} mode - Whether for the SingleApplication block to be applied
|
||||||
|
* User wide or System wide.
|
||||||
|
* @arg {int} timeout - Timeout to wait in milliseconds.
|
||||||
|
* @note argc and argv may be changed as Qt removes arguments that it
|
||||||
|
* recognizes
|
||||||
|
* @note Mode::SecondaryNotification only works if set on both the primary
|
||||||
|
* instance and the secondary instance.
|
||||||
|
* @note The timeout is just a hint for the maximum time of blocking
|
||||||
|
* operations. It does not guarantee that the SingleApplication
|
||||||
|
* initialisation will be completed in given time, though is a good hint.
|
||||||
|
* Usually 4*timeout would be the worst case (fail) scenario.
|
||||||
|
*/
|
||||||
|
explicit SingleApplication(int &argc, char *argv[], const bool allowSecondary = false, const Options options = Mode::User, const int timeout = 1000);
|
||||||
|
~SingleApplication() override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns if the instance is the primary instance
|
||||||
|
* @returns {bool}
|
||||||
|
*/
|
||||||
|
bool isPrimary() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns if the instance is a secondary instance
|
||||||
|
* @returns {bool}
|
||||||
|
*/
|
||||||
|
bool isSecondary() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns a unique identifier for the current instance
|
||||||
|
* @returns {qint32}
|
||||||
|
*/
|
||||||
|
quint32 instanceId() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the process ID (PID) of the primary instance
|
||||||
|
* @returns {qint64}
|
||||||
|
*/
|
||||||
|
qint64 primaryPid() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the username of the user running the primary instance
|
||||||
|
* @returns {QString}
|
||||||
|
*/
|
||||||
|
QString primaryUser() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the username of the current user
|
||||||
|
* @returns {QString}
|
||||||
|
*/
|
||||||
|
QString currentUser() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sends a message to the primary instance. Returns true on success.
|
||||||
|
* @param {int} timeout - Timeout for connecting
|
||||||
|
* @returns {bool}
|
||||||
|
* @note sendMessage() will return false if invoked from the primary
|
||||||
|
* instance.
|
||||||
|
*/
|
||||||
|
bool sendMessage(const QByteArray &message, const int timeout = 1000);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void instanceStarted();
|
||||||
|
void receivedMessage(quint32 instanceId, QByteArray message);
|
||||||
|
|
||||||
|
private:
|
||||||
|
SingleApplicationPrivate *d_ptr;
|
||||||
|
Q_DECLARE_PRIVATE(SingleApplication)
|
||||||
|
void abortSafely();
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_DECLARE_OPERATORS_FOR_FLAGS(SingleApplication::Options)
|
||||||
|
|
||||||
|
#endif // SINGLEAPPLICATION_H
|
||||||
526
3rdparty/singleapplication/singleapplication_p.cpp
vendored
Normal file
526
3rdparty/singleapplication/singleapplication_p.cpp
vendored
Normal file
@@ -0,0 +1,526 @@
|
|||||||
|
// The MIT License (MIT)
|
||||||
|
//
|
||||||
|
// Copyright (c) Itay Grudev 2015 - 2020
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
//
|
||||||
|
// W A R N I N G !!!
|
||||||
|
// -----------------
|
||||||
|
//
|
||||||
|
// This is a modified version of SingleApplication,
|
||||||
|
// The original version is at:
|
||||||
|
//
|
||||||
|
// https://github.com/itay-grudev/SingleApplication
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <QtGlobal>
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
#ifdef Q_OS_UNIX
|
||||||
|
# include <unistd.h>
|
||||||
|
# include <sys/types.h>
|
||||||
|
# include <pwd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
# ifndef NOMINMAX
|
||||||
|
# define NOMINMAX 1
|
||||||
|
# endif
|
||||||
|
# include <windows.h>
|
||||||
|
# include <lmcons.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QThread>
|
||||||
|
#include <QIODevice>
|
||||||
|
#include <QSharedMemory>
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QDataStream>
|
||||||
|
#include <QCryptographicHash>
|
||||||
|
#include <QLocalServer>
|
||||||
|
#include <QLocalSocket>
|
||||||
|
#include <QElapsedTimer>
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
|
||||||
|
# include <QRandomGenerator>
|
||||||
|
#else
|
||||||
|
# include <QDateTime>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "singleapplication.h"
|
||||||
|
#include "singleapplication_p.h"
|
||||||
|
|
||||||
|
SingleApplicationPrivate::SingleApplicationPrivate(SingleApplication *ptr)
|
||||||
|
: q_ptr(ptr),
|
||||||
|
memory_(nullptr),
|
||||||
|
socket_(nullptr),
|
||||||
|
server_(nullptr),
|
||||||
|
instanceNumber_(-1) {}
|
||||||
|
|
||||||
|
SingleApplicationPrivate::~SingleApplicationPrivate() {
|
||||||
|
|
||||||
|
if (socket_ != nullptr) {
|
||||||
|
socket_->close();
|
||||||
|
delete socket_;
|
||||||
|
socket_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memory_ != nullptr) {
|
||||||
|
memory_->lock();
|
||||||
|
InstancesInfo *instance = static_cast<InstancesInfo*>(memory_->data());
|
||||||
|
if (server_ != nullptr) {
|
||||||
|
server_->close();
|
||||||
|
delete server_;
|
||||||
|
instance->primary = false;
|
||||||
|
instance->primaryPid = -1;
|
||||||
|
instance->primaryUser[0] = '\0';
|
||||||
|
instance->checksum = blockChecksum();
|
||||||
|
}
|
||||||
|
memory_->unlock();
|
||||||
|
|
||||||
|
delete memory_;
|
||||||
|
memory_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QString SingleApplicationPrivate::getUsername() {
|
||||||
|
|
||||||
|
#ifdef Q_OS_UNIX
|
||||||
|
QString username;
|
||||||
|
#if defined(HAVE_GETEUID) && defined(HAVE_GETPWUID)
|
||||||
|
struct passwd *pw = getpwuid(geteuid());
|
||||||
|
if (pw) {
|
||||||
|
username = QString::fromLocal8Bit(pw->pw_name);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (username.isEmpty()) {
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
|
||||||
|
username = qEnvironmentVariable("USER");
|
||||||
|
#else
|
||||||
|
username = QString::fromLocal8Bit(qgetenv("USER"));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return username;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
wchar_t username[UNLEN + 1];
|
||||||
|
// Specifies size of the buffer on input
|
||||||
|
DWORD usernameLength = UNLEN + 1;
|
||||||
|
if (GetUserNameW(username, &usernameLength)) {
|
||||||
|
return QString::fromWCharArray(username);
|
||||||
|
}
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
|
||||||
|
return qEnvironmentVariable("USERNAME");
|
||||||
|
#else
|
||||||
|
return QString::fromLocal8Bit(qgetenv("USERNAME"));
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SingleApplicationPrivate::genBlockServerName() {
|
||||||
|
|
||||||
|
QCryptographicHash appData(QCryptographicHash::Sha256);
|
||||||
|
appData.addData("SingleApplication");
|
||||||
|
appData.addData(SingleApplication::app_t::applicationName().toUtf8());
|
||||||
|
appData.addData(SingleApplication::app_t::organizationName().toUtf8());
|
||||||
|
appData.addData(SingleApplication::app_t::organizationDomain().toUtf8());
|
||||||
|
|
||||||
|
if (!(options_ & SingleApplication::Mode::ExcludeAppVersion)) {
|
||||||
|
appData.addData(SingleApplication::app_t::applicationVersion().toUtf8());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(options_ & SingleApplication::Mode::ExcludeAppPath)) {
|
||||||
|
#if defined(Q_OS_UNIX)
|
||||||
|
const QByteArray appImagePath = qgetenv("APPIMAGE");
|
||||||
|
if (appImagePath.isEmpty()) {
|
||||||
|
appData.addData(SingleApplication::app_t::applicationFilePath().toUtf8());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
appData.addData(appImagePath);
|
||||||
|
};
|
||||||
|
#elif defined(Q_OS_WIN)
|
||||||
|
appData.addData(SingleApplication::app_t::applicationFilePath().toLower().toUtf8());
|
||||||
|
#else
|
||||||
|
appData.addData(SingleApplication::app_t::applicationFilePath().toUtf8());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// User level block requires a user specific data in the hash
|
||||||
|
if (options_ & SingleApplication::Mode::User) {
|
||||||
|
appData.addData(getUsername().toUtf8());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace the backslash in RFC 2045 Base64 [a-zA-Z0-9+/=] to comply with server naming requirements.
|
||||||
|
blockServerName_ = appData.result().toBase64().replace("/", "_");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SingleApplicationPrivate::initializeMemoryBlock() const {
|
||||||
|
|
||||||
|
InstancesInfo *instance = static_cast<InstancesInfo*>(memory_->data());
|
||||||
|
instance->primary = false;
|
||||||
|
instance->secondary = 0;
|
||||||
|
instance->primaryPid = -1;
|
||||||
|
instance->primaryUser[0] = '\0';
|
||||||
|
instance->checksum = blockChecksum();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SingleApplicationPrivate::startPrimary() {
|
||||||
|
|
||||||
|
// Reset the number of connections
|
||||||
|
InstancesInfo *instance = static_cast<InstancesInfo*>(memory_->data());
|
||||||
|
|
||||||
|
instance->primary = true;
|
||||||
|
instance->primaryPid = QCoreApplication::applicationPid();
|
||||||
|
qstrncpy(instance->primaryUser, getUsername().toUtf8().data(), sizeof(instance->primaryUser));
|
||||||
|
instance->checksum = blockChecksum();
|
||||||
|
instanceNumber_ = 0;
|
||||||
|
// Successful creation means that no main process exists
|
||||||
|
// So we start a QLocalServer to listen for connections
|
||||||
|
QLocalServer::removeServer(blockServerName_);
|
||||||
|
server_ = new QLocalServer();
|
||||||
|
|
||||||
|
// Restrict access to the socket according to the SingleApplication::Mode::User flag on User level or no restrictions
|
||||||
|
if (options_ & SingleApplication::Mode::User) {
|
||||||
|
server_->setSocketOptions(QLocalServer::UserAccessOption);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
server_->setSocketOptions(QLocalServer::WorldAccessOption);
|
||||||
|
}
|
||||||
|
|
||||||
|
server_->listen(blockServerName_);
|
||||||
|
QObject::connect(server_, &QLocalServer::newConnection, this, &SingleApplicationPrivate::slotConnectionEstablished);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SingleApplicationPrivate::startSecondary() {
|
||||||
|
|
||||||
|
InstancesInfo *instance = static_cast<InstancesInfo*>(memory_->data());
|
||||||
|
|
||||||
|
instance->secondary += 1;
|
||||||
|
instance->checksum = blockChecksum();
|
||||||
|
instanceNumber_ = instance->secondary;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SingleApplicationPrivate::connectToPrimary(const int timeout, const ConnectionType connectionType) {
|
||||||
|
|
||||||
|
QElapsedTimer time;
|
||||||
|
time.start();
|
||||||
|
|
||||||
|
// Connect to the Local Server of the Primary Instance if not already connected.
|
||||||
|
if (socket_ == nullptr) {
|
||||||
|
socket_ = new QLocalSocket();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (socket_->state() == QLocalSocket::ConnectedState) return true;
|
||||||
|
|
||||||
|
if (socket_->state() != QLocalSocket::ConnectedState) {
|
||||||
|
|
||||||
|
forever {
|
||||||
|
randomSleep();
|
||||||
|
|
||||||
|
if (socket_->state() != QLocalSocket::ConnectingState) {
|
||||||
|
socket_->connectToServer(blockServerName_);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (socket_->state() == QLocalSocket::ConnectingState) {
|
||||||
|
socket_->waitForConnected(static_cast<int>(timeout - time.elapsed()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If connected break out of the loop
|
||||||
|
if (socket_->state() == QLocalSocket::ConnectedState) break;
|
||||||
|
|
||||||
|
// If elapsed time since start is longer than the method timeout return
|
||||||
|
if (time.elapsed() >= timeout) return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialisation message according to the SingleApplication protocol
|
||||||
|
QByteArray initMsg;
|
||||||
|
QDataStream writeStream(&initMsg, QIODevice::WriteOnly);
|
||||||
|
writeStream.setVersion(QDataStream::Qt_5_8);
|
||||||
|
|
||||||
|
writeStream << blockServerName_.toLatin1();
|
||||||
|
writeStream << static_cast<quint8>(connectionType);
|
||||||
|
writeStream << instanceNumber_;
|
||||||
|
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||||
|
quint16 checksum = qChecksum(QByteArray(initMsg, static_cast<quint32>(initMsg.length())));
|
||||||
|
#else
|
||||||
|
quint16 checksum = qChecksum(initMsg.constData(), static_cast<quint32>(initMsg.length()));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
writeStream << checksum;
|
||||||
|
|
||||||
|
return writeConfirmedMessage(static_cast<int>(timeout - time.elapsed()), initMsg);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SingleApplicationPrivate::writeAck(QLocalSocket *sock) {
|
||||||
|
sock->putChar('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SingleApplicationPrivate::writeConfirmedMessage(const int timeout, const QByteArray &msg) const {
|
||||||
|
|
||||||
|
QElapsedTimer time;
|
||||||
|
time.start();
|
||||||
|
|
||||||
|
// Frame 1: The header indicates the message length that follows
|
||||||
|
QByteArray header;
|
||||||
|
QDataStream headerStream(&header, QIODevice::WriteOnly);
|
||||||
|
headerStream.setVersion(QDataStream::Qt_5_8);
|
||||||
|
headerStream << static_cast<quint64>(msg.length());
|
||||||
|
|
||||||
|
if (!writeConfirmedFrame(static_cast<int>(timeout - time.elapsed()), header)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Frame 2: The message
|
||||||
|
return writeConfirmedFrame(static_cast<int>(timeout - time.elapsed()), msg);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SingleApplicationPrivate::writeConfirmedFrame(const int timeout, const QByteArray &msg) const {
|
||||||
|
|
||||||
|
socket_->write(msg);
|
||||||
|
socket_->flush();
|
||||||
|
|
||||||
|
bool result = socket_->waitForReadyRead(timeout);
|
||||||
|
if (result) {
|
||||||
|
socket_->read(1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
quint16 SingleApplicationPrivate::blockChecksum() const {
|
||||||
|
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||||
|
quint16 checksum = qChecksum(QByteArray(static_cast<const char*>(memory_->constData()), offsetof(InstancesInfo, checksum)));
|
||||||
|
#else
|
||||||
|
quint16 checksum = qChecksum(static_cast<const char*>(memory_->constData()), offsetof(InstancesInfo, checksum));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return checksum;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 SingleApplicationPrivate::primaryPid() const {
|
||||||
|
|
||||||
|
memory_->lock();
|
||||||
|
InstancesInfo *instance = static_cast<InstancesInfo*>(memory_->data());
|
||||||
|
qint64 pid = instance->primaryPid;
|
||||||
|
memory_->unlock();
|
||||||
|
|
||||||
|
return pid;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QString SingleApplicationPrivate::primaryUser() const {
|
||||||
|
|
||||||
|
memory_->lock();
|
||||||
|
InstancesInfo *instance = static_cast<InstancesInfo*>(memory_->data());
|
||||||
|
QByteArray username = instance->primaryUser;
|
||||||
|
memory_->unlock();
|
||||||
|
|
||||||
|
return QString::fromUtf8(username);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Executed when a connection has been made to the LocalServer
|
||||||
|
*/
|
||||||
|
void SingleApplicationPrivate::slotConnectionEstablished() {
|
||||||
|
|
||||||
|
QLocalSocket *nextConnSocket = server_->nextPendingConnection();
|
||||||
|
connectionMap_.insert(nextConnSocket, ConnectionInfo());
|
||||||
|
|
||||||
|
QObject::connect(nextConnSocket, &QLocalSocket::aboutToClose, this, [nextConnSocket, this]() {
|
||||||
|
const ConnectionInfo &info = connectionMap_[nextConnSocket];
|
||||||
|
slotClientConnectionClosed(nextConnSocket, info.instanceId);
|
||||||
|
});
|
||||||
|
|
||||||
|
QObject::connect(nextConnSocket, &QLocalSocket::disconnected, nextConnSocket, &QLocalSocket::deleteLater);
|
||||||
|
|
||||||
|
QObject::connect(nextConnSocket, &QLocalSocket::destroyed, this, [nextConnSocket, this]() {
|
||||||
|
connectionMap_.remove(nextConnSocket);
|
||||||
|
});
|
||||||
|
|
||||||
|
QObject::connect(nextConnSocket, &QLocalSocket::readyRead, this, [nextConnSocket, this]() {
|
||||||
|
const ConnectionInfo &info = connectionMap_[nextConnSocket];
|
||||||
|
switch (info.stage) {
|
||||||
|
case StageInitHeader:
|
||||||
|
readMessageHeader(nextConnSocket, StageInitBody);
|
||||||
|
break;
|
||||||
|
case StageInitBody:
|
||||||
|
readInitMessageBody(nextConnSocket);
|
||||||
|
break;
|
||||||
|
case StageConnectedHeader:
|
||||||
|
readMessageHeader(nextConnSocket, StageConnectedBody);
|
||||||
|
break;
|
||||||
|
case StageConnectedBody:
|
||||||
|
this->slotDataAvailable(nextConnSocket, info.instanceId);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SingleApplicationPrivate::readMessageHeader(QLocalSocket *sock, const SingleApplicationPrivate::ConnectionStage nextStage) {
|
||||||
|
|
||||||
|
if (!connectionMap_.contains(sock)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sock->bytesAvailable() < static_cast<qint64>(sizeof(quint64))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDataStream headerStream(sock);
|
||||||
|
headerStream.setVersion(QDataStream::Qt_5_8);
|
||||||
|
|
||||||
|
// Read the header to know the message length
|
||||||
|
quint64 msgLen = 0;
|
||||||
|
headerStream >> msgLen;
|
||||||
|
ConnectionInfo &info = connectionMap_[sock];
|
||||||
|
info.stage = nextStage;
|
||||||
|
info.msgLen = msgLen;
|
||||||
|
|
||||||
|
writeAck(sock);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SingleApplicationPrivate::isFrameComplete(QLocalSocket *sock) {
|
||||||
|
|
||||||
|
if (!connectionMap_.contains(sock)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ConnectionInfo &info = connectionMap_[sock];
|
||||||
|
return (sock->bytesAvailable() >= static_cast<qint64>(info.msgLen));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SingleApplicationPrivate::readInitMessageBody(QLocalSocket *sock) {
|
||||||
|
|
||||||
|
Q_Q(SingleApplication);
|
||||||
|
|
||||||
|
if (!isFrameComplete(sock)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the message body
|
||||||
|
QByteArray msgBytes = sock->readAll();
|
||||||
|
QDataStream readStream(msgBytes);
|
||||||
|
readStream.setVersion(QDataStream::Qt_5_8);
|
||||||
|
|
||||||
|
// server name
|
||||||
|
QByteArray latin1Name;
|
||||||
|
readStream >> latin1Name;
|
||||||
|
|
||||||
|
// connection type
|
||||||
|
ConnectionType connectionType = InvalidConnection;
|
||||||
|
quint8 connTypeVal = InvalidConnection;
|
||||||
|
readStream >> connTypeVal;
|
||||||
|
connectionType = static_cast<ConnectionType>(connTypeVal);
|
||||||
|
|
||||||
|
// instance id
|
||||||
|
quint32 instanceId = 0;
|
||||||
|
readStream >> instanceId;
|
||||||
|
|
||||||
|
// checksum
|
||||||
|
quint16 msgChecksum = 0;
|
||||||
|
readStream >> msgChecksum;
|
||||||
|
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||||
|
const quint16 actualChecksum = qChecksum(QByteArray(msgBytes, static_cast<quint32>(msgBytes.length() - sizeof(quint16))));
|
||||||
|
#else
|
||||||
|
const quint16 actualChecksum = qChecksum(msgBytes.constData(), static_cast<quint32>(msgBytes.length() - sizeof(quint16)));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool isValid = readStream.status() == QDataStream::Ok && QLatin1String(latin1Name) == blockServerName_ && msgChecksum == actualChecksum;
|
||||||
|
|
||||||
|
if (!isValid) {
|
||||||
|
sock->close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectionInfo &info = connectionMap_[sock];
|
||||||
|
info.instanceId = instanceId;
|
||||||
|
info.stage = StageConnectedHeader;
|
||||||
|
|
||||||
|
if (connectionType == NewInstance || (connectionType == SecondaryInstance && options_ & SingleApplication::Mode::SecondaryNotification)) {
|
||||||
|
emit q->instanceStarted();
|
||||||
|
}
|
||||||
|
|
||||||
|
writeAck(sock);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SingleApplicationPrivate::slotDataAvailable(QLocalSocket *dataSocket, const quint32 instanceId) {
|
||||||
|
|
||||||
|
Q_Q(SingleApplication);
|
||||||
|
|
||||||
|
if (!isFrameComplete(dataSocket)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QByteArray message = dataSocket->readAll();
|
||||||
|
|
||||||
|
writeAck(dataSocket);
|
||||||
|
|
||||||
|
ConnectionInfo &info = connectionMap_[dataSocket];
|
||||||
|
info.stage = StageConnectedHeader;
|
||||||
|
|
||||||
|
emit q->receivedMessage(instanceId, message);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SingleApplicationPrivate::slotClientConnectionClosed(QLocalSocket *closedSocket, const quint32 instanceId) {
|
||||||
|
|
||||||
|
if (closedSocket->bytesAvailable() > 0) {
|
||||||
|
slotDataAvailable(closedSocket, instanceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SingleApplicationPrivate::randomSleep() {
|
||||||
|
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
|
||||||
|
QThread::msleep(QRandomGenerator::global()->bounded(8U, 18U));
|
||||||
|
#else
|
||||||
|
qsrand(QDateTime::currentMSecsSinceEpoch() % std::numeric_limits<uint>::max());
|
||||||
|
QThread::msleep(qrand() % 11 + 8);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
116
3rdparty/singleapplication/singleapplication_p.h
vendored
Normal file
116
3rdparty/singleapplication/singleapplication_p.h
vendored
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
// The MIT License (MIT)
|
||||||
|
//
|
||||||
|
// Copyright (c) Itay Grudev 2015 - 2020
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
//
|
||||||
|
// W A R N I N G !!!
|
||||||
|
// -----------------
|
||||||
|
//
|
||||||
|
// This is a modified version of SingleApplication,
|
||||||
|
// The original version is at:
|
||||||
|
//
|
||||||
|
// https://github.com/itay-grudev/SingleApplication
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef SINGLEAPPLICATION_P_H
|
||||||
|
#define SINGLEAPPLICATION_P_H
|
||||||
|
|
||||||
|
#include <QtGlobal>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QString>
|
||||||
|
#include <QHash>
|
||||||
|
|
||||||
|
#include "singleapplication.h"
|
||||||
|
|
||||||
|
class QLocalServer;
|
||||||
|
class QLocalSocket;
|
||||||
|
class QSharedMemory;
|
||||||
|
|
||||||
|
struct InstancesInfo {
|
||||||
|
bool primary;
|
||||||
|
quint32 secondary;
|
||||||
|
qint64 primaryPid;
|
||||||
|
char primaryUser[128];
|
||||||
|
quint16 checksum;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ConnectionInfo {
|
||||||
|
explicit ConnectionInfo() : msgLen(0), instanceId(0), stage(0) {}
|
||||||
|
quint64 msgLen;
|
||||||
|
quint32 instanceId;
|
||||||
|
quint8 stage;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SingleApplicationPrivate : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum ConnectionType : quint8 {
|
||||||
|
InvalidConnection = 0,
|
||||||
|
NewInstance = 1,
|
||||||
|
SecondaryInstance = 2,
|
||||||
|
Reconnect = 3
|
||||||
|
};
|
||||||
|
enum ConnectionStage : quint8 {
|
||||||
|
StageInitHeader = 0,
|
||||||
|
StageInitBody = 1,
|
||||||
|
StageConnectedHeader = 2,
|
||||||
|
StageConnectedBody = 3,
|
||||||
|
};
|
||||||
|
Q_DECLARE_PUBLIC(SingleApplication)
|
||||||
|
|
||||||
|
explicit SingleApplicationPrivate(SingleApplication *ptr);
|
||||||
|
~SingleApplicationPrivate() override;
|
||||||
|
|
||||||
|
static QString getUsername();
|
||||||
|
void genBlockServerName();
|
||||||
|
void initializeMemoryBlock() const;
|
||||||
|
void startPrimary();
|
||||||
|
void startSecondary();
|
||||||
|
bool connectToPrimary(const int timeout, const ConnectionType connectionType);
|
||||||
|
quint16 blockChecksum() const;
|
||||||
|
qint64 primaryPid() const;
|
||||||
|
QString primaryUser() const;
|
||||||
|
bool isFrameComplete(QLocalSocket *sock);
|
||||||
|
void readMessageHeader(QLocalSocket *socket, const ConnectionStage nextStage);
|
||||||
|
void readInitMessageBody(QLocalSocket *socket);
|
||||||
|
void writeAck(QLocalSocket *sock);
|
||||||
|
bool writeConfirmedFrame(const int timeout, const QByteArray &msg) const;
|
||||||
|
bool writeConfirmedMessage(const int timeout, const QByteArray &msg) const;
|
||||||
|
static void randomSleep();
|
||||||
|
|
||||||
|
SingleApplication *q_ptr;
|
||||||
|
QSharedMemory *memory_;
|
||||||
|
QLocalSocket *socket_;
|
||||||
|
QLocalServer *server_;
|
||||||
|
quint32 instanceNumber_;
|
||||||
|
QString blockServerName_;
|
||||||
|
SingleApplication::Options options_;
|
||||||
|
QHash<QLocalSocket*, ConnectionInfo> connectionMap_;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void slotConnectionEstablished();
|
||||||
|
void slotDataAvailable(QLocalSocket*, const quint32);
|
||||||
|
void slotClientConnectionClosed(QLocalSocket*, const quint32);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SINGLEAPPLICATION_P_H
|
||||||
266
3rdparty/singleapplication/singlecoreapplication.cpp
vendored
Normal file
266
3rdparty/singleapplication/singlecoreapplication.cpp
vendored
Normal file
@@ -0,0 +1,266 @@
|
|||||||
|
// The MIT License (MIT)
|
||||||
|
//
|
||||||
|
// Copyright (c) Itay Grudev 2015 - 2020
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
//
|
||||||
|
// W A R N I N G !!!
|
||||||
|
// -----------------
|
||||||
|
//
|
||||||
|
// This is a modified version of SingleApplication,
|
||||||
|
// The original version is at:
|
||||||
|
//
|
||||||
|
// https://github.com/itay-grudev/SingleApplication
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
#include <QtGlobal>
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QThread>
|
||||||
|
#include <QSharedMemory>
|
||||||
|
#include <QLocalSocket>
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QElapsedTimer>
|
||||||
|
#include <QtDebug>
|
||||||
|
|
||||||
|
#include "singlecoreapplication.h"
|
||||||
|
#include "singlecoreapplication_p.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Constructor. Checks and fires up LocalServer or closes the program if another instance already exists
|
||||||
|
* @param argc
|
||||||
|
* @param argv
|
||||||
|
* @param allowSecondary Whether to enable secondary instance support
|
||||||
|
* @param options Optional flags to toggle specific behaviour
|
||||||
|
* @param timeout Maximum time blocking functions are allowed during app load
|
||||||
|
*/
|
||||||
|
SingleCoreApplication::SingleCoreApplication(int &argc, char *argv[], const bool allowSecondary, const Options options, const int timeout)
|
||||||
|
: app_t(argc, argv),
|
||||||
|
d_ptr(new SingleCoreApplicationPrivate(this)) {
|
||||||
|
|
||||||
|
Q_D(SingleCoreApplication);
|
||||||
|
|
||||||
|
// Store the current mode of the program
|
||||||
|
d->options_ = options;
|
||||||
|
|
||||||
|
// Generating an application ID used for identifying the shared memory block and QLocalServer
|
||||||
|
d->genBlockServerName();
|
||||||
|
|
||||||
|
// To mitigate QSharedMemory issues with large amount of processes attempting to attach at the same time
|
||||||
|
SingleCoreApplicationPrivate::randomSleep();
|
||||||
|
|
||||||
|
#ifdef Q_OS_UNIX
|
||||||
|
// By explicitly attaching it and then deleting it we make sure that the memory is deleted even after the process has crashed on Unix.
|
||||||
|
d->memory_ = new QSharedMemory(d->blockServerName_);
|
||||||
|
d->memory_->attach();
|
||||||
|
delete d->memory_;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Guarantee thread safe behaviour with a shared memory block.
|
||||||
|
d->memory_ = new QSharedMemory(d->blockServerName_);
|
||||||
|
|
||||||
|
// Create a shared memory block
|
||||||
|
if (d->memory_->create(sizeof(InstancesInfo))) {
|
||||||
|
// Initialize the shared memory block
|
||||||
|
if (!d->memory_->lock()) {
|
||||||
|
qCritical() << "SingleCoreApplication: Unable to lock memory block after create.";
|
||||||
|
abortSafely();
|
||||||
|
}
|
||||||
|
d->initializeMemoryBlock();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (d->memory_->error() == QSharedMemory::AlreadyExists) {
|
||||||
|
// Attempt to attach to the memory segment
|
||||||
|
if (!d->memory_->attach()) {
|
||||||
|
qCritical() << "SingleCoreApplication: Unable to attach to shared memory block.";
|
||||||
|
abortSafely();
|
||||||
|
}
|
||||||
|
if (!d->memory_->lock()) {
|
||||||
|
qCritical() << "SingleCoreApplication: Unable to lock memory block after attach.";
|
||||||
|
abortSafely();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
qCritical() << "SingleCoreApplication: Unable to create block.";
|
||||||
|
abortSafely();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
InstancesInfo *instance = static_cast<InstancesInfo*>(d->memory_->data());
|
||||||
|
QElapsedTimer time;
|
||||||
|
time.start();
|
||||||
|
|
||||||
|
// Make sure the shared memory block is initialised and in consistent state
|
||||||
|
forever {
|
||||||
|
// If the shared memory block's checksum is valid continue
|
||||||
|
if (d->blockChecksum() == instance->checksum) break;
|
||||||
|
|
||||||
|
// If more than 5s have elapsed, assume the primary instance crashed and assume it's position
|
||||||
|
if (time.elapsed() > 5000) {
|
||||||
|
qWarning() << "SingleCoreApplication: Shared memory block has been in an inconsistent state from more than 5s. Assuming primary instance failure.";
|
||||||
|
d->initializeMemoryBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise wait for a random period and try again.
|
||||||
|
// The random sleep here limits the probability of a collision between two racing apps and allows the app to initialise faster
|
||||||
|
if (!d->memory_->unlock()) {
|
||||||
|
qDebug() << "SingleCoreApplication: Unable to unlock memory for random wait.";
|
||||||
|
qDebug() << d->memory_->errorString();
|
||||||
|
}
|
||||||
|
SingleCoreApplicationPrivate::randomSleep();
|
||||||
|
if (!d->memory_->lock()) {
|
||||||
|
qCritical() << "SingleCoreApplication: Unable to lock memory after random wait.";
|
||||||
|
abortSafely();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!instance->primary) {
|
||||||
|
d->startPrimary();
|
||||||
|
if (!d->memory_->unlock()) {
|
||||||
|
qDebug() << "SingleCoreApplication: Unable to unlock memory after primary start.";
|
||||||
|
qDebug() << d->memory_->errorString();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if another instance can be started
|
||||||
|
if (allowSecondary) {
|
||||||
|
d->startSecondary();
|
||||||
|
if (d->options_ & Mode::SecondaryNotification) {
|
||||||
|
d->connectToPrimary(timeout, SingleCoreApplicationPrivate::SecondaryInstance);
|
||||||
|
}
|
||||||
|
if (!d->memory_->unlock()) {
|
||||||
|
qDebug() << "SingleCoreApplication: Unable to unlock memory after secondary start.";
|
||||||
|
qDebug() << d->memory_->errorString();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!d->memory_->unlock()) {
|
||||||
|
qDebug() << "SingleCoreApplication: Unable to unlock memory at end of execution.";
|
||||||
|
qDebug() << d->memory_->errorString();
|
||||||
|
}
|
||||||
|
|
||||||
|
d->connectToPrimary(timeout, SingleCoreApplicationPrivate::NewInstance);
|
||||||
|
|
||||||
|
delete d;
|
||||||
|
|
||||||
|
::exit(EXIT_SUCCESS);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
SingleCoreApplication::~SingleCoreApplication() {
|
||||||
|
Q_D(SingleCoreApplication);
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the current application instance is primary.
|
||||||
|
* @return Returns true if the instance is primary, false otherwise.
|
||||||
|
*/
|
||||||
|
bool SingleCoreApplication::isPrimary() const {
|
||||||
|
Q_D(const SingleCoreApplication);
|
||||||
|
return d->server_ != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the current application instance is secondary.
|
||||||
|
* @return Returns true if the instance is secondary, false otherwise.
|
||||||
|
*/
|
||||||
|
bool SingleCoreApplication::isSecondary() const {
|
||||||
|
Q_D(const SingleCoreApplication);
|
||||||
|
return d->server_ == nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows you to identify an instance by returning unique consecutive instance ids.
|
||||||
|
* It is reset when the first (primary) instance of your app starts and only incremented afterwards.
|
||||||
|
* @return Returns a unique instance id.
|
||||||
|
*/
|
||||||
|
quint32 SingleCoreApplication::instanceId() const {
|
||||||
|
Q_D(const SingleCoreApplication);
|
||||||
|
return d->instanceNumber_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the OS PID (Process Identifier) of the process running the primary instance.
|
||||||
|
* Especially useful when SingleCoreApplication is coupled with OS. specific APIs.
|
||||||
|
* @return Returns the primary instance PID.
|
||||||
|
*/
|
||||||
|
qint64 SingleCoreApplication::primaryPid() const {
|
||||||
|
Q_D(const SingleCoreApplication);
|
||||||
|
return d->primaryPid();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the username the primary instance is running as.
|
||||||
|
* @return Returns the username the primary instance is running as.
|
||||||
|
*/
|
||||||
|
QString SingleCoreApplication::primaryUser() const {
|
||||||
|
Q_D(const SingleCoreApplication);
|
||||||
|
return d->primaryUser();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the username the current instance is running as.
|
||||||
|
* @return Returns the username the current instance is running as.
|
||||||
|
*/
|
||||||
|
QString SingleCoreApplication::currentUser() const {
|
||||||
|
return SingleCoreApplicationPrivate::getUsername();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends message to the Primary Instance.
|
||||||
|
* @param message The message to send.
|
||||||
|
* @param timeout the maximum timeout in milliseconds for blocking functions.
|
||||||
|
* @return true if the message was sent successfully, false otherwise.
|
||||||
|
*/
|
||||||
|
bool SingleCoreApplication::sendMessage(const QByteArray &message, const int timeout) {
|
||||||
|
|
||||||
|
Q_D(SingleCoreApplication);
|
||||||
|
|
||||||
|
// Nobody to connect to
|
||||||
|
if (isPrimary()) return false;
|
||||||
|
|
||||||
|
// Make sure the socket is connected
|
||||||
|
if (!d->connectToPrimary(timeout, SingleCoreApplicationPrivate::Reconnect)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return d->writeConfirmedMessage(timeout, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleans up the shared memory block and exits with a failure.
|
||||||
|
* This function halts program execution.
|
||||||
|
*/
|
||||||
|
void SingleCoreApplication::abortSafely() {
|
||||||
|
|
||||||
|
Q_D(SingleCoreApplication);
|
||||||
|
|
||||||
|
qCritical() << "SingleCoreApplication: " << d->memory_->error() << d->memory_->errorString();
|
||||||
|
delete d;
|
||||||
|
|
||||||
|
::exit(EXIT_FAILURE);
|
||||||
|
|
||||||
|
}
|
||||||
152
3rdparty/singleapplication/singlecoreapplication.h
vendored
Normal file
152
3rdparty/singleapplication/singlecoreapplication.h
vendored
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
// The MIT License (MIT)
|
||||||
|
//
|
||||||
|
// Copyright (c) Itay Grudev 2015 - 2020
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
//
|
||||||
|
// W A R N I N G !!!
|
||||||
|
// -----------------
|
||||||
|
//
|
||||||
|
// This is a modified version of SingleApplication,
|
||||||
|
// The original version is at:
|
||||||
|
//
|
||||||
|
// https://github.com/itay-grudev/SingleApplication
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef SINGLECOREAPPLICATION_H
|
||||||
|
#define SINGLECOREAPPLICATION_H
|
||||||
|
|
||||||
|
#include <QtGlobal>
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QFlags>
|
||||||
|
#include <QByteArray>
|
||||||
|
|
||||||
|
class SingleCoreApplicationPrivate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The SingleCoreApplication class handles multiple instances of the same Application
|
||||||
|
* @see QCoreApplication
|
||||||
|
*/
|
||||||
|
class SingleCoreApplication : public QCoreApplication { // clazy:exclude=ctor-missing-parent-argument
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
using app_t = QCoreApplication;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Mode of operation of SingleCoreApplication.
|
||||||
|
* Whether the block should be user-wide or system-wide and whether the
|
||||||
|
* primary instance should be notified when a secondary instance had been
|
||||||
|
* started.
|
||||||
|
* @note Operating system can restrict the shared memory blocks to the same
|
||||||
|
* user, in which case the User/System modes will have no effect and the
|
||||||
|
* block will be user wide.
|
||||||
|
* @enum
|
||||||
|
*/
|
||||||
|
enum Mode {
|
||||||
|
User = 1 << 0,
|
||||||
|
System = 1 << 1,
|
||||||
|
SecondaryNotification = 1 << 2,
|
||||||
|
ExcludeAppVersion = 1 << 3,
|
||||||
|
ExcludeAppPath = 1 << 4
|
||||||
|
};
|
||||||
|
Q_DECLARE_FLAGS(Options, Mode)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Intitializes a SingleCoreApplication instance with argc command line
|
||||||
|
* arguments in argv
|
||||||
|
* @arg {int &} argc - Number of arguments in argv
|
||||||
|
* @arg {const char *[]} argv - Supplied command line arguments
|
||||||
|
* @arg {bool} allowSecondary - Whether to start the instance as secondary
|
||||||
|
* if there is already a primary instance.
|
||||||
|
* @arg {Mode} mode - Whether for the SingleCoreApplication block to be applied
|
||||||
|
* User wide or System wide.
|
||||||
|
* @arg {int} timeout - Timeout to wait in milliseconds.
|
||||||
|
* @note argc and argv may be changed as Qt removes arguments that it
|
||||||
|
* recognizes
|
||||||
|
* @note Mode::SecondaryNotification only works if set on both the primary
|
||||||
|
* instance and the secondary instance.
|
||||||
|
* @note The timeout is just a hint for the maximum time of blocking
|
||||||
|
* operations. It does not guarantee that the SingleCoreApplication
|
||||||
|
* initialisation will be completed in given time, though is a good hint.
|
||||||
|
* Usually 4*timeout would be the worst case (fail) scenario.
|
||||||
|
*/
|
||||||
|
explicit SingleCoreApplication(int &argc, char *argv[], const bool allowSecondary = false, const Options options = Mode::User, const int timeout = 1000);
|
||||||
|
~SingleCoreApplication() override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns if the instance is the primary instance
|
||||||
|
* @returns {bool}
|
||||||
|
*/
|
||||||
|
bool isPrimary() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns if the instance is a secondary instance
|
||||||
|
* @returns {bool}
|
||||||
|
*/
|
||||||
|
bool isSecondary() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns a unique identifier for the current instance
|
||||||
|
* @returns {qint32}
|
||||||
|
*/
|
||||||
|
quint32 instanceId() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the process ID (PID) of the primary instance
|
||||||
|
* @returns {qint64}
|
||||||
|
*/
|
||||||
|
qint64 primaryPid() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the username of the user running the primary instance
|
||||||
|
* @returns {QString}
|
||||||
|
*/
|
||||||
|
QString primaryUser() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the username of the current user
|
||||||
|
* @returns {QString}
|
||||||
|
*/
|
||||||
|
QString currentUser() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sends a message to the primary instance. Returns true on success.
|
||||||
|
* @param {int} timeout - Timeout for connecting
|
||||||
|
* @returns {bool}
|
||||||
|
* @note sendMessage() will return false if invoked from the primary
|
||||||
|
* instance.
|
||||||
|
*/
|
||||||
|
bool sendMessage(const QByteArray &message, const int timeout = 1000);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void instanceStarted();
|
||||||
|
void receivedMessage(quint32 instanceId, QByteArray message);
|
||||||
|
|
||||||
|
private:
|
||||||
|
SingleCoreApplicationPrivate *d_ptr;
|
||||||
|
Q_DECLARE_PRIVATE(SingleCoreApplication)
|
||||||
|
void abortSafely();
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_DECLARE_OPERATORS_FOR_FLAGS(SingleCoreApplication::Options)
|
||||||
|
|
||||||
|
#endif // SINGLECOREAPPLICATION_H
|
||||||
526
3rdparty/singleapplication/singlecoreapplication_p.cpp
vendored
Normal file
526
3rdparty/singleapplication/singlecoreapplication_p.cpp
vendored
Normal file
@@ -0,0 +1,526 @@
|
|||||||
|
// The MIT License (MIT)
|
||||||
|
//
|
||||||
|
// Copyright (c) Itay Grudev 2015 - 2020
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
//
|
||||||
|
// W A R N I N G !!!
|
||||||
|
// -----------------
|
||||||
|
//
|
||||||
|
// This is a modified version of SingleApplication,
|
||||||
|
// The original version is at:
|
||||||
|
//
|
||||||
|
// https://github.com/itay-grudev/SingleApplication
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <QtGlobal>
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
#ifdef Q_OS_UNIX
|
||||||
|
# include <unistd.h>
|
||||||
|
# include <sys/types.h>
|
||||||
|
# include <pwd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
# ifndef NOMINMAX
|
||||||
|
# define NOMINMAX 1
|
||||||
|
# endif
|
||||||
|
# include <windows.h>
|
||||||
|
# include <lmcons.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QThread>
|
||||||
|
#include <QIODevice>
|
||||||
|
#include <QSharedMemory>
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QDataStream>
|
||||||
|
#include <QCryptographicHash>
|
||||||
|
#include <QLocalServer>
|
||||||
|
#include <QLocalSocket>
|
||||||
|
#include <QElapsedTimer>
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
|
||||||
|
# include <QRandomGenerator>
|
||||||
|
#else
|
||||||
|
# include <QDateTime>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "singlecoreapplication.h"
|
||||||
|
#include "singlecoreapplication_p.h"
|
||||||
|
|
||||||
|
SingleCoreApplicationPrivate::SingleCoreApplicationPrivate(SingleCoreApplication *ptr)
|
||||||
|
: q_ptr(ptr),
|
||||||
|
memory_(nullptr),
|
||||||
|
socket_(nullptr),
|
||||||
|
server_(nullptr),
|
||||||
|
instanceNumber_(-1) {}
|
||||||
|
|
||||||
|
SingleCoreApplicationPrivate::~SingleCoreApplicationPrivate() {
|
||||||
|
|
||||||
|
if (socket_ != nullptr) {
|
||||||
|
socket_->close();
|
||||||
|
delete socket_;
|
||||||
|
socket_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memory_ != nullptr) {
|
||||||
|
memory_->lock();
|
||||||
|
InstancesInfo *instance = static_cast<InstancesInfo*>(memory_->data());
|
||||||
|
if (server_ != nullptr) {
|
||||||
|
server_->close();
|
||||||
|
delete server_;
|
||||||
|
instance->primary = false;
|
||||||
|
instance->primaryPid = -1;
|
||||||
|
instance->primaryUser[0] = '\0';
|
||||||
|
instance->checksum = blockChecksum();
|
||||||
|
}
|
||||||
|
memory_->unlock();
|
||||||
|
|
||||||
|
delete memory_;
|
||||||
|
memory_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QString SingleCoreApplicationPrivate::getUsername() {
|
||||||
|
|
||||||
|
#ifdef Q_OS_UNIX
|
||||||
|
QString username;
|
||||||
|
#if defined(HAVE_GETEUID) && defined(HAVE_GETPWUID)
|
||||||
|
struct passwd *pw = getpwuid(geteuid());
|
||||||
|
if (pw) {
|
||||||
|
username = QString::fromLocal8Bit(pw->pw_name);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (username.isEmpty()) {
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
|
||||||
|
username = qEnvironmentVariable("USER");
|
||||||
|
#else
|
||||||
|
username = QString::fromLocal8Bit(qgetenv("USER"));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return username;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
wchar_t username[UNLEN + 1];
|
||||||
|
// Specifies size of the buffer on input
|
||||||
|
DWORD usernameLength = UNLEN + 1;
|
||||||
|
if (GetUserNameW(username, &usernameLength)) {
|
||||||
|
return QString::fromWCharArray(username);
|
||||||
|
}
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
|
||||||
|
return qEnvironmentVariable("USERNAME");
|
||||||
|
#else
|
||||||
|
return QString::fromLocal8Bit(qgetenv("USERNAME"));
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SingleCoreApplicationPrivate::genBlockServerName() {
|
||||||
|
|
||||||
|
QCryptographicHash appData(QCryptographicHash::Sha256);
|
||||||
|
appData.addData("SingleApplication");
|
||||||
|
appData.addData(SingleCoreApplication::app_t::applicationName().toUtf8());
|
||||||
|
appData.addData(SingleCoreApplication::app_t::organizationName().toUtf8());
|
||||||
|
appData.addData(SingleCoreApplication::app_t::organizationDomain().toUtf8());
|
||||||
|
|
||||||
|
if (!(options_ & SingleCoreApplication::Mode::ExcludeAppVersion)) {
|
||||||
|
appData.addData(SingleCoreApplication::app_t::applicationVersion().toUtf8());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(options_ & SingleCoreApplication::Mode::ExcludeAppPath)) {
|
||||||
|
#if defined(Q_OS_UNIX)
|
||||||
|
const QByteArray appImagePath = qgetenv("APPIMAGE");
|
||||||
|
if (appImagePath.isEmpty()) {
|
||||||
|
appData.addData(SingleCoreApplication::app_t::applicationFilePath().toUtf8());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
appData.addData(appImagePath);
|
||||||
|
};
|
||||||
|
#elif defined(Q_OS_WIN)
|
||||||
|
appData.addData(SingleCoreApplication::app_t::applicationFilePath().toLower().toUtf8());
|
||||||
|
#else
|
||||||
|
appData.addData(SingleCoreApplication::app_t::applicationFilePath().toUtf8());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// User level block requires a user specific data in the hash
|
||||||
|
if (options_ & SingleCoreApplication::Mode::User) {
|
||||||
|
appData.addData(getUsername().toUtf8());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace the backslash in RFC 2045 Base64 [a-zA-Z0-9+/=] to comply with server naming requirements.
|
||||||
|
blockServerName_ = appData.result().toBase64().replace("/", "_");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SingleCoreApplicationPrivate::initializeMemoryBlock() const {
|
||||||
|
|
||||||
|
InstancesInfo *instance = static_cast<InstancesInfo*>(memory_->data());
|
||||||
|
instance->primary = false;
|
||||||
|
instance->secondary = 0;
|
||||||
|
instance->primaryPid = -1;
|
||||||
|
instance->primaryUser[0] = '\0';
|
||||||
|
instance->checksum = blockChecksum();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SingleCoreApplicationPrivate::startPrimary() {
|
||||||
|
|
||||||
|
// Reset the number of connections
|
||||||
|
InstancesInfo *instance = static_cast<InstancesInfo*>(memory_->data());
|
||||||
|
|
||||||
|
instance->primary = true;
|
||||||
|
instance->primaryPid = QCoreApplication::applicationPid();
|
||||||
|
qstrncpy(instance->primaryUser, getUsername().toUtf8().data(), sizeof(instance->primaryUser));
|
||||||
|
instance->checksum = blockChecksum();
|
||||||
|
instanceNumber_ = 0;
|
||||||
|
// Successful creation means that no main process exists
|
||||||
|
// So we start a QLocalServer to listen for connections
|
||||||
|
QLocalServer::removeServer(blockServerName_);
|
||||||
|
server_ = new QLocalServer();
|
||||||
|
|
||||||
|
// Restrict access to the socket according to the SingleCoreApplication::Mode::User flag on User level or no restrictions
|
||||||
|
if (options_ & SingleCoreApplication::Mode::User) {
|
||||||
|
server_->setSocketOptions(QLocalServer::UserAccessOption);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
server_->setSocketOptions(QLocalServer::WorldAccessOption);
|
||||||
|
}
|
||||||
|
|
||||||
|
server_->listen(blockServerName_);
|
||||||
|
QObject::connect(server_, &QLocalServer::newConnection, this, &SingleCoreApplicationPrivate::slotConnectionEstablished);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SingleCoreApplicationPrivate::startSecondary() {
|
||||||
|
|
||||||
|
InstancesInfo *instance = static_cast<InstancesInfo*>(memory_->data());
|
||||||
|
|
||||||
|
instance->secondary += 1;
|
||||||
|
instance->checksum = blockChecksum();
|
||||||
|
instanceNumber_ = instance->secondary;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SingleCoreApplicationPrivate::connectToPrimary(const int timeout, const ConnectionType connectionType) {
|
||||||
|
|
||||||
|
QElapsedTimer time;
|
||||||
|
time.start();
|
||||||
|
|
||||||
|
// Connect to the Local Server of the Primary Instance if not already connected.
|
||||||
|
if (socket_ == nullptr) {
|
||||||
|
socket_ = new QLocalSocket();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (socket_->state() == QLocalSocket::ConnectedState) return true;
|
||||||
|
|
||||||
|
if (socket_->state() != QLocalSocket::ConnectedState) {
|
||||||
|
|
||||||
|
forever {
|
||||||
|
randomSleep();
|
||||||
|
|
||||||
|
if (socket_->state() != QLocalSocket::ConnectingState) {
|
||||||
|
socket_->connectToServer(blockServerName_);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (socket_->state() == QLocalSocket::ConnectingState) {
|
||||||
|
socket_->waitForConnected(static_cast<int>(timeout - time.elapsed()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If connected break out of the loop
|
||||||
|
if (socket_->state() == QLocalSocket::ConnectedState) break;
|
||||||
|
|
||||||
|
// If elapsed time since start is longer than the method timeout return
|
||||||
|
if (time.elapsed() >= timeout) return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialisation message according to the SingleCoreApplication protocol
|
||||||
|
QByteArray initMsg;
|
||||||
|
QDataStream writeStream(&initMsg, QIODevice::WriteOnly);
|
||||||
|
writeStream.setVersion(QDataStream::Qt_5_8);
|
||||||
|
|
||||||
|
writeStream << blockServerName_.toLatin1();
|
||||||
|
writeStream << static_cast<quint8>(connectionType);
|
||||||
|
writeStream << instanceNumber_;
|
||||||
|
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||||
|
quint16 checksum = qChecksum(QByteArray(initMsg, static_cast<quint32>(initMsg.length())));
|
||||||
|
#else
|
||||||
|
quint16 checksum = qChecksum(initMsg.constData(), static_cast<quint32>(initMsg.length()));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
writeStream << checksum;
|
||||||
|
|
||||||
|
return writeConfirmedMessage(static_cast<int>(timeout - time.elapsed()), initMsg);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SingleCoreApplicationPrivate::writeAck(QLocalSocket *sock) {
|
||||||
|
sock->putChar('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SingleCoreApplicationPrivate::writeConfirmedMessage(const int timeout, const QByteArray &msg) const {
|
||||||
|
|
||||||
|
QElapsedTimer time;
|
||||||
|
time.start();
|
||||||
|
|
||||||
|
// Frame 1: The header indicates the message length that follows
|
||||||
|
QByteArray header;
|
||||||
|
QDataStream headerStream(&header, QIODevice::WriteOnly);
|
||||||
|
headerStream.setVersion(QDataStream::Qt_5_8);
|
||||||
|
headerStream << static_cast<quint64>(msg.length());
|
||||||
|
|
||||||
|
if (!writeConfirmedFrame(static_cast<int>(timeout - time.elapsed()), header)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Frame 2: The message
|
||||||
|
return writeConfirmedFrame(static_cast<int>(timeout - time.elapsed()), msg);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SingleCoreApplicationPrivate::writeConfirmedFrame(const int timeout, const QByteArray &msg) const {
|
||||||
|
|
||||||
|
socket_->write(msg);
|
||||||
|
socket_->flush();
|
||||||
|
|
||||||
|
bool result = socket_->waitForReadyRead(timeout);
|
||||||
|
if (result) {
|
||||||
|
socket_->read(1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
quint16 SingleCoreApplicationPrivate::blockChecksum() const {
|
||||||
|
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||||
|
quint16 checksum = qChecksum(QByteArray(static_cast<const char*>(memory_->constData()), offsetof(InstancesInfo, checksum)));
|
||||||
|
#else
|
||||||
|
quint16 checksum = qChecksum(static_cast<const char*>(memory_->constData()), offsetof(InstancesInfo, checksum));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return checksum;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 SingleCoreApplicationPrivate::primaryPid() const {
|
||||||
|
|
||||||
|
memory_->lock();
|
||||||
|
InstancesInfo *instance = static_cast<InstancesInfo*>(memory_->data());
|
||||||
|
qint64 pid = instance->primaryPid;
|
||||||
|
memory_->unlock();
|
||||||
|
|
||||||
|
return pid;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QString SingleCoreApplicationPrivate::primaryUser() const {
|
||||||
|
|
||||||
|
memory_->lock();
|
||||||
|
InstancesInfo *instance = static_cast<InstancesInfo*>(memory_->data());
|
||||||
|
QByteArray username = instance->primaryUser;
|
||||||
|
memory_->unlock();
|
||||||
|
|
||||||
|
return QString::fromUtf8(username);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Executed when a connection has been made to the LocalServer
|
||||||
|
*/
|
||||||
|
void SingleCoreApplicationPrivate::slotConnectionEstablished() {
|
||||||
|
|
||||||
|
QLocalSocket *nextConnSocket = server_->nextPendingConnection();
|
||||||
|
connectionMap_.insert(nextConnSocket, ConnectionInfo());
|
||||||
|
|
||||||
|
QObject::connect(nextConnSocket, &QLocalSocket::aboutToClose, this, [nextConnSocket, this]() {
|
||||||
|
const ConnectionInfo &info = connectionMap_[nextConnSocket];
|
||||||
|
slotClientConnectionClosed(nextConnSocket, info.instanceId);
|
||||||
|
});
|
||||||
|
|
||||||
|
QObject::connect(nextConnSocket, &QLocalSocket::disconnected, nextConnSocket, &QLocalSocket::deleteLater);
|
||||||
|
|
||||||
|
QObject::connect(nextConnSocket, &QLocalSocket::destroyed, this, [nextConnSocket, this]() {
|
||||||
|
connectionMap_.remove(nextConnSocket);
|
||||||
|
});
|
||||||
|
|
||||||
|
QObject::connect(nextConnSocket, &QLocalSocket::readyRead, this, [nextConnSocket, this]() {
|
||||||
|
const ConnectionInfo &info = connectionMap_[nextConnSocket];
|
||||||
|
switch (info.stage) {
|
||||||
|
case StageInitHeader:
|
||||||
|
readMessageHeader(nextConnSocket, StageInitBody);
|
||||||
|
break;
|
||||||
|
case StageInitBody:
|
||||||
|
readInitMessageBody(nextConnSocket);
|
||||||
|
break;
|
||||||
|
case StageConnectedHeader:
|
||||||
|
readMessageHeader(nextConnSocket, StageConnectedBody);
|
||||||
|
break;
|
||||||
|
case StageConnectedBody:
|
||||||
|
this->slotDataAvailable(nextConnSocket, info.instanceId);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SingleCoreApplicationPrivate::readMessageHeader(QLocalSocket *sock, SingleCoreApplicationPrivate::ConnectionStage nextStage) {
|
||||||
|
|
||||||
|
if (!connectionMap_.contains(sock)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sock->bytesAvailable() < static_cast<qint64>(sizeof(quint64))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDataStream headerStream(sock);
|
||||||
|
headerStream.setVersion(QDataStream::Qt_5_8);
|
||||||
|
|
||||||
|
// Read the header to know the message length
|
||||||
|
quint64 msgLen = 0;
|
||||||
|
headerStream >> msgLen;
|
||||||
|
ConnectionInfo &info = connectionMap_[sock];
|
||||||
|
info.stage = nextStage;
|
||||||
|
info.msgLen = msgLen;
|
||||||
|
|
||||||
|
writeAck(sock);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SingleCoreApplicationPrivate::isFrameComplete(QLocalSocket *sock) {
|
||||||
|
|
||||||
|
if (!connectionMap_.contains(sock)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectionInfo &info = connectionMap_[sock];
|
||||||
|
return (sock->bytesAvailable() >= static_cast<qint64>(info.msgLen));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SingleCoreApplicationPrivate::readInitMessageBody(QLocalSocket *sock) {
|
||||||
|
|
||||||
|
Q_Q(SingleCoreApplication);
|
||||||
|
|
||||||
|
if (!isFrameComplete(sock)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the message body
|
||||||
|
QByteArray msgBytes = sock->readAll();
|
||||||
|
QDataStream readStream(msgBytes);
|
||||||
|
readStream.setVersion(QDataStream::Qt_5_8);
|
||||||
|
|
||||||
|
// server name
|
||||||
|
QByteArray latin1Name;
|
||||||
|
readStream >> latin1Name;
|
||||||
|
|
||||||
|
// connection type
|
||||||
|
ConnectionType connectionType = InvalidConnection;
|
||||||
|
quint8 connTypeVal = InvalidConnection;
|
||||||
|
readStream >> connTypeVal;
|
||||||
|
connectionType = static_cast<ConnectionType>(connTypeVal);
|
||||||
|
|
||||||
|
// instance id
|
||||||
|
quint32 instanceId = 0;
|
||||||
|
readStream >> instanceId;
|
||||||
|
|
||||||
|
// checksum
|
||||||
|
quint16 msgChecksum = 0;
|
||||||
|
readStream >> msgChecksum;
|
||||||
|
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||||
|
const quint16 actualChecksum = qChecksum(QByteArray(msgBytes, static_cast<quint32>(msgBytes.length() - sizeof(quint16))));
|
||||||
|
#else
|
||||||
|
const quint16 actualChecksum = qChecksum(msgBytes.constData(), static_cast<quint32>(msgBytes.length() - sizeof(quint16)));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool isValid = readStream.status() == QDataStream::Ok && QLatin1String(latin1Name) == blockServerName_ && msgChecksum == actualChecksum;
|
||||||
|
|
||||||
|
if (!isValid) {
|
||||||
|
sock->close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectionInfo &info = connectionMap_[sock];
|
||||||
|
info.instanceId = instanceId;
|
||||||
|
info.stage = StageConnectedHeader;
|
||||||
|
|
||||||
|
if (connectionType == NewInstance || (connectionType == SecondaryInstance && options_ & SingleCoreApplication::Mode::SecondaryNotification)) {
|
||||||
|
emit q->instanceStarted();
|
||||||
|
}
|
||||||
|
|
||||||
|
writeAck(sock);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SingleCoreApplicationPrivate::slotDataAvailable(QLocalSocket *dataSocket, const quint32 instanceId) {
|
||||||
|
|
||||||
|
Q_Q(SingleCoreApplication);
|
||||||
|
|
||||||
|
if (!isFrameComplete(dataSocket)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QByteArray message = dataSocket->readAll();
|
||||||
|
|
||||||
|
writeAck(dataSocket);
|
||||||
|
|
||||||
|
ConnectionInfo &info = connectionMap_[dataSocket];
|
||||||
|
info.stage = StageConnectedHeader;
|
||||||
|
|
||||||
|
emit q->receivedMessage(instanceId, message);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SingleCoreApplicationPrivate::slotClientConnectionClosed(QLocalSocket *closedSocket, const quint32 instanceId) {
|
||||||
|
|
||||||
|
if (closedSocket->bytesAvailable() > 0) {
|
||||||
|
slotDataAvailable(closedSocket, instanceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SingleCoreApplicationPrivate::randomSleep() {
|
||||||
|
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
|
||||||
|
QThread::msleep(QRandomGenerator::global()->bounded(8U, 18U));
|
||||||
|
#else
|
||||||
|
qsrand(QDateTime::currentMSecsSinceEpoch() % std::numeric_limits<uint>::max());
|
||||||
|
QThread::msleep(qrand() % 11 + 8);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
116
3rdparty/singleapplication/singlecoreapplication_p.h
vendored
Normal file
116
3rdparty/singleapplication/singlecoreapplication_p.h
vendored
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
// The MIT License (MIT)
|
||||||
|
//
|
||||||
|
// Copyright (c) Itay Grudev 2015 - 2020
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
//
|
||||||
|
// W A R N I N G !!!
|
||||||
|
// -----------------
|
||||||
|
//
|
||||||
|
// This is a modified version of SingleApplication,
|
||||||
|
// The original version is at:
|
||||||
|
//
|
||||||
|
// https://github.com/itay-grudev/SingleApplication
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef SINGLECOREAPPLICATION_P_H
|
||||||
|
#define SINGLECOREAPPLICATION_P_H
|
||||||
|
|
||||||
|
#include <QtGlobal>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QString>
|
||||||
|
#include <QHash>
|
||||||
|
|
||||||
|
#include "singlecoreapplication.h"
|
||||||
|
|
||||||
|
class QLocalServer;
|
||||||
|
class QLocalSocket;
|
||||||
|
class QSharedMemory;
|
||||||
|
|
||||||
|
struct InstancesInfo {
|
||||||
|
bool primary;
|
||||||
|
quint32 secondary;
|
||||||
|
qint64 primaryPid;
|
||||||
|
char primaryUser[128];
|
||||||
|
quint16 checksum;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ConnectionInfo {
|
||||||
|
explicit ConnectionInfo() : msgLen(0), instanceId(0), stage(0) {}
|
||||||
|
quint64 msgLen;
|
||||||
|
quint32 instanceId;
|
||||||
|
quint8 stage;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SingleCoreApplicationPrivate : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum ConnectionType : quint8 {
|
||||||
|
InvalidConnection = 0,
|
||||||
|
NewInstance = 1,
|
||||||
|
SecondaryInstance = 2,
|
||||||
|
Reconnect = 3
|
||||||
|
};
|
||||||
|
enum ConnectionStage : quint8 {
|
||||||
|
StageInitHeader = 0,
|
||||||
|
StageInitBody = 1,
|
||||||
|
StageConnectedHeader = 2,
|
||||||
|
StageConnectedBody = 3,
|
||||||
|
};
|
||||||
|
Q_DECLARE_PUBLIC(SingleCoreApplication)
|
||||||
|
|
||||||
|
explicit SingleCoreApplicationPrivate(SingleCoreApplication *ptr);
|
||||||
|
~SingleCoreApplicationPrivate() override;
|
||||||
|
|
||||||
|
static QString getUsername();
|
||||||
|
void genBlockServerName();
|
||||||
|
void initializeMemoryBlock() const;
|
||||||
|
void startPrimary();
|
||||||
|
void startSecondary();
|
||||||
|
bool connectToPrimary(const int timeout, const ConnectionType connectionType);
|
||||||
|
quint16 blockChecksum() const;
|
||||||
|
qint64 primaryPid() const;
|
||||||
|
QString primaryUser() const;
|
||||||
|
bool isFrameComplete(QLocalSocket *sock);
|
||||||
|
void readMessageHeader(QLocalSocket *socket, const ConnectionStage nextStage);
|
||||||
|
void readInitMessageBody(QLocalSocket *socket);
|
||||||
|
void writeAck(QLocalSocket *sock);
|
||||||
|
bool writeConfirmedFrame(const int timeout, const QByteArray &msg) const;
|
||||||
|
bool writeConfirmedMessage(const int timeout, const QByteArray &msg) const;
|
||||||
|
static void randomSleep();
|
||||||
|
|
||||||
|
SingleCoreApplication *q_ptr;
|
||||||
|
QSharedMemory *memory_;
|
||||||
|
QLocalSocket *socket_;
|
||||||
|
QLocalServer *server_;
|
||||||
|
quint32 instanceNumber_;
|
||||||
|
QString blockServerName_;
|
||||||
|
SingleCoreApplication::Options options_;
|
||||||
|
QHash<QLocalSocket*, ConnectionInfo> connectionMap_;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void slotConnectionEstablished();
|
||||||
|
void slotDataAvailable(QLocalSocket*, const quint32);
|
||||||
|
void slotClientConnectionClosed(QLocalSocket*, const quint32);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SINGLECOREAPPLICATION_P_H
|
||||||
398
3rdparty/taglib/CMakeLists.txt
vendored
398
3rdparty/taglib/CMakeLists.txt
vendored
@@ -1,398 +0,0 @@
|
|||||||
cmake_minimum_required(VERSION 2.8.11)
|
|
||||||
set(CMAKE_CXX_STANDARD 11)
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-delete-non-virtual-dtor")
|
|
||||||
|
|
||||||
set(TAGLIB_SOVERSION_CURRENT 17)
|
|
||||||
set(TAGLIB_SOVERSION_REVISION 0)
|
|
||||||
set(TAGLIB_SOVERSION_AGE 16)
|
|
||||||
|
|
||||||
math(EXPR TAGLIB_SOVERSION_MAJOR "${TAGLIB_SOVERSION_CURRENT} - ${TAGLIB_SOVERSION_AGE}")
|
|
||||||
math(EXPR TAGLIB_SOVERSION_MINOR "${TAGLIB_SOVERSION_AGE}")
|
|
||||||
math(EXPR TAGLIB_SOVERSION_PATCH "${TAGLIB_SOVERSION_REVISION}")
|
|
||||||
|
|
||||||
include(TestBigEndian)
|
|
||||||
test_big_endian(IS_BIG_ENDIAN)
|
|
||||||
|
|
||||||
if(NOT IS_BIG_ENDIAN)
|
|
||||||
add_definitions(-DSYSTEM_BYTEORDER=1)
|
|
||||||
else()
|
|
||||||
add_definitions(-DSYSTEM_BYTEORDER=2)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
configure_file(taglib_config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/taglib_config.h)
|
|
||||||
|
|
||||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
|
||||||
include_directories(
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/toolkit
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/asf
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/mpeg
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/ogg
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/ogg/flac
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/flac
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/mpc
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/mp4
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/ogg/vorbis
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/ogg/speex
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/ogg/opus
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/mpeg/id3v2
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/mpeg/id3v2/frames
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/mpeg/id3v1
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/ape
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/wavpack
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/trueaudio
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/riff
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/riff/aiff
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/riff/wav
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/mod
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/s3m
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/it
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/xm
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/dsf
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/dsdiff
|
|
||||||
${CMAKE_SOURCE_DIR}/3rdparty
|
|
||||||
)
|
|
||||||
|
|
||||||
if(ZLIB_FOUND)
|
|
||||||
include_directories(${ZLIB_INCLUDE_DIR})
|
|
||||||
elseif(HAVE_ZLIB_SOURCE)
|
|
||||||
include_directories(${ZLIB_SOURCE})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(tag_HDRS
|
|
||||||
tag.h
|
|
||||||
fileref.h
|
|
||||||
audioproperties.h
|
|
||||||
taglib_export.h
|
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/taglib_config.h
|
|
||||||
toolkit/taglib.h
|
|
||||||
toolkit/tstring.h
|
|
||||||
toolkit/tlist.h
|
|
||||||
toolkit/tlist.tcc
|
|
||||||
toolkit/tstringlist.h
|
|
||||||
toolkit/tbytevector.h
|
|
||||||
toolkit/tbytevectorlist.h
|
|
||||||
toolkit/tbytevectorstream.h
|
|
||||||
toolkit/tiostream.h
|
|
||||||
toolkit/tfile.h
|
|
||||||
toolkit/tfilestream.h
|
|
||||||
toolkit/tmap.h
|
|
||||||
toolkit/tmap.tcc
|
|
||||||
toolkit/tpropertymap.h
|
|
||||||
toolkit/trefcounter.h
|
|
||||||
toolkit/tdebuglistener.h
|
|
||||||
mpeg/mpegfile.h
|
|
||||||
mpeg/mpegproperties.h
|
|
||||||
mpeg/mpegheader.h
|
|
||||||
mpeg/xingheader.h
|
|
||||||
mpeg/id3v1/id3v1tag.h
|
|
||||||
mpeg/id3v1/id3v1genres.h
|
|
||||||
mpeg/id3v2/id3v2extendedheader.h
|
|
||||||
mpeg/id3v2/id3v2frame.h
|
|
||||||
mpeg/id3v2/id3v2header.h
|
|
||||||
mpeg/id3v2/id3v2synchdata.h
|
|
||||||
mpeg/id3v2/id3v2footer.h
|
|
||||||
mpeg/id3v2/id3v2framefactory.h
|
|
||||||
mpeg/id3v2/id3v2tag.h
|
|
||||||
mpeg/id3v2/frames/attachedpictureframe.h
|
|
||||||
mpeg/id3v2/frames/commentsframe.h
|
|
||||||
mpeg/id3v2/frames/eventtimingcodesframe.h
|
|
||||||
mpeg/id3v2/frames/generalencapsulatedobjectframe.h
|
|
||||||
mpeg/id3v2/frames/ownershipframe.h
|
|
||||||
mpeg/id3v2/frames/popularimeterframe.h
|
|
||||||
mpeg/id3v2/frames/privateframe.h
|
|
||||||
mpeg/id3v2/frames/relativevolumeframe.h
|
|
||||||
mpeg/id3v2/frames/synchronizedlyricsframe.h
|
|
||||||
mpeg/id3v2/frames/textidentificationframe.h
|
|
||||||
mpeg/id3v2/frames/uniquefileidentifierframe.h
|
|
||||||
mpeg/id3v2/frames/unknownframe.h
|
|
||||||
mpeg/id3v2/frames/unsynchronizedlyricsframe.h
|
|
||||||
mpeg/id3v2/frames/urllinkframe.h
|
|
||||||
mpeg/id3v2/frames/chapterframe.h
|
|
||||||
mpeg/id3v2/frames/tableofcontentsframe.h
|
|
||||||
mpeg/id3v2/frames/podcastframe.h
|
|
||||||
ogg/oggfile.h
|
|
||||||
ogg/oggpage.h
|
|
||||||
ogg/oggpageheader.h
|
|
||||||
ogg/xiphcomment.h
|
|
||||||
ogg/vorbis/vorbisfile.h
|
|
||||||
ogg/vorbis/vorbisproperties.h
|
|
||||||
ogg/flac/oggflacfile.h
|
|
||||||
ogg/speex/speexfile.h
|
|
||||||
ogg/speex/speexproperties.h
|
|
||||||
ogg/opus/opusfile.h
|
|
||||||
ogg/opus/opusproperties.h
|
|
||||||
flac/flacfile.h
|
|
||||||
flac/flacpicture.h
|
|
||||||
flac/flacproperties.h
|
|
||||||
flac/flacmetadatablock.h
|
|
||||||
ape/apefile.h
|
|
||||||
ape/apeproperties.h
|
|
||||||
ape/apetag.h
|
|
||||||
ape/apefooter.h
|
|
||||||
ape/apeitem.h
|
|
||||||
mpc/mpcfile.h
|
|
||||||
mpc/mpcproperties.h
|
|
||||||
wavpack/wavpackfile.h
|
|
||||||
wavpack/wavpackproperties.h
|
|
||||||
trueaudio/trueaudiofile.h
|
|
||||||
trueaudio/trueaudioproperties.h
|
|
||||||
riff/rifffile.h
|
|
||||||
riff/aiff/aifffile.h
|
|
||||||
riff/aiff/aiffproperties.h
|
|
||||||
riff/wav/wavfile.h
|
|
||||||
riff/wav/wavproperties.h
|
|
||||||
riff/wav/infotag.h
|
|
||||||
asf/asffile.h
|
|
||||||
asf/asfproperties.h
|
|
||||||
asf/asftag.h
|
|
||||||
asf/asfattribute.h
|
|
||||||
asf/asfpicture.h
|
|
||||||
mp4/mp4file.h
|
|
||||||
mp4/mp4atom.h
|
|
||||||
mp4/mp4tag.h
|
|
||||||
mp4/mp4item.h
|
|
||||||
mp4/mp4properties.h
|
|
||||||
mp4/mp4coverart.h
|
|
||||||
mod/modfilebase.h
|
|
||||||
mod/modfile.h
|
|
||||||
mod/modtag.h
|
|
||||||
mod/modproperties.h
|
|
||||||
it/itfile.h
|
|
||||||
it/itproperties.h
|
|
||||||
s3m/s3mfile.h
|
|
||||||
s3m/s3mproperties.h
|
|
||||||
xm/xmfile.h
|
|
||||||
xm/xmproperties.h
|
|
||||||
dsf/dsffile.h
|
|
||||||
dsf/dsfproperties.h
|
|
||||||
dsdiff/dsdifffile.h
|
|
||||||
dsdiff/dsdiffproperties.h
|
|
||||||
dsdiff/dsdiffdiintag.h
|
|
||||||
)
|
|
||||||
|
|
||||||
set(mpeg_SRCS
|
|
||||||
mpeg/mpegfile.cpp
|
|
||||||
mpeg/mpegproperties.cpp
|
|
||||||
mpeg/mpegheader.cpp
|
|
||||||
mpeg/xingheader.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
set(id3v1_SRCS
|
|
||||||
mpeg/id3v1/id3v1tag.cpp
|
|
||||||
mpeg/id3v1/id3v1genres.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
set(id3v2_SRCS
|
|
||||||
mpeg/id3v2/id3v2framefactory.cpp
|
|
||||||
mpeg/id3v2/id3v2synchdata.cpp
|
|
||||||
mpeg/id3v2/id3v2tag.cpp
|
|
||||||
mpeg/id3v2/id3v2header.cpp
|
|
||||||
mpeg/id3v2/id3v2frame.cpp
|
|
||||||
mpeg/id3v2/id3v2footer.cpp
|
|
||||||
mpeg/id3v2/id3v2extendedheader.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
set(frames_SRCS
|
|
||||||
mpeg/id3v2/frames/attachedpictureframe.cpp
|
|
||||||
mpeg/id3v2/frames/commentsframe.cpp
|
|
||||||
mpeg/id3v2/frames/eventtimingcodesframe.cpp
|
|
||||||
mpeg/id3v2/frames/generalencapsulatedobjectframe.cpp
|
|
||||||
mpeg/id3v2/frames/ownershipframe.cpp
|
|
||||||
mpeg/id3v2/frames/popularimeterframe.cpp
|
|
||||||
mpeg/id3v2/frames/privateframe.cpp
|
|
||||||
mpeg/id3v2/frames/relativevolumeframe.cpp
|
|
||||||
mpeg/id3v2/frames/synchronizedlyricsframe.cpp
|
|
||||||
mpeg/id3v2/frames/textidentificationframe.cpp
|
|
||||||
mpeg/id3v2/frames/uniquefileidentifierframe.cpp
|
|
||||||
mpeg/id3v2/frames/unknownframe.cpp
|
|
||||||
mpeg/id3v2/frames/unsynchronizedlyricsframe.cpp
|
|
||||||
mpeg/id3v2/frames/urllinkframe.cpp
|
|
||||||
mpeg/id3v2/frames/chapterframe.cpp
|
|
||||||
mpeg/id3v2/frames/tableofcontentsframe.cpp
|
|
||||||
mpeg/id3v2/frames/podcastframe.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
set(ogg_SRCS
|
|
||||||
ogg/oggfile.cpp
|
|
||||||
ogg/oggpage.cpp
|
|
||||||
ogg/oggpageheader.cpp
|
|
||||||
ogg/xiphcomment.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
set(vorbis_SRCS
|
|
||||||
ogg/vorbis/vorbisfile.cpp
|
|
||||||
ogg/vorbis/vorbisproperties.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
set(flacs_SRCS
|
|
||||||
flac/flacfile.cpp
|
|
||||||
flac/flacpicture.cpp
|
|
||||||
flac/flacproperties.cpp
|
|
||||||
flac/flacmetadatablock.cpp
|
|
||||||
flac/flacunknownmetadatablock.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
set(oggflacs_SRCS
|
|
||||||
ogg/flac/oggflacfile.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
set(mpc_SRCS
|
|
||||||
mpc/mpcfile.cpp
|
|
||||||
mpc/mpcproperties.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
set(mp4_SRCS
|
|
||||||
mp4/mp4file.cpp
|
|
||||||
mp4/mp4atom.cpp
|
|
||||||
mp4/mp4tag.cpp
|
|
||||||
mp4/mp4item.cpp
|
|
||||||
mp4/mp4properties.cpp
|
|
||||||
mp4/mp4coverart.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
set(ape_SRCS
|
|
||||||
ape/apetag.cpp
|
|
||||||
ape/apefooter.cpp
|
|
||||||
ape/apeitem.cpp
|
|
||||||
ape/apefile.cpp
|
|
||||||
ape/apeproperties.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
set(wavpack_SRCS
|
|
||||||
wavpack/wavpackfile.cpp
|
|
||||||
wavpack/wavpackproperties.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
set(speex_SRCS
|
|
||||||
ogg/speex/speexfile.cpp
|
|
||||||
ogg/speex/speexproperties.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
set(opus_SRCS
|
|
||||||
ogg/opus/opusfile.cpp
|
|
||||||
ogg/opus/opusproperties.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
set(trueaudio_SRCS
|
|
||||||
trueaudio/trueaudiofile.cpp
|
|
||||||
trueaudio/trueaudioproperties.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
set(asf_SRCS
|
|
||||||
asf/asftag.cpp
|
|
||||||
asf/asffile.cpp
|
|
||||||
asf/asfproperties.cpp
|
|
||||||
asf/asfattribute.cpp
|
|
||||||
asf/asfpicture.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
set(riff_SRCS
|
|
||||||
riff/rifffile.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
set(aiff_SRCS
|
|
||||||
riff/aiff/aifffile.cpp
|
|
||||||
riff/aiff/aiffproperties.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
set(wav_SRCS
|
|
||||||
riff/wav/wavfile.cpp
|
|
||||||
riff/wav/wavproperties.cpp
|
|
||||||
riff/wav/infotag.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
set(mod_SRCS
|
|
||||||
mod/modfilebase.cpp
|
|
||||||
mod/modfile.cpp
|
|
||||||
mod/modtag.cpp
|
|
||||||
mod/modproperties.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
set(s3m_SRCS
|
|
||||||
s3m/s3mfile.cpp
|
|
||||||
s3m/s3mproperties.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
set(it_SRCS
|
|
||||||
it/itfile.cpp
|
|
||||||
it/itproperties.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
set(xm_SRCS
|
|
||||||
xm/xmfile.cpp
|
|
||||||
xm/xmproperties.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
set(dsf_SRCS
|
|
||||||
dsf/dsffile.cpp
|
|
||||||
dsf/dsfproperties.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
set(dsdiff_SRCS
|
|
||||||
dsdiff/dsdifffile.cpp
|
|
||||||
dsdiff/dsdiffproperties.cpp
|
|
||||||
dsdiff/dsdiffdiintag.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
set(toolkit_SRCS
|
|
||||||
toolkit/tstring.cpp
|
|
||||||
toolkit/tstringlist.cpp
|
|
||||||
toolkit/tbytevector.cpp
|
|
||||||
toolkit/tbytevectorlist.cpp
|
|
||||||
toolkit/tbytevectorstream.cpp
|
|
||||||
toolkit/tiostream.cpp
|
|
||||||
toolkit/tfile.cpp
|
|
||||||
toolkit/tfilestream.cpp
|
|
||||||
toolkit/tdebug.cpp
|
|
||||||
toolkit/tpropertymap.cpp
|
|
||||||
toolkit/trefcounter.cpp
|
|
||||||
toolkit/tdebuglistener.cpp
|
|
||||||
toolkit/tzlib.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
if(HAVE_ZLIB_SOURCE)
|
|
||||||
set(zlib_SRCS
|
|
||||||
${ZLIB_SOURCE}/adler32.c
|
|
||||||
${ZLIB_SOURCE}/crc32.c
|
|
||||||
${ZLIB_SOURCE}/inffast.c
|
|
||||||
${ZLIB_SOURCE}/inflate.c
|
|
||||||
${ZLIB_SOURCE}/inftrees.c
|
|
||||||
${ZLIB_SOURCE}/zutil.c
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(tag_LIB_SRCS
|
|
||||||
${mpeg_SRCS} ${id3v1_SRCS} ${id3v2_SRCS} ${frames_SRCS} ${ogg_SRCS}
|
|
||||||
${vorbis_SRCS} ${oggflacs_SRCS} ${mpc_SRCS} ${ape_SRCS} ${toolkit_SRCS} ${flacs_SRCS}
|
|
||||||
${wavpack_SRCS} ${speex_SRCS} ${trueaudio_SRCS} ${riff_SRCS} ${aiff_SRCS} ${wav_SRCS}
|
|
||||||
${asf_SRCS} ${mp4_SRCS} ${mod_SRCS} ${s3m_SRCS} ${it_SRCS} ${xm_SRCS} ${opus_SRCS} ${dsf_SRCS} ${dsdiff_SRCS}
|
|
||||||
${zlib_SRCS}
|
|
||||||
tag.cpp
|
|
||||||
tagunion.cpp
|
|
||||||
fileref.cpp
|
|
||||||
audioproperties.cpp
|
|
||||||
tagutils.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
add_library(tag STATIC ${tag_LIB_SRCS} ${tag_HDRS})
|
|
||||||
|
|
||||||
if(HAVE_ZLIB AND NOT HAVE_ZLIB_SOURCE)
|
|
||||||
target_link_libraries(tag ${ZLIB_LIBRARIES})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set_target_properties(tag PROPERTIES
|
|
||||||
VERSION ${TAGLIB_SOVERSION_MAJOR}.${TAGLIB_SOVERSION_MINOR}.${TAGLIB_SOVERSION_PATCH}
|
|
||||||
SOVERSION ${TAGLIB_SOVERSION_MAJOR}
|
|
||||||
DEFINE_SYMBOL MAKE_TAGLIB_LIB
|
|
||||||
LINK_INTERFACE_LIBRARIES ""
|
|
||||||
)
|
|
||||||
|
|
||||||
foreach(header ${tag_HDRS})
|
|
||||||
get_filename_component(header_name ${header} NAME)
|
|
||||||
configure_file(
|
|
||||||
"${header}"
|
|
||||||
"${CMAKE_CURRENT_BINARY_DIR}/headers/taglib/${header_name}"
|
|
||||||
COPYONLY
|
|
||||||
)
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
502
3rdparty/taglib/COPYING
vendored
502
3rdparty/taglib/COPYING
vendored
@@ -1,502 +0,0 @@
|
|||||||
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!
|
|
||||||
170
3rdparty/taglib/ape/ape-tag-format.txt
vendored
170
3rdparty/taglib/ape/ape-tag-format.txt
vendored
@@ -1,170 +0,0 @@
|
|||||||
================================================================================
|
|
||||||
= APE Tag Specification, Version 2.000
|
|
||||||
================================================================================
|
|
||||||
|
|
||||||
Original Content (C) 2004, Frank Klemm <frank.klemm@elster.offl.uni-jena.de>
|
|
||||||
Formatting / Editing (C) 2004, Scott Wheeler <wheeler@kde.org>
|
|
||||||
|
|
||||||
================================================================================
|
|
||||||
= Contents
|
|
||||||
================================================================================
|
|
||||||
|
|
||||||
1 - APE Tag General Structure
|
|
||||||
2 - APE Tag Header / Footer Format
|
|
||||||
3 - APE Tag Flags
|
|
||||||
4 - APE Tag Item Format
|
|
||||||
5 - APE Tag Item Supported Keys
|
|
||||||
6 - APE Tag Item Content
|
|
||||||
7 - Data Types
|
|
||||||
7.1 - Data Types / UTF-8
|
|
||||||
7.2 - Data Types / Dates
|
|
||||||
7.3 - Data Types / Timestamps
|
|
||||||
|
|
||||||
================================================================================
|
|
||||||
= 1 - APE Tag General Structure
|
|
||||||
================================================================================
|
|
||||||
|
|
||||||
Member of Basic Components of SV8 Stream Note:
|
|
||||||
|
|
||||||
It is strongly recommended that the data size be stored in the tags. The size
|
|
||||||
should normally be in the roughly one kilobyte, never more than 8 kilobytes.
|
|
||||||
|
|
||||||
Larger data should be stored externally using link entries. Linked data is much
|
|
||||||
easier to process by normal programs, so for instance JPEG data should not be
|
|
||||||
included inside the audio file.
|
|
||||||
|
|
||||||
APE Tag Version 2.000 (with header, recommended):
|
|
||||||
|
|
||||||
/================================\
|
|
||||||
| APE Tag Header | 32 bytes |
|
|
||||||
|-------------------|------------|
|
|
||||||
| APE Tag Item 1 | > 10 bytes |
|
|
||||||
| APE Tag Item 2 | > 10 bytes |
|
|
||||||
| APE Tag Item n-1 | > 10 bytes |
|
|
||||||
| APE Tag Item n | > 10 bytes |
|
|
||||||
|-------------------|------------|
|
|
||||||
| APE Tag Footer | 32 bytes |
|
|
||||||
\================================/
|
|
||||||
|
|
||||||
|
|
||||||
APE tag items should be sorted ascending by size. When streaming, parts of the
|
|
||||||
APE tag may be dropped to reduce the danger of drop outs between tracks. This
|
|
||||||
is not required, but is strongly recommended. It would be desirable for the i
|
|
||||||
tems to be sorted by importance / size, but this is not feasible. This
|
|
||||||
convention should only be broken when adding less important small items and it
|
|
||||||
is not desirable to rewrite the entire tag. An APE tag at the end of a file
|
|
||||||
(the recommended location) must have at least a footer; an APE tag at the
|
|
||||||
beginning of a file (strongly discouraged) must have at least a header.
|
|
||||||
|
|
||||||
APE Tag Version 1.000 (without header, deprecated)
|
|
||||||
|
|
||||||
/================================\
|
|
||||||
| APE Tag Item 1 | > 10 bytes |
|
|
||||||
| APE Tag Item 2 | > 10 bytes |
|
|
||||||
| APE Tag Item n-1 | > 10 bytes |
|
|
||||||
| APE Tag Item n | > 10 bytes |
|
|
||||||
|-------------------|------------|
|
|
||||||
| APE Tag Footer | 32 bytes |
|
|
||||||
\================================/
|
|
||||||
|
|
||||||
================================================================================
|
|
||||||
= 2 - APE Tag Header / Footer Format
|
|
||||||
================================================================================
|
|
||||||
|
|
||||||
Contains number, length and attributes of all tag items
|
|
||||||
|
|
||||||
Header and Footer are different in 1 bit in the Tags Flags to distinguish
|
|
||||||
between them.
|
|
||||||
|
|
||||||
Member of APE Tag 2.0
|
|
||||||
|
|
||||||
/===========================================================================\
|
|
||||||
| Preamble | 8 bytes | { 'A', 'P', 'E', 'T', 'A', 'G', 'E', 'X' } |
|
|
||||||
|----------------|---------|------------------------------------------------|
|
|
||||||
| Version Number | 4 bytes | 1000 = Version 1.000, 2000 = Version 2.000 |
|
|
||||||
|----------------|---------|------------------------------------------------|
|
|
||||||
| Tag Size | 4 bytes | Tag size in bytes including footer and all tag |
|
|
||||||
| | | items excluding the header (for 1.000 |
|
|
||||||
| | | compatibility) |
|
|
||||||
|----------------|---------|------------------------------------------------|
|
|
||||||
| Item Count | 4 bytes | Number of items in the tag |
|
|
||||||
|----------------|---------|------------------------------------------------|
|
|
||||||
| Tag Flags | 4 bytes | Global flags |
|
|
||||||
|----------------|---------|------------------------------------------------|
|
|
||||||
| Reserved | 8 bytes | Must be zeroed |
|
|
||||||
\===========================================================================/
|
|
||||||
|
|
||||||
================================================================================
|
|
||||||
= 3 - APE Tag Flags
|
|
||||||
================================================================================
|
|
||||||
|
|
||||||
The general flag structure for either items or headers / footers is the same.
|
|
||||||
Bits 31, 30 and 29 are specific to headers / footers, whereas 2 through 0 are
|
|
||||||
item specific.
|
|
||||||
|
|
||||||
Note: APE Tags from Version 1.0 do not use any of the following. All flags in
|
|
||||||
that version are zeroed and ignored when reading.
|
|
||||||
|
|
||||||
/=================================================================\
|
|
||||||
| Contains Header | Bit 31 | 1 - has header | 0 - no header |
|
|
||||||
|-----------------|-------------|---------------------------------|
|
|
||||||
| Contains Footer | Bit 30 | 1 - has footer | 0 - no footer |
|
|
||||||
|-----------------|-------------|---------------------------------|
|
|
||||||
| Is Header | Bit 29 | 1 - is header | 0 - is footer |
|
|
||||||
|-----------------|-------------|---------------------------------|
|
|
||||||
| Undefined | Bits 28 - 3 | Undefined, must be zeroed |
|
|
||||||
|-----------------|-------------|---------------------------------|
|
|
||||||
| Encoding | Bits 2 - 1 | 00 - UTF-8 |
|
|
||||||
| | | 01 - Binary Data * |
|
|
||||||
| | | 10 - External Reference ** |
|
|
||||||
| | | 11 - Reserved |
|
|
||||||
|-----------------|-------------|---------------------------------|
|
|
||||||
| Read Only | Bit 0 | 1 - read only | 0 - read/write |
|
|
||||||
\=================================================================/
|
|
||||||
|
|
||||||
(*) Should be ignored by tools for editing text values
|
|
||||||
(**) Allowed external reference formats:
|
|
||||||
- http://host/directory/filename.ext
|
|
||||||
- ftp://host/directory/filename.ext
|
|
||||||
- filename.ext
|
|
||||||
- /directory/filename.ext
|
|
||||||
- DRIVE:/directory/filename.ext
|
|
||||||
|
|
||||||
Note: External references are also UTF-8 encoded.
|
|
||||||
|
|
||||||
================================================================================
|
|
||||||
= 4 - APE Tag Item Format
|
|
||||||
================================================================================
|
|
||||||
|
|
||||||
APE Tag Items are stored as key-value pairs. APE Tags Item Key are case
|
|
||||||
sensitive, however it is illegal to use keys which only differ in case and
|
|
||||||
it is recommended that tag reading not be case sensitive.
|
|
||||||
|
|
||||||
Every key can only occur (at most) once. It is not possible to repeat a key
|
|
||||||
to signify updated contents.
|
|
||||||
|
|
||||||
Tags can be partially or completely repeated in the streaming format. This
|
|
||||||
makes it possible to display an artist and / or title if it was missed at the
|
|
||||||
beginning of the stream. It is recommended that the important information like
|
|
||||||
artist, album and title should occur approximately every 2 minutes in the
|
|
||||||
stream and again 5 to 10 seconds before the end. However, care should be tak
|
|
||||||
en not to replicate this information too often or during passages with high
|
|
||||||
bitrate demands to avoid unnecessary drop-outs.
|
|
||||||
|
|
||||||
/==============================================================================\
|
|
||||||
| Content Size | 4 bytes | Length of the value in bytes |
|
|
||||||
|----------------|---------------|---------------------------------------------|
|
|
||||||
| Flags | 4 bytes | Item flags |
|
|
||||||
|----------------|---------------|---------------------------------------------|
|
|
||||||
| Key | 2 - 255 bytes | Item key |
|
|
||||||
|----------------|---------------|---------------------------------------------|
|
|
||||||
| Key Terminator | 1 byte | Null byte that indicates the end of the key |
|
|
||||||
|----------------|---------------|---------------------------------------------|
|
|
||||||
| Value | variable | Content (formatted according to the flags) |
|
|
||||||
\==============================================================================/
|
|
||||||
|
|
||||||
================================================================================
|
|
||||||
|
|
||||||
Sections 5 - 7 haven't yet been converted from:
|
|
||||||
|
|
||||||
http://www.personal.uni-jena.de/~pfk/mpp/sv8/apetag.html
|
|
||||||
314
3rdparty/taglib/ape/apefile.cpp
vendored
314
3rdparty/taglib/ape/apefile.cpp
vendored
@@ -1,314 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
copyright : (C) 2010 by Alex Novichkov
|
|
||||||
email : novichko@atnet.ru
|
|
||||||
|
|
||||||
copyright : (C) 2006 by Lukáš Lalinský
|
|
||||||
email : lalinsky@gmail.com
|
|
||||||
(original WavPack implementation)
|
|
||||||
|
|
||||||
copyright : (C) 2004 by Allan Sandfeld Jensen
|
|
||||||
email : kde@carewolf.org
|
|
||||||
(original MPC implementation)
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* This library is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU Lesser General Public License version *
|
|
||||||
* 2.1 as published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 *
|
|
||||||
* *
|
|
||||||
* Alternatively, this file is available under the Mozilla Public *
|
|
||||||
* License Version 1.1. You may obtain a copy of the License at *
|
|
||||||
* http://www.mozilla.org/MPL/ *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#include <tbytevector.h>
|
|
||||||
#include <tstring.h>
|
|
||||||
#include <tdebug.h>
|
|
||||||
#include <tagunion.h>
|
|
||||||
#include <id3v1tag.h>
|
|
||||||
#include <id3v2header.h>
|
|
||||||
#include <tpropertymap.h>
|
|
||||||
#include <tagutils.h>
|
|
||||||
|
|
||||||
#include "apefile.h"
|
|
||||||
#include "apetag.h"
|
|
||||||
#include "apefooter.h"
|
|
||||||
|
|
||||||
using namespace TagLib;
|
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
enum { ApeAPEIndex = 0, ApeID3v1Index = 1 };
|
|
||||||
}
|
|
||||||
|
|
||||||
class APE::File::FilePrivate
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
FilePrivate() :
|
|
||||||
APELocation(-1),
|
|
||||||
APESize(0),
|
|
||||||
ID3v1Location(-1),
|
|
||||||
ID3v2Header(0),
|
|
||||||
ID3v2Location(-1),
|
|
||||||
ID3v2Size(0),
|
|
||||||
properties(0) {}
|
|
||||||
|
|
||||||
~FilePrivate()
|
|
||||||
{
|
|
||||||
delete ID3v2Header;
|
|
||||||
delete properties;
|
|
||||||
}
|
|
||||||
|
|
||||||
long APELocation;
|
|
||||||
long APESize;
|
|
||||||
|
|
||||||
long ID3v1Location;
|
|
||||||
|
|
||||||
ID3v2::Header *ID3v2Header;
|
|
||||||
long ID3v2Location;
|
|
||||||
long ID3v2Size;
|
|
||||||
|
|
||||||
TagUnion tag;
|
|
||||||
|
|
||||||
Properties *properties;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// static members
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
bool APE::File::isSupported(IOStream *stream)
|
|
||||||
{
|
|
||||||
// An APE file has an ID "MAC " somewhere. An ID3v2 tag may precede.
|
|
||||||
|
|
||||||
const ByteVector buffer = Utils::readHeader(stream, bufferSize(), true);
|
|
||||||
return (buffer.find("MAC ") >= 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// public members
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
APE::File::File(FileName file, bool readProperties, Properties::ReadStyle) :
|
|
||||||
TagLib::File(file),
|
|
||||||
d(new FilePrivate())
|
|
||||||
{
|
|
||||||
if(isOpen())
|
|
||||||
read(readProperties);
|
|
||||||
}
|
|
||||||
|
|
||||||
APE::File::File(IOStream *stream, bool readProperties, Properties::ReadStyle) :
|
|
||||||
TagLib::File(stream),
|
|
||||||
d(new FilePrivate())
|
|
||||||
{
|
|
||||||
if(isOpen())
|
|
||||||
read(readProperties);
|
|
||||||
}
|
|
||||||
|
|
||||||
APE::File::~File()
|
|
||||||
{
|
|
||||||
delete d;
|
|
||||||
}
|
|
||||||
|
|
||||||
TagLib::Tag *APE::File::tag() const
|
|
||||||
{
|
|
||||||
return &d->tag;
|
|
||||||
}
|
|
||||||
|
|
||||||
PropertyMap APE::File::properties() const
|
|
||||||
{
|
|
||||||
return d->tag.properties();
|
|
||||||
}
|
|
||||||
|
|
||||||
void APE::File::removeUnsupportedProperties(const StringList &properties)
|
|
||||||
{
|
|
||||||
d->tag.removeUnsupportedProperties(properties);
|
|
||||||
}
|
|
||||||
|
|
||||||
PropertyMap APE::File::setProperties(const PropertyMap &properties)
|
|
||||||
{
|
|
||||||
if(ID3v1Tag())
|
|
||||||
ID3v1Tag()->setProperties(properties);
|
|
||||||
|
|
||||||
return APETag(true)->setProperties(properties);
|
|
||||||
}
|
|
||||||
|
|
||||||
APE::Properties *APE::File::audioProperties() const
|
|
||||||
{
|
|
||||||
return d->properties;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool APE::File::save()
|
|
||||||
{
|
|
||||||
if(readOnly()) {
|
|
||||||
debug("APE::File::save() -- File is read only.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update ID3v1 tag
|
|
||||||
|
|
||||||
if(ID3v1Tag() && !ID3v1Tag()->isEmpty()) {
|
|
||||||
|
|
||||||
// ID3v1 tag is not empty. Update the old one or create a new one.
|
|
||||||
|
|
||||||
if(d->ID3v1Location >= 0) {
|
|
||||||
seek(d->ID3v1Location);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
seek(0, End);
|
|
||||||
d->ID3v1Location = tell();
|
|
||||||
}
|
|
||||||
|
|
||||||
writeBlock(ID3v1Tag()->render());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
// ID3v1 tag is empty. Remove the old one.
|
|
||||||
|
|
||||||
if(d->ID3v1Location >= 0) {
|
|
||||||
truncate(d->ID3v1Location);
|
|
||||||
d->ID3v1Location = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update APE tag
|
|
||||||
|
|
||||||
if(APETag() && !APETag()->isEmpty()) {
|
|
||||||
|
|
||||||
// APE tag is not empty. Update the old one or create a new one.
|
|
||||||
|
|
||||||
if(d->APELocation < 0) {
|
|
||||||
if(d->ID3v1Location >= 0)
|
|
||||||
d->APELocation = d->ID3v1Location;
|
|
||||||
else
|
|
||||||
d->APELocation = length();
|
|
||||||
}
|
|
||||||
|
|
||||||
const ByteVector data = APETag()->render();
|
|
||||||
insert(data, d->APELocation, d->APESize);
|
|
||||||
|
|
||||||
if(d->ID3v1Location >= 0)
|
|
||||||
d->ID3v1Location += (static_cast<long>(data.size()) - d->APESize);
|
|
||||||
|
|
||||||
d->APESize = data.size();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
// APE tag is empty. Remove the old one.
|
|
||||||
|
|
||||||
if(d->APELocation >= 0) {
|
|
||||||
removeBlock(d->APELocation, d->APESize);
|
|
||||||
|
|
||||||
if(d->ID3v1Location >= 0)
|
|
||||||
d->ID3v1Location -= d->APESize;
|
|
||||||
|
|
||||||
d->APELocation = -1;
|
|
||||||
d->APESize = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
ID3v1::Tag *APE::File::ID3v1Tag(bool create)
|
|
||||||
{
|
|
||||||
return d->tag.access<ID3v1::Tag>(ApeID3v1Index, create);
|
|
||||||
}
|
|
||||||
|
|
||||||
APE::Tag *APE::File::APETag(bool create)
|
|
||||||
{
|
|
||||||
return d->tag.access<APE::Tag>(ApeAPEIndex, create);
|
|
||||||
}
|
|
||||||
|
|
||||||
void APE::File::strip(int tags)
|
|
||||||
{
|
|
||||||
if(tags & ID3v1)
|
|
||||||
d->tag.set(ApeID3v1Index, 0);
|
|
||||||
|
|
||||||
if(tags & APE)
|
|
||||||
d->tag.set(ApeAPEIndex, 0);
|
|
||||||
|
|
||||||
if(!ID3v1Tag())
|
|
||||||
APETag(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool APE::File::hasAPETag() const
|
|
||||||
{
|
|
||||||
return (d->APELocation >= 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool APE::File::hasID3v1Tag() const
|
|
||||||
{
|
|
||||||
return (d->ID3v1Location >= 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// private members
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void APE::File::read(bool readProperties)
|
|
||||||
{
|
|
||||||
// Look for an ID3v2 tag
|
|
||||||
|
|
||||||
d->ID3v2Location = Utils::findID3v2(this);
|
|
||||||
|
|
||||||
if(d->ID3v2Location >= 0) {
|
|
||||||
seek(d->ID3v2Location);
|
|
||||||
d->ID3v2Header = new ID3v2::Header(readBlock(ID3v2::Header::size()));
|
|
||||||
d->ID3v2Size = d->ID3v2Header->completeTagSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Look for an ID3v1 tag
|
|
||||||
|
|
||||||
d->ID3v1Location = Utils::findID3v1(this);
|
|
||||||
|
|
||||||
if(d->ID3v1Location >= 0)
|
|
||||||
d->tag.set(ApeID3v1Index, new ID3v1::Tag(this, d->ID3v1Location));
|
|
||||||
|
|
||||||
// Look for an APE tag
|
|
||||||
|
|
||||||
d->APELocation = Utils::findAPE(this, d->ID3v1Location);
|
|
||||||
|
|
||||||
if(d->APELocation >= 0) {
|
|
||||||
d->tag.set(ApeAPEIndex, new APE::Tag(this, d->APELocation));
|
|
||||||
d->APESize = APETag()->footer()->completeTagSize();
|
|
||||||
d->APELocation = d->APELocation + APE::Footer::size() - d->APESize;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(d->ID3v1Location < 0)
|
|
||||||
APETag(true);
|
|
||||||
|
|
||||||
// Look for APE audio properties
|
|
||||||
|
|
||||||
if(readProperties) {
|
|
||||||
|
|
||||||
long streamLength;
|
|
||||||
|
|
||||||
if(d->APELocation >= 0)
|
|
||||||
streamLength = d->APELocation;
|
|
||||||
else if(d->ID3v1Location >= 0)
|
|
||||||
streamLength = d->ID3v1Location;
|
|
||||||
else
|
|
||||||
streamLength = length();
|
|
||||||
|
|
||||||
if(d->ID3v2Location >= 0) {
|
|
||||||
seek(d->ID3v2Location + d->ID3v2Size);
|
|
||||||
streamLength -= (d->ID3v2Location + d->ID3v2Size);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
seek(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
d->properties = new Properties(this, streamLength);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
235
3rdparty/taglib/ape/apefile.h
vendored
235
3rdparty/taglib/ape/apefile.h
vendored
@@ -1,235 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
copyright : (C) 2010 by Alex Novichkov
|
|
||||||
email : novichko@atnet.ru
|
|
||||||
|
|
||||||
copyright : (C) 2006 by Lukáš Lalinský
|
|
||||||
email : lalinsky@gmail.com
|
|
||||||
(original WavPack implementation)
|
|
||||||
|
|
||||||
copyright : (C) 2004 by Allan Sandfeld Jensen
|
|
||||||
email : kde@carewolf.org
|
|
||||||
(original MPC implementation)
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* This library is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU Lesser General Public License version *
|
|
||||||
* 2.1 as published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 *
|
|
||||||
* *
|
|
||||||
* Alternatively, this file is available under the Mozilla Public *
|
|
||||||
* License Version 1.1. You may obtain a copy of the License at *
|
|
||||||
* http://www.mozilla.org/MPL/ *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#ifndef TAGLIB_APEFILE_H
|
|
||||||
#define TAGLIB_APEFILE_H
|
|
||||||
|
|
||||||
#include "tfile.h"
|
|
||||||
#include "taglib_export.h"
|
|
||||||
#include "apeproperties.h"
|
|
||||||
|
|
||||||
namespace TagLib {
|
|
||||||
|
|
||||||
class Tag;
|
|
||||||
|
|
||||||
namespace ID3v1 { class Tag; }
|
|
||||||
namespace APE { class Tag; }
|
|
||||||
|
|
||||||
//! An implementation of APE metadata
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* This is implementation of APE metadata.
|
|
||||||
*
|
|
||||||
* This supports ID3v1 and APE (v1 and v2) style comments as well as reading stream
|
|
||||||
* properties from the file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace APE {
|
|
||||||
|
|
||||||
//! An implementation of TagLib::File with APE specific methods
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* This implements and provides an interface for APE files to the
|
|
||||||
* TagLib::Tag and TagLib::AudioProperties interfaces by way of implementing
|
|
||||||
* the abstract TagLib::File API as well as providing some additional
|
|
||||||
* information specific to APE files.
|
|
||||||
*/
|
|
||||||
|
|
||||||
class TAGLIB_EXPORT File : public TagLib::File
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/*!
|
|
||||||
* This set of flags is used for various operations and is suitable for
|
|
||||||
* being OR-ed together.
|
|
||||||
*/
|
|
||||||
enum TagTypes {
|
|
||||||
//! Empty set. Matches no tag types.
|
|
||||||
NoTags = 0x0000,
|
|
||||||
//! Matches ID3v1 tags.
|
|
||||||
ID3v1 = 0x0001,
|
|
||||||
//! Matches APE tags.
|
|
||||||
APE = 0x0002,
|
|
||||||
//! Matches all tag types.
|
|
||||||
AllTags = 0xffff
|
|
||||||
};
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Constructs an APE file from \a file. If \a readProperties is true the
|
|
||||||
* file's audio properties will also be read.
|
|
||||||
*
|
|
||||||
* \note In the current implementation, \a propertiesStyle is ignored.
|
|
||||||
*/
|
|
||||||
File(FileName file, bool readProperties = true,
|
|
||||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Constructs an APE file from \a stream. If \a readProperties is true the
|
|
||||||
* file's audio properties will also be read.
|
|
||||||
*
|
|
||||||
* \note TagLib will *not* take ownership of the stream, the caller is
|
|
||||||
* responsible for deleting it after the File object.
|
|
||||||
*
|
|
||||||
* \note In the current implementation, \a propertiesStyle is ignored.
|
|
||||||
*/
|
|
||||||
File(IOStream *stream, bool readProperties = true,
|
|
||||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Destroys this instance of the File.
|
|
||||||
*/
|
|
||||||
virtual ~File();
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns the Tag for this file. This will be an APE tag, an ID3v1 tag
|
|
||||||
* or a combination of the two.
|
|
||||||
*/
|
|
||||||
virtual TagLib::Tag *tag() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Implements the unified property interface -- export function.
|
|
||||||
* If the file contains both an APE and an ID3v1 tag, only APE
|
|
||||||
* will be converted to the PropertyMap.
|
|
||||||
*/
|
|
||||||
PropertyMap properties() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Removes unsupported properties. Forwards to the actual Tag's
|
|
||||||
* removeUnsupportedProperties() function.
|
|
||||||
*/
|
|
||||||
void removeUnsupportedProperties(const StringList &properties);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Implements the unified property interface -- import function.
|
|
||||||
* Creates an APEv2 tag if necessary. A potentially existing ID3v1
|
|
||||||
* tag will be updated as well.
|
|
||||||
*/
|
|
||||||
PropertyMap setProperties(const PropertyMap &);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns the APE::Properties for this file. If no audio properties
|
|
||||||
* were read then this will return a null pointer.
|
|
||||||
*/
|
|
||||||
virtual Properties *audioProperties() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Saves the file.
|
|
||||||
*
|
|
||||||
* \note According to the official Monkey's Audio SDK, an APE file
|
|
||||||
* can only have either ID3V1 or APE tags, so a parameter is used here.
|
|
||||||
*/
|
|
||||||
virtual bool save();
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns a pointer to the ID3v1 tag of the file.
|
|
||||||
*
|
|
||||||
* If \a create is false (the default) this may return a null pointer
|
|
||||||
* if there is no valid ID3v1 tag. If \a create is true it will create
|
|
||||||
* an ID3v1 tag if one does not exist and returns a valid pointer.
|
|
||||||
*
|
|
||||||
* \note This may return a valid pointer regardless of whether or not the
|
|
||||||
* file on disk has an ID3v1 tag. Use hasID3v1Tag() to check if the file
|
|
||||||
* on disk actually has an ID3v1 tag.
|
|
||||||
*
|
|
||||||
* \note The Tag <b>is still</b> owned by the MPEG::File and should not be
|
|
||||||
* deleted by the user. It will be deleted when the file (object) is
|
|
||||||
* destroyed.
|
|
||||||
*
|
|
||||||
* \see hasID3v1Tag()
|
|
||||||
*/
|
|
||||||
ID3v1::Tag *ID3v1Tag(bool create = false);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns a pointer to the APE tag of the file.
|
|
||||||
*
|
|
||||||
* If \a create is false (the default) this may return a null pointer
|
|
||||||
* if there is no valid APE tag. If \a create is true it will create
|
|
||||||
* an APE tag if one does not exist and returns a valid pointer.
|
|
||||||
*
|
|
||||||
* \note This may return a valid pointer regardless of whether or not the
|
|
||||||
* file on disk has an APE tag. Use hasAPETag() to check if the file
|
|
||||||
* on disk actually has an APE tag.
|
|
||||||
*
|
|
||||||
* \note The Tag <b>is still</b> owned by the MPEG::File and should not be
|
|
||||||
* deleted by the user. It will be deleted when the file (object) is
|
|
||||||
* destroyed.
|
|
||||||
*
|
|
||||||
* \see hasAPETag()
|
|
||||||
*/
|
|
||||||
APE::Tag *APETag(bool create = false);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* This will remove the tags that match the OR-ed together TagTypes from the
|
|
||||||
* file. By default it removes all tags.
|
|
||||||
*
|
|
||||||
* \note This will also invalidate pointers to the tags
|
|
||||||
* as their memory will be freed.
|
|
||||||
* \note In order to make the removal permanent save() still needs to be called
|
|
||||||
*/
|
|
||||||
void strip(int tags = AllTags);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns whether or not the file on disk actually has an APE tag.
|
|
||||||
*
|
|
||||||
* \see APETag()
|
|
||||||
*/
|
|
||||||
bool hasAPETag() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns whether or not the file on disk actually has an ID3v1 tag.
|
|
||||||
*
|
|
||||||
* \see ID3v1Tag()
|
|
||||||
*/
|
|
||||||
bool hasID3v1Tag() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns whether or not the given \a stream can be opened as an APE
|
|
||||||
* file.
|
|
||||||
*
|
|
||||||
* \note This method is designed to do a quick check. The result may
|
|
||||||
* not necessarily be correct.
|
|
||||||
*/
|
|
||||||
static bool isSupported(IOStream *stream);
|
|
||||||
|
|
||||||
private:
|
|
||||||
File(const File &);
|
|
||||||
File &operator=(const File &);
|
|
||||||
|
|
||||||
void read(bool readProperties);
|
|
||||||
|
|
||||||
class FilePrivate;
|
|
||||||
FilePrivate *d;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
234
3rdparty/taglib/ape/apefooter.cpp
vendored
234
3rdparty/taglib/ape/apefooter.cpp
vendored
@@ -1,234 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
copyright : (C) 2004 by Allan Sandfeld Jensen
|
|
||||||
(C) 2002 - 2008 by Scott Wheeler (id3v2header.cpp)
|
|
||||||
email : kde@carewolf.org
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* This library is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU Lesser General Public License version *
|
|
||||||
* 2.1 as published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 *
|
|
||||||
* *
|
|
||||||
* Alternatively, this file is available under the Mozilla Public *
|
|
||||||
* License Version 1.1. You may obtain a copy of the License at *
|
|
||||||
* http://www.mozilla.org/MPL/ *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <bitset>
|
|
||||||
|
|
||||||
#include <tstring.h>
|
|
||||||
#include <tdebug.h>
|
|
||||||
|
|
||||||
#include "apefooter.h"
|
|
||||||
|
|
||||||
using namespace TagLib;
|
|
||||||
using namespace APE;
|
|
||||||
|
|
||||||
class APE::Footer::FooterPrivate
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
FooterPrivate() :
|
|
||||||
version(0),
|
|
||||||
footerPresent(true),
|
|
||||||
headerPresent(false),
|
|
||||||
isHeader(false),
|
|
||||||
itemCount(0),
|
|
||||||
tagSize(0) {}
|
|
||||||
|
|
||||||
unsigned int version;
|
|
||||||
|
|
||||||
bool footerPresent;
|
|
||||||
bool headerPresent;
|
|
||||||
|
|
||||||
bool isHeader;
|
|
||||||
|
|
||||||
unsigned int itemCount;
|
|
||||||
unsigned int tagSize;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// static members
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
unsigned int APE::Footer::size()
|
|
||||||
{
|
|
||||||
return 32;
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteVector APE::Footer::fileIdentifier()
|
|
||||||
{
|
|
||||||
return ByteVector("APETAGEX");
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// public members
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
APE::Footer::Footer() :
|
|
||||||
d(new FooterPrivate())
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
APE::Footer::Footer(const ByteVector &data) :
|
|
||||||
d(new FooterPrivate())
|
|
||||||
{
|
|
||||||
parse(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
APE::Footer::~Footer()
|
|
||||||
{
|
|
||||||
delete d;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int APE::Footer::version() const
|
|
||||||
{
|
|
||||||
return d->version;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool APE::Footer::headerPresent() const
|
|
||||||
{
|
|
||||||
return d->headerPresent;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool APE::Footer::footerPresent() const
|
|
||||||
{
|
|
||||||
return d->footerPresent;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool APE::Footer::isHeader() const
|
|
||||||
{
|
|
||||||
return d->isHeader;
|
|
||||||
}
|
|
||||||
|
|
||||||
void APE::Footer::setHeaderPresent(bool b) const
|
|
||||||
{
|
|
||||||
d->headerPresent = b;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int APE::Footer::itemCount() const
|
|
||||||
{
|
|
||||||
return d->itemCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
void APE::Footer::setItemCount(unsigned int s)
|
|
||||||
{
|
|
||||||
d->itemCount = s;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int APE::Footer::tagSize() const
|
|
||||||
{
|
|
||||||
return d->tagSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int APE::Footer::completeTagSize() const
|
|
||||||
{
|
|
||||||
if(d->headerPresent)
|
|
||||||
return d->tagSize + size();
|
|
||||||
else
|
|
||||||
return d->tagSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
void APE::Footer::setTagSize(unsigned int s)
|
|
||||||
{
|
|
||||||
d->tagSize = s;
|
|
||||||
}
|
|
||||||
|
|
||||||
void APE::Footer::setData(const ByteVector &data)
|
|
||||||
{
|
|
||||||
parse(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteVector APE::Footer::renderFooter() const
|
|
||||||
{
|
|
||||||
return render(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteVector APE::Footer::renderHeader() const
|
|
||||||
{
|
|
||||||
if(!d->headerPresent)
|
|
||||||
return ByteVector();
|
|
||||||
else
|
|
||||||
return render(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// protected members
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void APE::Footer::parse(const ByteVector &data)
|
|
||||||
{
|
|
||||||
if(data.size() < size())
|
|
||||||
return;
|
|
||||||
|
|
||||||
// The first eight bytes, data[0..7], are the File Identifier, "APETAGEX".
|
|
||||||
|
|
||||||
// Read the version number
|
|
||||||
|
|
||||||
d->version = data.toUInt(8, false);
|
|
||||||
|
|
||||||
// Read the tag size
|
|
||||||
|
|
||||||
d->tagSize = data.toUInt(12, false);
|
|
||||||
|
|
||||||
// Read the item count
|
|
||||||
|
|
||||||
d->itemCount = data.toUInt(16, false);
|
|
||||||
|
|
||||||
// Read the flags
|
|
||||||
|
|
||||||
std::bitset<32> flags(TAGLIB_CONSTRUCT_BITSET(data.toUInt(20, false)));
|
|
||||||
|
|
||||||
d->headerPresent = flags[31];
|
|
||||||
d->footerPresent = !flags[30];
|
|
||||||
d->isHeader = flags[29];
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteVector APE::Footer::render(bool isHeader) const
|
|
||||||
{
|
|
||||||
ByteVector v;
|
|
||||||
|
|
||||||
// add the file identifier -- "APETAGEX"
|
|
||||||
|
|
||||||
v.append(fileIdentifier());
|
|
||||||
|
|
||||||
// add the version number -- we always render a 2.000 tag regardless of what
|
|
||||||
// the tag originally was.
|
|
||||||
|
|
||||||
v.append(ByteVector::fromUInt(2000, false));
|
|
||||||
|
|
||||||
// add the tag size
|
|
||||||
|
|
||||||
v.append(ByteVector::fromUInt(d->tagSize, false));
|
|
||||||
|
|
||||||
// add the item count
|
|
||||||
|
|
||||||
v.append(ByteVector::fromUInt(d->itemCount, false));
|
|
||||||
|
|
||||||
// render and add the flags
|
|
||||||
|
|
||||||
std::bitset<32> flags;
|
|
||||||
|
|
||||||
flags[31] = d->headerPresent;
|
|
||||||
flags[30] = false; // footer is always present
|
|
||||||
flags[29] = isHeader;
|
|
||||||
|
|
||||||
v.append(ByteVector::fromUInt(flags.to_ulong(), false));
|
|
||||||
|
|
||||||
// add the reserved 64bit
|
|
||||||
|
|
||||||
v.append(ByteVector::fromLongLong(0));
|
|
||||||
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
173
3rdparty/taglib/ape/apefooter.h
vendored
173
3rdparty/taglib/ape/apefooter.h
vendored
@@ -1,173 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
copyright : (C) 2004 by Allan Sandfeld Jensen
|
|
||||||
email : kde@carewolf.org
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* This library is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU Lesser General Public License version *
|
|
||||||
* 2.1 as published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 *
|
|
||||||
* *
|
|
||||||
* Alternatively, this file is available under the Mozilla Public *
|
|
||||||
* License Version 1.1. You may obtain a copy of the License at *
|
|
||||||
* http://www.mozilla.org/MPL/ *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#ifndef TAGLIB_APEFOOTER_H
|
|
||||||
#define TAGLIB_APEFOOTER_H
|
|
||||||
|
|
||||||
#include "tbytevector.h"
|
|
||||||
#include "taglib_export.h"
|
|
||||||
|
|
||||||
namespace TagLib {
|
|
||||||
|
|
||||||
namespace APE {
|
|
||||||
|
|
||||||
//! An implementation of APE footers
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* This class implements APE footers (and headers). It attempts to follow, both
|
|
||||||
* semantically and programmatically, the structure specified in
|
|
||||||
* the APE v2.0 standard. The API is based on the properties of APE footer and
|
|
||||||
* headers specified there.
|
|
||||||
*/
|
|
||||||
|
|
||||||
class TAGLIB_EXPORT Footer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/*!
|
|
||||||
* Constructs an empty APE footer.
|
|
||||||
*/
|
|
||||||
Footer();
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Constructs an APE footer based on \a data. parse() is called
|
|
||||||
* immediately.
|
|
||||||
*/
|
|
||||||
Footer(const ByteVector &data);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Destroys the footer.
|
|
||||||
*/
|
|
||||||
virtual ~Footer();
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns the version number. (Note: This is the 1000 or 2000.)
|
|
||||||
*/
|
|
||||||
unsigned int version() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns true if a header is present in the tag.
|
|
||||||
*/
|
|
||||||
bool headerPresent() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns true if a footer is present in the tag.
|
|
||||||
*/
|
|
||||||
bool footerPresent() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns true this is actually the header.
|
|
||||||
*/
|
|
||||||
bool isHeader() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Sets whether the header should be rendered or not
|
|
||||||
*/
|
|
||||||
void setHeaderPresent(bool b) const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns the number of items in the tag.
|
|
||||||
*/
|
|
||||||
unsigned int itemCount() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Set the item count to \a s.
|
|
||||||
* \see itemCount()
|
|
||||||
*/
|
|
||||||
void setItemCount(unsigned int s);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns the tag size in bytes. This is the size of the frame content and footer.
|
|
||||||
* The size of the \e entire tag will be this plus the header size, if present.
|
|
||||||
*
|
|
||||||
* \see completeTagSize()
|
|
||||||
*/
|
|
||||||
unsigned int tagSize() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns the tag size, including if present, the header
|
|
||||||
* size.
|
|
||||||
*
|
|
||||||
* \see tagSize()
|
|
||||||
*/
|
|
||||||
unsigned int completeTagSize() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Set the tag size to \a s.
|
|
||||||
* \see tagSize()
|
|
||||||
*/
|
|
||||||
void setTagSize(unsigned int s);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns the size of the footer. Presently this is always 32 bytes.
|
|
||||||
*/
|
|
||||||
static unsigned int size();
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns the string used to identify an APE tag inside of a file.
|
|
||||||
* Presently this is always "APETAGEX".
|
|
||||||
*/
|
|
||||||
static ByteVector fileIdentifier();
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Sets the data that will be used as the footer. 32 bytes,
|
|
||||||
* starting from \a data will be used.
|
|
||||||
*/
|
|
||||||
void setData(const ByteVector &data);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Renders the footer back to binary format.
|
|
||||||
*/
|
|
||||||
ByteVector renderFooter() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Renders the header corresponding to the footer. If headerPresent is
|
|
||||||
* set to false, it returns an empty ByteVector.
|
|
||||||
*/
|
|
||||||
ByteVector renderHeader() const;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
/*!
|
|
||||||
* Called by setData() to parse the footer data. It makes this information
|
|
||||||
* available through the public API.
|
|
||||||
*/
|
|
||||||
void parse(const ByteVector &data);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Called by renderFooter and renderHeader
|
|
||||||
*/
|
|
||||||
ByteVector render(bool isHeader) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
Footer(const Footer &);
|
|
||||||
Footer &operator=(const Footer &);
|
|
||||||
|
|
||||||
class FooterPrivate;
|
|
||||||
FooterPrivate *d;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
301
3rdparty/taglib/ape/apeitem.cpp
vendored
301
3rdparty/taglib/ape/apeitem.cpp
vendored
@@ -1,301 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
copyright : (C) 2004 by Allan Sandfeld Jensen
|
|
||||||
email : kde@carewolf.com
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* This library is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU Lesser General Public License version *
|
|
||||||
* 2.1 as published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 *
|
|
||||||
* *
|
|
||||||
* Alternatively, this file is available under the Mozilla Public *
|
|
||||||
* License Version 1.1. You may obtain a copy of the License at *
|
|
||||||
* http://www.mozilla.org/MPL/ *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#include <tbytevectorlist.h>
|
|
||||||
#include <tdebug.h>
|
|
||||||
|
|
||||||
#include "apeitem.h"
|
|
||||||
|
|
||||||
using namespace TagLib;
|
|
||||||
using namespace APE;
|
|
||||||
|
|
||||||
class APE::Item::ItemPrivate
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ItemPrivate() :
|
|
||||||
type(Text),
|
|
||||||
readOnly(false) {}
|
|
||||||
|
|
||||||
Item::ItemTypes type;
|
|
||||||
String key;
|
|
||||||
ByteVector value;
|
|
||||||
StringList text;
|
|
||||||
bool readOnly;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// public members
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
APE::Item::Item() :
|
|
||||||
d(new ItemPrivate())
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
APE::Item::Item(const String &key, const String &value) :
|
|
||||||
d(new ItemPrivate())
|
|
||||||
{
|
|
||||||
d->key = key;
|
|
||||||
d->text.append(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
APE::Item::Item(const String &key, const StringList &values) :
|
|
||||||
d(new ItemPrivate())
|
|
||||||
{
|
|
||||||
d->key = key;
|
|
||||||
d->text = values;
|
|
||||||
}
|
|
||||||
|
|
||||||
APE::Item::Item(const String &key, const ByteVector &value, bool binary) :
|
|
||||||
d(new ItemPrivate())
|
|
||||||
{
|
|
||||||
d->key = key;
|
|
||||||
if(binary) {
|
|
||||||
d->type = Binary;
|
|
||||||
d->value = value;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
d->text.append(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
APE::Item::Item(const Item &item) :
|
|
||||||
d(new ItemPrivate(*item.d))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
APE::Item::~Item()
|
|
||||||
{
|
|
||||||
delete d;
|
|
||||||
}
|
|
||||||
|
|
||||||
Item &APE::Item::operator=(const Item &item)
|
|
||||||
{
|
|
||||||
Item(item).swap(*this);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void APE::Item::swap(Item &item)
|
|
||||||
{
|
|
||||||
using std::swap;
|
|
||||||
|
|
||||||
swap(d, item.d);
|
|
||||||
}
|
|
||||||
|
|
||||||
void APE::Item::setReadOnly(bool readOnly)
|
|
||||||
{
|
|
||||||
d->readOnly = readOnly;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool APE::Item::isReadOnly() const
|
|
||||||
{
|
|
||||||
return d->readOnly;
|
|
||||||
}
|
|
||||||
|
|
||||||
void APE::Item::setType(APE::Item::ItemTypes val)
|
|
||||||
{
|
|
||||||
d->type = val;
|
|
||||||
}
|
|
||||||
|
|
||||||
APE::Item::ItemTypes APE::Item::type() const
|
|
||||||
{
|
|
||||||
return d->type;
|
|
||||||
}
|
|
||||||
|
|
||||||
String APE::Item::key() const
|
|
||||||
{
|
|
||||||
return d->key;
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteVector APE::Item::binaryData() const
|
|
||||||
{
|
|
||||||
return d->value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void APE::Item::setBinaryData(const ByteVector &value)
|
|
||||||
{
|
|
||||||
d->type = Binary;
|
|
||||||
d->value = value;
|
|
||||||
d->text.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteVector APE::Item::value() const
|
|
||||||
{
|
|
||||||
// This seems incorrect as it won't be actually rendering the value to keep it
|
|
||||||
// up to date.
|
|
||||||
|
|
||||||
return d->value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void APE::Item::setKey(const String &key)
|
|
||||||
{
|
|
||||||
d->key = key;
|
|
||||||
}
|
|
||||||
|
|
||||||
void APE::Item::setValue(const String &value)
|
|
||||||
{
|
|
||||||
d->type = Text;
|
|
||||||
d->text = value;
|
|
||||||
d->value.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void APE::Item::setValues(const StringList &value)
|
|
||||||
{
|
|
||||||
d->type = Text;
|
|
||||||
d->text = value;
|
|
||||||
d->value.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void APE::Item::appendValue(const String &value)
|
|
||||||
{
|
|
||||||
d->type = Text;
|
|
||||||
d->text.append(value);
|
|
||||||
d->value.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void APE::Item::appendValues(const StringList &values)
|
|
||||||
{
|
|
||||||
d->type = Text;
|
|
||||||
d->text.append(values);
|
|
||||||
d->value.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
int APE::Item::size() const
|
|
||||||
{
|
|
||||||
int result = 8 + d->key.size() + 1;
|
|
||||||
switch(d->type) {
|
|
||||||
case Text:
|
|
||||||
if(!d->text.isEmpty()) {
|
|
||||||
StringList::ConstIterator it = d->text.begin();
|
|
||||||
|
|
||||||
result += it->data(String::UTF8).size();
|
|
||||||
it++;
|
|
||||||
for(; it != d->text.end(); ++it)
|
|
||||||
result += 1 + it->data(String::UTF8).size();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Binary:
|
|
||||||
case Locator:
|
|
||||||
result += d->value.size();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
StringList APE::Item::toStringList() const
|
|
||||||
{
|
|
||||||
return d->text;
|
|
||||||
}
|
|
||||||
|
|
||||||
StringList APE::Item::values() const
|
|
||||||
{
|
|
||||||
return d->text;
|
|
||||||
}
|
|
||||||
|
|
||||||
String APE::Item::toString() const
|
|
||||||
{
|
|
||||||
if(d->type == Text && !isEmpty())
|
|
||||||
return d->text.front();
|
|
||||||
else
|
|
||||||
return String();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool APE::Item::isEmpty() const
|
|
||||||
{
|
|
||||||
switch(d->type) {
|
|
||||||
case Text:
|
|
||||||
if(d->text.isEmpty())
|
|
||||||
return true;
|
|
||||||
if(d->text.size() == 1 && d->text.front().isEmpty())
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
case Binary:
|
|
||||||
case Locator:
|
|
||||||
return d->value.isEmpty();
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void APE::Item::parse(const ByteVector &data)
|
|
||||||
{
|
|
||||||
// 11 bytes is the minimum size for an APE item
|
|
||||||
|
|
||||||
if(data.size() < 11) {
|
|
||||||
debug("APE::Item::parse() -- no data in item");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const unsigned int valueLength = data.toUInt(0, false);
|
|
||||||
const unsigned int flags = data.toUInt(4, false);
|
|
||||||
|
|
||||||
// An item key can contain ASCII characters from 0x20 up to 0x7E, not UTF-8.
|
|
||||||
// We assume that the validity of the given key has been checked.
|
|
||||||
|
|
||||||
d->key = String(&data[8], String::Latin1);
|
|
||||||
|
|
||||||
const ByteVector value = data.mid(8 + d->key.size() + 1, valueLength);
|
|
||||||
|
|
||||||
setReadOnly(flags & 1);
|
|
||||||
setType(ItemTypes((flags >> 1) & 3));
|
|
||||||
|
|
||||||
if(Text == d->type)
|
|
||||||
d->text = StringList(ByteVectorList::split(value, '\0'), String::UTF8);
|
|
||||||
else
|
|
||||||
d->value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteVector APE::Item::render() const
|
|
||||||
{
|
|
||||||
ByteVector data;
|
|
||||||
unsigned int flags = ((d->readOnly) ? 1 : 0) | (d->type << 1);
|
|
||||||
ByteVector value;
|
|
||||||
|
|
||||||
if(isEmpty())
|
|
||||||
return data;
|
|
||||||
|
|
||||||
if(d->type == Text) {
|
|
||||||
StringList::ConstIterator it = d->text.begin();
|
|
||||||
|
|
||||||
value.append(it->data(String::UTF8));
|
|
||||||
it++;
|
|
||||||
for(; it != d->text.end(); ++it) {
|
|
||||||
value.append('\0');
|
|
||||||
value.append(it->data(String::UTF8));
|
|
||||||
}
|
|
||||||
d->value = value;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
value.append(d->value);
|
|
||||||
|
|
||||||
data.append(ByteVector::fromUInt(value.size(), false));
|
|
||||||
data.append(ByteVector::fromUInt(flags, false));
|
|
||||||
data.append(d->key.data(String::Latin1));
|
|
||||||
data.append(ByteVector('\0'));
|
|
||||||
data.append(value);
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
224
3rdparty/taglib/ape/apeitem.h
vendored
224
3rdparty/taglib/ape/apeitem.h
vendored
@@ -1,224 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
copyright : (C) 2004 by Allan Sandfeld Jensen
|
|
||||||
email : kde@carewolf.org
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* This library is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU Lesser General Public License version *
|
|
||||||
* 2.1 as published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 *
|
|
||||||
* *
|
|
||||||
* Alternatively, this file is available under the Mozilla Public *
|
|
||||||
* License Version 1.1. You may obtain a copy of the License at *
|
|
||||||
* http://www.mozilla.org/MPL/ *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#ifndef TAGLIB_APEITEM_H
|
|
||||||
#define TAGLIB_APEITEM_H
|
|
||||||
|
|
||||||
#include "tbytevector.h"
|
|
||||||
#include "tstring.h"
|
|
||||||
#include "tstringlist.h"
|
|
||||||
|
|
||||||
namespace TagLib {
|
|
||||||
|
|
||||||
namespace APE {
|
|
||||||
|
|
||||||
//! An implementation of APE-items
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* This class provides the features of items in the APEv2 standard.
|
|
||||||
*/
|
|
||||||
class TAGLIB_EXPORT Item
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/*!
|
|
||||||
* Enum of types an Item can have. The value of 3 is reserved.
|
|
||||||
*/
|
|
||||||
enum ItemTypes {
|
|
||||||
//! Item contains text information coded in UTF-8
|
|
||||||
Text = 0,
|
|
||||||
//! Item contains binary information
|
|
||||||
Binary = 1,
|
|
||||||
//! Item is a locator of external stored information
|
|
||||||
Locator = 2
|
|
||||||
};
|
|
||||||
/*!
|
|
||||||
* Constructs an empty item.
|
|
||||||
*/
|
|
||||||
Item();
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Constructs a text item with \a key and \a value.
|
|
||||||
*/
|
|
||||||
// BIC: Remove this, StringList has a constructor from a single string
|
|
||||||
Item(const String &key, const String &value);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Constructs a text item with \a key and \a values.
|
|
||||||
*/
|
|
||||||
Item(const String &key, const StringList &values);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Constructs an item with \a key and \a value.
|
|
||||||
* If \a binary is true a Binary item will be created, otherwise \a value will be interpreted as text
|
|
||||||
*/
|
|
||||||
Item(const String &key, const ByteVector &value, bool binary);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Construct an item as a copy of \a item.
|
|
||||||
*/
|
|
||||||
Item(const Item &item);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Destroys the item.
|
|
||||||
*/
|
|
||||||
virtual ~Item();
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Copies the contents of \a item into this item.
|
|
||||||
*/
|
|
||||||
Item &operator=(const Item &item);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Exchanges the content of this item by the content of \a item.
|
|
||||||
*/
|
|
||||||
void swap(Item &item);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns the key.
|
|
||||||
*/
|
|
||||||
String key() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns the binary value.
|
|
||||||
* If the item type is not \a Binary, always returns an empty ByteVector.
|
|
||||||
*/
|
|
||||||
ByteVector binaryData() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Set the binary value to \a value
|
|
||||||
* The item's type will also be set to \a Binary
|
|
||||||
*/
|
|
||||||
void setBinaryData(const ByteVector &value);
|
|
||||||
|
|
||||||
#ifndef DO_NOT_DOCUMENT
|
|
||||||
/* Remove in next binary incompatible release */
|
|
||||||
ByteVector value() const;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Sets the key for the item to \a key.
|
|
||||||
*/
|
|
||||||
void setKey(const String &key);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Sets the text value of the item to \a value and clears any previous contents.
|
|
||||||
*
|
|
||||||
* \see toString()
|
|
||||||
*/
|
|
||||||
void setValue(const String &value);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Sets the text value of the item to the list of values in \a value and clears
|
|
||||||
* any previous contents.
|
|
||||||
*
|
|
||||||
* \see toStringList()
|
|
||||||
*/
|
|
||||||
void setValues(const StringList &values);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Appends \a value to create (or extend) the current list of text values.
|
|
||||||
*
|
|
||||||
* \see toString()
|
|
||||||
*/
|
|
||||||
void appendValue(const String &value);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Appends \a values to extend the current list of text values.
|
|
||||||
*
|
|
||||||
* \see toStringList()
|
|
||||||
*/
|
|
||||||
void appendValues(const StringList &values);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns the size of the full item.
|
|
||||||
*/
|
|
||||||
int size() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns the value as a single string. In case of multiple strings,
|
|
||||||
* the first is returned. If the data type is not \a Text, always returns
|
|
||||||
* an empty String.
|
|
||||||
*/
|
|
||||||
String toString() const;
|
|
||||||
|
|
||||||
#ifndef DO_NOT_DOCUMENT
|
|
||||||
/* Remove in next binary incompatible release */
|
|
||||||
StringList toStringList() const;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns the list of text values. If the data type is not \a Text, always
|
|
||||||
* returns an empty StringList.
|
|
||||||
*/
|
|
||||||
StringList values() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Render the item to a ByteVector.
|
|
||||||
*/
|
|
||||||
ByteVector render() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Parse the item from the ByteVector \a data.
|
|
||||||
*/
|
|
||||||
void parse(const ByteVector& data);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Set the item to read-only.
|
|
||||||
*/
|
|
||||||
void setReadOnly(bool readOnly);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Return true if the item is read-only.
|
|
||||||
*/
|
|
||||||
bool isReadOnly() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Sets the type of the item to \a type.
|
|
||||||
*
|
|
||||||
* \see ItemTypes
|
|
||||||
*/
|
|
||||||
void setType(ItemTypes type);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns the type of the item.
|
|
||||||
*/
|
|
||||||
ItemTypes type() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns if the item has any real content.
|
|
||||||
*/
|
|
||||||
bool isEmpty() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
class ItemPrivate;
|
|
||||||
ItemPrivate *d;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
252
3rdparty/taglib/ape/apeproperties.cpp
vendored
252
3rdparty/taglib/ape/apeproperties.cpp
vendored
@@ -1,252 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
copyright : (C) 2010 by Alex Novichkov
|
|
||||||
email : novichko@atnet.ru
|
|
||||||
|
|
||||||
copyright : (C) 2006 by Lukáš Lalinský
|
|
||||||
email : lalinsky@gmail.com
|
|
||||||
(original WavPack implementation)
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* This library is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU Lesser General Public License version *
|
|
||||||
* 2.1 as published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 *
|
|
||||||
* *
|
|
||||||
* Alternatively, this file is available under the Mozilla Public *
|
|
||||||
* License Version 1.1. You may obtain a copy of the License at *
|
|
||||||
* http://www.mozilla.org/MPL/ *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#include <tstring.h>
|
|
||||||
#include <tdebug.h>
|
|
||||||
#include <bitset>
|
|
||||||
#include "id3v2tag.h"
|
|
||||||
#include "apeproperties.h"
|
|
||||||
#include "apefile.h"
|
|
||||||
#include "apetag.h"
|
|
||||||
#include "apefooter.h"
|
|
||||||
|
|
||||||
using namespace TagLib;
|
|
||||||
|
|
||||||
class APE::Properties::PropertiesPrivate
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
PropertiesPrivate() :
|
|
||||||
length(0),
|
|
||||||
bitrate(0),
|
|
||||||
sampleRate(0),
|
|
||||||
channels(0),
|
|
||||||
version(0),
|
|
||||||
bitsPerSample(0),
|
|
||||||
sampleFrames(0) {}
|
|
||||||
|
|
||||||
int length;
|
|
||||||
int bitrate;
|
|
||||||
int sampleRate;
|
|
||||||
int channels;
|
|
||||||
int version;
|
|
||||||
int bitsPerSample;
|
|
||||||
unsigned int sampleFrames;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// public members
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
APE::Properties::Properties(File *, ReadStyle style) :
|
|
||||||
AudioProperties(style),
|
|
||||||
d(new PropertiesPrivate())
|
|
||||||
{
|
|
||||||
debug("APE::Properties::Properties() -- This constructor is no longer used.");
|
|
||||||
}
|
|
||||||
|
|
||||||
APE::Properties::Properties(File *file, long streamLength, ReadStyle style) :
|
|
||||||
AudioProperties(style),
|
|
||||||
d(new PropertiesPrivate())
|
|
||||||
{
|
|
||||||
read(file, streamLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
APE::Properties::~Properties()
|
|
||||||
{
|
|
||||||
delete d;
|
|
||||||
}
|
|
||||||
|
|
||||||
int APE::Properties::length() const
|
|
||||||
{
|
|
||||||
return lengthInSeconds();
|
|
||||||
}
|
|
||||||
|
|
||||||
int APE::Properties::lengthInSeconds() const
|
|
||||||
{
|
|
||||||
return d->length / 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
int APE::Properties::lengthInMilliseconds() const
|
|
||||||
{
|
|
||||||
return d->length;
|
|
||||||
}
|
|
||||||
|
|
||||||
int APE::Properties::bitrate() const
|
|
||||||
{
|
|
||||||
return d->bitrate;
|
|
||||||
}
|
|
||||||
|
|
||||||
int APE::Properties::sampleRate() const
|
|
||||||
{
|
|
||||||
return d->sampleRate;
|
|
||||||
}
|
|
||||||
|
|
||||||
int APE::Properties::channels() const
|
|
||||||
{
|
|
||||||
return d->channels;
|
|
||||||
}
|
|
||||||
|
|
||||||
int APE::Properties::version() const
|
|
||||||
{
|
|
||||||
return d->version;
|
|
||||||
}
|
|
||||||
|
|
||||||
int APE::Properties::bitsPerSample() const
|
|
||||||
{
|
|
||||||
return d->bitsPerSample;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int APE::Properties::sampleFrames() const
|
|
||||||
{
|
|
||||||
return d->sampleFrames;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// private members
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
int headerVersion(const ByteVector &header)
|
|
||||||
{
|
|
||||||
if(header.size() < 6 || !header.startsWith("MAC "))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return header.toUShort(4, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void APE::Properties::read(File *file, long streamLength)
|
|
||||||
{
|
|
||||||
// First, we assume that the file pointer is set at the first descriptor.
|
|
||||||
long offset = file->tell();
|
|
||||||
int version = headerVersion(file->readBlock(6));
|
|
||||||
|
|
||||||
// Next, we look for the descriptor.
|
|
||||||
if(version < 0) {
|
|
||||||
offset = file->find("MAC ", offset);
|
|
||||||
file->seek(offset);
|
|
||||||
version = headerVersion(file->readBlock(6));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(version < 0) {
|
|
||||||
debug("APE::Properties::read() -- APE descriptor not found");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
d->version = version;
|
|
||||||
|
|
||||||
if(d->version >= 3980)
|
|
||||||
analyzeCurrent(file);
|
|
||||||
else
|
|
||||||
analyzeOld(file);
|
|
||||||
|
|
||||||
if(d->sampleFrames > 0 && d->sampleRate > 0) {
|
|
||||||
const double length = d->sampleFrames * 1000.0 / d->sampleRate;
|
|
||||||
d->length = static_cast<int>(length + 0.5);
|
|
||||||
d->bitrate = static_cast<int>(streamLength * 8.0 / length + 0.5);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void APE::Properties::analyzeCurrent(File *file)
|
|
||||||
{
|
|
||||||
// Read the descriptor
|
|
||||||
file->seek(2, File::Current);
|
|
||||||
const ByteVector descriptor = file->readBlock(44);
|
|
||||||
if(descriptor.size() < 44) {
|
|
||||||
debug("APE::Properties::analyzeCurrent() -- descriptor is too short.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const unsigned int descriptorBytes = descriptor.toUInt(0, false);
|
|
||||||
|
|
||||||
if((descriptorBytes - 52) > 0)
|
|
||||||
file->seek(descriptorBytes - 52, File::Current);
|
|
||||||
|
|
||||||
// Read the header
|
|
||||||
const ByteVector header = file->readBlock(24);
|
|
||||||
if(header.size() < 24) {
|
|
||||||
debug("APE::Properties::analyzeCurrent() -- MAC header is too short.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the APE info
|
|
||||||
d->channels = header.toShort(18, false);
|
|
||||||
d->sampleRate = header.toUInt(20, false);
|
|
||||||
d->bitsPerSample = header.toShort(16, false);
|
|
||||||
|
|
||||||
const unsigned int totalFrames = header.toUInt(12, false);
|
|
||||||
if(totalFrames == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const unsigned int blocksPerFrame = header.toUInt(4, false);
|
|
||||||
const unsigned int finalFrameBlocks = header.toUInt(8, false);
|
|
||||||
d->sampleFrames = (totalFrames - 1) * blocksPerFrame + finalFrameBlocks;
|
|
||||||
}
|
|
||||||
|
|
||||||
void APE::Properties::analyzeOld(File *file)
|
|
||||||
{
|
|
||||||
const ByteVector header = file->readBlock(26);
|
|
||||||
if(header.size() < 26) {
|
|
||||||
debug("APE::Properties::analyzeOld() -- MAC header is too short.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const unsigned int totalFrames = header.toUInt(18, false);
|
|
||||||
|
|
||||||
// Fail on 0 length APE files (catches non-finalized APE files)
|
|
||||||
if(totalFrames == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const short compressionLevel = header.toShort(0, false);
|
|
||||||
unsigned int blocksPerFrame;
|
|
||||||
if(d->version >= 3950)
|
|
||||||
blocksPerFrame = 73728 * 4;
|
|
||||||
else if(d->version >= 3900 || (d->version >= 3800 && compressionLevel == 4000))
|
|
||||||
blocksPerFrame = 73728;
|
|
||||||
else
|
|
||||||
blocksPerFrame = 9216;
|
|
||||||
|
|
||||||
// Get the APE info
|
|
||||||
d->channels = header.toShort(4, false);
|
|
||||||
d->sampleRate = header.toUInt(6, false);
|
|
||||||
|
|
||||||
const unsigned int finalFrameBlocks = header.toUInt(22, false);
|
|
||||||
d->sampleFrames = (totalFrames - 1) * blocksPerFrame + finalFrameBlocks;
|
|
||||||
|
|
||||||
// Get the bit depth from the RIFF-fmt chunk.
|
|
||||||
file->seek(16, File::Current);
|
|
||||||
const ByteVector fmt = file->readBlock(28);
|
|
||||||
if(fmt.size() < 28 || !fmt.startsWith("WAVEfmt ")) {
|
|
||||||
debug("APE::Properties::analyzeOld() -- fmt header is too short.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
d->bitsPerSample = fmt.toShort(26, false);
|
|
||||||
}
|
|
||||||
143
3rdparty/taglib/ape/apeproperties.h
vendored
143
3rdparty/taglib/ape/apeproperties.h
vendored
@@ -1,143 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
copyright : (C) 2010 by Alex Novichkov
|
|
||||||
email : novichko@atnet.ru
|
|
||||||
|
|
||||||
copyright : (C) 2006 by Lukáš Lalinský
|
|
||||||
email : lalinsky@gmail.com
|
|
||||||
(original WavPack implementation)
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* This library is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU Lesser General Public License version *
|
|
||||||
* 2.1 as published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 *
|
|
||||||
* *
|
|
||||||
* Alternatively, this file is available under the Mozilla Public *
|
|
||||||
* License Version 1.1. You may obtain a copy of the License at *
|
|
||||||
* http://www.mozilla.org/MPL/ *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#ifndef TAGLIB_APEPROPERTIES_H
|
|
||||||
#define TAGLIB_APEPROPERTIES_H
|
|
||||||
|
|
||||||
#include "taglib_export.h"
|
|
||||||
#include "audioproperties.h"
|
|
||||||
|
|
||||||
namespace TagLib {
|
|
||||||
|
|
||||||
namespace APE {
|
|
||||||
|
|
||||||
class File;
|
|
||||||
|
|
||||||
//! An implementation of audio property reading for APE
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* This reads the data from an APE stream found in the AudioProperties
|
|
||||||
* API.
|
|
||||||
*/
|
|
||||||
|
|
||||||
class TAGLIB_EXPORT Properties : public AudioProperties
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/*!
|
|
||||||
* Create an instance of APE::Properties with the data read from the
|
|
||||||
* APE::File \a file.
|
|
||||||
*
|
|
||||||
* \deprecated
|
|
||||||
*/
|
|
||||||
Properties(File *file, ReadStyle style = Average);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Create an instance of APE::Properties with the data read from the
|
|
||||||
* APE::File \a file.
|
|
||||||
*/
|
|
||||||
Properties(File *file, long streamLength, ReadStyle style = Average);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Destroys this APE::Properties instance.
|
|
||||||
*/
|
|
||||||
virtual ~Properties();
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns the length of the file in seconds. The length is rounded down to
|
|
||||||
* the nearest whole second.
|
|
||||||
*
|
|
||||||
* \note This method is just an alias of lengthInSeconds().
|
|
||||||
*
|
|
||||||
* \deprecated
|
|
||||||
*/
|
|
||||||
virtual int length() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns the length of the file in seconds. The length is rounded down to
|
|
||||||
* the nearest whole second.
|
|
||||||
*
|
|
||||||
* \see lengthInMilliseconds()
|
|
||||||
*/
|
|
||||||
// BIC: make virtual
|
|
||||||
int lengthInSeconds() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns the length of the file in milliseconds.
|
|
||||||
*
|
|
||||||
* \see lengthInSeconds()
|
|
||||||
*/
|
|
||||||
// BIC: make virtual
|
|
||||||
int lengthInMilliseconds() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns the average bit rate of the file in kb/s.
|
|
||||||
*/
|
|
||||||
virtual int bitrate() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns the sample rate in Hz.
|
|
||||||
*/
|
|
||||||
virtual int sampleRate() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns the number of audio channels.
|
|
||||||
*/
|
|
||||||
virtual int channels() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns the number of bits per audio sample.
|
|
||||||
*/
|
|
||||||
int bitsPerSample() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns the total number of audio samples in file.
|
|
||||||
*/
|
|
||||||
unsigned int sampleFrames() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns APE version.
|
|
||||||
*/
|
|
||||||
int version() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
Properties(const Properties &);
|
|
||||||
Properties &operator=(const Properties &);
|
|
||||||
|
|
||||||
void read(File *file, long streamLength);
|
|
||||||
|
|
||||||
void analyzeCurrent(File *file);
|
|
||||||
void analyzeOld(File *file);
|
|
||||||
|
|
||||||
class PropertiesPrivate;
|
|
||||||
PropertiesPrivate *d;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
437
3rdparty/taglib/ape/apetag.cpp
vendored
437
3rdparty/taglib/ape/apetag.cpp
vendored
@@ -1,437 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
copyright : (C) 2004 by Allan Sandfeld Jensen
|
|
||||||
email : kde@carewolf.com
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* This library is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU Lesser General Public License version *
|
|
||||||
* 2.1 as published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 *
|
|
||||||
* *
|
|
||||||
* Alternatively, this file is available under the Mozilla Public *
|
|
||||||
* License Version 1.1. You may obtain a copy of the License at *
|
|
||||||
* http://www.mozilla.org/MPL/ *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#if defined(__SUNPRO_CC) && (__SUNPRO_CC < 0x5130)
|
|
||||||
// Sun Studio finds multiple specializations of Map because
|
|
||||||
// it considers specializations with and without class types
|
|
||||||
// to be different; this define forces Map to use only the
|
|
||||||
// specialization with the class keyword.
|
|
||||||
#define WANT_CLASS_INSTANTIATION_OF_MAP (1)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <tfile.h>
|
|
||||||
#include <tstring.h>
|
|
||||||
#include <tmap.h>
|
|
||||||
#include <tpropertymap.h>
|
|
||||||
#include <tdebug.h>
|
|
||||||
#include <tutils.h>
|
|
||||||
|
|
||||||
#include "apetag.h"
|
|
||||||
#include "apefooter.h"
|
|
||||||
#include "apeitem.h"
|
|
||||||
|
|
||||||
using namespace TagLib;
|
|
||||||
using namespace APE;
|
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
const unsigned int MinKeyLength = 2;
|
|
||||||
const unsigned int MaxKeyLength = 255;
|
|
||||||
|
|
||||||
bool isKeyValid(const ByteVector &key)
|
|
||||||
{
|
|
||||||
const char *invalidKeys[] = { "ID3", "TAG", "OGGS", "MP+", 0 };
|
|
||||||
|
|
||||||
// only allow printable ASCII including space (32..126)
|
|
||||||
|
|
||||||
for(ByteVector::ConstIterator it = key.begin(); it != key.end(); ++it) {
|
|
||||||
const int c = static_cast<unsigned char>(*it);
|
|
||||||
if(c < 32 || c > 126)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const String upperKey = String(key).upper();
|
|
||||||
for(size_t i = 0; invalidKeys[i] != 0; ++i) {
|
|
||||||
if(upperKey == invalidKeys[i])
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class APE::Tag::TagPrivate
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
TagPrivate() :
|
|
||||||
file(0),
|
|
||||||
footerLocation(0) {}
|
|
||||||
|
|
||||||
File *file;
|
|
||||||
long footerLocation;
|
|
||||||
|
|
||||||
Footer footer;
|
|
||||||
ItemListMap itemListMap;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// public methods
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
APE::Tag::Tag() :
|
|
||||||
TagLib::Tag(),
|
|
||||||
d(new TagPrivate())
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
APE::Tag::Tag(TagLib::File *file, long footerLocation) :
|
|
||||||
TagLib::Tag(),
|
|
||||||
d(new TagPrivate())
|
|
||||||
{
|
|
||||||
d->file = file;
|
|
||||||
d->footerLocation = footerLocation;
|
|
||||||
|
|
||||||
read();
|
|
||||||
}
|
|
||||||
|
|
||||||
APE::Tag::~Tag()
|
|
||||||
{
|
|
||||||
delete d;
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteVector APE::Tag::fileIdentifier()
|
|
||||||
{
|
|
||||||
return ByteVector::fromCString("APETAGEX");
|
|
||||||
}
|
|
||||||
|
|
||||||
String APE::Tag::title() const
|
|
||||||
{
|
|
||||||
if(d->itemListMap["TITLE"].isEmpty())
|
|
||||||
return String();
|
|
||||||
return d->itemListMap["TITLE"].values().toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
String APE::Tag::artist() const
|
|
||||||
{
|
|
||||||
if(d->itemListMap["ARTIST"].isEmpty())
|
|
||||||
return String();
|
|
||||||
return d->itemListMap["ARTIST"].values().toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
String APE::Tag::album() const
|
|
||||||
{
|
|
||||||
if(d->itemListMap["ALBUM"].isEmpty())
|
|
||||||
return String();
|
|
||||||
return d->itemListMap["ALBUM"].values().toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
String APE::Tag::comment() const
|
|
||||||
{
|
|
||||||
if(d->itemListMap["COMMENT"].isEmpty())
|
|
||||||
return String();
|
|
||||||
return d->itemListMap["COMMENT"].values().toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
String APE::Tag::genre() const
|
|
||||||
{
|
|
||||||
if(d->itemListMap["GENRE"].isEmpty())
|
|
||||||
return String();
|
|
||||||
return d->itemListMap["GENRE"].values().toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int APE::Tag::year() const
|
|
||||||
{
|
|
||||||
if(d->itemListMap["YEAR"].isEmpty())
|
|
||||||
return 0;
|
|
||||||
return d->itemListMap["YEAR"].toString().toInt();
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int APE::Tag::track() const
|
|
||||||
{
|
|
||||||
if(d->itemListMap["TRACK"].isEmpty())
|
|
||||||
return 0;
|
|
||||||
return d->itemListMap["TRACK"].toString().toInt();
|
|
||||||
}
|
|
||||||
|
|
||||||
void APE::Tag::setTitle(const String &s)
|
|
||||||
{
|
|
||||||
addValue("TITLE", s, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void APE::Tag::setArtist(const String &s)
|
|
||||||
{
|
|
||||||
addValue("ARTIST", s, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void APE::Tag::setAlbum(const String &s)
|
|
||||||
{
|
|
||||||
addValue("ALBUM", s, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void APE::Tag::setComment(const String &s)
|
|
||||||
{
|
|
||||||
addValue("COMMENT", s, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void APE::Tag::setGenre(const String &s)
|
|
||||||
{
|
|
||||||
addValue("GENRE", s, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void APE::Tag::setYear(unsigned int i)
|
|
||||||
{
|
|
||||||
if(i == 0)
|
|
||||||
removeItem("YEAR");
|
|
||||||
else
|
|
||||||
addValue("YEAR", String::number(i), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void APE::Tag::setTrack(unsigned int i)
|
|
||||||
{
|
|
||||||
if(i == 0)
|
|
||||||
removeItem("TRACK");
|
|
||||||
else
|
|
||||||
addValue("TRACK", String::number(i), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
// conversions of tag keys between what we use in PropertyMap and what's usual
|
|
||||||
// for APE tags
|
|
||||||
// usual, APE
|
|
||||||
const char *keyConversions[][2] = {{"TRACKNUMBER", "TRACK" },
|
|
||||||
{"DATE", "YEAR" },
|
|
||||||
{"ALBUMARTIST", "ALBUM ARTIST"},
|
|
||||||
{"DISCNUMBER", "DISC" },
|
|
||||||
{"REMIXER", "MIXARTIST" }};
|
|
||||||
const size_t keyConversionsSize = sizeof(keyConversions) / sizeof(keyConversions[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
PropertyMap APE::Tag::properties() const
|
|
||||||
{
|
|
||||||
PropertyMap properties;
|
|
||||||
ItemListMap::ConstIterator it = itemListMap().begin();
|
|
||||||
for(; it != itemListMap().end(); ++it) {
|
|
||||||
String tagName = it->first.upper();
|
|
||||||
// if the item is Binary or Locator, or if the key is an invalid string,
|
|
||||||
// add to unsupportedData
|
|
||||||
if(it->second.type() != Item::Text || tagName.isEmpty()) {
|
|
||||||
properties.unsupportedData().append(it->first);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Some tags need to be handled specially
|
|
||||||
for(size_t i = 0; i < keyConversionsSize; ++i) {
|
|
||||||
if(tagName == keyConversions[i][1])
|
|
||||||
tagName = keyConversions[i][0];
|
|
||||||
}
|
|
||||||
properties[tagName].append(it->second.toStringList());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return properties;
|
|
||||||
}
|
|
||||||
|
|
||||||
void APE::Tag::removeUnsupportedProperties(const StringList &properties)
|
|
||||||
{
|
|
||||||
StringList::ConstIterator it = properties.begin();
|
|
||||||
for(; it != properties.end(); ++it)
|
|
||||||
removeItem(*it);
|
|
||||||
}
|
|
||||||
|
|
||||||
PropertyMap APE::Tag::setProperties(const PropertyMap &origProps)
|
|
||||||
{
|
|
||||||
PropertyMap properties(origProps); // make a local copy that can be modified
|
|
||||||
|
|
||||||
// see comment in properties()
|
|
||||||
for(size_t i = 0; i < keyConversionsSize; ++i)
|
|
||||||
if(properties.contains(keyConversions[i][0])) {
|
|
||||||
properties.insert(keyConversions[i][1], properties[keyConversions[i][0]]);
|
|
||||||
properties.erase(keyConversions[i][0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// first check if tags need to be removed completely
|
|
||||||
StringList toRemove;
|
|
||||||
ItemListMap::ConstIterator remIt = itemListMap().begin();
|
|
||||||
for(; remIt != itemListMap().end(); ++remIt) {
|
|
||||||
String key = remIt->first.upper();
|
|
||||||
// only remove if a) key is valid, b) type is text, c) key not contained in new properties
|
|
||||||
if(!key.isEmpty() && remIt->second.type() == APE::Item::Text && !properties.contains(key))
|
|
||||||
toRemove.append(remIt->first);
|
|
||||||
}
|
|
||||||
|
|
||||||
for(StringList::ConstIterator removeIt = toRemove.begin(); removeIt != toRemove.end(); removeIt++)
|
|
||||||
removeItem(*removeIt);
|
|
||||||
|
|
||||||
// now sync in the "forward direction"
|
|
||||||
PropertyMap::ConstIterator it = properties.begin();
|
|
||||||
PropertyMap invalid;
|
|
||||||
for(; it != properties.end(); ++it) {
|
|
||||||
const String &tagName = it->first;
|
|
||||||
if(!checkKey(tagName))
|
|
||||||
invalid.insert(it->first, it->second);
|
|
||||||
else if(!(itemListMap().contains(tagName)) || !(itemListMap()[tagName].values() == it->second)) {
|
|
||||||
if(it->second.isEmpty())
|
|
||||||
removeItem(tagName);
|
|
||||||
else {
|
|
||||||
StringList::ConstIterator valueIt = it->second.begin();
|
|
||||||
addValue(tagName, *valueIt, true);
|
|
||||||
++valueIt;
|
|
||||||
for(; valueIt != it->second.end(); ++valueIt)
|
|
||||||
addValue(tagName, *valueIt, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return invalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool APE::Tag::checkKey(const String &key)
|
|
||||||
{
|
|
||||||
if(key.size() < MinKeyLength || key.size() > MaxKeyLength)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return isKeyValid(key.data(String::UTF8));
|
|
||||||
}
|
|
||||||
|
|
||||||
APE::Footer *APE::Tag::footer() const
|
|
||||||
{
|
|
||||||
return &d->footer;
|
|
||||||
}
|
|
||||||
|
|
||||||
const APE::ItemListMap& APE::Tag::itemListMap() const
|
|
||||||
{
|
|
||||||
return d->itemListMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
void APE::Tag::removeItem(const String &key)
|
|
||||||
{
|
|
||||||
d->itemListMap.erase(key.upper());
|
|
||||||
}
|
|
||||||
|
|
||||||
void APE::Tag::addValue(const String &key, const String &value, bool replace)
|
|
||||||
{
|
|
||||||
if(replace)
|
|
||||||
removeItem(key);
|
|
||||||
|
|
||||||
if(value.isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Text items may contain more than one value.
|
|
||||||
// Binary or locator items may have only one value, hence always replaced.
|
|
||||||
|
|
||||||
ItemListMap::Iterator it = d->itemListMap.find(key.upper());
|
|
||||||
|
|
||||||
if(it != d->itemListMap.end() && it->second.type() == Item::Text)
|
|
||||||
it->second.appendValue(value);
|
|
||||||
else
|
|
||||||
setItem(key, Item(key, value));
|
|
||||||
}
|
|
||||||
|
|
||||||
void APE::Tag::setData(const String &key, const ByteVector &value)
|
|
||||||
{
|
|
||||||
removeItem(key);
|
|
||||||
|
|
||||||
if(value.isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
setItem(key, Item(key, value, true));
|
|
||||||
}
|
|
||||||
|
|
||||||
void APE::Tag::setItem(const String &key, const Item &item)
|
|
||||||
{
|
|
||||||
if(!checkKey(key)) {
|
|
||||||
debug("APE::Tag::setItem() - Couldn't set an item due to an invalid key.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
d->itemListMap[key.upper()] = item;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool APE::Tag::isEmpty() const
|
|
||||||
{
|
|
||||||
return d->itemListMap.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// protected methods
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void APE::Tag::read()
|
|
||||||
{
|
|
||||||
if(d->file && d->file->isValid()) {
|
|
||||||
|
|
||||||
d->file->seek(d->footerLocation);
|
|
||||||
d->footer.setData(d->file->readBlock(Footer::size()));
|
|
||||||
|
|
||||||
if(d->footer.tagSize() <= Footer::size() ||
|
|
||||||
d->footer.tagSize() > static_cast<unsigned long>(d->file->length()))
|
|
||||||
return;
|
|
||||||
|
|
||||||
d->file->seek(d->footerLocation + Footer::size() - d->footer.tagSize());
|
|
||||||
parse(d->file->readBlock(d->footer.tagSize() - Footer::size()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteVector APE::Tag::render() const
|
|
||||||
{
|
|
||||||
ByteVector data;
|
|
||||||
unsigned int itemCount = 0;
|
|
||||||
|
|
||||||
for(ItemListMap::ConstIterator it = d->itemListMap.begin(); it != d->itemListMap.end(); ++it) {
|
|
||||||
data.append(it->second.render());
|
|
||||||
itemCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
d->footer.setItemCount(itemCount);
|
|
||||||
d->footer.setTagSize(data.size() + Footer::size());
|
|
||||||
d->footer.setHeaderPresent(true);
|
|
||||||
|
|
||||||
return d->footer.renderHeader() + data + d->footer.renderFooter();
|
|
||||||
}
|
|
||||||
|
|
||||||
void APE::Tag::parse(const ByteVector &data)
|
|
||||||
{
|
|
||||||
// 11 bytes is the minimum size for an APE item
|
|
||||||
|
|
||||||
if(data.size() < 11)
|
|
||||||
return;
|
|
||||||
|
|
||||||
unsigned int pos = 0;
|
|
||||||
|
|
||||||
for(unsigned int i = 0; i < d->footer.itemCount() && pos <= data.size() - 11; i++) {
|
|
||||||
|
|
||||||
const int nullPos = data.find('\0', pos + 8);
|
|
||||||
if(nullPos < 0) {
|
|
||||||
debug("APE::Tag::parse() - Couldn't find a key/value separator. Stopped parsing.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const unsigned int keyLength = nullPos - pos - 8;
|
|
||||||
const unsigned int valLegnth = data.toUInt(pos, false);
|
|
||||||
|
|
||||||
if(keyLength >= MinKeyLength
|
|
||||||
&& keyLength <= MaxKeyLength
|
|
||||||
&& isKeyValid(data.mid(pos + 8, keyLength)))
|
|
||||||
{
|
|
||||||
APE::Item item;
|
|
||||||
item.parse(data.mid(pos));
|
|
||||||
|
|
||||||
d->itemListMap.insert(item.key().upper(), item);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
debug("APE::Tag::parse() - Skipped an item due to an invalid key.");
|
|
||||||
}
|
|
||||||
|
|
||||||
pos += keyLength + valLegnth + 9;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
208
3rdparty/taglib/ape/apetag.h
vendored
208
3rdparty/taglib/ape/apetag.h
vendored
@@ -1,208 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
copyright : (C) 2004 by Allan Sandfeld Jensen
|
|
||||||
email : kde@carewolf.org
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* This library is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU Lesser General Public License version *
|
|
||||||
* 2.1 as published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 *
|
|
||||||
* *
|
|
||||||
* Alternatively, this file is available under the Mozilla Public *
|
|
||||||
* License Version 1.1. You may obtain a copy of the License at *
|
|
||||||
* http://www.mozilla.org/MPL/ *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#ifndef TAGLIB_APETAG_H
|
|
||||||
#define TAGLIB_APETAG_H
|
|
||||||
|
|
||||||
#include "tag.h"
|
|
||||||
#include "tbytevector.h"
|
|
||||||
#include "tmap.h"
|
|
||||||
#include "tstring.h"
|
|
||||||
#include "taglib_export.h"
|
|
||||||
|
|
||||||
#include "apeitem.h"
|
|
||||||
|
|
||||||
namespace TagLib {
|
|
||||||
|
|
||||||
class File;
|
|
||||||
|
|
||||||
//! An implementation of the APE tagging format
|
|
||||||
|
|
||||||
namespace APE {
|
|
||||||
|
|
||||||
class Footer;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* A mapping between a list of item names, or keys, and the associated item.
|
|
||||||
*
|
|
||||||
* \see APE::Tag::itemListMap()
|
|
||||||
*/
|
|
||||||
typedef Map<const String, Item> ItemListMap;
|
|
||||||
|
|
||||||
|
|
||||||
//! An APE tag implementation
|
|
||||||
|
|
||||||
class TAGLIB_EXPORT Tag : public TagLib::Tag
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/*!
|
|
||||||
* Create an APE tag with default values.
|
|
||||||
*/
|
|
||||||
Tag();
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Create an APE tag and parse the data in \a file with APE footer at
|
|
||||||
* \a tagOffset.
|
|
||||||
*/
|
|
||||||
Tag(TagLib::File *file, long footerLocation);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Destroys this Tag instance.
|
|
||||||
*/
|
|
||||||
virtual ~Tag();
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Renders the in memory values to a ByteVector suitable for writing to
|
|
||||||
* the file.
|
|
||||||
*/
|
|
||||||
ByteVector render() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns the string "APETAGEX" suitable for usage in locating the tag in a
|
|
||||||
* file.
|
|
||||||
*/
|
|
||||||
static ByteVector fileIdentifier();
|
|
||||||
|
|
||||||
// Reimplementations.
|
|
||||||
|
|
||||||
virtual String title() const;
|
|
||||||
virtual String artist() const;
|
|
||||||
virtual String album() const;
|
|
||||||
virtual String comment() const;
|
|
||||||
virtual String genre() const;
|
|
||||||
virtual unsigned int year() const;
|
|
||||||
virtual unsigned int track() const;
|
|
||||||
|
|
||||||
virtual void setTitle(const String &s);
|
|
||||||
virtual void setArtist(const String &s);
|
|
||||||
virtual void setAlbum(const String &s);
|
|
||||||
virtual void setComment(const String &s);
|
|
||||||
virtual void setGenre(const String &s);
|
|
||||||
virtual void setYear(unsigned int i);
|
|
||||||
virtual void setTrack(unsigned int i);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Implements the unified tag dictionary interface -- export function.
|
|
||||||
* APE tags are perfectly compatible with the dictionary interface because they
|
|
||||||
* support both arbitrary tag names and multiple values. Currently only
|
|
||||||
* APE items of type *Text* are handled by the dictionary interface; all *Binary*
|
|
||||||
* and *Locator* items will be put into the unsupportedData list and can be
|
|
||||||
* deleted on request using removeUnsupportedProperties(). The same happens
|
|
||||||
* to Text items if their key is invalid for PropertyMap (which should actually
|
|
||||||
* never happen).
|
|
||||||
*
|
|
||||||
* The only conversion done by this export function is to rename the APE tags
|
|
||||||
* TRACK to TRACKNUMBER, YEAR to DATE, and ALBUM ARTIST to ALBUMARTIST, respectively,
|
|
||||||
* in order to be compliant with the names used in other formats.
|
|
||||||
*/
|
|
||||||
PropertyMap properties() const;
|
|
||||||
|
|
||||||
void removeUnsupportedProperties(const StringList &properties);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Implements the unified tag dictionary interface -- import function. The same
|
|
||||||
* comments as for the export function apply; additionally note that the APE tag
|
|
||||||
* specification requires keys to have between 2 and 16 printable ASCII characters
|
|
||||||
* with the exception of the fixed strings "ID3", "TAG", "OGGS", and "MP+".
|
|
||||||
*/
|
|
||||||
PropertyMap setProperties(const PropertyMap &);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Check if the given String is a valid APE tag key.
|
|
||||||
*/
|
|
||||||
static bool checkKey(const String&);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns a pointer to the tag's footer.
|
|
||||||
*/
|
|
||||||
Footer *footer() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns a reference to the item list map. This is an ItemListMap of
|
|
||||||
* all of the items in the tag.
|
|
||||||
*
|
|
||||||
* This is the most powerful structure for accessing the items of the tag.
|
|
||||||
*
|
|
||||||
* APE tags are case-insensitive, all keys in this map have been converted
|
|
||||||
* to upper case.
|
|
||||||
*
|
|
||||||
* \warning You should not modify this data structure directly, instead
|
|
||||||
* use setItem() and removeItem().
|
|
||||||
*/
|
|
||||||
const ItemListMap &itemListMap() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Removes the \a key item from the tag
|
|
||||||
*/
|
|
||||||
void removeItem(const String &key);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Adds to the text item specified by \a key the data \a value. If \a replace
|
|
||||||
* is true, then all of the other values on the same key will be removed
|
|
||||||
* first. If a binary item exists for \a key it will be removed first.
|
|
||||||
*/
|
|
||||||
void addValue(const String &key, const String &value, bool replace = true);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Set the binary data for the key specified by \a item to \a value
|
|
||||||
* This will convert the item to type \a Binary if it isn't already and
|
|
||||||
* all of the other values on the same key will be removed.
|
|
||||||
*/
|
|
||||||
void setData(const String &key, const ByteVector &value);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Sets the \a key item to the value of \a item. If an item with the \a key is already
|
|
||||||
* present, it will be replaced.
|
|
||||||
*/
|
|
||||||
void setItem(const String &key, const Item &item);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns true if the tag does not contain any data.
|
|
||||||
*/
|
|
||||||
bool isEmpty() const;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Reads from the file specified in the constructor.
|
|
||||||
*/
|
|
||||||
void read();
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Parses the body of the tag in \a data.
|
|
||||||
*/
|
|
||||||
void parse(const ByteVector &data);
|
|
||||||
|
|
||||||
private:
|
|
||||||
Tag(const Tag &);
|
|
||||||
Tag &operator=(const Tag &);
|
|
||||||
|
|
||||||
class TagPrivate;
|
|
||||||
TagPrivate *d;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
351
3rdparty/taglib/asf/asfattribute.cpp
vendored
351
3rdparty/taglib/asf/asfattribute.cpp
vendored
@@ -1,351 +0,0 @@
|
|||||||
/**************************************************************************
|
|
||||||
copyright : (C) 2005-2007 by Lukáš Lalinský
|
|
||||||
email : lalinsky@gmail.com
|
|
||||||
**************************************************************************/
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* This library is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU Lesser General Public License version *
|
|
||||||
* 2.1 as published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 *
|
|
||||||
* *
|
|
||||||
* Alternatively, this file is available under the Mozilla Public *
|
|
||||||
* License Version 1.1. You may obtain a copy of the License at *
|
|
||||||
* http://www.mozilla.org/MPL/ *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#include <taglib.h>
|
|
||||||
#include <tdebug.h>
|
|
||||||
#include <trefcounter.h>
|
|
||||||
|
|
||||||
#include "asfattribute.h"
|
|
||||||
#include "asffile.h"
|
|
||||||
#include "asfutils.h"
|
|
||||||
|
|
||||||
using namespace TagLib;
|
|
||||||
|
|
||||||
class ASF::Attribute::AttributePrivate : public RefCounter
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
AttributePrivate() :
|
|
||||||
pictureValue(ASF::Picture::fromInvalid()),
|
|
||||||
numericValue(0),
|
|
||||||
stream(0),
|
|
||||||
language(0) {}
|
|
||||||
AttributeTypes type;
|
|
||||||
String stringValue;
|
|
||||||
ByteVector byteVectorValue;
|
|
||||||
ASF::Picture pictureValue;
|
|
||||||
unsigned long long numericValue;
|
|
||||||
int stream;
|
|
||||||
int language;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// public members
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
ASF::Attribute::Attribute() :
|
|
||||||
d(new AttributePrivate())
|
|
||||||
{
|
|
||||||
d->type = UnicodeType;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASF::Attribute::Attribute(const ASF::Attribute &other) :
|
|
||||||
d(other.d)
|
|
||||||
{
|
|
||||||
d->ref();
|
|
||||||
}
|
|
||||||
|
|
||||||
ASF::Attribute::Attribute(const String &value) :
|
|
||||||
d(new AttributePrivate())
|
|
||||||
{
|
|
||||||
d->type = UnicodeType;
|
|
||||||
d->stringValue = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASF::Attribute::Attribute(const ByteVector &value) :
|
|
||||||
d(new AttributePrivate())
|
|
||||||
{
|
|
||||||
d->type = BytesType;
|
|
||||||
d->byteVectorValue = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASF::Attribute::Attribute(const ASF::Picture &value) :
|
|
||||||
d(new AttributePrivate())
|
|
||||||
{
|
|
||||||
d->type = BytesType;
|
|
||||||
d->pictureValue = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASF::Attribute::Attribute(unsigned int value) :
|
|
||||||
d(new AttributePrivate())
|
|
||||||
{
|
|
||||||
d->type = DWordType;
|
|
||||||
d->numericValue = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASF::Attribute::Attribute(unsigned long long value) :
|
|
||||||
d(new AttributePrivate())
|
|
||||||
{
|
|
||||||
d->type = QWordType;
|
|
||||||
d->numericValue = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASF::Attribute::Attribute(unsigned short value) :
|
|
||||||
d(new AttributePrivate())
|
|
||||||
{
|
|
||||||
d->type = WordType;
|
|
||||||
d->numericValue = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASF::Attribute::Attribute(bool value) :
|
|
||||||
d(new AttributePrivate())
|
|
||||||
{
|
|
||||||
d->type = BoolType;
|
|
||||||
d->numericValue = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASF::Attribute &ASF::Attribute::operator=(const ASF::Attribute &other)
|
|
||||||
{
|
|
||||||
Attribute(other).swap(*this);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASF::Attribute::swap(Attribute &other)
|
|
||||||
{
|
|
||||||
using std::swap;
|
|
||||||
|
|
||||||
swap(d, other.d);
|
|
||||||
}
|
|
||||||
|
|
||||||
ASF::Attribute::~Attribute()
|
|
||||||
{
|
|
||||||
if(d->deref())
|
|
||||||
delete d;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASF::Attribute::AttributeTypes ASF::Attribute::type() const
|
|
||||||
{
|
|
||||||
return d->type;
|
|
||||||
}
|
|
||||||
|
|
||||||
String ASF::Attribute::toString() const
|
|
||||||
{
|
|
||||||
return d->stringValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteVector ASF::Attribute::toByteVector() const
|
|
||||||
{
|
|
||||||
if(d->pictureValue.isValid())
|
|
||||||
return d->pictureValue.render();
|
|
||||||
return d->byteVectorValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned short ASF::Attribute::toBool() const
|
|
||||||
{
|
|
||||||
return d->numericValue ? 1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned short ASF::Attribute::toUShort() const
|
|
||||||
{
|
|
||||||
return static_cast<unsigned short>(d->numericValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int ASF::Attribute::toUInt() const
|
|
||||||
{
|
|
||||||
return static_cast<unsigned int>(d->numericValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned long long ASF::Attribute::toULongLong() const
|
|
||||||
{
|
|
||||||
return static_cast<unsigned long long>(d->numericValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
ASF::Picture ASF::Attribute::toPicture() const
|
|
||||||
{
|
|
||||||
return d->pictureValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
String ASF::Attribute::parse(ASF::File &f, int kind)
|
|
||||||
{
|
|
||||||
unsigned int size, nameLength;
|
|
||||||
String name;
|
|
||||||
d->pictureValue = Picture::fromInvalid();
|
|
||||||
// extended content descriptor
|
|
||||||
if(kind == 0) {
|
|
||||||
nameLength = readWORD(&f);
|
|
||||||
name = readString(&f, nameLength);
|
|
||||||
d->type = ASF::Attribute::AttributeTypes(readWORD(&f));
|
|
||||||
size = readWORD(&f);
|
|
||||||
}
|
|
||||||
// metadata & metadata library
|
|
||||||
else {
|
|
||||||
int temp = readWORD(&f);
|
|
||||||
// metadata library
|
|
||||||
if(kind == 2) {
|
|
||||||
d->language = temp;
|
|
||||||
}
|
|
||||||
d->stream = readWORD(&f);
|
|
||||||
nameLength = readWORD(&f);
|
|
||||||
d->type = ASF::Attribute::AttributeTypes(readWORD(&f));
|
|
||||||
size = readDWORD(&f);
|
|
||||||
name = readString(&f, nameLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(kind != 2 && size > 65535) {
|
|
||||||
debug("ASF::Attribute::parse() -- Value larger than 64kB");
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(d->type) {
|
|
||||||
case WordType:
|
|
||||||
d->numericValue = readWORD(&f);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BoolType:
|
|
||||||
if(kind == 0) {
|
|
||||||
d->numericValue = (readDWORD(&f) != 0);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
d->numericValue = (readWORD(&f) != 0);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DWordType:
|
|
||||||
d->numericValue = readDWORD(&f);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case QWordType:
|
|
||||||
d->numericValue = readQWORD(&f);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case UnicodeType:
|
|
||||||
d->stringValue = readString(&f, size);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BytesType:
|
|
||||||
case GuidType:
|
|
||||||
d->byteVectorValue = f.readBlock(size);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(d->type == BytesType && name == "WM/Picture") {
|
|
||||||
d->pictureValue.parse(d->byteVectorValue);
|
|
||||||
if(d->pictureValue.isValid()) {
|
|
||||||
d->byteVectorValue.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ASF::Attribute::dataSize() const
|
|
||||||
{
|
|
||||||
switch (d->type) {
|
|
||||||
case WordType:
|
|
||||||
return 2;
|
|
||||||
case BoolType:
|
|
||||||
return 4;
|
|
||||||
case DWordType:
|
|
||||||
return 4;
|
|
||||||
case QWordType:
|
|
||||||
return 5;
|
|
||||||
case UnicodeType:
|
|
||||||
return d->stringValue.size() * 2 + 2;
|
|
||||||
case BytesType:
|
|
||||||
if(d->pictureValue.isValid())
|
|
||||||
return d->pictureValue.dataSize();
|
|
||||||
case GuidType:
|
|
||||||
return d->byteVectorValue.size();
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteVector ASF::Attribute::render(const String &name, int kind) const
|
|
||||||
{
|
|
||||||
ByteVector data;
|
|
||||||
|
|
||||||
switch (d->type) {
|
|
||||||
case WordType:
|
|
||||||
data.append(ByteVector::fromShort(toUShort(), false));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BoolType:
|
|
||||||
if(kind == 0) {
|
|
||||||
data.append(ByteVector::fromUInt(toBool(), false));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
data.append(ByteVector::fromShort(toBool(), false));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DWordType:
|
|
||||||
data.append(ByteVector::fromUInt(toUInt(), false));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case QWordType:
|
|
||||||
data.append(ByteVector::fromLongLong(toULongLong(), false));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case UnicodeType:
|
|
||||||
data.append(renderString(d->stringValue));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BytesType:
|
|
||||||
if(d->pictureValue.isValid()) {
|
|
||||||
data.append(d->pictureValue.render());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case GuidType:
|
|
||||||
data.append(d->byteVectorValue);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(kind == 0) {
|
|
||||||
data = renderString(name, true) +
|
|
||||||
ByteVector::fromShort((int)d->type, false) +
|
|
||||||
ByteVector::fromShort(data.size(), false) +
|
|
||||||
data;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ByteVector nameData = renderString(name);
|
|
||||||
data = ByteVector::fromShort(kind == 2 ? d->language : 0, false) +
|
|
||||||
ByteVector::fromShort(d->stream, false) +
|
|
||||||
ByteVector::fromShort(nameData.size(), false) +
|
|
||||||
ByteVector::fromShort((int)d->type, false) +
|
|
||||||
ByteVector::fromUInt(data.size(), false) +
|
|
||||||
nameData +
|
|
||||||
data;
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ASF::Attribute::language() const
|
|
||||||
{
|
|
||||||
return d->language;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASF::Attribute::setLanguage(int value)
|
|
||||||
{
|
|
||||||
d->language = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ASF::Attribute::stream() const
|
|
||||||
{
|
|
||||||
return d->stream;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASF::Attribute::setStream(int value)
|
|
||||||
{
|
|
||||||
d->stream = value;
|
|
||||||
}
|
|
||||||
208
3rdparty/taglib/asf/asfattribute.h
vendored
208
3rdparty/taglib/asf/asfattribute.h
vendored
@@ -1,208 +0,0 @@
|
|||||||
/**************************************************************************
|
|
||||||
copyright : (C) 2005-2007 by Lukáš Lalinský
|
|
||||||
email : lalinsky@gmail.com
|
|
||||||
**************************************************************************/
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* This library is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU Lesser General Public License version *
|
|
||||||
* 2.1 as published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 *
|
|
||||||
* *
|
|
||||||
* Alternatively, this file is available under the Mozilla Public *
|
|
||||||
* License Version 1.1. You may obtain a copy of the License at *
|
|
||||||
* http://www.mozilla.org/MPL/ *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#ifndef TAGLIB_ASFATTRIBUTE_H
|
|
||||||
#define TAGLIB_ASFATTRIBUTE_H
|
|
||||||
|
|
||||||
#include "tstring.h"
|
|
||||||
#include "tbytevector.h"
|
|
||||||
#include "taglib_export.h"
|
|
||||||
#include "asfpicture.h"
|
|
||||||
|
|
||||||
namespace TagLib
|
|
||||||
{
|
|
||||||
|
|
||||||
namespace ASF
|
|
||||||
{
|
|
||||||
|
|
||||||
class File;
|
|
||||||
class Picture;
|
|
||||||
|
|
||||||
class TAGLIB_EXPORT Attribute
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Enum of types an Attribute can have.
|
|
||||||
*/
|
|
||||||
enum AttributeTypes {
|
|
||||||
UnicodeType = 0,
|
|
||||||
BytesType = 1,
|
|
||||||
BoolType = 2,
|
|
||||||
DWordType = 3,
|
|
||||||
QWordType = 4,
|
|
||||||
WordType = 5,
|
|
||||||
GuidType = 6
|
|
||||||
};
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Constructs an empty attribute.
|
|
||||||
*/
|
|
||||||
Attribute();
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Constructs an attribute with \a key and a UnicodeType \a value.
|
|
||||||
*/
|
|
||||||
Attribute(const String &value);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Constructs an attribute with \a key and a BytesType \a value.
|
|
||||||
*/
|
|
||||||
Attribute(const ByteVector &value);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Constructs an attribute with \a key and a Picture \a value.
|
|
||||||
*
|
|
||||||
* This attribute is compatible with the ID3 frame, APIC. The ID3 specification for the APIC frame stipulates that,
|
|
||||||
* while there may be any number of APIC frames associated with a file,
|
|
||||||
* only one may be of type 1 and only one may be of type 2.
|
|
||||||
*
|
|
||||||
* The specification also states that the description of the picture can be no longer than 64 characters, but can be empty.
|
|
||||||
* WM/Picture attributes added with TagLib::ASF are not automatically validated to conform to ID3 specifications.
|
|
||||||
* You must add code in your application to perform validations if you want to maintain complete compatibility with ID3.
|
|
||||||
*/
|
|
||||||
Attribute(const Picture &value);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Constructs an attribute with \a key and a DWordType \a value.
|
|
||||||
*/
|
|
||||||
Attribute(unsigned int value);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Constructs an attribute with \a key and a QWordType \a value.
|
|
||||||
*/
|
|
||||||
Attribute(unsigned long long value);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Constructs an attribute with \a key and a WordType \a value.
|
|
||||||
*/
|
|
||||||
Attribute(unsigned short value);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Constructs an attribute with \a key and a BoolType \a value.
|
|
||||||
*/
|
|
||||||
Attribute(bool value);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Construct an attribute as a copy of \a other.
|
|
||||||
*/
|
|
||||||
Attribute(const Attribute &item);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Copies the contents of \a other into this item.
|
|
||||||
*/
|
|
||||||
Attribute &operator=(const Attribute &other);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Exchanges the content of the Attribute by the content of \a other.
|
|
||||||
*/
|
|
||||||
void swap(Attribute &other);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Destroys the attribute.
|
|
||||||
*/
|
|
||||||
virtual ~Attribute();
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns type of the value.
|
|
||||||
*/
|
|
||||||
AttributeTypes type() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns the BoolType \a value.
|
|
||||||
*/
|
|
||||||
unsigned short toBool() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns the WordType \a value.
|
|
||||||
*/
|
|
||||||
unsigned short toUShort() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns the DWordType \a value.
|
|
||||||
*/
|
|
||||||
unsigned int toUInt() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns the QWordType \a value.
|
|
||||||
*/
|
|
||||||
unsigned long long toULongLong() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns the UnicodeType \a value.
|
|
||||||
*/
|
|
||||||
String toString() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns the BytesType \a value.
|
|
||||||
*/
|
|
||||||
ByteVector toByteVector() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns the Picture \a value.
|
|
||||||
*/
|
|
||||||
Picture toPicture() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns the language number, or 0 is no stream number was set.
|
|
||||||
*/
|
|
||||||
int language() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Sets the language number.
|
|
||||||
*/
|
|
||||||
void setLanguage(int value);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns the stream number, or 0 is no stream number was set.
|
|
||||||
*/
|
|
||||||
int stream() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Sets the stream number.
|
|
||||||
*/
|
|
||||||
void setStream(int value);
|
|
||||||
|
|
||||||
#ifndef DO_NOT_DOCUMENT
|
|
||||||
/* THIS IS PRIVATE, DON'T TOUCH IT! */
|
|
||||||
String parse(ASF::File &file, int kind = 0);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//! Returns the size of the stored data
|
|
||||||
int dataSize() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
friend class File;
|
|
||||||
|
|
||||||
ByteVector render(const String &name, int kind = 0) const;
|
|
||||||
|
|
||||||
class AttributePrivate;
|
|
||||||
AttributePrivate *d;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
705
3rdparty/taglib/asf/asffile.cpp
vendored
705
3rdparty/taglib/asf/asffile.cpp
vendored
@@ -1,705 +0,0 @@
|
|||||||
/**************************************************************************
|
|
||||||
copyright : (C) 2005-2007 by Lukáš Lalinský
|
|
||||||
email : lalinsky@gmail.com
|
|
||||||
**************************************************************************/
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* This library is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU Lesser General Public License version *
|
|
||||||
* 2.1 as published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 *
|
|
||||||
* *
|
|
||||||
* Alternatively, this file is available under the Mozilla Public *
|
|
||||||
* License Version 1.1. You may obtain a copy of the License at *
|
|
||||||
* http://www.mozilla.org/MPL/ *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#include <tdebug.h>
|
|
||||||
#include <tbytevectorlist.h>
|
|
||||||
#include <tpropertymap.h>
|
|
||||||
#include <tstring.h>
|
|
||||||
#include <tagutils.h>
|
|
||||||
|
|
||||||
#include "asffile.h"
|
|
||||||
#include "asftag.h"
|
|
||||||
#include "asfproperties.h"
|
|
||||||
#include "asfutils.h"
|
|
||||||
|
|
||||||
using namespace TagLib;
|
|
||||||
|
|
||||||
class ASF::File::FilePrivate
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
class BaseObject;
|
|
||||||
class UnknownObject;
|
|
||||||
class FilePropertiesObject;
|
|
||||||
class StreamPropertiesObject;
|
|
||||||
class ContentDescriptionObject;
|
|
||||||
class ExtendedContentDescriptionObject;
|
|
||||||
class HeaderExtensionObject;
|
|
||||||
class CodecListObject;
|
|
||||||
class MetadataObject;
|
|
||||||
class MetadataLibraryObject;
|
|
||||||
|
|
||||||
FilePrivate():
|
|
||||||
headerSize(0),
|
|
||||||
tag(0),
|
|
||||||
properties(0),
|
|
||||||
contentDescriptionObject(0),
|
|
||||||
extendedContentDescriptionObject(0),
|
|
||||||
headerExtensionObject(0),
|
|
||||||
metadataObject(0),
|
|
||||||
metadataLibraryObject(0)
|
|
||||||
{
|
|
||||||
objects.setAutoDelete(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
~FilePrivate()
|
|
||||||
{
|
|
||||||
delete tag;
|
|
||||||
delete properties;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned long long headerSize;
|
|
||||||
|
|
||||||
ASF::Tag *tag;
|
|
||||||
ASF::Properties *properties;
|
|
||||||
|
|
||||||
List<BaseObject *> objects;
|
|
||||||
|
|
||||||
ContentDescriptionObject *contentDescriptionObject;
|
|
||||||
ExtendedContentDescriptionObject *extendedContentDescriptionObject;
|
|
||||||
HeaderExtensionObject *headerExtensionObject;
|
|
||||||
MetadataObject *metadataObject;
|
|
||||||
MetadataLibraryObject *metadataLibraryObject;
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
const ByteVector headerGuid("\x30\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C", 16);
|
|
||||||
const ByteVector filePropertiesGuid("\xA1\xDC\xAB\x8C\x47\xA9\xCF\x11\x8E\xE4\x00\xC0\x0C\x20\x53\x65", 16);
|
|
||||||
const ByteVector streamPropertiesGuid("\x91\x07\xDC\xB7\xB7\xA9\xCF\x11\x8E\xE6\x00\xC0\x0C\x20\x53\x65", 16);
|
|
||||||
const ByteVector contentDescriptionGuid("\x33\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C", 16);
|
|
||||||
const ByteVector extendedContentDescriptionGuid("\x40\xA4\xD0\xD2\x07\xE3\xD2\x11\x97\xF0\x00\xA0\xC9\x5E\xA8\x50", 16);
|
|
||||||
const ByteVector headerExtensionGuid("\xb5\x03\xbf_.\xa9\xcf\x11\x8e\xe3\x00\xc0\x0c Se", 16);
|
|
||||||
const ByteVector metadataGuid("\xEA\xCB\xF8\xC5\xAF[wH\204g\xAA\214D\xFAL\xCA", 16);
|
|
||||||
const ByteVector metadataLibraryGuid("\224\034#D\230\224\321I\241A\x1d\x13NEpT", 16);
|
|
||||||
const ByteVector codecListGuid("\x40\x52\xd1\x86\x1d\x31\xd0\x11\xa3\xa4\x00\xa0\xc9\x03\x48\xf6", 16);
|
|
||||||
const ByteVector contentEncryptionGuid("\xFB\xB3\x11\x22\x23\xBD\xD2\x11\xB4\xB7\x00\xA0\xC9\x55\xFC\x6E", 16);
|
|
||||||
const ByteVector extendedContentEncryptionGuid("\x14\xE6\x8A\x29\x22\x26 \x17\x4C\xB9\x35\xDA\xE0\x7E\xE9\x28\x9C", 16);
|
|
||||||
const ByteVector advancedContentEncryptionGuid("\xB6\x9B\x07\x7A\xA4\xDA\x12\x4E\xA5\xCA\x91\xD3\x8D\xC1\x1A\x8D", 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
class ASF::File::FilePrivate::BaseObject
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ByteVector data;
|
|
||||||
virtual ~BaseObject() {}
|
|
||||||
virtual ByteVector guid() const = 0;
|
|
||||||
virtual void parse(ASF::File *file, unsigned int size);
|
|
||||||
virtual ByteVector render(ASF::File *file);
|
|
||||||
};
|
|
||||||
|
|
||||||
class ASF::File::FilePrivate::UnknownObject : public ASF::File::FilePrivate::BaseObject
|
|
||||||
{
|
|
||||||
ByteVector myGuid;
|
|
||||||
public:
|
|
||||||
UnknownObject(const ByteVector &guid);
|
|
||||||
ByteVector guid() const;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ASF::File::FilePrivate::FilePropertiesObject : public ASF::File::FilePrivate::BaseObject
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ByteVector guid() const;
|
|
||||||
void parse(ASF::File *file, unsigned int size);
|
|
||||||
};
|
|
||||||
|
|
||||||
class ASF::File::FilePrivate::StreamPropertiesObject : public ASF::File::FilePrivate::BaseObject
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ByteVector guid() const;
|
|
||||||
void parse(ASF::File *file, unsigned int size);
|
|
||||||
};
|
|
||||||
|
|
||||||
class ASF::File::FilePrivate::ContentDescriptionObject : public ASF::File::FilePrivate::BaseObject
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ByteVector guid() const;
|
|
||||||
void parse(ASF::File *file, unsigned int size);
|
|
||||||
ByteVector render(ASF::File *file);
|
|
||||||
};
|
|
||||||
|
|
||||||
class ASF::File::FilePrivate::ExtendedContentDescriptionObject : public ASF::File::FilePrivate::BaseObject
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ByteVectorList attributeData;
|
|
||||||
ByteVector guid() const;
|
|
||||||
void parse(ASF::File *file, unsigned int size);
|
|
||||||
ByteVector render(ASF::File *file);
|
|
||||||
};
|
|
||||||
|
|
||||||
class ASF::File::FilePrivate::MetadataObject : public ASF::File::FilePrivate::BaseObject
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ByteVectorList attributeData;
|
|
||||||
ByteVector guid() const;
|
|
||||||
void parse(ASF::File *file, unsigned int size);
|
|
||||||
ByteVector render(ASF::File *file);
|
|
||||||
};
|
|
||||||
|
|
||||||
class ASF::File::FilePrivate::MetadataLibraryObject : public ASF::File::FilePrivate::BaseObject
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ByteVectorList attributeData;
|
|
||||||
ByteVector guid() const;
|
|
||||||
void parse(ASF::File *file, unsigned int size);
|
|
||||||
ByteVector render(ASF::File *file);
|
|
||||||
};
|
|
||||||
|
|
||||||
class ASF::File::FilePrivate::HeaderExtensionObject : public ASF::File::FilePrivate::BaseObject
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
List<ASF::File::FilePrivate::BaseObject *> objects;
|
|
||||||
HeaderExtensionObject();
|
|
||||||
ByteVector guid() const;
|
|
||||||
void parse(ASF::File *file, unsigned int size);
|
|
||||||
ByteVector render(ASF::File *file);
|
|
||||||
};
|
|
||||||
|
|
||||||
class ASF::File::FilePrivate::CodecListObject : public ASF::File::FilePrivate::BaseObject
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ByteVector guid() const;
|
|
||||||
void parse(ASF::File *file, unsigned int size);
|
|
||||||
|
|
||||||
private:
|
|
||||||
enum CodecType
|
|
||||||
{
|
|
||||||
Video = 0x0001,
|
|
||||||
Audio = 0x0002,
|
|
||||||
Unknown = 0xFFFF
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
void ASF::File::FilePrivate::BaseObject::parse(ASF::File *file, unsigned int size)
|
|
||||||
{
|
|
||||||
data.clear();
|
|
||||||
if(size > 24 && size <= (unsigned int)(file->length()))
|
|
||||||
data = file->readBlock(size - 24);
|
|
||||||
else
|
|
||||||
data = ByteVector();
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteVector ASF::File::FilePrivate::BaseObject::render(ASF::File * /*file*/)
|
|
||||||
{
|
|
||||||
return guid() + ByteVector::fromLongLong(data.size() + 24, false) + data;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASF::File::FilePrivate::UnknownObject::UnknownObject(const ByteVector &guid) : myGuid(guid)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteVector ASF::File::FilePrivate::UnknownObject::guid() const
|
|
||||||
{
|
|
||||||
return myGuid;
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteVector ASF::File::FilePrivate::FilePropertiesObject::guid() const
|
|
||||||
{
|
|
||||||
return filePropertiesGuid;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASF::File::FilePrivate::FilePropertiesObject::parse(ASF::File *file, unsigned int size)
|
|
||||||
{
|
|
||||||
BaseObject::parse(file, size);
|
|
||||||
if(data.size() < 64) {
|
|
||||||
debug("ASF::File::FilePrivate::FilePropertiesObject::parse() -- data is too short.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const long long duration = data.toLongLong(40, false);
|
|
||||||
const long long preroll = data.toLongLong(56, false);
|
|
||||||
file->d->properties->setLengthInMilliseconds(static_cast<int>(duration / 10000.0 - preroll + 0.5));
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteVector ASF::File::FilePrivate::StreamPropertiesObject::guid() const
|
|
||||||
{
|
|
||||||
return streamPropertiesGuid;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASF::File::FilePrivate::StreamPropertiesObject::parse(ASF::File *file, unsigned int size)
|
|
||||||
{
|
|
||||||
BaseObject::parse(file, size);
|
|
||||||
if(data.size() < 70) {
|
|
||||||
debug("ASF::File::FilePrivate::StreamPropertiesObject::parse() -- data is too short.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
file->d->properties->setCodec(data.toUShort(54, false));
|
|
||||||
file->d->properties->setChannels(data.toUShort(56, false));
|
|
||||||
file->d->properties->setSampleRate(data.toUInt(58, false));
|
|
||||||
file->d->properties->setBitrate(static_cast<int>(data.toUInt(62, false) * 8.0 / 1000.0 + 0.5));
|
|
||||||
file->d->properties->setBitsPerSample(data.toUShort(68, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteVector ASF::File::FilePrivate::ContentDescriptionObject::guid() const
|
|
||||||
{
|
|
||||||
return contentDescriptionGuid;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASF::File::FilePrivate::ContentDescriptionObject::parse(ASF::File *file, unsigned int /*size*/)
|
|
||||||
{
|
|
||||||
const int titleLength = readWORD(file);
|
|
||||||
const int artistLength = readWORD(file);
|
|
||||||
const int copyrightLength = readWORD(file);
|
|
||||||
const int commentLength = readWORD(file);
|
|
||||||
const int ratingLength = readWORD(file);
|
|
||||||
file->d->tag->setTitle(readString(file,titleLength));
|
|
||||||
file->d->tag->setArtist(readString(file,artistLength));
|
|
||||||
file->d->tag->setCopyright(readString(file,copyrightLength));
|
|
||||||
file->d->tag->setComment(readString(file,commentLength));
|
|
||||||
file->d->tag->setRating(readString(file,ratingLength));
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteVector ASF::File::FilePrivate::ContentDescriptionObject::render(ASF::File *file)
|
|
||||||
{
|
|
||||||
const ByteVector v1 = renderString(file->d->tag->title());
|
|
||||||
const ByteVector v2 = renderString(file->d->tag->artist());
|
|
||||||
const ByteVector v3 = renderString(file->d->tag->copyright());
|
|
||||||
const ByteVector v4 = renderString(file->d->tag->comment());
|
|
||||||
const ByteVector v5 = renderString(file->d->tag->rating());
|
|
||||||
data.clear();
|
|
||||||
data.append(ByteVector::fromShort(v1.size(), false));
|
|
||||||
data.append(ByteVector::fromShort(v2.size(), false));
|
|
||||||
data.append(ByteVector::fromShort(v3.size(), false));
|
|
||||||
data.append(ByteVector::fromShort(v4.size(), false));
|
|
||||||
data.append(ByteVector::fromShort(v5.size(), false));
|
|
||||||
data.append(v1);
|
|
||||||
data.append(v2);
|
|
||||||
data.append(v3);
|
|
||||||
data.append(v4);
|
|
||||||
data.append(v5);
|
|
||||||
return BaseObject::render(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteVector ASF::File::FilePrivate::ExtendedContentDescriptionObject::guid() const
|
|
||||||
{
|
|
||||||
return extendedContentDescriptionGuid;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASF::File::FilePrivate::ExtendedContentDescriptionObject::parse(ASF::File *file, unsigned int /*size*/)
|
|
||||||
{
|
|
||||||
int count = readWORD(file);
|
|
||||||
while(count--) {
|
|
||||||
ASF::Attribute attribute;
|
|
||||||
String name = attribute.parse(*file);
|
|
||||||
file->d->tag->addAttribute(name, attribute);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteVector ASF::File::FilePrivate::ExtendedContentDescriptionObject::render(ASF::File *file)
|
|
||||||
{
|
|
||||||
data.clear();
|
|
||||||
data.append(ByteVector::fromShort(attributeData.size(), false));
|
|
||||||
data.append(attributeData.toByteVector(""));
|
|
||||||
return BaseObject::render(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteVector ASF::File::FilePrivate::MetadataObject::guid() const
|
|
||||||
{
|
|
||||||
return metadataGuid;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASF::File::FilePrivate::MetadataObject::parse(ASF::File *file, unsigned int /*size*/)
|
|
||||||
{
|
|
||||||
int count = readWORD(file);
|
|
||||||
while(count--) {
|
|
||||||
ASF::Attribute attribute;
|
|
||||||
String name = attribute.parse(*file, 1);
|
|
||||||
file->d->tag->addAttribute(name, attribute);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteVector ASF::File::FilePrivate::MetadataObject::render(ASF::File *file)
|
|
||||||
{
|
|
||||||
data.clear();
|
|
||||||
data.append(ByteVector::fromShort(attributeData.size(), false));
|
|
||||||
data.append(attributeData.toByteVector(""));
|
|
||||||
return BaseObject::render(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteVector ASF::File::FilePrivate::MetadataLibraryObject::guid() const
|
|
||||||
{
|
|
||||||
return metadataLibraryGuid;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASF::File::FilePrivate::MetadataLibraryObject::parse(ASF::File *file, unsigned int /*size*/)
|
|
||||||
{
|
|
||||||
int count = readWORD(file);
|
|
||||||
while(count--) {
|
|
||||||
ASF::Attribute attribute;
|
|
||||||
String name = attribute.parse(*file, 2);
|
|
||||||
file->d->tag->addAttribute(name, attribute);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteVector ASF::File::FilePrivate::MetadataLibraryObject::render(ASF::File *file)
|
|
||||||
{
|
|
||||||
data.clear();
|
|
||||||
data.append(ByteVector::fromShort(attributeData.size(), false));
|
|
||||||
data.append(attributeData.toByteVector(""));
|
|
||||||
return BaseObject::render(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
ASF::File::FilePrivate::HeaderExtensionObject::HeaderExtensionObject()
|
|
||||||
{
|
|
||||||
objects.setAutoDelete(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteVector ASF::File::FilePrivate::HeaderExtensionObject::guid() const
|
|
||||||
{
|
|
||||||
return headerExtensionGuid;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASF::File::FilePrivate::HeaderExtensionObject::parse(ASF::File *file, unsigned int /*size*/)
|
|
||||||
{
|
|
||||||
file->seek(18, File::Current);
|
|
||||||
long long dataSize = readDWORD(file);
|
|
||||||
long long dataPos = 0;
|
|
||||||
while(dataPos < dataSize) {
|
|
||||||
ByteVector guid = file->readBlock(16);
|
|
||||||
if(guid.size() != 16) {
|
|
||||||
file->setValid(false);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
bool ok;
|
|
||||||
long long size = readQWORD(file, &ok);
|
|
||||||
if(!ok) {
|
|
||||||
file->setValid(false);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
BaseObject *obj;
|
|
||||||
if(guid == metadataGuid) {
|
|
||||||
file->d->metadataObject = new MetadataObject();
|
|
||||||
obj = file->d->metadataObject;
|
|
||||||
}
|
|
||||||
else if(guid == metadataLibraryGuid) {
|
|
||||||
file->d->metadataLibraryObject = new MetadataLibraryObject();
|
|
||||||
obj = file->d->metadataLibraryObject;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
obj = new UnknownObject(guid);
|
|
||||||
}
|
|
||||||
obj->parse(file, (unsigned int)size);
|
|
||||||
objects.append(obj);
|
|
||||||
dataPos += size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteVector ASF::File::FilePrivate::HeaderExtensionObject::render(ASF::File *file)
|
|
||||||
{
|
|
||||||
data.clear();
|
|
||||||
for(List<BaseObject *>::ConstIterator it = objects.begin(); it != objects.end(); ++it) {
|
|
||||||
data.append((*it)->render(file));
|
|
||||||
}
|
|
||||||
data = ByteVector("\x11\xD2\xD3\xAB\xBA\xA9\xcf\x11\x8E\xE6\x00\xC0\x0C\x20\x53\x65\x06\x00", 18) + ByteVector::fromUInt(data.size(), false) + data;
|
|
||||||
return BaseObject::render(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteVector ASF::File::FilePrivate::CodecListObject::guid() const
|
|
||||||
{
|
|
||||||
return codecListGuid;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASF::File::FilePrivate::CodecListObject::parse(ASF::File *file, unsigned int size)
|
|
||||||
{
|
|
||||||
BaseObject::parse(file, size);
|
|
||||||
if(data.size() <= 20) {
|
|
||||||
debug("ASF::File::FilePrivate::CodecListObject::parse() -- data is too short.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int pos = 16;
|
|
||||||
|
|
||||||
const int count = data.toUInt(pos, false);
|
|
||||||
pos += 4;
|
|
||||||
|
|
||||||
for(int i = 0; i < count; ++i) {
|
|
||||||
|
|
||||||
if(pos >= data.size())
|
|
||||||
break;
|
|
||||||
|
|
||||||
const CodecType type = static_cast<CodecType>(data.toUShort(pos, false));
|
|
||||||
pos += 2;
|
|
||||||
|
|
||||||
int nameLength = data.toUShort(pos, false);
|
|
||||||
pos += 2;
|
|
||||||
|
|
||||||
const unsigned int namePos = pos;
|
|
||||||
pos += nameLength * 2;
|
|
||||||
|
|
||||||
const int descLength = data.toUShort(pos, false);
|
|
||||||
pos += 2;
|
|
||||||
|
|
||||||
const unsigned int descPos = pos;
|
|
||||||
pos += descLength * 2;
|
|
||||||
|
|
||||||
const int infoLength = data.toUShort(pos, false);
|
|
||||||
pos += 2 + infoLength * 2;
|
|
||||||
|
|
||||||
if(type == CodecListObject::Audio) {
|
|
||||||
// First audio codec found.
|
|
||||||
|
|
||||||
const String name(data.mid(namePos, nameLength * 2), String::UTF16LE);
|
|
||||||
file->d->properties->setCodecName(name.stripWhiteSpace());
|
|
||||||
|
|
||||||
const String desc(data.mid(descPos, descLength * 2), String::UTF16LE);
|
|
||||||
file->d->properties->setCodecDescription(desc.stripWhiteSpace());
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// static members
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
bool ASF::File::isSupported(IOStream *stream)
|
|
||||||
{
|
|
||||||
// An ASF file has to start with the designated GUID.
|
|
||||||
|
|
||||||
const ByteVector id = Utils::readHeader(stream, 16, false);
|
|
||||||
return (id == headerGuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// public members
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
ASF::File::File(FileName file, bool, Properties::ReadStyle) :
|
|
||||||
TagLib::File(file),
|
|
||||||
d(new FilePrivate())
|
|
||||||
{
|
|
||||||
if(isOpen())
|
|
||||||
read();
|
|
||||||
}
|
|
||||||
|
|
||||||
ASF::File::File(IOStream *stream, bool, Properties::ReadStyle) :
|
|
||||||
TagLib::File(stream),
|
|
||||||
d(new FilePrivate())
|
|
||||||
{
|
|
||||||
if(isOpen())
|
|
||||||
read();
|
|
||||||
}
|
|
||||||
|
|
||||||
ASF::File::~File()
|
|
||||||
{
|
|
||||||
delete d;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASF::Tag *ASF::File::tag() const
|
|
||||||
{
|
|
||||||
return d->tag;
|
|
||||||
}
|
|
||||||
|
|
||||||
PropertyMap ASF::File::properties() const
|
|
||||||
{
|
|
||||||
return d->tag->properties();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASF::File::removeUnsupportedProperties(const StringList &properties)
|
|
||||||
{
|
|
||||||
d->tag->removeUnsupportedProperties(properties);
|
|
||||||
}
|
|
||||||
|
|
||||||
PropertyMap ASF::File::setProperties(const PropertyMap &properties)
|
|
||||||
{
|
|
||||||
return d->tag->setProperties(properties);
|
|
||||||
}
|
|
||||||
|
|
||||||
ASF::Properties *ASF::File::audioProperties() const
|
|
||||||
{
|
|
||||||
return d->properties;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ASF::File::save()
|
|
||||||
{
|
|
||||||
if(readOnly()) {
|
|
||||||
debug("ASF::File::save() -- File is read only.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!isValid()) {
|
|
||||||
debug("ASF::File::save() -- Trying to save invalid file.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!d->contentDescriptionObject) {
|
|
||||||
d->contentDescriptionObject = new FilePrivate::ContentDescriptionObject();
|
|
||||||
d->objects.append(d->contentDescriptionObject);
|
|
||||||
}
|
|
||||||
if(!d->extendedContentDescriptionObject) {
|
|
||||||
d->extendedContentDescriptionObject = new FilePrivate::ExtendedContentDescriptionObject();
|
|
||||||
d->objects.append(d->extendedContentDescriptionObject);
|
|
||||||
}
|
|
||||||
if(!d->headerExtensionObject) {
|
|
||||||
d->headerExtensionObject = new FilePrivate::HeaderExtensionObject();
|
|
||||||
d->objects.append(d->headerExtensionObject);
|
|
||||||
}
|
|
||||||
if(!d->metadataObject) {
|
|
||||||
d->metadataObject = new FilePrivate::MetadataObject();
|
|
||||||
d->headerExtensionObject->objects.append(d->metadataObject);
|
|
||||||
}
|
|
||||||
if(!d->metadataLibraryObject) {
|
|
||||||
d->metadataLibraryObject = new FilePrivate::MetadataLibraryObject();
|
|
||||||
d->headerExtensionObject->objects.append(d->metadataLibraryObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
d->extendedContentDescriptionObject->attributeData.clear();
|
|
||||||
d->metadataObject->attributeData.clear();
|
|
||||||
d->metadataLibraryObject->attributeData.clear();
|
|
||||||
|
|
||||||
const AttributeListMap allAttributes = d->tag->attributeListMap();
|
|
||||||
|
|
||||||
for(AttributeListMap::ConstIterator it = allAttributes.begin(); it != allAttributes.end(); ++it) {
|
|
||||||
|
|
||||||
const String &name = it->first;
|
|
||||||
const AttributeList &attributes = it->second;
|
|
||||||
|
|
||||||
bool inExtendedContentDescriptionObject = false;
|
|
||||||
bool inMetadataObject = false;
|
|
||||||
|
|
||||||
for(AttributeList::ConstIterator jt = attributes.begin(); jt != attributes.end(); ++jt) {
|
|
||||||
|
|
||||||
const Attribute &attribute = *jt;
|
|
||||||
const bool largeValue = (attribute.dataSize() > 65535);
|
|
||||||
const bool guid = (attribute.type() == Attribute::GuidType);
|
|
||||||
|
|
||||||
if(!inExtendedContentDescriptionObject && !guid && !largeValue && attribute.language() == 0 && attribute.stream() == 0) {
|
|
||||||
d->extendedContentDescriptionObject->attributeData.append(attribute.render(name));
|
|
||||||
inExtendedContentDescriptionObject = true;
|
|
||||||
}
|
|
||||||
else if(!inMetadataObject && !guid && !largeValue && attribute.language() == 0 && attribute.stream() != 0) {
|
|
||||||
d->metadataObject->attributeData.append(attribute.render(name, 1));
|
|
||||||
inMetadataObject = true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
d->metadataLibraryObject->attributeData.append(attribute.render(name, 2));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteVector data;
|
|
||||||
for(List<FilePrivate::BaseObject *>::ConstIterator it = d->objects.begin(); it != d->objects.end(); ++it) {
|
|
||||||
data.append((*it)->render(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
seek(16);
|
|
||||||
writeBlock(ByteVector::fromLongLong(data.size() + 30, false));
|
|
||||||
writeBlock(ByteVector::fromUInt(d->objects.size(), false));
|
|
||||||
writeBlock(ByteVector("\x01\x02", 2));
|
|
||||||
|
|
||||||
insert(data, 30, static_cast<unsigned long>(d->headerSize - 30));
|
|
||||||
|
|
||||||
d->headerSize = data.size() + 30;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// private members
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void ASF::File::read()
|
|
||||||
{
|
|
||||||
if(!isValid())
|
|
||||||
return;
|
|
||||||
|
|
||||||
if(readBlock(16) != headerGuid) {
|
|
||||||
debug("ASF::File::read(): Not an ASF file.");
|
|
||||||
setValid(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
d->tag = new ASF::Tag();
|
|
||||||
d->properties = new ASF::Properties();
|
|
||||||
|
|
||||||
bool ok;
|
|
||||||
d->headerSize = readQWORD(this, &ok);
|
|
||||||
if(!ok) {
|
|
||||||
setValid(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int numObjects = readDWORD(this, &ok);
|
|
||||||
if(!ok) {
|
|
||||||
setValid(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
seek(2, Current);
|
|
||||||
|
|
||||||
FilePrivate::FilePropertiesObject *filePropertiesObject = 0;
|
|
||||||
FilePrivate::StreamPropertiesObject *streamPropertiesObject = 0;
|
|
||||||
for(int i = 0; i < numObjects; i++) {
|
|
||||||
const ByteVector guid = readBlock(16);
|
|
||||||
if(guid.size() != 16) {
|
|
||||||
setValid(false);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
long size = (long)readQWORD(this, &ok);
|
|
||||||
if(!ok) {
|
|
||||||
setValid(false);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
FilePrivate::BaseObject *obj;
|
|
||||||
if(guid == filePropertiesGuid) {
|
|
||||||
filePropertiesObject = new FilePrivate::FilePropertiesObject();
|
|
||||||
obj = filePropertiesObject;
|
|
||||||
}
|
|
||||||
else if(guid == streamPropertiesGuid) {
|
|
||||||
streamPropertiesObject = new FilePrivate::StreamPropertiesObject();
|
|
||||||
obj = streamPropertiesObject;
|
|
||||||
}
|
|
||||||
else if(guid == contentDescriptionGuid) {
|
|
||||||
d->contentDescriptionObject = new FilePrivate::ContentDescriptionObject();
|
|
||||||
obj = d->contentDescriptionObject;
|
|
||||||
}
|
|
||||||
else if(guid == extendedContentDescriptionGuid) {
|
|
||||||
d->extendedContentDescriptionObject = new FilePrivate::ExtendedContentDescriptionObject();
|
|
||||||
obj = d->extendedContentDescriptionObject;
|
|
||||||
}
|
|
||||||
else if(guid == headerExtensionGuid) {
|
|
||||||
d->headerExtensionObject = new FilePrivate::HeaderExtensionObject();
|
|
||||||
obj = d->headerExtensionObject;
|
|
||||||
}
|
|
||||||
else if(guid == codecListGuid) {
|
|
||||||
obj = new FilePrivate::CodecListObject();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if(guid == contentEncryptionGuid ||
|
|
||||||
guid == extendedContentEncryptionGuid ||
|
|
||||||
guid == advancedContentEncryptionGuid) {
|
|
||||||
d->properties->setEncrypted(true);
|
|
||||||
}
|
|
||||||
obj = new FilePrivate::UnknownObject(guid);
|
|
||||||
}
|
|
||||||
obj->parse(this, size);
|
|
||||||
d->objects.append(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!filePropertiesObject || !streamPropertiesObject) {
|
|
||||||
debug("ASF::File::read(): Missing mandatory header objects.");
|
|
||||||
setValid(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
138
3rdparty/taglib/asf/asffile.h
vendored
138
3rdparty/taglib/asf/asffile.h
vendored
@@ -1,138 +0,0 @@
|
|||||||
/**************************************************************************
|
|
||||||
copyright : (C) 2005-2007 by Lukáš Lalinský
|
|
||||||
email : lalinsky@gmail.com
|
|
||||||
**************************************************************************/
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* This library is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU Lesser General Public License version *
|
|
||||||
* 2.1 as published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 *
|
|
||||||
* *
|
|
||||||
* Alternatively, this file is available under the Mozilla Public *
|
|
||||||
* License Version 1.1. You may obtain a copy of the License at *
|
|
||||||
* http://www.mozilla.org/MPL/ *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#ifndef TAGLIB_ASFFILE_H
|
|
||||||
#define TAGLIB_ASFFILE_H
|
|
||||||
|
|
||||||
#include "tag.h"
|
|
||||||
#include "tfile.h"
|
|
||||||
#include "taglib_export.h"
|
|
||||||
#include "asfproperties.h"
|
|
||||||
#include "asftag.h"
|
|
||||||
|
|
||||||
namespace TagLib {
|
|
||||||
|
|
||||||
//! An implementation of ASF (WMA) metadata
|
|
||||||
namespace ASF {
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* This implements and provides an interface for ASF files to the
|
|
||||||
* TagLib::Tag and TagLib::AudioProperties interfaces by way of implementing
|
|
||||||
* the abstract TagLib::File API as well as providing some additional
|
|
||||||
* information specific to ASF files.
|
|
||||||
*/
|
|
||||||
class TAGLIB_EXPORT File : public TagLib::File
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Constructs an ASF file from \a file.
|
|
||||||
*
|
|
||||||
* \note In the current implementation, both \a readProperties and
|
|
||||||
* \a propertiesStyle are ignored. The audio properties are always
|
|
||||||
* read.
|
|
||||||
*/
|
|
||||||
File(FileName file, bool readProperties = true,
|
|
||||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Constructs an ASF file from \a stream.
|
|
||||||
*
|
|
||||||
* \note In the current implementation, both \a readProperties and
|
|
||||||
* \a propertiesStyle are ignored. The audio properties are always
|
|
||||||
* read.
|
|
||||||
*
|
|
||||||
* \note TagLib will *not* take ownership of the stream, the caller is
|
|
||||||
* responsible for deleting it after the File object.
|
|
||||||
*/
|
|
||||||
File(IOStream *stream, bool readProperties = true,
|
|
||||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Destroys this instance of the File.
|
|
||||||
*/
|
|
||||||
virtual ~File();
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns a pointer to the ASF tag of the file.
|
|
||||||
*
|
|
||||||
* ASF::Tag implements the tag interface, so this serves as the
|
|
||||||
* reimplementation of TagLib::File::tag().
|
|
||||||
*
|
|
||||||
* \note The Tag <b>is still</b> owned by the ASF::File and should not be
|
|
||||||
* deleted by the user. It will be deleted when the file (object) is
|
|
||||||
* destroyed.
|
|
||||||
*/
|
|
||||||
virtual Tag *tag() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Implements the unified property interface -- export function.
|
|
||||||
*/
|
|
||||||
PropertyMap properties() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Removes unsupported properties. Forwards to the actual Tag's
|
|
||||||
* removeUnsupportedProperties() function.
|
|
||||||
*/
|
|
||||||
void removeUnsupportedProperties(const StringList &properties);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Implements the unified property interface -- import function.
|
|
||||||
*/
|
|
||||||
PropertyMap setProperties(const PropertyMap &);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns the ASF audio properties for this file.
|
|
||||||
*/
|
|
||||||
virtual Properties *audioProperties() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Save the file.
|
|
||||||
*
|
|
||||||
* This returns true if the save was successful.
|
|
||||||
*/
|
|
||||||
virtual bool save();
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns whether or not the given \a stream can be opened as an ASF
|
|
||||||
* file.
|
|
||||||
*
|
|
||||||
* \note This method is designed to do a quick check. The result may
|
|
||||||
* not necessarily be correct.
|
|
||||||
*/
|
|
||||||
static bool isSupported(IOStream *stream);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void read();
|
|
||||||
|
|
||||||
class FilePrivate;
|
|
||||||
FilePrivate *d;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
183
3rdparty/taglib/asf/asfpicture.cpp
vendored
183
3rdparty/taglib/asf/asfpicture.cpp
vendored
@@ -1,183 +0,0 @@
|
|||||||
/**************************************************************************
|
|
||||||
copyright : (C) 2010 by Anton Sergunov
|
|
||||||
email : setosha@gmail.com
|
|
||||||
**************************************************************************/
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* This library is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU Lesser General Public License version *
|
|
||||||
* 2.1 as published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 *
|
|
||||||
* *
|
|
||||||
* Alternatively, this file is available under the Mozilla Public *
|
|
||||||
* License Version 1.1. You may obtain a copy of the License at *
|
|
||||||
* http://www.mozilla.org/MPL/ *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#include <taglib.h>
|
|
||||||
#include <tdebug.h>
|
|
||||||
#include <trefcounter.h>
|
|
||||||
|
|
||||||
#include "asfattribute.h"
|
|
||||||
#include "asffile.h"
|
|
||||||
#include "asfpicture.h"
|
|
||||||
#include "asfutils.h"
|
|
||||||
|
|
||||||
using namespace TagLib;
|
|
||||||
|
|
||||||
class ASF::Picture::PicturePrivate : public RefCounter
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
bool valid;
|
|
||||||
Type type;
|
|
||||||
String mimeType;
|
|
||||||
String description;
|
|
||||||
ByteVector picture;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Picture class members
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
ASF::Picture::Picture() :
|
|
||||||
d(new PicturePrivate())
|
|
||||||
{
|
|
||||||
d->valid = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASF::Picture::Picture(const Picture& other) :
|
|
||||||
d(other.d)
|
|
||||||
{
|
|
||||||
d->ref();
|
|
||||||
}
|
|
||||||
|
|
||||||
ASF::Picture::~Picture()
|
|
||||||
{
|
|
||||||
if(d->deref())
|
|
||||||
delete d;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ASF::Picture::isValid() const
|
|
||||||
{
|
|
||||||
return d->valid;
|
|
||||||
}
|
|
||||||
|
|
||||||
String ASF::Picture::mimeType() const
|
|
||||||
{
|
|
||||||
return d->mimeType;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASF::Picture::setMimeType(const String &value)
|
|
||||||
{
|
|
||||||
d->mimeType = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASF::Picture::Type ASF::Picture::type() const
|
|
||||||
{
|
|
||||||
return d->type;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASF::Picture::setType(const ASF::Picture::Type& t)
|
|
||||||
{
|
|
||||||
d->type = t;
|
|
||||||
}
|
|
||||||
|
|
||||||
String ASF::Picture::description() const
|
|
||||||
{
|
|
||||||
return d->description;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASF::Picture::setDescription(const String &desc)
|
|
||||||
{
|
|
||||||
d->description = desc;
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteVector ASF::Picture::picture() const
|
|
||||||
{
|
|
||||||
return d->picture;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASF::Picture::setPicture(const ByteVector &p)
|
|
||||||
{
|
|
||||||
d->picture = p;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ASF::Picture::dataSize() const
|
|
||||||
{
|
|
||||||
return
|
|
||||||
9 + (d->mimeType.length() + d->description.length()) * 2 +
|
|
||||||
d->picture.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
ASF::Picture& ASF::Picture::operator=(const ASF::Picture& other)
|
|
||||||
{
|
|
||||||
Picture(other).swap(*this);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASF::Picture::swap(Picture &other)
|
|
||||||
{
|
|
||||||
using std::swap;
|
|
||||||
|
|
||||||
swap(d, other.d);
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteVector ASF::Picture::render() const
|
|
||||||
{
|
|
||||||
if(!isValid())
|
|
||||||
return ByteVector();
|
|
||||||
|
|
||||||
return
|
|
||||||
ByteVector((char)d->type) +
|
|
||||||
ByteVector::fromUInt(d->picture.size(), false) +
|
|
||||||
renderString(d->mimeType) +
|
|
||||||
renderString(d->description) +
|
|
||||||
d->picture;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASF::Picture::parse(const ByteVector& bytes)
|
|
||||||
{
|
|
||||||
d->valid = false;
|
|
||||||
if(bytes.size() < 9)
|
|
||||||
return;
|
|
||||||
int pos = 0;
|
|
||||||
d->type = (Type)bytes[0]; ++pos;
|
|
||||||
const unsigned int dataLen = bytes.toUInt(pos, false); pos+=4;
|
|
||||||
|
|
||||||
const ByteVector nullStringTerminator(2, 0);
|
|
||||||
|
|
||||||
int endPos = bytes.find(nullStringTerminator, pos, 2);
|
|
||||||
if(endPos < 0)
|
|
||||||
return;
|
|
||||||
d->mimeType = String(bytes.mid(pos, endPos - pos), String::UTF16LE);
|
|
||||||
pos = endPos+2;
|
|
||||||
|
|
||||||
endPos = bytes.find(nullStringTerminator, pos, 2);
|
|
||||||
if(endPos < 0)
|
|
||||||
return;
|
|
||||||
d->description = String(bytes.mid(pos, endPos - pos), String::UTF16LE);
|
|
||||||
pos = endPos+2;
|
|
||||||
|
|
||||||
if(dataLen + pos != bytes.size())
|
|
||||||
return;
|
|
||||||
|
|
||||||
d->picture = bytes.mid(pos, dataLen);
|
|
||||||
d->valid = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASF::Picture ASF::Picture::fromInvalid()
|
|
||||||
{
|
|
||||||
Picture ret;
|
|
||||||
ret.d->valid = false;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
222
3rdparty/taglib/asf/asfpicture.h
vendored
222
3rdparty/taglib/asf/asfpicture.h
vendored
@@ -1,222 +0,0 @@
|
|||||||
/**************************************************************************
|
|
||||||
copyright : (C) 2010 by Anton Sergunov
|
|
||||||
email : setosha@gmail.com
|
|
||||||
**************************************************************************/
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* This library is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU Lesser General Public License version *
|
|
||||||
* 2.1 as published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 *
|
|
||||||
* *
|
|
||||||
* Alternatively, this file is available under the Mozilla Public *
|
|
||||||
* License Version 1.1. You may obtain a copy of the License at *
|
|
||||||
* http://www.mozilla.org/MPL/ *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#ifndef ASFPICTURE_H
|
|
||||||
#define ASFPICTURE_H
|
|
||||||
|
|
||||||
#include "tstring.h"
|
|
||||||
#include "tbytevector.h"
|
|
||||||
#include "taglib_export.h"
|
|
||||||
#include "attachedpictureframe.h"
|
|
||||||
|
|
||||||
namespace TagLib
|
|
||||||
{
|
|
||||||
namespace ASF
|
|
||||||
{
|
|
||||||
|
|
||||||
//! An ASF attached picture interface implementation
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* This is an implementation of ASF attached pictures interface. Pictures may be
|
|
||||||
* included in attributes, one per WM/Picture attribute (but there may be multiple WM/Picture
|
|
||||||
* attribute in a single tag). These pictures are usually in either JPEG or
|
|
||||||
* PNG format.
|
|
||||||
* \see Attribute::toPicture()
|
|
||||||
* \see Attribute::Attribute(const Picture& picture)
|
|
||||||
*/
|
|
||||||
class TAGLIB_EXPORT Picture {
|
|
||||||
public:
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* This describes the function or content of the picture.
|
|
||||||
*/
|
|
||||||
enum Type {
|
|
||||||
//! A type not enumerated below
|
|
||||||
Other = 0x00,
|
|
||||||
//! 32x32 PNG image that should be used as the file icon
|
|
||||||
FileIcon = 0x01,
|
|
||||||
//! File icon of a different size or format
|
|
||||||
OtherFileIcon = 0x02,
|
|
||||||
//! Front cover image of the album
|
|
||||||
FrontCover = 0x03,
|
|
||||||
//! Back cover image of the album
|
|
||||||
BackCover = 0x04,
|
|
||||||
//! Inside leaflet page of the album
|
|
||||||
LeafletPage = 0x05,
|
|
||||||
//! Image from the album itself
|
|
||||||
Media = 0x06,
|
|
||||||
//! Picture of the lead artist or soloist
|
|
||||||
LeadArtist = 0x07,
|
|
||||||
//! Picture of the artist or performer
|
|
||||||
Artist = 0x08,
|
|
||||||
//! Picture of the conductor
|
|
||||||
Conductor = 0x09,
|
|
||||||
//! Picture of the band or orchestra
|
|
||||||
Band = 0x0A,
|
|
||||||
//! Picture of the composer
|
|
||||||
Composer = 0x0B,
|
|
||||||
//! Picture of the lyricist or text writer
|
|
||||||
Lyricist = 0x0C,
|
|
||||||
//! Picture of the recording location or studio
|
|
||||||
RecordingLocation = 0x0D,
|
|
||||||
//! Picture of the artists during recording
|
|
||||||
DuringRecording = 0x0E,
|
|
||||||
//! Picture of the artists during performance
|
|
||||||
DuringPerformance = 0x0F,
|
|
||||||
//! Picture from a movie or video related to the track
|
|
||||||
MovieScreenCapture = 0x10,
|
|
||||||
//! Picture of a large, coloured fish
|
|
||||||
ColouredFish = 0x11,
|
|
||||||
//! Illustration related to the track
|
|
||||||
Illustration = 0x12,
|
|
||||||
//! Logo of the band or performer
|
|
||||||
BandLogo = 0x13,
|
|
||||||
//! Logo of the publisher (record company)
|
|
||||||
PublisherLogo = 0x14
|
|
||||||
};
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Constructs an empty picture.
|
|
||||||
*/
|
|
||||||
Picture();
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Construct an picture as a copy of \a other.
|
|
||||||
*/
|
|
||||||
Picture(const Picture& other);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Destroys the picture.
|
|
||||||
*/
|
|
||||||
virtual ~Picture();
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Copies the contents of \a other into this picture.
|
|
||||||
*/
|
|
||||||
Picture& operator=(const Picture& other);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Exchanges the content of the Picture by the content of \a other.
|
|
||||||
*/
|
|
||||||
void swap(Picture &other);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns true if Picture stores valid picture
|
|
||||||
*/
|
|
||||||
bool isValid() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns the mime type of the image. This should in most cases be
|
|
||||||
* "image/png" or "image/jpeg".
|
|
||||||
* \see setMimeType(const String &)
|
|
||||||
* \see picture()
|
|
||||||
* \see setPicture(const ByteArray&)
|
|
||||||
*/
|
|
||||||
String mimeType() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Sets the mime type of the image. This should in most cases be
|
|
||||||
* "image/png" or "image/jpeg".
|
|
||||||
* \see setMimeType(const String &)
|
|
||||||
* \see picture()
|
|
||||||
* \see setPicture(const ByteArray&)
|
|
||||||
*/
|
|
||||||
void setMimeType(const String &value);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns the type of the image.
|
|
||||||
*
|
|
||||||
* \see Type
|
|
||||||
* \see setType()
|
|
||||||
*/
|
|
||||||
Type type() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Sets the type for the image.
|
|
||||||
*
|
|
||||||
* \see Type
|
|
||||||
* \see type()
|
|
||||||
*/
|
|
||||||
void setType(const ASF::Picture::Type& t);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns a text description of the image.
|
|
||||||
*
|
|
||||||
* \see setDescription()
|
|
||||||
*/
|
|
||||||
String description() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Sets a textual description of the image to \a desc.
|
|
||||||
*
|
|
||||||
* \see description()
|
|
||||||
*/
|
|
||||||
void setDescription(const String &desc);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns the image data as a ByteVector.
|
|
||||||
*
|
|
||||||
* \note ByteVector has a data() method that returns a const char * which
|
|
||||||
* should make it easy to export this data to external programs.
|
|
||||||
*
|
|
||||||
* \see setPicture()
|
|
||||||
* \see mimeType()
|
|
||||||
*/
|
|
||||||
ByteVector picture() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Sets the image data to \a p. \a p should be of the type specified in
|
|
||||||
* this frame's mime-type specification.
|
|
||||||
*
|
|
||||||
* \see picture()
|
|
||||||
* \see mimeType()
|
|
||||||
* \see setMimeType()
|
|
||||||
*/
|
|
||||||
void setPicture(const ByteVector &p);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns picture as binary raw data \a value
|
|
||||||
*/
|
|
||||||
ByteVector render() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns picture as binary raw data \a value
|
|
||||||
*/
|
|
||||||
int dataSize() const;
|
|
||||||
|
|
||||||
#ifndef DO_NOT_DOCUMENT
|
|
||||||
/* THIS IS PRIVATE, DON'T TOUCH IT! */
|
|
||||||
void parse(const ByteVector& );
|
|
||||||
static Picture fromInvalid();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
private:
|
|
||||||
class PicturePrivate;
|
|
||||||
PicturePrivate *d;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // ASFPICTURE_H
|
|
||||||
194
3rdparty/taglib/asf/asfproperties.cpp
vendored
194
3rdparty/taglib/asf/asfproperties.cpp
vendored
@@ -1,194 +0,0 @@
|
|||||||
/**************************************************************************
|
|
||||||
copyright : (C) 2005-2007 by Lukáš Lalinský
|
|
||||||
email : lalinsky@gmail.com
|
|
||||||
**************************************************************************/
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* This library is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU Lesser General Public License version *
|
|
||||||
* 2.1 as published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 *
|
|
||||||
* *
|
|
||||||
* Alternatively, this file is available under the Mozilla Public *
|
|
||||||
* License Version 1.1. You may obtain a copy of the License at *
|
|
||||||
* http://www.mozilla.org/MPL/ *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#include <tdebug.h>
|
|
||||||
#include <tstring.h>
|
|
||||||
#include "asfproperties.h"
|
|
||||||
|
|
||||||
using namespace TagLib;
|
|
||||||
|
|
||||||
class ASF::Properties::PropertiesPrivate
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
PropertiesPrivate() :
|
|
||||||
length(0),
|
|
||||||
bitrate(0),
|
|
||||||
sampleRate(0),
|
|
||||||
channels(0),
|
|
||||||
bitsPerSample(0),
|
|
||||||
codec(ASF::Properties::Unknown),
|
|
||||||
encrypted(false) {}
|
|
||||||
|
|
||||||
int length;
|
|
||||||
int bitrate;
|
|
||||||
int sampleRate;
|
|
||||||
int channels;
|
|
||||||
int bitsPerSample;
|
|
||||||
ASF::Properties::Codec codec;
|
|
||||||
String codecName;
|
|
||||||
String codecDescription;
|
|
||||||
bool encrypted;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// public members
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
ASF::Properties::Properties() :
|
|
||||||
AudioProperties(AudioProperties::Average),
|
|
||||||
d(new PropertiesPrivate())
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
ASF::Properties::~Properties()
|
|
||||||
{
|
|
||||||
delete d;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ASF::Properties::length() const
|
|
||||||
{
|
|
||||||
return lengthInSeconds();
|
|
||||||
}
|
|
||||||
|
|
||||||
int ASF::Properties::lengthInSeconds() const
|
|
||||||
{
|
|
||||||
return d->length / 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ASF::Properties::lengthInMilliseconds() const
|
|
||||||
{
|
|
||||||
return d->length;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ASF::Properties::bitrate() const
|
|
||||||
{
|
|
||||||
return d->bitrate;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ASF::Properties::sampleRate() const
|
|
||||||
{
|
|
||||||
return d->sampleRate;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ASF::Properties::channels() const
|
|
||||||
{
|
|
||||||
return d->channels;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ASF::Properties::bitsPerSample() const
|
|
||||||
{
|
|
||||||
return d->bitsPerSample;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASF::Properties::Codec ASF::Properties::codec() const
|
|
||||||
{
|
|
||||||
return d->codec;
|
|
||||||
}
|
|
||||||
|
|
||||||
String ASF::Properties::codecName() const
|
|
||||||
{
|
|
||||||
return d->codecName;
|
|
||||||
}
|
|
||||||
|
|
||||||
String ASF::Properties::codecDescription() const
|
|
||||||
{
|
|
||||||
return d->codecDescription;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ASF::Properties::isEncrypted() const
|
|
||||||
{
|
|
||||||
return d->encrypted;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// private members
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void ASF::Properties::setLength(int /*length*/)
|
|
||||||
{
|
|
||||||
debug("ASF::Properties::setLength() -- This method is deprecated. Do not use.");
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASF::Properties::setLengthInMilliseconds(int value)
|
|
||||||
{
|
|
||||||
d->length = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASF::Properties::setBitrate(int value)
|
|
||||||
{
|
|
||||||
d->bitrate = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASF::Properties::setSampleRate(int value)
|
|
||||||
{
|
|
||||||
d->sampleRate = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASF::Properties::setChannels(int value)
|
|
||||||
{
|
|
||||||
d->channels = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASF::Properties::setBitsPerSample(int value)
|
|
||||||
{
|
|
||||||
d->bitsPerSample = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASF::Properties::setCodec(int value)
|
|
||||||
{
|
|
||||||
switch(value)
|
|
||||||
{
|
|
||||||
case 0x0160:
|
|
||||||
d->codec = WMA1;
|
|
||||||
break;
|
|
||||||
case 0x0161:
|
|
||||||
d->codec = WMA2;
|
|
||||||
break;
|
|
||||||
case 0x0162:
|
|
||||||
d->codec = WMA9Pro;
|
|
||||||
break;
|
|
||||||
case 0x0163:
|
|
||||||
d->codec = WMA9Lossless;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
d->codec = Unknown;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASF::Properties::setCodecName(const String &value)
|
|
||||||
{
|
|
||||||
d->codecName = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASF::Properties::setCodecDescription(const String &value)
|
|
||||||
{
|
|
||||||
d->codecDescription = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASF::Properties::setEncrypted(bool value)
|
|
||||||
{
|
|
||||||
d->encrypted = value;
|
|
||||||
}
|
|
||||||
186
3rdparty/taglib/asf/asfproperties.h
vendored
186
3rdparty/taglib/asf/asfproperties.h
vendored
@@ -1,186 +0,0 @@
|
|||||||
/**************************************************************************
|
|
||||||
copyright : (C) 2005-2007 by Lukáš Lalinský
|
|
||||||
email : lalinsky@gmail.com
|
|
||||||
**************************************************************************/
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* This library is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU Lesser General Public License version *
|
|
||||||
* 2.1 as published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 *
|
|
||||||
* *
|
|
||||||
* Alternatively, this file is available under the Mozilla Public *
|
|
||||||
* License Version 1.1. You may obtain a copy of the License at *
|
|
||||||
* http://www.mozilla.org/MPL/ *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#ifndef TAGLIB_ASFPROPERTIES_H
|
|
||||||
#define TAGLIB_ASFPROPERTIES_H
|
|
||||||
|
|
||||||
#include "audioproperties.h"
|
|
||||||
#include "tstring.h"
|
|
||||||
#include "taglib_export.h"
|
|
||||||
|
|
||||||
namespace TagLib {
|
|
||||||
|
|
||||||
namespace ASF {
|
|
||||||
|
|
||||||
//! An implementation of ASF audio properties
|
|
||||||
class TAGLIB_EXPORT Properties : public AudioProperties
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Audio codec types can be used in ASF file.
|
|
||||||
*/
|
|
||||||
enum Codec
|
|
||||||
{
|
|
||||||
/*!
|
|
||||||
* Couldn't detect the codec.
|
|
||||||
*/
|
|
||||||
Unknown = 0,
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Windows Media Audio 1
|
|
||||||
*/
|
|
||||||
WMA1,
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Windows Media Audio 2 or above
|
|
||||||
*/
|
|
||||||
WMA2,
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Windows Media Audio 9 Professional
|
|
||||||
*/
|
|
||||||
WMA9Pro,
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Windows Media Audio 9 Lossless
|
|
||||||
*/
|
|
||||||
WMA9Lossless,
|
|
||||||
};
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Creates an instance of ASF::Properties.
|
|
||||||
*/
|
|
||||||
Properties();
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Destroys this ASF::Properties instance.
|
|
||||||
*/
|
|
||||||
virtual ~Properties();
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns the length of the file in seconds. The length is rounded down to
|
|
||||||
* the nearest whole second.
|
|
||||||
*
|
|
||||||
* \note This method is just an alias of lengthInSeconds().
|
|
||||||
*
|
|
||||||
* \deprecated
|
|
||||||
*/
|
|
||||||
virtual int length() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns the length of the file in seconds. The length is rounded down to
|
|
||||||
* the nearest whole second.
|
|
||||||
*
|
|
||||||
* \see lengthInMilliseconds()
|
|
||||||
*/
|
|
||||||
// BIC: make virtual
|
|
||||||
int lengthInSeconds() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns the length of the file in milliseconds.
|
|
||||||
*
|
|
||||||
* \see lengthInSeconds()
|
|
||||||
*/
|
|
||||||
// BIC: make virtual
|
|
||||||
int lengthInMilliseconds() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns the average bit rate of the file in kb/s.
|
|
||||||
*/
|
|
||||||
virtual int bitrate() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns the sample rate in Hz.
|
|
||||||
*/
|
|
||||||
virtual int sampleRate() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns the number of audio channels.
|
|
||||||
*/
|
|
||||||
virtual int channels() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns the number of bits per audio sample.
|
|
||||||
*/
|
|
||||||
int bitsPerSample() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns the codec used in the file.
|
|
||||||
*
|
|
||||||
* \see codecName()
|
|
||||||
* \see codecDescription()
|
|
||||||
*/
|
|
||||||
Codec codec() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns the concrete codec name, for example "Windows Media Audio 9.1"
|
|
||||||
* used in the file if available, otherwise an empty string.
|
|
||||||
*
|
|
||||||
* \see codec()
|
|
||||||
* \see codecDescription()
|
|
||||||
*/
|
|
||||||
String codecName() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns the codec description, typically contains the encoder settings,
|
|
||||||
* for example "VBR Quality 50, 44kHz, stereo 1-pass VBR" if available,
|
|
||||||
* otherwise an empty string.
|
|
||||||
*
|
|
||||||
* \see codec()
|
|
||||||
* \see codecName()
|
|
||||||
*/
|
|
||||||
String codecDescription() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Returns whether or not the file is encrypted.
|
|
||||||
*/
|
|
||||||
bool isEncrypted() const;
|
|
||||||
|
|
||||||
#ifndef DO_NOT_DOCUMENT
|
|
||||||
// deprecated
|
|
||||||
void setLength(int value);
|
|
||||||
|
|
||||||
void setLengthInMilliseconds(int value);
|
|
||||||
void setBitrate(int value);
|
|
||||||
void setSampleRate(int value);
|
|
||||||
void setChannels(int value);
|
|
||||||
void setBitsPerSample(int value);
|
|
||||||
void setCodec(int value);
|
|
||||||
void setCodecName(const String &value);
|
|
||||||
void setCodecDescription(const String &value);
|
|
||||||
void setEncrypted(bool value);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
private:
|
|
||||||
class PropertiesPrivate;
|
|
||||||
PropertiesPrivate *d;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
378
3rdparty/taglib/asf/asftag.cpp
vendored
378
3rdparty/taglib/asf/asftag.cpp
vendored
@@ -1,378 +0,0 @@
|
|||||||
/**************************************************************************
|
|
||||||
copyright : (C) 2005-2007 by Lukáš Lalinský
|
|
||||||
email : lalinsky@gmail.com
|
|
||||||
**************************************************************************/
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* This library is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU Lesser General Public License version *
|
|
||||||
* 2.1 as published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 *
|
|
||||||
* *
|
|
||||||
* Alternatively, this file is available under the Mozilla Public *
|
|
||||||
* License Version 1.1. You may obtain a copy of the License at *
|
|
||||||
* http://www.mozilla.org/MPL/ *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#include <tpropertymap.h>
|
|
||||||
#include "asftag.h"
|
|
||||||
|
|
||||||
using namespace TagLib;
|
|
||||||
|
|
||||||
class ASF::Tag::TagPrivate
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
String title;
|
|
||||||
String artist;
|
|
||||||
String copyright;
|
|
||||||
String comment;
|
|
||||||
String rating;
|
|
||||||
AttributeListMap attributeListMap;
|
|
||||||
};
|
|
||||||
|
|
||||||
ASF::Tag::Tag() :
|
|
||||||
TagLib::Tag(),
|
|
||||||
d(new TagPrivate())
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
ASF::Tag::~Tag()
|
|
||||||
{
|
|
||||||
delete d;
|
|
||||||
}
|
|
||||||
|
|
||||||
String ASF::Tag::title() const
|
|
||||||
{
|
|
||||||
return d->title;
|
|
||||||
}
|
|
||||||
|
|
||||||
String ASF::Tag::artist() const
|
|
||||||
{
|
|
||||||
return d->artist;
|
|
||||||
}
|
|
||||||
|
|
||||||
String ASF::Tag::album() const
|
|
||||||
{
|
|
||||||
if(d->attributeListMap.contains("WM/AlbumTitle"))
|
|
||||||
return d->attributeListMap["WM/AlbumTitle"][0].toString();
|
|
||||||
return String();
|
|
||||||
}
|
|
||||||
|
|
||||||
String ASF::Tag::copyright() const
|
|
||||||
{
|
|
||||||
return d->copyright;
|
|
||||||
}
|
|
||||||
|
|
||||||
String ASF::Tag::comment() const
|
|
||||||
{
|
|
||||||
return d->comment;
|
|
||||||
}
|
|
||||||
|
|
||||||
String ASF::Tag::rating() const
|
|
||||||
{
|
|
||||||
return d->rating;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int ASF::Tag::year() const
|
|
||||||
{
|
|
||||||
if(d->attributeListMap.contains("WM/Year"))
|
|
||||||
return d->attributeListMap["WM/Year"][0].toString().toInt();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int ASF::Tag::track() const
|
|
||||||
{
|
|
||||||
if(d->attributeListMap.contains("WM/TrackNumber")) {
|
|
||||||
const ASF::Attribute attr = d->attributeListMap["WM/TrackNumber"][0];
|
|
||||||
if(attr.type() == ASF::Attribute::DWordType)
|
|
||||||
return attr.toUInt();
|
|
||||||
else
|
|
||||||
return attr.toString().toInt();
|
|
||||||
}
|
|
||||||
if(d->attributeListMap.contains("WM/Track"))
|
|
||||||
return d->attributeListMap["WM/Track"][0].toUInt();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
String ASF::Tag::genre() const
|
|
||||||
{
|
|
||||||
if(d->attributeListMap.contains("WM/Genre"))
|
|
||||||
return d->attributeListMap["WM/Genre"][0].toString();
|
|
||||||
return String();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASF::Tag::setTitle(const String &value)
|
|
||||||
{
|
|
||||||
d->title = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASF::Tag::setArtist(const String &value)
|
|
||||||
{
|
|
||||||
d->artist = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASF::Tag::setCopyright(const String &value)
|
|
||||||
{
|
|
||||||
d->copyright = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASF::Tag::setComment(const String &value)
|
|
||||||
{
|
|
||||||
d->comment = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASF::Tag::setRating(const String &value)
|
|
||||||
{
|
|
||||||
d->rating = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASF::Tag::setAlbum(const String &value)
|
|
||||||
{
|
|
||||||
setAttribute("WM/AlbumTitle", value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASF::Tag::setGenre(const String &value)
|
|
||||||
{
|
|
||||||
setAttribute("WM/Genre", value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASF::Tag::setYear(unsigned int value)
|
|
||||||
{
|
|
||||||
setAttribute("WM/Year", String::number(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASF::Tag::setTrack(unsigned int value)
|
|
||||||
{
|
|
||||||
setAttribute("WM/TrackNumber", String::number(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
ASF::AttributeListMap& ASF::Tag::attributeListMap()
|
|
||||||
{
|
|
||||||
return d->attributeListMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ASF::AttributeListMap &ASF::Tag::attributeListMap() const
|
|
||||||
{
|
|
||||||
return d->attributeListMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ASF::Tag::contains(const String &key) const
|
|
||||||
{
|
|
||||||
return d->attributeListMap.contains(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASF::Tag::removeItem(const String &key)
|
|
||||||
{
|
|
||||||
d->attributeListMap.erase(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
ASF::AttributeList ASF::Tag::attribute(const String &name) const
|
|
||||||
{
|
|
||||||
return d->attributeListMap[name];
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASF::Tag::setAttribute(const String &name, const Attribute &attribute)
|
|
||||||
{
|
|
||||||
AttributeList value;
|
|
||||||
value.append(attribute);
|
|
||||||
d->attributeListMap.insert(name, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASF::Tag::setAttribute(const String &name, const AttributeList &values)
|
|
||||||
{
|
|
||||||
d->attributeListMap.insert(name, values);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASF::Tag::addAttribute(const String &name, const Attribute &attribute)
|
|
||||||
{
|
|
||||||
if(d->attributeListMap.contains(name)) {
|
|
||||||
d->attributeListMap[name].append(attribute);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
setAttribute(name, attribute);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ASF::Tag::isEmpty() const
|
|
||||||
{
|
|
||||||
return TagLib::Tag::isEmpty() &&
|
|
||||||
copyright().isEmpty() &&
|
|
||||||
rating().isEmpty() &&
|
|
||||||
d->attributeListMap.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
const char *keyTranslation[][2] = {
|
|
||||||
{ "WM/AlbumTitle", "ALBUM" },
|
|
||||||
{ "WM/AlbumArtist", "ALBUMARTIST" },
|
|
||||||
{ "WM/Composer", "COMPOSER" },
|
|
||||||
{ "WM/Writer", "WRITER" },
|
|
||||||
{ "WM/Conductor", "CONDUCTOR" },
|
|
||||||
{ "WM/ModifiedBy", "REMIXER" },
|
|
||||||
{ "WM/Year", "DATE" },
|
|
||||||
{ "WM/OriginalReleaseYear", "ORIGINALDATE" },
|
|
||||||
{ "WM/Producer", "PRODUCER" },
|
|
||||||
{ "WM/ContentGroupDescription", "GROUPING" },
|
|
||||||
{ "WM/SubTitle", "SUBTITLE" },
|
|
||||||
{ "WM/SetSubTitle", "DISCSUBTITLE" },
|
|
||||||
{ "WM/TrackNumber", "TRACKNUMBER" },
|
|
||||||
{ "WM/PartOfSet", "DISCNUMBER" },
|
|
||||||
{ "WM/Genre", "GENRE" },
|
|
||||||
{ "WM/BeatsPerMinute", "BPM" },
|
|
||||||
{ "WM/Mood", "MOOD" },
|
|
||||||
{ "WM/ISRC", "ISRC" },
|
|
||||||
{ "WM/Lyrics", "LYRICS" },
|
|
||||||
{ "WM/Media", "MEDIA" },
|
|
||||||
{ "WM/Publisher", "LABEL" },
|
|
||||||
{ "WM/CatalogNo", "CATALOGNUMBER" },
|
|
||||||
{ "WM/Barcode", "BARCODE" },
|
|
||||||
{ "WM/EncodedBy", "ENCODEDBY" },
|
|
||||||
{ "WM/AlbumSortOrder", "ALBUMSORT" },
|
|
||||||
{ "WM/AlbumArtistSortOrder", "ALBUMARTISTSORT" },
|
|
||||||
{ "WM/ArtistSortOrder", "ARTISTSORT" },
|
|
||||||
{ "WM/TitleSortOrder", "TITLESORT" },
|
|
||||||
{ "WM/Script", "SCRIPT" },
|
|
||||||
{ "WM/Language", "LANGUAGE" },
|
|
||||||
{ "MusicBrainz/Track Id", "MUSICBRAINZ_TRACKID" },
|
|
||||||
{ "MusicBrainz/Artist Id", "MUSICBRAINZ_ARTISTID" },
|
|
||||||
{ "MusicBrainz/Album Id", "MUSICBRAINZ_ALBUMID" },
|
|
||||||
{ "MusicBrainz/Album Artist Id", "MUSICBRAINZ_ALBUMARTISTID" },
|
|
||||||
{ "MusicBrainz/Release Group Id", "MUSICBRAINZ_RELEASEGROUPID" },
|
|
||||||
{ "MusicBrainz/Work Id", "MUSICBRAINZ_WORKID" },
|
|
||||||
{ "MusicIP/PUID", "MUSICIP_PUID" },
|
|
||||||
{ "Acoustid/Id", "ACOUSTID_ID" },
|
|
||||||
{ "Acoustid/Fingerprint", "ACOUSTID_FINGERPRINT" },
|
|
||||||
};
|
|
||||||
const size_t keyTranslationSize = sizeof(keyTranslation) / sizeof(keyTranslation[0]);
|
|
||||||
|
|
||||||
String translateKey(const String &key)
|
|
||||||
{
|
|
||||||
for(size_t i = 0; i < keyTranslationSize; ++i) {
|
|
||||||
if(key == keyTranslation[i][0])
|
|
||||||
return keyTranslation[i][1];
|
|
||||||
}
|
|
||||||
|
|
||||||
return String();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PropertyMap ASF::Tag::properties() const
|
|
||||||
{
|
|
||||||
PropertyMap props;
|
|
||||||
|
|
||||||
if(!d->title.isEmpty()) {
|
|
||||||
props["TITLE"] = d->title;
|
|
||||||
}
|
|
||||||
if(!d->artist.isEmpty()) {
|
|
||||||
props["ARTIST"] = d->artist;
|
|
||||||
}
|
|
||||||
if(!d->copyright.isEmpty()) {
|
|
||||||
props["COPYRIGHT"] = d->copyright;
|
|
||||||
}
|
|
||||||
if(!d->comment.isEmpty()) {
|
|
||||||
props["COMMENT"] = d->comment;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASF::AttributeListMap::ConstIterator it = d->attributeListMap.begin();
|
|
||||||
for(; it != d->attributeListMap.end(); ++it) {
|
|
||||||
const String key = translateKey(it->first);
|
|
||||||
if(!key.isEmpty()) {
|
|
||||||
AttributeList::ConstIterator it2 = it->second.begin();
|
|
||||||
for(; it2 != it->second.end(); ++it2) {
|
|
||||||
if(key == "TRACKNUMBER") {
|
|
||||||
if(it2->type() == ASF::Attribute::DWordType)
|
|
||||||
props.insert(key, String::number(it2->toUInt()));
|
|
||||||
else
|
|
||||||
props.insert(key, it2->toString());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
props.insert(key, it2->toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
props.unsupportedData().append(it->first);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return props;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASF::Tag::removeUnsupportedProperties(const StringList &props)
|
|
||||||
{
|
|
||||||
StringList::ConstIterator it = props.begin();
|
|
||||||
for(; it != props.end(); ++it)
|
|
||||||
d->attributeListMap.erase(*it);
|
|
||||||
}
|
|
||||||
|
|
||||||
PropertyMap ASF::Tag::setProperties(const PropertyMap &props)
|
|
||||||
{
|
|
||||||
static Map<String, String> reverseKeyMap;
|
|
||||||
if(reverseKeyMap.isEmpty()) {
|
|
||||||
int numKeys = sizeof(keyTranslation) / sizeof(keyTranslation[0]);
|
|
||||||
for(int i = 0; i < numKeys; i++) {
|
|
||||||
reverseKeyMap[keyTranslation[i][1]] = keyTranslation[i][0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PropertyMap origProps = properties();
|
|
||||||
PropertyMap::ConstIterator it = origProps.begin();
|
|
||||||
for(; it != origProps.end(); ++it) {
|
|
||||||
if(!props.contains(it->first) || props[it->first].isEmpty()) {
|
|
||||||
if(it->first == "TITLE") {
|
|
||||||
d->title.clear();
|
|
||||||
}
|
|
||||||
else if(it->first == "ARTIST") {
|
|
||||||
d->artist.clear();
|
|
||||||
}
|
|
||||||
else if(it->first == "COMMENT") {
|
|
||||||
d->comment.clear();
|
|
||||||
}
|
|
||||||
else if(it->first == "COPYRIGHT") {
|
|
||||||
d->copyright.clear();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
d->attributeListMap.erase(reverseKeyMap[it->first]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PropertyMap ignoredProps;
|
|
||||||
it = props.begin();
|
|
||||||
for(; it != props.end(); ++it) {
|
|
||||||
if(reverseKeyMap.contains(it->first)) {
|
|
||||||
String name = reverseKeyMap[it->first];
|
|
||||||
removeItem(name);
|
|
||||||
StringList::ConstIterator it2 = it->second.begin();
|
|
||||||
for(; it2 != it->second.end(); ++it2) {
|
|
||||||
addAttribute(name, *it2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(it->first == "TITLE") {
|
|
||||||
d->title = it->second.toString();
|
|
||||||
}
|
|
||||||
else if(it->first == "ARTIST") {
|
|
||||||
d->artist = it->second.toString();
|
|
||||||
}
|
|
||||||
else if(it->first == "COMMENT") {
|
|
||||||
d->comment = it->second.toString();
|
|
||||||
}
|
|
||||||
else if(it->first == "COPYRIGHT") {
|
|
||||||
d->copyright = it->second.toString();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ignoredProps.insert(it->first, it->second);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ignoredProps;
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user